add support for simulator-only values #35

Merged
programmerjake merged 6 commits from programmerjake/fayalite:sim-non-hdl-data into master 2025-09-09 05:35:24 +00:00
53 changed files with 11618 additions and 7079 deletions

View file

@ -41,6 +41,7 @@ jobs:
- run: | - run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.89.0 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.89.0
source "$HOME/.cargo/env" source "$HOME/.cargo/env"
rustup component add rust-src
echo "$PATH" >> "$GITHUB_PATH" echo "$PATH" >> "$GITHUB_PATH"
- uses: https://git.libre-chip.org/mirrors/cache/restore@v3 - uses: https://git.libre-chip.org/mirrors/cache/restore@v3
with: with:

View file

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

View file

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

View file

@ -34,6 +34,7 @@ which.workspace = true
[dev-dependencies] [dev-dependencies]
trybuild.workspace = true trybuild.workspace = true
serde = { workspace = true, features = ["rc"] }
[build-dependencies] [build-dependencies]
fayalite-visit-gen.workspace = true fayalite-visit-gen.workspace = true

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

@ -31,7 +31,7 @@ use hashbrown::hash_map::Entry;
use num_bigint::BigInt; use num_bigint::BigInt;
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::VecDeque, collections::{BTreeMap, VecDeque},
convert::Infallible, convert::Infallible,
fmt, fmt,
future::IntoFuture, future::IntoFuture,
@ -1524,7 +1524,8 @@ impl TargetState {
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => TargetStateInner::Single { | CanonicalType::Reset(_)
| CanonicalType::DynSimOnly(_) => TargetStateInner::Single {
declared_in_block, declared_in_block,
written_in_blocks: RefCell::default(), written_in_blocks: RefCell::default(),
}, },
@ -1792,12 +1793,49 @@ impl<T: BundleType> Module<T> {
pub fn new_unchecked( pub fn new_unchecked(
name_id: NameId, name_id: NameId,
source_location: SourceLocation, source_location: SourceLocation,
body: ModuleBody, mut body: ModuleBody,
module_io: impl IntoIterator<Item = AnnotatedModuleIO>, module_io: impl IntoIterator<Item = AnnotatedModuleIO>,
module_annotations: impl IntoAnnotations, module_annotations: impl IntoAnnotations,
) -> Module<T> { ) -> Module<T> {
let module_io: Interned<[_]> = module_io.into_iter().collect(); let module_io: Interned<[_]> = module_io.into_iter().collect();
let module_annotations = module_annotations.into_annotations().into_iter().collect(); let module_annotations = module_annotations.into_annotations().into_iter().collect();
match &mut body {
ModuleBody::Normal(_) => {}
ModuleBody::Extern(ExternModuleBody {
simulation: Some(simulation),
..
}) => {
if module_io.iter().any(|io| {
!simulation
.sim_io_to_generator_map
.contains_key(&io.module_io.intern())
}) {
let mut sim_io_to_generator_map =
BTreeMap::clone(&simulation.sim_io_to_generator_map);
for io in module_io.iter() {
let io = io.module_io.intern();
sim_io_to_generator_map.entry(io).or_insert(io);
}
simulation.sim_io_to_generator_map = sim_io_to_generator_map.intern_sized();
}
if simulation.sim_io_to_generator_map.len() > module_io.len() {
// if sim_io_to_generator_map is bigger, then there must be a key that's not in module_io
let module_io_set = HashSet::from_iter(module_io.iter().map(|v| v.module_io));
for (sim_io, generator_io) in simulation.sim_io_to_generator_map.iter() {
if !module_io_set.contains(&**sim_io) {
panic!(
"extern module has invalid `sim_io_to_generator_map`: key is not in containing module's `module_io`:\n\
key={sim_io:?}\nvalue={generator_io:?}\nmodule location: {source_location}"
);
}
}
unreachable!();
}
}
ModuleBody::Extern(ExternModuleBody {
simulation: None, ..
}) => {}
}
let retval = Module { let retval = Module {
name: name_id, name: name_id,
source_location, source_location,

View file

@ -18,18 +18,20 @@ use crate::{
intern::{Intern, Interned, Memoize}, intern::{Intern, Interned, Memoize},
memory::{DynPortType, MemPort}, memory::{DynPortType, MemPort},
module::{ module::{
AnnotatedModuleIO, Block, ExprInInstantiatedModule, ExternModuleBody, InstantiatedModule, AnnotatedModuleIO, Block, ExprInInstantiatedModule, ExternModuleBody,
ModuleBody, ModuleIO, NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, ExternModuleParameter, InstantiatedModule, ModuleBody, ModuleIO, NameId, NormalModuleBody,
StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg,
StmtWire,
}, },
prelude::*, prelude::*,
reset::{ResetType, ResetTypeDispatch}, reset::{ResetType, ResetTypeDispatch},
sim::ExternModuleSimulation,
util::{HashMap, HashSet}, util::{HashMap, HashSet},
}; };
use hashbrown::hash_map::Entry; use hashbrown::hash_map::Entry;
use num_bigint::BigInt; use num_bigint::BigInt;
use petgraph::unionfind::UnionFind; use petgraph::unionfind::UnionFind;
use std::{fmt, marker::PhantomData}; use std::{collections::BTreeMap, fmt, marker::PhantomData};
#[derive(Debug)] #[derive(Debug)]
pub enum DeduceResetsError { pub enum DeduceResetsError {
@ -163,6 +165,7 @@ impl ResetsLayout {
CanonicalType::Reset(_) => ResetsLayout::Reset, CanonicalType::Reset(_) => ResetsLayout::Reset,
CanonicalType::Clock(_) => ResetsLayout::NoResets, CanonicalType::Clock(_) => ResetsLayout::NoResets,
CanonicalType::PhantomConst(_) => ResetsLayout::NoResets, CanonicalType::PhantomConst(_) => ResetsLayout::NoResets,
CanonicalType::DynSimOnly(_) => ResetsLayout::NoResets,
} }
} }
} }
@ -416,7 +419,8 @@ impl Resets {
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => Ok(self.ty), | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => Ok(self.ty),
CanonicalType::Array(ty) => Ok(CanonicalType::Array(Array::new_dyn( CanonicalType::Array(ty) => Ok(CanonicalType::Array(Array::new_dyn(
self.array_elements().substituted_type( self.array_elements().substituted_type(
reset_graph, reset_graph,
@ -1008,7 +1012,8 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
| CanonicalType::Enum(_) | CanonicalType::Enum(_)
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::PhantomConst(_) => unreachable!(), | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!(),
$(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)* $(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)*
} }
}; };
@ -1020,7 +1025,8 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
| CanonicalType::Enum(_) | CanonicalType::Enum(_)
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::Reset(_) => unreachable!(), | CanonicalType::Reset(_) => unreachable!(),
CanonicalType::PhantomConst(_) => Expr::expr_enum(arg), CanonicalType::PhantomConst(_) |
CanonicalType::DynSimOnly(_) => Expr::expr_enum(arg),
$(CanonicalType::$Variant(_) => { $(CanonicalType::$Variant(_) => {
let arg = Expr::<$Variant>::from_canonical(arg); let arg = Expr::<$Variant>::from_canonical(arg);
match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock) match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock)
@ -1683,7 +1689,8 @@ impl RunPassDispatch for AnyReg {
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) | CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => unreachable!(), | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!(),
} }
}) })
} }
@ -1737,6 +1744,33 @@ impl RunPassDispatch for Instance<Bundle> {
} }
} }
impl<P: Pass> RunPass<P> for ExternModuleSimulation {
fn run_pass(
&self,
mut pass_args: PassArgs<'_, P>,
) -> Result<PassOutput<Self, P>, DeduceResetsError> {
let Self {
generator,
sim_io_to_generator_map,
source_location,
} = *self;
let sim_io_to_generator_map = Result::<PassOutput<BTreeMap<_, _>, P>, _>::from_iter(
sim_io_to_generator_map
.iter()
.map(|(sim_io, generator_io)| {
Ok(sim_io
.run_pass(pass_args.as_mut())?
.map(|v| (v, *generator_io)))
}),
)?;
Ok(sim_io_to_generator_map.map(|sim_io_to_generator_map| Self {
generator,
sim_io_to_generator_map: sim_io_to_generator_map.intern_sized(),
source_location,
}))
}
}
macro_rules! impl_run_pass_copy { macro_rules! impl_run_pass_copy {
([$($generics:tt)*] $ty:ty) => { ([$($generics:tt)*] $ty:ty) => {
impl<P: Pass, $($generics)*> RunPass<P> for $ty { impl<P: Pass, $($generics)*> RunPass<P> for $ty {
@ -1764,6 +1798,7 @@ macro_rules! impl_run_pass_clone {
} }
impl_run_pass_clone!([] BigInt); impl_run_pass_clone!([] BigInt);
impl_run_pass_clone!([] ExternModuleParameter);
impl_run_pass_clone!([] SIntValue); impl_run_pass_clone!([] SIntValue);
impl_run_pass_clone!([] std::ops::Range<usize>); impl_run_pass_clone!([] std::ops::Range<usize>);
impl_run_pass_clone!([] UIntValue); impl_run_pass_clone!([] UIntValue);
@ -1773,7 +1808,6 @@ impl_run_pass_copy!([] bool);
impl_run_pass_copy!([] CustomFirrtlAnnotation); impl_run_pass_copy!([] CustomFirrtlAnnotation);
impl_run_pass_copy!([] DocStringAnnotation); impl_run_pass_copy!([] DocStringAnnotation);
impl_run_pass_copy!([] DontTouchAnnotation); impl_run_pass_copy!([] DontTouchAnnotation);
impl_run_pass_copy!([] ExternModuleBody);
impl_run_pass_copy!([] Interned<str>); impl_run_pass_copy!([] Interned<str>);
impl_run_pass_copy!([] NameId); impl_run_pass_copy!([] NameId);
impl_run_pass_copy!([] SInt); impl_run_pass_copy!([] SInt);
@ -2034,6 +2068,14 @@ impl_run_pass_for_struct! {
} }
} }
impl_run_pass_for_struct! {
impl[] RunPass for ExternModuleBody {
verilog_name: _,
parameters: _,
simulation: _,
}
}
impl_run_pass_copy!([] MemPort<DynPortType>); // Mem can't contain any `Reset` types impl_run_pass_copy!([] MemPort<DynPortType>); // Mem can't contain any `Reset` types
impl_run_pass_copy!([] Mem); // Mem can't contain any `Reset` types impl_run_pass_copy!([] Mem); // Mem can't contain any `Reset` types

View file

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

View file

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

View file

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

View file

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

View file

@ -33,7 +33,7 @@ pub use crate::{
sim::{ sim::{
ExternModuleSimulationState, Simulation, ExternModuleSimulationState, Simulation,
time::{SimDuration, SimInstant}, time::{SimDuration, SimInstant},
value::{SimValue, ToSimValue, ToSimValueWithType}, value::{SimOnly, SimOnlyValue, SimValue, ToSimValue, ToSimValueWithType},
}, },
source_location::SourceLocation, source_location::SourceLocation,
ty::{AsMask, CanonicalType, Type}, ty::{AsMask, CanonicalType, Type},

View file

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

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}, expr::{CastBitsTo, Expr, ToExpr},
int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue},
reset::{AsyncReset, Reset, SyncReset}, reset::{AsyncReset, Reset, SyncReset},
ty::{CanonicalType, StaticType, Type}, source_location::SourceLocation,
ty::{
CanonicalType, OpaqueSimValue, OpaqueSimValueSize, OpaqueSimValueSlice,
OpaqueSimValueWriter, StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
util::{ util::{
ConstUsize, ConstUsize, HashMap,
alternating_cell::{AlternatingCell, AlternatingCellMethods}, alternating_cell::{AlternatingCell, AlternatingCellMethods},
}, },
}; };
use bitvec::{slice::BitSlice, vec::BitVec}; use bitvec::{slice::BitSlice, vec::BitVec};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use hashbrown::hash_map::Entry;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _};
use std::{ use std::{
fmt, borrow::Cow,
fmt::{self, Write},
hash::{BuildHasher, Hash, Hasher, RandomState},
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
sync::Arc, sync::{Arc, Mutex},
};
pub(crate) mod sim_only_value_unsafe;
pub use sim_only_value_unsafe::{
DynSimOnly, DynSimOnlyValue, SimOnly, SimOnlyValue, SimOnlyValueTrait,
}; };
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Copy, Clone, Eq, PartialEq)]
enum ValidFlags { enum ValidFlags {
BothValid = 0, BothValid = 0,
OnlyValueValid = 1, OnlyValueValid = 1,
OnlyBitsValid = 2, OnlyOpaqueValid = 2,
} }
#[derive(Clone)] #[derive(Clone)]
struct SimValueInner<T: Type> { struct SimValueInner<T: Type> {
value: T::SimValue, value: T::SimValue,
bits: UIntValue, opaque: OpaqueSimValue,
valid_flags: ValidFlags, valid_flags: ValidFlags,
ty: T, ty: T,
sim_only_values_len: usize,
} }
impl<T: Type> SimValueInner<T> { impl<T: Type> SimValueInner<T> {
fn fill_bits(&mut self) { fn size(&self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.opaque.bit_width(),
sim_only_values_len: self.sim_only_values_len,
}
}
fn fill_opaque(&mut self) {
match self.valid_flags { match self.valid_flags {
ValidFlags::BothValid | ValidFlags::OnlyBitsValid => {} ValidFlags::BothValid | ValidFlags::OnlyOpaqueValid => {}
ValidFlags::OnlyValueValid => { ValidFlags::OnlyValueValid => {
self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut()); OpaqueSimValueWriter::rewrite_with(self.size(), &mut self.opaque, |writer| {
self.ty.sim_value_to_opaque(&self.value, writer)
});
self.valid_flags = ValidFlags::BothValid; self.valid_flags = ValidFlags::BothValid;
} }
} }
} }
fn into_bits(mut self) -> UIntValue { fn into_opaque(mut self) -> OpaqueSimValue {
self.fill_bits(); self.fill_opaque();
self.bits self.opaque
} }
fn bits_mut(&mut self) -> &mut UIntValue { fn opaque_mut(&mut self) -> &mut OpaqueSimValue {
self.fill_bits(); self.fill_opaque();
self.valid_flags = ValidFlags::OnlyBitsValid; self.valid_flags = ValidFlags::OnlyOpaqueValid;
&mut self.bits &mut self.opaque
} }
fn fill_value(&mut self) { fn fill_value(&mut self) {
match self.valid_flags { match self.valid_flags {
ValidFlags::BothValid | ValidFlags::OnlyValueValid => {} ValidFlags::BothValid | ValidFlags::OnlyValueValid => {}
ValidFlags::OnlyBitsValid => { ValidFlags::OnlyOpaqueValid => {
self.ty self.ty
.sim_value_clone_from_bits(&mut self.value, self.bits.bits()); .sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice());
self.valid_flags = ValidFlags::BothValid; self.valid_flags = ValidFlags::BothValid;
} }
} }
@ -83,11 +105,13 @@ impl<T: Type> AlternatingCellMethods for SimValueInner<T> {
match self.valid_flags { match self.valid_flags {
ValidFlags::BothValid => return, ValidFlags::BothValid => return,
ValidFlags::OnlyValueValid => { ValidFlags::OnlyValueValid => {
self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut()) OpaqueSimValueWriter::rewrite_with(self.size(), &mut self.opaque, |writer| {
self.ty.sim_value_to_opaque(&self.value, writer)
})
} }
ValidFlags::OnlyBitsValid => self ValidFlags::OnlyOpaqueValid => self
.ty .ty
.sim_value_clone_from_bits(&mut self.value, self.bits.bits()), .sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice()),
} }
self.valid_flags = ValidFlags::BothValid; self.valid_flags = ValidFlags::BothValid;
} }
@ -143,13 +167,15 @@ impl<T: Type + Clone> Clone for SimValue<T> {
impl<T: Type> SimValue<T> { impl<T: Type> SimValue<T> {
#[track_caller] #[track_caller]
pub fn from_bits(ty: T, bits: UIntValue) -> Self { pub fn from_opaque(ty: T, opaque: OpaqueSimValue) -> Self {
assert_eq!(ty.canonical().bit_width(), bits.width()); let size = ty.canonical().size();
assert_eq!(size, opaque.size());
let inner = SimValueInner { let inner = SimValueInner {
value: ty.sim_value_from_bits(bits.bits()), value: ty.sim_value_from_opaque(opaque.as_slice()),
bits, opaque,
valid_flags: ValidFlags::BothValid, valid_flags: ValidFlags::BothValid,
ty, ty,
sim_only_values_len: size.sim_only_values_len,
}; };
Self { Self {
inner: AlternatingCell::new_shared(inner), inner: AlternatingCell::new_shared(inner),
@ -157,14 +183,30 @@ impl<T: Type> SimValue<T> {
} }
#[track_caller] #[track_caller]
pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self { pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self {
Self::from_bits(ty, UIntValue::new(Arc::new(bits.to_bitvec()))) Self::from_bitslice_and_sim_only_values(ty, bits, Vec::new())
}
#[track_caller]
pub fn from_bitslice_and_sim_only_values(
ty: T,
bits: &BitSlice,
sim_only_values: Vec<DynSimOnlyValue>,
) -> Self {
Self::from_opaque(
ty,
OpaqueSimValue::from_bitslice_and_sim_only_values(bits, sim_only_values),
)
} }
pub fn from_value(ty: T, value: T::SimValue) -> Self { pub fn from_value(ty: T, value: T::SimValue) -> Self {
let type_properties = ty.canonical().type_properties();
let inner = SimValueInner { let inner = SimValueInner {
bits: UIntValue::new_dyn(Arc::new(BitVec::repeat(false, ty.canonical().bit_width()))), opaque: OpaqueSimValue::from_bits_and_sim_only_values(
UIntValue::new_dyn(Arc::new(BitVec::repeat(false, type_properties.bit_width))),
Vec::with_capacity(type_properties.sim_only_values_len),
),
value, value,
valid_flags: ValidFlags::OnlyValueValid, valid_flags: ValidFlags::OnlyValueValid,
ty, ty,
sim_only_values_len: type_properties.sim_only_values_len,
}; };
Self { Self {
inner: AlternatingCell::new_unique(inner), inner: AlternatingCell::new_unique(inner),
@ -173,18 +215,24 @@ impl<T: Type> SimValue<T> {
pub fn ty(this: &Self) -> T { pub fn ty(this: &Self) -> T {
this.inner.share().ty this.inner.share().ty
} }
pub fn into_bits(this: Self) -> UIntValue { pub fn into_opaque(this: Self) -> OpaqueSimValue {
this.inner.into_inner().into_bits() this.inner.into_inner().into_opaque()
} }
pub fn into_ty_and_bits(this: Self) -> (T, UIntValue) { pub fn into_ty_and_opaque(this: Self) -> (T, OpaqueSimValue) {
let inner = this.inner.into_inner(); let inner = this.inner.into_inner();
(inner.ty, inner.into_bits()) (inner.ty, inner.into_opaque())
}
pub fn opaque(this: &Self) -> &OpaqueSimValue {
&this.inner.share().opaque
}
pub fn opaque_mut(this: &mut Self) -> &mut OpaqueSimValue {
this.inner.unique().opaque_mut()
} }
pub fn bits(this: &Self) -> &UIntValue { pub fn bits(this: &Self) -> &UIntValue {
&this.inner.share().bits Self::opaque(this).bits()
} }
pub fn bits_mut(this: &mut Self) -> &mut UIntValue { pub fn bits_mut(this: &mut Self) -> &mut UIntValue {
this.inner.unique().bits_mut() Self::opaque_mut(this).bits_mut()
} }
pub fn into_value(this: Self) -> T::SimValue { pub fn into_value(this: Self) -> T::SimValue {
this.inner.into_inner().into_value() this.inner.into_inner().into_value()
@ -197,59 +245,59 @@ impl<T: Type> SimValue<T> {
} }
#[track_caller] #[track_caller]
pub fn from_canonical(v: SimValue<CanonicalType>) -> Self { pub fn from_canonical(v: SimValue<CanonicalType>) -> Self {
let (ty, bits) = SimValue::into_ty_and_bits(v); let (ty, opaque) = SimValue::into_ty_and_opaque(v);
Self::from_bits(T::from_canonical(ty), bits) Self::from_opaque(T::from_canonical(ty), opaque)
} }
pub fn into_canonical(this: Self) -> SimValue<CanonicalType> { pub fn into_canonical(this: Self) -> SimValue<CanonicalType> {
let (ty, bits) = Self::into_ty_and_bits(this); let (ty, opaque) = Self::into_ty_and_opaque(this);
SimValue::from_bits(ty.canonical(), bits) SimValue::from_opaque(ty.canonical(), opaque)
} }
pub fn canonical(this: &Self) -> SimValue<CanonicalType> { pub fn canonical(this: &Self) -> SimValue<CanonicalType> {
SimValue::from_bits(Self::ty(this).canonical(), Self::bits(this).clone()) SimValue::from_opaque(Self::ty(this).canonical(), Self::opaque(this).clone())
} }
#[track_caller] #[track_caller]
pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self
where where
T: IntType, T: IntType,
{ {
let (ty, bits) = SimValue::into_ty_and_bits(v); let (ty, opaque) = SimValue::into_ty_and_opaque(v);
SimValue::from_bits(T::from_dyn_int(ty), bits) SimValue::from_opaque(T::from_dyn_int(ty), opaque)
} }
pub fn into_dyn_int(this: Self) -> SimValue<T::Dyn> pub fn into_dyn_int(this: Self) -> SimValue<T::Dyn>
where where
T: IntType, T: IntType,
{ {
let (ty, bits) = Self::into_ty_and_bits(this); let (ty, opaque) = Self::into_ty_and_opaque(this);
SimValue::from_bits(ty.as_dyn_int(), bits) SimValue::from_opaque(ty.as_dyn_int(), opaque)
} }
pub fn to_dyn_int(this: &Self) -> SimValue<T::Dyn> pub fn to_dyn_int(this: &Self) -> SimValue<T::Dyn>
where where
T: IntType, T: IntType,
{ {
SimValue::from_bits(Self::ty(this).as_dyn_int(), Self::bits(&this).clone()) SimValue::from_opaque(Self::ty(this).as_dyn_int(), Self::opaque(&this).clone())
} }
#[track_caller] #[track_caller]
pub fn from_bundle(v: SimValue<Bundle>) -> Self pub fn from_bundle(v: SimValue<Bundle>) -> Self
where where
T: BundleType, T: BundleType,
{ {
let (ty, bits) = SimValue::into_ty_and_bits(v); let (ty, opaque) = SimValue::into_ty_and_opaque(v);
SimValue::from_bits(T::from_canonical(CanonicalType::Bundle(ty)), bits) SimValue::from_opaque(T::from_canonical(CanonicalType::Bundle(ty)), opaque)
} }
pub fn into_bundle(this: Self) -> SimValue<Bundle> pub fn into_bundle(this: Self) -> SimValue<Bundle>
where where
T: BundleType, T: BundleType,
{ {
let (ty, bits) = Self::into_ty_and_bits(this); let (ty, opaque) = Self::into_ty_and_opaque(this);
SimValue::from_bits(Bundle::from_canonical(ty.canonical()), bits) SimValue::from_opaque(Bundle::from_canonical(ty.canonical()), opaque)
} }
pub fn to_bundle(this: &Self) -> SimValue<Bundle> pub fn to_bundle(this: &Self) -> SimValue<Bundle>
where where
T: BundleType, T: BundleType,
{ {
SimValue::from_bits( SimValue::from_opaque(
Bundle::from_canonical(Self::ty(this).canonical()), Bundle::from_canonical(Self::ty(this).canonical()),
Self::bits(&this).clone(), Self::opaque(&this).clone(),
) )
} }
#[track_caller] #[track_caller]
@ -257,23 +305,23 @@ impl<T: Type> SimValue<T> {
where where
T: EnumType, T: EnumType,
{ {
let (ty, bits) = SimValue::into_ty_and_bits(v); let (ty, opaque) = SimValue::into_ty_and_opaque(v);
SimValue::from_bits(T::from_canonical(CanonicalType::Enum(ty)), bits) SimValue::from_opaque(T::from_canonical(CanonicalType::Enum(ty)), opaque)
} }
pub fn into_enum(this: Self) -> SimValue<Enum> pub fn into_enum(this: Self) -> SimValue<Enum>
where where
T: EnumType, T: EnumType,
{ {
let (ty, bits) = Self::into_ty_and_bits(this); let (ty, opaque) = Self::into_ty_and_opaque(this);
SimValue::from_bits(Enum::from_canonical(ty.canonical()), bits) SimValue::from_opaque(Enum::from_canonical(ty.canonical()), opaque)
} }
pub fn to_enum(this: &Self) -> SimValue<Enum> pub fn to_enum(this: &Self) -> SimValue<Enum>
where where
T: EnumType, T: EnumType,
{ {
SimValue::from_bits( SimValue::from_opaque(
Enum::from_canonical(Self::ty(this).canonical()), Enum::from_canonical(Self::ty(this).canonical()),
Self::bits(&this).clone(), Self::opaque(&this).clone(),
) )
} }
} }
@ -308,7 +356,11 @@ impl<T: Type> ToExpr for SimValue<T> {
#[track_caller] #[track_caller]
fn to_expr(&self) -> Expr<Self::Type> { fn to_expr(&self) -> Expr<Self::Type> {
let inner = self.inner.share(); let inner = self.inner.share();
inner.bits.cast_bits_to(inner.ty) assert_eq!(
inner.sim_only_values_len, 0,
"can't convert sim-only values to Expr"
);
inner.opaque.bits().cast_bits_to(inner.ty)
} }
} }
@ -443,12 +495,15 @@ impl<T: Type> ToSimValueWithType<T> for BitVec {
#[track_caller] #[track_caller]
fn arc_into_sim_value_with_type(self: Arc<Self>, ty: T) -> SimValue<T> { fn arc_into_sim_value_with_type(self: Arc<Self>, ty: T) -> SimValue<T> {
SimValue::from_bits(ty, UIntValue::new_dyn(self)) SimValue::from_opaque(ty, OpaqueSimValue::from_bits(UIntValue::new_dyn(self)))
} }
#[track_caller] #[track_caller]
fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: T) -> SimValue<T> { fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: T) -> SimValue<T> {
SimValue::from_bits(ty, UIntValue::new_dyn(self.clone())) SimValue::from_opaque(
ty,
OpaqueSimValue::from_bits(UIntValue::new_dyn(self.clone())),
)
} }
} }
@ -792,16 +847,18 @@ impl ToSimValueWithType<CanonicalType> for bool {
| CanonicalType::Array(_) | CanonicalType::Array(_)
| CanonicalType::Enum(_) | CanonicalType::Enum(_)
| CanonicalType::Bundle(_) | CanonicalType::Bundle(_)
| CanonicalType::PhantomConst(_) => { | CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => {
panic!("can't create SimValue from bool: expected value of type: {ty:?}"); panic!("can't create SimValue from bool: expected value of type: {ty:?}");
} }
CanonicalType::Bool(_) CanonicalType::Bool(_)
| CanonicalType::AsyncReset(_) | CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_) | CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) | CanonicalType::Reset(_)
| CanonicalType::Clock(_) => { | CanonicalType::Clock(_) => SimValue::from_opaque(
SimValue::from_bits(ty, UIntValue::new(Arc::new(BitVec::repeat(*self, 1)))) ty,
} OpaqueSimValue::from_bits(UIntValue::new(Arc::new(BitVec::repeat(*self, 1)))),
),
} }
} }
} }
@ -911,3 +968,377 @@ macro_rules! impl_to_sim_value_for_int_value {
impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType); impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType);
impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType); impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType);
#[derive(Default)]
struct DynSimOnlySerdeTableRest {
from_serde: HashMap<DynSimOnlySerdeId, DynSimOnly>,
serde_id_random_state: RandomState,
buffer: String,
}
impl DynSimOnlySerdeTableRest {
#[cold]
fn add_new(&mut self, ty: DynSimOnly) -> DynSimOnlySerdeId {
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 = DynSimOnlySerdeId(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 DynSimOnlySerdeTable {
to_serde: HashMap<DynSimOnly, DynSimOnlySerdeId>,
rest: DynSimOnlySerdeTableRest,
}
static DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE: Mutex<Option<DynSimOnlySerdeTable>> = Mutex::new(None);
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
struct DynSimOnlySerdeId([u32; 4]);
impl From<DynSimOnly> for DynSimOnlySerdeId {
fn from(ty: DynSimOnly) -> Self {
let mut locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE
.lock()
.expect("shouldn't be poison");
let DynSimOnlySerdeTable { 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 DynSimOnlySerdeId {
fn ty(self) -> Option<DynSimOnly> {
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 DynSimOnlySerde<'a> {
random_id: DynSimOnlySerdeId,
#[serde(borrow)]
type_name: Cow<'a, str>,
}
impl Serialize for DynSimOnly {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
DynSimOnlySerde {
random_id: (*self).into(),
type_name: Cow::Borrowed(self.type_name()),
}
.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for DynSimOnly {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let deserialized = DynSimOnlySerde::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 DynSimOnly that was serialized this time this program was run",
)
})
}
}
impl DynSimOnly {
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 DynSimOnly {
type BaseType = DynSimOnly;
type MaskType = Bool;
type SimValue = DynSimOnlyValue;
impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType {
Bool
}
fn canonical(&self) -> CanonicalType {
CanonicalType::DynSimOnly(*self)
}
fn from_canonical(canonical_type: CanonicalType) -> Self {
let CanonicalType::DynSimOnly(v) = canonical_type else {
panic!("expected DynSimOnly");
};
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 SimOnly<T> {
type BaseType = DynSimOnly;
type MaskType = Bool;
type SimValue = SimOnlyValue<T>;
impl_match_variant_as_self!();
fn mask_type(&self) -> Self::MaskType {
Bool
}
fn canonical(&self) -> CanonicalType {
DynSimOnly::from(*self).canonical()
}
fn from_canonical(canonical_type: CanonicalType) -> Self {
DynSimOnly::from_canonical(canonical_type)
.downcast()
.expect("got wrong SimOnly")
}
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 = match opaque.sim_only_values()[0].clone().downcast::<T>() {
Ok(v) => v,
Err(v) => panic!(
"type mismatch: expected {:?}, got {:?}",
DynSimOnly::of::<T>(),
v.ty()
),
};
}
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 SimOnly<T> {
const TYPE: Self = Self::new();
const MASK_TYPE: Self::MaskType = Bool;
const TYPE_PROPERTIES: TypeProperties = DynSimOnly::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: DynSimOnly,
#[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<DynSimOnly> for DynSimOnlyValue {
#[track_caller]
fn to_sim_value_with_type(&self, ty: DynSimOnly) -> SimValue<DynSimOnly> {
assert_eq!(self.ty(), ty, "mismatched type");
SimValue::from_value(ty, self.clone())
}
#[track_caller]
fn into_sim_value_with_type(self, ty: DynSimOnly) -> SimValue<DynSimOnly> {
assert_eq!(self.ty(), ty, "mismatched type");
SimValue::from_value(ty, self)
}
}
impl<T: SimOnlyValueTrait> ToSimValueWithType<SimOnly<T>> for SimOnlyValue<T> {
fn to_sim_value_with_type(&self, ty: SimOnly<T>) -> SimValue<SimOnly<T>> {
SimValue::from_value(ty, self.clone())
}
fn into_sim_value_with_type(self, ty: SimOnly<T>) -> SimValue<SimOnly<T>> {
SimValue::from_value(ty, self)
}
}
impl ToSimValue for DynSimOnlyValue {
type Type = DynSimOnly;
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 = SimOnly<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)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{any, collections::BTreeMap};
#[test]
fn test_sim_value_serde() -> eyre::Result<()> {
type Inner = Option<BTreeMap<String, Option<u32>>>;
let original = SimOnlyValue::<Inner>::new(Some(BTreeMap::from_iter([
(String::new(), Some(3)),
(String::from("foo"), None),
])));
let json = SimOnlyValue::with_dyn_ref(&original, serde_json::to_string_pretty)?;
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct ExpectedTy {
random_id: [u32; 4],
type_name: String,
}
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct Expected {
ty: ExpectedTy,
value: String,
}
let Expected {
ty: ExpectedTy {
random_id,
type_name,
},
value,
} = serde_json::from_str(&json)?;
let _ = random_id;
assert_eq!(type_name, any::type_name::<Inner>());
assert_eq!(value, r#"{"":3,"foo":null}"#);
let deserialized: DynSimOnlyValue = serde_json::from_str(&json)?;
assert_eq!(Some(&*original), deserialized.downcast_ref::<Inner>());
Ok(())
}
}

View file

@ -0,0 +1,304 @@
// 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::{
any::{self, TypeId},
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
mem::ManuallyDrop,
rc::Rc,
};
pub trait SimOnlyValueTrait:
'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone + Default
{
}
impl<T: 'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone + Default>
SimOnlyValueTrait for T
{
}
/// Safety: `type_id_dyn` must return `TypeId::of::<T>()` where `Self = SimOnly<T>`
unsafe trait DynSimOnlyTrait: 'static + Send + Sync {
fn type_id_dyn(&self) -> TypeId;
fn type_name(&self) -> &'static str;
fn default_value(&self) -> Rc<dyn DynSimOnlyValueTrait>;
fn deserialize_from_json_string(
&self,
json_str: &str,
) -> serde_json::Result<Rc<dyn DynSimOnlyValueTrait>>;
}
/// Safety: `type_id_dyn` is implemented correctly
unsafe impl<T: SimOnlyValueTrait> DynSimOnlyTrait for SimOnly<T> {
fn type_id_dyn(&self) -> TypeId {
TypeId::of::<T>()
}
fn type_name(&self) -> &'static str {
any::type_name::<T>()
}
fn default_value(&self) -> Rc<dyn DynSimOnlyValueTrait> {
Rc::new(T::default())
}
fn deserialize_from_json_string(
&self,
json_str: &str,
) -> serde_json::Result<Rc<dyn DynSimOnlyValueTrait>> {
Ok(Rc::<T>::new(serde_json::from_str(json_str)?))
}
}
/// Safety:
/// * `type_id_dyn()` must return `TypeId::of::<Self>()`.
/// * `ty().type_id()` must return `TypeId::of::<Self>()`.
unsafe trait DynSimOnlyValueTrait: 'static + fmt::Debug {
fn type_id_dyn(&self) -> TypeId;
fn ty(&self) -> DynSimOnly;
fn eq_dyn(&self, other: &dyn DynSimOnlyValueTrait) -> bool;
fn serialize_to_json_string(&self) -> serde_json::Result<String>;
fn hash_dyn(&self, state: &mut dyn Hasher);
}
impl dyn DynSimOnlyValueTrait {
fn is<T: SimOnlyValueTrait>(&self) -> bool {
Self::type_id_dyn(self) == TypeId::of::<T>()
}
fn downcast_ref<T: SimOnlyValueTrait>(&self) -> Option<&T> {
if Self::is::<T>(self) {
// Safety: checked that `Self` is really `T`
Some(unsafe { &*(self as *const Self as *const T) })
} else {
None
}
}
fn downcast_rc<T: SimOnlyValueTrait>(self: Rc<Self>) -> Result<Rc<T>, Rc<Self>> {
if Self::is::<T>(&*self) {
// Safety: checked that `Self` is really `T`
Ok(unsafe { Rc::from_raw(Rc::into_raw(self) as *const T) })
} else {
Err(self)
}
}
}
/// Safety:
/// * `type_id_dyn()` returns `TypeId::of::<Self>()`.
/// * `ty().type_id()` returns `TypeId::of::<Self>()`.
unsafe impl<T: SimOnlyValueTrait> DynSimOnlyValueTrait for T {
fn type_id_dyn(&self) -> TypeId {
TypeId::of::<T>()
}
fn ty(&self) -> DynSimOnly {
DynSimOnly::of::<T>()
}
fn eq_dyn(&self, other: &dyn DynSimOnlyValueTrait) -> bool {
other.downcast_ref::<T>().is_some_and(|other| self == other)
}
fn serialize_to_json_string(&self) -> serde_json::Result<String> {
serde_json::to_string(self)
}
fn hash_dyn(&self, mut state: &mut dyn Hasher) {
self.hash(&mut state);
}
}
#[derive(Copy, Clone)]
pub struct DynSimOnly {
ty: &'static dyn DynSimOnlyTrait,
}
impl DynSimOnly {
pub const fn of<T: SimOnlyValueTrait>() -> Self {
Self {
ty: &const { SimOnly::<T>::new() },
}
}
pub fn type_id(self) -> TypeId {
self.ty.type_id_dyn()
}
pub fn type_name(self) -> &'static str {
self.ty.type_name()
}
pub fn is<T: SimOnlyValueTrait>(self) -> bool {
self.type_id() == TypeId::of::<T>()
}
pub fn downcast<T: SimOnlyValueTrait>(self) -> Option<SimOnly<T>> {
self.is::<T>().then_some(SimOnly::default())
}
pub fn deserialize_from_json_string(
self,
json_str: &str,
) -> serde_json::Result<DynSimOnlyValue> {
self.ty
.deserialize_from_json_string(json_str)
.map(DynSimOnlyValue)
}
pub fn default_value(self) -> DynSimOnlyValue {
DynSimOnlyValue(self.ty.default_value())
}
}
impl PartialEq for DynSimOnly {
fn eq(&self, other: &Self) -> bool {
Self::type_id(*self) == Self::type_id(*other)
}
}
impl Eq for DynSimOnly {}
impl Hash for DynSimOnly {
fn hash<H: Hasher>(&self, state: &mut H) {
Self::type_id(*self).hash(state);
}
}
impl fmt::Debug for DynSimOnly {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SimOnly<{}>", self.ty.type_name())
}
}
impl<T: SimOnlyValueTrait> From<SimOnly<T>> for DynSimOnly {
fn from(value: SimOnly<T>) -> Self {
let SimOnly(PhantomData) = value;
Self::of::<T>()
}
}
/// the [`Type`][Type] for a value that can only be used in a Fayalite simulation, it can't be converted to FIRRTL
///
/// [Type]: crate::ty::Type
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct SimOnly<T: SimOnlyValueTrait>(PhantomData<fn(T) -> T>);
impl<T: SimOnlyValueTrait> fmt::Debug for SimOnly<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
DynSimOnly::of::<T>().fmt(f)
}
}
impl<T: SimOnlyValueTrait> SimOnly<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<T: SimOnlyValueTrait> Copy for SimOnly<T> {}
impl<T: SimOnlyValueTrait> Default for SimOnly<T> {
fn default() -> Self {
Self::new()
}
}
/// a value that can only be used in a Fayalite simulation, it can't be converted to FIRRTL
#[derive(Clone, Eq, PartialEq, Hash, Default, PartialOrd, Ord)]
pub struct SimOnlyValue<T: SimOnlyValueTrait>(Rc<T>);
impl<T: SimOnlyValueTrait> SimOnlyValue<T> {
pub fn with_dyn_ref<F: FnOnce(&DynSimOnlyValue) -> R, R>(&self, f: F) -> R {
// Safety: creating a copied `Rc<T>` is safe as long as the copy isn't dropped and isn't changed
// to point somewhere else, `f` can't change `dyn_ref` because it's only given a shared reference.
let dyn_ref =
unsafe { ManuallyDrop::new(DynSimOnlyValue(Rc::<T>::from_raw(Rc::as_ptr(&self.0)))) };
f(&dyn_ref)
}
pub fn from_rc(v: Rc<T>) -> Self {
Self(v)
}
pub fn new(v: T) -> Self {
Self(Rc::new(v))
}
pub fn into_inner(this: Self) -> Rc<T> {
this.0
}
pub fn inner_mut(this: &mut Self) -> &mut Rc<T> {
&mut this.0
}
pub fn inner(this: &Self) -> &Rc<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 {
Rc::make_mut(&mut self.0)
}
}
#[derive(Clone)]
pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
impl fmt::Debug for DynSimOnlyValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<dyn DynSimOnlyValueTrait as fmt::Debug>::fmt(&*self.0, f)
}
}
impl PartialEq for DynSimOnlyValue {
fn eq(&self, other: &Self) -> bool {
DynSimOnlyValueTrait::eq_dyn(&*self.0, &*other.0)
}
}
impl Eq for DynSimOnlyValue {}
impl Hash for DynSimOnlyValue {
fn hash<H: Hasher>(&self, state: &mut H) {
DynSimOnlyValueTrait::hash_dyn(&*self.0, state);
}
}
impl<T: SimOnlyValueTrait> From<SimOnlyValue<T>> for DynSimOnlyValue {
fn from(value: SimOnlyValue<T>) -> Self {
Self(value.0)
}
}
impl DynSimOnlyValue {
pub fn ty(&self) -> DynSimOnly {
self.0.ty()
}
pub fn type_id(&self) -> TypeId {
self.0.type_id_dyn()
}
pub fn is<T: SimOnlyValueTrait>(&self) -> bool {
self.0.is::<T>()
}
pub fn downcast<T: SimOnlyValueTrait>(self) -> Result<SimOnlyValue<T>, DynSimOnlyValue> {
match <dyn DynSimOnlyValueTrait>::downcast_rc(self.0) {
Ok(v) => Ok(SimOnlyValue(v)),
Err(v) => Err(Self(v)),
}
}
pub fn downcast_ref<T: SimOnlyValueTrait>(&self) -> Option<&T> {
<dyn DynSimOnlyValueTrait>::downcast_ref(&*self.0)
}
pub fn serialize_to_json_string(&self) -> serde_json::Result<String> {
self.0.serialize_to_json_string()
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -5,6 +5,7 @@ use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView};
use std::{ use std::{
cell::Cell, cell::Cell,
fmt::{self, Debug, Write}, fmt::{self, Debug, Write},
ops::{Bound, Range, RangeBounds},
rc::Rc, rc::Rc,
sync::{Arc, OnceLock}, sync::{Arc, OnceLock},
}; };
@ -209,3 +210,36 @@ impl std::io::Write for RcWriter {
Ok(()) Ok(())
} }
} }
macro_rules! chain {
() => {
std::iter::empty()
};
($first:expr $(, $rest:expr)* $(,)?) => {
{
let retval = IntoIterator::into_iter($first);
$(let retval = Iterator::chain(retval, $rest);)*
retval
}
};
}
pub(crate) use chain;
pub fn try_slice_range<R: RangeBounds<usize>>(range: R, size: usize) -> Option<Range<usize>> {
let start = match range.start_bound() {
Bound::Included(start) => *start,
Bound::Excluded(start) => start.checked_add(1)?,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(end) => end.checked_add(1)?,
Bound::Excluded(end) => *end,
Bound::Unbounded => size,
};
(start <= end && end <= size).then_some(start..end)
}
pub fn slice_range<R: RangeBounds<usize>>(range: R, size: usize) -> Range<usize> {
try_slice_range(range, size).expect("range out of bounds")
}

