1
0
Fork 0

Compare commits

...

4 commits

46 changed files with 5688 additions and 3568 deletions

View file

@ -674,23 +674,24 @@ impl ToTokens for ParsedBundle {
} }
}, },
)); ));
let sim_value_from_bits_fields = Vec::from_iter(fields.named().into_iter().map(|field| { let sim_value_from_opaque_fields =
let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=>
#ident: v.field_from_bits(),
}
}));
let sim_value_clone_from_bits_fields =
Vec::from_iter(fields.named().into_iter().map(|field| { Vec::from_iter(fields.named().into_iter().map(|field| {
let ident: &Ident = field.ident().as_ref().unwrap(); let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=> quote_spanned! {span=>
v.field_clone_from_bits(&mut value.#ident); #ident: v.field_from_opaque(),
} }
})); }));
let sim_value_to_bits_fields = Vec::from_iter(fields.named().into_iter().map(|field| { let sim_value_clone_from_opaque_fields =
Vec::from_iter(fields.named().into_iter().map(|field| {
let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=>
v.field_clone_from_opaque(&mut value.#ident);
}
}));
let sim_value_to_opaque_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
let ident: &Ident = field.ident().as_ref().unwrap(); let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=> quote_spanned! {span=>
v.field_to_bits(&value.#ident); v.field(&value.#ident);
} }
})); }));
let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| { let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
@ -745,33 +746,34 @@ impl ToTokens for ParsedBundle {
fn source_location() -> ::fayalite::source_location::SourceLocation { fn source_location() -> ::fayalite::source_location::SourceLocation {
::fayalite::source_location::SourceLocation::caller() ::fayalite::source_location::SourceLocation::caller()
} }
fn sim_value_from_bits( fn sim_value_from_opaque(
&self, &self,
bits: &::fayalite::bitvec::slice::BitSlice, opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) -> <Self as ::fayalite::ty::Type>::SimValue { ) -> <Self as ::fayalite::ty::Type>::SimValue {
#![allow(unused_mut, unused_variables)] #![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#mask_type_sim_value_ident { #mask_type_sim_value_ident {
#(#sim_value_from_bits_fields)* #(#sim_value_from_opaque_fields)*
} }
} }
fn sim_value_clone_from_bits( fn sim_value_clone_from_opaque(
&self, &self,
value: &mut <Self as ::fayalite::ty::Type>::SimValue, value: &mut <Self as ::fayalite::ty::Type>::SimValue,
bits: &::fayalite::bitvec::slice::BitSlice, opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) { ) {
#![allow(unused_mut, unused_variables)] #![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#(#sim_value_clone_from_bits_fields)* #(#sim_value_clone_from_opaque_fields)*
} }
fn sim_value_to_bits( fn sim_value_to_opaque<'__w>(
&self, &self,
value: &<Self as ::fayalite::ty::Type>::SimValue, value: &<Self as ::fayalite::ty::Type>::SimValue,
bits: &mut ::fayalite::bitvec::slice::BitSlice, writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
) { ) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
#![allow(unused_mut, unused_variables)] #![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits); let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer);
#(#sim_value_to_bits_fields)* #(#sim_value_to_opaque_fields)*
v.finish()
} }
} }
#[automatically_derived] #[automatically_derived]
@ -894,33 +896,34 @@ impl ToTokens for ParsedBundle {
fn source_location() -> ::fayalite::source_location::SourceLocation { fn source_location() -> ::fayalite::source_location::SourceLocation {
::fayalite::source_location::SourceLocation::caller() ::fayalite::source_location::SourceLocation::caller()
} }
fn sim_value_from_bits( fn sim_value_from_opaque(
&self, &self,
bits: &::fayalite::bitvec::slice::BitSlice, opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) -> <Self as ::fayalite::ty::Type>::SimValue { ) -> <Self as ::fayalite::ty::Type>::SimValue {
#![allow(unused_mut, unused_variables)] #![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#sim_value_ident { #sim_value_ident {
#(#sim_value_from_bits_fields)* #(#sim_value_from_opaque_fields)*
} }
} }
fn sim_value_clone_from_bits( fn sim_value_clone_from_opaque(
&self, &self,
value: &mut <Self as ::fayalite::ty::Type>::SimValue, value: &mut <Self as ::fayalite::ty::Type>::SimValue,
bits: &::fayalite::bitvec::slice::BitSlice, opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) { ) {
#![allow(unused_mut, unused_variables)] #![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits); let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#(#sim_value_clone_from_bits_fields)* #(#sim_value_clone_from_opaque_fields)*
} }
fn sim_value_to_bits( fn sim_value_to_opaque<'__w>(
&self, &self,
value: &<Self as ::fayalite::ty::Type>::SimValue, value: &<Self as ::fayalite::ty::Type>::SimValue,
bits: &mut ::fayalite::bitvec::slice::BitSlice, writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
) { ) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
#![allow(unused_mut, unused_variables)] #![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits); let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer);
#(#sim_value_to_bits_fields)* #(#sim_value_to_opaque_fields)*
v.finish()
} }
} }
#[automatically_derived] #[automatically_derived]

View file

@ -701,18 +701,18 @@ impl ToTokens for ParsedEnum {
} }
}, },
)); ));
let sim_value_from_bits_unknown_match_arm = if let Some(sim_value_unknown_variant_name) = let sim_value_from_opaque_unknown_match_arm = if let Some(sim_value_unknown_variant_name) =
&sim_value_unknown_variant_name &sim_value_unknown_variant_name
{ {
quote_spanned! {span=> quote_spanned! {span=>
_ => #sim_value_ident::#sim_value_unknown_variant_name(v.unknown_variant_from_bits()), _ => #sim_value_ident::#sim_value_unknown_variant_name(v.unknown_variant_from_opaque()),
} }
} else { } else {
quote_spanned! {span=> quote_spanned! {span=>
_ => ::fayalite::__std::unreachable!(), _ => ::fayalite::__std::unreachable!(),
} }
}; };
let sim_value_from_bits_match_arms = Vec::from_iter( let sim_value_from_opaque_match_arms = Vec::from_iter(
variants variants
.iter() .iter()
.enumerate() .enumerate()
@ -729,29 +729,29 @@ impl ToTokens for ParsedEnum {
if let Some(_) = field { if let Some(_) = field {
quote_spanned! {span=> quote_spanned! {span=>
#index => { #index => {
let (field, padding) = v.variant_with_field_from_bits(); let (field, padding) = v.variant_with_field_from_opaque();
#sim_value_ident::#ident(field, padding) #sim_value_ident::#ident(field, padding)
} }
} }
} else { } else {
quote_spanned! {span=> quote_spanned! {span=>
#index => #sim_value_ident::#ident( #index => #sim_value_ident::#ident(
v.variant_no_field_from_bits(), v.variant_no_field_from_opaque(),
), ),
} }
} }
}, },
) )
.chain([sim_value_from_bits_unknown_match_arm]), .chain([sim_value_from_opaque_unknown_match_arm]),
); );
let sim_value_clone_from_bits_unknown_match_arm = let sim_value_clone_from_opaque_unknown_match_arm =
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name { if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
quote_spanned! {span=> quote_spanned! {span=>
_ => if let #sim_value_ident::#sim_value_unknown_variant_name(value) = value { _ => if let #sim_value_ident::#sim_value_unknown_variant_name(value) = value {
v.unknown_variant_clone_from_bits(value); v.unknown_variant_clone_from_opaque(value);
} else { } else {
*value = #sim_value_ident::#sim_value_unknown_variant_name( *value = #sim_value_ident::#sim_value_unknown_variant_name(
v.unknown_variant_from_bits(), v.unknown_variant_from_opaque(),
); );
}, },
} }
@ -760,7 +760,7 @@ impl ToTokens for ParsedEnum {
_ => ::fayalite::__std::unreachable!(), _ => ::fayalite::__std::unreachable!(),
} }
}; };
let sim_value_clone_from_bits_match_arms = Vec::from_iter( let sim_value_clone_from_opaque_match_arms = Vec::from_iter(
variants variants
.iter() .iter()
.enumerate() .enumerate()
@ -777,28 +777,28 @@ impl ToTokens for ParsedEnum {
if let Some(_) = field { if let Some(_) = field {
quote_spanned! {span=> quote_spanned! {span=>
#index => if let #sim_value_ident::#ident(field, padding) = value { #index => if let #sim_value_ident::#ident(field, padding) = value {
v.variant_with_field_clone_from_bits(field, padding); v.variant_with_field_clone_from_opaque(field, padding);
} else { } else {
let (field, padding) = v.variant_with_field_from_bits(); let (field, padding) = v.variant_with_field_from_opaque();
*value = #sim_value_ident::#ident(field, padding); *value = #sim_value_ident::#ident(field, padding);
}, },
} }
} else { } else {
quote_spanned! {span=> quote_spanned! {span=>
#index => if let #sim_value_ident::#ident(padding) = value { #index => if let #sim_value_ident::#ident(padding) = value {
v.variant_no_field_clone_from_bits(padding); v.variant_no_field_clone_from_opaque(padding);
} else { } else {
*value = #sim_value_ident::#ident( *value = #sim_value_ident::#ident(
v.variant_no_field_from_bits(), v.variant_no_field_from_opaque(),
); );
}, },
} }
} }
}, },
) )
.chain([sim_value_clone_from_bits_unknown_match_arm]), .chain([sim_value_clone_from_opaque_unknown_match_arm]),
); );
let sim_value_to_bits_match_arms = Vec::from_iter( let sim_value_to_opaque_match_arms = Vec::from_iter(
variants variants
.iter() .iter()
.enumerate() .enumerate()
@ -815,13 +815,13 @@ impl ToTokens for ParsedEnum {
if let Some(_) = field { if let Some(_) = field {
quote_spanned! {span=> quote_spanned! {span=>
#sim_value_ident::#ident(field, padding) => { #sim_value_ident::#ident(field, padding) => {
v.variant_with_field_to_bits(#index, field, padding); v.variant_with_field_to_opaque(#index, field, padding)
} }
} }
} else { } else {
quote_spanned! {span=> quote_spanned! {span=>
#sim_value_ident::#ident(padding) => { #sim_value_ident::#ident(padding) => {
v.variant_no_field_to_bits(#index, padding); v.variant_no_field_to_opaque(#index, padding)
} }
} }
} }
@ -831,7 +831,7 @@ impl ToTokens for ParsedEnum {
|sim_value_unknown_variant_name| { |sim_value_unknown_variant_name| {
quote_spanned! {span=> quote_spanned! {span=>
#sim_value_ident::#sim_value_unknown_variant_name(value) => { #sim_value_ident::#sim_value_unknown_variant_name(value) => {
v.unknown_variant_to_bits(value); v.unknown_variant_to_opaque(value)
} }
} }
}, },
@ -878,33 +878,33 @@ impl ToTokens for ParsedEnum {
fn source_location() -> ::fayalite::source_location::SourceLocation { fn source_location() -> ::fayalite::source_location::SourceLocation {
::fayalite::source_location::SourceLocation::caller() ::fayalite::source_location::SourceLocation::caller()
} }
fn sim_value_from_bits( fn sim_value_from_opaque(
&self, &self,
bits: &::fayalite::bitvec::slice::BitSlice, opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) -> <Self as ::fayalite::ty::Type>::SimValue { ) -> <Self as ::fayalite::ty::Type>::SimValue {
let v = ::fayalite::enum_::EnumSimValueFromBits::new(*self, bits); let v = ::fayalite::enum_::EnumSimValueFromOpaque::new(*self, opaque);
match v.discriminant() { match v.discriminant() {
#(#sim_value_from_bits_match_arms)* #(#sim_value_from_opaque_match_arms)*
} }
} }
fn sim_value_clone_from_bits( fn sim_value_clone_from_opaque(
&self, &self,
value: &mut <Self as ::fayalite::ty::Type>::SimValue, value: &mut <Self as ::fayalite::ty::Type>::SimValue,
bits: &::fayalite::bitvec::slice::BitSlice, opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) { ) {
let v = ::fayalite::enum_::EnumSimValueFromBits::new(*self, bits); let v = ::fayalite::enum_::EnumSimValueFromOpaque::new(*self, opaque);
match v.discriminant() { match v.discriminant() {
#(#sim_value_clone_from_bits_match_arms)* #(#sim_value_clone_from_opaque_match_arms)*
} }
} }
fn sim_value_to_bits( fn sim_value_to_opaque<'__w>(
&self, &self,
value: &<Self as ::fayalite::ty::Type>::SimValue, value: &<Self as ::fayalite::ty::Type>::SimValue,
bits: &mut ::fayalite::bitvec::slice::BitSlice, writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
) { ) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
let v = ::fayalite::enum_::EnumSimValueToBits::new(*self, bits); let v = ::fayalite::enum_::EnumSimValueToOpaque::new(*self, writer);
match value { match value {
#(#sim_value_to_bits_match_arms)* #(#sim_value_to_opaque_match_arms)*
} }
} }
} }

View file

@ -12,12 +12,12 @@ use crate::{
sim::value::{SimValue, SimValuePartialEq}, sim::value::{SimValue, SimValuePartialEq},
source_location::SourceLocation, source_location::SourceLocation,
ty::{ ty::{
CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref, CanonicalType, MatchVariantWithoutScope, OpaqueSimValueSlice, OpaqueSimValueWriter,
OpaqueSimValueWritten, StaticType, Type, TypeProperties, TypeWithDeref,
serde_impls::SerdeCanonicalType, serde_impls::SerdeCanonicalType,
}, },
util::ConstUsize, util::ConstUsize,
}; };
use bitvec::slice::BitSlice;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error}; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
use std::{iter::FusedIterator, ops::Index}; use std::{iter::FusedIterator, ops::Index};
@ -48,15 +48,20 @@ impl<T: Type, Len: Size> ArrayType<T, Len> {
is_storable, is_storable,
is_castable_from_bits, is_castable_from_bits,
bit_width, bit_width,
sim_only_values_len,
} = element; } = element;
let Some(bit_width) = bit_width.checked_mul(len) else { let Some(bit_width) = bit_width.checked_mul(len) else {
panic!("array too big"); panic!("array too big");
}; };
let Some(sim_only_values_len) = sim_only_values_len.checked_mul(len) else {
panic!("array too big");
};
TypeProperties { TypeProperties {
is_passive, is_passive,
is_storable, is_storable,
is_castable_from_bits, is_castable_from_bits,
bit_width, bit_width,
sim_only_values_len,
} }
} }
pub fn new(element: T, len: Len::SizeType) -> Self { pub fn new(element: T, len: Len::SizeType) -> Self {
@ -194,42 +199,51 @@ impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, mut opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(bits.len(), self.type_properties.bit_width); let element_ty = self.element();
let element = self.element(); let element_size = element_ty.canonical().size();
let element_bit_width = element.canonical().bit_width(); let mut value = Vec::with_capacity(self.len());
TryFrom::try_from(Vec::from_iter((0..self.len()).map(|i| { for _ in 0..self.len() {
SimValue::from_bitslice(element, &bits[i * element_bit_width..][..element_bit_width]) let (element_opaque, rest) = opaque.split_at(element_size);
}))) value.push(SimValue::from_opaque(element_ty, element_opaque.to_owned()));
.ok() opaque = rest;
.expect("used correct length") }
value.try_into().ok().expect("used correct length")
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
assert_eq!(bits.len(), self.type_properties.bit_width); &self,
value: &mut Self::SimValue,
mut opaque: OpaqueSimValueSlice<'_>,
) {
let element_ty = self.element(); let element_ty = self.element();
let element_bit_width = element_ty.canonical().bit_width(); let element_size = element_ty.canonical().size();
let value: &mut [SimValue<T>] = value.as_mut(); let value = AsMut::<[SimValue<T>]>::as_mut(value);
assert_eq!(self.len(), value.len()); assert_eq!(self.len(), value.len());
for (i, element_value) in value.iter_mut().enumerate() { for element_value in value {
assert_eq!(SimValue::ty(element_value), element_ty); assert_eq!(SimValue::ty(element_value), element_ty);
SimValue::bits_mut(element_value) let (element_opaque, rest) = opaque.split_at(element_size);
.bits_mut() SimValue::opaque_mut(element_value).clone_from_slice(element_opaque);
.copy_from_bitslice(&bits[i * element_bit_width..][..element_bit_width]); opaque = rest;
} }
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
assert_eq!(bits.len(), self.type_properties.bit_width); &self,
value: &Self::SimValue,
mut writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
let element_ty = self.element(); let element_ty = self.element();
let element_bit_width = element_ty.canonical().bit_width(); let element_size = element_ty.canonical().size();
let value: &[SimValue<T>] = value.as_ref(); let value = AsRef::<[SimValue<T>]>::as_ref(value);
assert_eq!(self.len(), value.len()); assert_eq!(self.len(), value.len());
for (i, element_value) in value.iter().enumerate() { for element_value in value {
assert_eq!(SimValue::ty(element_value), element_ty); assert_eq!(SimValue::ty(element_value), element_ty);
bits[i * element_bit_width..][..element_bit_width] writer.fill_prefix_with(element_size, |writer| {
.copy_from_bitslice(SimValue::bits(element_value).bits()); writer.fill_cloned_from_slice(SimValue::opaque(element_value).as_slice())
});
} }
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
} }
} }

View file

