sim: add SimValue and reading/writing more than just a scalar
This commit is contained in:
parent
304d8da0e8
commit
21c73051ec
|
@ -4,12 +4,14 @@
|
|||
use crate::{
|
||||
expr::{ops::BundleLiteral, Expr, ToExpr},
|
||||
intern::{Intern, Interned},
|
||||
sim::{SimValue, ToSimValue},
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, StaticType, Type,
|
||||
TypeProperties, TypeWithDeref,
|
||||
},
|
||||
};
|
||||
use bitvec::vec::BitVec;
|
||||
use hashbrown::HashMap;
|
||||
use std::{fmt, marker::PhantomData};
|
||||
|
||||
|
@ -323,7 +325,7 @@ macro_rules! impl_tuple_builder_fields {
|
|||
}
|
||||
|
||||
macro_rules! impl_tuples {
|
||||
([$({#[num = $num:literal, field = $field:ident] $var:ident: $T:ident})*] []) => {
|
||||
([$({#[num = $num:literal, field = $field:ident, ty = $ty_var:ident: $Ty:ident] $var:ident: $T:ident})*] []) => {
|
||||
impl_tuple_builder_fields! {
|
||||
{}
|
||||
[$({
|
||||
|
@ -423,6 +425,79 @@ macro_rules! impl_tuples {
|
|||
BundleLiteral::new(ty, field_values[..].intern()).to_expr()
|
||||
}
|
||||
}
|
||||
impl<$($T: ToSimValue<CanonicalType>,)*> ToSimValue<CanonicalType> for ($($T,)*) {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
ToSimValue::<Bundle>::to_sim_value(self, Bundle::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType>
|
||||
{
|
||||
ToSimValue::<Bundle>::into_sim_value(self, Bundle::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
ToSimValue::<Bundle>::box_into_sim_value(self, Bundle::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
}
|
||||
impl<$($T: ToSimValue<CanonicalType>,)*> ToSimValue<Bundle> for ($($T,)*) {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: Bundle) -> SimValue<Bundle> {
|
||||
let ($($var,)*) = self;
|
||||
let [$($ty_var,)*] = *ty.fields() else {
|
||||
panic!("bundle has wrong number of fields");
|
||||
};
|
||||
$(let $var = $var.to_sim_value($ty_var.ty);)*
|
||||
ToSimValue::into_sim_value(($($var,)*), ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: Bundle) -> SimValue<Bundle> {
|
||||
#![allow(unused_mut)]
|
||||
#![allow(clippy::unused_unit)]
|
||||
let ($($var,)*) = self;
|
||||
let [$($ty_var,)*] = *ty.fields() else {
|
||||
panic!("bundle has wrong number of fields");
|
||||
};
|
||||
let mut bits: Option<BitVec> = None;
|
||||
$(let $var = $var.into_sim_value($ty_var.ty);
|
||||
assert_eq!($var.ty(), $ty_var.ty);
|
||||
if !$var.bits().is_empty() {
|
||||
if let Some(bits) = &mut bits {
|
||||
bits.extend_from_bitslice($var.bits());
|
||||
} else {
|
||||
let mut $var = $var.into_bits();
|
||||
$var.reserve(ty.type_properties().bit_width - $var.len());
|
||||
bits = Some($var);
|
||||
}
|
||||
}
|
||||
)*
|
||||
bits.unwrap_or_else(BitVec::new).into_sim_value(ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: Bundle) -> SimValue<Bundle> {
|
||||
Self::into_sim_value(*self, ty)
|
||||
}
|
||||
}
|
||||
impl<$($T: ToSimValue<$Ty>, $Ty: Type,)*> ToSimValue<($($Ty,)*)> for ($($T,)*) {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> {
|
||||
let ($($var,)*) = self;
|
||||
let ($($ty_var,)*) = ty;
|
||||
$(let $var = $var.to_sim_value($ty_var).into_canonical();)*
|
||||
SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical()))
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> {
|
||||
let ($($var,)*) = self;
|
||||
let ($($ty_var,)*) = ty;
|
||||
$(let $var = $var.into_sim_value($ty_var).into_canonical();)*
|
||||
SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical()))
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> {
|
||||
Self::into_sim_value(*self, ty)
|
||||
}
|
||||
}
|
||||
};
|
||||
([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => {
|
||||
impl_tuples!([$($lhs)*] []);
|
||||
|
@ -432,18 +507,18 @@ macro_rules! impl_tuples {
|
|||
|
||||
impl_tuples! {
|
||||
[] [
|
||||
{#[num = 0, field = field_0] v0: T0}
|
||||
{#[num = 1, field = field_1] v1: T1}
|
||||
{#[num = 2, field = field_2] v2: T2}
|
||||
{#[num = 3, field = field_3] v3: T3}
|
||||
{#[num = 4, field = field_4] v4: T4}
|
||||
{#[num = 5, field = field_5] v5: T5}
|
||||
{#[num = 6, field = field_6] v6: T6}
|
||||
{#[num = 7, field = field_7] v7: T7}
|
||||
{#[num = 8, field = field_8] v8: T8}
|
||||
{#[num = 9, field = field_9] v9: T9}
|
||||
{#[num = 10, field = field_10] v10: T10}
|
||||
{#[num = 11, field = field_11] v11: T11}
|
||||
{#[num = 0, field = field_0, ty = ty0: Ty0] v0: T0}
|
||||
{#[num = 1, field = field_1, ty = ty1: Ty1] v1: T1}
|
||||
{#[num = 2, field = field_2, ty = ty2: Ty2] v2: T2}
|
||||
{#[num = 3, field = field_3, ty = ty3: Ty3] v3: T3}
|
||||
{#[num = 4, field = field_4, ty = ty4: Ty4] v4: T4}
|
||||
{#[num = 5, field = field_5, ty = ty5: Ty5] v5: T5}
|
||||
{#[num = 6, field = field_6, ty = ty6: Ty6] v6: T6}
|
||||
{#[num = 7, field = field_7, ty = ty7: Ty7] v7: T7}
|
||||
{#[num = 8, field = field_8, ty = ty8: Ty8] v8: T8}
|
||||
{#[num = 9, field = field_9, ty = ty9: Ty9] v9: T9}
|
||||
{#[num = 10, field = field_10, ty = ty10: Ty10] v10: T10}
|
||||
{#[num = 11, field = field_11, ty = ty11: Ty11] v11: T11}
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -528,3 +603,27 @@ impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomData<T> {
|
|||
BundleLiteral::new(PhantomData, Interned::default()).to_expr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> ToSimValue<Self> for PhantomData<T> {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: Self) -> SimValue<Self> {
|
||||
ToSimValue::into_sim_value(BitVec::new(), ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> ToSimValue<Bundle> for PhantomData<T> {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: Bundle) -> SimValue<Bundle> {
|
||||
assert!(ty.fields().is_empty());
|
||||
ToSimValue::into_sim_value(BitVec::new(), ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> ToSimValue<CanonicalType> for PhantomData<T> {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
let ty = Bundle::from_canonical(ty);
|
||||
assert!(ty.fields().is_empty());
|
||||
ToSimValue::into_sim_value(BitVec::new(), ty).into_canonical()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::{
|
|||
},
|
||||
ExprEnum, Flow, ToLiteralBits,
|
||||
},
|
||||
int::BoolOrIntType,
|
||||
int::{BoolOrIntType, IntType, SIntValue, UIntValue},
|
||||
intern::{Intern, Interned, Memoize},
|
||||
memory::PortKind,
|
||||
module::{
|
||||
|
@ -42,7 +42,7 @@ use crate::{
|
|||
use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::{Signed, ToPrimitive, Zero};
|
||||
use num_traits::{Signed, Zero};
|
||||
use petgraph::{
|
||||
data::FromElements,
|
||||
visit::{
|
||||
|
@ -50,7 +50,9 @@ use petgraph::{
|
|||
IntoNodeIdentifiers, IntoNodeReferences, NodeRef, VisitMap, Visitable,
|
||||
},
|
||||
};
|
||||
use std::{borrow::Cow, collections::BTreeSet, fmt, marker::PhantomData, mem, ops::IndexMut};
|
||||
use std::{
|
||||
borrow::Cow, collections::BTreeSet, fmt, marker::PhantomData, mem, ops::IndexMut, sync::Arc,
|
||||
};
|
||||
|
||||
mod interpreter;
|
||||
pub mod time;
|
||||
|
@ -5806,6 +5808,624 @@ impl SimTraceKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct SimValue<T: Type> {
|
||||
ty: T,
|
||||
bits: BitVec,
|
||||
}
|
||||
|
||||
impl SimValue<CanonicalType> {
|
||||
#[track_caller]
|
||||
fn to_expr_impl(ty: CanonicalType, bits: &BitSlice) -> Expr<CanonicalType> {
|
||||
match ty {
|
||||
CanonicalType::UInt(_) => Expr::canonical(<UInt>::bits_to_expr(Cow::Borrowed(bits))),
|
||||
CanonicalType::SInt(_) => Expr::canonical(<SInt>::bits_to_expr(Cow::Borrowed(bits))),
|
||||
CanonicalType::Bool(_) => Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits))),
|
||||
CanonicalType::Array(ty) => {
|
||||
let element_bit_width = ty.element().bit_width();
|
||||
Expr::<Array>::canonical(
|
||||
crate::expr::ops::ArrayLiteral::new(
|
||||
ty.element(),
|
||||
(0..ty.len())
|
||||
.map(|array_index| {
|
||||
let start = element_bit_width * array_index;
|
||||
let end = start + element_bit_width;
|
||||
Self::to_expr_impl(ty.element(), &bits[start..end])
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
.to_expr(),
|
||||
)
|
||||
}
|
||||
CanonicalType::Enum(ty) => {
|
||||
let discriminant_bit_width = ty.discriminant_bit_width();
|
||||
let mut variant_index = [0; mem::size_of::<usize>()];
|
||||
variant_index.view_bits_mut::<Lsb0>()[0..discriminant_bit_width]
|
||||
.clone_from_bitslice(&bits[..discriminant_bit_width]);
|
||||
let variant_index = usize::from_le_bytes(variant_index);
|
||||
if let Some(variant) = ty.variants().get(variant_index) {
|
||||
let data_bit_width = variant.ty.map_or(0, CanonicalType::bit_width);
|
||||
Expr::canonical(
|
||||
crate::expr::ops::EnumLiteral::new_by_index(
|
||||
ty,
|
||||
variant_index,
|
||||
variant.ty.map(|ty| {
|
||||
Self::to_expr_impl(
|
||||
ty,
|
||||
&bits[discriminant_bit_width
|
||||
..discriminant_bit_width + data_bit_width],
|
||||
)
|
||||
}),
|
||||
)
|
||||
.to_expr(),
|
||||
)
|
||||
} else {
|
||||
Expr::canonical(<UInt>::bits_to_expr(Cow::Borrowed(bits)).cast_bits_to(ty))
|
||||
}
|
||||
}
|
||||
CanonicalType::Bundle(ty) => Expr::canonical(
|
||||
crate::expr::ops::BundleLiteral::new(
|
||||
ty,
|
||||
ty.fields()
|
||||
.iter()
|
||||
.zip(ty.field_offsets().iter())
|
||||
.map(|(field, &field_offset)| {
|
||||
Self::to_expr_impl(
|
||||
field.ty,
|
||||
&bits[field_offset..field_offset + field.ty.bit_width()],
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
.to_expr(),
|
||||
),
|
||||
CanonicalType::AsyncReset(ty) => {
|
||||
Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits)).cast_to(ty))
|
||||
}
|
||||
CanonicalType::SyncReset(ty) => {
|
||||
Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits)).cast_to(ty))
|
||||
}
|
||||
CanonicalType::Reset(_) => panic!(
|
||||
"can't convert SimValue<Reset> to Expr<Reset> -- \
|
||||
can't deduce whether reset value should be sync or async"
|
||||
),
|
||||
CanonicalType::Clock(ty) => {
|
||||
Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits)).cast_to(ty))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type> ToExpr for SimValue<T> {
|
||||
type Type = T;
|
||||
|
||||
#[track_caller]
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
Expr::from_canonical(SimValue::to_expr_impl(self.ty.canonical(), &self.bits))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type> ToSimValue<T> for SimValue<T> {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: T) -> SimValue<T> {
|
||||
assert_eq!(self.ty, ty);
|
||||
self.clone()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: T) -> SimValue<T> {
|
||||
assert_eq!(self.ty, ty);
|
||||
self
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: T) -> SimValue<T> {
|
||||
assert_eq!(self.ty, ty);
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type> ToSimValue<T> for BitVec {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: T) -> SimValue<T> {
|
||||
self.clone().into_sim_value(ty)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: T) -> SimValue<T> {
|
||||
assert_eq!(ty.canonical().bit_width(), self.len());
|
||||
SimValue { ty, bits: self }
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: T) -> SimValue<T> {
|
||||
Self::into_sim_value(*self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type> ToSimValue<T> for bitvec::boxed::BitBox {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: T) -> SimValue<T> {
|
||||
self.clone().into_sim_value(ty)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: T) -> SimValue<T> {
|
||||
assert_eq!(ty.canonical().bit_width(), self.len());
|
||||
SimValue {
|
||||
ty,
|
||||
bits: self.into_bitvec(),
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: T) -> SimValue<T> {
|
||||
Self::into_sim_value(*self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type> ToSimValue<T> for BitSlice {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: T) -> SimValue<T> {
|
||||
assert_eq!(ty.canonical().bit_width(), self.len());
|
||||
SimValue {
|
||||
ty,
|
||||
bits: self.to_bitvec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type> SimValue<T> {
|
||||
pub fn ty(&self) -> T {
|
||||
self.ty
|
||||
}
|
||||
pub fn bits(&self) -> &BitSlice {
|
||||
&self.bits
|
||||
}
|
||||
pub fn into_bits(self) -> BitVec {
|
||||
self.bits
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn from_canonical(v: SimValue<CanonicalType>) -> Self {
|
||||
Self {
|
||||
ty: T::from_canonical(v.ty),
|
||||
bits: v.bits,
|
||||
}
|
||||
}
|
||||
pub fn into_canonical(self) -> SimValue<CanonicalType> {
|
||||
SimValue {
|
||||
ty: self.ty.canonical(),
|
||||
bits: self.bits,
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self
|
||||
where
|
||||
T: IntType,
|
||||
{
|
||||
Self {
|
||||
ty: T::from_dyn_int(v.ty),
|
||||
bits: v.bits,
|
||||
}
|
||||
}
|
||||
pub fn into_dyn_int(self) -> SimValue<T::Dyn>
|
||||
where
|
||||
T: IntType,
|
||||
{
|
||||
SimValue {
|
||||
ty: self.ty.as_dyn_int(),
|
||||
bits: self.bits,
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn from_bundle(v: SimValue<Bundle>) -> Self
|
||||
where
|
||||
T: BundleType,
|
||||
{
|
||||
Self {
|
||||
ty: T::from_canonical(CanonicalType::Bundle(v.ty)),
|
||||
bits: v.bits,
|
||||
}
|
||||
}
|
||||
pub fn into_bundle(self) -> SimValue<Bundle>
|
||||
where
|
||||
T: BundleType,
|
||||
{
|
||||
SimValue {
|
||||
ty: Bundle::from_canonical(self.ty.canonical()),
|
||||
bits: self.bits,
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn from_enum(v: SimValue<Enum>) -> Self
|
||||
where
|
||||
T: EnumType,
|
||||
{
|
||||
Self {
|
||||
ty: T::from_canonical(CanonicalType::Enum(v.ty)),
|
||||
bits: v.bits,
|
||||
}
|
||||
}
|
||||
pub fn into_enum(self) -> SimValue<Enum>
|
||||
where
|
||||
T: EnumType,
|
||||
{
|
||||
SimValue {
|
||||
ty: Enum::from_canonical(self.ty.canonical()),
|
||||
bits: self.bits,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToSimValue<T: Type> {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: T) -> SimValue<T>;
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: T) -> SimValue<T>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.to_sim_value(ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: T) -> SimValue<T> {
|
||||
self.to_sim_value(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<This: ?Sized + ToSimValue<T>, T: Type> ToSimValue<T> for &'_ This {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: T) -> SimValue<T> {
|
||||
This::to_sim_value(self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<This: ?Sized + ToSimValue<T>, T: Type> ToSimValue<T> for &'_ mut This {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: T) -> SimValue<T> {
|
||||
This::to_sim_value(self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<This: ?Sized + ToSimValue<T>, T: Type> ToSimValue<T> for Box<This> {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: T) -> SimValue<T> {
|
||||
This::to_sim_value(self, ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: T) -> SimValue<T> {
|
||||
This::box_into_sim_value(self, ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: T) -> SimValue<T> {
|
||||
This::box_into_sim_value(*self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<This: ?Sized + ToSimValue<T> + Send + Sync + 'static, T: Type> ToSimValue<T>
|
||||
for Interned<This>
|
||||
{
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: T) -> SimValue<T> {
|
||||
This::to_sim_value(self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type, Len: Size> SimValue<ArrayType<T, Len>> {
|
||||
#[track_caller]
|
||||
pub fn from_array_elements<
|
||||
I: IntoIterator<Item: ToSimValue<T>, IntoIter: ExactSizeIterator>,
|
||||
>(
|
||||
elements: I,
|
||||
ty: ArrayType<T, Len>,
|
||||
) -> Self {
|
||||
let mut iter = elements.into_iter();
|
||||
assert_eq!(iter.len(), ty.len());
|
||||
let Some(first) = iter.next() else {
|
||||
return SimValue {
|
||||
ty,
|
||||
bits: BitVec::new(),
|
||||
};
|
||||
};
|
||||
let SimValue {
|
||||
ty: element_ty,
|
||||
mut bits,
|
||||
} = first.into_sim_value(ty.element());
|
||||
assert_eq!(element_ty, ty.element());
|
||||
bits.reserve(ty.type_properties().bit_width - bits.len());
|
||||
for element in iter {
|
||||
let SimValue {
|
||||
ty: element_ty,
|
||||
bits: element_bits,
|
||||
} = element.into_sim_value(ty.element());
|
||||
assert_eq!(element_ty, ty.element());
|
||||
bits.extend_from_bitslice(&element_bits);
|
||||
}
|
||||
SimValue { ty, bits }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Element: ToSimValue<T>, T: Type> ToSimValue<Array<T>> for [Element] {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: Array<T>) -> SimValue<Array<T>> {
|
||||
SimValue::from_array_elements(self, ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: Array<T>) -> SimValue<Array<T>> {
|
||||
SimValue::from_array_elements(self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Element: ToSimValue<CanonicalType>> ToSimValue<CanonicalType> for [Element] {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
SimValue::from_array_elements(self, <Array>::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
SimValue::from_array_elements(self, <Array>::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Element: ToSimValue<T>, T: Type, const N: usize> ToSimValue<Array<T, N>> for [Element; N]
|
||||
where
|
||||
ConstUsize<N>: KnownSize,
|
||||
{
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: Array<T, N>) -> SimValue<Array<T, N>> {
|
||||
SimValue::from_array_elements(self, ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: Array<T, N>) -> SimValue<Array<T, N>> {
|
||||
SimValue::from_array_elements(self, ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: Array<T, N>) -> SimValue<Array<T, N>> {
|
||||
SimValue::from_array_elements(<Vec<Element> as From<Box<[Element]>>>::from(self), ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Element: ToSimValue<T>, T: Type, const N: usize> ToSimValue<Array<T>> for [Element; N]
|
||||
where
|
||||
ConstUsize<N>: KnownSize,
|
||||
{
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: Array<T>) -> SimValue<Array<T>> {
|
||||
SimValue::from_array_elements(self, ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: Array<T>) -> SimValue<Array<T>> {
|
||||
SimValue::from_array_elements(self, ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: Array<T>) -> SimValue<Array<T>> {
|
||||
SimValue::from_array_elements(<Vec<Element> as From<Box<[Element]>>>::from(self), ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Element: ToSimValue<CanonicalType>, const N: usize> ToSimValue<CanonicalType>
|
||||
for [Element; N]
|
||||
{
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
SimValue::from_array_elements(self, <Array>::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
SimValue::from_array_elements(self, <Array>::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
SimValue::from_array_elements(
|
||||
<Vec<Element> as From<Box<[Element]>>>::from(self),
|
||||
<Array>::from_canonical(ty),
|
||||
)
|
||||
.into_canonical()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Element: ToSimValue<T>, T: Type> ToSimValue<Array<T>> for Vec<Element> {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: Array<T>) -> SimValue<Array<T>> {
|
||||
SimValue::from_array_elements(self, ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: Array<T>) -> SimValue<Array<T>> {
|
||||
SimValue::from_array_elements(self, ty)
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: Array<T>) -> SimValue<Array<T>> {
|
||||
SimValue::from_array_elements(*self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Element: ToSimValue<CanonicalType>> ToSimValue<CanonicalType> for Vec<Element> {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
SimValue::from_array_elements(self, <Array>::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
SimValue::from_array_elements(self, <Array>::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
SimValue::from_array_elements(*self, <Array>::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type> ToSimValue<T> for Expr<T> {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: T) -> SimValue<T> {
|
||||
assert_eq!(Expr::ty(*self), ty);
|
||||
SimValue {
|
||||
ty,
|
||||
bits: self
|
||||
.to_literal_bits()
|
||||
.expect("must be a literal expression")
|
||||
.to_bitvec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_to_sim_value_for_bool_like {
|
||||
($ty:ident) => {
|
||||
impl ToSimValue<$ty> for bool {
|
||||
fn to_sim_value(&self, ty: $ty) -> SimValue<$ty> {
|
||||
SimValue {
|
||||
ty,
|
||||
bits: BitVec::repeat(*self, 1),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_to_sim_value_for_bool_like!(Bool);
|
||||
impl_to_sim_value_for_bool_like!(AsyncReset);
|
||||
impl_to_sim_value_for_bool_like!(SyncReset);
|
||||
impl_to_sim_value_for_bool_like!(Reset);
|
||||
impl_to_sim_value_for_bool_like!(Clock);
|
||||
|
||||
impl ToSimValue<CanonicalType> for bool {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
match ty {
|
||||
CanonicalType::UInt(_)
|
||||
| CanonicalType::SInt(_)
|
||||
| CanonicalType::Array(_)
|
||||
| CanonicalType::Enum(_)
|
||||
| CanonicalType::Bundle(_) => {
|
||||
panic!("can't create SimValue from bool: expected value of type: {ty:?}");
|
||||
}
|
||||
CanonicalType::Bool(_)
|
||||
| CanonicalType::AsyncReset(_)
|
||||
| CanonicalType::SyncReset(_)
|
||||
| CanonicalType::Reset(_)
|
||||
| CanonicalType::Clock(_) => SimValue {
|
||||
ty,
|
||||
bits: BitVec::repeat(*self, 1),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_to_sim_value_for_primitive_int {
|
||||
($prim:ident) => {
|
||||
impl ToSimValue<<$prim as ToExpr>::Type> for $prim {
|
||||
#[track_caller]
|
||||
fn to_sim_value(
|
||||
&self,
|
||||
ty: <$prim as ToExpr>::Type,
|
||||
) -> SimValue<<$prim as ToExpr>::Type> {
|
||||
SimValue {
|
||||
ty,
|
||||
bits: <<$prim as ToExpr>::Type as BoolOrIntType>::le_bytes_to_bits_wrapping(
|
||||
&self.to_le_bytes(),
|
||||
ty.width(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> for $prim {
|
||||
#[track_caller]
|
||||
fn to_sim_value(
|
||||
&self,
|
||||
ty: <<$prim as ToExpr>::Type as IntType>::Dyn,
|
||||
) -> SimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> {
|
||||
SimValue {
|
||||
ty,
|
||||
bits: <<$prim as ToExpr>::Type as BoolOrIntType>::le_bytes_to_bits_wrapping(
|
||||
&self.to_le_bytes(),
|
||||
ty.width(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSimValue<CanonicalType> for $prim {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
let ty: <<$prim as ToExpr>::Type as IntType>::Dyn = Type::from_canonical(ty);
|
||||
self.to_sim_value(ty).into_canonical()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_to_sim_value_for_primitive_int!(u8);
|
||||
impl_to_sim_value_for_primitive_int!(u16);
|
||||
impl_to_sim_value_for_primitive_int!(u32);
|
||||
impl_to_sim_value_for_primitive_int!(u64);
|
||||
impl_to_sim_value_for_primitive_int!(u128);
|
||||
impl_to_sim_value_for_primitive_int!(usize);
|
||||
impl_to_sim_value_for_primitive_int!(i8);
|
||||
impl_to_sim_value_for_primitive_int!(i16);
|
||||
impl_to_sim_value_for_primitive_int!(i32);
|
||||
impl_to_sim_value_for_primitive_int!(i64);
|
||||
impl_to_sim_value_for_primitive_int!(i128);
|
||||
impl_to_sim_value_for_primitive_int!(isize);
|
||||
|
||||
macro_rules! impl_to_sim_value_for_int_value {
|
||||
($IntValue:ident, $Int:ident, $IntType:ident) => {
|
||||
impl<Width: KnownSize> ToSimValue<$IntType<Width>> for $IntValue<Width> {
|
||||
fn to_sim_value(&self, ty: $IntType<Width>) -> SimValue<$IntType<Width>> {
|
||||
self.bits().to_bitvec().into_sim_value(ty)
|
||||
}
|
||||
|
||||
fn into_sim_value(self, ty: $IntType<Width>) -> SimValue<$IntType<Width>> {
|
||||
Arc::try_unwrap(self.into_bits())
|
||||
.unwrap_or_else(|v: Arc<BitVec>| v.to_bitvec())
|
||||
.into_sim_value(ty)
|
||||
}
|
||||
|
||||
fn box_into_sim_value(
|
||||
self: Box<Self>,
|
||||
ty: $IntType<Width>,
|
||||
) -> SimValue<$IntType<Width>> {
|
||||
Self::into_sim_value(*self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> ToSimValue<$Int> for $IntValue<Width> {
|
||||
fn to_sim_value(&self, ty: $Int) -> SimValue<$Int> {
|
||||
self.bits().to_bitvec().into_sim_value(ty)
|
||||
}
|
||||
|
||||
fn into_sim_value(self, ty: $Int) -> SimValue<$Int> {
|
||||
Arc::try_unwrap(self.into_bits())
|
||||
.unwrap_or_else(|v: Arc<BitVec>| v.to_bitvec())
|
||||
.into_sim_value(ty)
|
||||
}
|
||||
|
||||
fn box_into_sim_value(self: Box<Self>, ty: $Int) -> SimValue<$Int> {
|
||||
Self::into_sim_value(*self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> ToSimValue<CanonicalType> for $IntValue<Width> {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
ToSimValue::<$Int>::to_sim_value(self, $Int::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn into_sim_value(self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
ToSimValue::<$Int>::into_sim_value(self, $Int::from_canonical(ty)).into_canonical()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn box_into_sim_value(self: Box<Self>, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
Self::into_sim_value(*self, ty)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType);
|
||||
impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType);
|
||||
|
||||
struct SimulationImpl {
|
||||
state: interpreter::State,
|
||||
io: Expr<Bundle>,
|
||||
|
@ -6263,8 +6883,11 @@ impl SimulationImpl {
|
|||
let value: BigInt = value.into();
|
||||
match compiled_value.range.len() {
|
||||
TypeLen::A_SMALL_SLOT => {
|
||||
self.state.small_slots[compiled_value.range.small_slots.start] =
|
||||
value.to_u64().expect("value out of range");
|
||||
let mut small_value = value.iter_u64_digits().next().unwrap_or(0);
|
||||
if value.is_negative() {
|
||||
small_value = small_value.wrapping_neg();
|
||||
}
|
||||
self.state.small_slots[compiled_value.range.small_slots.start] = small_value;
|
||||
}
|
||||
TypeLen::A_BIG_SLOT => {
|
||||
self.state.big_slots[compiled_value.range.big_slots.start] = value
|
||||
|
@ -6272,6 +6895,130 @@ impl SimulationImpl {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
fn read_write_sim_value_helper(
|
||||
&mut self,
|
||||
compiled_value: CompiledValue<CanonicalType>,
|
||||
bits: &mut BitSlice,
|
||||
read_write_big_scalar: impl Fn(bool, &mut BitSlice, &mut BigInt) + Copy,
|
||||
read_write_small_scalar: impl Fn(bool, &mut BitSlice, &mut SmallUInt) + Copy,
|
||||
) {
|
||||
match compiled_value.layout.body {
|
||||
CompiledTypeLayoutBody::Scalar => {
|
||||
let signed = match compiled_value.layout.ty {
|
||||
CanonicalType::UInt(_) => false,
|
||||
CanonicalType::SInt(_) => true,
|
||||
CanonicalType::Bool(_) => false,
|
||||
CanonicalType::Array(_) => unreachable!(),
|
||||
CanonicalType::Enum(_) => false,
|
||||
CanonicalType::Bundle(_) => unreachable!(),
|
||||
CanonicalType::AsyncReset(_) => false,
|
||||
CanonicalType::SyncReset(_) => false,
|
||||
CanonicalType::Reset(_) => false,
|
||||
CanonicalType::Clock(_) => false,
|
||||
};
|
||||
match compiled_value.range.len() {
|
||||
TypeLen::A_SMALL_SLOT => read_write_small_scalar(
|
||||
signed,
|
||||
bits,
|
||||
&mut self.state.small_slots[compiled_value.range.small_slots.start],
|
||||
),
|
||||
TypeLen::A_BIG_SLOT => read_write_big_scalar(
|
||||
signed,
|
||||
bits,
|
||||
&mut self.state.big_slots[compiled_value.range.big_slots.start],
|
||||
),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
CompiledTypeLayoutBody::Array { element } => {
|
||||
let ty = <Array>::from_canonical(compiled_value.layout.ty);
|
||||
let element_bit_width = ty.element().bit_width();
|
||||
for element_index in 0..ty.len() {
|
||||
self.read_write_sim_value_helper(
|
||||
CompiledValue {
|
||||
layout: *element,
|
||||
range: compiled_value
|
||||
.range
|
||||
.index_array(element.layout.len(), element_index),
|
||||
write: None,
|
||||
},
|
||||
&mut bits[element_index * element_bit_width..][..element_bit_width],
|
||||
read_write_big_scalar,
|
||||
read_write_small_scalar,
|
||||
);
|
||||
}
|
||||
}
|
||||
CompiledTypeLayoutBody::Bundle { fields } => {
|
||||
let ty = Bundle::from_canonical(compiled_value.layout.ty);
|
||||
for (
|
||||
(field, offset),
|
||||
CompiledBundleField {
|
||||
offset: layout_offset,
|
||||
ty: field_layout,
|
||||
},
|
||||
) in ty.fields().iter().zip(ty.field_offsets()).zip(fields)
|
||||
{
|
||||
self.read_write_sim_value_helper(
|
||||
CompiledValue {
|
||||
layout: field_layout,
|
||||
range: compiled_value.range.slice(TypeIndexRange::new(
|
||||
layout_offset,
|
||||
field_layout.layout.len(),
|
||||
)),
|
||||
write: None,
|
||||
},
|
||||
&mut bits[offset..][..field.ty.bit_width()],
|
||||
read_write_big_scalar,
|
||||
read_write_small_scalar,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
fn read(&mut self, io: Expr<CanonicalType>) -> SimValue<CanonicalType> {
|
||||
let compiled_value = self.read_helper(io);
|
||||
let mut bits = BitVec::repeat(false, compiled_value.layout.ty.bit_width());
|
||||
self.read_write_sim_value_helper(
|
||||
compiled_value,
|
||||
&mut bits,
|
||||
|_signed, bits, value| <UInt>::copy_bits_from_bigint_wrapping(value, bits),
|
||||
|_signed, bits, value| {
|
||||
let bytes = value.to_le_bytes();
|
||||
let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes);
|
||||
bits.clone_from_bitslice(&bitslice[..bits.len()]);
|
||||
},
|
||||
);
|
||||
SimValue {
|
||||
ty: Expr::ty(io),
|
||||
bits,
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
fn write(&mut self, io: Expr<CanonicalType>, value: SimValue<CanonicalType>) {
|
||||
let compiled_value = self.write_helper(io);
|
||||
assert_eq!(Expr::ty(io), value.ty());
|
||||
self.read_write_sim_value_helper(
|
||||
compiled_value,
|
||||
&mut value.into_bits(),
|
||||
|signed, bits, value| {
|
||||
if signed {
|
||||
*value = SInt::bits_to_bigint(bits);
|
||||
} else {
|
||||
*value = UInt::bits_to_bigint(bits);
|
||||
}
|
||||
},
|
||||
|signed, bits, value| {
|
||||
let mut small_value = [0; mem::size_of::<SmallUInt>()];
|
||||
if signed && bits.last().as_deref().copied() == Some(true) {
|
||||
small_value.fill(u8::MAX);
|
||||
}
|
||||
small_value.view_bits_mut::<Lsb0>()[0..bits.len()].clone_from_bitslice(bits);
|
||||
*value = SmallUInt::from_le_bytes(small_value);
|
||||
},
|
||||
);
|
||||
}
|
||||
fn close_all_trace_writers(&mut self) -> std::io::Result<()> {
|
||||
let trace_writers = mem::take(&mut self.trace_writers);
|
||||
let mut retval = Ok(());
|
||||
|
@ -6525,6 +7272,17 @@ impl<T: BundleType> Simulation<T> {
|
|||
pub fn read_reset<R: ResetType>(&mut self, io: Expr<R>) -> bool {
|
||||
self.sim_impl.read_bit(Expr::canonical(io))
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn read<IO: Type>(&mut self, io: Expr<IO>) -> SimValue<IO> {
|
||||
SimValue::from_canonical(self.sim_impl.read(Expr::canonical(io)))
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn write<IO: Type, V: ToSimValue<IO>>(&mut self, io: Expr<IO>, value: V) {
|
||||
self.sim_impl.write(
|
||||
Expr::canonical(io),
|
||||
value.into_sim_value(Expr::ty(io)).into_canonical(),
|
||||
);
|
||||
}
|
||||
#[doc(hidden)]
|
||||
/// This is explicitly unstable and may be changed/removed at any time
|
||||
pub fn set_breakpoints_unstable(&mut self, pcs: HashSet<usize>, trace: bool) {
|
||||
|
|
|
@ -5,7 +5,8 @@ use fayalite::{
|
|||
int::UIntValue,
|
||||
prelude::*,
|
||||
reset::ResetType,
|
||||
sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation},
|
||||
sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation, ToSimValue},
|
||||
ty::StaticType,
|
||||
util::RcWriter,
|
||||
};
|
||||
use std::num::NonZeroUsize;
|
||||
|
@ -309,6 +310,8 @@ pub fn enums() {
|
|||
let which_out: UInt<2> = m.output();
|
||||
#[hdl]
|
||||
let data_out: UInt<4> = m.output();
|
||||
#[hdl]
|
||||
let b_out: HdlOption<(UInt<1>, Bool)> = m.output();
|
||||
|
||||
#[hdl]
|
||||
struct MyStruct<T> {
|
||||
|
@ -348,6 +351,8 @@ pub fn enums() {
|
|||
}
|
||||
}
|
||||
|
||||
connect(b_out, HdlNone());
|
||||
|
||||
#[hdl]
|
||||
match the_reg {
|
||||
MyEnum::A => {
|
||||
|
@ -357,6 +362,7 @@ pub fn enums() {
|
|||
MyEnum::B(v) => {
|
||||
connect(which_out, 1_hdl_u2);
|
||||
connect_any(data_out, v.0 | (v.1.cast_to_static::<UInt<1>>() << 1));
|
||||
connect(b_out, HdlSome(v));
|
||||
}
|
||||
MyEnum::C(v) => {
|
||||
connect(which_out, 2_hdl_u2);
|
||||
|
@ -382,13 +388,33 @@ fn test_enums() {
|
|||
sim.advance_time(SimDuration::from_nanos(100));
|
||||
sim.write_reset(sim.io().cd.rst, false);
|
||||
sim.advance_time(SimDuration::from_nanos(900));
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
type BOutTy = HdlOption<(UInt<1>, Bool)>;
|
||||
#[derive(Debug)]
|
||||
struct IO {
|
||||
en: bool,
|
||||
which_in: u8,
|
||||
data_in: u8,
|
||||
which_out: u8,
|
||||
data_out: u8,
|
||||
b_out: Expr<BOutTy>,
|
||||
}
|
||||
impl PartialEq for IO {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Self {
|
||||
en,
|
||||
which_in,
|
||||
data_in,
|
||||
which_out,
|
||||
data_out,
|
||||
b_out,
|
||||
} = *self;
|
||||
en == other.en
|
||||
&& which_in == other.which_in
|
||||
&& data_in == other.data_in
|
||||
&& which_out == other.which_out
|
||||
&& data_out == other.data_out
|
||||
&& b_out.to_sim_value(BOutTy::TYPE) == other.b_out.to_sim_value(BOutTy::TYPE)
|
||||
}
|
||||
}
|
||||
let io_cycles = [
|
||||
IO {
|
||||
|
@ -397,6 +423,7 @@ fn test_enums() {
|
|||
data_in: 0,
|
||||
which_out: 0,
|
||||
data_out: 0,
|
||||
b_out: HdlNone(),
|
||||
},
|
||||
IO {
|
||||
en: true,
|
||||
|
@ -404,6 +431,7 @@ fn test_enums() {
|
|||
data_in: 0,
|
||||
which_out: 0,
|
||||
data_out: 0,
|
||||
b_out: HdlNone(),
|
||||
},
|
||||
IO {
|
||||
en: false,
|
||||
|
@ -411,6 +439,7 @@ fn test_enums() {
|
|||
data_in: 0,
|
||||
which_out: 1,
|
||||
data_out: 0,
|
||||
b_out: HdlSome((0_hdl_u1, false)),
|
||||
},
|
||||
IO {
|
||||
en: true,
|
||||
|
@ -418,6 +447,7 @@ fn test_enums() {
|
|||
data_in: 0xF,
|
||||
which_out: 1,
|
||||
data_out: 0,
|
||||
b_out: HdlSome((0_hdl_u1, false)),
|
||||
},
|
||||
IO {
|
||||
en: true,
|
||||
|
@ -425,6 +455,7 @@ fn test_enums() {
|
|||
data_in: 0xF,
|
||||
which_out: 1,
|
||||
data_out: 0x3,
|
||||
b_out: HdlSome((1_hdl_u1, true)),
|
||||
},
|
||||
IO {
|
||||
en: true,
|
||||
|
@ -432,6 +463,7 @@ fn test_enums() {
|
|||
data_in: 0xF,
|
||||
which_out: 1,
|
||||
data_out: 0x3,
|
||||
b_out: HdlSome((1_hdl_u1, true)),
|
||||
},
|
||||
IO {
|
||||
en: true,
|
||||
|
@ -439,6 +471,7 @@ fn test_enums() {
|
|||
data_in: 0xF,
|
||||
which_out: 2,
|
||||
data_out: 0xF,
|
||||
b_out: HdlNone(),
|
||||
},
|
||||
];
|
||||
for (
|
||||
|
@ -449,6 +482,7 @@ fn test_enums() {
|
|||
data_in,
|
||||
which_out: _,
|
||||
data_out: _,
|
||||
b_out: _,
|
||||
},
|
||||
) in io_cycles.into_iter().enumerate()
|
||||
{
|
||||
|
@ -469,6 +503,7 @@ fn test_enums() {
|
|||
.to_bigint()
|
||||
.try_into()
|
||||
.expect("known to be in range"),
|
||||
b_out: sim.read(sim.io().b_out).to_expr(),
|
||||
};
|
||||
assert_eq!(
|
||||
expected,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,18 +9,25 @@ $var wire 2 $ which_in $end
|
|||
$var wire 4 % data_in $end
|
||||
$var wire 2 & which_out $end
|
||||
$var wire 4 ' data_out $end
|
||||
$scope struct the_reg $end
|
||||
$scope struct b_out $end
|
||||
$var string 1 ( \$tag $end
|
||||
$scope struct HdlSome $end
|
||||
$var wire 1 ) \0 $end
|
||||
$var wire 1 * \1 $end
|
||||
$upscope $end
|
||||
$upscope $end
|
||||
$scope struct the_reg $end
|
||||
$var string 1 + \$tag $end
|
||||
$scope struct B $end
|
||||
$var reg 1 ) \0 $end
|
||||
$var reg 1 * \1 $end
|
||||
$var reg 1 , \0 $end
|
||||
$var reg 1 - \1 $end
|
||||
$upscope $end
|
||||
$scope struct C $end
|
||||
$scope struct a $end
|
||||
$var reg 1 + \[0] $end
|
||||
$var reg 1 , \[1] $end
|
||||
$var reg 1 . \[0] $end
|
||||
$var reg 1 / \[1] $end
|
||||
$upscope $end
|
||||
$var reg 2 - b $end
|
||||
$var reg 2 0 b $end
|
||||
$upscope $end
|
||||
$upscope $end
|
||||
$upscope $end
|
||||
|
@ -33,12 +40,15 @@ b0 $
|
|||
b0 %
|
||||
b0 &
|
||||
b0 '
|
||||
sA\x20(0) (
|
||||
sHdlNone\x20(0) (
|
||||
0)
|
||||
0*
|
||||
0+
|
||||
sA\x20(0) +
|
||||
0,
|
||||
b0 -
|
||||
0-
|
||||
0.
|
||||
0/
|
||||
b0 0
|
||||
$end
|
||||
#1000000
|
||||
1!
|
||||
|
@ -55,7 +65,8 @@ b1 $
|
|||
#5000000
|
||||
1!
|
||||
b1 &
|
||||
sB\x20(1) (
|
||||
sHdlSome\x20(1) (
|
||||
sB\x20(1) +
|
||||
#6000000
|
||||
0#
|
||||
b0 $
|
||||
|
@ -72,8 +83,10 @@ b1111 %
|
|||
b11 '
|
||||
1)
|
||||
1*
|
||||
1+
|
||||
1,
|
||||
1-
|
||||
1.
|
||||
1/
|
||||
#10000000
|
||||
0!
|
||||
#11000000
|
||||
|
@ -85,8 +98,11 @@ b10 $
|
|||
1!
|
||||
b10 &
|
||||
b1111 '
|
||||
sC\x20(2) (
|
||||
b11 -
|
||||
sHdlNone\x20(0) (
|
||||
0)
|
||||
0*
|
||||
sC\x20(2) +
|
||||
b11 0
|
||||
#14000000
|
||||
0!
|
||||
#15000000
|
||||
|
|
Loading…
Reference in a new issue