View file

@ -9,7 +9,7 @@ use fayalite::{
sim::vcd::VcdWriterDecls, sim::vcd::VcdWriterDecls,
util::RcWriter, util::RcWriter,
}; };
use std::num::NonZeroUsize; use std::{collections::BTreeMap, num::NonZeroUsize, rc::Rc};
#[hdl_module(outline_generated)] #[hdl_module(outline_generated)]
pub fn connect_const() { pub fn connect_const() {
@ -1626,3 +1626,99 @@ fn test_ripple_counter() {
panic!(); panic!();
} }
} }
/// use `Rc` to ensure you can use `!Send + !Sync` types
type SimOnlyTestMap = BTreeMap<String, Rc<str>>;
#[hdl_module(outline_generated, extern)]
fn sim_only_connects_helper() {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let inp: SimOnly<SimOnlyTestMap> = m.input();
#[hdl]
let out: SimOnly<SimOnlyTestMap> = m.output();
m.extern_module_simulation_fn((cd, inp, out), |(cd, inp, out), mut sim| async move {
sim.write(out, SimOnlyValue::default()).await;
loop {
sim.wait_for_clock_edge(cd.clk).await;
let mut map = sim.read(inp).await;
let foo = map.get("foo").cloned().unwrap_or_default();
map.insert(String::from("bar"), foo);
map.insert(String::from("foo"), Rc::from("baz"));
sim.write(out, map).await;
}
});
}
#[hdl_module(outline_generated)]
pub fn sim_only_connects() {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let inp: SimOnly<SimOnlyTestMap> = m.input();
#[hdl]
let out1: SimOnly<SimOnlyTestMap> = m.output();
#[hdl]
let out2: SimOnly<SimOnlyTestMap> = m.output();
#[hdl]
let out3: SimOnly<SimOnlyTestMap> = m.output();
#[hdl]
let helper1 = instance(sim_only_connects_helper());
#[hdl]
let delay1: SimOnly<SimOnlyTestMap> = reg_builder()
.clock_domain(cd)
.reset(SimOnly::<SimOnlyTestMap>::new().uninit());
#[hdl]
let delay1_empty: Bool = reg_builder().clock_domain(cd).reset(true);
connect(helper1.cd, cd);
connect(helper1.inp, delay1);
connect(out1, delay1);
#[hdl]
if delay1_empty {
connect(helper1.inp, inp);
connect(out1, inp);
}
connect(delay1, inp);
connect(delay1_empty, false);
connect(out2, helper1.out);
#[hdl]
let helper2 = instance(sim_only_connects_helper());
connect(helper2.cd, cd);
connect(helper2.inp, out2);
connect(out3, helper2.out);
}
#[test]
fn test_sim_only_connects() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(sim_only_connects());
let mut writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
sim.write(sim.io().cd.rst, true);
sim.write(
sim.io().inp,
SimOnlyValue::new(BTreeMap::from_iter([(
String::from("extra"),
Rc::from("value"),
)])),
);
for _ in 0..8 {
sim.write(sim.io().cd.clk, false);
sim.advance_time(SimDuration::from_micros(1));
sim.write(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_micros(1));
sim.write(sim.io().cd.rst, false);
}
sim.flush_traces().unwrap();
let vcd = String::from_utf8(writer.take()).unwrap();
println!("####### VCD:\n{vcd}\n#######");
if vcd != include_str!("sim/expected/sim_only_connects.vcd") {
panic!();
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/sim_only_connects.txt") {
panic!();
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -22,6 +22,12 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -50,6 +56,9 @@ Simulation {
1, 1,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::extern_module, name: <simulator>::extern_module,
@ -146,6 +155,30 @@ Simulation {
), ),
f: ..., f: ...,
}, },
sim_io_to_generator_map: {
ModuleIO {
name: extern_module::i,
is_input: true,
ty: Bool,
..
}: ModuleIO {
name: extern_module::i,
is_input: true,
ty: Bool,
..
},
ModuleIO {
name: extern_module::o,
is_input: false,
ty: Bool,
..
}: ModuleIO {
name: extern_module::o,
is_input: false,
ty: Bool,
..
},
},
source_location: SourceLocation( source_location: SourceLocation(
module-XXXXXXXXXX.rs:4:1, module-XXXXXXXXXX.rs:4:1,
), ),