@ -11,12 +11,12 @@ use crate::{
sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType},
source_location::SourceLocation, source_location::SourceLocation,
ty::{ ty::{
CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, StaticType, Type, TypeProperties, CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, OpaqueSimValueSize,
TypeWithDeref, impl_match_variant_as_self, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type,
TypeProperties, TypeWithDeref, impl_match_variant_as_self,
}, },
util::HashMap, util::HashMap,
}; };
use bitvec::{slice::BitSlice, vec::BitVec};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fmt, marker::PhantomData}; use std::{fmt, marker::PhantomData};
@ -69,7 +69,7 @@ impl fmt::Display for FmtDebugInStruct {
struct BundleImpl { struct BundleImpl {
fields: Interned<[BundleField]>, fields: Interned<[BundleField]>,
name_indexes: HashMap<Interned<str>, usize>, name_indexes: HashMap<Interned<str>, usize>,
field_offsets: Interned<[usize]>, field_offsets: Interned<[OpaqueSimValueSize]>,
type_properties: TypeProperties, type_properties: TypeProperties,
} }
@ -89,12 +89,9 @@ impl std::fmt::Debug for BundleImpl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Bundle ")?; f.write_str("Bundle ")?;
f.debug_set() f.debug_set()
.entries( .entries(self.fields.iter().enumerate().map(|(index, field)| {
self.fields field.fmt_debug_in_struct(self.field_offsets[index].bit_width)
.iter() }))
.enumerate()
.map(|(index, field)| field.fmt_debug_in_struct(self.field_offsets[index])),
)
.finish() .finish()
} }
} }
@ -119,6 +116,7 @@ impl BundleTypePropertiesBuilder {
is_storable: true, is_storable: true,
is_castable_from_bits: true, is_castable_from_bits: true,
bit_width: 0, bit_width: 0,
sim_only_values_len: 0,
}) })
} }
pub const fn clone(&self) -> Self { pub const fn clone(&self) -> Self {
@ -126,8 +124,12 @@ impl BundleTypePropertiesBuilder {
} }
#[must_use] #[must_use]
pub const fn field(self, flipped: bool, field_props: TypeProperties) -> Self { pub const fn field(self, flipped: bool, field_props: TypeProperties) -> Self {
let Some(bit_width) = self.0.bit_width.checked_add(field_props.bit_width) else { let Some(OpaqueSimValueSize {
panic!("bundle is too big: bit-width overflowed"); bit_width,
sim_only_values_len,
}) = self.0.size().checked_add(field_props.size())
else {
panic!("bundle is too big: size overflowed");
}; };
if flipped { if flipped {
Self(TypeProperties { Self(TypeProperties {
@ -135,6 +137,7 @@ impl BundleTypePropertiesBuilder {
is_storable: false, is_storable: false,
is_castable_from_bits: false, is_castable_from_bits: false,
bit_width, bit_width,
sim_only_values_len,
}) })
} else { } else {
Self(TypeProperties { Self(TypeProperties {
@ -143,6 +146,7 @@ impl BundleTypePropertiesBuilder {
is_castable_from_bits: self.0.is_castable_from_bits is_castable_from_bits: self.0.is_castable_from_bits
& field_props.is_castable_from_bits, & field_props.is_castable_from_bits,
bit_width, bit_width,
sim_only_values_len,
}) })
} }
} }
@ -167,7 +171,7 @@ impl Bundle {
if let Some(old_index) = name_indexes.insert(name, index) { if let Some(old_index) = name_indexes.insert(name, index) {
panic!("duplicate field name {name:?}: at both index {old_index} and {index}"); panic!("duplicate field name {name:?}: at both index {old_index} and {index}");
} }
field_offsets.push(type_props_builder.0.bit_width); field_offsets.push(type_props_builder.0.size());
type_props_builder = type_props_builder.field(flipped, ty.type_properties()); type_props_builder = type_props_builder.field(flipped, ty.type_properties());
} }
Self(Intern::intern_sized(BundleImpl { Self(Intern::intern_sized(BundleImpl {
@ -183,7 +187,7 @@ impl Bundle {
pub fn field_by_name(&self, name: Interned<str>) -> Option<BundleField> { pub fn field_by_name(&self, name: Interned<str>) -> Option<BundleField> {
Some(self.0.fields[*self.0.name_indexes.get(&name)?]) Some(self.0.fields[*self.0.name_indexes.get(&name)?])
} }
pub fn field_offsets(self) -> Interned<[usize]> { pub fn field_offsets(self) -> Interned<[OpaqueSimValueSize]> {
self.0.field_offsets self.0.field_offsets
} }
pub fn type_properties(self) -> TypeProperties { pub fn type_properties(self) -> TypeProperties {
@ -241,19 +245,27 @@ impl Type for Bundle {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(bits.len(), self.type_properties().bit_width); assert_eq!(self.type_properties().size(), opaque.size());
OpaqueSimValue::from_bitslice(bits) opaque.to_owned()
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
assert_eq!(bits.len(), self.type_properties().bit_width); &self,
assert_eq!(value.bit_width(), self.type_properties().bit_width); value: &mut Self::SimValue,
value.bits_mut().bits_mut().copy_from_bitslice(bits); opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(self.type_properties().size(), opaque.size());
assert_eq!(value.size(), opaque.size());
value.clone_from_slice(opaque);
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
assert_eq!(bits.len(), self.type_properties().bit_width); &self,
assert_eq!(value.bit_width(), self.type_properties().bit_width); value: &Self::SimValue,
bits.copy_from_bitslice(value.bits().bits()); writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(self.type_properties().size(), writer.size());
assert_eq!(value.size(), writer.size());
writer.fill_cloned_from_slice(value.as_slice())
} }
} }
@ -263,29 +275,29 @@ pub trait BundleType: Type<BaseType = Bundle> {
fn fields(&self) -> Interned<[BundleField]>; fn fields(&self) -> Interned<[BundleField]>;
} }
pub struct BundleSimValueFromBits<'a> { pub struct BundleSimValueFromOpaque<'a> {
fields: std::slice::Iter<'static, BundleField>, fields: std::slice::Iter<'static, BundleField>,
bits: &'a BitSlice, opaque: OpaqueSimValueSlice<'a>,
} }
impl<'a> BundleSimValueFromBits<'a> { impl<'a> BundleSimValueFromOpaque<'a> {
#[track_caller] #[track_caller]
pub fn new<T: BundleType>(bundle_ty: T, bits: &'a BitSlice) -> Self { pub fn new<T: BundleType>(bundle_ty: T, opaque: OpaqueSimValueSlice<'a>) -> Self {
let fields = bundle_ty.fields(); let fields = bundle_ty.fields();
assert_eq!( assert_eq!(
bits.len(), opaque.size(),
fields fields
.iter() .iter()
.map(|BundleField { ty, .. }| ty.bit_width()) .map(|BundleField { ty, .. }| ty.size())
.sum::<usize>() .sum::<OpaqueSimValueSize>()
); );
Self { Self {
fields: Interned::into_inner(fields).iter(), fields: Interned::into_inner(fields).iter(),
bits, opaque,
} }
} }
#[track_caller] #[track_caller]
fn field_ty_and_bits<T: Type>(&mut self) -> (T, &'a BitSlice) { fn field_ty_and_opaque<T: Type>(&mut self) -> (T, OpaqueSimValueSlice<'a>) {
let Some(&BundleField { let Some(&BundleField {
name: _, name: _,
flipped: _, flipped: _,
@ -294,59 +306,68 @@ impl<'a> BundleSimValueFromBits<'a> {
else { else {
panic!("tried to read too many fields from BundleSimValueFromBits"); panic!("tried to read too many fields from BundleSimValueFromBits");
}; };
let (field_bits, rest) = self.bits.split_at(ty.bit_width()); let (field_opaque, rest) = self.opaque.split_at(ty.size());
self.bits = rest; self.opaque = rest;
(T::from_canonical(ty), field_bits) (T::from_canonical(ty), field_opaque)
} }
#[track_caller] #[track_caller]
pub fn field_from_bits<T: Type>(&mut self) -> SimValue<T> { pub fn field_from_opaque<T: Type>(&mut self) -> SimValue<T> {
let (field_ty, field_bits) = self.field_ty_and_bits::<T>(); let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>();
SimValue::from_bitslice(field_ty, field_bits) SimValue::from_opaque(field_ty, field_opaque.to_owned())
} }
#[track_caller] #[track_caller]
pub fn field_clone_from_bits<T: Type>(&mut self, field_value: &mut SimValue<T>) { pub fn field_clone_from_opaque<T: Type>(&mut self, field_value: &mut SimValue<T>) {
let (field_ty, field_bits) = self.field_ty_and_bits::<T>(); let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>();
assert_eq!(field_ty, SimValue::ty(field_value)); assert_eq!(field_ty, SimValue::ty(field_value));
SimValue::bits_mut(field_value) SimValue::opaque_mut(field_value).clone_from_slice(field_opaque);
.bits_mut()
.copy_from_bitslice(field_bits);
} }
} }
pub struct BundleSimValueToBits<'a> { pub struct BundleSimValueToOpaque<'a> {
fields: std::slice::Iter<'static, BundleField>, fields: std::slice::Iter<'static, BundleField>,
bits: &'a mut BitSlice, writer: OpaqueSimValueWriter<'a>,
} }
impl<'a> BundleSimValueToBits<'a> { impl<'a> BundleSimValueToOpaque<'a> {
#[track_caller] #[track_caller]
pub fn new<T: BundleType>(bundle_ty: T, bits: &'a mut BitSlice) -> Self { pub fn new<T: BundleType>(bundle_ty: T, writer: OpaqueSimValueWriter<'a>) -> Self {
let fields = bundle_ty.fields(); let fields = bundle_ty.fields();
assert_eq!( assert_eq!(
bits.len(), writer.size(),
fields fields
.iter() .iter()
.map(|BundleField { ty, .. }| ty.bit_width()) .map(|BundleField { ty, .. }| ty.size())
.sum::<usize>() .sum::<OpaqueSimValueSize>()
); );
Self { Self {
fields: Interned::into_inner(fields).iter(), fields: Interned::into_inner(fields).iter(),
bits, writer,
} }
} }
#[track_caller] #[track_caller]
pub fn field_to_bits<T: Type>(&mut self, field_value: &SimValue<T>) { pub fn field<T: Type>(&mut self, field_value: &SimValue<T>) {
let Some(&BundleField { let Some(&BundleField {
name: _, name: _,
flipped: _, flipped: _,
ty, ty,
}) = self.fields.next() }) = self.fields.next()
else { else {
panic!("tried to read too many fields from BundleSimValueFromBits"); panic!("tried to write too many fields with BundleSimValueToOpaque");
}; };
assert_eq!(T::from_canonical(ty), SimValue::ty(field_value)); assert_eq!(T::from_canonical(ty), SimValue::ty(field_value));
self.bits[..ty.bit_width()].copy_from_bitslice(SimValue::bits(field_value).bits()); self.writer.fill_prefix_with(ty.size(), |writer| {
self.bits = &mut std::mem::take(&mut self.bits)[ty.bit_width()..]; writer.fill_cloned_from_slice(SimValue::opaque(field_value).as_slice())
});
}
#[track_caller]
pub fn finish(mut self) -> OpaqueSimValueWritten<'a> {
assert_eq!(
self.fields.next(),
None,
"wrote too few fields with BundleSimValueToOpaque"
);
self.writer
.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
} }
} }
@ -495,23 +516,32 @@ macro_rules! impl_tuples {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
#![allow(unused_mut, unused_variables)] #![allow(unused_mut, unused_variables)]
let mut v = BundleSimValueFromBits::new(*self, bits); let mut v = BundleSimValueFromOpaque::new(*self, opaque);
$(let $var = v.field_from_bits();)* $(let $var = v.field_from_opaque();)*
($($var,)*) ($($var,)*)
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
#![allow(unused_mut, unused_variables)] #![allow(unused_mut, unused_variables)]
let mut v = BundleSimValueFromBits::new(*self, bits); let mut v = BundleSimValueFromOpaque::new(*self, opaque);
let ($($var,)*) = value; let ($($var,)*) = value;
$(v.field_clone_from_bits($var);)* $(v.field_clone_from_opaque($var);)*
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
#![allow(unused_mut, unused_variables)] #![allow(unused_mut, unused_variables)]
let mut v = BundleSimValueToBits::new(*self, bits); let mut v = BundleSimValueToOpaque::new(*self, writer);
let ($($var,)*) = value; let ($($var,)*) = value;
$(v.field_to_bits($var);)* $(v.field($var);)*
v.finish()
} }
} }
impl<$($T: Type,)*> BundleType for ($($T,)*) { impl<$($T: Type,)*> BundleType for ($($T,)*) {
@ -592,12 +622,12 @@ macro_rules! impl_tuples {
let [$($ty_var,)*] = *ty.fields() else { let [$($ty_var,)*] = *ty.fields() else {
panic!("bundle has wrong number of fields"); panic!("bundle has wrong number of fields");
}; };
let mut bits = BitVec::new(); let mut opaque = OpaqueSimValue::empty();
$(let $var = $var.into_sim_value_with_type($ty_var.ty); $(let $var = $var.into_sim_value_with_type($ty_var.ty);
assert_eq!(SimValue::ty(&$var), $ty_var.ty); assert_eq!(SimValue::ty(&$var), $ty_var.ty);
bits.extend_from_bitslice(SimValue::bits(&$var).bits()); opaque.extend_from_slice(SimValue::opaque(&$var).as_slice());
)* )*
bits.into_sim_value_with_type(ty) SimValue::from_opaque(ty, opaque)
} }
} }
impl<$($T: ToSimValueWithType<$Ty>, $Ty: Type,)*> ToSimValueWithType<($($Ty,)*)> for ($($T,)*) { impl<$($T: ToSimValueWithType<$Ty>, $Ty: Type,)*> ToSimValueWithType<($($Ty,)*)> for ($($T,)*) {
@ -723,15 +753,23 @@ impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert!(bits.is_empty()); assert!(opaque.is_empty());
*self *self
} }
fn sim_value_clone_from_bits(&self, _value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
assert!(bits.is_empty()); &self,
_value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert!(opaque.is_empty());
} }
fn sim_value_to_bits(&self, _value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
assert!(bits.is_empty()); &self,
_value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
} }
} }
@ -800,18 +838,15 @@ impl<T: ?Sized> ToSimValueWithType<Bundle> for PhantomData<T> {
#[track_caller] #[track_caller]
fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> { fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue<Bundle> {
assert!(ty.fields().is_empty()); assert!(ty.fields().is_empty());
ToSimValueWithType::into_sim_value_with_type(BitVec::new(), ty) SimValue::from_opaque(ty, OpaqueSimValue::empty())
} }
} }
impl<T: ?Sized> ToSimValueWithType<CanonicalType> for PhantomData<T> { impl<T: ?Sized> ToSimValueWithType<CanonicalType> for PhantomData<T> {
#[track_caller] #[track_caller]
fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> { fn to_sim_value_with_type(&self, canonical_ty: CanonicalType) -> SimValue<CanonicalType> {
let ty = Bundle::from_canonical(ty); let ty = Bundle::from_canonical(canonical_ty);
assert!(ty.fields().is_empty()); assert!(ty.fields().is_empty());
SimValue::into_canonical(ToSimValueWithType::into_sim_value_with_type( SimValue::from_opaque(canonical_ty, OpaqueSimValue::empty())
BitVec::new(),
ty,
))
} }
} }

View file

@ -6,9 +6,12 @@ use crate::{
int::Bool, int::Bool,
reset::{Reset, ResetType}, reset::{Reset, ResetType},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self}, ty::{
CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter,
OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
}; };
use bitvec::slice::BitSlice; use bitvec::{bits, order::Lsb0};
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct Clock; pub struct Clock;
@ -39,19 +42,29 @@ impl Type for Clock {
retval retval
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(bits.len(), 1); assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
bits[0] opaque.bits()[0]
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
assert_eq!(bits.len(), 1); &self,
*value = bits[0]; value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
*value = opaque.bits()[0];
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
assert_eq!(bits.len(), 1); &self,
bits.set(0, *value); value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1));
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(
[bits![0], bits![1]][*value as usize],
))
} }
} }
@ -72,6 +85,7 @@ impl StaticType for Clock {
is_storable: false, is_storable: false,
is_castable_from_bits: true, is_castable_from_bits: true,
bit_width: 1, bit_width: 1,
sim_only_values_len: 0,
}; };
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
} }

View file

