WIP making progress

This commit is contained in:
Jacob Lifshay 2025-09-01 04:46:24 -07:00
parent 6d36698adf
commit 4b4ef4b459
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
24 changed files with 2553 additions and 653 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -16,7 +16,8 @@ use crate::{
sim::value::{SimValue, SimValuePartialEq},
source_location::SourceLocation,
ty::{
CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, StaticType, Type,
CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, OpaqueSimValueSize,
OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type,
TypeProperties,
},
util::HashMap,
@ -120,6 +121,7 @@ impl EnumTypePropertiesBuilder {
is_storable: true,
is_castable_from_bits: true,
bit_width: 0,
sim_only_values_len: 0,
},
variant_count: 0,
}
@ -138,9 +140,14 @@ impl EnumTypePropertiesBuilder {
is_storable,
is_castable_from_bits,
bit_width,
sim_only_values_len,
}) = field_props
{
assert!(is_passive, "variant type must be a passive type");
assert!(
sim_only_values_len == 0,
"can't have `SimOnlyValue`s in an Enum"
);
type_properties = TypeProperties {
is_passive: true,
is_storable: type_properties.is_storable & is_storable,
@ -151,6 +158,7 @@ impl EnumTypePropertiesBuilder {
} else {
type_properties.bit_width
},
sim_only_values_len: 0,
};
}
Self {
@ -381,19 +389,27 @@ impl Type for Enum {
fn source_location() -> SourceLocation {
SourceLocation::builtin()
}
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue {
assert_eq!(bits.len(), self.type_properties().bit_width);
OpaqueSimValue::from_bitslice(bits)
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue {
assert_eq!(self.type_properties().size(), opaque.size());
opaque.to_owned()
}
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
assert_eq!(bits.len(), self.type_properties().bit_width);
assert_eq!(value.bit_width(), self.type_properties().bit_width);
value.bits_mut().bits_mut().copy_from_bitslice(bits);
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
) {
assert_eq!(self.type_properties().size(), opaque.size());
assert_eq!(value.size(), opaque.size());
value.clone_from_slice(opaque);
}
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
assert_eq!(bits.len(), self.type_properties().bit_width);
assert_eq!(value.bit_width(), self.type_properties().bit_width);
bits.copy_from_bitslice(value.bits().bits());
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w> {
assert_eq!(self.type_properties().size(), writer.size());
assert_eq!(value.size(), writer.size());
writer.fill_cloned_from_slice(value.as_slice())
}
}
@ -458,23 +474,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)
}
}

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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!(),
}
}
}

View file

@ -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,

View file

@ -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>,

View file

