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