@ -16,7 +16,8 @@ use crate::{
sim::value::{SimValue, SimValuePartialEq}, sim::value::{SimValue, SimValuePartialEq},
source_location::SourceLocation, source_location::SourceLocation,
ty::{ ty::{
CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, StaticType, Type, CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, OpaqueSimValueSize,
OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type,
TypeProperties, TypeProperties,
}, },
util::HashMap, util::HashMap,
@ -120,6 +121,7 @@ impl EnumTypePropertiesBuilder {
is_storable: true, is_storable: true,
is_castable_from_bits: true, is_castable_from_bits: true,
bit_width: 0, bit_width: 0,
sim_only_values_len: 0,
}, },
variant_count: 0, variant_count: 0,
} }
@ -138,9 +140,14 @@ impl EnumTypePropertiesBuilder {
is_storable, is_storable,
is_castable_from_bits, is_castable_from_bits,
bit_width, bit_width,
sim_only_values_len,
}) = field_props }) = field_props
{ {
assert!(is_passive, "variant type must be a passive type"); assert!(is_passive, "variant type must be a passive type");
assert!(
sim_only_values_len == 0,
"can't have `SimOnlyValue`s in an Enum"
);
type_properties = TypeProperties { type_properties = TypeProperties {
is_passive: true, is_passive: true,
is_storable: type_properties.is_storable & is_storable, is_storable: type_properties.is_storable & is_storable,
@ -151,6 +158,7 @@ impl EnumTypePropertiesBuilder {
} else { } else {
type_properties.bit_width type_properties.bit_width
}, },
sim_only_values_len: 0,
}; };
} }
Self { Self {
@ -381,19 +389,27 @@ impl Type for Enum {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(bits.len(), self.type_properties().bit_width); assert_eq!(self.type_properties().size(), opaque.size());
OpaqueSimValue::from_bitslice(bits) opaque.to_owned()
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
assert_eq!(bits.len(), self.type_properties().bit_width); &self,
assert_eq!(value.bit_width(), self.type_properties().bit_width); value: &mut Self::SimValue,
value.bits_mut().bits_mut().copy_from_bitslice(bits); opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(self.type_properties().size(), opaque.size());
assert_eq!(value.size(), opaque.size());
value.clone_from_slice(opaque);
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
assert_eq!(bits.len(), self.type_properties().bit_width); &self,
assert_eq!(value.bit_width(), self.type_properties().bit_width); value: &Self::SimValue,
bits.copy_from_bitslice(value.bits().bits()); writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(self.type_properties().size(), writer.size());
assert_eq!(value.size(), writer.size());
writer.fill_cloned_from_slice(value.as_slice())
} }
} }
@ -458,23 +474,25 @@ impl UnknownVariantSimValue {
} }
} }
pub struct EnumSimValueFromBits<'a> { pub struct EnumSimValueFromOpaque<'a> {
variants: Interned<[EnumVariant]>, variants: Interned<[EnumVariant]>,
discriminant: usize, discriminant: usize,
body_bits: &'a BitSlice, body_bits: &'a BitSlice,
} }
impl<'a> EnumSimValueFromBits<'a> { impl<'a> EnumSimValueFromOpaque<'a> {
#[track_caller] #[track_caller]
pub fn new<T: EnumType>(ty: T, bits: &'a BitSlice) -> Self { pub fn new<T: EnumType>(ty: T, opaque: OpaqueSimValueSlice<'a>) -> Self {
let variants = ty.variants(); let variants = ty.variants();
let bit_width = EnumTypePropertiesBuilder::new() let size = EnumTypePropertiesBuilder::new()
.variants(variants) .variants(variants)
.finish() .finish()
.bit_width; .size();
assert_eq!(bit_width, bits.len()); assert!(size.only_bit_width().is_some());
let (discriminant_bits, body_bits) = assert_eq!(size, opaque.size());
bits.split_at(discriminant_bit_width_impl(variants.len())); let (discriminant_bits, body_bits) = opaque
.bits()
.split_at(discriminant_bit_width_impl(variants.len()));
let mut discriminant = 0usize; let mut discriminant = 0usize;
discriminant.view_bits_mut::<Lsb0>()[..discriminant_bits.len()] discriminant.view_bits_mut::<Lsb0>()[..discriminant_bits.len()]
.copy_from_bitslice(discriminant_bits); .copy_from_bitslice(discriminant_bits);
@ -517,7 +535,7 @@ impl<'a> EnumSimValueFromBits<'a> {
(*ty, variant_bits, padding_bits) (*ty, variant_bits, padding_bits)
} }
#[track_caller] #[track_caller]
pub fn unknown_variant_from_bits(self) -> UnknownVariantSimValue { pub fn unknown_variant_from_opaque(self) -> UnknownVariantSimValue {
let None = self.variants.get(self.discriminant) else { let None = self.variants.get(self.discriminant) else {
self.usage_error(false); self.usage_error(false);
}; };
@ -527,7 +545,7 @@ impl<'a> EnumSimValueFromBits<'a> {
) )
} }
#[track_caller] #[track_caller]
pub fn unknown_variant_clone_from_bits(self, value: &mut UnknownVariantSimValue) { pub fn unknown_variant_clone_from_opaque(self, value: &mut UnknownVariantSimValue) {
let None = self.variants.get(self.discriminant) else { let None = self.variants.get(self.discriminant) else {
self.usage_error(true); self.usage_error(true);
}; };
@ -539,14 +557,14 @@ impl<'a> EnumSimValueFromBits<'a> {
.copy_from_bitslice(self.body_bits); .copy_from_bitslice(self.body_bits);
} }
#[track_caller] #[track_caller]
pub fn variant_no_field_from_bits(self) -> EnumPaddingSimValue { pub fn variant_no_field_from_opaque(self) -> EnumPaddingSimValue {
let (None, _variant_bits, padding_bits) = self.known_variant(false) else { let (None, _variant_bits, padding_bits) = self.known_variant(false) else {
self.usage_error(false); self.usage_error(false);
}; };
EnumPaddingSimValue::from_bitslice(padding_bits) EnumPaddingSimValue::from_bitslice(padding_bits)
} }
#[track_caller] #[track_caller]
pub fn variant_with_field_from_bits<T: Type>(self) -> (SimValue<T>, EnumPaddingSimValue) { pub fn variant_with_field_from_opaque<T: Type>(self) -> (SimValue<T>, EnumPaddingSimValue) {
let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(false) else { let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(false) else {
self.usage_error(false); self.usage_error(false);
}; };
@ -566,14 +584,14 @@ impl<'a> EnumSimValueFromBits<'a> {
} }
} }
#[track_caller] #[track_caller]
pub fn variant_no_field_clone_from_bits(self, padding: &mut EnumPaddingSimValue) { pub fn variant_no_field_clone_from_opaque(self, padding: &mut EnumPaddingSimValue) {
let (None, _variant_bits, padding_bits) = self.known_variant(true) else { let (None, _variant_bits, padding_bits) = self.known_variant(true) else {
self.usage_error(true); self.usage_error(true);
}; };
Self::clone_padding_from_bits(padding, padding_bits); Self::clone_padding_from_bits(padding, padding_bits);
} }
#[track_caller] #[track_caller]
pub fn variant_with_field_clone_from_bits<T: Type>( pub fn variant_with_field_clone_from_opaque<T: Type>(
self, self,
value: &mut SimValue<T>, value: &mut SimValue<T>,
padding: &mut EnumPaddingSimValue, padding: &mut EnumPaddingSimValue,
@ -589,35 +607,42 @@ impl<'a> EnumSimValueFromBits<'a> {
} }
} }
pub struct EnumSimValueToBits<'a> { pub struct EnumSimValueToOpaque<'a> {
variants: Interned<[EnumVariant]>, variants: Interned<[EnumVariant]>,
bit_width: usize, bit_width: usize,
discriminant_bit_width: usize, discriminant_bit_width: usize,
bits: &'a mut BitSlice, writer: OpaqueSimValueWriter<'a>,
} }
impl<'a> EnumSimValueToBits<'a> { impl<'a> EnumSimValueToOpaque<'a> {
#[track_caller] #[track_caller]
pub fn new<T: EnumType>(ty: T, bits: &'a mut BitSlice) -> Self { pub fn new<T: EnumType>(ty: T, writer: OpaqueSimValueWriter<'a>) -> Self {
let variants = ty.variants(); let variants = ty.variants();
let bit_width = EnumTypePropertiesBuilder::new() let size = EnumTypePropertiesBuilder::new()
.variants(variants) .variants(variants)
.finish() .finish()
.bit_width; .size();
assert_eq!(bit_width, bits.len()); assert_eq!(size, writer.size());
Self { Self {
variants, variants,
bit_width, bit_width: size
.only_bit_width()
.expect("enums should only contain bits"),
discriminant_bit_width: discriminant_bit_width_impl(variants.len()), discriminant_bit_width: discriminant_bit_width_impl(variants.len()),
bits, writer,
} }
} }
#[track_caller] #[track_caller]
fn discriminant_to_bits(&mut self, mut discriminant: usize) { fn write_discriminant(&mut self, mut discriminant: usize) {
let orig_discriminant = discriminant; let orig_discriminant = discriminant;
let discriminant_bits = let discriminant_bits =
&mut discriminant.view_bits_mut::<Lsb0>()[..self.discriminant_bit_width]; &mut discriminant.view_bits_mut::<Lsb0>()[..self.discriminant_bit_width];
self.bits[..self.discriminant_bit_width].copy_from_bitslice(discriminant_bits); self.writer.fill_prefix_with(
OpaqueSimValueSize::from_bit_width(self.discriminant_bit_width),
|writer| {
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(discriminant_bits))
},
);
discriminant_bits.fill(false); discriminant_bits.fill(false);
assert!( assert!(
discriminant == 0, discriminant == 0,
@ -625,8 +650,11 @@ impl<'a> EnumSimValueToBits<'a> {
); );
} }
#[track_caller] #[track_caller]
pub fn unknown_variant_to_bits(mut self, value: &UnknownVariantSimValue) { pub fn unknown_variant_to_opaque(
self.discriminant_to_bits(value.discriminant); mut self,
value: &UnknownVariantSimValue,
) -> OpaqueSimValueWritten<'a> {
self.write_discriminant(value.discriminant);
let None = self.variants.get(value.discriminant) else { let None = self.variants.get(value.discriminant) else {
panic!("can't use UnknownVariantSimValue to set known discriminant"); panic!("can't use UnknownVariantSimValue to set known discriminant");
}; };
@ -634,45 +662,57 @@ impl<'a> EnumSimValueToBits<'a> {
self.bit_width - self.discriminant_bit_width, self.bit_width - self.discriminant_bit_width,
value.body_bits.width() value.body_bits.width()
); );
self.bits[self.discriminant_bit_width..].copy_from_bitslice(value.body_bits.bits()); self.writer
.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(value.body_bits.bits()))
} }
#[track_caller] #[track_caller]
fn known_variant( fn known_variant(
mut self, mut self,
discriminant: usize, discriminant: usize,
value: Option<&OpaqueSimValue>,
padding: &EnumPaddingSimValue, padding: &EnumPaddingSimValue,
) -> (Option<CanonicalType>, &'a mut BitSlice) { ) -> OpaqueSimValueWritten<'a> {
self.discriminant_to_bits(discriminant); self.write_discriminant(discriminant);
let variant_ty = self.variants[discriminant].ty; let variant_ty = self.variants[discriminant].ty;
let variant_bit_width = variant_ty.map_or(0, CanonicalType::bit_width); let variant_size = variant_ty.map_or(OpaqueSimValueSize::empty(), CanonicalType::size);
let padding_bits = &mut self.bits[self.discriminant_bit_width..][variant_bit_width..]; if let Some(value) = value {
if let Some(padding) = padding.bits() { if variant_ty.is_none() {
assert_eq!(padding.width(), padding_bits.len()); panic!("expected variant to have no field");
padding_bits.copy_from_bitslice(padding.bits()); }
} else { self.writer.fill_prefix_with(variant_size, |writer| {
padding_bits.fill(false); writer.fill_cloned_from_slice(value.as_slice())
});
} else if variant_ty.is_some() {
panic!("expected variant to have a field");
}
if let Some(padding) = padding.bits() {
assert_eq!(padding.ty().type_properties().size(), self.writer.size());
self.writer
.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(padding.bits()))
} else {
self.writer.fill_with_zeros()
} }
let variant_bits = &mut self.bits[self.discriminant_bit_width..][..variant_bit_width];
(variant_ty, variant_bits)
} }
#[track_caller] #[track_caller]
pub fn variant_no_field_to_bits(self, discriminant: usize, padding: &EnumPaddingSimValue) { pub fn variant_no_field_to_opaque(
let (None, _variant_bits) = self.known_variant(discriminant, padding) else { self,
panic!("expected variant to have no field"); discriminant: usize,
}; padding: &EnumPaddingSimValue,
) -> OpaqueSimValueWritten<'a> {
self.known_variant(discriminant, None, padding)
} }
#[track_caller] #[track_caller]
pub fn variant_with_field_to_bits<T: Type>( pub fn variant_with_field_to_opaque<T: Type>(
self, self,
discriminant: usize, discriminant: usize,
value: &SimValue<T>, value: &SimValue<T>,
padding: &EnumPaddingSimValue, padding: &EnumPaddingSimValue,
) { ) -> OpaqueSimValueWritten<'a> {
let (Some(variant_ty), variant_bits) = self.known_variant(discriminant, padding) else { let Some(variant_ty) = self.variants[discriminant].ty else {
panic!("expected variant to have a field"); panic!("expected variant to have no field");
}; };
assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty));
variant_bits.copy_from_bitslice(SimValue::bits(value).bits()); self.known_variant(discriminant, Some(SimValue::opaque(value)), padding)
} }
} }

View file

@ -1937,7 +1937,8 @@ impl<FieldType: Type> FieldAccess<FieldType> {
let field = Expr::ty(base).fields()[field_index]; let field = Expr::ty(base).fields()[field_index];
let field_type = FieldType::from_canonical(field.ty); let field_type = FieldType::from_canonical(field.ty);
let literal_bits = base.to_literal_bits().map(|bits| { let literal_bits = base.to_literal_bits().map(|bits| {
bits[Expr::ty(base).field_offsets()[field_index]..][..field.ty.bit_width()].intern() bits[Expr::ty(base).field_offsets()[field_index].bit_width..][..field.ty.bit_width()]
.intern()
}); });
let target = base.target().map(|base| { let target = base.target().map(|base| {
Intern::intern_sized(base.join(TargetPathElement::intern_sized( Intern::intern_sized(base.join(TargetPathElement::intern_sized(

File diff suppressed because it is too large Load diff

View file

@ -11,10 +11,13 @@ use crate::{
intern::{Intern, Interned, Memoize}, intern::{Intern, Interned, Memoize},
sim::value::{SimValue, ToSimValueWithType}, sim::value::{SimValue, ToSimValueWithType},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self}, ty::{
util::{ConstBool, ConstUsize, GenericConstBool, GenericConstUsize, interned_bit}, CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter,
OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
util::{ConstBool, ConstUsize, GenericConstBool, GenericConstUsize, interned_bit, slice_range},
}; };
use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView};
use num_bigint::{BigInt, BigUint, Sign}; use num_bigint::{BigInt, BigUint, Sign};
use num_traits::{One, Signed, Zero}; use num_traits::{One, Signed, Zero};
use serde::{ use serde::{
@ -26,7 +29,7 @@ use std::{
fmt, fmt,
marker::PhantomData, marker::PhantomData,
num::NonZero, num::NonZero,
ops::{Bound, Index, Not, Range, RangeBounds, RangeInclusive}, ops::{Index, Not, Range, RangeBounds, RangeInclusive},
str::FromStr, str::FromStr,
sync::Arc, sync::Arc,
}; };
@ -645,6 +648,7 @@ macro_rules! impl_int {
is_storable: true, is_storable: true,
is_castable_from_bits: true, is_castable_from_bits: true,
bit_width: self.width, bit_width: self.width,
sim_only_values_len: 0,
} }
} }
} }
@ -678,19 +682,36 @@ macro_rules! impl_int {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(bits.len(), self.width()); assert_eq!(
$value::new(Arc::new(bits.to_bitvec())) opaque.size(),
OpaqueSimValueSize::from_bit_width(self.width())
);
$value::new(Arc::new(opaque.bits().to_bitvec()))
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
assert_eq!(bits.len(), self.width()); &self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(
opaque.size(),
OpaqueSimValueSize::from_bit_width(self.width())
);
assert_eq!(value.width(), self.width()); assert_eq!(value.width(), self.width());
value.bits_mut().copy_from_bitslice(bits); value.bits_mut().copy_from_bitslice(opaque.bits());
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
assert_eq!(bits.len(), self.width()); &self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(
writer.size(),
OpaqueSimValueSize::from_bit_width(self.width())
);
assert_eq!(value.width(), self.width()); assert_eq!(value.width(), self.width());
bits.copy_from_bitslice(value.bits()); writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(value.bits()))
} }
} }
@ -898,6 +919,9 @@ macro_rules! impl_int {
_phantom: PhantomData, _phantom: PhantomData,
} }
} }
pub fn bitvec_mut(&mut self) -> &mut BitVec {
Arc::make_mut(&mut self.bits)
}
} }
}; };
} }
@ -1160,19 +1184,7 @@ pub trait IntType:
Self::Dyn::new(width) Self::Dyn::new(width)
} }
fn slice_index_to_range<I: RangeBounds<usize>>(self, index: I) -> Range<usize> { fn slice_index_to_range<I: RangeBounds<usize>>(self, index: I) -> Range<usize> {
let width = self.width(); slice_range(index, self.width())
let start = match index.start_bound() {
Bound::Included(start) => *start,
Bound::Excluded(start) => *start + 1,
Bound::Unbounded => 0,
};
let end = match index.end_bound() {
Bound::Included(end) => *end + 1,
Bound::Excluded(end) => *end,
Bound::Unbounded => width,
};
assert!(start <= end && end <= width, "slice range out-of-range");
start..end
} }
fn slice_and_shift<I: RangeBounds<usize>>(self, index: I) -> (UInt, usize) { fn slice_and_shift<I: RangeBounds<usize>>(self, index: I) -> (UInt, usize) {
let range = self.slice_index_to_range(index); let range = self.slice_index_to_range(index);
@ -1252,17 +1264,27 @@ impl Type for Bool {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(bits.len(), 1); assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
bits[0] opaque.bits()[0]
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
assert_eq!(bits.len(), 1); &self,
*value = bits[0]; value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
*value = opaque.bits()[0];
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
assert_eq!(bits.len(), 1); &self,
bits.set(0, *value); value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1));
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(
[bits![0], bits![1]][*value as usize],
))
} }
} }
@ -1274,6 +1296,7 @@ impl StaticType for Bool {
is_storable: true, is_storable: true,
is_castable_from_bits: true, is_castable_from_bits: true,
bit_width: 1, bit_width: 1,
sim_only_values_len: 0,
}; };
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
} }

View file

@ -12,9 +12,12 @@ use crate::{
phantom_const::PhantomConst, phantom_const::PhantomConst,
sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType}, sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self}, ty::{
CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
}; };
use bitvec::{order::Lsb0, slice::BitSlice, view::BitView}; use bitvec::{order::Lsb0, view::BitView};
use serde::{ use serde::{
Deserialize, Deserializer, Serialize, Serializer, Deserialize, Deserializer, Serialize, Serializer,
de::{Error, Visitor, value::UsizeDeserializer}, de::{Error, Visitor, value::UsizeDeserializer},
@ -70,16 +73,24 @@ impl Type for UIntInRangeMaskType {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
Bool.sim_value_from_bits(bits) Bool.sim_value_from_opaque(opaque)
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
Bool.sim_value_clone_from_bits(value, bits); &self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
Bool.sim_value_clone_from_opaque(value, opaque);
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
Bool.sim_value_to_bits(value, bits); &self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
Bool.sim_value_to_opaque(value, writer)
} }
} }
@ -353,18 +364,30 @@ macro_rules! define_uint_in_range_type {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(opaque.size(), self.value.type_properties().size());
let mut retval = 0usize; let mut retval = 0usize;
retval.view_bits_mut::<Lsb0>()[..bits.len()].clone_from_bitslice(bits); retval.view_bits_mut::<Lsb0>()[..opaque.bit_width()]
.clone_from_bitslice(opaque.bits());
retval retval
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
*value = self.sim_value_from_bits(bits); &self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
*value = self.sim_value_from_opaque(opaque);
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
bits.clone_from_bitslice(&value.view_bits::<Lsb0>()[..bits.len()]); &self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(
&value.view_bits::<Lsb0>()[..self.value.width()],
))
} }
} }

View file

@ -1066,7 +1066,8 @@ pub fn splat_mask<T: Type>(ty: T, value: Expr<Bool>) -> Expr<AsMask<T>> {
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::Enum(_) => Expr::from_canonical(Expr::canonical(value)), | CanonicalType::Enum(_)
| CanonicalType::DynSimOnlyValueType(_) => Expr::from_canonical(Expr::canonical(value)),
CanonicalType::Array(array) => Expr::from_canonical(Expr::canonical(repeat( CanonicalType::Array(array) => Expr::from_canonical(Expr::canonical(repeat(
splat_mask(array.element(), value), splat_mask(array.element(), value),
array.len(), array.len(),

View file

@ -1524,7 +1524,8 @@ impl TargetState {
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => TargetStateInner::Single { | CanonicalType::Reset(_)
| CanonicalType::DynSimOnlyValueType(_) => TargetStateInner::Single {
declared_in_block, declared_in_block,
written_in_blocks: RefCell::default(), written_in_blocks: RefCell::default(),
}, },

View file

@ -163,6 +163,7 @@ impl ResetsLayout {
CanonicalType::Reset(_) => ResetsLayout::Reset, CanonicalType::Reset(_) => ResetsLayout::Reset,
CanonicalType::Clock(_) => ResetsLayout::NoResets, CanonicalType::Clock(_) => ResetsLayout::NoResets,
CanonicalType::PhantomConst(_) => ResetsLayout::NoResets, CanonicalType::PhantomConst(_) => ResetsLayout::NoResets,
CanonicalType::DynSimOnlyValueType(_) => ResetsLayout::NoResets,
} }
} }
} }
@ -416,7 +417,8 @@ impl Resets {
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => Ok(self.ty), | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => Ok(self.ty),
CanonicalType::Array(ty) => Ok(CanonicalType::Array(Array::new_dyn( CanonicalType::Array(ty) => Ok(CanonicalType::Array(Array::new_dyn(
self.array_elements().substituted_type( self.array_elements().substituted_type(
reset_graph, reset_graph,
@ -1008,7 +1010,8 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
| CanonicalType::Enum(_) | CanonicalType::Enum(_)
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::PhantomConst(_) => unreachable!(), | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => unreachable!(),
$(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)* $(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)*
} }
}; };
@ -1020,7 +1023,8 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
| CanonicalType::Enum(_) | CanonicalType::Enum(_)
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::Reset(_) => unreachable!(), | CanonicalType::Reset(_) => unreachable!(),
CanonicalType::PhantomConst(_) => Expr::expr_enum(arg), CanonicalType::PhantomConst(_) |
CanonicalType::DynSimOnlyValueType(_) => Expr::expr_enum(arg),
$(CanonicalType::$Variant(_) => { $(CanonicalType::$Variant(_) => {
let arg = Expr::<$Variant>::from_canonical(arg); let arg = Expr::<$Variant>::from_canonical(arg);
match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock) match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock)
@ -1683,7 +1687,8 @@ impl RunPassDispatch for AnyReg {
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => unreachable!(), | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => unreachable!(),
} }
}) })
} }

View file

@ -70,7 +70,8 @@ fn contains_any_enum_types(ty: CanonicalType) -> bool {
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => false, | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => false,
} }
} }
} }
@ -514,7 +515,8 @@ impl State {
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => unreachable!(), | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => unreachable!(),
} }
} }
} }
@ -580,7 +582,8 @@ fn connect_port(
| (CanonicalType::AsyncReset(_), _) | (CanonicalType::AsyncReset(_), _)
| (CanonicalType::SyncReset(_), _) | (CanonicalType::SyncReset(_), _)
| (CanonicalType::Reset(_), _) | (CanonicalType::Reset(_), _)
| (CanonicalType::PhantomConst(_), _) => unreachable!( | (CanonicalType::PhantomConst(_), _)
| (CanonicalType::DynSimOnlyValueType(_), _) => unreachable!(
"trying to connect memory ports:\n{:?}\n{:?}", "trying to connect memory ports:\n{:?}\n{:?}",
Expr::ty(lhs), Expr::ty(lhs),
Expr::ty(rhs), Expr::ty(rhs),
@ -928,7 +931,8 @@ impl Folder for State {
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::PhantomConst(_) => canonical_type.default_fold(self), | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => canonical_type.default_fold(self),
} }
} }

