Compare commits

..

5 commits

Author SHA1 Message Date
9dd3b7e7e4
add simulator support for sim-only values -- still needs tests
Some checks failed
/ deps (pull_request) Successful in 11m43s
/ test (pull_request) Failing after 2m53s
2025-09-05 19:13:21 -07:00
b5b1ee866c
converted to using get_state_part_kinds! 2025-09-05 19:10:06 -07:00
f0e3aef061
add get_state_part_kinds! macro 2025-09-05 19:07:07 -07:00
6d36698adf
move public paths of sim::{Compiled,Compiler} to sim::compiler 2025-08-26 19:23:21 -07:00
e7e831cf00
split out simulator compiler into a separate module 2025-08-26 19:17:21 -07:00
47 changed files with 9409 additions and 7065 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 ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=>
#ident: v.field_from_bits(),
}
}));
let sim_value_clone_from_bits_fields =
let sim_value_from_opaque_fields =
Vec::from_iter(fields.named().into_iter().map(|field| {
let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=>
v.field_clone_from_bits(&mut value.#ident);
#ident: v.field_from_opaque(),
}
}));
let sim_value_to_bits_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
let sim_value_clone_from_opaque_fields =
Vec::from_iter(fields.named().into_iter().map(|field| {
let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=>
v.field_clone_from_opaque(&mut value.#ident);
}
}));
let sim_value_to_opaque_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
let ident: &Ident = field.ident().as_ref().unwrap();
quote_spanned! {span=>
v.field_to_bits(&value.#ident);
v.field(&value.#ident);
}
}));
let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
@ -745,33 +746,34 @@ impl ToTokens for ParsedBundle {
fn source_location() -> ::fayalite::source_location::SourceLocation {
::fayalite::source_location::SourceLocation::caller()
}
fn sim_value_from_bits(
fn sim_value_from_opaque(
&self,
bits: &::fayalite::bitvec::slice::BitSlice,
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) -> <Self as ::fayalite::ty::Type>::SimValue {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits);
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#mask_type_sim_value_ident {
#(#sim_value_from_bits_fields)*
#(#sim_value_from_opaque_fields)*
}
}
fn sim_value_clone_from_bits(
fn sim_value_clone_from_opaque(
&self,
value: &mut <Self as ::fayalite::ty::Type>::SimValue,
bits: &::fayalite::bitvec::slice::BitSlice,
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits);
#(#sim_value_clone_from_bits_fields)*
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#(#sim_value_clone_from_opaque_fields)*
}
fn sim_value_to_bits(
fn sim_value_to_opaque<'__w>(
&self,
value: &<Self as ::fayalite::ty::Type>::SimValue,
bits: &mut ::fayalite::bitvec::slice::BitSlice,
) {
writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits);
#(#sim_value_to_bits_fields)*
let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer);
#(#sim_value_to_opaque_fields)*
v.finish()
}
}
#[automatically_derived]
@ -894,33 +896,34 @@ impl ToTokens for ParsedBundle {
fn source_location() -> ::fayalite::source_location::SourceLocation {
::fayalite::source_location::SourceLocation::caller()
}
fn sim_value_from_bits(
fn sim_value_from_opaque(
&self,
bits: &::fayalite::bitvec::slice::BitSlice,
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) -> <Self as ::fayalite::ty::Type>::SimValue {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits);
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#sim_value_ident {
#(#sim_value_from_bits_fields)*
#(#sim_value_from_opaque_fields)*
}
}
fn sim_value_clone_from_bits(
fn sim_value_clone_from_opaque(
&self,
value: &mut <Self as ::fayalite::ty::Type>::SimValue,
bits: &::fayalite::bitvec::slice::BitSlice,
opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>,
) {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueFromBits::new(*self, bits);
#(#sim_value_clone_from_bits_fields)*
let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque);
#(#sim_value_clone_from_opaque_fields)*
}
fn sim_value_to_bits(
fn sim_value_to_opaque<'__w>(
&self,
value: &<Self as ::fayalite::ty::Type>::SimValue,
bits: &mut ::fayalite::bitvec::slice::BitSlice,
) {
writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>,
) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> {
#![allow(unused_mut, unused_variables)]
let mut v = ::fayalite::bundle::BundleSimValueToBits::new(*self, bits);
#(#sim_value_to_bits_fields)*
let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer);
#(#sim_value_to_opaque_fields)*
v.finish()
}
}
#[automatically_derived]

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