@ -9,60 +9,82 @@ use crate::{
expr::{CastBitsTo, Expr, ToExpr},
int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue},
reset::{AsyncReset, Reset, SyncReset},
ty::{CanonicalType, StaticType, Type},
source_location::SourceLocation,
ty::{
CanonicalType, OpaqueSimValue, OpaqueSimValueSize, OpaqueSimValueSlice,
OpaqueSimValueWriter, StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
util::{
ConstUsize,
ConstUsize, HashMap,
alternating_cell::{AlternatingCell, AlternatingCellMethods},
},
};
use bitvec::{slice::BitSlice, vec::BitVec};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use hashbrown::hash_map::Entry;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _};
use std::{
fmt,
borrow::Cow,
fmt::{self, Write},
hash::{BuildHasher, Hash, Hasher, RandomState},
ops::{Deref, DerefMut},
sync::Arc,
sync::{Arc, Mutex},
};
pub(crate) mod sim_only_value_unsafe;
pub use sim_only_value_unsafe::{
DynSimOnlyValue, DynSimOnlyValueType, SimOnlyValue, SimOnlyValueTrait, SimOnlyValueType,
};
#[derive(Copy, Clone, Eq, PartialEq)]
enum ValidFlags {
BothValid = 0,
OnlyValueValid = 1,
OnlyBitsValid = 2,
OnlyOpaqueValid = 2,
}
#[derive(Clone)]
struct SimValueInner<T: Type> {
value: T::SimValue,
bits: UIntValue,
opaque: OpaqueSimValue,
valid_flags: ValidFlags,
ty: T,
sim_only_values_len: usize,
}
impl<T: Type> SimValueInner<T> {
fn fill_bits(&mut self) {
fn size(&self) -> OpaqueSimValueSize {
OpaqueSimValueSize {
bit_width: self.opaque.bit_width(),
sim_only_values_len: self.sim_only_values_len,
}
}
fn fill_opaque(&mut self) {
match self.valid_flags {
ValidFlags::BothValid | ValidFlags::OnlyBitsValid => {}
ValidFlags::BothValid | ValidFlags::OnlyOpaqueValid => {}
ValidFlags::OnlyValueValid => {
self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut());
OpaqueSimValueWriter::rewrite_with(self.size(), &mut self.opaque, |writer| {
self.ty.sim_value_to_opaque(&self.value, writer)
});
self.valid_flags = ValidFlags::BothValid;
}
}
}
fn into_bits(mut self) -> UIntValue {
self.fill_bits();
self.bits
fn into_opaque(mut self) -> OpaqueSimValue {
self.fill_opaque();
self.opaque
}
fn bits_mut(&mut self) -> &mut UIntValue {
self.fill_bits();
self.valid_flags = ValidFlags::OnlyBitsValid;
&mut self.bits
fn opaque_mut(&mut self) -> &mut OpaqueSimValue {
self.fill_opaque();
self.valid_flags = ValidFlags::OnlyOpaqueValid;
&mut self.opaque
}
fn fill_value(&mut self) {
match self.valid_flags {
ValidFlags::BothValid | ValidFlags::OnlyValueValid => {}
ValidFlags::OnlyBitsValid => {
ValidFlags::OnlyOpaqueValid => {
self.ty
.sim_value_clone_from_bits(&mut self.value, self.bits.bits());
.sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice());
self.valid_flags = ValidFlags::BothValid;
}
}
@ -83,11 +105,13 @@ impl<T: Type> AlternatingCellMethods for SimValueInner<T> {
match self.valid_flags {
ValidFlags::BothValid => return,
ValidFlags::OnlyValueValid => {
self.ty.sim_value_to_bits(&self.value, self.bits.bits_mut())
OpaqueSimValueWriter::rewrite_with(self.size(), &mut self.opaque, |writer| {
self.ty.sim_value_to_opaque(&self.value, writer)
})
}
ValidFlags::OnlyBitsValid => self
ValidFlags::OnlyOpaqueValid => self
.ty
.sim_value_clone_from_bits(&mut self.value, self.bits.bits()),
.sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice()),
}
self.valid_flags = ValidFlags::BothValid;
}
@ -143,13 +167,15 @@ impl<T: Type + Clone> Clone for SimValue<T> {
impl<T: Type> SimValue<T> {
#[track_caller]
pub fn from_bits(ty: T, bits: UIntValue) -> Self {
assert_eq!(ty.canonical().bit_width(), bits.width());
pub fn from_opaque(ty: T, opaque: OpaqueSimValue) -> Self {
let size = ty.canonical().size();
assert_eq!(size, opaque.size());
let inner = SimValueInner {
value: ty.sim_value_from_bits(bits.bits()),
bits,
value: ty.sim_value_from_opaque(opaque.as_slice()),
opaque,
valid_flags: ValidFlags::BothValid,
ty,
sim_only_values_len: size.sim_only_values_len,
};
Self {
inner: AlternatingCell::new_shared(inner),
@ -157,14 +183,30 @@ impl<T: Type> SimValue<T> {
}
#[track_caller]
pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self {
Self::from_bits(ty, UIntValue::new(Arc::new(bits.to_bitvec())))
Self::from_bitslice_and_sim_only_values(ty, bits, Vec::new())
}
#[track_caller]
pub fn from_bitslice_and_sim_only_values(
ty: T,
bits: &BitSlice,
sim_only_values: Vec<DynSimOnlyValue>,
) -> Self {
Self::from_opaque(
ty,
OpaqueSimValue::from_bitslice_and_sim_only_values(bits, sim_only_values),
)
}
pub fn from_value(ty: T, value: T::SimValue) -> Self {
let type_properties = ty.canonical().type_properties();
let inner = SimValueInner {
bits: UIntValue::new_dyn(Arc::new(BitVec::repeat(false, ty.canonical().bit_width()))),
opaque: OpaqueSimValue::from_bits_and_sim_only_values(
UIntValue::new_dyn(Arc::new(BitVec::repeat(false, type_properties.bit_width))),
Vec::with_capacity(type_properties.sim_only_values_len),
),
value,
valid_flags: ValidFlags::OnlyValueValid,
ty,
sim_only_values_len: type_properties.sim_only_values_len,
};
Self {
inner: AlternatingCell::new_unique(inner),
@ -173,18 +215,24 @@ impl<T: Type> SimValue<T> {
pub fn ty(this: &Self) -> T {
this.inner.share().ty
}
pub fn into_bits(this: Self) -> UIntValue {
this.inner.into_inner().into_bits()
pub fn into_opaque(this: Self) -> OpaqueSimValue {
this.inner.into_inner().into_opaque()
}
pub fn into_ty_and_bits(this: Self) -> (T, UIntValue) {
pub fn into_ty_and_opaque(this: Self) -> (T, OpaqueSimValue) {
let inner = this.inner.into_inner();
(inner.ty, inner.into_bits())
(inner.ty, inner.into_opaque())
}
pub fn opaque(this: &Self) -> &OpaqueSimValue {
&this.inner.share().opaque
}
pub fn opaque_mut(this: &mut Self) -> &mut OpaqueSimValue {
&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)
}
}

View file

@ -0,0 +1,357 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
//! `unsafe` parts of [`DynSimOnlyValue`]
use serde::{Serialize, de::DeserializeOwned};
use std::{
alloc::{Layout, alloc, dealloc, handle_alloc_error},
any::TypeId,
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
mem::ManuallyDrop,
ptr::{self, NonNull},
};
struct SimOnlyValueVTable {
layout: Layout,
// TODO: replace with TypeId once TypeId::of is const-stable
type_id: fn() -> TypeId,
type_name: fn() -> &'static str,
drop_in_place: unsafe fn(this: NonNull<()>),
eq: unsafe fn(this: NonNull<()>, other: NonNull<()>) -> bool,
hash: unsafe fn(this: NonNull<()>, hasher: &mut dyn Hasher),
debug_fmt: unsafe fn(this: NonNull<()>, f: &mut fmt::Formatter<'_>) -> fmt::Result,
serialize_to_json_string: unsafe fn(this: NonNull<()>) -> serde_json::Result<String>,
deserialize_into_uninit_from_json_string:
unsafe fn(this: NonNull<()>, json_str: &str) -> serde_json::Result<()>,
clone_into_uninit: unsafe fn(target: NonNull<()>, src: NonNull<()>),
clone_from: unsafe fn(this: NonNull<()>, src: NonNull<()>),
}
pub trait SimOnlyValueTrait:
'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone
{
}
impl<T: 'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone> SimOnlyValueTrait
for T
{
}
unsafe trait GetSimOnlyValueVTable: SimOnlyValueTrait {
const VTABLE: &'static SimOnlyValueVTable;
}
unsafe impl<T: SimOnlyValueTrait> GetSimOnlyValueVTable for T {
const VTABLE: &'static SimOnlyValueVTable = &SimOnlyValueVTable {
layout: Layout::new::<T>(),
type_id: TypeId::of::<T>,
type_name: std::any::type_name::<T>,
drop_in_place: |this| unsafe {
this.cast::<T>().drop_in_place();
},
eq: |this, other| unsafe { this.cast::<T>().as_ref() == other.cast::<T>().as_ref() },
hash: |this, mut hasher| unsafe { this.cast::<T>().as_ref().hash(&mut hasher) },
debug_fmt: |this, f| unsafe { fmt::Debug::fmt(this.cast::<T>().as_ref(), f) },
serialize_to_json_string: |this| unsafe {
serde_json::to_string(this.cast::<T>().as_ref())
},
deserialize_into_uninit_from_json_string: |this, json_str| unsafe {
serde_json::from_str(json_str).map(|v| this.cast::<T>().write(v))
},
clone_into_uninit: |target, src| unsafe {
target
.cast::<T>()
.write(Clone::clone(src.cast::<T>().as_ref()));
},
clone_from: |this, src| unsafe {
Clone::clone_from(this.cast::<T>().as_mut(), src.cast::<T>().as_ref());
},
};
}
#[derive(Copy, Clone)]
pub struct DynSimOnlyValueType {
vtable: &'static SimOnlyValueVTable,
}
struct DynSimOnlyValueUninit {
ty: DynSimOnlyValueType,
value: NonNull<()>,
}
impl DynSimOnlyValueUninit {
fn new(ty: DynSimOnlyValueType) -> Self {
let layout = ty.vtable.layout;
let value = if layout.size() == 0 {
ptr::without_provenance_mut(layout.align())
} else {
unsafe { alloc(layout).cast() }
};
let Some(value) = NonNull::new(value) else {
handle_alloc_error(layout)
};
Self { ty, value }
}
unsafe fn assume_init(self) -> DynSimOnlyValue {
let this = ManuallyDrop::new(self);
DynSimOnlyValue {
ty: this.ty,
value: this.value,
}
}
}
impl Drop for DynSimOnlyValueUninit {
fn drop(&mut self) {
let layout = self.ty.vtable.layout;
if layout.size() != 0 {
unsafe {
dealloc(self.value.as_ptr().cast(), layout);
}
}
}
}
impl DynSimOnlyValueType {
pub const fn of<T: SimOnlyValueTrait>() -> Self {
Self {
vtable: <T as GetSimOnlyValueVTable>::VTABLE,
}
}
pub fn type_id(self) -> TypeId {
(self.vtable.type_id)()
}
pub fn type_name(self) -> &'static str {
(self.vtable.type_name)()
}
pub fn is<T: SimOnlyValueTrait>(self) -> bool {
self.type_id() == TypeId::of::<T>()
}
pub fn downcast<T: SimOnlyValueTrait>(self) -> Option<SimOnlyValueType<T>> {
self.is::<T>().then_some(SimOnlyValueType::default())
}
pub fn deserialize_from_json_string(
self,
json_str: &str,
) -> serde_json::Result<DynSimOnlyValue> {
let retval = DynSimOnlyValueUninit::new(self);
unsafe {
(self.vtable.deserialize_into_uninit_from_json_string)(retval.value, json_str)?;
Ok(retval.assume_init())
}
}
}
impl PartialEq for DynSimOnlyValueType {
fn eq(&self, other: &Self) -> bool {
if ptr::eq(self.vtable, other.vtable) {
true
} else if self.vtable.layout != other.vtable.layout {
false
} else {
(self.vtable.type_id)() == (other.vtable.type_id)()
}
}
}
impl Eq for DynSimOnlyValueType {}
impl Hash for DynSimOnlyValueType {
fn hash<H: Hasher>(&self, state: &mut H) {
(self.vtable.type_id)().hash(state);
}
}
impl fmt::Debug for DynSimOnlyValueType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SimOnlyValueType<{}>", (self.vtable.type_name)())
}
}
impl<T: SimOnlyValueTrait> From<SimOnlyValueType<T>> for DynSimOnlyValueType {
fn from(value: SimOnlyValueType<T>) -> Self {
let SimOnlyValueType(PhantomData) = value;
Self {
vtable: <T as GetSimOnlyValueVTable>::VTABLE,
}
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct SimOnlyValueType<T: SimOnlyValueTrait>(PhantomData<fn(T) -> T>);
impl<T: SimOnlyValueTrait> SimOnlyValueType<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<T: SimOnlyValueTrait> Copy for SimOnlyValueType<T> {}
impl<T: SimOnlyValueTrait> Default for SimOnlyValueType<T> {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Eq, PartialEq, Hash, Default, PartialOrd, Ord)]
pub struct SimOnlyValue<T: SimOnlyValueTrait>(Box<T>);
impl<T: SimOnlyValueTrait> SimOnlyValue<T> {
pub fn with_dyn_ref<F: FnOnce(&DynSimOnlyValue) -> R, R>(&self, f: F) -> R {
let dyn_ref = ManuallyDrop::new(DynSimOnlyValue {
ty: SimOnlyValueType::<T>::default().into(),
value: NonNull::<T>::from_ref(&self.0).cast(),
});
f(&dyn_ref)
}
pub fn from_box(v: Box<T>) -> Self {
Self(v)
}
pub fn new(v: T) -> Self {
Self(Box::new(v))
}
pub fn into_inner(this: Self) -> T {
*this.0
}
pub fn into_inner_box(this: Self) -> Box<T> {
this.0
}
pub fn into_dyn(this: Self) -> DynSimOnlyValue {
DynSimOnlyValue::from(this)
}
}
impl<T: SimOnlyValueTrait> std::ops::Deref for SimOnlyValue<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: SimOnlyValueTrait> std::ops::DerefMut for SimOnlyValue<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub struct DynSimOnlyValue {
ty: DynSimOnlyValueType,
value: NonNull<()>,
}
struct DebugDynSimOnlyValueInner<'a>(&'a DynSimOnlyValue);
impl<'a> fmt::Debug for DebugDynSimOnlyValueInner<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
unsafe { (self.0.ty.vtable.debug_fmt)(self.0.value, f) }
}
}
impl fmt::Debug for DynSimOnlyValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SimOnlyValue<{}>", self.ty.type_name())?;
f.debug_tuple("")
.field(&DebugDynSimOnlyValueInner(self))
.finish()
}
}
impl PartialEq for DynSimOnlyValue {
fn eq(&self, other: &Self) -> bool {
self.ty == other.ty && unsafe { (self.ty.vtable.eq)(self.value, other.value) }
}
}
impl Eq for DynSimOnlyValue {}
impl Hash for DynSimOnlyValue {
fn hash<H: Hasher>(&self, state: &mut H) {
self.ty.hash(state);
unsafe { (self.ty.vtable.hash)(self.value, state) };
}
}
impl Clone for DynSimOnlyValue {
fn clone(&self) -> Self {
let retval = DynSimOnlyValueUninit::new(self.ty);
unsafe {
(self.ty.vtable.clone_into_uninit)(retval.value, self.value);
retval.assume_init()
}
}
fn clone_from(&mut self, source: &Self) {
if self.ty == source.ty {
unsafe { (self.ty.vtable.clone_from)(self.value, source.value) };
} else {
*self = source.clone();
}
}
}
impl Drop for DynSimOnlyValue {
fn drop(&mut self) {
unsafe {
ptr::read(self).drop_in_place_and_keep_alloc();
}
}
}
impl<T: SimOnlyValueTrait> From<SimOnlyValue<T>> for DynSimOnlyValue {
fn from(value: SimOnlyValue<T>) -> Self {
unsafe {
Self {
ty: SimOnlyValueType::<T>::default().into(),
value: NonNull::new_unchecked(Box::into_raw(value.0)).cast::<()>(),
}
}
}
}
impl DynSimOnlyValue {
pub fn ty(&self) -> DynSimOnlyValueType {
self.ty
}
pub fn type_id(&self) -> TypeId {
self.ty.type_id()
}
pub fn is<T: SimOnlyValueTrait>(&self) -> bool {
self.ty.is::<T>()
}
pub fn downcast<T: SimOnlyValueTrait>(self) -> Result<SimOnlyValue<T>, DynSimOnlyValue> {
let Some(_) = self.ty.downcast::<T>() else {
return Err(self);
};
Ok(SimOnlyValue(unsafe {
Box::from_raw(ManuallyDrop::new(self).value.as_ptr().cast::<T>())
}))
}
pub fn downcast_ref<T: SimOnlyValueTrait>(&self) -> Option<&T> {
self.ty
.downcast::<T>()
.map(|_| unsafe { &*self.value.as_ptr().cast::<T>() })
}
pub fn downcast_mut<T: SimOnlyValueTrait>(&mut self) -> Option<&mut T> {
self.ty
.downcast::<T>()
.map(|_| unsafe { &mut *self.value.as_ptr().cast::<T>() })
}
pub fn serialize_to_json_string(&self) -> serde_json::Result<String> {
unsafe { (self.ty.vtable.serialize_to_json_string)(self.value) }
}
fn forget_and_keep_alloc(self) -> DynSimOnlyValueUninit {
let this = ManuallyDrop::new(self);
DynSimOnlyValueUninit {
ty: this.ty,
value: this.value,
}
}
fn drop_in_place_and_keep_alloc(self) -> DynSimOnlyValueUninit {
let retval = self.forget_and_keep_alloc();
unsafe { (retval.ty.vtable.drop_in_place)(retval.value) };
retval
}
}

View file

@ -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> {

View file

@ -11,13 +11,21 @@ use crate::{
intern::{Intern, Interned},
phantom_const::PhantomConst,
reset::{AsyncReset, Reset, SyncReset},
sim::value::{SimValue, ToSimValueWithType},
sim::value::{DynSimOnlyValue, DynSimOnlyValueType, SimValue, ToSimValueWithType},
source_location::SourceLocation,
util::ConstUsize,
util::{ConstUsize, slice_range, try_slice_range},
};
use bitvec::slice::BitSlice;
use bitvec::{slice::BitSlice, vec::BitVec};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned};
use std::{fmt, hash::Hash, iter::FusedIterator, ops::Index, sync::Arc};
use std::{
fmt,
hash::Hash,
iter::{FusedIterator, Sum},
marker::PhantomData,
mem,
ops::{Add, AddAssign, Bound, Index, Mul, MulAssign, Range, Sub, SubAssign},
sync::Arc,
};
pub(crate) mod serde_impls;
@ -28,6 +36,23 @@ pub struct TypeProperties {
pub is_storable: bool,
pub is_castable_from_bits: bool,
pub bit_width: usize,
pub sim_only_values_len: usize,
}
impl TypeProperties {
pub const fn size(self) -> OpaqueSimValueSize {
let Self {
is_passive: _,
is_storable: _,
is_castable_from_bits: _,
bit_width,
sim_only_values_len,
} = self;
OpaqueSimValueSize {
bit_width,
sim_only_values_len,
}
}
}
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
@ -43,6 +68,7 @@ pub enum CanonicalType {
Reset(Reset),
Clock(Clock),
PhantomConst(PhantomConst),
DynSimOnlyValueType(DynSimOnlyValueType),
}
impl fmt::Debug for CanonicalType {
@ -59,6 +85,7 @@ impl fmt::Debug for CanonicalType {
Self::Reset(v) => v.fmt(f),
Self::Clock(v) => v.fmt(f),
Self::PhantomConst(v) => v.fmt(f),
Self::DynSimOnlyValueType(v) => v.fmt(f),
}
}
}
@ -95,6 +122,7 @@ impl CanonicalType {
CanonicalType::Reset(v) => v.type_properties(),
CanonicalType::Clock(v) => v.type_properties(),
CanonicalType::PhantomConst(v) => v.type_properties(),
CanonicalType::DynSimOnlyValueType(v) => v.type_properties(),
}
}
pub fn is_passive(self) -> bool {
@ -109,6 +137,12 @@ impl CanonicalType {
pub fn bit_width(self) -> usize {
self.type_properties().bit_width
}
pub fn sim_only_values_len(self) -> usize {
self.type_properties().sim_only_values_len
}
pub fn size(self) -> OpaqueSimValueSize {
self.type_properties().size()
}
pub fn can_connect(self, rhs: Self) -> bool {
match self {
CanonicalType::UInt(lhs) => {
@ -177,6 +211,12 @@ impl CanonicalType {
};
lhs.can_connect(rhs)
}
CanonicalType::DynSimOnlyValueType(lhs) => {
let CanonicalType::DynSimOnlyValueType(rhs) = rhs else {
return false;
};
lhs.can_connect(rhs)
}
}
}
pub(crate) fn as_serde_unexpected_str(self) -> &'static str {
@ -287,6 +327,7 @@ impl_base_type!(SyncReset);
impl_base_type!(Reset);
impl_base_type!(Clock);
impl_base_type!(PhantomConst);
impl_base_type!(DynSimOnlyValueType);
impl_base_type_serde!(Bool, "a Bool");
impl_base_type_serde!(Enum, "an Enum");
@ -348,9 +389,17 @@ pub trait Type:
fn canonical(&self) -> CanonicalType;
fn from_canonical(canonical_type: CanonicalType) -> Self;
fn source_location() -> SourceLocation;
fn sim_value_from_bits(&self, bits: &BitSlice) -> Self::SimValue;
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice);
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice);
fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue;
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: OpaqueSimValueSlice<'_>,
);
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: OpaqueSimValueWriter<'w>,
) -> OpaqueSimValueWritten<'w>;
}
pub trait BaseType:
@ -405,6 +454,7 @@ impl Type for CanonicalType {
CanonicalType::Reset(v) => v.mask_type().canonical(),
CanonicalType::Clock(v) => v.mask_type().canonical(),
CanonicalType::PhantomConst(v) => v.mask_type().canonical(),
CanonicalType::DynSimOnlyValueType(v) => v.mask_type().canonical(),
}
}
fn canonical(&self) -> CanonicalType {
@ -416,28 +466,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;

View file

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

View file

@ -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;

View file

@ -5,6 +5,7 @@ use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView};
use std::{
cell::Cell,
fmt::{self, Debug, Write},
ops::{Bound, Range, RangeBounds},
rc::Rc,
sync::{Arc, OnceLock},
};
@ -209,3 +210,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")
}