View file

@ -194,6 +194,7 @@ impl MemSplit {
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"), | CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"),
CanonicalType::DynSimOnlyValueType(_) => todo!("memory containing sim-only values"),
} }
} }
} }
@ -323,6 +324,9 @@ impl SplitMemState<'_, '_> {
Expr::field(Expr::<Bundle>::from_canonical(e), &field.name) Expr::field(Expr::<Bundle>::from_canonical(e), &field.name)
}, },
|initial_value_element| { |initial_value_element| {
let Some(field_offset) = field_offset.only_bit_width() else {
todo!("memory containing sim-only values");
};
&initial_value_element[field_offset..][..field_ty_bit_width] &initial_value_element[field_offset..][..field_ty_bit_width]
}, },
); );
@ -620,6 +624,7 @@ impl ModuleState {
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"), | CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"),
CanonicalType::DynSimOnlyValueType(_) => todo!("memory containing sim-only values"),
} }
break; break;
} }

View file

@ -30,7 +30,7 @@ use crate::{
phantom_const::PhantomConst, phantom_const::PhantomConst,
reg::Reg, reg::Reg,
reset::{AsyncReset, Reset, ResetType, SyncReset}, reset::{AsyncReset, Reset, ResetType, SyncReset},
sim::ExternModuleSimulation, sim::{ExternModuleSimulation, value::DynSimOnlyValueType},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, Type}, ty::{CanonicalType, Type},
wire::Wire, wire::Wire,

View file

@ -11,11 +11,11 @@ use crate::{
sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType},
source_location::SourceLocation, source_location::SourceLocation,
ty::{ ty::{
CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self, CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
StaticType, Type, TypeProperties, impl_match_variant_as_self,
serde_impls::{SerdeCanonicalType, SerdePhantomConst}, serde_impls::{SerdeCanonicalType, SerdePhantomConst},
}, },
}; };
use bitvec::slice::BitSlice;
use serde::{ use serde::{
Deserialize, Deserializer, Serialize, Serializer, Deserialize, Deserializer, Serialize, Serializer,
de::{DeserializeOwned, Error}, de::{DeserializeOwned, Error},
@ -284,19 +284,27 @@ impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert!(bits.is_empty()); assert!(opaque.is_empty());
*self *self
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
assert!(bits.is_empty()); &self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert!(opaque.is_empty());
assert_eq!(*value, *self); assert_eq!(*value, *self);
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
assert!(bits.is_empty()); &self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(*value, *self); assert_eq!(*value, *self);
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
} }
} }

View file

@ -5,9 +5,12 @@ use crate::{
expr::{Expr, ToExpr, ops}, expr::{Expr, ToExpr, ops},
int::{Bool, SInt, UInt}, int::{Bool, SInt, UInt},
source_location::SourceLocation, source_location::SourceLocation,
ty::{CanonicalType, StaticType, Type, TypeProperties, impl_match_variant_as_self}, ty::{
CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter,
OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
}; };
use bitvec::slice::BitSlice; use bitvec::{bits, order::Lsb0};
mod sealed { mod sealed {
pub trait ResetTypeSealed {} pub trait ResetTypeSealed {}
@ -69,19 +72,29 @@ macro_rules! reset_type {
retval retval
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(bits.len(), 1); assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
bits[0] opaque.bits()[0]
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
assert_eq!(bits.len(), 1); &self,
*value = bits[0]; value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1));
*value = opaque.bits()[0];
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
assert_eq!(bits.len(), 1); &self,
bits.set(0, *value); value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1));
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(
[bits![0], bits![1]][*value as usize],
))
} }
} }
@ -102,6 +115,7 @@ macro_rules! reset_type {
is_storable: false, is_storable: false,
is_castable_from_bits: $is_castable_from_bits, is_castable_from_bits: $is_castable_from_bits,
bit_width: 1, bit_width: 1,
sim_only_values_len: 0,
}; };
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
} }

View file

@ -11,7 +11,7 @@ use crate::{
GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
}, },
}, },
int::{BoolOrIntType, UIntValue}, int::BoolOrIntType,
intern::{Intern, Interned, InternedCompare, PtrEqWithTypeId, SupportsPtrEqWithTypeId}, intern::{Intern, Interned, InternedCompare, PtrEqWithTypeId, SupportsPtrEqWithTypeId},
prelude::*, prelude::*,
reset::ResetType, reset::ResetType,
@ -21,12 +21,18 @@ use crate::{
CompiledValue, CompiledValue,
}, },
interpreter::{ interpreter::{
BreakAction, BreakpointsSet, RunResult, SmallUInt, State, StatePartIndex, BreakAction, BreakpointsSet, RunResult, SmallUInt, State,
StatePartKindBigSlots, StatePartKindMemories, StatePartKindSmallSlots, TypeIndexRange, parts::{
TypeLen, StatePartIndex, StatePartKindBigSlots, StatePartKindMemories,
StatePartKindSimOnlySlots, StatePartKindSmallSlots, TypeIndexRange, TypeLenSingle,
},
}, },
time::{SimDuration, SimInstant}, time::{SimDuration, SimInstant},
value::SimValue, value::{DynSimOnlyValue, DynSimOnlyValueType, SimValue},
},
ty::{
OpaqueSimValue, OpaqueSimValueSize, OpaqueSimValueSizeRange, OpaqueSimValueSlice,
OpaqueSimValueWriter,
}, },
util::{BitSliceWriteWithBase, DebugAsDisplay, HashMap, HashSet}, util::{BitSliceWriteWithBase, DebugAsDisplay, HashMap, HashSet},
}; };
@ -402,6 +408,15 @@ impl_trace_decl! {
name: Interned<str>, name: Interned<str>,
flow: Flow, flow: Flow,
}), }),
SimOnly(TraceSimOnly {
fn location(self) -> _ {
self.location
}
location: TraceLocation,
name: Interned<str>,
ty: DynSimOnlyValueType,
flow: Flow,
}),
}), }),
} }
@ -503,6 +518,12 @@ pub trait TraceWriter: fmt::Debug + 'static {
variant_index: usize, variant_index: usize,
ty: Enum, ty: Enum,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
fn set_signal_sim_only_value(
&mut self,
id: TraceScalarId,
value: Option<&DynSimOnlyValue>,
ty: DynSimOnlyValueType,
) -> Result<(), Self::Error>;
} }
pub struct DynTraceWriterDecls(Box<dyn TraceWriterDeclsDynTrait>); pub struct DynTraceWriterDecls(Box<dyn TraceWriterDeclsDynTrait>);
@ -557,6 +578,12 @@ trait TraceWriterDynTrait: fmt::Debug + 'static {
variant_index: usize, variant_index: usize,
ty: Enum, ty: Enum,
) -> std::io::Result<()>; ) -> std::io::Result<()>;
fn set_signal_sim_only_value_dyn(
&mut self,
id: TraceScalarId,
value: Option<&DynSimOnlyValue>,
ty: DynSimOnlyValueType,
) -> std::io::Result<()>;
} }
impl<T: TraceWriter> TraceWriterDynTrait for T { impl<T: TraceWriter> TraceWriterDynTrait for T {
@ -616,6 +643,14 @@ impl<T: TraceWriter> TraceWriterDynTrait for T {
.map_err(err_into_io)?, .map_err(err_into_io)?,
) )
} }
fn set_signal_sim_only_value_dyn(
&mut self,
id: TraceScalarId,
value: Option<&DynSimOnlyValue>,
ty: DynSimOnlyValueType,
) -> std::io::Result<()> {
Ok(TraceWriter::set_signal_sim_only_value(self, id, value, ty).map_err(err_into_io)?)
}
} }
pub struct DynTraceWriter(Box<dyn TraceWriterDynTrait>); pub struct DynTraceWriter(Box<dyn TraceWriterDynTrait>);
@ -680,6 +715,14 @@ impl TraceWriter for DynTraceWriter {
self.0 self.0
.set_signal_enum_discriminant_dyn(id, variant_index, ty) .set_signal_enum_discriminant_dyn(id, variant_index, ty)
} }
fn set_signal_sim_only_value(
&mut self,
id: TraceScalarId,
value: Option<&DynSimOnlyValue>,
ty: DynSimOnlyValueType,
) -> Result<(), Self::Error> {
self.0.set_signal_sim_only_value_dyn(id, value, ty)
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -723,7 +766,7 @@ where
} }
} }
impl<T: ?Sized + 'static + Send + Sync, I> SimTraceDebug<I> for Box<T> impl<T: ?Sized, I> SimTraceDebug<I> for Box<T>
where where
T: SimTraceDebug<I>, T: SimTraceDebug<I>,
{ {
@ -782,7 +825,7 @@ impl<K: fmt::Debug> SimTraceDebug<TraceScalarId> for SimTrace<K, ()> {
} }
} }
impl<K: fmt::Debug> SimTraceDebug<TraceScalarId> for SimTrace<K, BitVec> { impl<K: fmt::Debug> SimTraceDebug<TraceScalarId> for SimTrace<K, SimTraceState> {
fn fmt(&self, id: TraceScalarId, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, id: TraceScalarId, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { let Self {
kind, kind,
@ -792,8 +835,8 @@ impl<K: fmt::Debug> SimTraceDebug<TraceScalarId> for SimTrace<K, BitVec> {
f.debug_struct("SimTrace") f.debug_struct("SimTrace")
.field("id", &id) .field("id", &id)
.field("kind", kind) .field("kind", kind)
.field("state", &BitSliceWriteWithBase(state)) .field("state", state)
.field("last_state", &BitSliceWriteWithBase(last_state)) .field("last_state", last_state)
.finish() .finish()
} }
} }
@ -844,16 +887,103 @@ pub(crate) enum SimTraceKind {
index: StatePartIndex<StatePartKindSmallSlots>, index: StatePartIndex<StatePartKindSmallSlots>,
ty: Enum, ty: Enum,
}, },
SimOnly {
index: StatePartIndex<StatePartKindSimOnlySlots>,
ty: DynSimOnlyValueType,
},
}
pub(crate) enum SimTraceState {
Bits(BitVec),
SimOnly(Option<Rc<DynSimOnlyValue>>),
}
impl PartialEq for SimTraceState {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(SimTraceState::Bits(l), SimTraceState::Bits(r)) => l == r,
(SimTraceState::Bits(_), _) => false,
(SimTraceState::SimOnly(l), SimTraceState::SimOnly(r)) => match (l, r) {
(None, None) => true,
(None, Some(_)) => false,
(Some(l), Some(r)) => Rc::ptr_eq(l, r) || DynSimOnlyValue::eq(l, r),
(Some(_), None) => false,
},
(SimTraceState::SimOnly(_), _) => todo!(),
}
}
}
impl Clone for SimTraceState {
fn clone(&self) -> Self {
match self {
Self::Bits(v) => Self::Bits(v.clone()),
Self::SimOnly(v) => Self::SimOnly(v.clone()),
}
}
fn clone_from(&mut self, source: &Self) {
match (&mut *self, source) {
(SimTraceState::Bits(dest), SimTraceState::Bits(source)) => {
dest.clone_from_bitslice(source);
}
(SimTraceState::Bits(_), _) => *self = source.clone(),
(SimTraceState::SimOnly(dest), SimTraceState::SimOnly(source)) => {
dest.clone_from(source);
}
(SimTraceState::SimOnly(_), _) => *self = source.clone(),
}
}
}
impl SimTraceState {
fn unwrap_bits_ref(&self) -> &BitVec {
if let SimTraceState::Bits(v) = self {
v
} else {
unreachable!()
}
}
fn unwrap_bits_mut(&mut self) -> &mut BitVec {
if let SimTraceState::Bits(v) = self {
v
} else {
unreachable!()
}
}
fn unwrap_sim_only_ref(&self) -> &Option<Rc<DynSimOnlyValue>> {
if let SimTraceState::SimOnly(v) = self {
v
} else {
unreachable!()
}
}
fn unwrap_sim_only_mut(&mut self) -> &mut Option<Rc<DynSimOnlyValue>> {
if let SimTraceState::SimOnly(v) = self {
v
} else {
unreachable!()
}
}
}
impl fmt::Debug for SimTraceState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SimTraceState::Bits(v) => BitSliceWriteWithBase(v).fmt(f),
SimTraceState::SimOnly(None) => f.write_str("<uninit>"),
SimTraceState::SimOnly(Some(v)) => v.fmt(f),
}
}
} }
impl SimTraceKind { impl SimTraceKind {
fn make_state(self) -> BitVec { fn make_state(self) -> SimTraceState {
match self { match self {
SimTraceKind::BigUInt { index: _, ty } | SimTraceKind::SmallUInt { index: _, ty } => { SimTraceKind::BigUInt { index: _, ty } | SimTraceKind::SmallUInt { index: _, ty } => {
BitVec::repeat(false, ty.width) SimTraceState::Bits(BitVec::repeat(false, ty.width))
} }
SimTraceKind::BigSInt { index: _, ty } | SimTraceKind::SmallSInt { index: _, ty } => { SimTraceKind::BigSInt { index: _, ty } | SimTraceKind::SmallSInt { index: _, ty } => {
BitVec::repeat(false, ty.width) SimTraceState::Bits(BitVec::repeat(false, ty.width))
} }
SimTraceKind::BigBool { index: _ } SimTraceKind::BigBool { index: _ }
| SimTraceKind::BigAsyncReset { index: _ } | SimTraceKind::BigAsyncReset { index: _ }
@ -862,10 +992,13 @@ impl SimTraceKind {
| SimTraceKind::SmallBool { index: _ } | SimTraceKind::SmallBool { index: _ }
| SimTraceKind::SmallAsyncReset { index: _ } | SimTraceKind::SmallAsyncReset { index: _ }
| SimTraceKind::SmallSyncReset { index: _ } | SimTraceKind::SmallSyncReset { index: _ }
| SimTraceKind::SmallClock { index: _ } => BitVec::repeat(false, 1), | SimTraceKind::SmallClock { index: _ } => {
SimTraceKind::EnumDiscriminant { index: _, ty } => { SimTraceState::Bits(BitVec::repeat(false, 1))
BitVec::repeat(false, ty.discriminant_bit_width())
} }
SimTraceKind::EnumDiscriminant { index: _, ty } => {
SimTraceState::Bits(BitVec::repeat(false, ty.discriminant_bit_width()))
}
SimTraceKind::SimOnly { index: _, ty: _ } => SimTraceState::SimOnly(None),
} }
} }
} }
@ -1325,14 +1458,15 @@ impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBitFn {
type Output = bool; type Output = bool;
fn call(self, state: &mut interpreter::State) -> Self::Output { fn call(self, state: &mut interpreter::State) -> Self::Output {
match self.compiled_value.range.len() { match self.compiled_value.range.len().as_single() {
TypeLen::A_SMALL_SLOT => { Some(TypeLenSingle::SmallSlot) => {
state.small_slots[self.compiled_value.range.small_slots.start] != 0 state.small_slots[self.compiled_value.range.small_slots.start] != 0
} }
TypeLen::A_BIG_SLOT => !state.big_slots[self.compiled_value.range.big_slots.start] Some(TypeLenSingle::BigSlot) => !state.big_slots
[self.compiled_value.range.big_slots.start]
.clone() .clone()
.is_zero(), .is_zero(),
_ => unreachable!(), Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(),
} }
} }
} }
@ -1347,13 +1481,13 @@ impl<I: BoolOrIntType> MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBo
fn call(self, state: &mut interpreter::State) -> Self::Output { fn call(self, state: &mut interpreter::State) -> Self::Output {
let Self { compiled_value, io } = self; let Self { compiled_value, io } = self;
match compiled_value.range.len() { match compiled_value.range.len().as_single() {
TypeLen::A_SMALL_SLOT => Expr::ty(io) Some(TypeLenSingle::SmallSlot) => Expr::ty(io)
.value_from_int_wrapping(state.small_slots[compiled_value.range.small_slots.start]), .value_from_int_wrapping(state.small_slots[compiled_value.range.small_slots.start]),
TypeLen::A_BIG_SLOT => Expr::ty(io).value_from_int_wrapping( Some(TypeLenSingle::BigSlot) => Expr::ty(io).value_from_int_wrapping(
state.big_slots[compiled_value.range.big_slots.start].clone(), state.big_slots[compiled_value.range.big_slots.start].clone(),
), ),
_ => unreachable!(), Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(),
} }
} }
} }
@ -1368,12 +1502,7 @@ impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadFn {
fn call(self, state: &mut interpreter::State) -> Self::Output { fn call(self, state: &mut interpreter::State) -> Self::Output {
let Self { compiled_value, io } = self; let Self { compiled_value, io } = self;
SimulationImpl::read_no_settle_helper( SimulationImpl::read_no_settle_helper(state, io, compiled_value)
state,
io,
compiled_value,
UIntValue::new(Arc::new(BitVec::repeat(false, Expr::ty(io).bit_width()))),
)
} }
} }
@ -1409,7 +1538,7 @@ struct SimulationImpl {
extern_modules: Box<[SimulationExternModuleState]>, extern_modules: Box<[SimulationExternModuleState]>,
state_ready_to_run: bool, state_ready_to_run: bool,
trace_decls: TraceModule, trace_decls: TraceModule,
traces: SimTraces<Box<[SimTrace<SimTraceKind, BitVec>]>>, traces: SimTraces<Box<[SimTrace<SimTraceKind, SimTraceState>]>>,
trace_memories: HashMap<StatePartIndex<StatePartKindMemories>, TraceMem>, trace_memories: HashMap<StatePartIndex<StatePartKindMemories>, TraceMem>,
trace_writers: Vec<TraceWriterState<DynTraceWriterDecls>>, trace_writers: Vec<TraceWriterState<DynTraceWriterDecls>>,
instant: SimInstant, instant: SimInstant,
@ -1559,24 +1688,25 @@ impl SimulationImpl {
let id = TraceScalarId(id); let id = TraceScalarId(id);
match kind { match kind {
SimTraceKind::BigUInt { .. } | SimTraceKind::SmallUInt { .. } => { SimTraceKind::BigUInt { .. } | SimTraceKind::SmallUInt { .. } => {
trace_writer.set_signal_uint(id, state)?; trace_writer.set_signal_uint(id, state.unwrap_bits_ref())?;
} }
SimTraceKind::BigSInt { .. } | SimTraceKind::SmallSInt { .. } => { SimTraceKind::BigSInt { .. } | SimTraceKind::SmallSInt { .. } => {
trace_writer.set_signal_sint(id, state)?; trace_writer.set_signal_sint(id, state.unwrap_bits_ref())?;
} }
SimTraceKind::BigBool { .. } | SimTraceKind::SmallBool { .. } => { SimTraceKind::BigBool { .. } | SimTraceKind::SmallBool { .. } => {
trace_writer.set_signal_bool(id, state[0])?; trace_writer.set_signal_bool(id, state.unwrap_bits_ref()[0])?;
} }
SimTraceKind::BigAsyncReset { .. } | SimTraceKind::SmallAsyncReset { .. } => { SimTraceKind::BigAsyncReset { .. } | SimTraceKind::SmallAsyncReset { .. } => {
trace_writer.set_signal_async_reset(id, state[0])?; trace_writer.set_signal_async_reset(id, state.unwrap_bits_ref()[0])?;
} }
SimTraceKind::BigSyncReset { .. } | SimTraceKind::SmallSyncReset { .. } => { SimTraceKind::BigSyncReset { .. } | SimTraceKind::SmallSyncReset { .. } => {
trace_writer.set_signal_sync_reset(id, state[0])?; trace_writer.set_signal_sync_reset(id, state.unwrap_bits_ref()[0])?;
} }
SimTraceKind::BigClock { .. } | SimTraceKind::SmallClock { .. } => { SimTraceKind::BigClock { .. } | SimTraceKind::SmallClock { .. } => {
trace_writer.set_signal_clock(id, state[0])?; trace_writer.set_signal_clock(id, state.unwrap_bits_ref()[0])?;
} }
SimTraceKind::EnumDiscriminant { ty, .. } => { SimTraceKind::EnumDiscriminant { ty, .. } => {
let state = state.unwrap_bits_ref();
let mut variant_index = [0; mem::size_of::<usize>()]; let mut variant_index = [0; mem::size_of::<usize>()];
variant_index.view_bits_mut::<Lsb0>()[0..state.len()] variant_index.view_bits_mut::<Lsb0>()[0..state.len()]
.clone_from_bitslice(state); .clone_from_bitslice(state);
@ -1586,6 +1716,11 @@ impl SimulationImpl {
ty, ty,
)?; )?;
} }
SimTraceKind::SimOnly { ty, .. } => trace_writer.set_signal_sim_only_value(
id,
state.unwrap_sim_only_ref().as_deref(),
ty,
)?,
} }
} }
Ok(trace_writer) Ok(trace_writer)
@ -1617,6 +1752,7 @@ impl SimulationImpl {
} }
match kind { match kind {
SimTraceKind::BigUInt { index, ty: _ } | SimTraceKind::BigSInt { index, ty: _ } => { SimTraceKind::BigUInt { index, ty: _ } | SimTraceKind::BigSInt { index, ty: _ } => {
let state = state.unwrap_bits_mut();
let bigint = &self.state.big_slots[index]; let bigint = &self.state.big_slots[index];
let mut bytes = bigint.to_signed_bytes_le(); let mut bytes = bigint.to_signed_bytes_le();
bytes.resize( bytes.resize(
@ -1631,11 +1767,14 @@ impl SimulationImpl {
| SimTraceKind::BigAsyncReset { index } | SimTraceKind::BigAsyncReset { index }
| SimTraceKind::BigSyncReset { index } | SimTraceKind::BigSyncReset { index }
| SimTraceKind::BigClock { index } => { | SimTraceKind::BigClock { index } => {
state.set(0, !self.state.big_slots[index].is_zero()); state
.unwrap_bits_mut()
.set(0, !self.state.big_slots[index].is_zero());
} }
SimTraceKind::SmallUInt { index, ty: _ } SimTraceKind::SmallUInt { index, ty: _ }
| SimTraceKind::SmallSInt { index, ty: _ } | SimTraceKind::SmallSInt { index, ty: _ }
| SimTraceKind::EnumDiscriminant { index, ty: _ } => { | SimTraceKind::EnumDiscriminant { index, ty: _ } => {
let state = state.unwrap_bits_mut();
let bytes = self.state.small_slots[index].to_le_bytes(); let bytes = self.state.small_slots[index].to_le_bytes();
let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes); let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes);
let bitslice = &bitslice[..state.len()]; let bitslice = &bitslice[..state.len()];
@ -1645,11 +1784,18 @@ impl SimulationImpl {
| SimTraceKind::SmallAsyncReset { index } | SimTraceKind::SmallAsyncReset { index }
| SimTraceKind::SmallSyncReset { index } | SimTraceKind::SmallSyncReset { index }
| SimTraceKind::SmallClock { index } => { | SimTraceKind::SmallClock { index } => {
state.set(0, self.state.small_slots[index] != 0); state
.unwrap_bits_mut()
.set(0, self.state.small_slots[index] != 0);
}
SimTraceKind::SimOnly { index, ty: _ } => {
state
.unwrap_sim_only_mut()
.clone_from(&self.state.sim_only_slots[index]);
} }
} }
if IS_INITIAL_STEP { if IS_INITIAL_STEP {
last_state.copy_from_bitslice(state); last_state.clone_from(state);
} }
} }
} }
@ -1730,7 +1876,7 @@ impl SimulationImpl {
(WaitTarget::Instant(instant), None) => Some(instant), (WaitTarget::Instant(instant), None) => Some(instant),
(WaitTarget::Instant(instant), Some(retval)) => Some(instant.min(retval)), (WaitTarget::Instant(instant), Some(retval)) => Some(instant.min(retval)),
(WaitTarget::Change { key, value }, retval) => { (WaitTarget::Change { key, value }, retval) => {
if Self::value_changed(&mut self.state, key, SimValue::bits(value).bits()) { if Self::value_changed(&mut self.state, key, SimValue::opaque(value)) {
Some(self.instant) Some(self.instant)
} else { } else {
retval retval
@ -1980,14 +2126,14 @@ impl SimulationImpl {
.get_module_mut(which_module) .get_module_mut(which_module)
.write_helper(io, which_module); .write_helper(io, which_module);
self.state_ready_to_run = true; self.state_ready_to_run = true;
match compiled_value.range.len() { match compiled_value.range.len().as_single() {
TypeLen::A_SMALL_SLOT => { Some(TypeLenSingle::SmallSlot) => {
self.state.small_slots[compiled_value.range.small_slots.start] = value as _; self.state.small_slots[compiled_value.range.small_slots.start] = value as _;
} }
TypeLen::A_BIG_SLOT => { Some(TypeLenSingle::BigSlot) => {
self.state.big_slots[compiled_value.range.big_slots.start] = value.into() self.state.big_slots[compiled_value.range.big_slots.start] = value.into()
} }
_ => unreachable!(), Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(),
} }
} }
#[track_caller] #[track_caller]
@ -2013,28 +2159,30 @@ impl SimulationImpl {
.write_helper(Expr::canonical(io), which_module); .write_helper(Expr::canonical(io), which_module);
self.state_ready_to_run = true; self.state_ready_to_run = true;
let value: BigInt = value.into(); let value: BigInt = value.into();
match compiled_value.range.len() { match compiled_value.range.len().as_single() {
TypeLen::A_SMALL_SLOT => { Some(TypeLenSingle::SmallSlot) => {
let mut small_value = value.iter_u64_digits().next().unwrap_or(0); let mut small_value = value.iter_u64_digits().next().unwrap_or(0);
if value.is_negative() { if value.is_negative() {
small_value = small_value.wrapping_neg(); small_value = small_value.wrapping_neg();
} }
self.state.small_slots[compiled_value.range.small_slots.start] = small_value; self.state.small_slots[compiled_value.range.small_slots.start] = small_value;
} }
TypeLen::A_BIG_SLOT => { Some(TypeLenSingle::BigSlot) => {
self.state.big_slots[compiled_value.range.big_slots.start] = value self.state.big_slots[compiled_value.range.big_slots.start] = value
} }
_ => unreachable!(), Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(),
} }
} }
#[track_caller] #[track_caller]
fn read_write_sim_value_helper<Bits: ?Sized>( fn read_write_sim_value_helper<Opaque: ?Sized>(
state: &mut interpreter::State, state: &mut interpreter::State,
compiled_value: CompiledValue<CanonicalType>, compiled_value: CompiledValue<CanonicalType>,
start_bit_index: usize, start_index: OpaqueSimValueSize,
bits: &mut Bits, opaque: &mut Opaque,
read_write_big_scalar: impl Fn(bool, std::ops::Range<usize>, &mut Bits, &mut BigInt) + Copy, read_write_big_scalar: impl Fn(bool, std::ops::Range<usize>, &mut Opaque, &mut BigInt) + Copy,
read_write_small_scalar: impl Fn(bool, std::ops::Range<usize>, &mut Bits, &mut SmallUInt) + Copy, read_write_small_scalar: impl Fn(bool, std::ops::Range<usize>, &mut Opaque, &mut SmallUInt)
+ Copy,
read_write_sim_only_scalar: impl Fn(usize, &mut Opaque, &mut Option<Rc<DynSimOnlyValue>>) + Copy,
) { ) {
match compiled_value.layout.body { match compiled_value.layout.body {
CompiledTypeLayoutBody::Scalar => { CompiledTypeLayoutBody::Scalar => {
@ -2050,28 +2198,35 @@ impl SimulationImpl {
CanonicalType::Reset(_) => false, CanonicalType::Reset(_) => false,
CanonicalType::Clock(_) => false, CanonicalType::Clock(_) => false,
CanonicalType::PhantomConst(_) => unreachable!(), CanonicalType::PhantomConst(_) => unreachable!(),
CanonicalType::DynSimOnlyValueType(_) => false,
}; };
let bit_indexes = let indexes = OpaqueSimValueSizeRange::from(
start_bit_index..start_bit_index + compiled_value.layout.ty.bit_width(); start_index..start_index + compiled_value.layout.ty.size(),
match compiled_value.range.len() { );
TypeLen::A_SMALL_SLOT => read_write_small_scalar( match compiled_value.range.len().as_single() {
Some(TypeLenSingle::SmallSlot) => read_write_small_scalar(
signed, signed,
bit_indexes, indexes.bit_width,
bits, opaque,
&mut state.small_slots[compiled_value.range.small_slots.start], &mut state.small_slots[compiled_value.range.small_slots.start],
), ),
TypeLen::A_BIG_SLOT => read_write_big_scalar( Some(TypeLenSingle::BigSlot) => read_write_big_scalar(
signed, signed,
bit_indexes, indexes.bit_width,
bits, opaque,
&mut state.big_slots[compiled_value.range.big_slots.start], &mut state.big_slots[compiled_value.range.big_slots.start],
), ),
_ => unreachable!(), Some(TypeLenSingle::SimOnlySlot) => read_write_sim_only_scalar(
indexes.sim_only_values_len.start,
opaque,
&mut state.sim_only_slots[compiled_value.range.sim_only_slots.start],
),
None => unreachable!(),
} }
} }
CompiledTypeLayoutBody::Array { element } => { CompiledTypeLayoutBody::Array { element } => {
let ty = <Array>::from_canonical(compiled_value.layout.ty); let ty = <Array>::from_canonical(compiled_value.layout.ty);
let element_bit_width = ty.element().bit_width(); let element_size = ty.element().size();
for element_index in 0..ty.len() { for element_index in 0..ty.len() {
Self::read_write_sim_value_helper( Self::read_write_sim_value_helper(
state, state,
@ -2082,10 +2237,11 @@ impl SimulationImpl {
.index_array(element.layout.len(), element_index), .index_array(element.layout.len(), element_index),
write: None, write: None,
}, },
start_bit_index + element_index * element_bit_width, start_index + element_index * element_size,
bits, opaque,
read_write_big_scalar, read_write_big_scalar,
read_write_small_scalar, read_write_small_scalar,
read_write_sim_only_scalar,
); );
} }
} }
@ -2109,10 +2265,11 @@ impl SimulationImpl {
)), )),
write: None, write: None,
}, },
start_bit_index + offset, start_index + offset,
bits, opaque,
read_write_big_scalar, read_write_big_scalar,
read_write_small_scalar, read_write_small_scalar,
read_write_sim_only_scalar,
); );
} }
} }
@ -2123,48 +2280,93 @@ impl SimulationImpl {
state: &mut interpreter::State, state: &mut interpreter::State,
io: Expr<CanonicalType>, io: Expr<CanonicalType>,
compiled_value: CompiledValue<CanonicalType>, compiled_value: CompiledValue<CanonicalType>,
mut bits: UIntValue,
) -> SimValue<CanonicalType> { ) -> SimValue<CanonicalType> {
SimulationImpl::read_write_sim_value_helper( #[track_caller]
state, fn read_write_sim_only_scalar(
compiled_value, index: usize,
0, writer: &mut OpaqueSimValueWriter<'_>,
bits.bits_mut(), value: &mut Option<Rc<DynSimOnlyValue>>,
|_signed, bit_range, bits, value| { ) {
<UInt>::copy_bits_from_bigint_wrapping(value, &mut bits[bit_range]); let Some(value) = value else {
}, panic!("can't read uninitialized sim-only value");
|_signed, bit_range, bits, value| { };
let bytes = value.to_le_bytes(); assert_eq!(writer.sim_only_values_range().start, index);
let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes); writer.fill_prefix_with(
let bitslice = &bitslice[..bit_range.len()]; OpaqueSimValueSize {
bits[bit_range].clone_from_bitslice(bitslice); bit_width: 0,
}, sim_only_values_len: 1,
); },
SimValue::from_bits(Expr::ty(io), bits) |writer| {
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_parts(
BitSlice::empty(),
std::array::from_ref::<DynSimOnlyValue>(value),
))
},
);
}
let size = Expr::ty(io).size();
let mut opaque = OpaqueSimValue::with_capacity(size);
opaque.rewrite_with(size, |mut writer| {
SimulationImpl::read_write_sim_value_helper(
state,
compiled_value,
OpaqueSimValueSize::empty(),
&mut writer,
|_signed, bit_range, writer, value| {
writer.fill_prefix_with(
OpaqueSimValueSize::from_bit_width(bit_range.len()),
|writer| {
writer.fill_with_bits_with(|bits| {
<UInt>::copy_bits_from_bigint_wrapping(value, bits);
})
},
);
},
|_signed, bit_range, writer, value| {
let bytes = value.to_le_bytes();
let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes);
let bitslice = &bitslice[..bit_range.len()];
writer.fill_prefix_with(
OpaqueSimValueSize::from_bit_width(bit_range.len()),
|writer| {
writer.fill_with_bits_with(|bits| bits.clone_from_bitslice(bitslice))
},
);
},
read_write_sim_only_scalar,
);
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
});
SimValue::from_opaque(Expr::ty(io), opaque)
} }
/// doesn't modify `bits` /// doesn't modify `opaque`
fn value_changed( fn value_changed(
state: &mut interpreter::State, state: &mut interpreter::State,
compiled_value: CompiledValue<CanonicalType>, compiled_value: CompiledValue<CanonicalType>,
mut bits: &BitSlice, mut opaque: &OpaqueSimValue,
) -> bool { ) -> bool {
assert_eq!(bits.len(), compiled_value.layout.ty.bit_width()); assert_eq!(opaque.size(), compiled_value.layout.ty.size());
let any_change = std::cell::Cell::new(false); let any_change = std::cell::Cell::new(false);
SimulationImpl::read_write_sim_value_helper( SimulationImpl::read_write_sim_value_helper(
state, state,
compiled_value, compiled_value,
0, OpaqueSimValueSize::empty(),
&mut bits, &mut opaque,
|_signed, bit_range, bits, value| { |_signed, bit_range, opaque, value| {
if !<UInt>::bits_equal_bigint_wrapping(value, &bits[bit_range]) { if !<UInt>::bits_equal_bigint_wrapping(value, &opaque.bits().bits()[bit_range]) {
any_change.set(true); any_change.set(true);
} }
}, },
|_signed, bit_range, bits, value| { |_signed, bit_range, opaque, value| {
let bytes = value.to_le_bytes(); let bytes = value.to_le_bytes();
let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes); let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes);
let bitslice = &bitslice[..bit_range.len()]; let bitslice = &bitslice[..bit_range.len()];
if bits[bit_range] != *bitslice { if opaque.bits().bits()[bit_range] != *bitslice {
any_change.set(true);
}
},
|index, opaque, value| {
if Some(&opaque.sim_only_values()[index]) != value.as_deref() {
any_change.set(true); any_change.set(true);
} }
}, },
@ -2203,24 +2405,34 @@ impl SimulationImpl {
Self::read_write_sim_value_helper( Self::read_write_sim_value_helper(
&mut self.state, &mut self.state,
compiled_value, compiled_value,
0, OpaqueSimValueSize::empty(),
&mut value.bits().bits(), &mut SimValue::opaque(value),
|signed, bit_range, bits, value| { |signed, bit_range, opaque, value| {
if signed { if signed {
*value = SInt::bits_to_bigint(&bits[bit_range]); *value = SInt::bits_to_bigint(&opaque.bits().bits()[bit_range]);
} else { } else {
*value = UInt::bits_to_bigint(&bits[bit_range]); *value = UInt::bits_to_bigint(&opaque.bits().bits()[bit_range]);
} }
}, },
|signed, bit_range, bits, value| { |signed, bit_range, opaque, value| {
let mut small_value = [0; mem::size_of::<SmallUInt>()]; let mut small_value = [0; mem::size_of::<SmallUInt>()];
if signed && bits[bit_range.clone()].last().as_deref().copied() == Some(true) { if signed
&& opaque.bits().bits()[bit_range.clone()]
.last()
.as_deref()
.copied()
== Some(true)
{
small_value.fill(u8::MAX); small_value.fill(u8::MAX);
} }
small_value.view_bits_mut::<Lsb0>()[0..bit_range.len()] small_value.view_bits_mut::<Lsb0>()[0..bit_range.len()]
.clone_from_bitslice(&bits[bit_range]); .clone_from_bitslice(&opaque.bits().bits()[bit_range]);
*value = SmallUInt::from_le_bytes(small_value); *value = SmallUInt::from_le_bytes(small_value);
}, },
|index, opaque, value: &mut Option<Rc<DynSimOnlyValue>>| match value {
Some(value) => Rc::make_mut(value).clone_from(&opaque.sim_only_values()[index]),
None => *value = Some(Rc::new(opaque.sim_only_values()[index].clone())),
},
); );
} }
#[track_caller] #[track_caller]
@ -2409,6 +2621,21 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for SortedMapDebug<'_, K, V> {
} }
} }
struct SliceAsMapDebug<'a, T>(&'a [Option<T>]);
impl<T: fmt::Debug> fmt::Debug for SliceAsMapDebug<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map()
.entries(
self.0
.iter()
.enumerate()
.filter_map(|(k, v)| Some((k, v.as_ref()?))),
)
.finish()
}
}
impl<T: BundleType> fmt::Debug for Simulation<T> { impl<T: BundleType> fmt::Debug for Simulation<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { sim_impl, io } = self; let Self { sim_impl, io } = self;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -9,60 +9,82 @@ use crate::{
expr::{CastBitsTo, Expr, ToExpr}, expr::{CastBitsTo, Expr, ToExpr},
int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue},
reset::{AsyncReset, Reset, SyncReset}, reset::{AsyncReset, Reset, SyncReset},
ty::{CanonicalType, StaticType, Type}, source_location::SourceLocation,
ty::{
CanonicalType, OpaqueSimValue, OpaqueSimValueSize, OpaqueSimValueSlice,
OpaqueSimValueWriter, StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
util::{ util::{
ConstUsize, ConstUsize, HashMap,
alternating_cell::{AlternatingCell, AlternatingCellMethods}, alternating_cell::{AlternatingCell, AlternatingCellMethods},
}, },
}; };
use bitvec::{slice::BitSlice, vec::BitVec}; use bitvec::{slice::BitSlice, vec::BitVec};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use hashbrown::hash_map::Entry;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _};
use std::{ use std::{
fmt, borrow::Cow,
fmt::{self, Write},
hash::{BuildHasher, Hash, Hasher, RandomState},
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
sync::Arc, sync::{Arc, Mutex},
};
pub(crate) mod sim_only_value_unsafe;
pub use sim_only_value_unsafe::{
DynSimOnlyValue, DynSimOnlyValueType, SimOnlyValue, SimOnlyValueTrait, SimOnlyValueType,
}; };
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Copy, Clone, Eq, PartialEq)]
enum ValidFlags { enum ValidFlags {
BothValid = 0, BothValid = 0,
OnlyValueValid = 1, OnlyValueValid = 1,
OnlyBitsValid = 2, OnlyOpaqueValid = 2,
} }
#[derive(Clone)] #[derive(Clone)]
struct SimValueInner<T: Type> { struct SimValueInner<T: Type> {
value: T::SimValue, value: T::SimValue,
bits: UIntValue, opaque: OpaqueSimValue,
valid_flags: ValidFlags, valid_flags: ValidFlags,
ty: T, ty: T,
sim_only_values_len: usize,
} }
impl<T: Type> SimValueInner<T> { impl<T: Type> SimValueInner<T> {
fn fill_bits(&mut self) { fn size(&self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.opaque.bit_width(),
sim_only_values_len: self.sim_only_values_len,
}
}
fn fill_opaque(&mut self) {
match self.valid_flags { match self.valid_flags {
ValidFlags::BothValid | ValidFlags::OnlyBitsValid => {} ValidFlags::BothValid | ValidFlags::OnlyOpaqueValid => {}
ValidFlags::OnlyValueValid => { ValidFlags::OnlyValueValid => {
self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut()); OpaqueSimValueWriter::rewrite_with(self.size(), &mut self.opaque, |writer| {
self.ty.sim_value_to_opaque(&self.value, writer)
});
self.valid_flags = ValidFlags::BothValid; self.valid_flags = ValidFlags::BothValid;
} }
} }
} }
fn into_bits(mut self) -> UIntValue { fn into_opaque(mut self) -> OpaqueSimValue {
self.fill_bits(); self.fill_opaque();
self.bits self.opaque
} }
fn bits_mut(&mut self) -> &mut UIntValue { fn opaque_mut(&mut self) -> &mut OpaqueSimValue {
self.fill_bits(); self.fill_opaque();
self.valid_flags = ValidFlags::OnlyBitsValid; self.valid_flags = ValidFlags::OnlyOpaqueValid;
&mut self.bits &mut self.opaque
} }
fn fill_value(&mut self) { fn fill_value(&mut self) {
match self.valid_flags { match self.valid_flags {
ValidFlags::BothValid | ValidFlags::OnlyValueValid => {} ValidFlags::BothValid | ValidFlags::OnlyValueValid => {}
ValidFlags::OnlyBitsValid => { ValidFlags::OnlyOpaqueValid => {
self.ty self.ty
.sim_value_clone_from_bits(&mut self.value, self.bits.bits()); .sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice());
self.valid_flags = ValidFlags::BothValid; self.valid_flags = ValidFlags::BothValid;
} }
} }
@ -83,11 +105,13 @@ impl<T: Type> AlternatingCellMethods for SimValueInner<T> {
match self.valid_flags { match self.valid_flags {
ValidFlags::BothValid => return, ValidFlags::BothValid => return,
ValidFlags::OnlyValueValid => { ValidFlags::OnlyValueValid => {
self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut()) OpaqueSimValueWriter::rewrite_with(self.size(), &mut self.opaque, |writer| {
self.ty.sim_value_to_opaque(&self.value, writer)
})
} }
ValidFlags::OnlyBitsValid => self ValidFlags::OnlyOpaqueValid => self
.ty .ty
.sim_value_clone_from_bits(&mut self.value, self.bits.bits()), .sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice()),
} }
self.valid_flags = ValidFlags::BothValid; self.valid_flags = ValidFlags::BothValid;
} }
@ -143,13 +167,15 @@ impl<T: Type + Clone> Clone for SimValue<T> {
impl<T: Type> SimValue<T> { impl<T: Type> SimValue<T> {
#[track_caller] #[track_caller]
pub fn from_bits(ty: T, bits: UIntValue) -> Self { pub fn from_opaque(ty: T, opaque: OpaqueSimValue) -> Self {
assert_eq!(ty.canonical().bit_width(), bits.width()); let size = ty.canonical().size();
assert_eq!(size, opaque.size());
let inner = SimValueInner { let inner = SimValueInner {
value: ty.sim_value_from_bits(bits.bits()), value: ty.sim_value_from_opaque(opaque.as_slice()),
bits, opaque,
valid_flags: ValidFlags::BothValid, valid_flags: ValidFlags::BothValid,
ty, ty,
sim_only_values_len: size.sim_only_values_len,
}; };
Self { Self {
inner: AlternatingCell::new_shared(inner), inner: AlternatingCell::new_shared(inner),
@ -157,14 +183,30 @@ impl<T: Type> SimValue<T> {
} }
#[track_caller] #[track_caller]
pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self { pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self {
Self::from_bits(ty, UIntValue::new(Arc::new(bits.to_bitvec()))) Self::from_bitslice_and_sim_only_values(ty, bits, Vec::new())
}
#[track_caller]
pub fn from_bitslice_and_sim_only_values(
ty: T,
bits: &BitSlice,
sim_only_values: Vec<DynSimOnlyValue>,
) -> Self {
Self::from_opaque(
ty,
OpaqueSimValue::from_bitslice_and_sim_only_values(bits, sim_only_values),
)
} }
pub fn from_value(ty: T, value: T::SimValue) -> Self { pub fn from_value(ty: T, value: T::SimValue) -> Self {
let type_properties = ty.canonical().type_properties();
let inner = SimValueInner { let inner = SimValueInner {
bits: UIntValue::new_dyn(Arc::new(BitVec::repeat(false, ty.canonical().bit_width()))), opaque: OpaqueSimValue::from_bits_and_sim_only_values(
UIntValue::new_dyn(Arc::new(BitVec::repeat(false, type_properties.bit_width))),
Vec::with_capacity(type_properties.sim_only_values_len),
),
value, value,
valid_flags: ValidFlags::OnlyValueValid, valid_flags: ValidFlags::OnlyValueValid,
ty, ty,
sim_only_values_len: type_properties.sim_only_values_len,
}; };
Self { Self {
inner: AlternatingCell::new_unique(inner), inner: AlternatingCell::new_unique(inner),
@ -173,18 +215,24 @@ impl<T: Type> SimValue<T> {
pub fn ty(this: &Self) -> T { pub fn ty(this: &Self) -> T {
this.inner.share().ty this.inner.share().ty
} }
pub fn into_bits(this: Self) -> UIntValue { pub fn into_opaque(this: Self) -> OpaqueSimValue {
this.inner.into_inner().into_bits() this.inner.into_inner().into_opaque()
} }
pub fn into_ty_and_bits(this: Self) -> (T, UIntValue) { pub fn into_ty_and_opaque(this: Self) -> (T, OpaqueSimValue) {
let inner = this.inner.into_inner(); let inner = this.inner.into_inner();
(inner.ty, inner.into_bits()) (inner.ty, inner.into_opaque())
}
pub fn opaque(this: &Self) -> &OpaqueSimValue {
&this.inner.share().opaque
}
pub fn opaque_mut(this: &mut Self) -> &mut OpaqueSimValue {
this.inner.unique().opaque_mut()
} }
pub fn bits(this: &Self) -> &UIntValue { pub fn bits(this: &Self) -> &UIntValue {
&this.inner.share().bits Self::opaque(this).bits()
} }
pub fn bits_mut(this: &mut Self) -> &mut UIntValue { pub fn bits_mut(this: &mut Self) -> &mut UIntValue {
this.inner.unique().bits_mut() Self::opaque_mut(this).bits_mut()
} }
pub fn into_value(this: Self) -> T::SimValue { pub fn into_value(this: Self) -> T::SimValue {
this.inner.into_inner().into_value() this.inner.into_inner().into_value()
@ -197,59 +245,59 @@ impl<T: Type> SimValue<T> {
} }
#[track_caller] #[track_caller]
pub fn from_canonical(v: SimValue<CanonicalType>) -> Self { pub fn from_canonical(v: SimValue<CanonicalType>) -> Self {
let (ty, bits) = SimValue::into_ty_and_bits(v); let (ty, opaque) = SimValue::into_ty_and_opaque(v);
Self::from_bits(T::from_canonical(ty), bits) Self::from_opaque(T::from_canonical(ty), opaque)
} }
pub fn into_canonical(this: Self) -> SimValue<CanonicalType> { pub fn into_canonical(this: Self) -> SimValue<CanonicalType> {
let (ty, bits) = Self::into_ty_and_bits(this); let (ty, opaque) = Self::into_ty_and_opaque(this);
SimValue::from_bits(ty.canonical(), bits) SimValue::from_opaque(ty.canonical(), opaque)
} }
pub fn canonical(this: &Self) -> SimValue<CanonicalType> { pub fn canonical(this: &Self) -> SimValue<CanonicalType> {
SimValue::from_bits(Self::ty(this).canonical(), Self::bits(this).clone()) SimValue::from_opaque(Self::ty(this).canonical(), Self::opaque(this).clone())
} }
#[track_caller] #[track_caller]
pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self
where where
T: IntType, T: IntType,
{ {
let (ty, bits) = SimValue::into_ty_and_bits(v); let (ty, opaque) = SimValue::into_ty_and_opaque(v);
SimValue::from_bits(T::from_dyn_int(ty), bits) SimValue::from_opaque(T::from_dyn_int(ty), opaque)
} }
pub fn into_dyn_int(this: Self) -> SimValue<T::Dyn> pub fn into_dyn_int(this: Self) -> SimValue<T::Dyn>
where where
T: IntType, T: IntType,
{ {
let (ty, bits) = Self::into_ty_and_bits(this); let (ty, opaque) = Self::into_ty_and_opaque(this);
SimValue::from_bits(ty.as_dyn_int(), bits) SimValue::from_opaque(ty.as_dyn_int(), opaque)
} }
pub fn to_dyn_int(this: &Self) -> SimValue<T::Dyn> pub fn to_dyn_int(this: &Self) -> SimValue<T::Dyn>
where where
T: IntType, T: IntType,
{ {
SimValue::from_bits(Self::ty(this).as_dyn_int(), Self::bits(&this).clone()) SimValue::from_opaque(Self::ty(this).as_dyn_int(), Self::opaque(&this).clone())
} }
#[track_caller] #[track_caller]
pub fn from_bundle(v: SimValue<Bundle>) -> Self pub fn from_bundle(v: SimValue<Bundle>) -> Self
where where
T: BundleType, T: BundleType,
{ {
let (ty, bits) = SimValue::into_ty_and_bits(v); let (ty, opaque) = SimValue::into_ty_and_opaque(v);
SimValue::from_bits(T::from_canonical(CanonicalType::Bundle(ty)), bits) SimValue::from_opaque(T::from_canonical(CanonicalType::Bundle(ty)), opaque)
} }
pub fn into_bundle(this: Self) -> SimValue<Bundle> pub fn into_bundle(this: Self) -> SimValue<Bundle>
where where
T: BundleType, T: BundleType,
{ {
let (ty, bits) = Self::into_ty_and_bits(this); let (ty, opaque) = Self::into_ty_and_opaque(this);
SimValue::from_bits(Bundle::from_canonical(ty.canonical()), bits) SimValue::from_opaque(Bundle::from_canonical(ty.canonical()), opaque)
} }
pub fn to_bundle(this: &Self) -> SimValue<Bundle> pub fn to_bundle(this: &Self) -> SimValue<Bundle>
where where
T: BundleType, T: BundleType,
{ {
SimValue::from_bits( SimValue::from_opaque(
Bundle::from_canonical(Self::ty(this).canonical()), Bundle::from_canonical(Self::ty(this).canonical()),
Self::bits(&this).clone(), Self::opaque(&this).clone(),
) )
} }
#[track_caller] #[track_caller]
@ -257,23 +305,23 @@ impl<T: Type> SimValue<T> {
where where
T: EnumType, T: EnumType,
{ {
let (ty, bits) = SimValue::into_ty_and_bits(v); let (ty, opaque) = SimValue::into_ty_and_opaque(v);
SimValue::from_bits(T::from_canonical(CanonicalType::Enum(ty)), bits) SimValue::from_opaque(T::from_canonical(CanonicalType::Enum(ty)), opaque)
} }
pub fn into_enum(this: Self) -> SimValue<Enum> pub fn into_enum(this: Self) -> SimValue<Enum>
where where
T: EnumType, T: EnumType,
{ {
let (ty, bits) = Self::into_ty_and_bits(this); let (ty, opaque) = Self::into_ty_and_opaque(this);
SimValue::from_bits(Enum::from_canonical(ty.canonical()), bits) SimValue::from_opaque(Enum::from_canonical(ty.canonical()), opaque)
} }
pub fn to_enum(this: &Self) -> SimValue<Enum> pub fn to_enum(this: &Self) -> SimValue<Enum>
where where
T: EnumType, T: EnumType,
{ {
SimValue::from_bits( SimValue::from_opaque(
Enum::from_canonical(Self::ty(this).canonical()), Enum::from_canonical(Self::ty(this).canonical()),
Self::bits(&this).clone(), Self::opaque(&this).clone(),
) )
} }
} }
@ -308,7 +356,11 @@ impl<T: Type> ToExpr for SimValue<T> {
#[track_caller] #[track_caller]
fn to_expr(&self) -> Expr<Self::Type> { fn to_expr(&self) -> Expr<Self::Type> {
let inner = self.inner.share(); let inner = self.inner.share();
inner.bits.cast_bits_to(inner.ty) assert_eq!(
inner.sim_only_values_len, 0,
"can't convert sim-only values to Expr"
);
inner.opaque.bits().cast_bits_to(inner.ty)
} }
} }
@ -443,12 +495,15 @@ impl<T: Type> ToSimValueWithType<T> for BitVec {
#[track_caller] #[track_caller]
fn arc_into_sim_value_with_type(self: Arc<Self>, ty: T) -> SimValue<T> { fn arc_into_sim_value_with_type(self: Arc<Self>, ty: T) -> SimValue<T> {
SimValue::from_bits(ty, UIntValue::new_dyn(self)) SimValue::from_opaque(ty, OpaqueSimValue::from_bits(UIntValue::new_dyn(self)))
} }
#[track_caller] #[track_caller]
fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: T) -> SimValue<T> { fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: T) -> SimValue<T> {
SimValue::from_bits(ty, UIntValue::new_dyn(self.clone())) SimValue::from_opaque(
ty,
OpaqueSimValue::from_bits(UIntValue::new_dyn(self.clone())),
)
} }
} }
@ -792,16 +847,18 @@ impl ToSimValueWithType<CanonicalType> for bool {
| CanonicalType::Array(_) | CanonicalType::Array(_)
| CanonicalType::Enum(_) | CanonicalType::Enum(_)
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::PhantomConst(_) => { | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => {
panic!("can't create SimValue from bool: expected value of type: {ty:?}"); panic!("can't create SimValue from bool: expected value of type: {ty:?}");
} }
CanonicalType::Bool(_) CanonicalType::Bool(_)
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) => { | CanonicalType::Clock(_) => SimValue::from_opaque(
SimValue::from_bits(ty, UIntValue::new(Arc::new(BitVec::repeat(*self, 1)))) ty,
} OpaqueSimValue::from_bits(UIntValue::new(Arc::new(BitVec::repeat(*self, 1)))),
),
} }
} }
} }
@ -911,3 +968,330 @@ macro_rules! impl_to_sim_value_for_int_value {
impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType); impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType);
impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType); impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType);
#[derive(Default)]
struct DynSimOnlyValueTypeSerdeTableRest {
from_serde: HashMap<DynSimOnlyValueTypeSerdeId, DynSimOnlyValueType>,
serde_id_random_state: RandomState,
buffer: String,
}
impl DynSimOnlyValueTypeSerdeTableRest {
#[cold]
fn add_new(&mut self, ty: DynSimOnlyValueType) -> DynSimOnlyValueTypeSerdeId {
let mut try_number = 0u64;
let mut hasher = self.serde_id_random_state.build_hasher();
// extract more bits of randomness from TypeId -- its Hash impl only hashes 64-bits
write!(self.buffer, "{:?}", ty.type_id()).expect("shouldn't ever fail");
self.buffer.hash(&mut hasher);
loop {
let mut hasher = hasher.clone();
try_number.hash(&mut hasher);
try_number += 1;
let retval = DynSimOnlyValueTypeSerdeId(std::array::from_fn(|i| {
let mut hasher = hasher.clone();
i.hash(&mut hasher);
hasher.finish() as u32
}));
match self.from_serde.entry(retval) {
Entry::Occupied(_) => continue,
Entry::Vacant(e) => {
e.insert(ty);
return retval;
}
}
}
}
}
#[derive(Default)]
struct DynSimOnlyValueTypeSerdeTable {
to_serde: HashMap<DynSimOnlyValueType, DynSimOnlyValueTypeSerdeId>,
rest: DynSimOnlyValueTypeSerdeTableRest,
}
static DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE: Mutex<Option<DynSimOnlyValueTypeSerdeTable>> =
Mutex::new(None);
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
struct DynSimOnlyValueTypeSerdeId([u32; 4]);
impl From<DynSimOnlyValueType> for DynSimOnlyValueTypeSerdeId {
fn from(ty: DynSimOnlyValueType) -> Self {
let mut locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE
.lock()
.expect("shouldn't be poison");
let DynSimOnlyValueTypeSerdeTable { to_serde, rest } = locked.get_or_insert_default();
match to_serde.entry(ty) {
Entry::Occupied(occupied_entry) => *occupied_entry.get(),
Entry::Vacant(vacant_entry) => *vacant_entry.insert(rest.add_new(ty)),
}
}
}
impl DynSimOnlyValueTypeSerdeId {
fn ty(self) -> Option<DynSimOnlyValueType> {
let locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE
.lock()
.expect("shouldn't be poison");
Some(*locked.as_ref()?.rest.from_serde.get(&self)?)
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
struct DynSimOnlyValueTypeSerde<'a> {
random_id: DynSimOnlyValueTypeSerdeId,
#[serde(borrow)]
type_name: Cow<'a, str>,
}
impl Serialize for DynSimOnlyValueType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
DynSimOnlyValueTypeSerde {
random_id: (*self).into(),
type_name: Cow::Borrowed(self.type_name()),
}
.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for DynSimOnlyValueType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let deserialized = DynSimOnlyValueTypeSerde::deserialize(deserializer)?;
let retval = deserialized
.random_id
.ty()
.filter(|ty| ty.type_name() == deserialized.type_name);
retval.ok_or_else(|| D::Error::custom("doesn't match any DynSimOnlyValueType that was serialized this time this program was run"))
}
}
impl DynSimOnlyValueType {
pub const fn type_properties(self) -> TypeProperties {
TypeProperties {
is_passive: true,
is_storable: true,
is_castable_from_bits: false,
bit_width: 0,
sim_only_values_len: 1,
}
}
pub fn can_connect(self, other: Self) -> bool {
self == other
}
}
impl Type for DynSimOnlyValueType {
type BaseType = DynSimOnlyValueType;
type MaskType = Bool;
type SimValue = DynSimOnlyValue;
impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType {
Bool
}
fn canonical(&self) -> CanonicalType {
CanonicalType::DynSimOnlyValueType(*self)
}
fn from_canonical(canonical_type: CanonicalType) -> Self {
let CanonicalType::DynSimOnlyValueType(v) = canonical_type else {
panic!("expected DynSimOnlyValueType");
};
v
}
fn source_location() -> SourceLocation {
SourceLocation::builtin()
}
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(opaque.size(), self.type_properties().size());
opaque.sim_only_values()[0].clone()
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(opaque.size(), self.type_properties().size());
value.clone_from(&opaque.sim_only_values()[0]);
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> crate::ty::OpaqueSimValueWritten<'w> {
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_parts(
BitSlice::empty(),
std::array::from_ref(value),
))
}
}
impl<T: SimOnlyValueTrait> Type for SimOnlyValueType<T> {
type BaseType = DynSimOnlyValueType;
type MaskType = Bool;
type SimValue = SimOnlyValue<T>;
impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType {
Bool
}
fn canonical(&self) -> CanonicalType {
DynSimOnlyValueType::from(*self).canonical()
}
fn from_canonical(canonical_type: CanonicalType) -> Self {
DynSimOnlyValueType::from_canonical(canonical_type)
.downcast()
.expect("got wrong SimOnlyValueType")
}
fn source_location() -> SourceLocation {
SourceLocation::builtin()
}
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(Self::TYPE_PROPERTIES.size(), opaque.size());
SimOnlyValue::new(
opaque.sim_only_values()[0]
.downcast_ref::<T>()
.expect("type mismatch")
.clone(),
)
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(Self::TYPE_PROPERTIES.size(), opaque.size());
(**value).clone_from(
&opaque.sim_only_values()[0]
.downcast_ref::<T>()
.expect("type mismatch"),
)
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> crate::ty::OpaqueSimValueWritten<'w> {
SimOnlyValue::with_dyn_ref(value, |value| {
writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_parts(
BitSlice::empty(),
std::array::from_ref(value),
))
})
}
}
impl<T: SimOnlyValueTrait> StaticType for SimOnlyValueType<T> {
const TYPE: Self = Self::new();
const MASK_TYPE: Self::MaskType = Bool;
const TYPE_PROPERTIES: TypeProperties = DynSimOnlyValueType::of::<T>().type_properties();
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
}
impl<T: SimOnlyValueTrait> fmt::Debug for SimOnlyValue<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Self::with_dyn_ref(self, |this| fmt::Debug::fmt(this, f))
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename = "SimOnlyValue")]
struct SerdeSimOnlyValue<'a> {
ty: DynSimOnlyValueType,
#[serde(borrow)]
value: Cow<'a, str>,
}
impl Serialize for DynSimOnlyValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
SerdeSimOnlyValue {
ty: self.ty(),
value: Cow::Owned(self.serialize_to_json_string().map_err(S::Error::custom)?),
}
.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for DynSimOnlyValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let SerdeSimOnlyValue { ty, value } = Deserialize::deserialize(deserializer)?;
ty.deserialize_from_json_string(&value)
.map_err(D::Error::custom)
}
}
impl ToSimValueWithType<DynSimOnlyValueType> for DynSimOnlyValue {
#[track_caller]
fn to_sim_value_with_type(&self, ty: DynSimOnlyValueType) -> SimValue<DynSimOnlyValueType> {
assert_eq!(self.ty(), ty, "mismatched type");
SimValue::from_value(ty, self.clone())
}
#[track_caller]
fn into_sim_value_with_type(self, ty: DynSimOnlyValueType) -> SimValue<DynSimOnlyValueType> {
assert_eq!(self.ty(), ty, "mismatched type");
SimValue::from_value(ty, self)
}
}
impl<T: SimOnlyValueTrait> ToSimValueWithType<SimOnlyValueType<T>> for SimOnlyValue<T> {
fn to_sim_value_with_type(&self, ty: SimOnlyValueType<T>) -> SimValue<SimOnlyValueType<T>> {
SimValue::from_value(ty, self.clone())
}
fn into_sim_value_with_type(self, ty: SimOnlyValueType<T>) -> SimValue<SimOnlyValueType<T>> {
SimValue::from_value(ty, self)
}
}
impl ToSimValue for DynSimOnlyValue {
type Type = DynSimOnlyValueType;
fn to_sim_value(&self) -> SimValue<Self::Type> {
SimValue::from_value(self.ty(), self.clone())
}
fn into_sim_value(self) -> SimValue<Self::Type> {
SimValue::from_value(self.ty(), self)
}
}
impl<T: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> {
type Type = SimOnlyValueType<T>;
fn to_sim_value(&self) -> SimValue<Self::Type> {
SimValue::from_value(Default::default(), self.clone())
}
fn into_sim_value(self) -> SimValue<Self::Type> {
SimValue::from_value(Default::default(), self)
}
}