View file

@ -26,6 +26,12 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -55,6 +61,9 @@ Simulation {
101, 101,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::extern_module2, name: <simulator>::extern_module2,
@ -183,6 +192,41 @@ Simulation {
), ),
f: ..., f: ...,
}, },
sim_io_to_generator_map: {
ModuleIO {
name: extern_module2::clk,
is_input: true,
ty: Clock,
..
}: ModuleIO {
name: extern_module2::clk,
is_input: true,
ty: Clock,
..
},
ModuleIO {
name: extern_module2::en,
is_input: true,
ty: Bool,
..
}: ModuleIO {
name: extern_module2::en,
is_input: true,
ty: Bool,
..
},
ModuleIO {
name: extern_module2::o,
is_input: false,
ty: UInt<8>,
..
}: ModuleIO {
name: extern_module2::o,
is_input: false,
ty: UInt<8>,
..
},
},
source_location: SourceLocation( source_location: SourceLocation(
module-XXXXXXXXXX.rs:5:1, module-XXXXXXXXXX.rs:5:1,
), ),
@ -211,12 +255,19 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
body: Scalar, body: Scalar,
}, },
range: TypeIndexRange { range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 }, small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 }, big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
}, },
write: None, write: None,
}, },
@ -224,6 +275,7 @@ Simulation {
ty: Clock, ty: Clock,
value: OpaqueSimValue { value: OpaqueSimValue {
bits: 0x1_u1, bits: 0x1_u1,
sim_only_values: [],
}, },
}, },
}, },