@ -163,6 +163,7 @@ impl ResetsLayout {
CanonicalType::Reset(_) => ResetsLayout::Reset,
CanonicalType::Clock(_) => ResetsLayout::NoResets,
CanonicalType::PhantomConst(_) => ResetsLayout::NoResets,
CanonicalType::DynSimOnlyValueType(_) => ResetsLayout::NoResets,
}
}
}
@ -416,7 +417,8 @@ impl Resets {
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => Ok(self.ty),
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => Ok(self.ty),
CanonicalType::Array(ty) => Ok(CanonicalType::Array(Array::new_dyn(
self.array_elements().substituted_type(
reset_graph,
@ -1008,7 +1010,8 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
| CanonicalType::Enum(_)
| CanonicalType::Bundle(_)
| CanonicalType::Reset(_)
| CanonicalType::PhantomConst(_) => unreachable!(),
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => unreachable!(),
$(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::Bundle(_)
| CanonicalType::Reset(_) => unreachable!(),
CanonicalType::PhantomConst(_) => Expr::expr_enum(arg),
CanonicalType::PhantomConst(_) |
CanonicalType::DynSimOnlyValueType(_) => Expr::expr_enum(arg),
$(CanonicalType::$Variant(_) => {
let arg = Expr::<$Variant>::from_canonical(arg);
match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock)
@ -1683,7 +1687,8 @@ impl RunPassDispatch for AnyReg {
| CanonicalType::Bundle(_)
| CanonicalType::Reset(_)
| 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::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => false,
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => false,
}
}
}
@ -514,7 +515,8 @@ impl State {
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => unreachable!(),
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnlyValueType(_) => unreachable!(),
}
}
}
@ -580,7 +582,8 @@ fn connect_port(
| (CanonicalType::AsyncReset(_), _)
| (CanonicalType::SyncReset(_), _)
| (CanonicalType::Reset(_), _)
| (CanonicalType::PhantomConst(_), _) => unreachable!(
| (CanonicalType::PhantomConst(_), _)
| (CanonicalType::DynSimOnlyValueType(_), _) => unreachable!(
"trying to connect memory ports:\n{:?}\n{:?}",
Expr::ty(lhs),
Expr::ty(rhs),
@ -928,7 +931,8 @@ impl Folder for State {
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| 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::SyncReset(_)
| 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)
},
|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]
},
);
@ -620,6 +624,7 @@ impl ModuleState {
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"),
CanonicalType::DynSimOnlyValueType(_) => todo!("memory containing sim-only values"),
}
break;
}

View file

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

View file

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

View file

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

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

File diff suppressed because it is too large Load diff

View file

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

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,
TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance,
TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule,
TraceModuleIO, TraceReg, TraceSInt, TraceScalar, TraceScalarId, TraceScope, TraceSyncReset,
TraceUInt, TraceWire, TraceWriter, TraceWriterDecls,
TraceModuleIO, TraceReg, TraceSInt, TraceScalar, TraceScalarId, TraceScope, TraceSimOnly,
TraceSyncReset, TraceUInt, TraceWire, TraceWriter, TraceWriterDecls,
time::{SimDuration, SimInstant},
value::{DynSimOnlyValue, DynSimOnlyValueType},
},
util::HashMap,
};
@ -282,6 +283,7 @@ impl WriteTrace for TraceScalar {
Self::Clock(v) => v.write_trace(writer, arg),
Self::SyncReset(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 {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> {
match self {
@ -1061,6 +1090,20 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> {
) -> Result<(), Self::Error> {
write_enum_discriminant_value_change(&mut self.writer, variant_index, ty, id.as_usize())
}
fn set_signal_sim_only_value(
&mut self,
id: TraceScalarId,
value: 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> {

View file

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

View file

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

View file

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

View file

@ -5,6 +5,7 @@ use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView};
use std::{
cell::Cell,
fmt::{self, Debug, Write},
ops::{Bound, Range, RangeBounds},
rc::Rc,
sync::{Arc, OnceLock},
};
@ -209,3 +210,36 @@ impl std::io::Write for RcWriter {
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> {
len: 0,
@ -480,6 +485,9 @@ Simulation {
255,
],
},
sim_only_slots: StatePart {
value: [],
},
},
io: Instance {
name: <simulator>::array_rw,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -45,6 +45,64 @@ note: required by a bound in `fayalite::intern::Interned`
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned`
error[E0277]: `NonNull<()>` cannot be sent between threads safely
--> tests/ui/simvalue_is_not_internable.rs:11:26
|
11 | fn f(v: SimValue<()>) -> Interned<SimValue<()>> {
| ^^^^^^^^^^^^^^^^^^^^^^ `NonNull<()>` cannot be sent between threads safely
|
= help: within `SimValue<()>`, the trait `Send` is not implemented for `NonNull<()>`
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
| pub struct DynSimOnlyValue {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `PhantomData<DynSimOnlyValue>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: PointeeSized>;
| ^^^^^^^^^^^
note: required because it appears within the type `alloc::raw_vec::RawVec<DynSimOnlyValue>`
--> $RUST/alloc/src/raw_vec/mod.rs
|
| pub(crate) struct RawVec<T, A: Allocator = Global> {
| ^^^^^^
note: required because it appears within the type `Vec<DynSimOnlyValue>`
--> $RUST/alloc/src/vec/mod.rs
|
| pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| ^^^
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
| pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
|
| struct SimValueInner<T: Type> {
| ^^^^^^^^^^^^^
note: required because it appears within the type `UnsafeCell<value::SimValueInner<()>>`
--> $RUST/core/src/cell.rs
|
| pub struct UnsafeCell<T: ?Sized> {
| ^^^^^^^^^^
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `fayalite::intern::Interned`
--> src/intern.rs
|
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned`
error[E0277]: the trait bound `SimValue<()>: Intern` is not satisfied
--> tests/ui/simvalue_is_not_internable.rs:12:26
|
@ -138,6 +196,73 @@ help: consider dereferencing here
12 | Intern::intern_sized(*v)
| +
error[E0277]: `NonNull<()>` cannot be sent between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:26
|
12 | Intern::intern_sized(v)
| -------------------- ^ `NonNull<()>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
= help: within `SimValue<()>`, the trait `Send` is not implemented for `NonNull<()>`
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
| pub struct DynSimOnlyValue {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `PhantomData<DynSimOnlyValue>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: PointeeSized>;
| ^^^^^^^^^^^
note: required because it appears within the type `alloc::raw_vec::RawVec<DynSimOnlyValue>`
--> $RUST/alloc/src/raw_vec/mod.rs
|
| pub(crate) struct RawVec<T, A: Allocator = Global> {
| ^^^^^^
note: required because it appears within the type `Vec<DynSimOnlyValue>`
--> $RUST/alloc/src/vec/mod.rs
|
| pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| ^^^
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
| pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
|
| struct SimValueInner<T: Type> {
| ^^^^^^^^^^^^^
note: required because it appears within the type `UnsafeCell<value::SimValueInner<()>>`
--> $RUST/core/src/cell.rs
|
| pub struct UnsafeCell<T: ?Sized> {
| ^^^^^^^^^^
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `intern_sized`
--> src/intern.rs
|
| pub trait Intern: Any + Send + Sync {
| ^^^^ required by this bound in `Intern::intern_sized`
| fn intern(&self) -> Interned<Self>;
| fn intern_sized(self) -> Interned<Self>
| ------------ required by a bound in this associated function
help: consider dereferencing here
|
12 | Intern::intern_sized(*v)
| +
error[E0277]: `Cell<util::alternating_cell::State>` cannot be shared between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:5
|
@ -184,3 +309,61 @@ note: required by a bound in `fayalite::intern::Interned`
|
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned`
error[E0277]: `NonNull<()>` cannot be sent between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:5
|
12 | Intern::intern_sized(v)
| ^^^^^^^^^^^^^^^^^^^^^^^ `NonNull<()>` cannot be sent between threads safely
|
= help: within `SimValue<()>`, the trait `Send` is not implemented for `NonNull<()>`
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
| pub struct DynSimOnlyValue {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `PhantomData<DynSimOnlyValue>`
--> $RUST/core/src/marker.rs
|
| pub struct PhantomData<T: PointeeSized>;
| ^^^^^^^^^^^
note: required because it appears within the type `alloc::raw_vec::RawVec<DynSimOnlyValue>`
--> $RUST/alloc/src/raw_vec/mod.rs
|
| pub(crate) struct RawVec<T, A: Allocator = Global> {
| ^^^^^^
note: required because it appears within the type `Vec<DynSimOnlyValue>`
--> $RUST/alloc/src/vec/mod.rs
|
| pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| ^^^
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
| pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
|
| struct SimValueInner<T: Type> {
| ^^^^^^^^^^^^^
note: required because it appears within the type `UnsafeCell<value::SimValueInner<()>>`
--> $RUST/core/src/cell.rs
|
| pub struct UnsafeCell<T: ?Sized> {
| ^^^^^^^^^^
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
--> src/util/alternating_cell.rs
|
| pub(crate) struct AlternatingCell<T: ?Sized> {
| ^^^^^^^^^^^^^^^
note: required because it appears within the type `SimValue<()>`
--> src/sim/value.rs
|
| pub struct SimValue<T: Type> {
| ^^^^^^^^
note: required by a bound in `fayalite::intern::Interned`
--> src/intern.rs
|
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned`

View file

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