View 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
}
}

View file

@ -10,9 +10,10 @@ use crate::{
TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl, TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl,
TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance, TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance,
TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule,
TraceModuleIO, TraceReg, TraceSInt, TraceScalar, TraceScalarId, TraceScope, TraceSyncReset, TraceModuleIO, TraceReg, TraceSInt, TraceScalar, TraceScalarId, TraceScope, TraceSimOnly,
TraceUInt, TraceWire, TraceWriter, TraceWriterDecls, TraceSyncReset, TraceUInt, TraceWire, TraceWriter, TraceWriterDecls,
time::{SimDuration, SimInstant}, time::{SimDuration, SimInstant},
value::{DynSimOnlyValue, DynSimOnlyValueType},
}, },
util::HashMap, util::HashMap,
}; };
@ -282,6 +283,7 @@ impl WriteTrace for TraceScalar {
Self::Clock(v) => v.write_trace(writer, arg), Self::Clock(v) => v.write_trace(writer, arg),
Self::SyncReset(v) => v.write_trace(writer, arg), Self::SyncReset(v) => v.write_trace(writer, arg),
Self::AsyncReset(v) => v.write_trace(writer, arg), Self::AsyncReset(v) => v.write_trace(writer, arg),
Self::SimOnly(v) => v.write_trace(writer, arg),
} }
} }
} }
@ -547,6 +549,33 @@ impl WriteTrace for TraceAsyncReset {
} }
} }
impl WriteTrace for TraceSimOnly {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgInType {
source_var_type: _,
sink_var_type: _,
duplex_var_type: _,
properties,
scope,
} = arg.in_type();
let Self {
location,
name,
ty,
flow: _,
} = self;
write_vcd_var(
properties,
MemoryElementPartBody::Scalar,
writer,
"string",
1,
location,
scope.new_identifier(name),
)
}
}
impl WriteTrace for TraceScope { impl WriteTrace for TraceScope {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> { fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> {
match self { match self {
@ -1061,6 +1090,20 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> {
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
write_enum_discriminant_value_change(&mut self.writer, variant_index, ty, id.as_usize()) write_enum_discriminant_value_change(&mut self.writer, variant_index, ty, id.as_usize())
} }
fn set_signal_sim_only_value(
&mut self,
id: TraceScalarId,
value: Option<&DynSimOnlyValue>,
_ty: DynSimOnlyValueType,
) -> Result<(), Self::Error> {
match value {
Some(v) => {
write_string_value_change(&mut self.writer, format_args!("{v:?}"), id.as_usize())
}
None => write_string_value_change(&mut self.writer, "<uninit>", id.as_usize()),
}
}
} }
impl<W: io::Write> fmt::Debug for VcdWriter<W> { impl<W: io::Write> fmt::Debug for VcdWriter<W> {

View file

@ -11,13 +11,21 @@ use crate::{
intern::{Intern, Interned}, intern::{Intern, Interned},
phantom_const::PhantomConst, phantom_const::PhantomConst,
reset::{AsyncReset, Reset, SyncReset}, reset::{AsyncReset, Reset, SyncReset},
sim::value::{SimValue, ToSimValueWithType}, sim::value::{DynSimOnlyValue, DynSimOnlyValueType, SimValue, ToSimValueWithType},
source_location::SourceLocation, source_location::SourceLocation,
util::ConstUsize, util::{ConstUsize, slice_range, try_slice_range},
}; };
use bitvec::slice::BitSlice; use bitvec::{slice::BitSlice, vec::BitVec};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned}; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned};
use std::{fmt, hash::Hash, iter::FusedIterator, ops::Index, sync::Arc}; use std::{
fmt,
hash::Hash,
iter::{FusedIterator, Sum},
marker::PhantomData,
mem,
ops::{Add, AddAssign, Bound, Index, Mul, MulAssign, Range, Sub, SubAssign},
sync::Arc,
};
pub(crate) mod serde_impls; pub(crate) mod serde_impls;
@ -28,6 +36,23 @@ pub struct TypeProperties {
pub is_storable: bool, pub is_storable: bool,
pub is_castable_from_bits: bool, pub is_castable_from_bits: bool,
pub bit_width: usize, pub bit_width: usize,
pub sim_only_values_len: usize,
}
impl TypeProperties {
pub const fn size(self) -> OpaqueSimValueSize {
let Self {
is_passive: _,
is_storable: _,
is_castable_from_bits: _,
bit_width,
sim_only_values_len,
} = self;
OpaqueSimValueSize {
bit_width,
sim_only_values_len,
}
}
} }
#[derive(Copy, Clone, Hash, PartialEq, Eq)] #[derive(Copy, Clone, Hash, PartialEq, Eq)]
@ -43,6 +68,7 @@ pub enum CanonicalType {
Reset(Reset), Reset(Reset),
Clock(Clock), Clock(Clock),
PhantomConst(PhantomConst), PhantomConst(PhantomConst),
DynSimOnlyValueType(DynSimOnlyValueType),
} }
impl fmt::Debug for CanonicalType { impl fmt::Debug for CanonicalType {
@ -59,6 +85,7 @@ impl fmt::Debug for CanonicalType {
Self::Reset(v) => v.fmt(f), Self::Reset(v) => v.fmt(f),
Self::Clock(v) => v.fmt(f), Self::Clock(v) => v.fmt(f),
Self::PhantomConst(v) => v.fmt(f), Self::PhantomConst(v) => v.fmt(f),
Self::DynSimOnlyValueType(v) => v.fmt(f),
} }
} }
} }
@ -95,6 +122,7 @@ impl CanonicalType {
CanonicalType::Reset(v) => v.type_properties(), CanonicalType::Reset(v) => v.type_properties(),
CanonicalType::Clock(v) => v.type_properties(), CanonicalType::Clock(v) => v.type_properties(),
CanonicalType::PhantomConst(v) => v.type_properties(), CanonicalType::PhantomConst(v) => v.type_properties(),
CanonicalType::DynSimOnlyValueType(v) => v.type_properties(),
} }
} }
pub fn is_passive(self) -> bool { pub fn is_passive(self) -> bool {
@ -109,6 +137,12 @@ impl CanonicalType {
pub fn bit_width(self) -> usize { pub fn bit_width(self) -> usize {
self.type_properties().bit_width self.type_properties().bit_width
} }
pub fn sim_only_values_len(self) -> usize {
self.type_properties().sim_only_values_len
}
pub fn size(self) -> OpaqueSimValueSize {
self.type_properties().size()
}
pub fn can_connect(self, rhs: Self) -> bool { pub fn can_connect(self, rhs: Self) -> bool {
match self { match self {
CanonicalType::UInt(lhs) => { CanonicalType::UInt(lhs) => {
@ -177,6 +211,12 @@ impl CanonicalType {
}; };
lhs.can_connect(rhs) lhs.can_connect(rhs)
} }
CanonicalType::DynSimOnlyValueType(lhs) => {
let CanonicalType::DynSimOnlyValueType(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
} }
} }
pub(crate) fn as_serde_unexpected_str(self) -> &'static str { pub(crate) fn as_serde_unexpected_str(self) -> &'static str {
@ -287,6 +327,7 @@ impl_base_type!(SyncReset);
impl_base_type!(Reset); impl_base_type!(Reset);
impl_base_type!(Clock); impl_base_type!(Clock);
impl_base_type!(PhantomConst); impl_base_type!(PhantomConst);
impl_base_type!(DynSimOnlyValueType);
impl_base_type_serde!(Bool, "a Bool"); impl_base_type_serde!(Bool, "a Bool");
impl_base_type_serde!(Enum, "an Enum"); impl_base_type_serde!(Enum, "an Enum");
@ -348,9 +389,17 @@ pub trait Type:
fn canonical(&self) -> CanonicalType; fn canonical(&self) -> CanonicalType;
fn from_canonical(canonical_type: CanonicalType) -> Self; fn from_canonical(canonical_type: CanonicalType) -> Self;
fn source_location() -> SourceLocation; fn source_location() -> SourceLocation;
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue; fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue;
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice); fn sim_value_clone_from_opaque(
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice); &self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
);
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w>;
} }
pub trait BaseType: pub trait BaseType:
@ -405,6 +454,7 @@ impl Type for CanonicalType {
CanonicalType::Reset(v) => v.mask_type().canonical(), CanonicalType::Reset(v) => v.mask_type().canonical(),
CanonicalType::Clock(v) => v.mask_type().canonical(), CanonicalType::Clock(v) => v.mask_type().canonical(),
CanonicalType::PhantomConst(v) => v.mask_type().canonical(), CanonicalType::PhantomConst(v) => v.mask_type().canonical(),
CanonicalType::DynSimOnlyValueType(v) => v.mask_type().canonical(),
} }
} }
fn canonical(&self) -> CanonicalType { fn canonical(&self) -> CanonicalType {
@ -416,28 +466,299 @@ impl Type for CanonicalType {
fn source_location() -> SourceLocation { fn source_location() -> SourceLocation {
SourceLocation::builtin() SourceLocation::builtin()
} }
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue { fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(bits.len(), self.bit_width()); assert_eq!(self.type_properties().size(), opaque.size());
OpaqueSimValue::from_bitslice(bits) opaque.to_owned()
} }
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) { fn sim_value_clone_from_opaque(
assert_eq!(bits.len(), self.bit_width()); &self,
assert_eq!(value.bit_width(), self.bit_width()); value: &mut Self::SimValue,
value.bits_mut().bits_mut().copy_from_bitslice(bits); opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(self.type_properties().size(), opaque.size());
assert_eq!(value.size(), opaque.size());
value.clone_from_slice(opaque);
} }
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) { fn sim_value_to_opaque<'w>(
assert_eq!(bits.len(), self.bit_width()); &self,
assert_eq!(value.bit_width(), self.bit_width()); value: &Self::SimValue,
bits.copy_from_bitslice(value.bits().bits()); writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(self.type_properties().size(), writer.size());
assert_eq!(value.size(), writer.size());
writer.fill_cloned_from_slice(value.as_slice())
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)]
#[non_exhaustive]
pub struct OpaqueSimValueSizeRange {
pub bit_width: Range<usize>,
pub sim_only_values_len: Range<usize>,
}
impl OpaqueSimValueSizeRange {
pub fn start(&self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.bit_width.start,
sim_only_values_len: self.sim_only_values_len.start,
}
}
pub fn end(&self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.bit_width.end,
sim_only_values_len: self.sim_only_values_len.end,
}
}
pub fn is_empty(&self) -> bool {
let Self {
bit_width,
sim_only_values_len,
} = self;
bit_width.is_empty() && sim_only_values_len.is_empty()
}
}
impl From<Range<OpaqueSimValueSize>> for OpaqueSimValueSizeRange {
fn from(value: Range<OpaqueSimValueSize>) -> Self {
Self {
bit_width: value.start.bit_width..value.end.bit_width,
sim_only_values_len: value.start.sim_only_values_len..value.end.sim_only_values_len,
}
}
}
impl From<OpaqueSimValueSizeRange> for Range<OpaqueSimValueSize> {
fn from(value: OpaqueSimValueSizeRange) -> Self {
value.start()..value.end()
}
}
pub trait OpaqueSimValueSizeRangeBounds {
fn start_bound(&self) -> Bound<OpaqueSimValueSize>;
fn end_bound(&self) -> Bound<OpaqueSimValueSize>;
}
impl OpaqueSimValueSizeRangeBounds for OpaqueSimValueSizeRange {
fn start_bound(&self) -> Bound<OpaqueSimValueSize> {
Bound::Included(self.start())
}
fn end_bound(&self) -> Bound<OpaqueSimValueSize> {
Bound::Excluded(self.end())
}
}
impl<T: ?Sized + std::ops::RangeBounds<OpaqueSimValueSize>> OpaqueSimValueSizeRangeBounds for T {
fn start_bound(&self) -> Bound<OpaqueSimValueSize> {
std::ops::RangeBounds::start_bound(self).cloned()
}
fn end_bound(&self) -> Bound<OpaqueSimValueSize> {
std::ops::RangeBounds::end_bound(self).cloned()
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)]
#[non_exhaustive]
pub struct OpaqueSimValueSize {
pub bit_width: usize,
pub sim_only_values_len: usize,
}
impl OpaqueSimValueSize {
pub const fn from_bit_width(bit_width: usize) -> Self {
Self::from_bit_width_and_sim_only_values_len(bit_width, 0)
}
pub const fn from_bit_width_and_sim_only_values_len(
bit_width: usize,
sim_only_values_len: usize,
) -> Self {
Self {
bit_width,
sim_only_values_len,
}
}
pub const fn only_bit_width(self) -> Option<usize> {
if let Self {
bit_width,
sim_only_values_len: 0,
} = self
{
Some(bit_width)
} else {
None
}
}
pub const fn empty() -> Self {
Self {
bit_width: 0,
sim_only_values_len: 0,
}
}
pub const fn is_empty(self) -> bool {
let Self {
bit_width,
sim_only_values_len,
} = self;
bit_width == 0 && sim_only_values_len == 0
}
pub const fn checked_mul(self, factor: usize) -> Option<Self> {
let Some(bit_width) = self.bit_width.checked_mul(factor) else {
return None;
};
let Some(sim_only_values_len) = self.sim_only_values_len.checked_mul(factor) else {
return None;
};
Some(Self {
bit_width,
sim_only_values_len,
})
}
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
let Some(bit_width) = self.bit_width.checked_add(rhs.bit_width) else {
return None;
};
let Some(sim_only_values_len) = self
.sim_only_values_len
.checked_add(rhs.sim_only_values_len)
else {
return None;
};
Some(Self {
bit_width,
sim_only_values_len,
})
}
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
let Some(bit_width) = self.bit_width.checked_sub(rhs.bit_width) else {
return None;
};
let Some(sim_only_values_len) = self
.sim_only_values_len
.checked_sub(rhs.sim_only_values_len)
else {
return None;
};
Some(Self {
bit_width,
sim_only_values_len,
})
}
pub fn try_slice_range<R: OpaqueSimValueSizeRangeBounds>(
self,
range: R,
) -> Option<OpaqueSimValueSizeRange> {
let start = range.start_bound();
let end = range.end_bound();
let bit_width = try_slice_range(
(start.map(|v| v.bit_width), end.map(|v| v.bit_width)),
self.bit_width,
)?;
let sim_only_values_len = try_slice_range(
(
start.map(|v| v.sim_only_values_len),
end.map(|v| v.sim_only_values_len),
),
self.sim_only_values_len,
)?;
Some(OpaqueSimValueSizeRange {
bit_width,
sim_only_values_len,
})
}
pub fn slice_range<R: OpaqueSimValueSizeRangeBounds>(
self,
range: R,
) -> OpaqueSimValueSizeRange {
self.try_slice_range(range).expect("range out of bounds")
}
}
impl Mul<usize> for OpaqueSimValueSize {
type Output = OpaqueSimValueSize;
fn mul(self, rhs: usize) -> Self::Output {
self.checked_mul(rhs).expect("multiplication overflowed")
}
}
impl Mul<OpaqueSimValueSize> for usize {
type Output = OpaqueSimValueSize;
fn mul(self, rhs: OpaqueSimValueSize) -> Self::Output {
rhs.checked_mul(self).expect("multiplication overflowed")
}
}
impl Add for OpaqueSimValueSize {
type Output = OpaqueSimValueSize;
fn add(self, rhs: OpaqueSimValueSize) -> Self::Output {
rhs.checked_add(self).expect("addition overflowed")
}
}
impl Sub for OpaqueSimValueSize {
type Output = OpaqueSimValueSize;
fn sub(self, rhs: OpaqueSimValueSize) -> Self::Output {
rhs.checked_sub(self).expect("subtraction underflowed")
}
}
impl MulAssign<usize> for OpaqueSimValueSize {
fn mul_assign(&mut self, rhs: usize) {
*self = *self * rhs;
}
}
impl AddAssign for OpaqueSimValueSize {
fn add_assign(&mut self, rhs: OpaqueSimValueSize) {
*self = *self + rhs;
}
}
impl SubAssign for OpaqueSimValueSize {
fn sub_assign(&mut self, rhs: OpaqueSimValueSize) {
*self = *self - rhs;
}
}
impl Sum for OpaqueSimValueSize {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(OpaqueSimValueSize::empty(), Add::add)
} }
} }
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] #[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct OpaqueSimValue { pub struct OpaqueSimValue {
bits: UIntValue, bits: UIntValue,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
sim_only_values: Vec<DynSimOnlyValue>,
} }
impl OpaqueSimValue { impl OpaqueSimValue {
pub fn empty() -> Self {
Self {
bits: UIntValue::new(Default::default()),
sim_only_values: Vec::new(),
}
}
pub fn with_capacity(capacity: OpaqueSimValueSize) -> Self {
Self {
bits: UIntValue::new(Arc::new(BitVec::with_capacity(capacity.bit_width))),
sim_only_values: Vec::with_capacity(capacity.sim_only_values_len),
}
}
pub fn size(&self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.bits.width(),
sim_only_values_len: self.sim_only_values.len(),
}
}
pub fn is_empty(&self) -> bool {
self.size().is_empty()
}
pub fn bit_width(&self) -> usize { pub fn bit_width(&self) -> usize {
self.bits.width() self.bits.width()
} }
@ -451,11 +772,109 @@ impl OpaqueSimValue {
self.bits self.bits
} }
pub fn from_bits(bits: UIntValue) -> Self { pub fn from_bits(bits: UIntValue) -> Self {
Self { bits } Self {
bits,
sim_only_values: Vec::new(),
}
} }
pub fn from_bitslice(v: &BitSlice) -> Self { pub fn from_bitslice(v: &BitSlice) -> Self {
Self::from_bitslice_and_sim_only_values(v, Vec::new())
}
pub fn from_bitslice_and_sim_only_values(
bits: &BitSlice,
sim_only_values: Vec<DynSimOnlyValue>,
) -> Self {
Self { Self {
bits: UIntValue::new(Arc::new(v.to_bitvec())), bits: UIntValue::new(Arc::new(bits.to_bitvec())),
sim_only_values,
}
}
pub fn from_bits_and_sim_only_values(
bits: UIntValue,
sim_only_values: Vec<DynSimOnlyValue>,
) -> Self {
Self {
bits,
sim_only_values,
}
}
pub fn into_parts(self) -> (UIntValue, Vec<DynSimOnlyValue>) {
let Self {
bits,
sim_only_values,
} = self;
(bits, sim_only_values)
}
pub fn parts_mut(&mut self) -> (&mut UIntValue, &mut Vec<DynSimOnlyValue>) {
let Self {
bits,
sim_only_values,
} = self;
(bits, sim_only_values)
}
pub fn sim_only_values(&self) -> &[DynSimOnlyValue] {
&self.sim_only_values
}
pub fn sim_only_values_mut(&mut self) -> &mut Vec<DynSimOnlyValue> {
&mut self.sim_only_values
}
pub fn as_slice(&self) -> OpaqueSimValueSlice<'_> {
OpaqueSimValueSlice {
bits: self.bits.bits(),
sim_only_values: &self.sim_only_values,
}
}
pub fn slice<R: OpaqueSimValueSizeRangeBounds>(&self, range: R) -> OpaqueSimValueSlice<'_> {
self.as_slice().slice(range)
}
pub fn rewrite_with<F>(&mut self, target_size: OpaqueSimValueSize, f: F)
where
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
{
OpaqueSimValueWriter::rewrite_with(target_size, self, f);
}
pub fn clone_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) {
let OpaqueSimValueSlice {
bits,
sim_only_values,
} = slice;
self.bits.bits_mut().copy_from_bitslice(bits);
self.sim_only_values.clone_from_slice(sim_only_values);
}
pub fn extend_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) {
let OpaqueSimValueSlice {
bits,
sim_only_values,
} = slice;
self.bits.bitvec_mut().extend_from_bitslice(bits);
self.sim_only_values.extend_from_slice(sim_only_values);
}
}
impl<'a> Extend<OpaqueSimValueSlice<'a>> for OpaqueSimValue {
fn extend<T: IntoIterator<Item = OpaqueSimValueSlice<'a>>>(&mut self, iter: T) {
let Self {
bits,
sim_only_values,
} = self;
let bits = bits.bitvec_mut();
for slice in iter {
bits.extend_from_bitslice(slice.bits);
sim_only_values.extend_from_slice(slice.sim_only_values);
}
}
}
impl Extend<OpaqueSimValue> for OpaqueSimValue {
fn extend<T: IntoIterator<Item = OpaqueSimValue>>(&mut self, iter: T) {
let Self {
bits,
sim_only_values,
} = self;
let bits = bits.bitvec_mut();
for value in iter {
bits.extend_from_bitslice(value.bits().bits());
sim_only_values.extend_from_slice(value.sim_only_values());
} }
} }
} }
@ -469,6 +888,213 @@ 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 sim_only_values_range(&self) -> std::ops::Range<usize> {
self.sim_only_values_range.clone()
}
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_bits_with<F: FnOnce(&mut BitSlice)>(self, f: F) -> OpaqueSimValueWritten<'a> {
assert!(self.size().only_bit_width().is_some());
let Self {
bits,
sim_only_values,
sim_only_values_range,
} = self;
f(bits);
assert_eq!(sim_only_values.len(), sim_only_values_range.end);
OpaqueSimValueWritten {
_phantom: PhantomData,
}
}
pub fn fill_with_zeros(self) -> OpaqueSimValueWritten<'a> {
assert!(
self.size().only_bit_width().is_some(),
"can't fill things other than bits with zeros",
);
self.fill_with_bits_with(|bits| bits.fill(false))
}
pub fn fill_prefix_with<F>(&mut self, prefix_size: OpaqueSimValueSize, f: F)
where
F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand
{
let OpaqueSimValueSize {
bit_width,
sim_only_values_len,
} = prefix_size;
assert!(bit_width <= self.bit_width());
assert!(sim_only_values_len <= self.sim_only_values_len());
let next_start = self.sim_only_values_range.start + sim_only_values_len;
let OpaqueSimValueWritten {
_phantom: PhantomData,
} = f(OpaqueSimValueWriter {
bits: &mut self.bits[..bit_width],
sim_only_values: self.sim_only_values,
sim_only_values_range: self.sim_only_values_range.start..next_start,
});
assert!(self.sim_only_values.len() >= next_start);
self.bits = &mut mem::take(&mut self.bits)[bit_width..];
self.sim_only_values_range.start = next_start;
}
}
pub trait StaticType: Type + Default { pub trait StaticType: Type + Default {
const TYPE: Self; const TYPE: Self;
const MASK_TYPE: Self::MaskType; const MASK_TYPE: Self::MaskType;

View file

@ -11,6 +11,7 @@ use crate::{
phantom_const::{PhantomConstCanonicalValue, PhantomConstValue}, phantom_const::{PhantomConstCanonicalValue, PhantomConstValue},
prelude::PhantomConst, prelude::PhantomConst,
reset::{AsyncReset, Reset, SyncReset}, reset::{AsyncReset, Reset, SyncReset},
sim::value::DynSimOnlyValueType,
ty::{BaseType, CanonicalType}, ty::{BaseType, CanonicalType},
}; };
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -63,6 +64,7 @@ pub(crate) enum SerdeCanonicalType<
Reset, Reset,
Clock, Clock,
PhantomConst(ThePhantomConst), PhantomConst(ThePhantomConst),
DynSimOnlyValueType(DynSimOnlyValueType),
} }
impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomConstInner> { impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomConstInner> {
@ -79,6 +81,7 @@ impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomCo
Self::Reset => "a Reset", Self::Reset => "a Reset",
Self::Clock => "a Clock", Self::Clock => "a Clock",
Self::PhantomConst(_) => "a PhantomConst", Self::PhantomConst(_) => "a PhantomConst",
Self::DynSimOnlyValueType(_) => "a SimOnlyValue",
} }
} }
} }
@ -105,6 +108,7 @@ impl<T: BaseType> From<T> for SerdeCanonicalType {
CanonicalType::Reset(Reset {}) => Self::Reset, CanonicalType::Reset(Reset {}) => Self::Reset,
CanonicalType::Clock(Clock {}) => Self::Clock, CanonicalType::Clock(Clock {}) => Self::Clock,
CanonicalType::PhantomConst(ty) => Self::PhantomConst(SerdePhantomConst(ty.get())), CanonicalType::PhantomConst(ty) => Self::PhantomConst(SerdePhantomConst(ty.get())),
CanonicalType::DynSimOnlyValueType(ty) => Self::DynSimOnlyValueType(ty),
} }
} }
} }
@ -125,6 +129,7 @@ impl From<SerdeCanonicalType> for CanonicalType {
SerdeCanonicalType::PhantomConst(value) => { SerdeCanonicalType::PhantomConst(value) => {
Self::PhantomConst(PhantomConst::new(value.0)) Self::PhantomConst(PhantomConst::new(value.0))
} }
SerdeCanonicalType::DynSimOnlyValueType(value) => Self::DynSimOnlyValueType(value),
} }
} }
} }

