forked from libre-chip/fayalite
add UIntInRange[Inclusive][Type]
This commit is contained in:
parent
57aae7b7fb
commit
001fd31451
4 changed files with 759 additions and 17 deletions
|
@ -7,6 +7,7 @@ use crate::{
|
||||||
target::{GetTarget, Target},
|
target::{GetTarget, Target},
|
||||||
Expr, NotALiteralExpr, ToExpr, ToLiteralBits,
|
Expr, NotALiteralExpr, ToExpr, ToLiteralBits,
|
||||||
},
|
},
|
||||||
|
hdl,
|
||||||
intern::{Intern, Interned, Memoize},
|
intern::{Intern, Interned, Memoize},
|
||||||
sim::value::{SimValue, ToSimValueWithType},
|
sim::value::{SimValue, ToSimValueWithType},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
|
@ -30,6 +31,23 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod uint_in_range;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub type UIntInRangeType<Start: Size, End: Size> = uint_in_range::UIntInRangeType<Start, End>;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub type UIntInRange<const START: usize, const END: usize> =
|
||||||
|
UIntInRangeType<ConstUsize<START>, ConstUsize<END>>;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub type UIntInRangeInclusiveType<Start: Size, End: Size> =
|
||||||
|
uint_in_range::UIntInRangeInclusiveType<Start, End>;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub type UIntInRangeInclusive<const START: usize, const END: usize> =
|
||||||
|
UIntInRangeInclusiveType<ConstUsize<START>, ConstUsize<END>>;
|
||||||
|
|
||||||
mod sealed {
|
mod sealed {
|
||||||
pub trait BoolOrIntTypeSealed {}
|
pub trait BoolOrIntTypeSealed {}
|
||||||
pub trait SizeSealed {}
|
pub trait SizeSealed {}
|
||||||
|
@ -536,19 +554,14 @@ macro_rules! impl_int {
|
||||||
pub const $name: $generic_name = $generic_name;
|
pub const $name: $generic_name = $generic_name;
|
||||||
|
|
||||||
impl<Width: Size> $name<Width> {
|
impl<Width: Size> $name<Width> {
|
||||||
pub fn new(width: Width::SizeType) -> Self {
|
pub const fn new(width: Width::SizeType) -> Self {
|
||||||
Self { width }
|
Self { width }
|
||||||
}
|
}
|
||||||
pub fn width(self) -> usize {
|
pub fn width(self) -> usize {
|
||||||
Width::as_usize(self.width)
|
Width::as_usize(self.width)
|
||||||
}
|
}
|
||||||
pub fn type_properties(self) -> TypeProperties {
|
pub fn type_properties(self) -> TypeProperties {
|
||||||
TypeProperties {
|
self.as_dyn_int().type_properties_dyn()
|
||||||
is_passive: true,
|
|
||||||
is_storable: true,
|
|
||||||
is_castable_from_bits: true,
|
|
||||||
bit_width: self.width(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn bits_from_bigint_wrapping(self, v: &BigInt) -> BitVec {
|
pub fn bits_from_bigint_wrapping(self, v: &BigInt) -> BitVec {
|
||||||
BoolOrIntType::bits_from_bigint_wrapping(self, v)
|
BoolOrIntType::bits_from_bigint_wrapping(self, v)
|
||||||
|
@ -624,12 +637,20 @@ macro_rules! impl_int {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $name {
|
impl $name {
|
||||||
pub fn new_dyn(width: usize) -> Self {
|
pub const fn new_dyn(width: usize) -> Self {
|
||||||
Self { width }
|
Self { width }
|
||||||
}
|
}
|
||||||
pub fn bits_to_bigint(bits: &BitSlice) -> BigInt {
|
pub fn bits_to_bigint(bits: &BitSlice) -> BigInt {
|
||||||
<Self as BoolOrIntType>::bits_to_bigint(bits)
|
<Self as BoolOrIntType>::bits_to_bigint(bits)
|
||||||
}
|
}
|
||||||
|
pub const fn type_properties_dyn(self) -> TypeProperties {
|
||||||
|
TypeProperties {
|
||||||
|
is_passive: true,
|
||||||
|
is_storable: true,
|
||||||
|
is_castable_from_bits: true,
|
||||||
|
bit_width: self.width,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Width: KnownSize> $name<Width> {
|
impl<Width: KnownSize> $name<Width> {
|
||||||
|
@ -686,12 +707,10 @@ macro_rules! impl_int {
|
||||||
impl<Width: KnownSize> StaticType for $name<Width> {
|
impl<Width: KnownSize> StaticType for $name<Width> {
|
||||||
const TYPE: Self = Self { width: Width::SIZE };
|
const TYPE: Self = Self { width: Width::SIZE };
|
||||||
const MASK_TYPE: Self::MaskType = Bool;
|
const MASK_TYPE: Self::MaskType = Bool;
|
||||||
const TYPE_PROPERTIES: TypeProperties = TypeProperties {
|
const TYPE_PROPERTIES: TypeProperties = $name {
|
||||||
is_passive: true,
|
width: Width::VALUE,
|
||||||
is_storable: true,
|
}
|
||||||
is_castable_from_bits: true,
|
.type_properties_dyn();
|
||||||
bit_width: Width::VALUE,
|
|
||||||
};
|
|
||||||
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
|
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -905,6 +924,10 @@ impl UInt {
|
||||||
let v: BigUint = v.into();
|
let v: BigUint = v.into();
|
||||||
Self::new(v.bits().try_into().expect("too big"))
|
Self::new(v.bits().try_into().expect("too big"))
|
||||||
}
|
}
|
||||||
|
/// gets the smallest `UInt` that fits `v` losslessly
|
||||||
|
pub const fn for_value_usize(v: usize) -> Self {
|
||||||
|
Self::new((usize::BITS - v.leading_zeros()) as usize)
|
||||||
|
}
|
||||||
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
|
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn range(r: Range<impl Into<BigUint>>) -> Self {
|
pub fn range(r: Range<impl Into<BigUint>>) -> Self {
|
||||||
|
@ -915,6 +938,12 @@ impl UInt {
|
||||||
}
|
}
|
||||||
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
|
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
pub const fn range_usize(r: Range<usize>) -> Self {
|
||||||
|
assert!(r.end != 0, "empty range");
|
||||||
|
Self::range_inclusive_usize(r.start..=(r.end - 1))
|
||||||
|
}
|
||||||
|
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
|
||||||
|
#[track_caller]
|
||||||
pub fn range_inclusive(r: RangeInclusive<impl Into<BigUint>>) -> Self {
|
pub fn range_inclusive(r: RangeInclusive<impl Into<BigUint>>) -> Self {
|
||||||
let (start, end) = r.into_inner();
|
let (start, end) = r.into_inner();
|
||||||
let start: BigUint = start.into();
|
let start: BigUint = start.into();
|
||||||
|
@ -924,6 +953,16 @@ impl UInt {
|
||||||
// so must not take more bits than `end`
|
// so must not take more bits than `end`
|
||||||
Self::for_value(end)
|
Self::for_value(end)
|
||||||
}
|
}
|
||||||
|
/// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty
|
||||||
|
#[track_caller]
|
||||||
|
pub const fn range_inclusive_usize(r: RangeInclusive<usize>) -> Self {
|
||||||
|
let start = *r.start();
|
||||||
|
let end = *r.end();
|
||||||
|
assert!(start <= end, "empty range");
|
||||||
|
// no need to check `start`` since it's no larger than `end`
|
||||||
|
// so must not take more bits than `end`
|
||||||
|
Self::for_value_usize(end)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SInt {
|
impl SInt {
|
||||||
|
|
614
crates/fayalite/src/int/uint_in_range.rs
Normal file
614
crates/fayalite/src/int/uint_in_range.rs
Normal file
|
@ -0,0 +1,614 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bundle::{Bundle, BundleField, BundleType, BundleTypePropertiesBuilder, NoBuilder},
|
||||||
|
expr::{
|
||||||
|
ops::{ExprCastTo, ExprPartialEq, ExprPartialOrd},
|
||||||
|
CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd,
|
||||||
|
},
|
||||||
|
int::{Bool, DynSize, KnownSize, Size, SizeType, UInt, UIntType},
|
||||||
|
intern::{Intern, Interned},
|
||||||
|
phantom_const::PhantomConst,
|
||||||
|
sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType},
|
||||||
|
source_location::SourceLocation,
|
||||||
|
ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
|
||||||
|
};
|
||||||
|
use bitvec::{order::Lsb0, slice::BitSlice, view::BitView};
|
||||||
|
use serde::{
|
||||||
|
de::{value::UsizeDeserializer, Error, Visitor},
|
||||||
|
Deserialize, Deserializer, Serialize, Serializer,
|
||||||
|
};
|
||||||
|
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_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
||||||
|
Bool.sim_value_from_bits(bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sim_value_clone_from_bits(&self, value: &mut Self::SimValue, bits: &BitSlice) {
|
||||||
|
Bool.sim_value_clone_from_bits(value, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sim_value_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
||||||
|
Bool.sim_value_to_bits(value, bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BundleType for UIntInRangeMaskType {
|
||||||
|
type Builder = NoBuilder;
|
||||||
|
type FilledBuilder = Expr<UIntInRangeMaskType>;
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<UIntInRangeMaskType> for bool {
|
||||||
|
fn to_sim_value_with_type(&self, ty: UIntInRangeMaskType) -> SimValue<UIntInRangeMaskType> {
|
||||||
|
SimValue::from_value(ty, *self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<Bool> for UIntInRangeMaskType {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: Bool) -> Expr<Bool> {
|
||||||
|
src.cast_to_bits().cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCastTo<UIntInRangeMaskType> for Bool {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: UIntInRangeMaskType) -> Expr<UIntInRangeMaskType> {
|
||||||
|
src.cast_to_static::<UInt<1>>().cast_bits_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprPartialEq<Self> for UIntInRangeMaskType {
|
||||||
|
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimValuePartialEq<Self> for UIntInRangeMaskType {
|
||||||
|
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||||
|
**this == **other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PhantomConstRangeMaskType = <PhantomConst<SerdeRange<DynSize, DynSize>> 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: Size, End: Size> {
|
||||||
|
start: Start::SizeType,
|
||||||
|
end: End::SizeType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: KnownSize, End: KnownSize> Default for $SerdeRange<Start, End> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
start: Start::SIZE,
|
||||||
|
end: End::SIZE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for $SerdeRange<DynSize, DynSize> {
|
||||||
|
type Err = RangeParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
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<Start: Size, End: Size> fmt::Display for $SerdeRange<Start, End> {
|
||||||
|
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<Start: Size, End: Size> Serialize for $SerdeRange<Start, End> {
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
serializer.collect_str(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, Start: Size, End: Size> Deserialize<'de> for $SerdeRange<Start, End> {
|
||||||
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
|
struct SerdeRangeVisitor<Start: Size, End: Size>(PhantomData<(Start, End)>);
|
||||||
|
impl<'de, Start: Size, End: Size> Visitor<'de> for SerdeRangeVisitor<Start, End> {
|
||||||
|
type Value = $SerdeRange<Start, End>;
|
||||||
|
|
||||||
|
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("<int>")?;
|
||||||
|
};
|
||||||
|
f.write_str($range_operator_str)?;
|
||||||
|
if let Some(end) = End::KNOWN_VALUE {
|
||||||
|
write!(f, "{end}")?;
|
||||||
|
} else {
|
||||||
|
f.write_str("<int>")?;
|
||||||
|
};
|
||||||
|
f.write_str("\" that is a non-empty range")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
|
||||||
|
let $SerdeRange::<DynSize, DynSize> { start, end } =
|
||||||
|
v.parse().map_err(|_| {
|
||||||
|
Error::invalid_value(serde::de::Unexpected::Str(v), &self)
|
||||||
|
})?;
|
||||||
|
let start =
|
||||||
|
Start::SizeType::deserialize(UsizeDeserializer::<E>::new(start))?;
|
||||||
|
let end = End::SizeType::deserialize(UsizeDeserializer::<E>::new(end))?;
|
||||||
|
Ok($SerdeRange { start, end })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bytes<E: Error>(self, v: &[u8]) -> Result<Self::Value, E> {
|
||||||
|
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<Start: Size, End: Size> {
|
||||||
|
value: UInt,
|
||||||
|
range: PhantomConst<$SerdeRange<Start, End>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: Size, End: Size> $UIntInRangeType<Start, End> {
|
||||||
|
fn from_phantom_const_range(range: PhantomConst<$SerdeRange<Start, End>>) -> 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<Start: Size, End: Size> fmt::Debug for $UIntInRangeType<Start, End> {
|
||||||
|
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<Start: Size, End: Size> Type for $UIntInRangeType<Start, End> {
|
||||||
|
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<Start, End>>::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_bits(&self, bits: &BitSlice) -> Self::SimValue {
|
||||||
|
let mut retval = 0usize;
|
||||||
|
retval.view_bits_mut::<Lsb0>()[..bits.len()].clone_from_bitslice(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_to_bits(&self, value: &Self::SimValue, bits: &mut BitSlice) {
|
||||||
|
bits.clone_from_bitslice(&value.view_bits::<Lsb0>()[..bits.len()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: Size, End: Size> BundleType for $UIntInRangeType<Start, End> {
|
||||||
|
type Builder = NoBuilder;
|
||||||
|
type FilledBuilder = Expr<Self>;
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: KnownSize, End: KnownSize> Default for $UIntInRangeType<Start, End> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::TYPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: KnownSize, End: KnownSize> StaticType for $UIntInRangeType<Start, End> {
|
||||||
|
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<Start, End>>::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<Start, End>>::TYPE_PROPERTIES,
|
||||||
|
)
|
||||||
|
.finish();
|
||||||
|
const MASK_TYPE_PROPERTIES: TypeProperties = UIntInRangeMaskType::TYPE_PROPERTIES;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: Size, End: Size> ToSimValueWithType<$UIntInRangeType<Start, End>> for usize {
|
||||||
|
fn to_sim_value_with_type(
|
||||||
|
&self,
|
||||||
|
ty: $UIntInRangeType<Start, End>,
|
||||||
|
) -> SimValue<$UIntInRangeType<Start, End>> {
|
||||||
|
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<StartSize: SizeType> Index<StartSize> for $UIntInRangeTypeWithoutGenerics {
|
||||||
|
type Output = $UIntInRangeTypeWithStart<StartSize::Size>;
|
||||||
|
|
||||||
|
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: Size>(Start::SizeType);
|
||||||
|
|
||||||
|
impl<Start: Size, EndSize: SizeType<Size = End>, End: Size<SizeType = EndSize>>
|
||||||
|
Index<EndSize> for $UIntInRangeTypeWithStart<Start>
|
||||||
|
{
|
||||||
|
type Output = $UIntInRangeType<Start, End>;
|
||||||
|
|
||||||
|
fn index(&self, end: EndSize) -> &Self::Output {
|
||||||
|
Interned::into_inner($UIntInRangeType::new(self.0, end).intern_sized())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: Size, End: Size> ExprCastTo<UInt> for $UIntInRangeType<Start, End> {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: UInt) -> Expr<UInt> {
|
||||||
|
src.cast_to_bits().cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: Size, End: Size> ExprCastTo<$UIntInRangeType<Start, End>> for UInt {
|
||||||
|
fn cast_to(
|
||||||
|
src: Expr<Self>,
|
||||||
|
to_type: $UIntInRangeType<Start, End>,
|
||||||
|
) -> Expr<$UIntInRangeType<Start, End>> {
|
||||||
|
src.cast_bits_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<LhsStart: Size, LhsEnd: Size, RhsStart: Size, RhsEnd: Size>
|
||||||
|
ExprPartialEq<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||||
|
for $UIntInRangeType<LhsStart, LhsEnd>
|
||||||
|
{
|
||||||
|
fn cmp_eq(
|
||||||
|
lhs: Expr<Self>,
|
||||||
|
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||||
|
) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
fn cmp_ne(
|
||||||
|
lhs: Expr<Self>,
|
||||||
|
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||||
|
) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<LhsStart: Size, LhsEnd: Size, RhsStart: Size, RhsEnd: Size>
|
||||||
|
ExprPartialOrd<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||||
|
for $UIntInRangeType<LhsStart, LhsEnd>
|
||||||
|
{
|
||||||
|
fn cmp_lt(
|
||||||
|
lhs: Expr<Self>,
|
||||||
|
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||||
|
) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_lt(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
fn cmp_le(
|
||||||
|
lhs: Expr<Self>,
|
||||||
|
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||||
|
) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_le(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
fn cmp_gt(
|
||||||
|
lhs: Expr<Self>,
|
||||||
|
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||||
|
) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_gt(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
fn cmp_ge(
|
||||||
|
lhs: Expr<Self>,
|
||||||
|
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||||
|
) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_ge(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<LhsStart: Size, LhsEnd: Size, RhsStart: Size, RhsEnd: Size>
|
||||||
|
SimValuePartialEq<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||||
|
for $UIntInRangeType<LhsStart, LhsEnd>
|
||||||
|
{
|
||||||
|
fn sim_value_eq(
|
||||||
|
this: &SimValue<Self>,
|
||||||
|
other: &SimValue<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||||
|
) -> bool {
|
||||||
|
**this == **other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: Size, End: Size, Width: Size> ExprPartialEq<UIntType<Width>>
|
||||||
|
for $UIntInRangeType<Start, End>
|
||||||
|
{
|
||||||
|
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_eq(rhs)
|
||||||
|
}
|
||||||
|
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_ne(rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: Size, End: Size, Width: Size> ExprPartialEq<$UIntInRangeType<Start, End>>
|
||||||
|
for UIntType<Width>
|
||||||
|
{
|
||||||
|
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||||
|
lhs.cmp_eq(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||||
|
lhs.cmp_ne(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: Size, End: Size, Width: Size> ExprPartialOrd<UIntType<Width>>
|
||||||
|
for $UIntInRangeType<Start, End>
|
||||||
|
{
|
||||||
|
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_lt(rhs)
|
||||||
|
}
|
||||||
|
fn cmp_le(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_le(rhs)
|
||||||
|
}
|
||||||
|
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_gt(rhs)
|
||||||
|
}
|
||||||
|
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||||
|
lhs.cast_to_bits().cmp_ge(rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Start: Size, End: Size, Width: Size> ExprPartialOrd<$UIntInRangeType<Start, End>>
|
||||||
|
for UIntType<Width>
|
||||||
|
{
|
||||||
|
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||||
|
lhs.cmp_lt(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
fn cmp_le(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||||
|
lhs.cmp_le(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||||
|
lhs.cmp_gt(rhs.cast_to_bits())
|
||||||
|
}
|
||||||
|
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||||
|
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<DynSize, DynSize> {
|
||||||
|
fn is_empty(self) -> bool {
|
||||||
|
self.start >= self.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerdeRangeInclusive<DynSize, DynSize> {
|
||||||
|
fn is_empty(self) -> bool {
|
||||||
|
self.start > self.end
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
Expr, ToExpr,
|
Expr, ToExpr,
|
||||||
},
|
},
|
||||||
int::Bool,
|
int::Bool,
|
||||||
intern::{Intern, Interned, InternedCompare, LazyInterned, Memoize},
|
intern::{Intern, Interned, InternedCompare, LazyInterned, LazyInternedTrait, Memoize},
|
||||||
sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType},
|
sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType},
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
ty::{
|
ty::{
|
||||||
|
@ -228,6 +228,11 @@ impl<T: ?Sized + PhantomConstValue> PhantomConst<T> {
|
||||||
value: LazyInterned::Interned(value),
|
value: LazyInterned::Interned(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub const fn new_lazy(v: &'static dyn LazyInternedTrait<T>) -> Self {
|
||||||
|
Self {
|
||||||
|
value: LazyInterned::new_lazy(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn get(self) -> Interned<T> {
|
pub fn get(self) -> Interned<T> {
|
||||||
self.value.interned()
|
self.value.interned()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
assert_export_firrtl, firrtl::ExportOptions, intern::Intern,
|
assert_export_firrtl,
|
||||||
module::transform::simplify_enums::SimplifyEnumsKind, prelude::*, reset::ResetType,
|
firrtl::ExportOptions,
|
||||||
|
int::{UIntInRange, UIntInRangeInclusive},
|
||||||
|
intern::Intern,
|
||||||
|
module::transform::simplify_enums::SimplifyEnumsKind,
|
||||||
|
prelude::*,
|
||||||
|
reset::ResetType,
|
||||||
ty::StaticType,
|
ty::StaticType,
|
||||||
};
|
};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
@ -4547,3 +4552,82 @@ circuit check_struct_cmp_eq:
|
||||||
",
|
",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[hdl_module(outline_generated)]
|
||||||
|
pub fn check_uint_in_range() {
|
||||||
|
#[hdl]
|
||||||
|
let i_0_to_1: UIntInRange<0, 1> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_to_2: UIntInRange<0, 2> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_to_3: UIntInRange<0, 3> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_to_4: UIntInRange<0, 4> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_to_7: UIntInRange<0, 7> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_to_8: UIntInRange<0, 8> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_to_9: UIntInRange<0, 9> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_through_0: UIntInRangeInclusive<0, 0> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_through_1: UIntInRangeInclusive<0, 1> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_through_2: UIntInRangeInclusive<0, 2> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_through_3: UIntInRangeInclusive<0, 3> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_through_4: UIntInRangeInclusive<0, 4> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_through_7: UIntInRangeInclusive<0, 7> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_through_8: UIntInRangeInclusive<0, 8> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let i_0_through_9: UIntInRangeInclusive<0, 9> = m.input();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uint_in_range() {
|
||||||
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
let m = check_uint_in_range();
|
||||||
|
dbg!(m);
|
||||||
|
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
||||||
|
assert_export_firrtl! {
|
||||||
|
m =>
|
||||||
|
"/test/check_uint_in_range.fir": r"FIRRTL version 3.2.0
|
||||||
|
circuit check_uint_in_range:
|
||||||
|
type Ty0 = {value: UInt<0>, range: {}}
|
||||||
|
type Ty1 = {value: UInt<1>, range: {}}
|
||||||
|
type Ty2 = {value: UInt<2>, range: {}}
|
||||||
|
type Ty3 = {value: UInt<2>, range: {}}
|
||||||
|
type Ty4 = {value: UInt<3>, range: {}}
|
||||||
|
type Ty5 = {value: UInt<3>, range: {}}
|
||||||
|
type Ty6 = {value: UInt<4>, range: {}}
|
||||||
|
type Ty7 = {value: UInt<0>, range: {}}
|
||||||
|
type Ty8 = {value: UInt<1>, range: {}}
|
||||||
|
type Ty9 = {value: UInt<2>, range: {}}
|
||||||
|
type Ty10 = {value: UInt<2>, range: {}}
|
||||||
|
type Ty11 = {value: UInt<3>, range: {}}
|
||||||
|
type Ty12 = {value: UInt<3>, range: {}}
|
||||||
|
type Ty13 = {value: UInt<4>, range: {}}
|
||||||
|
type Ty14 = {value: UInt<4>, range: {}}
|
||||||
|
module check_uint_in_range: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
|
input i_0_to_1: Ty0 @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
input i_0_to_2: Ty1 @[module-XXXXXXXXXX.rs 3:1]
|
||||||
|
input i_0_to_3: Ty2 @[module-XXXXXXXXXX.rs 4:1]
|
||||||
|
input i_0_to_4: Ty3 @[module-XXXXXXXXXX.rs 5:1]
|
||||||
|
input i_0_to_7: Ty4 @[module-XXXXXXXXXX.rs 6:1]
|
||||||
|
input i_0_to_8: Ty5 @[module-XXXXXXXXXX.rs 7:1]
|
||||||
|
input i_0_to_9: Ty6 @[module-XXXXXXXXXX.rs 8:1]
|
||||||
|
input i_0_through_0: Ty7 @[module-XXXXXXXXXX.rs 9:1]
|
||||||
|
input i_0_through_1: Ty8 @[module-XXXXXXXXXX.rs 10:1]
|
||||||
|
input i_0_through_2: Ty9 @[module-XXXXXXXXXX.rs 11:1]
|
||||||
|
input i_0_through_3: Ty10 @[module-XXXXXXXXXX.rs 12:1]
|
||||||
|
input i_0_through_4: Ty11 @[module-XXXXXXXXXX.rs 13:1]
|
||||||
|
input i_0_through_7: Ty12 @[module-XXXXXXXXXX.rs 14:1]
|
||||||
|
input i_0_through_8: Ty13 @[module-XXXXXXXXXX.rs 15:1]
|
||||||
|
input i_0_through_9: Ty14 @[module-XXXXXXXXXX.rs 16:1]
|
||||||
|
",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue