// SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ bundle::{Bundle, BundleField, BundleType, BundleTypePropertiesBuilder, NoBuilder}, expr::{ CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, ops::{ExprCastTo, ExprPartialEq, ExprPartialOrd}, }, int::{Bool, DynSize, KnownSize, Size, SizeType, UInt, UIntType}, intern::{Intern, InternSlice, Interned}, phantom_const::PhantomConst, sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType}, source_location::SourceLocation, ty::{ CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self, }, }; use bitvec::{order::Lsb0, view::BitView}; use serde::{ Deserialize, Deserializer, Serialize, Serializer, de::{Error, Visitor, value::UsizeDeserializer}, }; use std::{fmt, marker::PhantomData, ops::Index}; const UINT_IN_RANGE_TYPE_FIELD_NAMES: [&'static str; 2] = ["value", "range"]; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] pub struct UIntInRangeMaskType { value: Bool, range: PhantomConstRangeMaskType, } impl Type for UIntInRangeMaskType { type BaseType = Bundle; type MaskType = Self; type SimValue = bool; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { *self } fn canonical(&self) -> CanonicalType { CanonicalType::Bundle(Bundle::new(self.fields())) } fn from_canonical(canonical_type: CanonicalType) -> Self { let fields = Bundle::from_canonical(canonical_type).fields(); let [ BundleField { name: value_name, flipped: false, ty: value, }, BundleField { name: range_name, flipped: false, ty: range, }, ] = *fields else { panic!("expected UIntInRangeMaskType"); }; assert_eq!([&*value_name, &*range_name], UINT_IN_RANGE_TYPE_FIELD_NAMES); let value = Bool::from_canonical(value); let range = PhantomConstRangeMaskType::from_canonical(range); Self { value, range } } fn source_location() -> SourceLocation { SourceLocation::builtin() } fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { Bool.sim_value_from_opaque(opaque) } 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_opaque<'w>( &self, value: &Self::SimValue, writer: OpaqueSimValueWriter<'w>, ) -> OpaqueSimValueWritten<'w> { Bool.sim_value_to_opaque(value, writer) } } impl BundleType for UIntInRangeMaskType { type Builder = NoBuilder; type FilledBuilder = Expr; fn fields(&self) -> Interned<[BundleField]> { let [value_name, range_name] = UINT_IN_RANGE_TYPE_FIELD_NAMES; let Self { value, range } = self; [ BundleField { name: value_name.intern(), flipped: false, ty: value.canonical(), }, BundleField { name: range_name.intern(), flipped: false, ty: range.canonical(), }, ] .intern_slice() } } impl StaticType for UIntInRangeMaskType { const TYPE: Self = Self { value: Bool, range: PhantomConstRangeMaskType::TYPE, }; const MASK_TYPE: Self::MaskType = Self::TYPE; const TYPE_PROPERTIES: TypeProperties = BundleTypePropertiesBuilder::new() .field(false, Bool::TYPE_PROPERTIES) .field(false, PhantomConstRangeMaskType::TYPE_PROPERTIES) .finish(); const MASK_TYPE_PROPERTIES: TypeProperties = Self::TYPE_PROPERTIES; } impl ToSimValueWithType for bool { fn to_sim_value_with_type(&self, ty: UIntInRangeMaskType) -> SimValue { SimValue::from_value(ty, *self) } } impl ExprCastTo for UIntInRangeMaskType { fn cast_to(src: Expr, to_type: Bool) -> Expr { src.cast_to_bits().cast_to(to_type) } } impl ExprCastTo for Bool { fn cast_to(src: Expr, to_type: UIntInRangeMaskType) -> Expr { src.cast_to_static::>().cast_bits_to(to_type) } } impl ExprPartialEq for UIntInRangeMaskType { fn cmp_eq(lhs: Expr, rhs: Expr) -> Expr { lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) } fn cmp_ne(lhs: Expr, rhs: Expr) -> Expr { lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits()) } } impl SimValuePartialEq for UIntInRangeMaskType { fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { **this == **other } } type PhantomConstRangeMaskType = > as Type>::MaskType; #[derive(Default, Copy, Clone, Debug)] struct RangeParseError; macro_rules! define_uint_in_range_type { ( $UIntInRange:ident, $UIntInRangeType:ident, $UIntInRangeTypeWithoutGenerics:ident, $UIntInRangeTypeWithStart:ident, $SerdeRange:ident, $range_operator_str:literal, |$uint_range_usize_start:ident, $uint_range_usize_end:ident| $uint_range_usize:expr, ) => { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] struct $SerdeRange { start: Start::SizeType, end: End::SizeType, } impl Default for $SerdeRange { fn default() -> Self { Self { start: Start::SIZE, end: End::SIZE, } } } impl std::str::FromStr for $SerdeRange { type Err = RangeParseError; fn from_str(s: &str) -> Result { let Some((start, end)) = s.split_once($range_operator_str) else { return Err(RangeParseError); }; if start.is_empty() || start.bytes().any(|b| !b.is_ascii_digit()) || end.is_empty() || end.bytes().any(|b| !b.is_ascii_digit()) { return Err(RangeParseError); } let start = start.parse().map_err(|_| RangeParseError)?; let end = end.parse().map_err(|_| RangeParseError)?; let retval = Self { start, end }; if retval.is_empty() { Err(RangeParseError) } else { Ok(retval) } } } impl fmt::Display for $SerdeRange { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { start, end } = *self; write!( f, "{}{}{}", Start::as_usize(start), $range_operator_str, End::as_usize(end), ) } } impl Serialize for $SerdeRange { fn serialize(&self, serializer: S) -> Result { serializer.collect_str(self) } } impl<'de, Start: Size, End: Size> Deserialize<'de> for $SerdeRange { fn deserialize>(deserializer: D) -> Result { struct SerdeRangeVisitor(PhantomData<(Start, End)>); impl<'de, Start: Size, End: Size> Visitor<'de> for SerdeRangeVisitor { type Value = $SerdeRange; fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("a string with format \"")?; if let Some(start) = Start::KNOWN_VALUE { write!(f, "{start}")?; } else { f.write_str("")?; }; f.write_str($range_operator_str)?; if let Some(end) = End::KNOWN_VALUE { write!(f, "{end}")?; } else { f.write_str("")?; }; f.write_str("\" that is a non-empty range") } fn visit_str(self, v: &str) -> Result { let $SerdeRange:: { start, end } = v.parse().map_err(|_| { Error::invalid_value(serde::de::Unexpected::Str(v), &self) })?; let start = Start::SizeType::deserialize(UsizeDeserializer::::new(start))?; let end = End::SizeType::deserialize(UsizeDeserializer::::new(end))?; Ok($SerdeRange { start, end }) } fn visit_bytes(self, v: &[u8]) -> Result { match std::str::from_utf8(v) { Ok(v) => self.visit_str(v), Err(_) => { Err(Error::invalid_value(serde::de::Unexpected::Bytes(v), &self)) } } } } deserializer.deserialize_str(SerdeRangeVisitor(PhantomData)) } } #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct $UIntInRangeType { value: UInt, range: PhantomConst<$SerdeRange>, } impl $UIntInRangeType { fn from_phantom_const_range(range: PhantomConst<$SerdeRange>) -> Self { let $SerdeRange { start, end } = *range.get(); let $uint_range_usize_start = Start::as_usize(start); let $uint_range_usize_end = End::as_usize(end); Self { value: $uint_range_usize, range, } } pub fn new(start: Start::SizeType, end: End::SizeType) -> Self { Self::from_phantom_const_range(PhantomConst::new( $SerdeRange { start, end }.intern_sized(), )) } } impl fmt::Debug for $UIntInRangeType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { value, range } = self; let $SerdeRange { start, end } = *range.get(); f.debug_struct(&format!( "{}<{}, {}>", stringify!($UIntInRange), Start::as_usize(start), End::as_usize(end), )) .field("value", value) .finish_non_exhaustive() } } impl Type for $UIntInRangeType { type BaseType = Bundle; type MaskType = UIntInRangeMaskType; type SimValue = usize; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { UIntInRangeMaskType::TYPE } fn canonical(&self) -> CanonicalType { CanonicalType::Bundle(Bundle::new(self.fields())) } fn from_canonical(canonical_type: CanonicalType) -> Self { let fields = Bundle::from_canonical(canonical_type).fields(); let [ BundleField { name: value_name, flipped: false, ty: value, }, BundleField { name: range_name, flipped: false, ty: range, }, ] = *fields else { panic!("expected {}", stringify!($UIntInRange)); }; assert_eq!([&*value_name, &*range_name], UINT_IN_RANGE_TYPE_FIELD_NAMES); let value = UInt::from_canonical(value); let range = PhantomConst::<$SerdeRange>::from_canonical(range); let retval = Self::from_phantom_const_range(range); assert_eq!(retval, Self { value, range }); retval } fn source_location() -> SourceLocation { SourceLocation::builtin() } 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::()[..opaque.bit_width()] .clone_from_bitslice(opaque.bits()); retval } fn sim_value_clone_from_opaque( &self, value: &mut Self::SimValue, opaque: OpaqueSimValueSlice<'_>, ) { *value = self.sim_value_from_opaque(opaque); } 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::()[..self.value.width()], )) } } impl BundleType for $UIntInRangeType { type Builder = NoBuilder; type FilledBuilder = Expr; fn fields(&self) -> Interned<[BundleField]> { let [value_name, range_name] = UINT_IN_RANGE_TYPE_FIELD_NAMES; let Self { value, range } = self; [ BundleField { name: value_name.intern(), flipped: false, ty: value.canonical(), }, BundleField { name: range_name.intern(), flipped: false, ty: range.canonical(), }, ] .intern_slice() } } impl Default for $UIntInRangeType { fn default() -> Self { Self::TYPE } } impl StaticType for $UIntInRangeType { const TYPE: Self = { let $uint_range_usize_start = Start::VALUE; let $uint_range_usize_end = End::VALUE; Self { value: $uint_range_usize, range: PhantomConst::<$SerdeRange>::TYPE, } }; const MASK_TYPE: Self::MaskType = UIntInRangeMaskType::TYPE; const TYPE_PROPERTIES: TypeProperties = BundleTypePropertiesBuilder::new() .field(false, Self::TYPE.value.type_properties_dyn()) .field( false, PhantomConst::<$SerdeRange>::TYPE_PROPERTIES, ) .finish(); const MASK_TYPE_PROPERTIES: TypeProperties = UIntInRangeMaskType::TYPE_PROPERTIES; } impl ToSimValueWithType<$UIntInRangeType> for usize { fn to_sim_value_with_type( &self, ty: $UIntInRangeType, ) -> SimValue<$UIntInRangeType> { SimValue::from_value(ty, *self) } } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] pub struct $UIntInRangeTypeWithoutGenerics; #[allow(non_upper_case_globals)] pub const $UIntInRangeType: $UIntInRangeTypeWithoutGenerics = $UIntInRangeTypeWithoutGenerics; impl Index for $UIntInRangeTypeWithoutGenerics { type Output = $UIntInRangeTypeWithStart; fn index(&self, start: StartSize) -> &Self::Output { Interned::into_inner($UIntInRangeTypeWithStart(start).intern_sized()) } } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct $UIntInRangeTypeWithStart(Start::SizeType); impl, End: Size> Index for $UIntInRangeTypeWithStart { type Output = $UIntInRangeType; fn index(&self, end: EndSize) -> &Self::Output { Interned::into_inner($UIntInRangeType::new(self.0, end).intern_sized()) } } impl ExprCastTo for $UIntInRangeType { fn cast_to(src: Expr, to_type: UInt) -> Expr { src.cast_to_bits().cast_to(to_type) } } impl ExprCastTo<$UIntInRangeType> for UInt { fn cast_to( src: Expr, to_type: $UIntInRangeType, ) -> Expr<$UIntInRangeType> { src.cast_bits_to(to_type) } } impl ExprPartialEq<$UIntInRangeType> for $UIntInRangeType { fn cmp_eq( lhs: Expr, rhs: Expr<$UIntInRangeType>, ) -> Expr { lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) } fn cmp_ne( lhs: Expr, rhs: Expr<$UIntInRangeType>, ) -> Expr { lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits()) } } impl ExprPartialOrd<$UIntInRangeType> for $UIntInRangeType { fn cmp_lt( lhs: Expr, rhs: Expr<$UIntInRangeType>, ) -> Expr { lhs.cast_to_bits().cmp_lt(rhs.cast_to_bits()) } fn cmp_le( lhs: Expr, rhs: Expr<$UIntInRangeType>, ) -> Expr { lhs.cast_to_bits().cmp_le(rhs.cast_to_bits()) } fn cmp_gt( lhs: Expr, rhs: Expr<$UIntInRangeType>, ) -> Expr { lhs.cast_to_bits().cmp_gt(rhs.cast_to_bits()) } fn cmp_ge( lhs: Expr, rhs: Expr<$UIntInRangeType>, ) -> Expr { lhs.cast_to_bits().cmp_ge(rhs.cast_to_bits()) } } impl SimValuePartialEq<$UIntInRangeType> for $UIntInRangeType { fn sim_value_eq( this: &SimValue, other: &SimValue<$UIntInRangeType>, ) -> bool { **this == **other } } impl ExprPartialEq> for $UIntInRangeType { fn cmp_eq(lhs: Expr, rhs: Expr>) -> Expr { lhs.cast_to_bits().cmp_eq(rhs) } fn cmp_ne(lhs: Expr, rhs: Expr>) -> Expr { lhs.cast_to_bits().cmp_ne(rhs) } } impl ExprPartialEq<$UIntInRangeType> for UIntType { fn cmp_eq(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { lhs.cmp_eq(rhs.cast_to_bits()) } fn cmp_ne(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { lhs.cmp_ne(rhs.cast_to_bits()) } } impl ExprPartialOrd> for $UIntInRangeType { fn cmp_lt(lhs: Expr, rhs: Expr>) -> Expr { lhs.cast_to_bits().cmp_lt(rhs) } fn cmp_le(lhs: Expr, rhs: Expr>) -> Expr { lhs.cast_to_bits().cmp_le(rhs) } fn cmp_gt(lhs: Expr, rhs: Expr>) -> Expr { lhs.cast_to_bits().cmp_gt(rhs) } fn cmp_ge(lhs: Expr, rhs: Expr>) -> Expr { lhs.cast_to_bits().cmp_ge(rhs) } } impl ExprPartialOrd<$UIntInRangeType> for UIntType { fn cmp_lt(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { lhs.cmp_lt(rhs.cast_to_bits()) } fn cmp_le(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { lhs.cmp_le(rhs.cast_to_bits()) } fn cmp_gt(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { lhs.cmp_gt(rhs.cast_to_bits()) } fn cmp_ge(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { lhs.cmp_ge(rhs.cast_to_bits()) } } }; } define_uint_in_range_type! { UIntInRange, UIntInRangeType, UIntInRangeTypeWithoutGenerics, UIntInRangeTypeWithStart, SerdeRange, "..", |start, end| UInt::range_usize(start..end), } define_uint_in_range_type! { UIntInRangeInclusive, UIntInRangeInclusiveType, UIntInRangeInclusiveTypeWithoutGenerics, UIntInRangeInclusiveTypeWithStart, SerdeRangeInclusive, "..=", |start, end| UInt::range_inclusive_usize(start..=end), } impl SerdeRange { fn is_empty(self) -> bool { self.start >= self.end } } impl SerdeRangeInclusive { fn is_empty(self) -> bool { self.start > self.end } }