View file

@ -33,10 +33,11 @@ pub use const_cmp::{
#[doc(inline)] #[doc(inline)]
pub use scoped_ref::ScopedRef; pub use scoped_ref::ScopedRef;
pub(crate) use misc::chain;
#[doc(inline)] #[doc(inline)]
pub use misc::{ pub use misc::{
BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice, RcWriter, interned_bit, BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice, RcWriter, interned_bit,
iter_eq_by, iter_eq_by, slice_range, try_slice_range,
}; };
pub mod job_server; pub mod job_server;

View file

@ -5,6 +5,7 @@ use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView};
use std::{ use std::{
cell::Cell, cell::Cell,
fmt::{self, Debug, Write}, fmt::{self, Debug, Write},
ops::{Bound, Range, RangeBounds},
rc::Rc, rc::Rc,
sync::{Arc, OnceLock}, sync::{Arc, OnceLock},
}; };
@ -209,3 +210,36 @@ impl std::io::Write for RcWriter {
Ok(()) Ok(())
} }
} }
macro_rules! chain {
() => {
std::iter::empty()
};
($first:expr $(, $rest:expr)* $(,)?) => {
{
let retval = IntoIterator::into_iter($first);
$(let retval = Iterator::chain(retval, $rest);)*
retval
}
};
}
pub(crate) use chain;
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")
}