View file

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

View file

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

View file

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

View file

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

View file

@ -283,6 +283,12 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
memories: StatePartLayout<Memories> { memories: StatePartLayout<Memories> {
len: 0, len: 0,
@ -691,6 +697,9 @@ Simulation {
0, 0,
], ],
}, },
sim_only_slots: StatePart {
value: [],
},
}, },
io: Instance { io: Instance {
name: <simulator>::ripple_counter, name: <simulator>::ripple_counter,
@ -787,6 +796,30 @@ Simulation {
), ),
f: ..., f: ...,
}, },
sim_io_to_generator_map: {
ModuleIO {
name: sw_reg::clk,
is_input: true,
ty: Clock,
..
}: ModuleIO {
name: sw_reg::clk,
is_input: true,
ty: Clock,
..
},
ModuleIO {
name: sw_reg::o,
is_input: false,
ty: Bool,
..
}: ModuleIO {
name: sw_reg::o,
is_input: false,
ty: Bool,
..
},
},
source_location: SourceLocation( source_location: SourceLocation(
module-XXXXXXXXXX-2.rs:4:1, module-XXXXXXXXXX-2.rs:4:1,
), ),
@ -815,12 +848,19 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
body: Scalar, body: Scalar,
}, },
range: TypeIndexRange { range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 3, len: 0 }, small_slots: StatePartIndexRange<SmallSlots> { start: 3, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 33, len: 1 }, big_slots: StatePartIndexRange<BigSlots> { start: 33, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
}, },
write: None, write: None,
}, },
@ -828,6 +868,7 @@ Simulation {
ty: Clock, ty: Clock,
value: OpaqueSimValue { value: OpaqueSimValue {
bits: 0x0_u1, bits: 0x0_u1,
sim_only_values: [],
}, },
}, },
}, },
@ -884,6 +925,30 @@ Simulation {
), ),
f: ..., f: ...,
}, },
sim_io_to_generator_map: {
ModuleIO {
name: sw_reg::clk,
is_input: true,
ty: Clock,
..
}: ModuleIO {
name: sw_reg::clk,
is_input: true,
ty: Clock,
..
},
ModuleIO {
name: sw_reg::o,
is_input: false,
ty: Bool,
..
}: ModuleIO {
name: sw_reg::o,
is_input: false,
ty: Bool,
..
},
},
source_location: SourceLocation( source_location: SourceLocation(
module-XXXXXXXXXX-2.rs:4:1, module-XXXXXXXXXX-2.rs:4:1,
), ),
@ -912,12 +977,19 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
body: Scalar, body: Scalar,
}, },
range: TypeIndexRange { range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 6, len: 0 }, small_slots: StatePartIndexRange<SmallSlots> { start: 6, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 44, len: 1 }, big_slots: StatePartIndexRange<BigSlots> { start: 44, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
}, },
write: None, write: None,
}, },
@ -925,6 +997,7 @@ Simulation {
ty: Clock, ty: Clock,
value: OpaqueSimValue { value: OpaqueSimValue {
bits: 0x0_u1, bits: 0x0_u1,
sim_only_values: [],
}, },
}, },
}, },
@ -981,6 +1054,30 @@ Simulation {
), ),
f: ..., f: ...,
}, },
sim_io_to_generator_map: {
ModuleIO {
name: sw_reg::clk,
is_input: true,
ty: Clock,
..
}: ModuleIO {
name: sw_reg::clk,
is_input: true,
ty: Clock,
..
},
ModuleIO {
name: sw_reg::o,
is_input: false,
ty: Bool,
..
}: ModuleIO {
name: sw_reg::o,
is_input: false,
ty: Bool,
..
},
},
source_location: SourceLocation( source_location: SourceLocation(
module-XXXXXXXXXX-2.rs:4:1, module-XXXXXXXXXX-2.rs:4:1,
), ),
@ -1009,12 +1106,19 @@ Simulation {
], ],
.. ..
}, },
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
}, },
body: Scalar, body: Scalar,
}, },
range: TypeIndexRange { range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 9, len: 0 }, small_slots: StatePartIndexRange<SmallSlots> { start: 9, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 55, len: 1 }, big_slots: StatePartIndexRange<BigSlots> { start: 55, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
}, },
write: None, write: None,
}, },
@ -1022,6 +1126,7 @@ Simulation {
ty: Clock, ty: Clock,
value: OpaqueSimValue { value: OpaqueSimValue {
bits: 0x0_u1, bits: 0x0_u1,
sim_only_values: [],
}, },
}, },
}, },