View file

@ -239,6 +239,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -480,6 +485,9 @@ Simulation {
255, 255,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::array_rw, name: <simulator>::array_rw,

View file

@ -30,6 +30,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -84,6 +89,9 @@ Simulation {
0, 0,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::conditional_assignment_last, name: <simulator>::conditional_assignment_last,

View file

@ -22,6 +22,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -60,6 +65,9 @@ Simulation {
5, 5,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::connect_const, name: <simulator>::connect_const,

View file

@ -34,6 +34,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -89,6 +94,9 @@ Simulation {
1, 1,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::connect_const_reset, name: <simulator>::connect_const_reset,

View file

@ -71,6 +71,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -195,6 +200,9 @@ Simulation {
4, 4,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::counter, name: <simulator>::counter,

View file

@ -67,6 +67,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -176,6 +181,9 @@ Simulation {
4, 4,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::counter, name: <simulator>::counter,

View file

@ -30,6 +30,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -80,6 +85,9 @@ Simulation {
6, 6,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::duplicate_names, name: <simulator>::duplicate_names,

View file

@ -529,6 +529,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -1304,6 +1309,9 @@ Simulation {
15, 15,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::enums, name: <simulator>::enums,

View file

@ -22,6 +22,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -50,6 +55,9 @@ Simulation {
1, 1,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::extern_module, name: <simulator>::extern_module,

View file

@ -26,6 +26,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -55,6 +60,9 @@ Simulation {
101, 101,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::extern_module2, name: <simulator>::extern_module2,
@ -211,12 +219,18 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
body: Scalar, body: Scalar,
}, },
range: TypeIndexRange { range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 }, small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 }, big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
}, },
write: None, write: None,
}, },
@ -224,6 +238,7 @@ Simulation {
ty: Clock, ty: Clock,
value: OpaqueSimValue { value: OpaqueSimValue {
bits: 0x1_u1, bits: 0x1_u1,
sim_only_values: [],
}, },
}, },
}, },

View file

@ -175,6 +175,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 1, len: 1,
@ -562,6 +567,9 @@ Simulation {
1, 1,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::memories, name: <simulator>::memories,

View file

@ -224,6 +224,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 1, len: 1,
@ -590,6 +595,9 @@ Simulation {
1, 1,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::memories2, name: <simulator>::memories2,

View file

@ -503,6 +503,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 1, len: 1,
@ -1478,6 +1483,9 @@ Simulation {
0, 0,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::memories3, name: <simulator>::memories3,

View file

@ -82,6 +82,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -208,6 +213,9 @@ Simulation {
15, 15,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::mod1, name: <simulator>::mod1,

View file

@ -283,6 +283,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -691,6 +696,9 @@ Simulation {
0, 0,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::ripple_counter, name: <simulator>::ripple_counter,
@ -815,12 +823,18 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
body: Scalar, body: Scalar,
}, },
range: TypeIndexRange { range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 3, len: 0 }, small_slots: StatePartIndexRange<SmallSlots> { start: 3, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 33, len: 1 }, big_slots: StatePartIndexRange<BigSlots> { start: 33, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
}, },
write: None, write: None,
}, },
@ -828,6 +842,7 @@ Simulation {
ty: Clock, ty: Clock,
value: OpaqueSimValue { value: OpaqueSimValue {
bits: 0x0_u1, bits: 0x0_u1,
sim_only_values: [],
}, },
}, },
}, },
@ -912,12 +927,18 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
body: Scalar, body: Scalar,
}, },
range: TypeIndexRange { range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 6, len: 0 }, small_slots: StatePartIndexRange<SmallSlots> { start: 6, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 44, len: 1 }, big_slots: StatePartIndexRange<BigSlots> { start: 44, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
}, },
write: None, write: None,
}, },
@ -925,6 +946,7 @@ Simulation {
ty: Clock, ty: Clock,
value: OpaqueSimValue { value: OpaqueSimValue {
bits: 0x0_u1, bits: 0x0_u1,
sim_only_values: [],
}, },
}, },
}, },
@ -1009,12 +1031,18 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
body: Scalar, body: Scalar,
}, },
range: TypeIndexRange { range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 9, len: 0 }, small_slots: StatePartIndexRange<SmallSlots> { start: 9, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 55, len: 1 }, big_slots: StatePartIndexRange<BigSlots> { start: 55, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
}, },
write: None, write: None,
}, },
@ -1022,6 +1050,7 @@ Simulation {
ty: Clock, ty: Clock,
value: OpaqueSimValue { value: OpaqueSimValue {
bits: 0x0_u1, bits: 0x0_u1,
sim_only_values: [],
}, },
}, },
}, },

View file

@ -83,6 +83,11 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -257,6 +262,9 @@ Simulation {
0, 0,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::shift_register, name: <simulator>::shift_register,

View file

@ -50,7 +50,8 @@
"SyncReset": "Visible", "SyncReset": "Visible",
"Reset": "Visible", "Reset": "Visible",
"Clock": "Visible", "Clock": "Visible",
"PhantomConst": "Visible" "PhantomConst": "Visible",
"DynSimOnlyValueType": "Visible"
} }
}, },
"Bundle": { "Bundle": {
@ -1271,6 +1272,11 @@
}, },
"generics": "<T: ?Sized + crate::phantom_const::PhantomConstValue>" "generics": "<T: ?Sized + crate::phantom_const::PhantomConstValue>"
}, },
"DynSimOnlyValueType": {
"data": {
"$kind": "Opaque"
}
},
"ExternModuleSimulation": { "ExternModuleSimulation": {
"data": { "data": {
"$kind": "Opaque" "$kind": "Opaque"