View file

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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,185 @@
$timescale 1 ps $end
$scope module sim_only_connects $end
$scope struct cd $end
$var wire 1 ! clk $end
$var wire 1 " rst $end
$upscope $end
$var string 1 # inp $end
$var string 1 $ out1 $end
$var string 1 % out2 $end
$var string 1 & out3 $end
$scope struct helper1 $end
$scope struct cd $end
$var wire 1 + clk $end
$var wire 1 , rst $end
$upscope $end
$var string 1 - inp $end
$var string 1 . out $end
$upscope $end
$scope module sim_only_connects_helper $end
$scope struct cd $end
$var wire 1 ' clk $end
$var wire 1 ( rst $end
$upscope $end
$var string 1 ) inp $end
$var string 1 * out $end
$upscope $end
$var string 1 / delay1 $end
$var reg 1 0 delay1_empty $end
$scope struct helper2 $end
$scope struct cd $end
$var wire 1 5 clk $end
$var wire 1 6 rst $end
$upscope $end
$var string 1 7 inp $end
$var string 1 8 out $end
$upscope $end
$scope module sim_only_connects_helper_2 $end
$scope struct cd $end
$var wire 1 1 clk $end
$var wire 1 2 rst $end
$upscope $end
$var string 1 3 inp $end
$var string 1 4 out $end
$upscope $end
$upscope $end
$enddefinitions $end
$dumpvars
0!
1"
s{\"extra\":\x20\"value\"} #
s{} $
s{} %
s{} &
0'
1(
s{} )
s{} *
0+
1,
s{} -
s{} .
s{} /
00
01
12
s{} 3
s{} 4
05
16
s{} 7
s{} 8
$end
#1000000
1!
1'
1+
10
11
15
s{\"extra\":\x20\"value\"} $
s{\"extra\":\x20\"value\"} )
s{\"extra\":\x20\"value\"} -
s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} *
s{\"bar\":\x20\"\",\x20\"foo\":\x20\"baz\"} 4
s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} %
s{\"bar\":\x20\"\",\x20\"foo\":\x20\"baz\"} &
s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} .
s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 3
s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 7
s{\"bar\":\x20\"\",\x20\"foo\":\x20\"baz\"} 8
#2000000
0!
0"
0'
0(
0+
0,
01
02
05
06
#3000000
1!
1'
1+
s{\"extra\":\x20\"value\"} /
00
11
15
s{\"bar\":\x20\"baz\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 4
s{\"bar\":\x20\"baz\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} &
s{\"bar\":\x20\"baz\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 8
#4000000
0!
0'
0+
01
05
#5000000
1!
1'
1+
11
15
#6000000
0!
0'
0+
01
05
#7000000
1!
1'
1+
11
15
#8000000
0!
0'
0+
01
05
#9000000
1!
1'
1+
11
15
#10000000
0!
0'
0+
01
05
#11000000
1!
1'
1+
11
15
#12000000
0!
0'
0+
01
05
#13000000
1!
1'
1+
11
15
#14000000
0!
0'
0+
01
05
#15000000
1!
1'
1+
11
15
#16000000

View file

@ -45,6 +45,64 @@ note: required by a bound in `fayalite::intern::Interned`
| pub struct Interned<T: ?Sized + 'static + Send + Sync> { | pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned` | ^^^^ required by this bound in `Interned`
error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
--> tests/ui/simvalue_is_not_internable.rs:11:26
|
11 | fn f(v: SimValue<()>) -> Interned<SimValue<()>> {
| ^^^^^^^^^^^^^^^^^^^^^^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
|
= help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
| pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
| ^^^^^^^^^^^^^^^
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 error[E0277]: the trait bound `SimValue<()>: Intern` is not satisfied
--> tests/ui/simvalue_is_not_internable.rs:12:26 --> tests/ui/simvalue_is_not_internable.rs:12:26
| |
@ -138,6 +196,73 @@ help: consider dereferencing here
12 | Intern::intern_sized(*v) 12 | Intern::intern_sized(*v)
| + | +
error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:26
|
12 | Intern::intern_sized(v)
| -------------------- ^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
= help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
| pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
| ^^^^^^^^^^^^^^^
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 error[E0277]: `Cell<util::alternating_cell::State>` cannot be shared between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:5 --> 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> { | pub struct Interned<T: ?Sized + 'static + Send + Sync> {
| ^^^^ required by this bound in `Interned` | ^^^^ required by this bound in `Interned`
error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
--> tests/ui/simvalue_is_not_internable.rs:12:5
|
12 | Intern::intern_sized(v)
| ^^^^^^^^^^^^^^^^^^^^^^^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
|
= help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
note: required because it appears within the type `DynSimOnlyValue`
--> src/sim/value/sim_only_value_unsafe.rs
|
| pub struct DynSimOnlyValue(Rc<dyn DynSimOnlyValueTrait>);
| ^^^^^^^^^^^^^^^
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", "SyncReset": "Visible",
"Reset": "Visible", "Reset": "Visible",
"Clock": "Visible", "Clock": "Visible",
"PhantomConst": "Visible" "PhantomConst": "Visible",
"DynSimOnly": "Visible"
} }
}, },
"Bundle": { "Bundle": {
@ -1271,10 +1272,15 @@
}, },
"generics": "<T: ?Sized + crate::phantom_const::PhantomConstValue>" "generics": "<T: ?Sized + crate::phantom_const::PhantomConstValue>"
}, },
"ExternModuleSimulation": { "DynSimOnly": {
"data": { "data": {
"$kind": "Opaque" "$kind": "Opaque"
} }
},
"ExternModuleSimulation": {
"data": {
"$kind": "ManualImpl"
}
} }
} }
} }