diff --git a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs index ca06c0b..605f662 100644 --- a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs +++ b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs @@ -1096,11 +1096,9 @@ impl Visitor<'_> { let (#(#bindings,)*) = { type __MatchTy = ::SimValue; let __match_value = #expr; - let __match_value = { - use ::fayalite::sim::value::match_sim_value::*; - // use method syntax to deduce the correct trait to call - ::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value).__fayalite_match_sim_value() - }; + // use method syntax to deduce what type to convert to + let __match_value = ::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value) + .__fayalite_match_sim_value(); #let_token #pat #eq_token __match_value #semi_token (#(#bindings_idents,)*) }; @@ -1172,11 +1170,9 @@ impl Visitor<'_> { { type __MatchTy = ::SimValue; let __match_value = #expr; - let __match_value = { - use ::fayalite::sim::value::match_sim_value::*; - // use method syntax to deduce the correct trait to call - ::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value).__fayalite_match_sim_value() - }; + // use method syntax to deduce what type to convert to + let __match_value = ::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value) + .__fayalite_match_sim_value(); #match_token __match_value { #(#arms)* } diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs index 8d70d21..065e5de 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs @@ -95,7 +95,23 @@ //! } //! //! #[hdl] -//! fn destructure_to_sim_value<'a, T: Type>(v: impl ToSimValue>) { +//! fn destructure_inner(v: as Type>::SimValue) { +//! #[hdl(sim)] +//! let MyStruct:: { +//! a, +//! mut b, +//! c, +//! } = v; +//! +//! // that gives these types: +//! let _: SimValue> = a; +//! let _: SimValue = b; +//! let _: SimValue = c; +//! *b = false; // can modify b since mut was used +//! } +//! +//! #[hdl] +//! fn destructure_inner_ref<'a, T: Type>(v: &'a as Type>::SimValue) { //! #[hdl(sim)] //! let MyStruct:: { //! a, @@ -104,8 +120,25 @@ //! } = v; //! //! // that gives these types: -//! let _: SimValue> = a; -//! let _: SimValue = b; -//! let _: SimValue = c; +//! let _: &'a SimValue> = a; +//! let _: &'a SimValue = b; +//! let _: &'a SimValue = c; +//! } +//! +//! #[hdl] +//! fn destructure_inner_mut<'a, T: Type>(v: &'a mut as Type>::SimValue) { +//! #[hdl(sim)] +//! let MyStruct:: { +//! a, +//! b, +//! c, +//! } = v; +//! +//! **b = true; // you can modify v by modifying b which borrows from it +//! +//! // that gives these types: +//! let _: &'a mut SimValue> = a; +//! let _: &'a mut SimValue = b; +//! let _: &'a mut SimValue = c; //! } //! ``` diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs index accd3d7..9e2d41d 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs @@ -72,15 +72,47 @@ //! } //! //! #[hdl] -//! fn match_to_sim_value<'a, T: Type>(v: impl ToSimValue>) { +//! fn match_inner_move(v: as Type>::SimValue) -> String { //! #[hdl(sim)] //! match v { -//! MyEnum::::A => println!("got A"), -//! MyEnum::::B(b) => { +//! MyEnum::::A => String::from("got A"), +//! MyEnum::::B(mut b) => { //! let _: SimValue = b; // b has this type -//! println!("got B({b})"); +//! let text = format!("got B({b})"); +//! *b = true; // can modify b since mut was used +//! text //! } -//! _ => println!("something else"), +//! _ => String::from("something else"), +//! } +//! } +//! +//! #[hdl] +//! fn match_inner_ref<'a, T: Type>(v: &'a as Type>::SimValue) -> u32 { +//! #[hdl(sim)] +//! match v { +//! MyEnum::::A => 1, +//! MyEnum::::B(b) => { +//! let _: &'a SimValue = b; // b has this type +//! println!("got B({b})"); +//! 5 +//! } +//! _ => 42, +//! } +//! } +//! +//! #[hdl] +//! fn match_inner_mut<'a, T: Type>(v: &'a mut as Type>::SimValue) -> Option<&'a mut SimValue> { +//! #[hdl(sim)] +//! match v { +//! MyEnum::::A => None, +//! MyEnum::::B(b) => { +//! println!("got B({b})"); +//! **b = true; // you can modify v by modifying b which borrows from it +//! let _: &'a mut SimValue = b; // b has this type +//! None +//! } +//! MyEnum::::C(v) => Some(v), // you can return matched values +//! _ => None, // HDL enums can have invalid discriminants, so we need this extra match arm //! } //! } //! ``` diff --git a/crates/fayalite/src/enum_.rs b/crates/fayalite/src/enum_.rs index d545f93..f6af578 100644 --- a/crates/fayalite/src/enum_.rs +++ b/crates/fayalite/src/enum_.rs @@ -2,7 +2,7 @@ // See Notices.txt for copyright information use crate::{ - expr::{Expr, HdlPartialEq, HdlPartialEqImpl, ToExpr, ValueType, ops::VariantAccess}, + expr::{Expr, ToExpr, ValueType, ops::VariantAccess}, hdl, int::{Bool, UIntValue}, intern::{Intern, Interned}, @@ -10,7 +10,7 @@ use crate::{ EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, Scope, connect, enum_match_variants_helper, incomplete_wire, wire, }, - sim::value::SimValue, + sim::value::{SimValue, ToSimValue, ToSimValueWithType}, source_location::SourceLocation, ty::{ CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, OpaqueSimValueSize, @@ -21,7 +21,7 @@ use crate::{ }; use bitvec::{order::Lsb0, slice::BitSlice, view::BitView}; use serde::{Deserialize, Serialize}; -use std::{borrow::Cow, convert::Infallible, fmt, iter::FusedIterator, sync::Arc}; +use std::{convert::Infallible, fmt, iter::FusedIterator, sync::Arc}; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] pub struct EnumVariant { @@ -732,95 +732,12 @@ pub fn enum_type_to_sim_builder(v: T) -> T::SimBuilder { v.into() } -#[hdl] +#[hdl(cmp_eq)] pub enum HdlOption { HdlNone, HdlSome(T), } -impl, Rhs: Type> HdlPartialEqImpl> - for HdlOption -{ - fn cmp_value_eq( - lhs: Self, - lhs_value: Cow<'_, Self::SimValue>, - rhs: HdlOption, - rhs_value: Cow<'_, as Type>::SimValue>, - ) -> bool { - type SimValueMatch = ::SimValue; - match (&*lhs_value, &*rhs_value) { - (SimValueMatch::::HdlNone(_), SimValueMatch::>::HdlNone(_)) => { - true - } - (SimValueMatch::::HdlSome(..), SimValueMatch::>::HdlNone(_)) - | (SimValueMatch::::HdlNone(_), SimValueMatch::>::HdlSome(..)) => { - false - } - ( - SimValueMatch::::HdlSome(l, _), - SimValueMatch::>::HdlSome(r, _), - ) => HdlPartialEqImpl::cmp_value_eq( - lhs.HdlSome, - Cow::Borrowed(&**l), - rhs.HdlSome, - Cow::Borrowed(&**r), - ), - } - } - - #[hdl] - fn cmp_expr_eq(lhs: Expr, rhs: Expr>) -> Expr { - #[hdl] - let cmp_eq = wire(); - #[hdl] - match lhs { - HdlSome(lhs) => - { - #[hdl] - match rhs { - HdlSome(rhs) => connect(cmp_eq, lhs.cmp_eq(rhs)), - HdlNone => connect(cmp_eq, false), - } - } - HdlNone => - { - #[hdl] - match rhs { - HdlSome(_) => connect(cmp_eq, false), - HdlNone => connect(cmp_eq, true), - } - } - } - cmp_eq - } - - #[hdl] - fn cmp_expr_ne(lhs: Expr, rhs: Expr>) -> Expr { - #[hdl] - let cmp_ne = wire(); - #[hdl] - match lhs { - HdlSome(lhs) => - { - #[hdl] - match rhs { - HdlSome(rhs) => connect(cmp_ne, lhs.cmp_ne(rhs)), - HdlNone => connect(cmp_ne, true), - } - } - HdlNone => - { - #[hdl] - match rhs { - HdlSome(_) => connect(cmp_ne, true), - HdlNone => connect(cmp_ne, false), - } - } - } - cmp_ne - } -} - #[allow(non_snake_case)] pub fn HdlNone() -> Expr> { HdlOption[T::TYPE].HdlNone() @@ -832,6 +749,123 @@ pub fn HdlSome(value: impl ToExpr) -> Expr> { HdlOption[value.ty()].HdlSome(value) } +impl From>> for Option> { + #[hdl] + fn from(value: SimValue>) -> Self { + #[hdl(sim)] + match value { + HdlSome(v) => Some(v), + HdlNone => None, + } + } +} + +impl<'a, T: Type> From<&'a SimValue>> for Option<&'a SimValue> { + #[hdl] + fn from(value: &'a SimValue>) -> Self { + #[hdl(sim)] + match value { + HdlSome(v) => Some(v), + HdlNone => None, + } + } +} + +impl<'a, T: Type> From<&'a mut SimValue>> for Option<&'a mut SimValue> { + #[hdl] + fn from(value: &'a mut SimValue>) -> Self { + #[hdl(sim)] + match value { + HdlSome(v) => Some(v), + HdlNone => None, + } + } +} + +impl>> ValueType for Option { + type Type = HdlOption; + type ValueCategory = T::ValueCategory; + + fn ty(&self) -> Self::Type { + StaticType::TYPE + } +} + +impl> ToSimValueWithType> for Option { + #[hdl] + fn to_sim_value_with_type(&self, ty: HdlOption) -> SimValue> { + match self { + Some(v) => + { + #[hdl(sim)] + ty.HdlSome(v) + } + None => + { + #[hdl(sim)] + ty.HdlNone() + } + } + } + #[hdl] + fn into_sim_value_with_type(self, ty: HdlOption) -> SimValue> { + match self { + Some(v) => + { + #[hdl(sim)] + ty.HdlSome(v) + } + None => + { + #[hdl(sim)] + ty.HdlNone() + } + } + } +} + +impl>> ToSimValue for Option { + #[hdl] + fn to_sim_value(&self) -> SimValue { + match self { + Some(v) => + { + #[hdl(sim)] + HdlSome(v) + } + None => + { + #[hdl(sim)] + HdlNone() + } + } + } + #[hdl] + fn into_sim_value(self) -> SimValue { + match self { + Some(v) => + { + #[hdl(sim)] + HdlSome(v) + } + None => + { + #[hdl(sim)] + HdlNone() + } + } + } +} + +impl>> ToExpr for Option { + fn to_expr(&self) -> Expr { + match self { + Some(v) => HdlSome(v), + None => HdlNone(), + } + } +} + impl HdlOption { #[track_caller] pub fn try_map( diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index 00a0cee..905c22b 100644 --- a/crates/fayalite/src/expr.rs +++ b/crates/fayalite/src/expr.rs @@ -17,7 +17,7 @@ use crate::{ reg::Reg, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, sim::value::{SimValue, ToSimValue, ToSimValueWithType}, - ty::{CanonicalType, OpaqueSimValue, StaticType, Type, TypeWithDeref}, + ty::{CanonicalType, OpaqueSimValue, StaticType, TraceAsString, Type, TypeWithDeref}, util::{ConstBool, ConstUsize}, wire::Wire, }; @@ -218,6 +218,8 @@ expr_enum! { SliceSInt(ops::SliceSInt), CastToBits(ops::CastToBits), CastBitsTo(ops::CastBitsTo), + ToTraceAsString(ops::ToTraceAsString), + TraceAsStringAsInner(ops::TraceAsStringAsInner), ModuleIO(ModuleIO), Instance(Instance), Wire(Wire), @@ -225,6 +227,7 @@ expr_enum! { RegSync(Reg), RegAsync(Reg), MemPort(MemPort), + FormalInput(ops::FormalInputExpr), } } @@ -389,6 +392,35 @@ impl Expr { __flow: this.__flow, } } + #[track_caller] + pub fn as_trace_as_string(this: Self, ty: TraceAsString) -> Expr> { + assert_eq!(this.ty(), ty.inner_ty()); + ops::ToTraceAsString::new(Expr::canonical(this), ty).to_expr() + } +} + +impl Expr { + pub fn unwrap_transparent_types(mut this: Self) -> Expr { + loop { + match this.ty() { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::Array(_) + | CanonicalType::Enum(_) + | CanonicalType::Bundle(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => return this, + CanonicalType::TraceAsString(_) => { + this = *Expr::::from_canonical(this); + } + } + } + } } impl ToLiteralBits for Expr { @@ -1692,3 +1724,188 @@ impl<'a, T: Type> ToSimValueInner<'a> for &'a SimValue { Cow::Borrowed(&**this) } } + +pub trait ToTraceAsString: ValueType { + type Output: ValueType, ValueCategory = Self::ValueCategory>; + fn to_trace_as_string_with_ty(&self, ty: TraceAsString) -> Self::Output; + fn into_trace_as_string_with_ty(self, ty: TraceAsString) -> Self::Output + where + Self: Sized; + fn to_trace_as_string(&self) -> Self::Output; + fn into_trace_as_string(self) -> Self::Output + where + Self: Sized; +} + +impl< + T: ?Sized + + ValueType + + ToTraceAsStringImpl<::Type, ::ValueCategory>, +> ToTraceAsString for T +{ + type Output = T::ImplOutput; + fn to_trace_as_string_with_ty(&self, ty: TraceAsString) -> Self::Output { + Self::to_trace_as_string_with_ty_impl(self, ty) + } + fn into_trace_as_string_with_ty(self, ty: TraceAsString) -> Self::Output + where + Self: Sized, + { + Self::into_trace_as_string_with_ty_impl(self, ty) + } + fn to_trace_as_string(&self) -> Self::Output { + Self::to_trace_as_string_impl(self) + } + fn into_trace_as_string(self) -> Self::Output + where + Self: Sized, + { + Self::into_trace_as_string_impl(self) + } +} + +pub trait ToTraceAsStringImpl { + type ImplOutput: ValueType, ValueCategory = C>; + fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput; + fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput + where + Self: Sized; + fn to_trace_as_string_with_ty_impl(this: &Self, ty: TraceAsString) -> Self::ImplOutput; + fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString) -> Self::ImplOutput + where + Self: Sized; +} + +impl + ToTraceAsStringImpl for T +{ + type ImplOutput = crate::ty::TraceAsStringSimValue; + + fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput { + crate::ty::TraceAsStringSimValue::new(this) + } + + fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput + where + Self: Sized, + { + crate::ty::TraceAsStringSimValue::new(this) + } + + fn to_trace_as_string_with_ty_impl( + this: &Self, + ty: TraceAsString, + ) -> Self::ImplOutput { + crate::ty::TraceAsStringSimValue::new_with_ty(this, ty) + } + + fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString) -> Self::ImplOutput + where + Self: Sized, + { + crate::ty::TraceAsStringSimValue::new_with_ty(this, ty) + } +} + +impl + ToTraceAsStringImpl for T +{ + type ImplOutput = SimValue>; + + fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput { + crate::ty::TraceAsStringSimValue::new(this).into_sim_value() + } + + fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput + where + Self: Sized, + { + crate::ty::TraceAsStringSimValue::new(this).into_sim_value() + } + + fn to_trace_as_string_with_ty_impl( + this: &Self, + ty: TraceAsString, + ) -> Self::ImplOutput { + crate::ty::TraceAsStringSimValue::new_with_ty(this, ty).into_sim_value() + } + + fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString) -> Self::ImplOutput + where + Self: Sized, + { + crate::ty::TraceAsStringSimValue::new_with_ty(this, ty).into_sim_value() + } +} + +impl ToTraceAsStringImpl for T { + type ImplOutput = Expr>; + + fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput { + let this = this.to_expr(); + ops::ToTraceAsString::new(Expr::canonical(this), TraceAsString::new(this.ty())).to_expr() + } + + fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput + where + Self: Sized, + { + let this = this.to_expr(); + ops::ToTraceAsString::new(Expr::canonical(this), TraceAsString::new(this.ty())).to_expr() + } + + fn to_trace_as_string_with_ty_impl( + this: &Self, + ty: TraceAsString, + ) -> Self::ImplOutput { + let this = this.to_expr(); + ops::ToTraceAsString::new( + Expr::canonical(this), + ty.with_new_inner_ty(this.ty().intern_sized()), + ) + .to_expr() + } + + fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString) -> Self::ImplOutput + where + Self: Sized, + { + let this = this.to_expr(); + ops::ToTraceAsString::new( + Expr::canonical(this), + ty.with_new_inner_ty(this.ty().intern_sized()), + ) + .to_expr() + } +} + +impl ToTraceAsStringImpl + for T +{ + type ImplOutput = Valueless>; + + fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput { + Valueless::new(TraceAsString::new(this.ty())) + } + + fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput + where + Self: Sized, + { + Valueless::new(TraceAsString::new(this.ty())) + } + + fn to_trace_as_string_with_ty_impl( + this: &Self, + ty: TraceAsString, + ) -> Self::ImplOutput { + Valueless::new(ty.with_new_inner_ty(this.ty().intern_sized())) + } + + fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString) -> Self::ImplOutput + where + Self: Sized, + { + Valueless::new(ty.with_new_inner_ty(this.ty().intern_sized())) + } +} diff --git a/crates/fayalite/src/expr/ops.rs b/crates/fayalite/src/expr/ops.rs index f4cfebd..5d0b346 100644 --- a/crates/fayalite/src/expr/ops.rs +++ b/crates/fayalite/src/expr/ops.rs @@ -11,11 +11,13 @@ use crate::{ HdlPartialEqImpl, HdlPartialOrd, HdlPartialOrdImpl, NotALiteralExpr, ReduceBitsImpl, ToExpr, ToLiteralBits, ToSimValueInner, ToValueless, ValueType, Valueless, target::{ - GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, - TargetPathDynArrayElement, TargetPathElement, + GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, + TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString, + TargetPathTraceAsStringInner, }, value_category::ValueCategoryExpr, }, + formal::FormalInput, int::{ Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue, @@ -27,7 +29,7 @@ use crate::{ ToSyncReset, }, sim::value::{SimValue, ToSimValue}, - ty::{CanonicalType, StaticType, Type}, + ty::{CanonicalType, StaticType, TraceAsString, Type}, util::ConstUsize, }; use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; @@ -44,6 +46,9 @@ use std::{ }, }; +#[cfg(test)] +mod test_ops_impls; + macro_rules! make_impls { ( $([$($args:tt)*])? @@ -583,9 +588,6 @@ macro_rules! make_impls { #[cfg(test)] pub(crate) use make_impls; -#[cfg(test)] -mod test_ops_impls; - macro_rules! impl_simple_binary_op_trait { ( [$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*), @@ -4694,3 +4696,252 @@ impl, A> FromIterator for Expr { This::expr_from_iter(iter) } } + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct ToTraceAsString { + inner: Expr, + ty: TraceAsString, + literal_bits: Result, NotALiteralExpr>, + target: Option>, +} + +impl fmt::Debug for ToTraceAsString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + inner, + ty: _, + literal_bits: _, + target: _, + } = self; + f.debug_struct("ToTraceAsString") + .field("inner", inner) + .finish_non_exhaustive() + } +} + +impl ToTraceAsString { + pub fn new(inner: Expr, ty: TraceAsString) -> Self { + assert_eq!(inner.ty(), ty.inner_ty().canonical()); + let literal_bits = inner.to_literal_bits(); + let target = inner.target().map(|base| { + Intern::intern_sized( + base.join(TargetPathElement::intern_sized( + TargetPathToTraceAsString { + ty: ty.canonical_trace_as_string(), + } + .into(), + )) + .canonicalized(), + ) + }); + Self { + inner, + ty, + literal_bits, + target, + } + } + pub fn inner(self) -> Expr { + self.inner + } +} + +impl GetTarget for ToTraceAsString { + fn target(&self) -> Option> { + self.target + } +} + +impl ToLiteralBits for ToTraceAsString { + fn to_literal_bits(&self) -> Result, NotALiteralExpr> { + self.literal_bits + } +} + +impl ValueType for ToTraceAsString { + type Type = TraceAsString; + type ValueCategory = ValueCategoryExpr; + + fn ty(&self) -> Self::Type { + self.ty + } +} + +impl ToExpr for ToTraceAsString { + fn to_expr(&self) -> Expr { + Expr { + __enum: ExprEnum::ToTraceAsString(ToTraceAsString { + inner: self.inner, + ty: self.ty.canonical_trace_as_string(), + literal_bits: self.literal_bits, + target: self.target, + }) + .intern(), + __ty: self.ty, + __flow: Expr::flow(self.inner), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct TraceAsStringAsInner { + arg: Expr>, + ty: T, + literal_bits: Result, NotALiteralExpr>, + target: Option>, +} + +impl fmt::Debug for TraceAsStringAsInner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + arg, + ty: _, + literal_bits: _, + target: _, + } = self; + f.debug_struct("TraceAsStringAsInner") + .field("arg", arg) + .finish_non_exhaustive() + } +} + +impl TraceAsStringAsInner { + pub fn from_arg_and_ty(arg: Expr>, ty: T) -> Self { + assert_eq!(arg.ty().inner_ty(), ty.canonical()); + let literal_bits = arg.to_literal_bits(); + let target = arg.target().map(|base| { + Intern::intern_sized( + base.join(TargetPathElement::intern_sized( + TargetPathTraceAsStringInner {}.into(), + )) + .canonicalized(), + ) + }); + Self { + arg, + ty, + literal_bits, + target, + } + } + pub fn new(arg: Expr>) -> Self { + Self::from_arg_and_ty( + Expr { + __enum: arg.__enum, + __ty: arg.__ty.canonical_trace_as_string(), + __flow: arg.__flow, + }, + arg.ty().inner_ty(), + ) + } + pub fn arg(self) -> Expr> { + self.arg + } + pub fn arg_typed(self) -> Expr> { + Expr { + __enum: self.arg.__enum, + __ty: TraceAsString::from_canonical_trace_as_string(self.arg.__ty), + __flow: self.arg.__flow, + } + } +} + +impl GetTarget for TraceAsStringAsInner { + fn target(&self) -> Option> { + self.target + } +} + +impl ToLiteralBits for TraceAsStringAsInner { + fn to_literal_bits(&self) -> Result, NotALiteralExpr> { + self.literal_bits + } +} + +impl ValueType for TraceAsStringAsInner { + type Type = T; + type ValueCategory = ValueCategoryExpr; + + fn ty(&self) -> Self::Type { + self.ty + } +} + +impl ToExpr for TraceAsStringAsInner { + fn to_expr(&self) -> Expr { + Expr { + __enum: ExprEnum::TraceAsStringAsInner(TraceAsStringAsInner { + arg: self.arg, + ty: self.ty.canonical(), + literal_bits: self.literal_bits, + target: self.target, + }) + .intern(), + __ty: self.ty, + __flow: Expr::flow(self.arg), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct FormalInputExpr { + formal_input: FormalInput, + ty: T, + target: Interned, +} + +impl fmt::Debug for FormalInputExpr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.formal_input.fmt(f) + } +} + +impl FormalInputExpr { + pub fn new(formal_input: FormalInput) -> Self { + Self { + formal_input, + ty: T::from_canonical(formal_input.ty()), + target: Target::Base(TargetBase::FormalInput(formal_input).intern_sized()) + .intern_sized(), + } + } + pub fn formal_input(self) -> FormalInput { + self.formal_input + } +} + +impl GetTarget for FormalInputExpr { + fn target(&self) -> Option> { + Some(self.target) + } +} + +impl ToLiteralBits for FormalInputExpr { + fn to_literal_bits(&self) -> Result, NotALiteralExpr> { + Err(NotALiteralExpr) + } +} + +impl ValueType for FormalInputExpr { + type Type = T; + type ValueCategory = ValueCategoryExpr; + + fn ty(&self) -> Self::Type { + self.ty + } +} + +impl ToExpr for FormalInputExpr { + fn to_expr(&self) -> Expr { + Expr { + __enum: ExprEnum::FormalInput(FormalInputExpr { + formal_input: self.formal_input, + ty: self.formal_input.ty(), + target: self.target, + }) + .intern(), + __ty: self.ty, + __flow: self.formal_input.flow(), + } + } +} diff --git a/crates/fayalite/src/expr/target.rs b/crates/fayalite/src/expr/target.rs index 95d8e0f..a4967e2 100644 --- a/crates/fayalite/src/expr/target.rs +++ b/crates/fayalite/src/expr/target.rs @@ -4,13 +4,14 @@ use crate::{ array::Array, bundle::{Bundle, BundleField}, expr::{Expr, Flow, ToExpr, ValueType, value_category::ValueCategoryExpr}, + formal::FormalInput, intern::{Intern, Interned}, memory::{DynPortType, MemPort}, module::{Instance, ModuleIO, TargetName}, reg::Reg, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, source_location::SourceLocation, - ty::{CanonicalType, Type}, + ty::{CanonicalType, TraceAsString, Type}, wire::Wire, }; use std::fmt; @@ -46,11 +47,33 @@ impl fmt::Display for TargetPathDynArrayElement { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct TargetPathTraceAsStringInner {} + +impl fmt::Display for TargetPathTraceAsStringInner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, ".") + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct TargetPathToTraceAsString { + pub ty: TraceAsString, +} + +impl fmt::Display for TargetPathToTraceAsString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, ".to_trace_as_string(...)") + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum TargetPathElement { BundleField(TargetPathBundleField), ArrayElement(TargetPathArrayElement), DynArrayElement(TargetPathDynArrayElement), + TraceAsStringInner(TargetPathTraceAsStringInner), + ToTraceAsString(TargetPathToTraceAsString), } impl From for TargetPathElement { @@ -71,12 +94,26 @@ impl From for TargetPathElement { } } +impl From for TargetPathElement { + fn from(value: TargetPathTraceAsStringInner) -> Self { + Self::TraceAsStringInner(value) + } +} + +impl From for TargetPathElement { + fn from(value: TargetPathToTraceAsString) -> Self { + Self::ToTraceAsString(value) + } +} + impl fmt::Display for TargetPathElement { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::BundleField(v) => v.fmt(f), Self::ArrayElement(v) => v.fmt(f), Self::DynArrayElement(v) => v.fmt(f), + Self::TraceAsStringInner(v) => v.fmt(f), + Self::ToTraceAsString(v) => v.fmt(f), } } } @@ -100,6 +137,15 @@ impl TargetPathElement { let parent_ty = Array::::from_canonical(parent.canonical_ty()); parent_ty.element() } + Self::TraceAsStringInner(_) => { + let parent_ty = + TraceAsString::::from_canonical(parent.canonical_ty()); + parent_ty.inner_ty() + } + &Self::ToTraceAsString(TargetPathToTraceAsString { ty }) => { + assert_eq!(parent.canonical_ty(), ty.inner_ty()); + ty.canonical() + } } } pub fn flow(&self, parent: Interned) -> Flow { @@ -111,13 +157,18 @@ impl TargetPathElement { .expect("field name is known to be a valid field of parent type"); parent.flow().flip_if(field.flipped) } - Self::ArrayElement(_) => parent.flow(), - Self::DynArrayElement(_) => parent.flow(), + Self::ArrayElement(_) + | Self::DynArrayElement(_) + | Self::TraceAsStringInner(_) + | Self::ToTraceAsString(_) => parent.flow(), } } pub fn is_static(&self) -> bool { match self { - Self::BundleField(_) | Self::ArrayElement(_) => true, + Self::BundleField(_) + | Self::ArrayElement(_) + | Self::TraceAsStringInner(_) + | Self::ToTraceAsString(_) => true, Self::DynArrayElement(_) => false, } } @@ -245,6 +296,10 @@ impl_target_base! { #[is = is_instance] #[to = instance] Instance(Instance), + #[from = from] + #[is = is_formal_input] + #[to = formal_input] + FormalInput(FormalInput), } } @@ -293,6 +348,7 @@ impl TargetBase { TargetBase::RegAsync(v) => TargetName(v.scoped_name(), None), TargetBase::Wire(v) => TargetName(v.scoped_name(), None), TargetBase::Instance(v) => TargetName(v.scoped_name(), None), + TargetBase::FormalInput(v) => TargetName(v.scoped_name(), None), } } pub fn canonical_ty(&self) -> CanonicalType { @@ -304,6 +360,7 @@ impl TargetBase { TargetBase::RegAsync(v) => v.ty(), TargetBase::Wire(v) => v.ty(), TargetBase::Instance(v) => v.ty().canonical(), + TargetBase::FormalInput(v) => v.ty(), } } } @@ -314,6 +371,7 @@ pub struct TargetChild { path_element: Interned, canonical_ty: CanonicalType, flow: Flow, + canonicalized_if_different: Option>, } impl fmt::Debug for TargetChild { @@ -323,6 +381,7 @@ impl fmt::Debug for TargetChild { path_element, canonical_ty: _, flow: _, + canonicalized_if_different: _, } = self; parent.fmt(f)?; fmt::Display::fmt(path_element, f) @@ -336,6 +395,7 @@ impl fmt::Display for TargetChild { path_element, canonical_ty: _, flow: _, + canonicalized_if_different: _, } = self; parent.fmt(f)?; path_element.fmt(f) @@ -343,14 +403,69 @@ impl fmt::Display for TargetChild { } impl TargetChild { - pub fn new(parent: Interned, path_element: Interned) -> Self { + fn new_helper( + parent: Interned, + path_element: Interned, + canonicalized_if_different: Option>, + ) -> Self { Self { parent, path_element, canonical_ty: path_element.canonical_ty(parent), flow: path_element.flow(parent), + canonicalized_if_different, } } + fn make_canonicalized_if_different( + parent: Interned, + path_element: Interned, + ) -> Option> { + use TargetPathElement::*; + match *path_element { + BundleField(_) => {} + ArrayElement(_) => {} + DynArrayElement(_) => {} + TraceAsStringInner(_) => { + if let Some(child) = parent.canonicalized().child() { + match *child.path_element() { + BundleField(_) + | ArrayElement(_) + | DynArrayElement(_) + | TraceAsStringInner(_) => {} + ToTraceAsString(_) => return Some(child.parent()), + } + } + } + ToTraceAsString(TargetPathToTraceAsString { ty }) => { + if let Some(child) = parent.canonicalized().child() { + match *child.path_element() { + BundleField(_) | ArrayElement(_) | DynArrayElement(_) + | ToTraceAsString(_) => {} + TraceAsStringInner(_) => { + if ty.canonical() == child.parent().canonical_ty() { + return Some(child.parent()); + } + } + } + } + } + } + Some( + Target::Child(Self::new_helper( + parent.canonicalized_if_different()?, + path_element, + None, + )) + .intern_sized(), + ) + } + pub fn new(parent: Interned, path_element: Interned) -> Self { + Self::new_helper( + parent, + path_element, + Self::make_canonicalized_if_different(parent, path_element), + ) + } pub fn parent(self) -> Interned { self.parent } @@ -363,6 +478,19 @@ impl TargetChild { pub fn flow(self) -> Flow { self.flow } + pub fn is_canonicalized(self) -> bool { + self.canonicalized_if_different.is_none() + } + pub fn canonicalized_if_different(self) -> Option> { + self.canonicalized_if_different + } + #[must_use] + pub fn canonicalized(self) -> Target { + match self.canonicalized_if_different { + Some(v) => *v, + None => Target::Child(self), + } + } pub fn bundle_field(self) -> Option { if let TargetPathElement::BundleField(TargetPathBundleField { name }) = *self.path_element { let parent_ty = Bundle::from_canonical(self.parent.canonical_ty()); @@ -443,6 +571,82 @@ impl Target { Target::Child(v) => v.canonical_ty(), } } + pub fn is_canonicalized(self) -> bool { + match self { + Self::Base(_) => true, + Self::Child(child) => child.is_canonicalized(), + } + } + pub fn canonicalized_if_different(self) -> Option> { + match self { + Self::Base(_) => None, + Self::Child(child) => child.canonicalized_if_different(), + } + } + #[must_use] + pub fn canonicalized(self) -> Target { + match self.canonicalized_if_different() { + Some(v) => *v, + None => self, + } + } + #[must_use] + pub fn canonicalized_interned(this: Interned) -> Interned { + this.canonicalized_if_different().unwrap_or(this) + } + #[must_use] + pub fn unwrap_transparent_types(mut self) -> Target { + loop { + self = self.canonicalized(); + match self.canonical_ty() { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::Array(_) + | CanonicalType::Enum(_) + | CanonicalType::Bundle(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => return self, + CanonicalType::TraceAsString(_) => { + if let Self::Child(child) = self + && let TargetPathElement::ToTraceAsString(_) = *child.path_element() + { + self = *child.parent(); + } else { + self = self.join(TargetPathElement::intern_sized( + TargetPathTraceAsStringInner {}.into(), + )); + } + } + } + } + } + #[must_use] + pub fn unwrap_transparent_types_interned(this: Interned) -> Interned { + let retval = this.unwrap_transparent_types(); + if retval != *this { + retval.intern_sized() + } else { + this + } + } + #[must_use] + pub fn without_trailing_transparent_path_elements(mut self) -> Target { + use TargetPathElement::*; + loop { + match self { + Self::Base(_) => return self, + Self::Child(child) => match *child.path_element() { + BundleField(_) | ArrayElement(_) | DynArrayElement(_) => return self, + TraceAsStringInner(_) | ToTraceAsString(_) => self = *child.parent(), + }, + } + } + } } impl fmt::Display for Target { diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index 383bd95..d7c5e0b 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -2,46 +2,41 @@ // See Notices.txt for copyright information #![allow(clippy::type_complexity)] use crate::{ - annotations::{ - Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, - DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, TargetedAnnotation, - }, - array::Array, + annotations::{Annotation, TargetedAnnotation}, build::{ToArgs, WriteArgs}, - bundle::{Bundle, BundleField, BundleType}, - clock::Clock, - enum_::{Enum, EnumType, EnumVariant}, + bundle::{BundleField, BundleType}, + enum_::{EnumType, EnumVariant}, expr::{ - CastBitsTo, Expr, ExprEnum, ToExpr, ValueType, + ExprEnum, ops::{self, VariantAccess}, target::{ Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, + TargetPathTraceAsStringInner, }, }, - formal::FormalKind, - int::{Bool, DynSize, IntType, SIntValue, UInt, UIntValue}, + formal::{FormalInput, FormalInputKind, FormalKind}, + int::IntType, intern::{Intern, Interned}, - memory::{Mem, PortKind, PortName, ReadUnderWrite}, + memory::{PortKind, PortName}, module::{ AnnotatedModuleIO, Block, ExternModuleBody, ExternModuleParameter, - ExternModuleParameterValue, Module, ModuleBody, ModuleIO, NameId, NameOptId, - NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, - StmtMatch, StmtReg, StmtWire, + ExternModuleParameterValue, ModuleBody, ModuleIO, NameId, NameOptId, NormalModuleBody, + Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, + StmtWire, transform::{ simplify_enums::{SimplifyEnumsError, SimplifyEnumsKind, simplify_enums}, simplify_memories::simplify_memories, }, }, - reset::{AsyncReset, Reset, ResetType, SyncReset}, - source_location::SourceLocation, - ty::{CanonicalType, OpaqueSimValueSize, Type}, + prelude::*, + reset::ResetType, + ty::OpaqueSimValueSize, util::{ BitSliceWriteWithBase, DebugAsRawString, GenericConstBool, HashMap, HashSet, const_str_array_is_strictly_ascending, }, vendor::xilinx::XilinxAnnotation, }; -use bitvec::slice::BitSlice; use clap::value_parser; use num_traits::Signed; use serde::{Deserialize, Serialize}; @@ -377,6 +372,90 @@ impl DefinitionsMap { } } +#[derive(Default)] +struct BlockDefinitionsCache { + array_literal_exprs: + RefCell, bool), String>>, + bundle_literal_exprs: RefCell>, + uninit_exprs: RefCell>, + cast_bundle_to_bits_exprs: RefCell>, + cast_enum_to_bits_exprs: RefCell>, + cast_array_to_bits_exprs: RefCell>, + cast_bits_to_bundle_exprs: RefCell>, + cast_bits_to_enum_exprs: RefCell>, + cast_bits_to_array_exprs: RefCell>, + cast_bits_to_phantom_const_exprs: RefCell>, + per_module_formal_inputs: RefCell>, +} + +struct BlockDefinitions<'a> { + rc_definitions: RcDefinitions, + parent: Option<&'a BlockDefinitions<'a>>, + cache: BlockDefinitionsCache, +} + +impl<'a> BlockDefinitions<'a> { + fn new(parent: &'a BlockDefinitions<'a>) -> Self { + Self { + rc_definitions: RcDefinitions::default(), + parent: Some(parent), + cache: Default::default(), + } + } + fn module() -> Self { + Self { + rc_definitions: RcDefinitions::default(), + parent: None, + cache: Default::default(), + } + } + fn get_or_write_definition( + &self, + key: K, + field: impl Fn(&BlockDefinitionsCache) -> &RefCell>, + write_definition: impl FnOnce(BlockDefinitionsWriter<'_, '_>, &K) -> Result, + ) -> Result { + let mut current = self; + loop { + let field = field(¤t.cache).borrow(); + if let Some(retval) = field.get(&key) { + return Ok(retval.clone()); + } + let Some(parent) = current.parent else { + break; + }; + current = parent; + } + let retval = write_definition(BlockDefinitionsWriter { definitions: self }, &key)?; + Ok(field(&self.cache) + .borrow_mut() + .entry(key) + .or_insert(retval) + .clone()) + } + fn write_out(&self, indent: Indent<'_>, out: &mut String) { + self.rc_definitions.write_and_clear(indent, out); + } +} + +struct BlockDefinitionsWriter<'a, 'b> { + definitions: &'b BlockDefinitions<'a>, +} + +impl BlockDefinitionsWriter<'_, '_> { + fn add_definition_line(&self, v: impl fmt::Display) { + self.definitions.rc_definitions.add_definition_line(v); + } +} + +impl<'a> std::ops::Deref for BlockDefinitionsWriter<'a, '_> { + type Target = BlockDefinitions<'a>; + + fn deref(&self) -> &Self::Target { + &self.definitions + } +} + struct EnumDef { variants: RefCell, body: String, @@ -471,7 +550,7 @@ impl TypeState { Ok(self.enum_def(ty)?.1.variants.borrow_mut().get(name)) } fn ty(&self, ty: T) -> Result { - Ok(match ty.canonical() { + Ok(match ty.canonical().unwrap_transparent_types() { CanonicalType::Bundle(ty) => self.bundle_ty(ty)?.to_string(), CanonicalType::Enum(ty) => self.enum_ty(ty)?.to_string(), CanonicalType::Array(ty) => { @@ -490,23 +569,23 @@ impl TypeState { CanonicalType::DynSimOnly(_) => { return Err(FirrtlError::SimOnlyValuesAreNotPermitted); } + CanonicalType::TraceAsString(_) => unreachable!("handled by unwrap_transparent_types"), }) } } struct ModuleState { ns: Namespace, - definitions: RcDefinitions, match_arm_values: HashMap, Ident>, + block_definitions: Rc>, } impl Default for ModuleState { fn default() -> Self { - let definitions = RcDefinitions::default(); Self { ns: Default::default(), - definitions, match_arm_values: Default::default(), + block_definitions: Rc::new(BlockDefinitions::module()), } } } @@ -874,7 +953,7 @@ impl<'a> Exporter<'a> { &mut self, value: Expr, to_ty: ToTy, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { let from_ty = value.ty(); @@ -909,7 +988,7 @@ impl<'a> Exporter<'a> { &mut self, firrtl_cast_fn: Option<&str>, value: Expr, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { let value = self.expr(Expr::canonical(value), definitions, const_ty)?; @@ -923,7 +1002,7 @@ impl<'a> Exporter<'a> { &mut self, base: Expr, range: Range, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { let base_width = base.ty().width(); @@ -941,73 +1020,95 @@ impl<'a> Exporter<'a> { fn array_literal_expr( &mut self, expr: ops::ArrayLiteral, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { - let ident = self.module.ns.make_new("_array_literal_expr"); - let ty_str = self.type_state.ty(expr.ty())?; - let const_ = if const_ty { "const " } else { "" }; - definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_str}")); - for (index, element) in expr.element_values().into_iter().enumerate() { - let element = self.expr(Expr::canonical(element), definitions, const_ty)?; - definitions.add_definition_line(format_args!("connect {ident}[{index}], {element}")); - } - if expr.element_values().is_empty() { - definitions.add_definition_line(format_args!("invalidate {ident}")); - } - Ok(ident.to_string()) + definitions.get_or_write_definition( + (expr, const_ty), + |c| &c.array_literal_exprs, + |definitions, &(expr, const_ty)| { + let ident = self.module.ns.make_new("_array_literal_expr"); + let ty_str = self.type_state.ty(expr.ty())?; + let const_ = if const_ty { "const " } else { "" }; + definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_str}")); + for (index, element) in expr.element_values().into_iter().enumerate() { + let element = self.expr(Expr::canonical(element), &definitions, const_ty)?; + definitions + .add_definition_line(format_args!("connect {ident}[{index}], {element}")); + } + if expr.element_values().is_empty() { + definitions.add_definition_line(format_args!("invalidate {ident}")); + } + Ok(ident.to_string()) + }, + ) } fn bundle_literal_expr( &mut self, expr: ops::BundleLiteral, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { - let ident = self.module.ns.make_new("_bundle_literal_expr"); - let ty = expr.ty(); - let (ty_ident, bundle_ns) = self.type_state.bundle_def(ty)?; - let const_ = if const_ty { "const " } else { "" }; - definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); - for ( - field_value, - BundleField { - name, - flipped, - ty: _, + definitions.get_or_write_definition( + (expr, const_ty), + |c| &c.bundle_literal_exprs, + |definitions, &(expr, const_ty)| { + let ident = self.module.ns.make_new("_bundle_literal_expr"); + let ty = expr.ty(); + let (ty_ident, bundle_ns) = self.type_state.bundle_def(ty)?; + let const_ = if const_ty { "const " } else { "" }; + definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); + for ( + field_value, + BundleField { + name, + flipped, + ty: _, + }, + ) in expr.field_values().into_iter().zip(ty.fields()) + { + debug_assert!( + !flipped, + "can't have bundle literal with flipped field -- \ + this should have been caught in BundleLiteral::new_unchecked" + ); + let name = bundle_ns.borrow_mut().get(name); + let field_value = + self.expr(Expr::canonical(field_value), &definitions, const_ty)?; + definitions + .add_definition_line(format_args!("connect {ident}.{name}, {field_value}")); + } + if ty.fields().is_empty() { + definitions.add_definition_line(format_args!("invalidate {ident}")); + } + Ok(ident.to_string()) }, - ) in expr.field_values().into_iter().zip(ty.fields()) - { - debug_assert!( - !flipped, - "can't have bundle literal with flipped field -- this should have been caught in BundleLiteral::new_unchecked" - ); - let name = bundle_ns.borrow_mut().get(name); - let field_value = self.expr(Expr::canonical(field_value), definitions, const_ty)?; - definitions.add_definition_line(format_args!("connect {ident}.{name}, {field_value}")); - } - if ty.fields().is_empty() { - definitions.add_definition_line(format_args!("invalidate {ident}")); - } - Ok(ident.to_string()) + ) } fn uninit_expr( &mut self, expr: ops::Uninit, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { - let ident = self.module.ns.make_new("_uninit_expr"); - let ty = expr.ty(); - let ty_ident = self.type_state.ty(ty)?; - let const_ = if const_ty { "const " } else { "" }; - definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); - definitions.add_definition_line(format_args!("invalidate {ident}")); - Ok(ident.to_string()) + definitions.get_or_write_definition( + (expr, const_ty), + |c| &c.uninit_exprs, + |definitions, &(expr, const_ty)| { + let ident = self.module.ns.make_new("_uninit_expr"); + let ty = expr.ty(); + let ty_ident = self.type_state.ty(ty)?; + let const_ = if const_ty { "const " } else { "" }; + definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); + definitions.add_definition_line(format_args!("invalidate {ident}")); + Ok(ident.to_string()) + }, + ) } fn enum_literal_expr( &mut self, expr: ops::EnumLiteral, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { let variant_expr = expr @@ -1020,178 +1121,201 @@ impl<'a> Exporter<'a> { &mut self, value_str: String, ty: Bundle, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - if ty.fields().is_empty() { - return Ok("UInt<0>(0)".into()); - } - if let [field] = *ty.fields() { - let field_ident = self.type_state.get_bundle_field(ty, field.name)?; - return self.expr_cast_to_bits( - format!("{value_str}.{field_ident}"), - field.ty, - definitions, - extra_indent, - ); - } - let flattened_bundle_ty = Bundle::new(Interned::from_iter(ty.fields().iter().map( - |&BundleField { - name, - flipped: _, - ty: field_ty, - }| BundleField { - name, - flipped: false, - ty: UInt[field_ty.bit_width()].canonical(), + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_bundle_to_bits_exprs, + |definitions, &(ref value_str, ty)| { + if ty.fields().is_empty() { + return Ok("UInt<0>(0)".into()); + } + if let [field] = *ty.fields() { + let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + return self.expr_cast_to_bits( + format!("{value_str}.{field_ident}"), + field.ty, + &definitions, + extra_indent, + ); + } + let flattened_bundle_ty = Bundle::new(Interned::from_iter(ty.fields().iter().map( + |&BundleField { + name, + flipped: _, + ty: field_ty, + }| BundleField { + name, + flipped: false, + ty: UInt[field_ty.bit_width()].canonical(), + }, + ))); + let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty)?; + let ident = self.module.ns.make_new("_cast_bundle_to_bits_expr"); + definitions.add_definition_line(format_args!( + "{extra_indent}wire {ident}: {flattened_ty_ident}" + )); + let mut cat_expr = None; + for field in ty.fields() { + let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + let flattened_field_ident = self + .type_state + .get_bundle_field(flattened_bundle_ty, field.name)?; + let field_bits = self.expr_cast_to_bits( + format!("{value_str}.{field_ident}"), + field.ty, + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {ident}.{flattened_field_ident}, {field_bits}" + )); + cat_expr = Some(if let Some(cat_expr) = cat_expr { + format!("cat({ident}.{flattened_field_ident}, {cat_expr})") + } else { + format!("{ident}.{flattened_field_ident}") + }); + } + let retval = self.module.ns.make_new("_cast_to_bits_expr"); + definitions.add_definition_line(format_args!( + "{extra_indent}wire {retval}: UInt<{}>", + ty.type_properties().bit_width + )); + let cat_expr = cat_expr.expect("bundle already checked to have fields"); + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {cat_expr}" + )); + Ok(retval.to_string()) }, - ))); - let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty)?; - let ident = self.module.ns.make_new("_cast_bundle_to_bits_expr"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {ident}: {flattened_ty_ident}" - )); - let mut cat_expr = None; - for field in ty.fields() { - let field_ident = self.type_state.get_bundle_field(ty, field.name)?; - let flattened_field_ident = self - .type_state - .get_bundle_field(flattened_bundle_ty, field.name)?; - let field_bits = self.expr_cast_to_bits( - format!("{value_str}.{field_ident}"), - field.ty, - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {ident}.{flattened_field_ident}, {field_bits}" - )); - cat_expr = Some(if let Some(cat_expr) = cat_expr { - format!("cat({ident}.{flattened_field_ident}, {cat_expr})") - } else { - format!("{ident}.{flattened_field_ident}") - }); - } - let retval = self.module.ns.make_new("_cast_to_bits_expr"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {retval}: UInt<{}>", - ty.type_properties().bit_width - )); - let cat_expr = cat_expr.expect("bundle already checked to have fields"); - definitions.add_definition_line(format_args!("{extra_indent}connect {retval}, {cat_expr}")); - Ok(retval.to_string()) + ) } fn expr_cast_enum_to_bits( &mut self, value_str: String, ty: Enum, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - if ty.variants().is_empty() { - return Ok("UInt<0>(0)".into()); - } - let retval = self.module.ns.make_new("_cast_enum_to_bits_expr"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {retval}: UInt<{}>", - ty.type_properties().bit_width - )); - definitions.add_definition_line(format_args!("{extra_indent}match {value_str}:")); - let _match_arms_indent = extra_indent.push(); - for (variant_index, variant) in ty.variants().into_iter().enumerate() { - if let Some(variant_ty) = variant.ty { - let variant_value = self - .module - .ns - .make_new(&format!("_cast_enum_to_bits_expr_{}", variant.name)); + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_enum_to_bits_exprs, + |definitions, &(ref value_str, ty)| { + if ty.variants().is_empty() { + return Ok("UInt<0>(0)".into()); + } + let retval = self.module.ns.make_new("_cast_enum_to_bits_expr"); definitions.add_definition_line(format_args!( - "{extra_indent}{}({variant_value}):", - self.type_state.get_enum_variant(ty, variant.name)?, + "{extra_indent}wire {retval}: UInt<{}>", + ty.type_properties().bit_width )); - let _match_arm_indent = extra_indent.push(); - let variant_bits = self.expr_cast_to_bits( - variant_value.to_string(), - variant_ty, - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, pad(cat({variant_bits}, UInt<{}>({variant_index})), {})", - ty.discriminant_bit_width(), - ty.type_properties().bit_width, - )); - } else { - definitions.add_definition_line(format_args!( - "{extra_indent}{}:", - self.type_state.get_enum_variant(ty, variant.name)?, - )); - let _match_arm_indent = extra_indent.push(); - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, UInt<{}>({variant_index})", - ty.type_properties().bit_width, - )); - } - } - Ok(retval.to_string()) + definitions.add_definition_line(format_args!("{extra_indent}match {value_str}:")); + let _match_arms_indent = extra_indent.push(); + for (variant_index, variant) in ty.variants().into_iter().enumerate() { + if let Some(variant_ty) = variant.ty { + let variant_value = self + .module + .ns + .make_new(&format!("_cast_enum_to_bits_expr_{}", variant.name)); + definitions.add_definition_line(format_args!( + "{extra_indent}{}({variant_value}):", + self.type_state.get_enum_variant(ty, variant.name)?, + )); + let _match_arm_indent = extra_indent.push(); + let variant_bits = self.expr_cast_to_bits( + variant_value.to_string(), + variant_ty, + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, \ + pad(cat({variant_bits}, UInt<{}>({variant_index})), {})", + ty.discriminant_bit_width(), + ty.type_properties().bit_width, + )); + } else { + definitions.add_definition_line(format_args!( + "{extra_indent}{}:", + self.type_state.get_enum_variant(ty, variant.name)?, + )); + let _match_arm_indent = extra_indent.push(); + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, UInt<{}>({variant_index})", + ty.type_properties().bit_width, + )); + } + } + Ok(retval.to_string()) + }, + ) } fn expr_cast_array_to_bits( &mut self, value_str: String, ty: Array, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - if ty.is_empty() { - return Ok("UInt<0>(0)".into()); - } - if ty.len() == 1 { - return self.expr_cast_to_bits( - value_str + "[0]", - ty.element(), - definitions, - extra_indent, - ); - } - let element_width = ty.element().bit_width(); - let ident = self.module.ns.make_new("_cast_array_to_bits_expr"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {ident}: UInt<{element_width}>[{}]", - ty.len(), - )); - let mut cat_expr = None; - for index in 0..ty.len() { - let element_bits = self.expr_cast_to_bits( - format!("{value_str}[{index}]"), - ty.element(), - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {ident}[{index}], {element_bits}" - )); - cat_expr = Some(if let Some(cat_expr) = cat_expr { - format!("cat({ident}[{index}], {cat_expr})") - } else { - format!("{ident}[{index}]") - }); - } - let retval = self.module.ns.make_new("_cast_to_bits_expr"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {retval}: UInt<{}>", - ty.type_properties().bit_width - )); - let cat_expr = cat_expr.expect("array already checked to have elements"); - definitions.add_definition_line(format_args!("{extra_indent}connect {retval}, {cat_expr}")); - Ok(retval.to_string()) + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_array_to_bits_exprs, + |definitions, &(ref value_str, ty)| { + if ty.is_empty() { + return Ok("UInt<0>(0)".into()); + } + if ty.len() == 1 { + return self.expr_cast_to_bits( + value_str.clone() + "[0]", + ty.element(), + &definitions, + extra_indent, + ); + } + let element_width = ty.element().bit_width(); + let ident = self.module.ns.make_new("_cast_array_to_bits_expr"); + definitions.add_definition_line(format_args!( + "{extra_indent}wire {ident}: UInt<{element_width}>[{}]", + ty.len(), + )); + let mut cat_expr = None; + for index in 0..ty.len() { + let element_bits = self.expr_cast_to_bits( + format!("{value_str}[{index}]"), + ty.element(), + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {ident}[{index}], {element_bits}" + )); + cat_expr = Some(if let Some(cat_expr) = cat_expr { + format!("cat({ident}[{index}], {cat_expr})") + } else { + format!("{ident}[{index}]") + }); + } + let retval = self.module.ns.make_new("_cast_to_bits_expr"); + definitions.add_definition_line(format_args!( + "{extra_indent}wire {retval}: UInt<{}>", + ty.type_properties().bit_width + )); + let cat_expr = cat_expr.expect("array already checked to have elements"); + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {cat_expr}" + )); + Ok(retval.to_string()) + }, + ) } fn expr_cast_to_bits( &mut self, value_str: String, ty: CanonicalType, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - match ty { + match ty.unwrap_transparent_types() { CanonicalType::Bundle(ty) => { self.expr_cast_bundle_to_bits(value_str, ty, definitions, extra_indent) } @@ -1210,204 +1334,240 @@ impl<'a> Exporter<'a> { | CanonicalType::Reset(_) => Ok(format!("asUInt({value_str})")), CanonicalType::PhantomConst(_) => Ok("UInt<0>(0)".into()), CanonicalType::DynSimOnly(_) => Err(FirrtlError::SimOnlyValuesAreNotPermitted.into()), + CanonicalType::TraceAsString(_) => unreachable!("handled by unwrap_transparent_types"), } } fn expr_cast_bits_to_bundle( &mut self, value_str: String, ty: Bundle, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - let (ty_ident, _) = self.type_state.bundle_def(ty)?; - let retval = self.module.ns.make_new("_cast_bits_to_bundle_expr"); - definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {ty_ident}")); - if ty.fields().is_empty() { - definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); - } - let flattened_bundle_ty = Bundle::new(Interned::from_iter(ty.fields().iter().map( - |&BundleField { - name, - flipped: _, - ty: field_ty, - }| BundleField { - name, - flipped: false, - ty: UInt[field_ty.bit_width()].canonical(), - }, - ))); - let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty)?; - let flattened_ident = self - .module - .ns - .make_new("_cast_bits_to_bundle_expr_flattened"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {flattened_ident}: {flattened_ty_ident}" - )); - for ( - field, - OpaqueSimValueSize { - bit_width: field_offset, - sim_only_values_len: _, - }, - ) in ty.fields().into_iter().zip(ty.field_offsets()) - { - let flattened_field_ident = self - .type_state - .get_bundle_field(flattened_bundle_ty, field.name)?; - let field_ident = self.type_state.get_bundle_field(ty, field.name)?; - if let Some(field_bit_width_minus_one) = field.ty.bit_width().checked_sub(1usize) { + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_bits_to_bundle_exprs, + |definitions, &(ref value_str, ty)| { + let (ty_ident, _) = self.type_state.bundle_def(ty)?; + let retval = self.module.ns.make_new("_cast_bits_to_bundle_expr"); + definitions + .add_definition_line(format_args!("{extra_indent}wire {retval}: {ty_ident}")); + if ty.fields().is_empty() { + definitions + .add_definition_line(format_args!("{extra_indent}invalidate {retval}")); + return Ok(retval.to_string()); + } + let flattened_bundle_ty = Bundle::new(Interned::from_iter(ty.fields().iter().map( + |&BundleField { + name, + flipped: _, + ty: field_ty, + }| BundleField { + name, + flipped: false, + ty: UInt[field_ty.bit_width()].canonical(), + }, + ))); + let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty)?; + let flattened_ident = self + .module + .ns + .make_new("_cast_bits_to_bundle_expr_flattened"); definitions.add_definition_line(format_args!( - "{extra_indent}connect {flattened_ident}.{flattened_field_ident}, bits({value_str}, {}, {field_offset})", - field_offset + field_bit_width_minus_one + "{extra_indent}wire {flattened_ident}: {flattened_ty_ident}" )); - } else { - definitions.add_definition_line(format_args!( + for ( + field, + OpaqueSimValueSize { + bit_width: field_offset, + sim_only_values_len: _, + }, + ) in ty.fields().into_iter().zip(ty.field_offsets()) + { + let flattened_field_ident = self + .type_state + .get_bundle_field(flattened_bundle_ty, field.name)?; + let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + if let Some(field_bit_width_minus_one) = + field.ty.bit_width().checked_sub(1usize) + { + definitions.add_definition_line(format_args!( + "{extra_indent}connect {flattened_ident}.{flattened_field_ident}, \ + bits({value_str}, {}, {field_offset})", + field_offset + field_bit_width_minus_one + )); + } else { + definitions.add_definition_line(format_args!( "{extra_indent}connect {flattened_ident}.{flattened_field_ident}, UInt<0>(0)" )); - } - let field_value = self.expr_cast_bits_to( - format!("{flattened_ident}.{flattened_field_ident}"), - field.ty, - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}.{field_ident}, {field_value}" - )); - } - Ok(retval.to_string()) + } + let field_value = self.expr_cast_bits_to( + format!("{flattened_ident}.{flattened_field_ident}"), + field.ty, + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}.{field_ident}, {field_value}" + )); + } + Ok(retval.to_string()) + }, + ) } fn expr_cast_bits_to_enum( &mut self, value_str: String, ty: Enum, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - let (ty_ident, enum_def) = self.type_state.enum_def(ty)?; - let retval = self.module.ns.make_new("_cast_bits_to_enum_expr"); - definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {ty_ident}")); - if ty.variants().is_empty() { - definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); - } - if let [variant] = *ty.variants() { - let enum_variant = self.type_state.get_enum_variant(ty, variant.name)?; - if let Some(variant_ty) = variant.ty { - let variant_value = - self.expr_cast_bits_to(value_str, variant_ty, definitions, extra_indent)?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, {}({enum_variant}, {variant_value})", - enum_def.body - )); - } else { - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, {}({enum_variant})", - enum_def.body - )); - } - return Ok(retval.to_string()); - } - let discriminant_bit_width = ty.discriminant_bit_width(); - let body_bit_width = ty.type_properties().bit_width - discriminant_bit_width; - let body_ident = self.module.ns.make_new("_cast_bits_to_enum_expr_body"); - let body_value = if body_bit_width != 0 { - definitions.add_definition_line(format_args!( - "{extra_indent}wire {body_ident}: UInt<{body_bit_width}>" - )); - definitions.add_definition_line(format_args!( - "{extra_indent}connect {body_ident}, head({value_str}, {body_bit_width})" - )); - body_ident.to_string() - } else { - "UInt<0>(0)".into() - }; - for (variant_index, variant) in ty.variants().into_iter().enumerate() { - let when_cond = format!( - "eq(UInt<{discriminant_bit_width}>({variant_index}), tail({value_str}, {body_bit_width}))" - ); - if variant_index == ty.variants().len() - 1 { - definitions.add_definition_line(format_args!("{extra_indent}else:")); - } else if variant_index == 0 { - definitions.add_definition_line(format_args!("{extra_indent}when {when_cond}:")); - } else { + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_bits_to_enum_exprs, + |definitions, &(ref value_str, ty)| { + let (ty_ident, enum_def) = self.type_state.enum_def(ty)?; + let retval = self.module.ns.make_new("_cast_bits_to_enum_expr"); definitions - .add_definition_line(format_args!("{extra_indent}else when {when_cond}:")); - } - let when_pushed_indent = extra_indent.push(); - let enum_variant = self.type_state.get_enum_variant(ty, variant.name)?; - if let Some(variant_ty) = variant.ty { - let variant_value = self.expr_cast_bits_to( - body_value.clone(), - variant_ty, - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, {}({enum_variant}, {variant_value})", - enum_def.body - )); - } else { - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}, {}({enum_variant})", - enum_def.body - )); - } - drop(when_pushed_indent); - } - Ok(retval.to_string()) + .add_definition_line(format_args!("{extra_indent}wire {retval}: {ty_ident}")); + if ty.variants().is_empty() { + definitions + .add_definition_line(format_args!("{extra_indent}invalidate {retval}")); + return Ok(retval.to_string()); + } + if let [variant] = *ty.variants() { + let enum_variant = self.type_state.get_enum_variant(ty, variant.name)?; + if let Some(variant_ty) = variant.ty { + let variant_value = self.expr_cast_bits_to( + value_str.clone(), + variant_ty, + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {}({enum_variant}, {variant_value})", + enum_def.body + )); + } else { + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {}({enum_variant})", + enum_def.body + )); + } + return Ok(retval.to_string()); + } + let discriminant_bit_width = ty.discriminant_bit_width(); + let body_bit_width = ty.type_properties().bit_width - discriminant_bit_width; + let body_ident = self.module.ns.make_new("_cast_bits_to_enum_expr_body"); + let body_value = if body_bit_width != 0 { + definitions.add_definition_line(format_args!( + "{extra_indent}wire {body_ident}: UInt<{body_bit_width}>" + )); + definitions.add_definition_line(format_args!( + "{extra_indent}connect {body_ident}, head({value_str}, {body_bit_width})" + )); + body_ident.to_string() + } else { + "UInt<0>(0)".into() + }; + for (variant_index, variant) in ty.variants().into_iter().enumerate() { + let when_cond = format!( + "eq(UInt<{discriminant_bit_width}>({variant_index}), \ + tail({value_str}, {body_bit_width}))" + ); + if variant_index == ty.variants().len() - 1 { + definitions.add_definition_line(format_args!("{extra_indent}else:")); + } else if variant_index == 0 { + definitions + .add_definition_line(format_args!("{extra_indent}when {when_cond}:")); + } else { + definitions.add_definition_line(format_args!( + "{extra_indent}else when {when_cond}:" + )); + } + let when_pushed_indent = extra_indent.push(); + let enum_variant = self.type_state.get_enum_variant(ty, variant.name)?; + if let Some(variant_ty) = variant.ty { + let variant_value = self.expr_cast_bits_to( + body_value.clone(), + variant_ty, + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {}({enum_variant}, {variant_value})", + enum_def.body + )); + } else { + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}, {}({enum_variant})", + enum_def.body + )); + } + drop(when_pushed_indent); + } + Ok(retval.to_string()) + }, + ) } fn expr_cast_bits_to_array( &mut self, value_str: String, ty: Array, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - let retval = self.module.ns.make_new("_cast_bits_to_array_expr"); - let array_ty = self.type_state.ty(ty)?; - definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {array_ty}")); - let element_bit_width = ty.element().bit_width(); - if ty.is_empty() || element_bit_width == 0 { - definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); - } - let flattened_ident = self - .module - .ns - .make_new("_cast_bits_to_array_expr_flattened"); - definitions.add_definition_line(format_args!( - "{extra_indent}wire {flattened_ident}: UInt<{element_bit_width}>[{}]", - ty.len(), - )); - for index in 0..ty.len() { - definitions.add_definition_line(format_args!( - "{extra_indent}connect {flattened_ident}[{index}], bits({value_str}, {}, {})", - element_bit_width * index + element_bit_width - 1, - element_bit_width * index, - )); - let element_value = self.expr_cast_bits_to( - format!("{flattened_ident}[{index}]"), - ty.element(), - definitions, - extra_indent, - )?; - definitions.add_definition_line(format_args!( - "{extra_indent}connect {retval}[{index}], {element_value}" - )); - } - Ok(retval.to_string()) + definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_bits_to_array_exprs, + |definitions, &(ref value_str, ty)| { + let retval = self.module.ns.make_new("_cast_bits_to_array_expr"); + let array_ty = self.type_state.ty(ty)?; + definitions + .add_definition_line(format_args!("{extra_indent}wire {retval}: {array_ty}")); + let element_bit_width = ty.element().bit_width(); + if ty.is_empty() || element_bit_width == 0 { + definitions + .add_definition_line(format_args!("{extra_indent}invalidate {retval}")); + return Ok(retval.to_string()); + } + let flattened_ident = self + .module + .ns + .make_new("_cast_bits_to_array_expr_flattened"); + definitions.add_definition_line(format_args!( + "{extra_indent}wire {flattened_ident}: UInt<{element_bit_width}>[{}]", + ty.len(), + )); + for index in 0..ty.len() { + definitions.add_definition_line(format_args!( + "{extra_indent}connect {flattened_ident}[{index}], \ + bits({value_str}, {}, {})", + element_bit_width * index + element_bit_width - 1, + element_bit_width * index, + )); + let element_value = self.expr_cast_bits_to( + format!("{flattened_ident}[{index}]"), + ty.element(), + &definitions, + extra_indent, + )?; + definitions.add_definition_line(format_args!( + "{extra_indent}connect {retval}[{index}], {element_value}" + )); + } + Ok(retval.to_string()) + }, + ) } fn expr_cast_bits_to( &mut self, value_str: String, ty: CanonicalType, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, extra_indent: Indent<'_>, ) -> Result { - match ty { + match ty.unwrap_transparent_types() { CanonicalType::Bundle(ty) => { self.expr_cast_bits_to_bundle(value_str, ty, definitions, extra_indent) } @@ -1424,20 +1584,27 @@ impl<'a> Exporter<'a> { CanonicalType::AsyncReset(_) => Ok(format!("asAsyncReset({value_str})")), CanonicalType::SyncReset(_) => Ok(value_str), CanonicalType::Reset(_) => unreachable!("Reset is not bit castable to"), - CanonicalType::PhantomConst(_) => { - let retval = self.module.ns.make_new("_cast_bits_to_phantom_const_expr"); - definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {{}}")); - definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); - } + CanonicalType::PhantomConst(ty) => definitions.get_or_write_definition( + (value_str, ty), + |c| &c.cast_bits_to_phantom_const_exprs, + |definitions, &(ref _value_str, _ty)| { + let retval = self.module.ns.make_new("_cast_bits_to_phantom_const_expr"); + definitions + .add_definition_line(format_args!("{extra_indent}wire {retval}: {{}}")); + definitions + .add_definition_line(format_args!("{extra_indent}invalidate {retval}")); + Ok(retval.to_string()) + }, + ), CanonicalType::DynSimOnly(_) => Err(FirrtlError::SimOnlyValuesAreNotPermitted.into()), + CanonicalType::TraceAsString(_) => unreachable!("handled by unwrap_transparent_types"), } } fn expr_unary( &mut self, func: &str, arg: Expr, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { Ok(format!( @@ -1450,7 +1617,7 @@ impl<'a> Exporter<'a> { func: &str, lhs: Expr, rhs: Expr, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { Ok(format!( @@ -1459,10 +1626,25 @@ impl<'a> Exporter<'a> { rhs = self.expr(Expr::canonical(rhs), definitions, const_ty)?, )) } + fn expr_formal_input(&mut self, formal_input: FormalInput, const_ty: bool) -> Result { + let definitions = self.module.block_definitions.clone(); + definitions.get_or_write_definition( + (formal_input, const_ty), + |c| &c.per_module_formal_inputs, + |definitions, &(formal_input, const_ty)| match formal_input.kind() { + FormalInputKind::FormalGlobalClock => todo!(), + FormalInputKind::FormalReset => todo!(), + FormalInputKind::AnyConst => todo!(), + FormalInputKind::AnySeq => todo!(), + FormalInputKind::AllConst => todo!(), + FormalInputKind::AllSeq => todo!(), + }, + ) + } fn expr( &mut self, expr: Expr, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, const_ty: bool, ) -> Result { match *Expr::expr_enum(expr) { @@ -1798,6 +1980,10 @@ impl<'a> Exporter<'a> { write!(out, "[{index}]").unwrap(); Ok(out) } + ExprEnum::ToTraceAsString(expr) => self.expr(expr.inner(), definitions, const_ty), + ExprEnum::TraceAsStringAsInner(expr) => { + self.expr(Expr::canonical(expr.arg()), definitions, const_ty) + } ExprEnum::ModuleIO(expr) => Ok(self.module.ns.get(expr.name_id()).to_string()), ExprEnum::Instance(expr) => { assert!(!const_ty, "not a constant"); @@ -1825,6 +2011,7 @@ impl<'a> Exporter<'a> { let port_name = Ident::from(expr.port_name()); Ok(format!("{mem_name}.{port_name}")) } + ExprEnum::FormalInput(expr) => self.expr_formal_input(expr.formal_input(), const_ty), } } fn write_mem_init( @@ -1939,6 +2126,7 @@ impl<'a> Exporter<'a> { TargetBase::RegAsync(v) => self.module.ns.get(v.name_id()), TargetBase::Wire(v) => self.module.ns.get(v.name_id()), TargetBase::Instance(v) => self.module.ns.get(v.name_id()), + TargetBase::FormalInput(_) => unreachable!("FormalInput can't be annotated"), }; Ok(AnnotationTargetRef { base, segments }) } @@ -1957,6 +2145,10 @@ impl<'a> Exporter<'a> { .segments .push(AnnotationTargetRefSegment::Index { index }), TargetPathElement::DynArrayElement(_) => unreachable!(), + TargetPathElement::ToTraceAsString(_) + | TargetPathElement::TraceAsStringInner(_) => { + // ignored + } } Ok(retval) } @@ -2050,7 +2242,7 @@ impl<'a> Exporter<'a> { &mut self, stmt_reg: StmtReg, module_name: Ident, - definitions: &RcDefinitions, + definitions: &BlockDefinitions<'_>, body: &mut String, ) -> Result<()> { let StmtReg { annotations, reg } = stmt_reg; @@ -2083,10 +2275,10 @@ impl<'a> Exporter<'a> { module: Interned>, block: Block, _block_indent: &PushIndent<'_>, - definitions: Option, + parent_definitions: &BlockDefinitions, ) -> Result { let indent = self.indent; - let definitions = definitions.unwrap_or_default(); + let mut definitions = BlockDefinitions::new(parent_definitions); let mut body = String::new(); let mut out = String::new(); let Block { memories, stmts } = block; @@ -2163,7 +2355,7 @@ impl<'a> Exporter<'a> { .unwrap(); pushed_indent = indent.push(); let then_block_str = - self.block(module, then_block, &pushed_indent, None)?; + self.block(module, then_block, &pushed_indent, &definitions)?; if !then_block_str.is_empty() { body.push_str(&then_block_str); } else { @@ -2181,7 +2373,8 @@ impl<'a> Exporter<'a> { break; } } - let else_block = self.block(module, else_block, &pushed_indent, None)?; + let else_block = + self.block(module, else_block, &pushed_indent, &definitions)?; drop(pushed_indent); if !else_block.is_empty() { writeln!(body, "{indent}else:").unwrap(); @@ -2224,7 +2417,8 @@ impl<'a> Exporter<'a> { }; body.push_str(":\n"); let match_arm_indent = indent.push(); - let block = self.block(module, match_arm_block, &match_arm_indent, None)?; + let block = + self.block(module, match_arm_block, &match_arm_indent, &definitions)?; if !block.is_empty() { body.push_str(&block); } else { @@ -2274,7 +2468,7 @@ impl<'a> Exporter<'a> { .unwrap(); } } - definitions.write_and_clear(indent, &mut out); + definitions.write_out(indent, &mut out); out.push_str(&body); body.clear(); } @@ -2282,6 +2476,7 @@ impl<'a> Exporter<'a> { } fn module(&mut self, module: Interned>) -> Result { self.module = ModuleState::default(); + let module_definitions = self.module.block_definitions.clone(); let indent = self.indent; let module_name = self.global_ns.get(module.name_id()); let mut body = String::new(); @@ -2350,12 +2545,10 @@ impl<'a> Exporter<'a> { "extmodule" } ModuleBody::Normal(NormalModuleBody { body: top_block }) => { - body.push_str(&self.block( - module, - top_block, - &module_indent, - Some(self.module.definitions.clone()), - )?); + let body_str = + self.block(module, top_block, &module_indent, &module_definitions)?; + module_definitions.write_out(indent, &mut body); + body.push_str(&body_str); "module" } }; @@ -3211,6 +3404,8 @@ impl ScalarizeTreeNode { TargetPathElement::DynArrayElement(_) => { unreachable!("annotations are only on static targets"); } + TargetPathElement::ToTraceAsString(_) + | TargetPathElement::TraceAsStringInner(_) => parent, } } } @@ -3337,6 +3532,13 @@ impl ScalarizeTreeBuilder { CanonicalType::DynSimOnly(_) => { return Err(ScalarizedModuleABIError::SimOnlyValuesAreNotPermitted); } + CanonicalType::TraceAsString(_) => self.build( + target + .join(TargetPathElement::intern_sized( + TargetPathTraceAsStringInner {}.into(), + )) + .intern_sized(), + )?, }) } } diff --git a/crates/fayalite/src/formal.rs b/crates/fayalite/src/formal.rs index 17d3122..850972a 100644 --- a/crates/fayalite/src/formal.rs +++ b/crates/fayalite/src/formal.rs @@ -1,11 +1,195 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ + expr::target::{GetTarget, Target}, int::BoolOrIntType, intern::{Intern, Interned, Memoize}, + module::{NameId, NameIdOrGlobal, ScopedNameId}, prelude::*, }; -use std::sync::OnceLock; +use std::{fmt, sync::OnceLock}; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum FormalInputKind { + FormalGlobalClock, + FormalReset, + AnyConst, + AnySeq, + AllConst, + AllSeq, +} + +impl FormalInputKind { + pub fn fixed_ty(self) -> Option { + match self { + Self::FormalGlobalClock => Some(Clock.into()), + Self::FormalReset => Some(SyncReset.into()), + Self::AnyConst => None, + Self::AnySeq => None, + Self::AllConst => None, + Self::AllSeq => None, + } + } + pub fn fixed_id(self) -> Option { + struct Cache { + formal_global_clock: crate::module::Id, + formal_reset: crate::module::Id, + } + static CACHE: OnceLock = OnceLock::new(); + let cache = || { + CACHE.get_or_init( + #[cold] + || Cache { + formal_global_clock: crate::module::Id::new(), + formal_reset: crate::module::Id::new(), + }, + ) + }; + match self { + Self::FormalGlobalClock => Some(cache().formal_global_clock), + Self::FormalReset => Some(cache().formal_reset), + Self::AnyConst => None, + Self::AnySeq => None, + Self::AllConst => None, + Self::AllSeq => None, + } + } + pub fn fixed_source_location(self) -> Option { + match self { + Self::FormalGlobalClock | Self::FormalReset => Some(SourceLocation::builtin()), + Self::AnyConst | Self::AnySeq | Self::AllConst | Self::AllSeq => None, + } + } + pub fn name(self) -> &'static str { + match self { + Self::FormalGlobalClock => "formal_global_clock", + Self::FormalReset => "formal_reset", + Self::AnyConst => "any_const", + Self::AnySeq => "any_seq", + Self::AllConst => "all_const", + Self::AllSeq => "all_seq", + } + } + pub fn interned_name(self) -> Interned { + macro_rules! impl_interned_name { + ($($variant:ident,)*) => { + match self { + $(Self::$variant => { + static CACHE: OnceLock> = OnceLock::new(); + *CACHE.get_or_init(|| Self::$variant.name().intern()) + })* + } + }; + } + impl_interned_name! { + FormalGlobalClock, + FormalReset, + AnyConst, + AnySeq, + AllConst, + AllSeq, + } + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +struct FormalInputData { + kind: FormalInputKind, + name_id: NameId, + ty: CanonicalType, + source_location: SourceLocation, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct FormalInput(Interned); + +impl fmt::Debug for FormalInput { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.kind().fixed_ty().is_some() { + f.write_str(&self.name()) + } else { + f.debug_tuple(&self.name()).field(&self.0.ty).finish() + } + } +} + +impl FormalInput { + #[track_caller] + pub fn new( + kind: FormalInputKind, + name_id: NameId, + ty: CanonicalType, + source_location: SourceLocation, + ) -> Self { + let NameId(name, id) = name_id; + assert_eq!(kind.interned_name(), name); + if let Some(fixed_ty) = kind.fixed_ty() { + assert_eq!(ty, fixed_ty); + } else { + assert!( + ty.is_castable_from_bits(), + "{name} type must be castable from bits. got:\n{ty:#?}", + ); + } + if let Some(fixed_source_location) = kind.fixed_source_location() { + assert_eq!(source_location, fixed_source_location); + } + if let Some(fixed_id) = kind.fixed_id() { + assert_eq!(id, fixed_id); + } + Self( + FormalInputData { + kind, + name_id, + ty, + source_location, + } + .intern_sized(), + ) + } + pub fn kind(self) -> FormalInputKind { + self.0.kind + } + pub fn name(self) -> Interned { + self.0.name_id.0 + } + pub fn name_id(self) -> NameId { + self.0.name_id + } + pub fn scoped_name(self) -> ScopedNameId { + ScopedNameId(NameIdOrGlobal::Global, self.name_id()) + } + pub fn source_location(self) -> SourceLocation { + self.0.source_location + } + pub(crate) fn must_connect_to(self) -> bool { + false + } + pub(crate) fn flow(self) -> crate::expr::Flow { + crate::expr::Flow::Source + } +} + +impl ValueType for FormalInput { + type Type = CanonicalType; + type ValueCategory = crate::expr::value_category::ValueCategoryExpr; + + fn ty(&self) -> Self::Type { + self.0.ty + } +} + +impl ToExpr for FormalInput { + fn to_expr(&self) -> Expr { + crate::expr::ops::FormalInputExpr::new(*self).to_expr() + } +} + +impl GetTarget for FormalInput { + fn target(&self) -> Option> { + Some(Target::from(*self).intern_sized()) + } +} #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum FormalKind { diff --git a/crates/fayalite/src/int.rs b/crates/fayalite/src/int.rs index ff20933..15f8ed1 100644 --- a/crates/fayalite/src/int.rs +++ b/crates/fayalite/src/int.rs @@ -1277,6 +1277,9 @@ macro_rules! impl_int { pub fn bitvec_mut(&mut self) -> &mut BitVec { Arc::make_mut(&mut self.bits) } + pub fn arc_bitvec_mut(&mut self) -> &mut Arc { + &mut self.bits + } } }; } diff --git a/crates/fayalite/src/memory.rs b/crates/fayalite/src/memory.rs index 83e7437..b3af13c 100644 --- a/crates/fayalite/src/memory.rs +++ b/crates/fayalite/src/memory.rs @@ -1093,6 +1093,7 @@ pub fn splat_mask(ty: T, value: Expr) -> Expr> { .to_expr(), )), CanonicalType::PhantomConst(_) => Expr::from_canonical(Expr::canonical(().to_expr())), + CanonicalType::TraceAsString(ty) => Expr::from_canonical(splat_mask(ty.inner_ty(), value)), } } diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index d959182..ecb910d 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -8,7 +8,7 @@ use crate::{ clock::{Clock, ClockDomain}, enum_::{Enum, EnumMatchVariantsIter, EnumType}, expr::{ - Expr, Flow, ToExpr, ValueType, + Expr, ExprEnum, Flow, ToExpr, ValueType, ops::VariantAccess, target::{ GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, @@ -20,6 +20,7 @@ use crate::{ int::{Bool, DynSize, Size}, intern::{Intern, Interned}, memory::{Mem, MemBuilder, MemBuilderTarget, PortName}, + module::transform::visit::{Visit, Visitor}, platform::PlatformIOBuilder, reg::Reg, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, @@ -726,7 +727,57 @@ impl fmt::Display for NameId { } #[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct ScopedNameId(pub NameId, pub NameId); +pub enum NameIdOrGlobal { + Global, + NameId(NameId), +} + +impl NameIdOrGlobal { + pub fn name_id(self) -> Option { + match self { + Self::Global => None, + Self::NameId(v) => Some(v), + } + } + #[track_caller] + pub fn assert_is_name_id(self) { + match self { + Self::Global => panic!("expected a NameId, got NameIdOrGlobal::Global"), + Self::NameId(_) => {} + } + } + #[track_caller] + pub fn unwrap_name_id(self) -> NameId { + match self { + Self::Global => panic!("expected a NameId, got NameIdOrGlobal::Global"), + Self::NameId(v) => v, + } + } +} + +impl fmt::Debug for NameIdOrGlobal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl fmt::Display for NameIdOrGlobal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Global => f.write_str("<>"), + Self::NameId(name_id) => fmt::Display::fmt(name_id, f), + } + } +} + +impl From for NameIdOrGlobal { + fn from(value: NameId) -> Self { + Self::NameId(value) + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct ScopedNameId(pub NameIdOrGlobal, pub NameId); impl fmt::Debug for ScopedNameId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -804,7 +855,7 @@ impl Instance { self.containing_module_name_id().0 } pub fn containing_module_name_id(self) -> NameId { - self.scoped_name.0 + self.scoped_name.0.unwrap_name_id() } pub fn name(self) -> Interned { self.name_id().0 @@ -821,11 +872,13 @@ impl Instance { pub fn source_location(self) -> SourceLocation { self.source_location } + #[track_caller] pub fn new_unchecked( scoped_name: ScopedNameId, instantiated: Interned>, source_location: SourceLocation, ) -> Self { + scoped_name.0.assert_is_name_id(); Self { scoped_name, instantiated, @@ -1111,7 +1164,10 @@ fn validate_clock_for_past( let mut target = clock_for_past; while let Target::Child(child) = target { match *child.path_element() { - TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) => {} + TargetPathElement::BundleField(_) + | TargetPathElement::ArrayElement(_) + | TargetPathElement::ToTraceAsString(_) + | TargetPathElement::TraceAsStringInner(_) => {} TargetPathElement::DynArrayElement(_) => { panic!( "clock_for_past: clock must be a static target (you can't use `Expr` array indexes):\n{clock_for_past:?}" @@ -1535,6 +1591,7 @@ impl TargetState { } } fn new(target: Interned, declared_in_block: usize) -> Self { + let target = Target::unwrap_transparent_types_interned(target); Self { target, inner: match target.canonical_ty() { @@ -1586,14 +1643,62 @@ impl TargetState { declared_in_block, written_in_blocks: RefCell::default(), }, + CanonicalType::TraceAsString(_) => { + unreachable!("handled by Target::unwrap_transparent_types_interned") + } }, } } } +struct VisibleExprsStack { + buf: Vec>, + len: usize, +} + +impl VisibleExprsStack { + fn top(&mut self) -> &mut HashSet { + &mut self.buf[self.len - 1] + } + fn slice(&self) -> &[HashSet] { + &self.buf[..self.len] + } + fn contains(&self, v: &ExprEnum) -> bool { + self.slice().iter().any(|i| i.contains(v)) + } + fn push_empty(&mut self) { + #[cold] + fn push_empty_cold(stack: &mut VisibleExprsStack) { + stack.buf.push(HashSet::default()); + assert_eq!(stack.buf.len(), stack.len) + } + self.len += 1; + if self.len > self.buf.len() { + push_empty_cold(self) + } + } + fn pop(&mut self) { + let Some(new_len) = self.len.checked_sub(1) else { + unreachable!("visible exprs stack underflow"); + }; + self.buf[new_len].clear(); + self.len = new_len; + } +} + +impl Default for VisibleExprsStack { + fn default() -> Self { + Self { + buf: Vec::new(), + len: 0, + } + } +} + struct AssertValidityState { module: Module, blocks: Vec, + visible_exprs: VisibleExprsStack, target_states: HashMap, TargetState>, } @@ -1605,44 +1710,59 @@ impl AssertValidityState { } fn get_target_states<'a>( &'a self, - target: &Target, + target: Target, process_target_state: &dyn Fn(&'a TargetState, bool), ) -> Result<(), ()> { - match target { - Target::Base(target_base) => { - let target_state = self.get_base_state(*target_base)?; - process_target_state(target_state, false); - Ok(()) - } - Target::Child(target_child) => self.get_target_states( - &target_child.parent(), - &|target_state, exact_target_unknown| { - let TargetStateInner::Decomposed { subtargets } = &target_state.inner else { - unreachable!( - "TargetState::new makes TargetState tree match the Target type" - ); - }; - match *target_child.path_element() { - TargetPathElement::BundleField(_) => process_target_state( - subtargets - .get(&target_child.path_element()) - .expect("bundle fields filled in by TargetState::new"), - exact_target_unknown, - ), - TargetPathElement::ArrayElement(_) => process_target_state( - subtargets - .get(&target_child.path_element()) - .expect("array elements filled in by TargetState::new"), - exact_target_unknown, - ), - TargetPathElement::DynArrayElement(_) => { - for target_state in subtargets.values() { - process_target_state(target_state, true); + let mut target = target.unwrap_transparent_types(); + loop { + break match target { + Target::Base(target_base) => { + let target_state = self.get_base_state(target_base)?; + process_target_state(target_state, false); + Ok(()) + } + Target::Child(target_child) => match *target_child.path_element() { + TargetPathElement::BundleField(_) + | TargetPathElement::ArrayElement(_) + | TargetPathElement::DynArrayElement(_) => self.get_target_states( + *target_child.parent(), + &|target_state, exact_target_unknown| { + let TargetStateInner::Decomposed { subtargets } = &target_state.inner + else { + unreachable!( + "TargetState::new makes TargetState tree match the Target type" + ); + }; + match *target_child.path_element() { + TargetPathElement::BundleField(_) => process_target_state( + subtargets + .get(&target_child.path_element()) + .expect("bundle fields filled in by TargetState::new"), + exact_target_unknown, + ), + TargetPathElement::ArrayElement(_) => process_target_state( + subtargets + .get(&target_child.path_element()) + .expect("array elements filled in by TargetState::new"), + exact_target_unknown, + ), + TargetPathElement::DynArrayElement(_) => { + for target_state in subtargets.values() { + process_target_state(target_state, true); + } + } + TargetPathElement::TraceAsStringInner(_) + | TargetPathElement::ToTraceAsString(_) => unreachable!(), } - } + }, + ), + TargetPathElement::TraceAsStringInner(_) + | TargetPathElement::ToTraceAsString(_) => { + target = *target_child.parent(); + continue; } }, - ), + }; } } fn get_base_state(&self, target_base: Interned) -> Result<&TargetState, ()> { @@ -1693,6 +1813,7 @@ impl AssertValidityState { &TargetPathElement::BundleField(_) => { let field = sub_target_state .target + .without_trailing_transparent_path_elements() .child() .expect("known to be a child") .bundle_field() @@ -1716,6 +1837,8 @@ impl AssertValidityState { TargetPathElement::DynArrayElement { .. } => { Self::set_connect_target_written(sub_target_state, is_lhs, block, true); } + TargetPathElement::TraceAsStringInner(_) + | TargetPathElement::ToTraceAsString(_) => unreachable!("never added"), } } } @@ -1733,7 +1856,7 @@ impl AssertValidityState { debug_assert!(!is_lhs, "the ModuleBuilder asserts lhs.target().is_some()"); return; }; - let result = self.get_target_states(&target, &|target_state, exact_target_unknown| { + let result = self.get_target_states(*target, &|target_state, exact_target_unknown| { Self::set_connect_target_written(target_state, is_lhs, block, exact_target_unknown); }); if result.is_err() { @@ -1746,6 +1869,7 @@ impl AssertValidityState { } } } + #[track_caller] fn process_conditional_sub_blocks( &mut self, parent_block: usize, @@ -1759,17 +1883,40 @@ impl AssertValidityState { } } #[track_caller] + fn assert_expr_validity(&mut self, expr: Expr, source_location: SourceLocation) { + let mut visitor = AssertExprValidity { state: self }; + match visitor.visit_expr(&expr) { + Ok(()) => {} + Err(e) => match e { + InvalidExpr::ExprIsNotVisible(expr) => { + if let Some(target) = expr.target() { + panic!( + "at {source_location}: expression isn't visible here, it's defined:\n\ + at {}: {expr:?}", + target.base().source_location(), + ); + } else { + panic!("at {source_location}: expression isn't visible here: {expr:?}"); + } + } + }, + } + } + #[track_caller] fn assert_subtree_validity(&mut self, block: usize) { + self.visible_exprs.push_empty(); let module = self.module; if block == 0 { for module_io in &*module.module_io { self.insert_new_base(TargetBase::intern_sized(module_io.module_io.into()), block); + self.visible_exprs.top().insert(module_io.module_io.into()); } } let Block { memories, stmts } = self.blocks[block]; for m in memories { for port in m.ports() { self.insert_new_base(TargetBase::intern_sized(port.into()), block); + self.visible_exprs.top().insert(port.into()); } } for stmt in stmts { @@ -1783,44 +1930,104 @@ impl AssertValidityState { } = connect; self.set_connect_side_written(lhs, source_location, true, block); self.set_connect_side_written(rhs, source_location, false, block); + self.assert_expr_validity(lhs, source_location); + self.assert_expr_validity(rhs, source_location); + } + Stmt::Formal(formal) => { + let StmtFormal { + kind: _, + clk, + pred, + en, + text: _, + source_location, + } = formal; + self.assert_expr_validity(clk, source_location); + self.assert_expr_validity(pred, source_location); + self.assert_expr_validity(en, source_location); } - Stmt::Formal(_) => {} Stmt::If(if_stmt) => { - let sub_blocks = if_stmt.blocks.map(|block| self.make_block_index(block)); + let StmtIf { + cond, + source_location, + blocks: sub_blocks, + } = if_stmt; + self.assert_expr_validity(cond, source_location); + let sub_blocks = sub_blocks.map(|block| self.make_block_index(block)); self.process_conditional_sub_blocks(block, sub_blocks) } Stmt::Match(match_stmt) => { match_stmt.assert_validity(); + let StmtMatch { + expr, + source_location, + blocks: sub_blocks, + } = match_stmt; + self.assert_expr_validity(expr, source_location); let sub_blocks = Vec::from_iter( - match_stmt - .blocks + sub_blocks .into_iter() .map(|block| self.make_block_index(block)), ); - self.process_conditional_sub_blocks(block, sub_blocks.iter().copied()) + self.visible_exprs.push_empty(); + let visible_exprs_top = self.visible_exprs.top(); + for variant_index in 0..expr.ty().variants().len() { + visible_exprs_top + .insert(::new_by_index(expr, variant_index).into()); + } + self.process_conditional_sub_blocks(block, sub_blocks.iter().copied()); + self.visible_exprs.pop(); } Stmt::Declaration(StmtDeclaration::Wire(StmtWire { annotations: _, wire, - })) => self.insert_new_base(TargetBase::intern_sized(wire.into()), block), + })) => { + self.insert_new_base(TargetBase::intern_sized(wire.into()), block); + self.visible_exprs.top().insert(wire.into()); + } Stmt::Declaration(StmtDeclaration::Reg(StmtReg { annotations: _, reg, - })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), + })) => { + self.assert_expr_validity(reg.clock_domain(), reg.source_location()); + if let Some(init) = reg.init() { + self.assert_expr_validity(init, reg.source_location()); + } + self.insert_new_base(TargetBase::intern_sized(reg.into()), block); + self.visible_exprs.top().insert(reg.into()); + } Stmt::Declaration(StmtDeclaration::RegSync(StmtReg { annotations: _, reg, - })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), + })) => { + self.assert_expr_validity(reg.clock_domain(), reg.source_location()); + if let Some(init) = reg.init() { + self.assert_expr_validity(init, reg.source_location()); + } + self.insert_new_base(TargetBase::intern_sized(reg.into()), block); + self.visible_exprs.top().insert(reg.into()); + } Stmt::Declaration(StmtDeclaration::RegAsync(StmtReg { annotations: _, reg, - })) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block), + })) => { + self.assert_expr_validity(reg.clock_domain(), reg.source_location()); + if let Some(init) = reg.init() { + self.assert_expr_validity(init, reg.source_location()); + } + self.insert_new_base(TargetBase::intern_sized(reg.into()), block); + self.visible_exprs.top().insert(reg.into()); + } Stmt::Declaration(StmtDeclaration::Instance(StmtInstance { annotations: _, instance, - })) => self.insert_new_base(TargetBase::intern_sized(instance.into()), block), + })) => { + self.insert_new_base(TargetBase::intern_sized(instance.into()), block); + self.visible_exprs.top().insert(instance.into()); + } } } + self.visible_exprs.pop(); } #[track_caller] fn assert_validity(&mut self) { @@ -1849,6 +2056,141 @@ impl AssertValidityState { } } +struct AssertExprValidity<'a> { + state: &'a mut AssertValidityState, +} + +enum InvalidExpr { + ExprIsNotVisible(Expr), +} + +impl transform::visit::Visitor for AssertExprValidity<'_> { + type Error = InvalidExpr; + fn visit_expr_enum(&mut self, v: &ExprEnum) -> Result<(), Self::Error> { + match v { + ExprEnum::UIntLiteral(_) + | ExprEnum::SIntLiteral(_) + | ExprEnum::BoolLiteral(_) + | ExprEnum::PhantomConst(_) + | ExprEnum::BundleLiteral(_) + | ExprEnum::ArrayLiteral(_) + | ExprEnum::EnumLiteral(_) + | ExprEnum::Uninit(_) + | ExprEnum::NotU(_) + | ExprEnum::NotS(_) + | ExprEnum::NotB(_) + | ExprEnum::Neg(_) + | ExprEnum::BitAndU(_) + | ExprEnum::BitAndS(_) + | ExprEnum::BitAndB(_) + | ExprEnum::BitOrU(_) + | ExprEnum::BitOrS(_) + | ExprEnum::BitOrB(_) + | ExprEnum::BitXorU(_) + | ExprEnum::BitXorS(_) + | ExprEnum::BitXorB(_) + | ExprEnum::AddU(_) + | ExprEnum::AddS(_) + | ExprEnum::SubU(_) + | ExprEnum::SubS(_) + | ExprEnum::MulU(_) + | ExprEnum::MulS(_) + | ExprEnum::DivU(_) + | ExprEnum::DivS(_) + | ExprEnum::RemU(_) + | ExprEnum::RemS(_) + | ExprEnum::DynShlU(_) + | ExprEnum::DynShlS(_) + | ExprEnum::DynShrU(_) + | ExprEnum::DynShrS(_) + | ExprEnum::FixedShlU(_) + | ExprEnum::FixedShlS(_) + | ExprEnum::FixedShrU(_) + | ExprEnum::FixedShrS(_) + | ExprEnum::CmpLtB(_) + | ExprEnum::CmpLeB(_) + | ExprEnum::CmpGtB(_) + | ExprEnum::CmpGeB(_) + | ExprEnum::CmpEqB(_) + | ExprEnum::CmpNeB(_) + | ExprEnum::CmpLtU(_) + | ExprEnum::CmpLeU(_) + | ExprEnum::CmpGtU(_) + | ExprEnum::CmpGeU(_) + | ExprEnum::CmpEqU(_) + | ExprEnum::CmpNeU(_) + | ExprEnum::CmpLtS(_) + | ExprEnum::CmpLeS(_) + | ExprEnum::CmpGtS(_) + | ExprEnum::CmpGeS(_) + | ExprEnum::CmpEqS(_) + | ExprEnum::CmpNeS(_) + | ExprEnum::CastUIntToUInt(_) + | ExprEnum::CastUIntToSInt(_) + | ExprEnum::CastSIntToUInt(_) + | ExprEnum::CastSIntToSInt(_) + | ExprEnum::CastBoolToUInt(_) + | ExprEnum::CastBoolToSInt(_) + | ExprEnum::CastUIntToBool(_) + | ExprEnum::CastSIntToBool(_) + | ExprEnum::CastBoolToSyncReset(_) + | ExprEnum::CastUIntToSyncReset(_) + | ExprEnum::CastSIntToSyncReset(_) + | ExprEnum::CastBoolToAsyncReset(_) + | ExprEnum::CastUIntToAsyncReset(_) + | ExprEnum::CastSIntToAsyncReset(_) + | ExprEnum::CastSyncResetToBool(_) + | ExprEnum::CastSyncResetToUInt(_) + | ExprEnum::CastSyncResetToSInt(_) + | ExprEnum::CastSyncResetToReset(_) + | ExprEnum::CastAsyncResetToBool(_) + | ExprEnum::CastAsyncResetToUInt(_) + | ExprEnum::CastAsyncResetToSInt(_) + | ExprEnum::CastAsyncResetToReset(_) + | ExprEnum::CastResetToBool(_) + | ExprEnum::CastResetToUInt(_) + | ExprEnum::CastResetToSInt(_) + | ExprEnum::CastBoolToClock(_) + | ExprEnum::CastUIntToClock(_) + | ExprEnum::CastSIntToClock(_) + | ExprEnum::CastClockToBool(_) + | ExprEnum::CastClockToUInt(_) + | ExprEnum::CastClockToSInt(_) + | ExprEnum::FieldAccess(_) + | ExprEnum::ArrayIndex(_) + | ExprEnum::DynArrayIndex(_) + | ExprEnum::ReduceBitAndU(_) + | ExprEnum::ReduceBitAndS(_) + | ExprEnum::ReduceBitOrU(_) + | ExprEnum::ReduceBitOrS(_) + | ExprEnum::ReduceBitXorU(_) + | ExprEnum::ReduceBitXorS(_) + | ExprEnum::SliceUInt(_) + | ExprEnum::SliceSInt(_) + | ExprEnum::CastToBits(_) + | ExprEnum::CastBitsTo(_) + | ExprEnum::ToTraceAsString(_) + | ExprEnum::TraceAsStringAsInner(_) + | ExprEnum::FormalInput(_) => v.default_visit(self), + ExprEnum::VariantAccess(_) + | ExprEnum::ModuleIO(_) + | ExprEnum::Instance(_) + | ExprEnum::Wire(_) + | ExprEnum::Reg(_) + | ExprEnum::RegSync(_) + | ExprEnum::RegAsync(_) + | ExprEnum::MemPort(_) => { + if self.state.visible_exprs.contains(v) { + // no need to visit inner expressions, we already checked them before adding them to visible_exprs + Ok(()) + } else { + Err(InvalidExpr::ExprIsNotVisible(v.to_expr())) + } + } + } + } +} + impl Module { /// you generally should use the [`#[hdl_module]`][`crate::hdl_module`] proc-macro and [`ModuleBuilder`] instead #[track_caller] @@ -1974,6 +2316,7 @@ impl Module { AssertValidityState { module: self.canonical(), blocks: vec![], + visible_exprs: VisibleExprsStack::default(), target_states: HashMap::with_capacity_and_hasher(64, Default::default()), } .assert_validity(); @@ -2079,7 +2422,7 @@ impl RegBuilder>, Option>, T> ty, } = self; ModuleBuilder::with(|module_builder| { - let scoped_name = ScopedNameId(module_builder.name, NameId(name, Id::new())); + let scoped_name = ScopedNameId(module_builder.name.into(), NameId(name, Id::new())); let reg = Reg::new_unchecked(scoped_name, source_location, ty, clock_domain, init); let retval = reg.to_expr(); // convert before borrow_mut since ModuleBuilder could be reentered by T::canonical() @@ -2475,6 +2818,7 @@ pub fn annotate(target: Expr, annotations: impl IntoAnnotations) { instance, } .into(), + TargetBase::FormalInput(_) => panic!("not a valid annotation target"), }; ModuleBuilder::with(|m| { unwrap!(m.impl_.borrow_mut().body.builder_normal_body_opt()) @@ -2489,7 +2833,7 @@ pub fn annotate(target: Expr, annotations: impl IntoAnnotations) { #[track_caller] pub fn wire_with_loc(name: &str, source_location: SourceLocation, ty: T) -> Expr { ModuleBuilder::with(|m| { - let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new())); + let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new())); let wire = Wire::::new_unchecked(scoped_name, source_location, ty); let retval = wire.to_expr(); let canonical_wire = wire.canonical(); @@ -2521,7 +2865,7 @@ fn incomplete_declaration( source_location: SourceLocation, ) -> Rc> { ModuleBuilder::with(|m| { - let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new())); + let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new())); let retval = Rc::new(RefCell::new(IncompleteDeclaration::Incomplete { name: scoped_name, source_location, @@ -2697,7 +3041,7 @@ pub fn instance_with_loc( source_location: SourceLocation, ) -> Expr { ModuleBuilder::with(|m| { - let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new())); + let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new())); let instance = Instance:: { scoped_name, instantiated, @@ -2736,7 +3080,7 @@ fn memory_impl( source_location: SourceLocation, ) -> MemBuilder { ModuleBuilder::with(|m| { - let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new())); + let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new())); let (retval, target_mem) = MemBuilder::new(scoped_name, source_location, mem_element_type); let mut impl_ = m.impl_.borrow_mut(); let body = impl_.body.builder_normal_body(); @@ -2891,7 +3235,7 @@ impl ModuleIO { NameId(self.bundle_field.name, self.id) } pub fn scoped_name(&self) -> ScopedNameId { - ScopedNameId(self.containing_module_name, self.name_id()) + ScopedNameId(self.containing_module_name.into(), self.name_id()) } pub fn source_location(&self) -> SourceLocation { self.source_location diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs index 61167fd..7141de9 100644 --- a/crates/fayalite/src/module/transform/deduce_resets.rs +++ b/crates/fayalite/src/module/transform/deduce_resets.rs @@ -10,7 +10,8 @@ use crate::{ ops::{self, ArrayLiteral}, target::{ Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, - TargetPathDynArrayElement, TargetPathElement, + TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString, + TargetPathTraceAsStringInner, }, }, formal::FormalKind, @@ -26,6 +27,7 @@ use crate::{ prelude::*, reset::{ResetType, ResetTypeDispatch}, sim::ExternModuleSimulation, + ty::TraceAsString, util::{HashMap, HashSet}, }; use hashbrown::hash_map::Entry; @@ -103,6 +105,10 @@ enum ResetsLayout { element: Interned, reset_count: usize, }, + Transparent { + inner: Interned, + reset_count: usize, + }, } impl ResetsLayout { @@ -112,7 +118,8 @@ impl ResetsLayout { ResetsLayout::Reset | ResetsLayout::SyncReset | ResetsLayout::AsyncReset => 1, ResetsLayout::Bundle { reset_count, .. } | ResetsLayout::Enum { reset_count, .. } - | ResetsLayout::Array { reset_count, .. } => reset_count, + | ResetsLayout::Array { reset_count, .. } + | ResetsLayout::Transparent { reset_count, .. } => reset_count, } } fn new(ty: CanonicalType) -> Self { @@ -166,6 +173,13 @@ impl ResetsLayout { CanonicalType::Clock(_) => ResetsLayout::NoResets, CanonicalType::PhantomConst(_) => ResetsLayout::NoResets, CanonicalType::DynSimOnly(_) => ResetsLayout::NoResets, + CanonicalType::TraceAsString(ty) => { + let inner = ResetsLayout::new(ty.inner_ty()).intern_sized(); + ResetsLayout::Transparent { + inner, + reset_count: inner.reset_count(), + } + } } } } @@ -315,6 +329,12 @@ impl ResetGraph { } => { self.append_new_nodes_for_layout(*element, node_indexes, source_location); } + ResetsLayout::Transparent { + inner, + reset_count: _, + } => { + self.append_new_nodes_for_layout(*inner, node_indexes, source_location); + } } } } @@ -357,6 +377,21 @@ impl Resets { node_indexes: self.node_indexes, } } + fn trace_as_string_inner(self) -> Self { + let trace_as_string = TraceAsString::from_canonical(self.ty); + let ResetsLayout::Transparent { + inner, + reset_count: _, + } = self.layout + else { + unreachable!(); + }; + Self { + ty: trace_as_string.inner_ty(), + layout: *inner, + node_indexes: self.node_indexes, + } + } fn bundle_fields(self) -> impl Iterator { let bundle = Bundle::from_canonical(self.ty); let ResetsLayout::Bundle { @@ -480,6 +515,17 @@ impl Resets { CanonicalType::SyncReset(SyncReset) }, ), + CanonicalType::TraceAsString(ty) => Ok(CanonicalType::TraceAsString( + ty.with_new_inner_ty( + self.array_elements() + .substituted_type( + reset_graph, + fallback_to_sync_reset, + fallback_error_source_location, + )? + .intern_sized(), + ), + )), } } } @@ -1013,7 +1059,8 @@ fn cast_bit_op( | CanonicalType::Bundle(_) | CanonicalType::Reset(_) | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => unreachable!(), + | CanonicalType::DynSimOnly(_) + | CanonicalType::TraceAsString(_) => unreachable!(), $(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)* } }; @@ -1024,7 +1071,8 @@ fn cast_bit_op( CanonicalType::Array(_) | CanonicalType::Enum(_) | CanonicalType::Bundle(_) - | CanonicalType::Reset(_) => unreachable!(), + | CanonicalType::Reset(_) + | CanonicalType::TraceAsString(_) => unreachable!(), CanonicalType::PhantomConst(_) | CanonicalType::DynSimOnly(_) => Expr::expr_enum(arg), $(CanonicalType::$Variant(_) => { @@ -1156,6 +1204,10 @@ impl RunPass

for ExprEnum { ExprEnum::SliceSInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::CastToBits(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::CastBitsTo(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), + ExprEnum::TraceAsStringAsInner(expr) => { + Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)) + } + ExprEnum::ToTraceAsString(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::Instance(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), @@ -1163,6 +1215,7 @@ impl RunPass

for ExprEnum { ExprEnum::RegSync(expr) => reg_expr_run_pass(expr, pass_args), ExprEnum::RegAsync(expr) => reg_expr_run_pass(expr, pass_args), ExprEnum::MemPort(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), + ExprEnum::FormalInput(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), } } } @@ -1536,6 +1589,67 @@ impl RunPassExpr for ops::CastBitsTo { } } +impl RunPassExpr for ops::TraceAsStringAsInner { + type Args<'a> = [Expr; 1]; + + fn args<'a>(&'a self) -> Self::Args<'a> { + [Expr::canonical(self.arg())] + } + + fn source_location(&self) -> Option { + None + } + + fn union_parts( + &self, + resets: Resets, + args_resets: Vec, + mut pass_args: PassArgs<'_, BuildResetGraph>, + ) -> Result<(), DeduceResetsError> { + pass_args.union(resets, args_resets[0].trace_as_string_inner(), None) + } + + fn new( + &self, + _ty: CanonicalType, + new_args: Vec>, + ) -> Result { + Ok(Self::new(Expr::from_canonical(new_args[0]))) + } +} + +impl RunPassExpr for ops::ToTraceAsString { + type Args<'a> = [Expr; 1]; + + fn args<'a>(&'a self) -> Self::Args<'a> { + [Expr::canonical(self.inner())] + } + + fn source_location(&self) -> Option { + None + } + + fn union_parts( + &self, + resets: Resets, + args_resets: Vec, + mut pass_args: PassArgs<'_, BuildResetGraph>, + ) -> Result<(), DeduceResetsError> { + pass_args.union(resets.trace_as_string_inner(), args_resets[0], None) + } + + fn new( + &self, + _ty: CanonicalType, + new_args: Vec>, + ) -> Result { + Ok(Self::new( + new_args[0], + self.ty().with_new_inner_ty(new_args[0].ty().intern_sized()), + )) + } +} + impl RunPassExpr for ModuleIO { type Args<'a> = [Expr; 0]; @@ -1691,7 +1805,8 @@ impl RunPassDispatch for AnyReg { | CanonicalType::Reset(_) | CanonicalType::Clock(_) | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => unreachable!(), + | CanonicalType::DynSimOnly(_) + | CanonicalType::TraceAsString(_) => unreachable!(), } }) } @@ -1818,6 +1933,8 @@ impl_run_pass_copy!([] SVAttributeAnnotation); impl_run_pass_copy!([] UInt); impl_run_pass_copy!([] usize); impl_run_pass_copy!([] FormalKind); +impl_run_pass_copy!([] crate::formal::FormalInput); +impl_run_pass_copy!([] ops::FormalInputExpr); impl_run_pass_copy!([] PhantomConst); macro_rules! impl_run_pass_for_struct { @@ -2134,6 +2251,9 @@ impl RunPass

for TargetBase { &TargetBase::RegAsync(v) => v.into(), TargetBase::Wire(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Wire)), TargetBase::Instance(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Instance)), + TargetBase::FormalInput(v) => { + return Ok(v.run_pass(pass_args)?.map(TargetBase::FormalInput)); + } }; Ok(reg.run_pass(pass_args)?.map(|reg| match reg { AnyReg::Reg(reg) => TargetBase::Reg(reg), @@ -2173,30 +2293,6 @@ impl RunPass

for StmtDeclaration { } } -impl_run_pass_for_struct! { - impl[] RunPass for TargetPathBundleField { - name: _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for TargetPathArrayElement { - index: _, - } -} - -impl_run_pass_for_struct! { - impl[] RunPass for TargetPathDynArrayElement {} -} - -impl_run_pass_for_enum! { - impl[] RunPass for TargetPathElement { - BundleField(v), - ArrayElement(v), - DynArrayElement(v), - } -} - impl_run_pass_for_enum! { impl[] RunPass for Target { Base(v), @@ -2204,11 +2300,28 @@ impl_run_pass_for_enum! { } } -impl_run_pass_for_struct! { - #[constructor = TargetChild::new(parent, path_element)] - impl[] RunPass for TargetChild { - parent(): _, - path_element(): _, +impl RunPass

for TargetChild { + fn run_pass( + &self, + mut pass_args: PassArgs<'_, P>, + ) -> Result, DeduceResetsError> { + Ok(self.parent().run_pass(pass_args.as_mut())?.map(|parent| { + let path_element = match *self.path_element() { + TargetPathElement::BundleField(TargetPathBundleField { name: _ }) + | TargetPathElement::ArrayElement(TargetPathArrayElement { index: _ }) + | TargetPathElement::DynArrayElement(TargetPathDynArrayElement {}) + | TargetPathElement::TraceAsStringInner(TargetPathTraceAsStringInner {}) => { + self.path_element() + } + TargetPathElement::ToTraceAsString(TargetPathToTraceAsString { ty }) => { + TargetPathElement::from(TargetPathToTraceAsString { + ty: ty.with_new_inner_ty(parent.canonical_ty().intern_sized()), + }) + .intern_sized() + } + }; + TargetChild::new(parent, path_element) + })) } } diff --git a/crates/fayalite/src/module/transform/simplify_enums.rs b/crates/fayalite/src/module/transform/simplify_enums.rs index 8902921..866402c 100644 --- a/crates/fayalite/src/module/transform/simplify_enums.rs +++ b/crates/fayalite/src/module/transform/simplify_enums.rs @@ -17,7 +17,7 @@ use crate::{ transform::visit::{Fold, Folder}, }, source_location::SourceLocation, - ty::{CanonicalType, Type}, + ty::{CanonicalType, TraceAsString, Type}, util::HashMap, wire::Wire, }; @@ -64,6 +64,7 @@ fn contains_any_enum_types(ty: CanonicalType) -> bool { .fields() .iter() .any(|field| contains_any_enum_types(field.ty)), + CanonicalType::TraceAsString(ty) => contains_any_enum_types(ty.inner_ty()), CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) @@ -95,11 +96,12 @@ enum EnumTypeState { struct ModuleState { module_name: NameId, + expr_cache: HashMap, } impl ModuleState { fn gen_name(&mut self, name: &str) -> ScopedNameId { - ScopedNameId(self.module_name, NameId(name.intern(), Id::new())) + ScopedNameId(self.module_name.into(), NameId(name.intern(), Id::new())) } } @@ -313,6 +315,24 @@ impl State { } Ok(()) } + fn handle_stmt_connect_trace_as_string( + &mut self, + unfolded_lhs_ty: TraceAsString, + unfolded_rhs_ty: TraceAsString, + folded_lhs: Expr, + folded_rhs: Expr, + source_location: SourceLocation, + output_stmts: &mut Vec, + ) -> Result<(), SimplifyEnumsError> { + self.handle_stmt_connect( + unfolded_lhs_ty.inner_ty(), + unfolded_rhs_ty.inner_ty(), + ops::TraceAsStringAsInner::new(folded_lhs).to_expr(), + ops::TraceAsStringAsInner::new(folded_rhs).to_expr(), + source_location, + output_stmts, + ) + } fn handle_stmt_connect_bundle( &mut self, unfolded_lhs_ty: Bundle, @@ -509,6 +529,15 @@ impl State { source_location, output_stmts, ), + CanonicalType::TraceAsString(unfolded_lhs_ty) => self + .handle_stmt_connect_trace_as_string( + unfolded_lhs_ty, + TraceAsString::from_canonical(unfolded_rhs_ty), + Expr::from_canonical(folded_lhs), + Expr::from_canonical(folded_rhs), + source_location, + output_stmts, + ), CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) @@ -528,6 +557,8 @@ fn connect_port( rhs: Expr, source_location: SourceLocation, ) { + let lhs = Expr::unwrap_transparent_types(lhs); + let rhs = Expr::unwrap_transparent_types(rhs); if lhs.ty() == rhs.ty() { stmts.push( StmtConnect { @@ -573,6 +604,9 @@ fn connect_port( connect_port(stmts, lhs[index], rhs[index], source_location); } } + (CanonicalType::TraceAsString(_), CanonicalType::TraceAsString(_)) => { + unreachable!("handled by unwrap_transparent_types") + } (CanonicalType::Bundle(_), _) | (CanonicalType::Enum(_), _) | (CanonicalType::Array(_), _) @@ -584,7 +618,8 @@ fn connect_port( | (CanonicalType::SyncReset(_), _) | (CanonicalType::Reset(_), _) | (CanonicalType::PhantomConst(_), _) - | (CanonicalType::DynSimOnly(_), _) => unreachable!( + | (CanonicalType::DynSimOnly(_), _) + | (CanonicalType::TraceAsString(_), _) => unreachable!( "trying to connect memory ports:\n{:?}\n{:?}", lhs.ty(), rhs.ty(), @@ -641,6 +676,7 @@ impl Folder for State { fn fold_module(&mut self, v: Module) -> Result, Self::Error> { self.module_state_stack.push(ModuleState { module_name: v.name_id(), + expr_cache: HashMap::default(), }); let retval = Fold::default_fold(v, self); self.module_state_stack.pop(); @@ -648,30 +684,39 @@ impl Folder for State { } fn fold_expr_enum(&mut self, op: ExprEnum) -> Result { - match op { + if let Some(folded_op) = self + .module_state_stack + .last() + .expect("known to be in module") + .expr_cache + .get(&op) + { + return Ok(*folded_op); + } + let folded_op = match op { ExprEnum::EnumLiteral(op) => { let folded_variant_value = op.variant_value().map(|v| v.fold(self)).transpose()?; - Ok(*Expr::expr_enum(self.handle_enum_literal( + *Expr::expr_enum(self.handle_enum_literal( op.ty(), op.variant_index(), folded_variant_value, - )?)) + )?) } ExprEnum::VariantAccess(op) => { let folded_base_expr = Expr::canonical(op.base()).fold(self)?; - Ok(*Expr::expr_enum(self.handle_variant_access( + *Expr::expr_enum(self.handle_variant_access( op.base().ty(), folded_base_expr, op.variant_index(), - )?)) + )?) } - ExprEnum::MemPort(mem_port) => Ok( + ExprEnum::MemPort(mem_port) => { if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) { ExprEnum::Wire(wire) } else { ExprEnum::MemPort(mem_port.fold(self)?) - }, - ), + } + } ExprEnum::UIntLiteral(_) | ExprEnum::SIntLiteral(_) | ExprEnum::BoolLiteral(_) @@ -772,13 +817,22 @@ impl Folder for State { | ExprEnum::SliceSInt(_) | ExprEnum::CastToBits(_) | ExprEnum::CastBitsTo(_) + | ExprEnum::TraceAsStringAsInner(_) + | ExprEnum::ToTraceAsString(_) | ExprEnum::ModuleIO(_) | ExprEnum::Instance(_) | ExprEnum::Wire(_) | ExprEnum::Reg(_) | ExprEnum::RegSync(_) - | ExprEnum::RegAsync(_) => op.default_fold(self), - } + | ExprEnum::RegAsync(_) + | ExprEnum::FormalInput(_) => op.default_fold(self)?, + }; + self.module_state_stack + .last_mut() + .expect("known to be in module") + .expr_cache + .insert(op, folded_op); + Ok(folded_op) } fn fold_block(&mut self, block: Block) -> Result { @@ -936,7 +990,8 @@ impl Folder for State { | CanonicalType::SyncReset(_) | CanonicalType::Reset(_) | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => canonical_type.default_fold(self), + | CanonicalType::DynSimOnly(_) + | CanonicalType::TraceAsString(_) => canonical_type.default_fold(self), } } diff --git a/crates/fayalite/src/module/transform/simplify_memories.rs b/crates/fayalite/src/module/transform/simplify_memories.rs index d741836..4a97353 100644 --- a/crates/fayalite/src/module/transform/simplify_memories.rs +++ b/crates/fayalite/src/module/transform/simplify_memories.rs @@ -90,7 +90,7 @@ impl MemSplit { } } fn new(element_type: CanonicalType) -> Self { - match element_type { + match element_type.unwrap_transparent_types() { CanonicalType::Bundle(bundle_ty) => MemSplit::Bundle { fields: bundle_ty .fields() @@ -195,6 +195,7 @@ impl MemSplit { | CanonicalType::SyncReset(_) | CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"), CanonicalType::DynSimOnly(_) => todo!("memory containing sim-only values"), + CanonicalType::TraceAsString(_) => unreachable!("handled by unwrap_transparent_types"), } } } @@ -306,7 +307,9 @@ impl SplitMemState<'_, '_> { let outer_mem_name_path_len = self.mem_name_path.len(); match self.split { MemSplit::Bundle { fields } => { - let CanonicalType::Bundle(bundle_type) = self.element_type else { + let CanonicalType::Bundle(bundle_type) = + self.element_type.unwrap_transparent_types() + else { unreachable!(); }; for ((field, field_offset), split) in bundle_type @@ -321,7 +324,10 @@ impl SplitMemState<'_, '_> { let field_ty_bit_width = field.ty.bit_width(); self.split_state_stack.push_map( |e: Expr| { - Expr::field(Expr::::from_canonical(e), &field.name) + Expr::field( + Expr::::from_canonical(Expr::unwrap_transparent_types(e)), + &field.name, + ) }, |initial_value_element| { let Some(field_offset) = field_offset.only_bit_width() else { @@ -377,8 +383,8 @@ impl SplitMemState<'_, '_> { }; self.output_stmts.push( StmtConnect { - lhs: Expr::field(port_expr, name), - rhs: Expr::field(wire_expr, name), + lhs: Expr::unwrap_transparent_types(Expr::field(port_expr, name)), + rhs: Expr::unwrap_transparent_types(Expr::field(wire_expr, name)), source_location: port.source_location(), } .into(), @@ -389,7 +395,8 @@ impl SplitMemState<'_, '_> { self.output_mems.push(new_mem); } MemSplit::Array { elements } => { - let CanonicalType::Array(array_type) = self.element_type else { + let CanonicalType::Array(array_type) = self.element_type.unwrap_transparent_types() + else { unreachable!(); }; let element_type = array_type.element(); @@ -398,7 +405,7 @@ impl SplitMemState<'_, '_> { self.mem_name_path.truncate(outer_mem_name_path_len); write!(self.mem_name_path, "_{index}").unwrap(); self.split_state_stack.push_map( - |e| Expr::::from_canonical(e)[index], + |e| Expr::::from_canonical(Expr::unwrap_transparent_types(e))[index], |initial_value_element| { &initial_value_element[index * element_bit_width..][..element_bit_width] }, @@ -464,7 +471,7 @@ impl ModuleState { assert_eq!(memory_element_array_range_len % input_array_type.len(), 0); let chunk_size = memory_element_array_range_len / input_array_type.len(); for index in 0..input_array_type.len() { - let map = |e| Expr::::from_canonical(e)[index]; + let map = |e| Expr::::from_canonical(Expr::unwrap_transparent_types(e))[index]; let wire_rdata = wire_rdata.map(map); let wire_wdata = wire_wdata.map(map); let wire_wmask = wire_wmask.map(map); @@ -505,8 +512,8 @@ impl ModuleState { port_read: Expr| { output_stmts.push( StmtConnect { - lhs: wire_read, - rhs: port_read, + lhs: Expr::unwrap_transparent_types(wire_read), + rhs: Expr::unwrap_transparent_types(port_read), source_location, } .into(), @@ -517,8 +524,8 @@ impl ModuleState { port_write: Expr| { output_stmts.push( StmtConnect { - lhs: port_write, - rhs: wire_write, + lhs: Expr::unwrap_transparent_types(port_write), + rhs: Expr::unwrap_transparent_types(wire_write), source_location, } .into(), @@ -530,7 +537,8 @@ impl ModuleState { connect_read( output_stmts, wire_read, - Expr::::from_canonical(port_read).cast_bits_to(wire_read.ty()), + Expr::::from_canonical(Expr::unwrap_transparent_types(port_read)) + .cast_bits_to(wire_read.ty()), ); }; let connect_write_enum = @@ -544,7 +552,7 @@ impl ModuleState { ); }; loop { - match input_element_type { + match input_element_type.unwrap_transparent_types() { CanonicalType::Bundle(_) => { unreachable!("bundle types are always split") } @@ -625,6 +633,9 @@ impl ModuleState { | CanonicalType::SyncReset(_) | CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"), CanonicalType::DynSimOnly(_) => todo!("memory containing sim-only values"), + CanonicalType::TraceAsString(_) => { + unreachable!("handled by unwrap_transparent_types") + } } break; } diff --git a/crates/fayalite/src/module/transform/visit.rs b/crates/fayalite/src/module/transform/visit.rs index 2869a49..1fd22f8 100644 --- a/crates/fayalite/src/module/transform/visit.rs +++ b/crates/fayalite/src/module/transform/visit.rs @@ -14,10 +14,11 @@ use crate::{ Expr, ExprEnum, ValueType, ops, target::{ Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, - TargetPathDynArrayElement, TargetPathElement, + TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString, + TargetPathTraceAsStringInner, }, }, - formal::FormalKind, + formal::{FormalInput, FormalInputKind, FormalKind}, int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue}, intern::{Intern, Interned}, memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite}, @@ -32,7 +33,7 @@ use crate::{ reset::{AsyncReset, Reset, ResetType, SyncReset}, sim::{ExternModuleSimulation, value::DynSimOnly}, source_location::SourceLocation, - ty::{CanonicalType, Type}, + ty::{CanonicalType, TraceAsString, Type}, vendor::xilinx::{ XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation, XilinxAnnotation, }, diff --git a/crates/fayalite/src/prelude.rs b/crates/fayalite/src/prelude.rs index 4c5bfdf..42038ca 100644 --- a/crates/fayalite/src/prelude.rs +++ b/crates/fayalite/src/prelude.rs @@ -13,7 +13,7 @@ pub use crate::{ enum_::{Enum, HdlNone, HdlOption, HdlSome}, expr::{ CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr, - ReduceBits, ToExpr, ValueType, repeat, + ReduceBits, ToExpr, ToTraceAsString, ValueType, repeat, }, formal::{ MakeFormalExpr, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, @@ -38,7 +38,7 @@ pub use crate::{ }, source_location::SourceLocation, testing::{FormalMode, assert_formal}, - ty::{AsMask, CanonicalType, Type}, + ty::{AsMask, CanonicalType, TraceAsString, Type}, util::{ConstUsize, GenericConstUsize}, wire::Wire, }; diff --git a/crates/fayalite/src/reg.rs b/crates/fayalite/src/reg.rs index 7f50655..2e4ab16 100644 --- a/crates/fayalite/src/reg.rs +++ b/crates/fayalite/src/reg.rs @@ -79,6 +79,7 @@ impl Reg { if let Some(init) = init { assert_eq!(ty, init.ty(), "register's type must match init type"); } + scoped_name.0.assert_is_name_id(); Self { name: scoped_name, source_location, @@ -94,7 +95,7 @@ impl Reg { self.containing_module_name_id().0 } pub fn containing_module_name_id(&self) -> NameId { - self.name.0 + self.name.0.unwrap_name_id() } pub fn name(&self) -> Interned { self.name_id().0 diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index b3e4cd6..1247fd8 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -9,6 +9,7 @@ use crate::{ Flow, target::{ GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, + TargetPathTraceAsStringInner, }, }, int::BoolOrIntType, @@ -38,7 +39,7 @@ use crate::{ }, ty::{ OpaqueSimValue, OpaqueSimValueSize, OpaqueSimValueSizeRange, OpaqueSimValueSlice, - OpaqueSimValueWriter, + OpaqueSimValueWriter, TraceAsString, }, util::{BitSliceWriteWithBase, DebugAsDisplay, HashMap, HashSet, copy_le_bytes_to_bitslice}, }; @@ -432,6 +433,15 @@ impl_trace_decl! { ty: DynSimOnly, flow: Flow, }), + TraceAsString(TraceTraceAsString { + fn location(self) -> _ { + self.location + } + location: TraceLocation, + name: Interned, + ty: TraceAsString, + flow: Flow, + }), }), } @@ -543,6 +553,7 @@ pub trait TraceWriter: fmt::Debug + 'static { id: TraceScalarId, value: &DynSimOnlyValue, ) -> Result<(), Self::Error>; + fn set_signal_string(&mut self, id: TraceScalarId, value: &str) -> Result<(), Self::Error>; } pub struct DynTraceWriterDecls(Box); @@ -607,6 +618,7 @@ trait TraceWriterDynTrait: fmt::Debug + 'static { id: TraceScalarId, value: &DynSimOnlyValue, ) -> std::io::Result<()>; + fn set_signal_string_dyn(&mut self, id: TraceScalarId, value: &str) -> std::io::Result<()>; } impl TraceWriterDynTrait for T { @@ -680,6 +692,9 @@ impl TraceWriterDynTrait for T { ) -> std::io::Result<()> { Ok(TraceWriter::set_signal_sim_only_value(self, id, value).map_err(err_into_io)?) } + fn set_signal_string_dyn(&mut self, id: TraceScalarId, value: &str) -> std::io::Result<()> { + Ok(TraceWriter::set_signal_string(self, id, value).map_err(err_into_io)?) + } } pub struct DynTraceWriter(Box); @@ -758,6 +773,9 @@ impl TraceWriter for DynTraceWriter { ) -> Result<(), Self::Error> { self.0.set_signal_sim_only_value_dyn(id, value) } + fn set_signal_string(&mut self, id: TraceScalarId, value: &str) -> Result<(), Self::Error> { + self.0.set_signal_string_dyn(id, value) + } } #[derive(Debug)] @@ -934,6 +952,10 @@ pub(crate) enum SimTraceKind { PhantomConst { ty: PhantomConst, }, + TraceAsString { + layout: compiler::CompiledTypeLayout, + range: TypeIndexRange, + }, } #[derive(PartialEq, Eq)] @@ -941,6 +963,7 @@ pub(crate) enum SimTraceState { Bits(BitVec), SimOnly(DynSimOnlyValue), PhantomConst, + OpaqueSimValue(OpaqueSimValue), } impl Clone for SimTraceState { @@ -949,6 +972,7 @@ impl Clone for SimTraceState { Self::Bits(v) => Self::Bits(v.clone()), Self::SimOnly(v) => Self::SimOnly(v.clone()), Self::PhantomConst => Self::PhantomConst, + Self::OpaqueSimValue(v) => Self::OpaqueSimValue(v.clone()), } } fn clone_from(&mut self, source: &Self) { @@ -956,6 +980,9 @@ impl Clone for SimTraceState { (SimTraceState::Bits(dest), SimTraceState::Bits(source)) => { dest.clone_from_bitslice(source); } + (SimTraceState::OpaqueSimValue(dest), SimTraceState::OpaqueSimValue(source)) => { + dest.clone_from(source); + } _ => *self = source.clone(), } } @@ -990,6 +1017,20 @@ impl SimTraceState { unreachable!() } } + fn unwrap_opaque_sim_value_ref(&self) -> &OpaqueSimValue { + if let SimTraceState::OpaqueSimValue(v) = self { + v + } else { + unreachable!() + } + } + fn unwrap_opaque_sim_value_mut(&mut self) -> &mut OpaqueSimValue { + if let SimTraceState::OpaqueSimValue(v) = self { + v + } else { + unreachable!() + } + } } impl fmt::Debug for SimTraceState { @@ -998,6 +1039,7 @@ impl fmt::Debug for SimTraceState { SimTraceState::Bits(v) => BitSliceWriteWithBase(v).fmt(f), SimTraceState::SimOnly(v) => v.fmt(f), SimTraceState::PhantomConst => f.debug_tuple("PhantomConst").finish(), + SimTraceState::OpaqueSimValue(v) => v.fmt(f), } } } @@ -1026,6 +1068,13 @@ impl SimTraceKind { } SimTraceKind::PhantomConst { .. } => SimTraceState::PhantomConst, SimTraceKind::SimOnly { index: _, ty } => SimTraceState::SimOnly(ty.default_value()), + SimTraceKind::TraceAsString { layout, range: _ } => { + let type_properties = layout.ty.type_properties(); + SimTraceState::OpaqueSimValue(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), + )) + } } } } @@ -1180,6 +1229,31 @@ impl SimulationModuleState { true } } + CompiledTypeLayoutBody::Transparent { .. } => { + let value = value.map_ty(|ty| match ty { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::Array(_) + | CanonicalType::Enum(_) + | CanonicalType::Bundle(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => unreachable!(), + CanonicalType::TraceAsString(ty) => ty, + }); + let sub_target = target + .join(TargetPathElement::from(TargetPathTraceAsStringInner {}).intern_sized()); + if self.parse_io(sub_target, value.inner()) { + self.uninitialized_ios.insert(target, vec![sub_target]); + true + } else { + false + } + } } } fn mark_target_as_initialized(&mut self, mut target: Target) { @@ -1230,7 +1304,10 @@ impl SimulationModuleState { Target::Base(_) => break, Target::Child(child) => { match *child.path_element() { - TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) => {} + TargetPathElement::BundleField(_) + | TargetPathElement::ArrayElement(_) + | TargetPathElement::TraceAsStringInner(_) + | TargetPathElement::ToTraceAsString(_) => {} TargetPathElement::DynArrayElement(_) => panic!( "simulator read/write expression must not have dynamic array indexes" ), @@ -1273,7 +1350,8 @@ impl SimulationModuleState { | CanonicalType::Reset(_) | CanonicalType::Clock(_) | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => unreachable!(), + | CanonicalType::DynSimOnly(_) + | CanonicalType::TraceAsString(_) => unreachable!(), CanonicalType::AsyncReset(_) => true, CanonicalType::SyncReset(_) => false, } @@ -1438,6 +1516,26 @@ impl SimulationExternModuleClockForPast { ); } } + CompiledTypeLayoutBody::Transparent { .. } => { + let map_ty_fn = |ty| match ty { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::Array(_) + | CanonicalType::Enum(_) + | CanonicalType::Bundle(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => unreachable!(), + CanonicalType::TraceAsString(ty) => ty, + }; + let current = current.map_ty(map_ty_fn); + let past = past.map_ty(map_ty_fn); + self.add_current_to_past_mapping(current.inner(), past.inner()); + } } } } @@ -1906,6 +2004,7 @@ struct SimulationImpl { ), >, waiting_sensitivity_sets_by_address: HashMap<*const SensitivitySet, Rc>, + trace_as_string_buf: String, } impl fmt::Debug for SimulationImpl { @@ -1995,6 +2094,7 @@ impl SimulationImpl { next_sensitivity_set_debug_id: _, waiting_sensitivity_sets_by_compiled_value, waiting_sensitivity_sets_by_address, + trace_as_string_buf: _, } = self; f.debug_struct("Simulation") .field("state", state) @@ -2101,6 +2201,7 @@ impl SimulationImpl { next_sensitivity_set_debug_id: 0, waiting_sensitivity_sets_by_compiled_value: HashMap::default(), waiting_sensitivity_sets_by_address: HashMap::default(), + trace_as_string_buf: String::with_capacity(256), } } fn write_traces( @@ -2181,6 +2282,15 @@ impl SimulationImpl { SimTraceKind::SimOnly { .. } => { trace_writer.set_signal_sim_only_value(id, state.unwrap_sim_only_ref())? } + SimTraceKind::TraceAsString { layout, .. } => { + self.trace_as_string_buf.clear(); + layout.ty.trace_fmt_append_to_string( + &mut self.trace_as_string_buf, + state.unwrap_opaque_sim_value_ref().as_slice(), + ); + trace_writer.set_signal_string(id, &self.trace_as_string_buf)?; + self.trace_as_string_buf.clear(); + } } } Ok(trace_writer) @@ -2217,7 +2327,7 @@ impl SimulationImpl { | SimTraceKind::BigClock { index } => self .state .big_slots - .state_index_fetch_and_clear_maybe_modified_flag(index), + .state_index_fetch_maybe_modified_flag(index), SimTraceKind::SmallUInt { index, ty: _ } | SimTraceKind::SmallSInt { index, ty: _ } | SimTraceKind::SmallBool { index } @@ -2227,12 +2337,15 @@ impl SimulationImpl { | SimTraceKind::EnumDiscriminant { index, ty: _ } => self .state .small_slots - .state_index_fetch_and_clear_maybe_modified_flag(index), + .state_index_fetch_maybe_modified_flag(index), SimTraceKind::SimOnly { index, ty: _ } => self .state .sim_only_slots - .state_index_fetch_and_clear_maybe_modified_flag(index), + .state_index_fetch_maybe_modified_flag(index), SimTraceKind::PhantomConst { ty: _ } => IS_INITIAL_STEP, + SimTraceKind::TraceAsString { layout: _, range } => self + .state + .type_index_range_fetch_maybe_modified_flags(range), }; if !new_maybe_changed && !IS_INITIAL_STEP { if *maybe_changed { @@ -2286,11 +2399,26 @@ impl SimulationImpl { .unwrap_sim_only_mut() .clone_from(&self.state.sim_only_slots[index]); } + SimTraceKind::TraceAsString { layout, range } => { + let CompiledTypeLayoutBody::Transparent { inner } = layout.body else { + unreachable!() + }; + Self::read_opaque_no_settle( + &mut self.state, + CompiledValue { + layout: *inner, + range, + write: None, + }, + state.unwrap_opaque_sim_value_mut(), + ); + } } if IS_INITIAL_STEP { last_state.clone_from(state); } } + self.state.clear_all_maybe_modified_flags(); } #[track_caller] fn advance_time(this_ref: &Rc>, duration: SimDuration) { @@ -2817,6 +2945,7 @@ impl SimulationImpl { + Copy, read_write_sim_only_scalar: impl Fn(usize, &mut Opaque, &mut DynSimOnlyValue) + Copy, ) { + let compiled_value = compiled_value.unwrap_transparent_types(); match compiled_value.layout.body { CompiledTypeLayoutBody::Scalar => { let signed = match compiled_value.layout.ty { @@ -2832,6 +2961,7 @@ impl SimulationImpl { CanonicalType::Clock(_) => false, CanonicalType::PhantomConst(_) => unreachable!(), CanonicalType::DynSimOnly(_) => false, + CanonicalType::TraceAsString(_) => unreachable!(), }; let indexes = OpaqueSimValueSizeRange::from( start_index..start_index + compiled_value.layout.ty.size(), @@ -2908,14 +3038,17 @@ impl SimulationImpl { ); } } + CompiledTypeLayoutBody::Transparent { .. } => { + unreachable!("handled by unwrap_transparent_types") + } } } #[track_caller] - fn read_no_settle_helper( + fn read_opaque_no_settle( state: &mut interpreter::State, - io: Expr, compiled_value: CompiledValue, - ) -> SimValue { + opaque: &mut OpaqueSimValue, + ) { #[track_caller] fn read_write_sim_only_scalar( index: usize, @@ -2936,8 +3069,7 @@ impl SimulationImpl { }, ); } - let size = io.ty().size(); - let mut opaque = OpaqueSimValue::with_capacity(size); + let size = compiled_value.layout.ty.size(); opaque.rewrite_with(size, |mut writer| { SimulationImpl::read_write_sim_value_helper( state, @@ -2969,6 +3101,16 @@ impl SimulationImpl { ); writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty()) }); + } + #[track_caller] + fn read_no_settle_helper( + state: &mut interpreter::State, + io: Expr, + compiled_value: CompiledValue, + ) -> SimValue { + let size = io.ty().size(); + let mut opaque = OpaqueSimValue::with_capacity(size); + Self::read_opaque_no_settle(state, compiled_value, &mut opaque); SimValue::from_opaque(io.ty(), opaque) } /// doesn't modify `opaque` diff --git a/crates/fayalite/src/sim/compiler.rs b/crates/fayalite/src/sim/compiler.rs index dbdbffb..4d6d9bc 100644 --- a/crates/fayalite/src/sim/compiler.rs +++ b/crates/fayalite/src/sim/compiler.rs @@ -10,7 +10,7 @@ use crate::{ ExprEnum, Flow, ValueType, ops, target::{ GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, - TargetPathElement, + TargetPathElement, TargetPathToTraceAsString, TargetPathTraceAsStringInner, }, }, int::BoolOrIntType, @@ -29,7 +29,8 @@ use crate::{ TraceBool, TraceBundle, TraceClock, TraceDecl, TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule, TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, - TraceScalarId, TraceScope, TraceSimOnly, TraceSyncReset, TraceUInt, TraceWire, + TraceScalarId, TraceScope, TraceSimOnly, TraceSyncReset, TraceTraceAsString, TraceUInt, + TraceWire, interpreter::{ self, Insn, InsnField, InsnFieldKind, InsnFieldType, InsnOrLabel, Insns, InsnsBuilding, InsnsBuildingDone, InsnsBuildingKind, Label, PrefixLinesWrapper, SmallUInt, @@ -42,7 +43,7 @@ use crate::{ }, }, }, - ty::{OpaqueSimValueSize, StaticType}, + ty::{OpaqueSimValueSize, StaticType, TraceAsString}, util::{HashMap, chain}, }; use bitvec::vec::BitVec; @@ -110,6 +111,9 @@ pub(crate) enum CompiledTypeLayoutBody { Bundle { fields: Interned<[CompiledBundleField]>, }, + Transparent { + inner: Interned>, + }, } impl CompiledTypeLayoutBody { @@ -128,6 +132,9 @@ impl CompiledTypeLayoutBody { .map(|field| field.with_prefixed_debug_names(prefix)) .collect(), }, + CompiledTypeLayoutBody::Transparent { inner } => CompiledTypeLayoutBody::Transparent { + inner: inner.with_prefixed_debug_names(prefix).intern_sized(), + }, } } fn with_anonymized_debug_info(self) -> Self { @@ -145,6 +152,9 @@ impl CompiledTypeLayoutBody { .map(|field| field.with_anonymized_debug_info()) .collect(), }, + CompiledTypeLayoutBody::Transparent { inner } => CompiledTypeLayoutBody::Transparent { + inner: inner.with_anonymized_debug_info().intern_sized(), + }, } } } @@ -179,7 +189,7 @@ impl CompiledTypeLayout { impl Memoize for MyMemoize { type Input = CanonicalType; type InputOwned = CanonicalType; - type Output = CompiledTypeLayout; + type Output = (TypeLayout, CompiledTypeLayoutBody); fn inner(self, input: &Self::Input) -> Self::Output { match input { @@ -197,11 +207,7 @@ impl CompiledTypeLayout { ty: *input, }; layout.big_slots = StatePartLayout::scalar(debug_data, ()); - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Scalar, - } + (layout.into(), CompiledTypeLayoutBody::Scalar) } CanonicalType::Array(array) => { let mut layout = TypeLayout::empty(); @@ -215,19 +221,16 @@ impl CompiledTypeLayout { if array.is_empty() { elements_non_empty.push(element.with_prefixed_debug_names("[]")); } - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Array { + ( + layout.into(), + CompiledTypeLayoutBody::Array { elements_non_empty: elements_non_empty.intern_deref(), }, - } + ) + } + CanonicalType::PhantomConst(_) => { + (TypeLayout::empty(), CompiledTypeLayoutBody::PhantomConst) } - CanonicalType::PhantomConst(_) => CompiledTypeLayout { - ty: *input, - layout: TypeLayout::empty(), - body: CompiledTypeLayoutBody::PhantomConst, - }, CanonicalType::Bundle(bundle) => { let mut layout = TypeLayout::empty(); let fields = bundle @@ -246,11 +249,7 @@ impl CompiledTypeLayout { }, ) .collect(); - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Bundle { fields }, - } + (layout.into(), CompiledTypeLayoutBody::Bundle { fields }) } CanonicalType::DynSimOnly(ty) => { let mut layout = TypeLayout::empty(); @@ -259,24 +258,30 @@ impl CompiledTypeLayout { ty: *input, }; layout.sim_only_slots = StatePartLayout::scalar(debug_data, *ty); - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Scalar, - } + (layout.into(), CompiledTypeLayoutBody::Scalar) + } + CanonicalType::TraceAsString(ty) => { + let inner = CompiledTypeLayout::get(ty.inner_ty()).intern_sized(); + (inner.layout, CompiledTypeLayoutBody::Transparent { inner }) } } } } - let CompiledTypeLayout { - ty: _, - layout, - body, - } = MyMemoize.get_owned(ty.canonical()); + let (layout, body) = MyMemoize.get_owned(ty.canonical()); Self { ty, layout, body } } } +impl CompiledTypeLayout { + #[must_use] + fn unwrap_transparent_types(mut self) -> Self { + while let CompiledTypeLayoutBody::Transparent { inner } = self.body { + self = *inner; + } + self + } +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub(crate) struct CompiledValue { pub(crate) layout: CompiledTypeLayout, @@ -324,6 +329,29 @@ impl CompiledValue { } } +impl CompiledValue { + #[must_use] + pub(crate) fn unwrap_transparent_types(self) -> Self { + let Self { + layout, + range, + write, + } = self; + Self { + layout: layout.unwrap_transparent_types(), + range, + write: write.map(|(layout, range)| (layout.unwrap_transparent_types(), range)), + } + } + #[must_use] + pub(crate) fn wrap_in_trace_as_string(self, ty: TraceAsString) -> CompiledValue { + self.map(|layout, range| { + assert_eq!(layout.ty, ty.inner_ty()); + (CompiledTypeLayout::get(ty), range) + }) + } +} + pub(crate) struct DebugCompiledValueStateAsMap<'a> { pub(crate) compiled_value: CompiledValue, pub(crate) state_layout: &'a interpreter::parts::StateLayout, @@ -402,6 +430,17 @@ impl CompiledValue { } } +impl CompiledValue { + pub(crate) fn inner(self) -> CompiledValue { + self.map(|layout, range| { + let CompiledTypeLayoutBody::Transparent { inner } = layout.body else { + unreachable!(); + }; + (*inner, range) + }) + } +} + macro_rules! make_type_array_indexes { ( type_plural_fields = [$($type_plural_field:ident,)*]; @@ -618,6 +657,16 @@ impl CompiledExpr { } } +impl CompiledExpr { + #[must_use] + pub(crate) fn wrap_in_trace_as_string(self, ty: TraceAsString) -> CompiledExpr { + CompiledExpr { + static_part: self.static_part.wrap_in_trace_as_string(ty), + indexes: self.indexes, + } + } +} + impl CompiledExpr { fn field_by_index(self, field_index: usize) -> CompiledExpr { CompiledExpr { @@ -666,6 +715,15 @@ impl CompiledExpr { } } +impl CompiledExpr { + pub(crate) fn inner(self) -> CompiledExpr { + CompiledExpr { + static_part: self.static_part.inner(), + indexes: self.indexes, + } + } +} + macro_rules! make_assignment_graph { ( type_plural_fields = [$($type_plural_field:ident,)*]; @@ -1977,6 +2035,39 @@ macro_rules! impl_compiler { flow, } .into(), + CanonicalType::TraceAsString(ty) => { + let location = match target { + MakeTraceDeclTarget::Expr(target) => { + let compiled_value = self.compile_expr(instantiated_module, target); + let CompiledValue { layout, range, write: _ } = + self.compiled_expr_to_value(compiled_value, source_location).map_ty(Type::from_canonical); + TraceLocation::Scalar(self.new_sim_trace(SimTraceKind::TraceAsString { + layout, + range, + })) + } + MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start, + ty: _, + } => TraceLocation::Memory(TraceMemoryLocation { + id, + depth, + stride, + start, + len: ty.type_properties().bit_width, + }), + }; + TraceTraceAsString { + location, + name, + ty, + flow, + } + .into() + } } } fn compiled_expr_to_value( @@ -2421,7 +2512,8 @@ impl Compiler { | CanonicalType::Reset(_) | CanonicalType::Clock(_) | CanonicalType::DynSimOnly(_) - | CanonicalType::PhantomConst(_) => { + | CanonicalType::PhantomConst(_) + | CanonicalType::TraceAsString(_) => { self.make_trace_scalar(instantiated_module, target, name, source_location) } } @@ -2591,6 +2683,12 @@ impl Compiler { parent.map_ty(Array::from_canonical).element(index) } TargetPathElement::DynArrayElement(_) => unreachable!(), + TargetPathElement::TraceAsStringInner(TargetPathTraceAsStringInner {}) => { + parent.map_ty(TraceAsString::from_canonical).inner() + } + TargetPathElement::ToTraceAsString(TargetPathToTraceAsString { ty }) => parent + .wrap_in_trace_as_string(ty) + .map_ty(|ty| ty.canonical()), } } }; @@ -2823,6 +2921,12 @@ impl Compiler { CanonicalType::PhantomConst(_) | CanonicalType::DynSimOnly(_) => { self.compile_cast_aggregate_to_bits(instantiated_module, []) } + CanonicalType::TraceAsString(_) => self.compile_cast_to_bits( + instantiated_module, + ops::CastToBits::new( + ops::TraceAsStringAsInner::new(Expr::from_canonical(expr.arg())).to_expr(), + ), + ), } } fn compile_cast_bits_to_or_uninit( @@ -2912,6 +3016,16 @@ impl Compiler { vec![] }); } + CanonicalType::TraceAsString(ty) => Expr::canonical( + ops::ToTraceAsString::new( + match arg { + Some(arg) => arg.cast_bits_to(ty.inner_ty()), + None => ty.inner_ty().uninit(), + }, + ty, + ) + .to_expr(), + ), }; let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); self.compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()) @@ -2963,6 +3077,7 @@ impl Compiler { CanonicalType::Clock(_) => false, CanonicalType::PhantomConst(_) => unreachable!(), CanonicalType::DynSimOnly(_) => unreachable!(), + CanonicalType::TraceAsString(_) => unreachable!(), }; let dest_signed = match expr.ty() { CanonicalType::UInt(_) => false, @@ -2977,6 +3092,7 @@ impl Compiler { CanonicalType::Clock(_) => false, CanonicalType::PhantomConst(_) => unreachable!(), CanonicalType::DynSimOnly(_) => unreachable!(), + CanonicalType::TraceAsString(_) => unreachable!(), }; self.simple_nary_big_expr(instantiated_module, expr.ty(), [arg], |dest, [src]| match ( src_signed, @@ -3722,6 +3838,14 @@ impl Compiler { ExprEnum::CastBitsTo(expr) => self .compile_cast_bits_to_or_uninit(instantiated_module, Some(expr.arg()), expr.ty()) .into(), + ExprEnum::ToTraceAsString(expr) => self + .compile_expr(instantiated_module, expr.inner()) + .wrap_in_trace_as_string(expr.ty()) + .map_ty(|ty| ty.canonical()), + ExprEnum::TraceAsStringAsInner(expr) => self + .compile_expr(instantiated_module, Expr::canonical(expr.arg())) + .map_ty(TraceAsString::from_canonical) + .inner(), ExprEnum::ModuleIO(expr) => self .compile_value(TargetInInstantiatedModule { instantiated_module, @@ -3869,6 +3993,21 @@ impl Compiler { CanonicalType::DynSimOnly(_) => { unreachable!("DynSimOnly mismatch"); } + CanonicalType::TraceAsString(_) => { + let lhs = Expr::::from_canonical(lhs); + let rhs = Expr::::from_canonical(rhs); + let lhs_expr = ops::TraceAsStringAsInner::new(lhs).to_expr(); + let rhs_expr = ops::TraceAsStringAsInner::new(rhs).to_expr(); + return self.compile_connect( + lhs_instantiated_module, + lhs_conditions, + lhs_expr, + rhs_instantiated_module, + rhs_conditions, + rhs_expr, + source_location, + ); + } } } let Some(target) = lhs.target() else { @@ -4244,6 +4383,8 @@ impl Compiler { mut read: Option>, mut write: Option>, ) { + let data_layout = data_layout.unwrap_transparent_types(); + let mask_layout = mask_layout.unwrap_transparent_types(); match data_layout.body { CompiledTypeLayoutBody::Scalar => { let CompiledTypeLayoutBody::Scalar = mask_layout.body else { @@ -4262,6 +4403,7 @@ impl Compiler { CanonicalType::Clock(_) => false, CanonicalType::PhantomConst(_) => unreachable!(), CanonicalType::DynSimOnly(_) => false, + CanonicalType::TraceAsString(_) => unreachable!(), }; let width = data_layout.ty.bit_width(); if let Some(MemoryPortReadInsns { @@ -4484,6 +4626,9 @@ impl Compiler { start = start + field.ty.ty.bit_width(); } } + CompiledTypeLayoutBody::Transparent { .. } => { + unreachable!("handled by unwrap_transparent_types") + } } } fn compile_memory_port_rw( diff --git a/crates/fayalite/src/sim/interpreter.rs b/crates/fayalite/src/sim/interpreter.rs index 0cf98d0..6b3eced 100644 --- a/crates/fayalite/src/sim/interpreter.rs +++ b/crates/fayalite/src/sim/interpreter.rs @@ -6,9 +6,9 @@ use crate::{ int::{BoolOrIntType, SInt, UInt}, intern::{Intern, Interned, Memoize}, sim::interpreter::parts::{ - StateLayout, StatePartIndex, StatePartKind, StatePartKindBigSlots, StatePartKindMemories, - StatePartKindSimOnlySlots, StatePartKindSmallSlots, StatePartLen, TypeIndexRange, - TypeLayout, get_state_part_kinds, + StateLayout, StatePartIndex, StatePartIndexRange, StatePartKind, StatePartKindBigSlots, + StatePartKindMemories, StatePartKindSimOnlySlots, StatePartKindSmallSlots, StatePartLen, + TypeIndexRange, TypeLayout, get_state_part_kinds, }, source_location::SourceLocation, util::{HashMap, HashSet}, @@ -914,11 +914,20 @@ impl StatePart { value: K::borrow_state(&mut self.value), } } - pub(crate) fn state_index_fetch_and_clear_maybe_modified_flag( - &mut self, + pub(crate) fn state_index_fetch_maybe_modified_flag( + &self, part_index: StatePartIndex, ) -> bool { - K::state_index_fetch_and_clear_maybe_modified_flag(&mut self.value, part_index) + K::state_index_fetch_maybe_modified_flag(&self.value, part_index) + } + pub(crate) fn state_index_range_fetch_maybe_modified_flags( + &self, + part_index_range: StatePartIndexRange, + ) -> bool { + K::state_index_range_fetch_maybe_modified_flags(&self.value, part_index_range) + } + pub(crate) fn clear_all_maybe_modified_flags(&mut self) { + K::clear_all_maybe_modified_flags(&mut self.value) } } @@ -1015,6 +1024,15 @@ macro_rules! make_state { $($type_plural_field: self.$type_plural_field.borrow(),)* } } + pub(crate) fn type_index_range_fetch_maybe_modified_flags(&self, range: TypeIndexRange) -> bool { + $(self.$type_plural_field.state_index_range_fetch_maybe_modified_flags( + range.$type_plural_field, + ))||* + } + pub(crate) fn clear_all_maybe_modified_flags(&mut self) { + $(self.$state_plural_field.clear_all_maybe_modified_flags();)* + $(self.$type_plural_field.clear_all_maybe_modified_flags();)* + } } #[derive(Debug)] diff --git a/crates/fayalite/src/sim/interpreter/parts.rs b/crates/fayalite/src/sim/interpreter/parts.rs index d9e4214..0d98c06 100644 --- a/crates/fayalite/src/sim/interpreter/parts.rs +++ b/crates/fayalite/src/sim/interpreter/parts.rs @@ -256,10 +256,15 @@ pub(crate) trait StatePartKind: state: &'a mut Self::State, part_index: StatePartIndex, ) -> &'a mut Self::StateElement; - fn state_index_fetch_and_clear_maybe_modified_flag( - state: &mut Self::State, + fn state_index_fetch_maybe_modified_flag( + state: &Self::State, part_index: StatePartIndex, ) -> bool; + fn state_index_range_fetch_maybe_modified_flags( + state: &Self::State, + part_index_range: StatePartIndexRange, + ) -> bool; + fn clear_all_maybe_modified_flags(state: &mut Self::State); fn borrowed_state_index<'a, 'b>( state: &'a Self::BorrowedState<'b>, part_index: StatePartIndex, @@ -335,12 +340,19 @@ impl StatePartKind for StatePartKindMemories { ) -> &'a mut Self::StateElement { &mut state[part_index.as_usize()] } - fn state_index_fetch_and_clear_maybe_modified_flag( - _state: &mut Self::State, + fn state_index_fetch_maybe_modified_flag( + _state: &Self::State, _part_index: StatePartIndex, ) -> bool { true } + fn state_index_range_fetch_maybe_modified_flags( + _state: &Self::State, + part_index_range: StatePartIndexRange, + ) -> bool { + part_index_range.len.value > 0 + } + fn clear_all_maybe_modified_flags(_state: &mut Self::State) {} fn borrowed_state_index<'a, 'b>( state: &'a Self::BorrowedState<'b>, part_index: StatePartIndex, @@ -438,11 +450,22 @@ impl StatePartKind for StatePartKindSmallSlots { state.modified[part_index.as_usize()] = true; &mut state.state[part_index.as_usize()] } - fn state_index_fetch_and_clear_maybe_modified_flag( - state: &mut Self::State, + fn state_index_fetch_maybe_modified_flag( + state: &Self::State, part_index: StatePartIndex, ) -> bool { - std::mem::replace(&mut state.modified[part_index.as_usize()], false) + state.modified[part_index.as_usize()] + } + fn state_index_range_fetch_maybe_modified_flags( + state: &Self::State, + part_index_range: StatePartIndexRange, + ) -> bool { + state.modified[part_index_range.start.as_usize()..] + [..part_index_range.len.as_index().as_usize()] + .contains(&true) + } + fn clear_all_maybe_modified_flags(state: &mut Self::State) { + state.modified.fill(false); } fn borrowed_state_index<'a, 'b>( state: &'a Self::BorrowedState<'b>, @@ -519,11 +542,22 @@ impl StatePartKind for StatePartKindBigSlots { state.modified[part_index.as_usize()] = true; &mut state.state[part_index.as_usize()] } - fn state_index_fetch_and_clear_maybe_modified_flag( - state: &mut Self::State, + fn state_index_fetch_maybe_modified_flag( + state: &Self::State, part_index: StatePartIndex, ) -> bool { - std::mem::replace(&mut state.modified[part_index.as_usize()], false) + state.modified[part_index.as_usize()] + } + fn state_index_range_fetch_maybe_modified_flags( + state: &Self::State, + part_index_range: StatePartIndexRange, + ) -> bool { + state.modified[part_index_range.start.as_usize()..] + [..part_index_range.len.as_index().as_usize()] + .contains(&true) + } + fn clear_all_maybe_modified_flags(state: &mut Self::State) { + state.modified.fill(false); } fn borrowed_state_index<'a, 'b>( state: &'a Self::BorrowedState<'b>, @@ -600,11 +634,22 @@ impl StatePartKind for StatePartKindSimOnlySlots { state.modified[part_index.as_usize()] = true; &mut state.state[part_index.as_usize()] } - fn state_index_fetch_and_clear_maybe_modified_flag( - state: &mut Self::State, + fn state_index_fetch_maybe_modified_flag( + state: &Self::State, part_index: StatePartIndex, ) -> bool { - std::mem::replace(&mut state.modified[part_index.as_usize()], false) + state.modified[part_index.as_usize()] + } + fn state_index_range_fetch_maybe_modified_flags( + state: &Self::State, + part_index_range: StatePartIndexRange, + ) -> bool { + state.modified[part_index_range.start.as_usize()..] + [..part_index_range.len.as_index().as_usize()] + .contains(&true) + } + fn clear_all_maybe_modified_flags(state: &mut Self::State) { + state.modified.fill(false); } fn borrowed_state_index<'a, 'b>( state: &'a Self::BorrowedState<'b>, diff --git a/crates/fayalite/src/sim/value.rs b/crates/fayalite/src/sim/value.rs index a127878..24bc1ef 100644 --- a/crates/fayalite/src/sim/value.rs +++ b/crates/fayalite/src/sim/value.rs @@ -19,20 +19,19 @@ use crate::{ impl_match_variant_as_self, }, util::{ - ConstUsize, HashMap, + ConstUsize, alternating_cell::{AlternatingCell, AlternatingCellMethods}, + serde_by_id::{SerdeById, SerdeByIdProperties, SerdeByIdTable, SerdeByIdTrait}, }, }; use bitvec::{slice::BitSlice, vec::BitVec}; -use hashbrown::hash_map::Entry; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _}; use std::{ borrow::{Borrow, BorrowMut, Cow}, - fmt::{self, Write}, - hash::{BuildHasher, Hash, Hasher, RandomState}, + fmt, num::NonZero, ops::{Deref, DerefMut, Index, IndexMut}, - sync::{Arc, Mutex}, + sync::Arc, }; pub(crate) mod sim_only_value_unsafe; @@ -552,113 +551,119 @@ impl_sim_value_cmp_as_bool!(AsyncReset); #[doc(hidden)] pub mod match_sim_value { - use crate::{ - sim::value::{SimValue, ToSimValue}, - ty::Type, - }; + use crate::{sim::value::SimValue, ty::Type}; + use std::ops::{Deref, DerefMut}; + + macro_rules! wrapper { + ( + $(pub struct $wrapper:ident<$T:ident>($inner:ty);)* + ) => { + $(#[doc(hidden)] + pub struct $wrapper<$T>($inner); + + impl<$T> $wrapper<$T> { + #[inline(always)] + pub fn new(value: $T) -> Self { + Self(<$inner>::new(value)) + } + } + + impl<$T> Deref for $wrapper<$T> { + type Target = $inner; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl<$T> DerefMut for $wrapper<$T> { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + })* + }; + } + + wrapper! { + pub struct MatchSimValueHelperCheckSimValue(MatchSimValueHelperCheckMutSimValue); + pub struct MatchSimValueHelperCheckMutSimValue(MatchSimValueHelperCheckRefSimValue); + pub struct MatchSimValueHelperCheckRefSimValue(MatchSimValueHelperCheckRefRefSimValue); + pub struct MatchSimValueHelperCheckRefRefSimValue(MatchSimValueHelperCheckRefMutSimValue); + pub struct MatchSimValueHelperCheckRefMutSimValue(MatchSimValueHelperCheckMutRefSimValue); + pub struct MatchSimValueHelperCheckMutRefSimValue(MatchSimValueHelperCheckMutMutSimValue); + pub struct MatchSimValueHelperCheckMutMutSimValue(MatchSimValueHelperIdentity); + } + + impl MatchSimValueHelperCheckSimValue> { + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> T::SimValue { + SimValue::into_value(self.take()) + } + } + + impl<'a, T: Type> MatchSimValueHelperCheckMutSimValue<&'a mut SimValue> { + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> &'a mut T::SimValue { + self.take() + } + } + + impl<'a, T: Type> MatchSimValueHelperCheckRefSimValue<&'a SimValue> { + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> &'a T::SimValue { + self.take() + } + } + + impl<'a, 'b, T: Type> MatchSimValueHelperCheckRefRefSimValue<&'a &'b SimValue> { + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> &'b T::SimValue { + self.take() + } + } + + impl<'a, 'b, T: Type> MatchSimValueHelperCheckRefMutSimValue<&'a &'b mut SimValue> { + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> &'a T::SimValue { + self.take() + } + } + + impl<'a, 'b, T: Type> MatchSimValueHelperCheckMutRefSimValue<&'a mut &'b SimValue> { + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> &'b T::SimValue { + self.take() + } + } + + impl<'a, 'b, T: Type> MatchSimValueHelperCheckMutMutSimValue<&'a mut &'b mut SimValue> { + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> &'a mut T::SimValue { + self.take() + } + } #[doc(hidden)] - pub struct MatchSimValueHelper(Option); + pub struct MatchSimValueHelperIdentity(Option); - impl MatchSimValueHelper { - pub fn new(v: T) -> Self { + impl MatchSimValueHelperIdentity { + fn new(v: T) -> Self { Self(Some(v)) } - } - - #[doc(hidden)] - pub trait MatchSimValue { - type MatchValue; - - /// use `self` so it comes first in the method resolution order - fn __fayalite_match_sim_value(self) -> Self::MatchValue - where - Self: Sized; - } - - impl MatchSimValue for MatchSimValueHelper> { - type MatchValue = T::SimValue; - - fn __fayalite_match_sim_value(self) -> Self::MatchValue { - SimValue::into_value(self.0.expect("should be Some")) + #[inline(always)] + fn take(&mut self) -> T { + self.0.take().expect("known to be Some") } - } - - impl<'a, T: Type> MatchSimValue for MatchSimValueHelper<&'a SimValue> { - type MatchValue = &'a T::SimValue; - - fn __fayalite_match_sim_value(self) -> Self::MatchValue { - SimValue::value(self.0.expect("should be Some")) - } - } - - impl<'a, T: Type> MatchSimValue for MatchSimValueHelper<&'a mut SimValue> { - type MatchValue = &'a mut T::SimValue; - - fn __fayalite_match_sim_value(self) -> Self::MatchValue { - SimValue::value_mut(self.0.expect("should be Some")) - } - } - - impl<'a, T> MatchSimValue for MatchSimValueHelper<&'_ &'a T> - where - MatchSimValueHelper<&'a T>: MatchSimValue, - { - type MatchValue = as MatchSimValue>::MatchValue; - - fn __fayalite_match_sim_value(self) -> Self::MatchValue { - MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| *v))) - } - } - - impl<'a, T> MatchSimValue for MatchSimValueHelper<&'_ mut &'a T> - where - MatchSimValueHelper<&'a T>: MatchSimValue, - { - type MatchValue = as MatchSimValue>::MatchValue; - - fn __fayalite_match_sim_value(self) -> Self::MatchValue { - MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| *v))) - } - } - - impl<'a, T> MatchSimValue for MatchSimValueHelper<&'a &'_ mut T> - where - MatchSimValueHelper<&'a T>: MatchSimValue, - { - type MatchValue = as MatchSimValue>::MatchValue; - - fn __fayalite_match_sim_value(self) -> Self::MatchValue { - MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| &**v))) - } - } - - impl<'a, T> MatchSimValue for MatchSimValueHelper<&'a mut &'_ mut T> - where - MatchSimValueHelper<&'a mut T>: MatchSimValue, - { - type MatchValue = as MatchSimValue>::MatchValue; - - fn __fayalite_match_sim_value(self) -> Self::MatchValue { - MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| &mut **v))) + #[inline(always)] + pub fn __fayalite_match_sim_value(&mut self) -> T { + self.take() } } #[doc(hidden)] - pub trait MatchSimValueFallback { - type MatchValue; - - /// use `&mut self` so it comes later in the method resolution order than MatchSimValue - fn __fayalite_match_sim_value(&mut self) -> Self::MatchValue; - } - - impl MatchSimValueFallback for MatchSimValueHelper { - type MatchValue = ::SimValue; - - fn __fayalite_match_sim_value(&mut self) -> Self::MatchValue { - SimValue::into_value(self.0.take().expect("should be Some").into_sim_value()) - } - } + pub type MatchSimValueHelper = MatchSimValueHelperCheckSimValue; } pub trait ToSimValue: ToSimValueWithType<::Type> + ValueType { @@ -1092,7 +1097,8 @@ impl ToSimValueWithType for bool { | CanonicalType::Enum(_) | CanonicalType::Bundle(_) | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => { + | CanonicalType::DynSimOnly(_) + | CanonicalType::TraceAsString(_) => { panic!("can't create SimValue from bool: expected value of type: {ty:?}"); } CanonicalType::Bool(_) @@ -1221,80 +1227,17 @@ 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 DynSimOnlySerdeTableRest { - from_serde: HashMap, - serde_id_random_state: RandomState, - buffer: String, -} - -impl DynSimOnlySerdeTableRest { - #[cold] - fn add_new(&mut self, ty: DynSimOnly) -> DynSimOnlySerdeId { - 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 = DynSimOnlySerdeId(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; - } - } - } +impl SerdeByIdTrait for DynSimOnly { + fn serde_by_id_properties(&self) -> SerdeByIdProperties { + self.serde_by_id_properties_inner() } -} -#[derive(Default)] -struct DynSimOnlySerdeTable { - to_serde: HashMap, - rest: DynSimOnlySerdeTableRest, -} - -static DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE: Mutex> = Mutex::new(None); - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] -#[serde(transparent)] -struct DynSimOnlySerdeId([u32; 4]); - -impl From for DynSimOnlySerdeId { - fn from(ty: DynSimOnly) -> Self { - let mut locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE - .lock() - .expect("shouldn't be poison"); - let DynSimOnlySerdeTable { 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)), - } + fn static_table() -> &'static SerdeByIdTable { + static TABLE: SerdeByIdTable = SerdeByIdTable::new(); + &TABLE } -} -impl DynSimOnlySerdeId { - fn ty(self) -> Option { - 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 DynSimOnlySerde<'a> { - random_id: DynSimOnlySerdeId, - #[serde(borrow)] - type_name: Cow<'a, str>, + const NAME: &'static str = "DynSimOnly"; } impl Serialize for DynSimOnly { @@ -1302,11 +1245,7 @@ impl Serialize for DynSimOnly { where S: Serializer, { - DynSimOnlySerde { - random_id: (*self).into(), - type_name: Cow::Borrowed(self.type_name()), - } - .serialize(serializer) + SerdeById { inner: *self }.serialize(serializer) } } @@ -1315,16 +1254,7 @@ impl<'de> Deserialize<'de> for DynSimOnly { where D: Deserializer<'de>, { - let deserialized = DynSimOnlySerde::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 DynSimOnly that was serialized this time this program was run", - ) - }) + Ok(SerdeById::deserialize(deserializer)?.inner) } } diff --git a/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs b/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs index 2424c03..bcbcdc6 100644 --- a/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs +++ b/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs @@ -3,7 +3,10 @@ //! `unsafe` parts of [`DynSimOnlyValue`] -use crate::expr::{ValueType, value_category::ValueCategoryValue}; +use crate::{ + expr::{ValueType, value_category::ValueCategoryValue}, + util::serde_by_id::SerdeByIdProperties, +}; use serde::{Serialize, de::DeserializeOwned}; use std::{ any::{self, TypeId}, @@ -33,6 +36,7 @@ unsafe trait DynSimOnlyTrait: 'static + Send + Sync { &self, json_str: &str, ) -> serde_json::Result>; + fn serde_by_id_properties_inner(&self) -> SerdeByIdProperties; } /// Safety: `type_id_dyn` is implemented correctly @@ -55,6 +59,9 @@ unsafe impl DynSimOnlyTrait for SimOnly { ) -> serde_json::Result> { Ok(Rc::::new(serde_json::from_str(json_str)?)) } + fn serde_by_id_properties_inner(&self) -> SerdeByIdProperties { + SerdeByIdProperties::of::() + } } /// Safety: @@ -151,6 +158,9 @@ impl DynSimOnly { pub fn default_value(self) -> DynSimOnlyValue { DynSimOnlyValue(self.ty.default_value()) } + pub(super) fn serde_by_id_properties_inner(self) -> SerdeByIdProperties { + self.ty.serde_by_id_properties_inner() + } } impl PartialEq for DynSimOnly { diff --git a/crates/fayalite/src/sim/vcd.rs b/crates/fayalite/src/sim/vcd.rs index ad3e974..09e7d66 100644 --- a/crates/fayalite/src/sim/vcd.rs +++ b/crates/fayalite/src/sim/vcd.rs @@ -12,11 +12,12 @@ use crate::{ TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule, TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, TraceScalar, TraceScalarId, - TraceScope, TraceSimOnly, TraceSyncReset, TraceUInt, TraceWire, TraceWriter, - TraceWriterDecls, + TraceScope, TraceSimOnly, TraceSyncReset, TraceTraceAsString, TraceUInt, TraceWire, + TraceWriter, TraceWriterDecls, time::{SimDuration, SimInstant}, value::DynSimOnlyValue, }, + ty::{OpaqueSimValueSlice, TraceAsString}, util::HashMap, }; use bitvec::{order::Lsb0, slice::BitSlice}; @@ -331,6 +332,7 @@ impl WriteTrace for TraceScalar { Self::AsyncReset(v) => v.write_trace(writer, arg), Self::PhantomConst(v) => v.write_trace(writer, arg), Self::SimOnly(v) => v.write_trace(writer, arg), + Self::TraceAsString(v) => v.write_trace(writer, arg), } } } @@ -726,6 +728,34 @@ impl WriteTrace for TraceSimOnly { } } +impl WriteTrace for TraceTraceAsString { + fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { + let ArgInType { + source_var_type: _, + sink_var_type: _, + duplex_var_type: _, + properties, + scope, + } = arg.in_type(); + let Self { + location, + name, + ty, + flow: _, + } = self; + write_vcd_var( + properties, + scope, + MemoryElementPartBody::TraceAsString { ty }, + writer, + "string", + 1, + location, + name, + ) + } +} + impl WriteTrace for TraceScope { fn write_trace(self, writer: &mut W, arg: A) -> io::Result<()> { match self { @@ -1093,6 +1123,7 @@ impl TraceWriterDecls for VcdWriterDecls { finished_init: false, timescale, properties, + trace_as_string_buf: String::with_capacity(256), }) } } @@ -1100,6 +1131,7 @@ impl TraceWriterDecls for VcdWriterDecls { enum MemoryElementPartBody { Scalar, EnumDiscriminant { ty: Enum }, + TraceAsString { ty: TraceAsString }, } struct MemoryElementPart { @@ -1217,6 +1249,7 @@ pub struct VcdWriter { finished_init: bool, timescale: SimDuration, properties: VcdWriterProperties, + trace_as_string_buf: String, } impl VcdWriter { @@ -1326,6 +1359,21 @@ impl TraceWriter for VcdWriter { .built_scalar_id_to_vcd_id(first_id + element_index), )? } + MemoryElementPartBody::TraceAsString { ty } => { + self.trace_as_string_buf.clear(); + ty.trace_fmt_append_to_string( + &mut self.trace_as_string_buf, + OpaqueSimValueSlice::from_bitslice(&element_data[start..start + len]), + ); + write_string_value_change( + &mut self.writer, + &self.trace_as_string_buf, + self.properties + .scalar_id_to_vcd_id_map + .built_scalar_id_to_vcd_id(first_id + element_index), + )?; + self.trace_as_string_buf.clear(); + } } } Ok(()) @@ -1419,6 +1467,16 @@ impl TraceWriter for VcdWriter { .built_scalar_id_to_vcd_id(id.as_usize()), ) } + + fn set_signal_string(&mut self, id: TraceScalarId, value: &str) -> Result<(), Self::Error> { + write_string_value_change( + &mut self.writer, + value, + self.properties + .scalar_id_to_vcd_id_map + .built_scalar_id_to_vcd_id(id.as_usize()), + ) + } } impl fmt::Debug for VcdWriter { @@ -1428,6 +1486,7 @@ impl fmt::Debug for VcdWriter { finished_init, timescale, properties: _, + trace_as_string_buf: _, } = self; f.debug_struct("VcdWriter") .field("finished_init", finished_init) diff --git a/crates/fayalite/src/ty.rs b/crates/fayalite/src/ty.rs index ed0ba03..843aedb 100644 --- a/crates/fayalite/src/ty.rs +++ b/crates/fayalite/src/ty.rs @@ -3,22 +3,28 @@ use crate::{ array::Array, - bundle::Bundle, + bundle::{Bundle, BundleField, BundleType}, clock::Clock, - enum_::Enum, - expr::Expr, + enum_::{Enum, EnumType, EnumVariant}, + expr::{Expr, HdlPartialEqImpl, HdlPartialOrdImpl, ToExpr, ValueType, Valueless, ops}, int::{Bool, SInt, UInt, UIntValue}, - intern::{Intern, Interned}, + intern::{Intern, Interned, LazyInterned, Memoize, SupportsPtrEqWithTypeId}, + module::transform::visit::{Fold, Folder, Visit, Visitor}, phantom_const::PhantomConst, reset::{AsyncReset, Reset, SyncReset}, - sim::value::{DynSimOnly, DynSimOnlyValue, SimValue, ToSimValueWithType}, + sim::value::{DynSimOnly, DynSimOnlyValue, SimValue, ToSimValue, ToSimValueWithType}, source_location::SourceLocation, - util::{ConstUsize, slice_range, try_slice_range}, + util::{ + ConstUsize, iter_eq_by, + serde_by_id::{SerdeByIdProperties, SerdeByIdTable, SerdeByIdTrait}, + slice_range, try_slice_range, + }, }; use bitvec::{slice::BitSlice, vec::BitVec}; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned}; use std::{ - fmt, + borrow::Cow, + fmt::{self, Write}, hash::Hash, iter::{FusedIterator, Sum}, marker::PhantomData, @@ -69,6 +75,7 @@ pub enum CanonicalType { Clock(Clock), PhantomConst(PhantomConst), DynSimOnly(DynSimOnly), + TraceAsString(TraceAsString), } impl fmt::Debug for CanonicalType { @@ -86,6 +93,7 @@ impl fmt::Debug for CanonicalType { Self::Clock(v) => v.fmt(f), Self::PhantomConst(v) => v.fmt(f), Self::DynSimOnly(v) => v.fmt(f), + Self::TraceAsString(v) => v.fmt(f), } } } @@ -123,6 +131,7 @@ impl CanonicalType { CanonicalType::Clock(v) => v.type_properties(), CanonicalType::PhantomConst(v) => v.type_properties(), CanonicalType::DynSimOnly(v) => v.type_properties(), + CanonicalType::TraceAsString(v) => v.type_properties(), } } pub fn is_passive(self) -> bool { @@ -217,11 +226,134 @@ impl CanonicalType { }; lhs.can_connect(rhs) } + CanonicalType::TraceAsString(lhs) => { + let CanonicalType::TraceAsString(rhs) = rhs else { + return false; + }; + lhs.can_connect(rhs) + } } } pub(crate) fn as_serde_unexpected_str(self) -> &'static str { serde_impls::SerdeCanonicalType::from(self).as_serde_unexpected_str() } + /// Unwrap transparent types until reaching a non-transparent type. Currently [`TraceAsString`] is the only transparent type. + /// + /// [`TraceAsString`]: struct@TraceAsString + pub fn unwrap_transparent_types(mut self) -> Self { + loop { + self = match self { + Self::UInt(_) + | Self::SInt(_) + | Self::Bool(_) + | Self::Array(_) + | Self::Enum(_) + | Self::Bundle(_) + | Self::AsyncReset(_) + | Self::SyncReset(_) + | Self::Reset(_) + | Self::Clock(_) + | Self::PhantomConst(_) + | Self::DynSimOnly(_) => return self, + Self::TraceAsString(ty) => ty.inner_ty(), + }; + } + } + pub fn is_layout_equivalent(self, other: Self) -> bool { + fn is_bit(ty: CanonicalType) -> bool { + match ty { + CanonicalType::UInt(ty) => ty.width() == 1, + CanonicalType::SInt(_) => false, // SInt<1> doesn't count since it would be -1/0 instead of 1/0 + CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) => true, + CanonicalType::Array(_) + | CanonicalType::Enum(_) + | CanonicalType::Bundle(_) + | CanonicalType::PhantomConst(_) + | CanonicalType::DynSimOnly(_) => false, + CanonicalType::TraceAsString(_) => { + unreachable!("handled by unwrap_transparent_types") + } + } + } + #[derive(Copy, Clone, PartialEq, Eq, Hash)] + struct MyMemoize; + impl Memoize for MyMemoize { + type Input = (CanonicalType, CanonicalType); + type InputOwned = (CanonicalType, CanonicalType); + type Output = bool; + + fn inner(self, input: &Self::Input) -> Self::Output { + let (this, other) = *input; + let this = this.unwrap_transparent_types(); + let other = other.unwrap_transparent_types(); + let this_is_bit = is_bit(this); + let other_is_bit = is_bit(other); + if this_is_bit || other_is_bit { + return this_is_bit && other_is_bit; + } + let this_is_empty = this.size().is_empty(); + let other_is_empty = other.size().is_empty(); + if this_is_empty || other_is_empty { + return this_is_empty && other_is_empty; + } + match this { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::DynSimOnly(_) => this == other, + CanonicalType::Array(this) => { + let CanonicalType::Array(other) = other else { + return false; + }; + this.len() == other.len() + && this.element().is_layout_equivalent(other.element()) + } + CanonicalType::Enum(this) => { + let CanonicalType::Enum(other) = other else { + return false; + }; + iter_eq_by( + this.variants(), + other.variants(), + |EnumVariant { name, ty }, other_variant| { + name == other_variant.name + && ty.unwrap_or_else(|| ().canonical()).is_layout_equivalent( + other_variant.ty.unwrap_or_else(|| ().canonical()), + ) + }, + ) + } + CanonicalType::Bundle(this) => { + let CanonicalType::Bundle(other) = other else { + return false; + }; + iter_eq_by( + this.fields().iter().filter(|f| !f.ty.size().is_empty()), + other.fields().iter().filter(|f| !f.ty.size().is_empty()), + |&BundleField { name, flipped, ty }, other_field| { + name == other_field.name + && flipped == other_field.flipped + && ty.is_layout_equivalent(other_field.ty) + }, + ) + } + CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) => unreachable!("handled by is_bit"), + CanonicalType::PhantomConst(_) => unreachable!("handled by is_empty"), + CanonicalType::TraceAsString(_) => { + unreachable!("handled by unwrap_transparent_types") + } + } + } + } + MyMemoize.get_owned((self, other)) + } } pub trait MatchVariantAndInactiveScope: Sized { @@ -328,6 +460,7 @@ impl_base_type!(Reset); impl_base_type!(Clock); impl_base_type!(PhantomConst); impl_base_type!(DynSimOnly); +impl_base_type!(TraceAsString); impl_base_type_serde!(Bool, "a Bool"); impl_base_type_serde!(Enum, "an Enum"); @@ -336,6 +469,7 @@ impl_base_type_serde!(AsyncReset, "an AsyncReset"); impl_base_type_serde!(SyncReset, "a SyncReset"); impl_base_type_serde!(Reset, "a Reset"); impl_base_type_serde!(Clock, "a Clock"); +impl_base_type_serde!(TraceAsString, "a TraceAsString"); impl sealed::BaseTypeSealed for CanonicalType {} @@ -473,6 +607,7 @@ impl Type for CanonicalType { CanonicalType::Clock(v) => v.mask_type().canonical(), CanonicalType::PhantomConst(v) => v.mask_type().canonical(), CanonicalType::DynSimOnly(v) => v.mask_type().canonical(), + CanonicalType::TraceAsString(v) => v.mask_type().canonical(), } } fn canonical(&self) -> CanonicalType { @@ -757,13 +892,34 @@ impl Sum for OpaqueSimValueSize { } } -#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] pub struct OpaqueSimValue { bits: UIntValue, #[serde(skip_serializing_if = "Vec::is_empty", default)] sim_only_values: Vec, } +impl Clone for OpaqueSimValue { + fn clone(&self) -> Self { + Self { + bits: self.bits.clone(), + sim_only_values: self.sim_only_values.clone(), + } + } + fn clone_from(&mut self, source: &Self) { + let Self { + bits, + sim_only_values, + } = self; + if let Some(bits) = Arc::get_mut(bits.arc_bitvec_mut()) { + bits.clone_from(source.bits.bits()); + } else { + *bits = source.bits.clone(); + } + sim_only_values.clone_from(&source.sim_only_values); + } +} + impl OpaqueSimValue { pub fn empty() -> Self { Self { @@ -1143,3 +1299,822 @@ impl Index for AsMaskWithoutGenerics { Interned::into_inner(Intern::intern_sized(ty.mask_type())) } } + +trait TraceAsStringTrait: fmt::Debug + 'static + Send + Sync + SupportsPtrEqWithTypeId { + fn trace_fmt(&self, opaque: OpaqueSimValueSlice<'_>, f: &mut fmt::Formatter<'_>) + -> fmt::Result; + fn serde_by_id_properties(&self) -> SerdeByIdProperties> { + SerdeByIdProperties::of::() + } + fn can_substitute_type(&self, new_type: CanonicalType) -> bool; +} + +#[derive(Clone, PartialEq, Eq, Hash)] +struct TraceAsStringState { + ty: Interned, + canonical_ty: CanonicalType, +} + +impl TraceAsStringState { + fn new(ty: Interned) -> Interned { + #[derive(Copy, Clone, PartialEq, Eq, Hash)] + struct MyMemoize(PhantomData); + impl Memoize for MyMemoize { + type Input = Interned; + type InputOwned = Interned; + type Output = Interned>; + + fn inner(self, input: &Self::Input) -> Self::Output { + TraceAsStringState { + ty: *input, + canonical_ty: input.canonical(), + } + .intern_sized() + } + } + MyMemoize(PhantomData).get_owned(ty) + } +} + +impl fmt::Debug for TraceAsStringState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.ty.fmt(f) + } +} + +impl TraceAsStringTrait for TraceAsStringState { + fn trace_fmt( + &self, + opaque: OpaqueSimValueSlice<'_>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + fmt::Debug::fmt(&Type::sim_value_from_opaque(&*self.ty, opaque), f) + } + fn can_substitute_type(&self, new_type: CanonicalType) -> bool { + self.canonical_ty.is_layout_equivalent(new_type) + } +} + +impl crate::intern::InternedCompare for dyn TraceAsStringTrait { + type InternedCompareKey = crate::intern::PtrEqWithTypeId; + + fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { + this.get_ptr_eq_with_type_id() + } +} + +impl SerdeByIdTrait for Interned { + fn serde_by_id_properties(&self) -> SerdeByIdProperties { + TraceAsStringTrait::serde_by_id_properties(&**self) + } + + fn static_table() -> &'static SerdeByIdTable { + static TABLE: SerdeByIdTable> = SerdeByIdTable::new(); + &TABLE + } + + const NAME: &'static str = "dyn TraceAsStringTrait"; +} + +/// When running the fayalite simulator, outputs a single string signal containing a formatted version of the inner value (uses [`fmt::Debug`] by default). +/// This is a transparent type, meaning [`CanonicalType::unwrap_transparent_types`] will unwrap this type. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct TraceAsString { + inner_ty: LazyInterned, + trace_as_string: LazyInterned, +} + +#[expect(non_upper_case_globals)] +pub const TraceAsString: TraceAsStringWithoutGenerics = TraceAsStringWithoutGenerics; + +impl fmt::Debug for TraceAsString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + inner_ty, + trace_as_string: _, + } = self; + f.debug_struct("TraceAsString") + .field("inner_ty", &inner_ty.interned()) + .finish_non_exhaustive() + } +} + +impl TraceAsString { + pub fn new(inner_ty: T) -> Self { + Self::new_interned(inner_ty.intern_sized()) + } + pub fn new_interned(inner_ty: Interned) -> Self { + Self { + inner_ty: LazyInterned::Interned(inner_ty), + trace_as_string: LazyInterned::Interned(Interned::cast_unchecked( + TraceAsStringState::new(inner_ty), + |v| -> &dyn TraceAsStringTrait { v }, + )), + } + } + pub fn interned_inner_ty(self) -> Interned { + self.inner_ty.interned() + } + pub fn inner_ty(self) -> T { + *self.interned_inner_ty() + } + /// create a new `TraceAsString` but try to keep the old formatting method + pub fn with_new_inner_ty(self, inner_ty: Interned) -> TraceAsString { + if self + .trace_as_string + .can_substitute_type(inner_ty.canonical()) + { + TraceAsString { + inner_ty: LazyInterned::Interned(inner_ty), + trace_as_string: self.trace_as_string, + } + } else { + TraceAsString::new_interned(inner_ty) + } + } + pub fn canonical_trace_as_string(self) -> TraceAsString { + let Self { + inner_ty, + trace_as_string, + } = self; + TraceAsString { + inner_ty: LazyInterned::Interned(inner_ty.interned().canonical().intern_sized()), + trace_as_string, + } + } + pub fn from_canonical_trace_as_string(canonical: TraceAsString) -> Self { + let TraceAsString { + inner_ty, + trace_as_string, + } = canonical; + Self { + inner_ty: LazyInterned::Interned( + T::from_canonical(*inner_ty.interned()).intern_sized(), + ), + trace_as_string, + } + } + pub fn type_properties(self) -> TypeProperties { + self.interned_inner_ty().canonical().type_properties() + } + pub fn can_connect(self, rhs: TraceAsString) -> bool { + self.interned_inner_ty() + .canonical() + .can_connect(rhs.interned_inner_ty().canonical()) + } + pub fn trace_fmt( + self, + opaque: OpaqueSimValueSlice<'_>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + self.trace_as_string.interned().trace_fmt(opaque, f) + } + pub fn trace_fmt_append_to_string(self, output: &mut String, opaque: OpaqueSimValueSlice<'_>) { + fn impl_fn( + trace_as_string: Interned, + output: &mut String, + opaque: OpaqueSimValueSlice<'_>, + ) { + let initial_len = output.len(); + if let Err(fmt::Error {}) = write!( + output, + "{}", + fmt::from_fn(|f| trace_as_string.trace_fmt(opaque, f)) + ) { + output.truncate(initial_len); + output.push_str(""); + } + } + impl_fn(self.trace_as_string.interned(), output, opaque) + } +} + +impl SimValueDebug for TraceAsString { + fn sim_value_debug( + value: &::SimValue, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + T::sim_value_debug(value.inner(), f) + } +} + +impl Type for TraceAsString { + type BaseType = TraceAsString; + type MaskType = T::MaskType; + type SimValue = TraceAsStringSimValue; + type MatchVariant = Expr; + type MatchActiveScope = (); + type MatchVariantAndInactiveScope = MatchVariantWithoutScope; + type MatchVariantsIter = std::iter::Once; + + fn match_variants( + this: Expr, + source_location: SourceLocation, + ) -> Self::MatchVariantsIter { + let _ = source_location; + std::iter::once(MatchVariantWithoutScope( + ops::TraceAsStringAsInner::new(this).to_expr(), + )) + } + + fn mask_type(&self) -> Self::MaskType { + self.inner_ty.mask_type() + } + + fn canonical(&self) -> CanonicalType { + CanonicalType::TraceAsString(self.canonical_trace_as_string()) + } + + fn from_canonical(canonical_type: CanonicalType) -> Self { + let CanonicalType::TraceAsString(canonical) = canonical_type else { + panic!("expected TraceAsString"); + }; + Self::from_canonical_trace_as_string(canonical) + } + + fn source_location() -> SourceLocation { + SourceLocation::builtin() + } + + fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { + TraceAsStringSimValue { + inner: SimValue::from_opaque(self.inner_ty(), opaque.to_owned()), + trace_as_string: self.trace_as_string.interned(), + } + } + + fn sim_value_clone_from_opaque( + &self, + value: &mut Self::SimValue, + opaque: OpaqueSimValueSlice<'_>, + ) { + self.inner_ty + .sim_value_clone_from_opaque(&mut value.inner, opaque); + } + + fn sim_value_to_opaque<'w>( + &self, + value: &Self::SimValue, + writer: OpaqueSimValueWriter<'w>, + ) -> OpaqueSimValueWritten<'w> { + self.inner_ty.sim_value_to_opaque(&value.inner, writer) + } +} + +impl TypeWithDeref for TraceAsString { + fn expr_deref(this: &Expr) -> &Self::MatchVariant { + Interned::into_inner( + ops::TraceAsStringAsInner::new(*this) + .to_expr() + .intern_sized(), + ) + } +} + +struct TraceAsStringStaticTypeHelper(PhantomData); + +impl Default for TraceAsStringStaticTypeHelper { + fn default() -> Self { + Self(PhantomData) + } +} + +impl From> for Interned { + fn from(_value: TraceAsStringStaticTypeHelper) -> Self { + Interned::cast_unchecked( + TraceAsStringState::new(T::TYPE.intern_sized()), + |v| -> &dyn TraceAsStringTrait { v }, + ) + } +} + +impl Default for TraceAsString { + fn default() -> Self { + Self::TYPE + } +} + +struct MakeType(Interned); + +impl From> for Interned { + fn from(value: MakeType) -> Self { + value.0 + } +} + +impl Default for MakeType { + fn default() -> Self { + Self(T::TYPE.intern_sized()) + } +} + +impl StaticType for TraceAsString { + const TYPE: Self = Self { + inner_ty: LazyInterned::new_const::>(), + trace_as_string: LazyInterned::new_const::>(), + }; + const MASK_TYPE: Self::MaskType = T::MASK_TYPE; + const TYPE_PROPERTIES: TypeProperties = T::TYPE_PROPERTIES; + const MASK_TYPE_PROPERTIES: TypeProperties = T::MASK_TYPE_PROPERTIES; +} + +#[doc(hidden)] +pub struct TraceAsStringWithoutGenerics; + +impl Index for TraceAsStringWithoutGenerics { + type Output = TraceAsString; + + fn index(&self, inner_ty: T) -> &Self::Output { + Interned::into_inner(TraceAsString::new(inner_ty).intern_sized()) + } +} + +#[derive(Clone)] +pub struct TraceAsStringSimValue { + inner: SimValue, + trace_as_string: Interned, +} + +#[derive(Serialize, Deserialize)] +#[serde(rename = "TraceAsStringSimValue")] +struct TraceAsStringSimValueSerde { + inner: T, + trace_as_string: crate::util::serde_by_id::SerdeById>, +} + +impl + Serialize> Serialize for TraceAsStringSimValue { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let Self { + inner, + trace_as_string, + } = self; + TraceAsStringSimValueSerde { + inner, + trace_as_string: crate::util::serde_by_id::SerdeById { + inner: *trace_as_string, + }, + } + .serialize(serializer) + } +} + +impl<'de, T: Type> + Deserialize<'de>> Deserialize<'de> + for TraceAsStringSimValue +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let TraceAsStringSimValueSerde { + inner, + trace_as_string: + crate::util::serde_by_id::SerdeById { + inner: trace_as_string, + }, + } = Deserialize::deserialize(deserializer)?; + Ok(Self { + inner, + trace_as_string, + }) + } +} + +impl TraceAsStringSimValue { + pub fn new_with_ty(inner: impl ToSimValueWithType, ty: TraceAsString) -> Self { + Self { + inner: inner.into_sim_value_with_type(ty.inner_ty()), + trace_as_string: ty.trace_as_string.interned(), + } + } + pub fn new(inner: impl ToSimValue) -> Self { + let inner = inner.into_sim_value(); + Self { + trace_as_string: TraceAsString::new(inner.ty()).trace_as_string.interned(), + inner, + } + } + pub fn into_inner(self) -> SimValue { + self.inner + } + pub fn inner(&self) -> &SimValue { + &self.inner + } + pub fn inner_mut(&mut self) -> &mut SimValue { + &mut self.inner + } +} + +impl ValueType for TraceAsStringSimValue { + type Type = TraceAsString; + type ValueCategory = crate::expr::value_category::ValueCategoryValue; + + fn ty(&self) -> Self::Type { + let inner_ty = self.inner.ty().intern_sized(); + if self + .trace_as_string + .can_substitute_type(inner_ty.canonical()) + { + TraceAsString { + inner_ty: LazyInterned::Interned(inner_ty), + trace_as_string: LazyInterned::Interned(self.trace_as_string), + } + } else { + TraceAsString::new_interned(inner_ty) + } + } +} + +impl ToExpr for TraceAsStringSimValue { + #[track_caller] + fn to_expr(&self) -> Expr { + let inner = self.inner.to_expr(); + let inner_canonical = Expr::canonical(inner); + let inner_ty = inner.ty().intern_sized(); + let ty = if self + .trace_as_string + .can_substitute_type(inner_canonical.ty()) + { + TraceAsString { + inner_ty: LazyInterned::Interned(inner_ty), + trace_as_string: LazyInterned::Interned(self.trace_as_string), + } + } else { + TraceAsString::new_interned(inner_ty) + }; + ops::ToTraceAsString::new(inner_canonical, ty).to_expr() + } +} + +impl ToSimValueWithType> for TraceAsStringSimValue { + fn to_sim_value_with_type(&self, ty: TraceAsString) -> SimValue> { + let inner = self.inner.to_sim_value_with_type(ty.inner_ty()); + SimValue::from_value( + ty, + TraceAsStringSimValue { + inner, + trace_as_string: ty.trace_as_string.interned(), + }, + ) + } + fn into_sim_value_with_type(self, ty: TraceAsString) -> SimValue> { + let inner = self.inner.into_sim_value_with_type(ty.inner_ty()); + SimValue::from_value( + ty, + TraceAsStringSimValue { + inner, + trace_as_string: ty.trace_as_string.interned(), + }, + ) + } +} + +impl ToSimValue for TraceAsStringSimValue { + fn to_sim_value(&self) -> SimValue { + SimValue::from_value(self.ty(), self.clone()) + } + fn into_sim_value(self) -> SimValue { + SimValue::from_value(self.ty(), self) + } +} + +impl fmt::Debug for TraceAsStringSimValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.inner, f) + } +} + +impl> fmt::Display for TraceAsStringSimValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.inner, f) + } +} + +impl Ord for TraceAsStringSimValue +where + SimValue: Ord, +{ + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.inner.cmp(&other.inner) + } +} + +impl PartialOrd> for TraceAsStringSimValue +where + SimValue: PartialOrd>, +{ + fn partial_cmp(&self, other: &TraceAsStringSimValue) -> Option { + self.inner.partial_cmp(&other.inner) + } +} + +impl Eq for TraceAsStringSimValue where SimValue: Eq {} + +impl Hash for TraceAsStringSimValue +where + SimValue: Hash, +{ + fn hash(&self, state: &mut H) { + self.inner.hash(state); + } +} + +impl Default for TraceAsStringSimValue +where + SimValue: Default, +{ + fn default() -> Self { + let inner = SimValue::default(); + Self { + trace_as_string: TraceAsString::new(inner.ty()).trace_as_string.interned(), + inner, + } + } +} + +impl PartialEq> for TraceAsStringSimValue +where + SimValue: PartialEq>, +{ + fn eq(&self, other: &TraceAsStringSimValue) -> bool { + self.inner == other.inner + } +} + +impl, State: ?Sized + Folder> Fold for TraceAsString { + fn fold(self, state: &mut State) -> Result { + state.fold_trace_as_string(self) + } + + fn default_fold(self, state: &mut State) -> Result { + Ok(self.with_new_inner_ty(self.interned_inner_ty().fold(state)?)) + } +} + +impl, State: ?Sized + Visitor> Visit for TraceAsString { + fn visit(&self, state: &mut State) -> Result<(), ::Error> { + state.visit_trace_as_string(self) + } + + fn default_visit(&self, state: &mut State) -> Result<(), ::Error> { + self.interned_inner_ty().visit(state) + } +} + +fn trace_as_string_cow_into_inner( + this: Cow<'_, SimValue>>, +) -> Cow<'_, SimValue> { + match this { + Cow::Borrowed(v) => Cow::Borrowed(&v.inner), + Cow::Owned(v) => Cow::Owned(SimValue::into_value(v).inner), + } +} + +fn trace_as_string_cow_into_inner_value( + this: Cow<'_, TraceAsStringSimValue>, +) -> Cow<'_, T::SimValue> { + match this { + Cow::Borrowed(v) => Cow::Borrowed(&v.inner), + Cow::Owned(v) => Cow::Owned(SimValue::into_value(v.inner)), + } +} + +impl, U: Type> HdlPartialEqImpl> for TraceAsString { + #[track_caller] + fn cmp_value_eq( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialEqImpl::cmp_value_eq( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_value_ne( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialEqImpl::cmp_value_ne( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_sim_value_eq( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialEqImpl::cmp_sim_value_eq( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_sim_value_ne( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialEqImpl::cmp_sim_value_ne( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_expr_eq(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialEqImpl::cmp_expr_eq(*lhs, *rhs) + } + + #[track_caller] + fn cmp_expr_ne(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialEqImpl::cmp_expr_ne(*lhs, *rhs) + } + + #[track_caller] + fn cmp_valueless_eq(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialEqImpl::cmp_valueless_eq( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } + + #[track_caller] + fn cmp_valueless_ne(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialEqImpl::cmp_valueless_ne( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } +} + +impl, U: Type> HdlPartialOrdImpl> for TraceAsString { + #[track_caller] + fn cmp_value_lt( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialOrdImpl::cmp_value_lt( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_value_le( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialOrdImpl::cmp_value_le( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_value_gt( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialOrdImpl::cmp_value_gt( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_value_ge( + lhs: Self, + lhs_value: Cow<'_, Self::SimValue>, + rhs: TraceAsString, + rhs_value: Cow<'_, as Type>::SimValue>, + ) -> bool { + HdlPartialOrdImpl::cmp_value_ge( + lhs.inner_ty(), + trace_as_string_cow_into_inner_value(lhs_value), + rhs.inner_ty(), + trace_as_string_cow_into_inner_value(rhs_value), + ) + } + + #[track_caller] + fn cmp_sim_value_lt( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialOrdImpl::cmp_sim_value_lt( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_sim_value_le( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialOrdImpl::cmp_sim_value_le( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_sim_value_gt( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialOrdImpl::cmp_sim_value_gt( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_sim_value_ge( + lhs: Cow<'_, SimValue>, + rhs: Cow<'_, SimValue>>, + ) -> SimValue { + HdlPartialOrdImpl::cmp_sim_value_ge( + trace_as_string_cow_into_inner(lhs), + trace_as_string_cow_into_inner(rhs), + ) + } + + #[track_caller] + fn cmp_expr_lt(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialOrdImpl::cmp_expr_lt(*lhs, *rhs) + } + + #[track_caller] + fn cmp_expr_le(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialOrdImpl::cmp_expr_le(*lhs, *rhs) + } + + #[track_caller] + fn cmp_expr_gt(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialOrdImpl::cmp_expr_gt(*lhs, *rhs) + } + + #[track_caller] + fn cmp_expr_ge(lhs: Expr, rhs: Expr>) -> Expr { + HdlPartialOrdImpl::cmp_expr_ge(*lhs, *rhs) + } + + #[track_caller] + fn cmp_valueless_lt(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialOrdImpl::cmp_valueless_lt( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } + + #[track_caller] + fn cmp_valueless_le(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialOrdImpl::cmp_valueless_le( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } + + #[track_caller] + fn cmp_valueless_gt(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialOrdImpl::cmp_valueless_gt( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } + + #[track_caller] + fn cmp_valueless_ge(lhs: Valueless, rhs: Valueless>) -> Valueless { + HdlPartialOrdImpl::cmp_valueless_ge( + Valueless::new(lhs.ty().inner_ty()), + Valueless::new(rhs.ty().inner_ty()), + ) + } +} diff --git a/crates/fayalite/src/ty/serde_impls.rs b/crates/fayalite/src/ty/serde_impls.rs index af324f9..d5b5551 100644 --- a/crates/fayalite/src/ty/serde_impls.rs +++ b/crates/fayalite/src/ty/serde_impls.rs @@ -12,7 +12,8 @@ use crate::{ prelude::PhantomConst, reset::{AsyncReset, Reset, SyncReset}, sim::value::DynSimOnly, - ty::{BaseType, CanonicalType}, + ty::{BaseType, CanonicalType, TraceAsString, TraceAsStringTrait}, + util::serde_by_id::SerdeById, }; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -38,6 +39,7 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for SerdePhantomConst< #[derive(Serialize, Deserialize)] #[serde(rename = "CanonicalType")] +#[expect(private_interfaces)] pub(crate) enum SerdeCanonicalType< ArrayElement = CanonicalType, ThePhantomConst = SerdePhantomConst>, @@ -65,6 +67,10 @@ pub(crate) enum SerdeCanonicalType< Clock, PhantomConst(ThePhantomConst), DynSimOnly(DynSimOnly), + TraceAsString { + inner_ty: Interned, + trace_as_string: SerdeById>, + }, } impl SerdeCanonicalType { @@ -82,6 +88,7 @@ impl SerdeCanonicalType "a Clock", Self::PhantomConst(_) => "a PhantomConst", Self::DynSimOnly(_) => "a SimOnlyValue", + Self::TraceAsString { .. } => "a TraceAsString", } } } @@ -109,6 +116,15 @@ impl From for SerdeCanonicalType { CanonicalType::Clock(Clock {}) => Self::Clock, CanonicalType::PhantomConst(ty) => Self::PhantomConst(SerdePhantomConst(ty.get())), CanonicalType::DynSimOnly(ty) => Self::DynSimOnly(ty), + CanonicalType::TraceAsString(TraceAsString { + inner_ty, + trace_as_string, + }) => Self::TraceAsString { + inner_ty: inner_ty.interned(), + trace_as_string: SerdeById { + inner: trace_as_string.interned(), + }, + }, } } } @@ -130,6 +146,13 @@ impl From for CanonicalType { Self::PhantomConst(PhantomConst::new_interned(value.0)) } SerdeCanonicalType::DynSimOnly(value) => Self::DynSimOnly(value), + SerdeCanonicalType::TraceAsString { + inner_ty, + trace_as_string, + } => Self::TraceAsString(TraceAsString { + inner_ty: crate::intern::LazyInterned::Interned(inner_ty), + trace_as_string: crate::intern::LazyInterned::Interned(trace_as_string.inner), + }), } } } diff --git a/crates/fayalite/src/util.rs b/crates/fayalite/src/util.rs index f1457de..6845d3c 100644 --- a/crates/fayalite/src/util.rs +++ b/crates/fayalite/src/util.rs @@ -46,3 +46,4 @@ pub(crate) use misc::{InternedStrCompareAsStr, chain, copy_le_bytes_to_bitslice} pub mod job_server; pub mod prefix_sum; pub mod ready_valid; +pub(crate) mod serde_by_id; diff --git a/crates/fayalite/src/util/serde_by_id.rs b/crates/fayalite/src/util/serde_by_id.rs new file mode 100644 index 0000000..3db4ab6 --- /dev/null +++ b/crates/fayalite/src/util/serde_by_id.rs @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use crate::util::HashMap; +use hashbrown::hash_map::Entry; +use serde::{Deserialize, Serialize, de::Error}; +use std::{ + any::TypeId, + borrow::Cow, + fmt::Write, + hash::{BuildHasher, Hash, Hasher}, + marker::PhantomData, + sync::Mutex, +}; + +pub(crate) struct SerdeByIdProperties { + type_id: TypeId, + type_name: &'static str, + _phantom: PhantomData T>, +} + +impl Clone for SerdeByIdProperties { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for SerdeByIdProperties {} + +impl SerdeByIdProperties { + pub fn of() -> Self { + Self { + type_id: TypeId::of::(), + type_name: std::any::type_name::(), + _phantom: PhantomData, + } + } +} + +pub(crate) trait SerdeByIdTrait: Hash + Eq + Clone + 'static + Send { + fn serde_by_id_properties(&self) -> SerdeByIdProperties; + fn static_table() -> &'static SerdeByIdTable; + const NAME: &'static str; +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] +#[serde(transparent)] +struct SerdeRandomId([u32; 4]); + +#[derive(Serialize, Deserialize)] +pub(crate) struct SerdeId<'a, T: SerdeByIdTrait> { + random_id: SerdeRandomId, + #[serde(borrow)] + type_name: Cow<'a, str>, + #[serde(skip)] + _phantom: PhantomData T>, +} + +impl<'a, T: SerdeByIdTrait> Clone for SerdeId<'a, T> { + fn clone(&self) -> Self { + Self { + random_id: self.random_id, + type_name: self.type_name.clone(), + _phantom: PhantomData, + } + } +} + +impl<'a, T: SerdeByIdTrait> Eq for SerdeId<'a, T> {} + +impl<'a, 'b, T: SerdeByIdTrait> PartialEq> for SerdeId<'a, T> { + fn eq(&self, other: &SerdeId<'b, T>) -> bool { + let Self { + random_id, + type_name, + _phantom: _, + } = self; + *random_id == other.random_id && *type_name == other.type_name + } +} + +impl<'a, T: SerdeByIdTrait> Hash for SerdeId<'a, T> { + fn hash(&self, state: &mut H) { + let Self { + random_id, + type_name: _, + _phantom: _, + } = self; + random_id.hash(state); + } +} + +struct SerdeByIdTableRest { + from_serde: HashMap, T>, + serde_id_random_state: std::hash::RandomState, + buffer: String, +} + +impl Default for SerdeByIdTableRest { + fn default() -> Self { + Self { + from_serde: Default::default(), + serde_id_random_state: Default::default(), + buffer: Default::default(), + } + } +} + +impl SerdeByIdTableRest { + fn add_new(&mut self, value: T) -> SerdeId<'static, T> { + let properties = value.serde_by_id_properties(); + 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, "{:?}", properties.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 key = SerdeId { + random_id: SerdeRandomId(std::array::from_fn(|i| { + let mut hasher = hasher.clone(); + i.hash(&mut hasher); + hasher.finish() as u32 + })), + type_name: Cow::Borrowed(properties.type_name), + _phantom: PhantomData, + }; + match self.from_serde.entry(key) { + Entry::Occupied(_) => continue, + Entry::Vacant(e) => { + let key = e.key().clone(); + e.insert(value); + return key; + } + } + } + } +} + +pub(crate) struct SerdeByIdTableMut { + to_serde: HashMap>, + rest: SerdeByIdTableRest, +} + +impl Default for SerdeByIdTableMut { + fn default() -> Self { + Self { + to_serde: Default::default(), + rest: Default::default(), + } + } +} + +impl SerdeByIdTableMut { + pub(crate) fn to_serde(&mut self, value: &T) -> SerdeId<'static, T> { + if let Some(retval) = self.to_serde.get(value) { + return retval.clone(); + } + self.to_serde_insert(value) + } + #[cold] + fn to_serde_insert(&mut self, value: &T) -> SerdeId<'static, T> { + let value = value.clone(); + let retval = self.rest.add_new(value.clone()); + self.to_serde.insert(value, retval.clone()); + retval + } + pub(crate) fn from_serde(&self, id: &SerdeId<'_, T>) -> Option { + self.rest.from_serde.get(id).cloned() + } +} + +pub(crate) struct SerdeByIdTable(Mutex>>); + +impl SerdeByIdTable { + pub(crate) const fn new() -> Self { + Self(Mutex::new(None)) + } + pub(crate) fn to_serde(&self, value: &T) -> SerdeId<'static, T> { + self.0 + .lock() + .expect("shouldn't be poison") + .get_or_insert_with( + #[cold] + || Default::default(), + ) + .to_serde(value) + } + pub(crate) fn from_serde(&self, id: &SerdeId<'_, T>) -> Option { + self.0 + .lock() + .expect("shouldn't be poison") + .get_or_insert_with( + #[cold] + || Default::default(), + ) + .from_serde(id) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, Ord, PartialOrd)] +pub(crate) struct SerdeById { + pub(crate) inner: T, +} + +impl<'de, T: SerdeByIdTrait> Deserialize<'de> for SerdeById { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let id = SerdeId::deserialize(deserializer)?; + let inner = T::static_table().from_serde(&id).ok_or_else(|| { + D::Error::custom(format_args!( + "doesn't match any {} that was serialized this time this program was run: type_name={:?}", + T::NAME, + id.type_name, + )) + })?; + Ok(Self { inner }) + } +} + +impl Serialize for SerdeById { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + T::static_table() + .to_serde(&self.inner) + .serialize(serializer) + } +} diff --git a/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs b/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs index 3e1ac0c..0f09979 100644 --- a/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs +++ b/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs @@ -546,7 +546,7 @@ impl Visitor for XdcFileWriter { base.source_location(), )? {}, } - match base.canonical_ty() { + match base.canonical_ty().unwrap_transparent_types() { CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) @@ -563,6 +563,9 @@ impl Visitor for XdcFileWriter { v, base.source_location(), )? {}, + CanonicalType::TraceAsString(_) => { + unreachable!("handled by unwrap_transparent_types") + } } self.required_dont_touch_targets.insert(target); match v { @@ -592,6 +595,7 @@ impl Visitor for XdcFileWriter { v, instance.source_location(), )? {}, + TargetBase::FormalInput(_) => unreachable!("FormalInput can't be annotated"), } } } diff --git a/crates/fayalite/src/wire.rs b/crates/fayalite/src/wire.rs index a350d9a..d167c5f 100644 --- a/crates/fayalite/src/wire.rs +++ b/crates/fayalite/src/wire.rs @@ -58,11 +58,13 @@ impl Wire { ty: T::from_canonical(ty), } } + #[track_caller] pub fn new_unchecked( scoped_name: ScopedNameId, source_location: SourceLocation, ty: T, ) -> Self { + scoped_name.0.assert_is_name_id(); Self { name: scoped_name, source_location, @@ -76,7 +78,7 @@ impl Wire { self.containing_module_name_id().0 } pub fn containing_module_name_id(&self) -> NameId { - self.name.0 + self.name.0.unwrap_name_id() } pub fn name(&self) -> Interned { self.name_id().0 diff --git a/crates/fayalite/tests/module.rs b/crates/fayalite/tests/module.rs index 9dc0107..5c62933 100644 --- a/crates/fayalite/tests/module.rs +++ b/crates/fayalite/tests/module.rs @@ -808,40 +808,8 @@ circuit check_enum_cmp_eq: connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2) connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]) - wire _cast_bits_to_array_expr_2: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0] - connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1] - connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2] - wire _cast_bits_to_array_expr_3: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0] - connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1] - connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2] - connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1]) - wire _cast_bits_to_array_expr_4: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0] - connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1] - connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2] - wire _cast_bits_to_array_expr_5: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0] - connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1] - connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2] - connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2]) + connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]) + connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]) wire _cast_array_to_bits_expr: UInt<1>[3] connect _cast_array_to_bits_expr[0], _array_literal_expr[0] connect _cast_array_to_bits_expr[1], _array_literal_expr[1] @@ -901,40 +869,8 @@ circuit check_enum_cmp_eq: connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2) connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]) - wire _cast_bits_to_array_expr_2: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0] - connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1] - connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2] - wire _cast_bits_to_array_expr_3: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0] - connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1] - connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2] - connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1]) - wire _cast_bits_to_array_expr_4: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(lhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0] - connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(lhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1] - connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(lhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2] - wire _cast_bits_to_array_expr_5: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(rhs.body, 2, 0), 0, 0) - connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0] - connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(rhs.body, 2, 0), 1, 1) - connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1] - connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(rhs.body, 2, 0), 2, 2) - connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2] - connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2]) + connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]) + connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]) wire _cast_array_to_bits_expr: UInt<1>[3] connect _cast_array_to_bits_expr[0], _array_literal_expr[0] connect _cast_array_to_bits_expr[1], _array_literal_expr[1] @@ -993,40 +929,8 @@ circuit check_enum_cmp_eq: connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2) connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2] connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]) - wire _cast_bits_to_array_expr_2: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0] - connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1] - connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2] - wire _cast_bits_to_array_expr_3: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0] - connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1] - connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2] - connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1]) - wire _cast_bits_to_array_expr_4: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0] - connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1] - connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2] - wire _cast_bits_to_array_expr_5: UInt<1>[3] - wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3] - connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0) - connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0] - connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1) - connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1] - connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2) - connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2] - connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2]) + connect _array_literal_expr[1], eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]) + connect _array_literal_expr[2], eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]) wire _cast_array_to_bits_expr: UInt<1>[3] connect _cast_array_to_bits_expr[0], _array_literal_expr[0] connect _cast_array_to_bits_expr[1], _array_literal_expr[1] @@ -3925,21 +3829,10 @@ circuit check_enum_connect_any: connect __connect_variant_body_1, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 8:1] HdlSome: wire __connect_variant_body_2: SInt<1> @[module-XXXXXXXXXX.rs 8:1] - wire _cast_bits_to_bundle_expr_1: Ty5 - wire _cast_bits_to_bundle_expr_flattened_1: Ty6 - connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 2, 0), 0, 0) - wire _cast_bits_to_enum_expr_1: Ty3 - when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.tag, 0)): - connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlNone) - else: - connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlSome) - connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_enum_expr_1 - connect _cast_bits_to_bundle_expr_flattened_1.body, bits(bits(i2.body, 2, 0), 2, 1) - connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body ; connect different types: ; lhs: SInt<1> ; rhs: SInt<2> - connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr_1.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1] + connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1] wire _bundle_literal_expr_2: Ty4 connect _bundle_literal_expr_2.tag, {|HdlNone, HdlSome|}(HdlSome) connect _bundle_literal_expr_2.body, asUInt(__connect_variant_body_2) @@ -3961,18 +3854,18 @@ circuit check_enum_connect_any: connect o1, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 8:1] C: wire __connect_variant_body_3: Ty8 @[module-XXXXXXXXXX.rs 8:1] - wire _cast_bits_to_bundle_expr_2: Ty8 - wire _cast_bits_to_bundle_expr_flattened_2: Ty9 - connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i2.body, 0, 0), 0, 0) - wire _cast_bits_to_enum_expr_2: Ty3 - when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)): - connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone) + wire _cast_bits_to_bundle_expr_1: Ty8 + wire _cast_bits_to_bundle_expr_flattened_1: Ty9 + connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_1: Ty3 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.tag, 0)): + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlNone) else: - connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome) - connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2 - connect _cast_bits_to_bundle_expr_flattened_2.body, UInt<0>(0) - connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body - connect __connect_variant_body_3, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 8:1] + connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_enum_expr_1 + connect _cast_bits_to_bundle_expr_flattened_1.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body + connect __connect_variant_body_3, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 8:1] wire _bundle_literal_expr_4: Ty1 connect _bundle_literal_expr_4.tag, {|A, B, C|}(C) wire _cast_bundle_to_bits_expr_1: Ty9 @@ -4001,18 +3894,18 @@ circuit check_enum_connect_any: connect o2, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 9:1] B: wire __connect_variant_body_5: Ty5 @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_3: Ty4 - wire _cast_bits_to_bundle_expr_flattened_3: Ty7 - connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 1, 0), 0, 0) - wire _cast_bits_to_enum_expr_3: Ty3 - when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)): - connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone) + wire _cast_bits_to_bundle_expr_2: Ty4 + wire _cast_bits_to_bundle_expr_flattened_2: Ty7 + connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i1.body, 1, 0), 0, 0) + wire _cast_bits_to_enum_expr_2: Ty3 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)): + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone) else: - connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome) - connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3 - connect _cast_bits_to_bundle_expr_flattened_3.body, bits(bits(i1.body, 1, 0), 1, 1) - connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body - match _cast_bits_to_bundle_expr_3.tag: @[module-XXXXXXXXXX.rs 9:1] + connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2 + connect _cast_bits_to_bundle_expr_flattened_2.body, bits(bits(i1.body, 1, 0), 1, 1) + connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body + match _cast_bits_to_bundle_expr_2.tag: @[module-XXXXXXXXXX.rs 9:1] HdlNone: wire _bundle_literal_expr_6: Ty5 connect _bundle_literal_expr_6.tag, {|HdlNone, HdlSome|}(HdlNone) @@ -4020,21 +3913,10 @@ circuit check_enum_connect_any: connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1] HdlSome: wire __connect_variant_body_6: SInt<2> @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_4: Ty4 - wire _cast_bits_to_bundle_expr_flattened_4: Ty7 - connect _cast_bits_to_bundle_expr_flattened_4.tag, bits(bits(i1.body, 1, 0), 0, 0) - wire _cast_bits_to_enum_expr_4: Ty3 - when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_4.tag, 0)): - connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome|}(HdlNone) - else: - connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome|}(HdlSome) - connect _cast_bits_to_bundle_expr_4.tag, _cast_bits_to_enum_expr_4 - connect _cast_bits_to_bundle_expr_flattened_4.body, bits(bits(i1.body, 1, 0), 1, 1) - connect _cast_bits_to_bundle_expr_4.body, _cast_bits_to_bundle_expr_flattened_4.body ; connect different types: ; lhs: SInt<2> ; rhs: SInt<1> - connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_4.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1] + connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1] wire _bundle_literal_expr_7: Ty5 connect _bundle_literal_expr_7.tag, {|HdlNone, HdlSome|}(HdlSome) connect _bundle_literal_expr_7.body, asUInt(__connect_variant_body_6) @@ -4056,18 +3938,18 @@ circuit check_enum_connect_any: connect o2, _bundle_literal_expr_8 @[module-XXXXXXXXXX.rs 9:1] C: wire __connect_variant_body_7: Ty8 @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_5: Ty8 - wire _cast_bits_to_bundle_expr_flattened_5: Ty9 - connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(bits(i1.body, 0, 0), 0, 0) - wire _cast_bits_to_enum_expr_5: Ty3 - when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_5.tag, 0)): - connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlNone) + wire _cast_bits_to_bundle_expr_3: Ty8 + wire _cast_bits_to_bundle_expr_flattened_3: Ty9 + connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 0, 0), 0, 0) + wire _cast_bits_to_enum_expr_3: Ty3 + when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)): + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone) else: - connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlSome) - connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_enum_expr_5 - connect _cast_bits_to_bundle_expr_flattened_5.body, UInt<0>(0) - connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body - connect __connect_variant_body_7, _cast_bits_to_bundle_expr_5 @[module-XXXXXXXXXX.rs 9:1] + connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome) + connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3 + connect _cast_bits_to_bundle_expr_flattened_3.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body + connect __connect_variant_body_7, _cast_bits_to_bundle_expr_3 @[module-XXXXXXXXXX.rs 9:1] wire _bundle_literal_expr_9: Ty2 connect _bundle_literal_expr_9.tag, {|A, B, C|}(C) wire _cast_bundle_to_bits_expr_3: Ty9 @@ -4134,16 +4016,10 @@ circuit check_enum_connect_any: connect __connect_variant_body_1, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 8:1] else: wire __connect_variant_body_2: SInt<1> @[module-XXXXXXXXXX.rs 8:1] - wire _cast_bits_to_bundle_expr_1: Ty3 - wire _cast_bits_to_bundle_expr_flattened_1: Ty3 - connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 2, 0), 0, 0) - connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_bundle_expr_flattened_1.tag - connect _cast_bits_to_bundle_expr_flattened_1.body, bits(bits(i2.body, 2, 0), 2, 1) - connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body ; connect different types: ; lhs: SInt<1> ; rhs: SInt<2> - connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr_1.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1] + connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1] wire _bundle_literal_expr_2: Ty2 connect _bundle_literal_expr_2.tag, UInt<1>(0h1) connect _bundle_literal_expr_2.body, asUInt(__connect_variant_body_2) @@ -4159,13 +4035,13 @@ circuit check_enum_connect_any: connect o1, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 8:1] else: wire __connect_variant_body_3: Ty4 @[module-XXXXXXXXXX.rs 8:1] - wire _cast_bits_to_bundle_expr_2: Ty4 - wire _cast_bits_to_bundle_expr_flattened_2: Ty4 - connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i2.body, 0, 0), 0, 0) - connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag - connect _cast_bits_to_bundle_expr_flattened_2.body, UInt<0>(0) - connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body - connect __connect_variant_body_3, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 8:1] + wire _cast_bits_to_bundle_expr_1: Ty4 + wire _cast_bits_to_bundle_expr_flattened_1: Ty4 + connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_bundle_expr_flattened_1.tag + connect _cast_bits_to_bundle_expr_flattened_1.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body + connect __connect_variant_body_3, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 8:1] wire _bundle_literal_expr_4: Ty0 connect _bundle_literal_expr_4.tag, UInt<2>(0h2) wire _cast_bundle_to_bits_expr_1: Ty4 @@ -4187,29 +4063,23 @@ circuit check_enum_connect_any: connect o2, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 9:1] else when eq(i1.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 9:1] wire __connect_variant_body_5: Ty3 @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_3: Ty2 - wire _cast_bits_to_bundle_expr_flattened_3: Ty2 - connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 1, 0), 0, 0) - connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag - connect _cast_bits_to_bundle_expr_flattened_3.body, bits(bits(i1.body, 1, 0), 1, 1) - connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body - when eq(_cast_bits_to_bundle_expr_3.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 9:1] + wire _cast_bits_to_bundle_expr_2: Ty2 + wire _cast_bits_to_bundle_expr_flattened_2: Ty2 + connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i1.body, 1, 0), 0, 0) + connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag + connect _cast_bits_to_bundle_expr_flattened_2.body, bits(bits(i1.body, 1, 0), 1, 1) + connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body + when eq(_cast_bits_to_bundle_expr_2.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 9:1] wire _bundle_literal_expr_6: Ty3 connect _bundle_literal_expr_6.tag, UInt<1>(0h0) connect _bundle_literal_expr_6.body, UInt<2>(0h0) connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1] else: wire __connect_variant_body_6: SInt<2> @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_4: Ty2 - wire _cast_bits_to_bundle_expr_flattened_4: Ty2 - connect _cast_bits_to_bundle_expr_flattened_4.tag, bits(bits(i1.body, 1, 0), 0, 0) - connect _cast_bits_to_bundle_expr_4.tag, _cast_bits_to_bundle_expr_flattened_4.tag - connect _cast_bits_to_bundle_expr_flattened_4.body, bits(bits(i1.body, 1, 0), 1, 1) - connect _cast_bits_to_bundle_expr_4.body, _cast_bits_to_bundle_expr_flattened_4.body ; connect different types: ; lhs: SInt<2> ; rhs: SInt<1> - connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_4.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1] + connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1] wire _bundle_literal_expr_7: Ty3 connect _bundle_literal_expr_7.tag, UInt<1>(0h1) connect _bundle_literal_expr_7.body, asUInt(__connect_variant_body_6) @@ -4225,13 +4095,13 @@ circuit check_enum_connect_any: connect o2, _bundle_literal_expr_8 @[module-XXXXXXXXXX.rs 9:1] else: wire __connect_variant_body_7: Ty4 @[module-XXXXXXXXXX.rs 9:1] - wire _cast_bits_to_bundle_expr_5: Ty4 - wire _cast_bits_to_bundle_expr_flattened_5: Ty4 - connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(bits(i1.body, 0, 0), 0, 0) - connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_bundle_expr_flattened_5.tag - connect _cast_bits_to_bundle_expr_flattened_5.body, UInt<0>(0) - connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body - connect __connect_variant_body_7, _cast_bits_to_bundle_expr_5 @[module-XXXXXXXXXX.rs 9:1] + wire _cast_bits_to_bundle_expr_3: Ty4 + wire _cast_bits_to_bundle_expr_flattened_3: Ty4 + connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 0, 0), 0, 0) + connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag + connect _cast_bits_to_bundle_expr_flattened_3.body, UInt<0>(0) + connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body + connect __connect_variant_body_7, _cast_bits_to_bundle_expr_3 @[module-XXXXXXXXXX.rs 9:1] wire _bundle_literal_expr_9: Ty1 connect _bundle_literal_expr_9.tag, UInt<2>(0h2) wire _cast_bundle_to_bits_expr_3: Ty4 diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index e57c064..80ae4c2 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -1,12 +1,19 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information +use bitvec::{order::Lsb0, view::BitView}; use fayalite::{ - memory::{ReadStruct, ReadWriteStruct, WriteStruct}, - module::{instance_with_loc, memory_with_init_and_loc, reg_builder_with_loc}, + assert_export_firrtl, + firrtl::ExportOptions, + memory::{ReadStruct, ReadWriteStruct, WriteStruct, splat_mask}, + module::{ + instance_with_loc, memory_with_init_and_loc, reg_builder_with_loc, + transform::simplify_enums::SimplifyEnumsKind, + }, prelude::*, reset::ResetType, sim::vcd::VcdWriterDecls, + ty::SimValueDebug, util::{RcWriter, ready_valid::queue}, }; use std::{collections::BTreeMap, num::NonZeroUsize, rc::Rc}; @@ -550,6 +557,150 @@ fn test_enums() { } } +#[hdl] +pub enum EnumWithSimpleBody { + A(UInt<8>), + B(UInt<8>), + C(UInt<8>), +} + +#[hdl_module(outline_generated)] +pub fn enum_with_simple_body() { + #[hdl] + let which_in: UInt<8> = m.input(); + #[hdl] + let data_in: UInt<8> = m.input(); + #[hdl] + let which_out: UInt<8> = m.output(); + #[hdl] + let data_out: UInt<8> = m.output(); + #[hdl] + let enum_out: EnumWithSimpleBody = m.output(); + + #[hdl] + if which_in.cmp_eq(0u8) { + connect(enum_out, EnumWithSimpleBody.A(data_in)); + } else if which_in.cmp_eq(1u8) { + connect(enum_out, EnumWithSimpleBody.B(data_in)); + } else { + connect(enum_out, EnumWithSimpleBody.C(data_in)); + } + + #[hdl] + match enum_out { + EnumWithSimpleBody::A(v) => { + connect(which_out, 0u8); + connect(data_out, v); + } + EnumWithSimpleBody::B(v) => { + connect(which_out, 1u8); + connect(data_out, v); + } + EnumWithSimpleBody::C(v) => { + connect(which_out, 2u8); + connect(data_out, v); + } + } +} + +#[hdl] +#[test] +fn test_enum_with_simple_body() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(enum_with_simple_body()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + for which in 0u8..=2 { + for data in (0..u8::MAX).step_by(45) { + sim.write(sim.io().which_in, which); + sim.write(sim.io().data_in, data); + sim.advance_time(SimDuration::from_micros(1)); + assert_eq!(sim.read(sim.io().which_out).as_int(), which); + assert_eq!(sim.read(sim.io().data_out).as_int(), data); + } + } + sim.flush_traces().unwrap(); + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + #[derive(Debug)] + struct WireState<'a> { + name: &'a str, + space_then_id: Option<&'a str>, + value: Option<&'a str>, + } + impl<'a> WireState<'a> { + fn new(name: &'a str) -> Self { + Self { + name, + space_then_id: None, + value: None, + } + } + } + let mut variant_wires = [ + WireState::new("A"), + WireState::new("B"), + WireState::new("C"), + ]; + // check that output .vcd has the proper values for all variants' wires + for (is_last, line) in vcd.lines().map(|line| (false, line)).chain([(true, "")]) { + if let Some(line) = line.strip_prefix("$var wire 8") + && let Some(line) = line.strip_suffix(" $end") + && let Some((space_then_id, state)) = variant_wires + .iter_mut() + .find_map(|state| Some((line.strip_suffix(state.name)?.strip_suffix(" ")?, state))) + { + assert_eq!(space_then_id.chars().next(), Some(' ')); + assert!( + space_then_id + .chars() + .skip(1) + .all(|ch| matches!(ch, '!'..='~')) + ); + assert_eq!(state.space_then_id.replace(space_then_id), None); + } else if line.starts_with("#") || is_last { + let Some(expected_value) = variant_wires[0].value else { + panic!( + "variant {} hasn't been initialized before a timestamp or EOF: {variant_wires:#?}\n\ + line={line:?}", + variant_wires[0].name, + ); + }; + for state in &variant_wires { + assert_eq!( + state.value, + Some(expected_value), + "at a timestamp or EOF: variant value for {} doesn't match expected value.\n\ + {variant_wires:#?}\nline={line:?}", + state.name, + ); + } + } else if line.starts_with("b") { + for state in &mut variant_wires { + let Some(space_then_id) = state.space_then_id else { + let name = state.name; + panic!( + "variant {name} hasn't had an id assigned yet: {variant_wires:#?}\n\ + line={line:?}", + ); + }; + if let Some(value) = line.strip_suffix(space_then_id) { + state.value = Some(value); + break; + } + } + } + } + if vcd != include_str!("sim/expected/enum_with_simple_body.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/enum_with_simple_body.txt") { + panic!(); + } +} + #[hdl_module(outline_generated)] pub fn memories() { #[hdl] @@ -2841,3 +2992,621 @@ fn test_queue_4_true_true() { include_str!("sim/expected/queue_4_true_true.txt"), ); } + +#[hdl(outline_generated, custom_debug(sim), cmp_eq)] +pub enum HasCustomDebug { + Text(UInt<512>), + FmtError, +} + +impl HasCustomDebug { + #[hdl] + pub fn new_sim(text: Result<&str, std::fmt::Error>) -> SimValue { + match text { + Ok(text) => { + let mut retval = HasCustomDebug.Text.zero(); + let src = text.as_bytes().view_bits::(); + let dest = retval.bits_mut(); + let len = src.len().min(dest.len()); + dest[..len].clone_from_bitslice(&src[..len]); + #[hdl(sim)] + HasCustomDebug.Text(retval) + } + Err(std::fmt::Error) => + { + #[hdl(sim)] + HasCustomDebug.FmtError() + } + } + } + pub fn new(text: Result<&str, std::fmt::Error>) -> Expr { + Self::new_sim(text).to_expr() + } +} + +impl SimValueDebug for HasCustomDebug { + #[hdl] + fn sim_value_debug( + value: &::SimValue, + f: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + if f.alternate() { + return #[hdl(sim)] + match value { + Self::FmtError => f.write_str("FmtError"), + Self::Text(text) => f.debug_tuple("Text").field(text).finish(), + }; + } + #[hdl(sim)] + match value { + Self::FmtError => Err(std::fmt::Error), + Self::Text(text) => { + assert_eq!(text.ty().width() % u8::BITS as usize, 0); + let mut bytes = vec![0u8; text.ty().width() / u8::BITS as usize]; + bytes + .view_bits_mut::() + .clone_from_bitslice(text.bits()); + if let Some(len) = bytes.iter().position(|b| *b == 0) { + bytes.truncate(len); + } + f.write_str(&String::from_utf8_lossy(&bytes)) + } + } + } +} + +#[hdl_module(outline_generated)] +pub fn sim_trace_as_string() { + #[hdl] + let clk: Clock = m.input(); + #[hdl] + let read: ReadStruct>, ConstUsize<8>> = m.input(); + #[hdl] + let write: WriteStruct, 2>, ConstUsize<8>> = m.input(); + #[hdl] + let mut mem = memory_with_init([[HasCustomDebug::new(Ok("")).to_trace_as_string(); 2]; 4]); + let read_port = mem.new_read_port(); + connect(read_port.clk, clk); + connect_any(read_port.addr, read.addr); + connect(read_port.en, read.en); + for (l, r) in read.data.iter().zip(read_port.data.iter()) { + connect(l, &**r); + } + let write_port = mem.new_write_port(); + connect(write_port.clk, clk); + connect_any(write_port.addr, write.addr); + connect(write_port.data, write.data); + connect(write_port.en, write.en); + connect(write_port.mask, write.mask); +} + +#[hdl] +#[test] +fn test_sim_trace_as_string() { + let _n = SourceLocation::normalize_files_for_tests(); + let m = sim_trace_as_string(); + let mut sim = Simulation::new(m); + // sim.set_breakpoints_unstable(Default::default(), true); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + sim.write(sim.io().clk, false); + sim.write(sim.io().read.clk, false); + sim.write(sim.io().write.clk, false); + #[derive(Debug)] + struct TestCase { + read: Option<(u8, [Result<&'static str, std::fmt::Error>; 2])>, + write_addr: Option, + write_data: [Result<&'static str, std::fmt::Error>; 2], + write_mask: [bool; 2], + } + const TEST_CASES: &[TestCase] = &[ + TestCase { + read: None, + write_addr: None, + write_data: [Ok(""); 2], + write_mask: [false; 2], + }, + TestCase { + read: None, + write_addr: Some(0), + write_data: [Ok("mem[0][0]"), Ok("mem[0][1]")], + write_mask: [true; 2], + }, + TestCase { + read: None, + write_addr: Some(1), + write_data: [Ok("mem[1][0]"), Ok("mem[1][1]")], + write_mask: [true; 2], + }, + TestCase { + read: None, + write_addr: Some(2), + write_data: [Ok("mem[2][0]"), Ok("mem[2][1]")], + write_mask: [true; 2], + }, + TestCase { + read: None, + write_addr: Some(3), + write_data: [Ok("mem[3][0]"), Ok("mem[3][1]")], + write_mask: [true; 2], + }, + TestCase { + read: Some((1, [Ok("mem[1][0]"), Ok("mem[1][1]")])), + write_addr: None, + write_data: [Err(std::fmt::Error), Err(std::fmt::Error)], + write_mask: [true; 2], + }, + TestCase { + read: Some((1, [Err(std::fmt::Error), Err(std::fmt::Error)])), + write_addr: Some(1), + write_data: [Err(std::fmt::Error), Err(std::fmt::Error)], + write_mask: [true; 2], + }, + ]; + for test_case in TEST_CASES { + let TestCase { + read, + write_addr, + write_data, + write_mask, + } = test_case; + sim.write(sim.io().read.addr, read.map(|v| v.0).unwrap_or(0)); + sim.write(sim.io().read.en, read.is_some()); + sim.write(sim.io().write.addr, write_addr.unwrap_or(0)); + sim.write(sim.io().write.en, write_addr.is_some()); + sim.write( + sim.io().write.data, + write_data.map(|v| HasCustomDebug::new_sim(v).to_trace_as_string()), + ); + sim.write( + sim.io().write.mask, + write_mask.map(|v| splat_mask(TraceAsString[HasCustomDebug], v.to_expr())), + ); + sim.write(sim.io().clk, false); + sim.advance_time(SimDuration::from_nanos(500)); + sim.write(sim.io().clk, true); + sim.advance_time(SimDuration::from_nanos(500)); + if let Some((_, expected_read_data)) = read { + let read_data = sim.read(sim.io().read.data); + let expected_read_data = expected_read_data + .map(HasCustomDebug::new_sim) + .into_sim_value(); + assert!( + *read_data.inner() == expected_read_data, + "{read_data:#?}\n!= {expected_read_data:#?}", + ); + } + } + sim.flush_traces().unwrap(); + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + if vcd != include_str!("sim/expected/sim_trace_as_string.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/sim_trace_as_string.txt") { + panic!(); + } +} + +#[test] +fn test_firrtl_trace_as_string() { + let _n = SourceLocation::normalize_files_for_tests(); + let m = sim_trace_as_string(); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m => + options: ExportOptions { + simplify_memories: false, + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0 +circuit sim_trace_as_string: %[[ + { + "class": "firrtl.annotations.MemoryFileInlineAnnotation", + "filename": "/test/sim_trace_as_string/mem.mem", + "hexOrBinary": "b", + "target": "~sim_trace_as_string|sim_trace_as_string>mem" + } +]] + type Ty0 = {|Text: UInt<512>, FmtError|} + type Ty1 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty0[2]} + type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]} + type Ty3 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty0[2]} + type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]} + module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1] + input clk: Clock @[module-XXXXXXXXXX.rs 2:1] + input `read`: Ty1 @[module-XXXXXXXXXX.rs 3:1] + input `write`: Ty2 @[module-XXXXXXXXXX.rs 4:1] + mem `mem`: @[module-XXXXXXXXXX.rs 5:1] + data-type => Ty0[2] + depth => 4 + read-latency => 0 + write-latency => 1 + read-under-write => old + reader => r0 + writer => w1 + connect `mem`.r0.clk, clk @[module-XXXXXXXXXX.rs 7:1] + ; connect different types: + ; lhs: UInt<2> + ; rhs: UInt<8> + connect `mem`.r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1] + connect `mem`.r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1] + connect `read`.data[0], `mem`.r0.data[0] @[module-XXXXXXXXXX.rs 10:1] + connect `read`.data[1], `mem`.r0.data[1] @[module-XXXXXXXXXX.rs 10:1] + connect `mem`.w1.clk, clk @[module-XXXXXXXXXX.rs 12:1] + ; connect different types: + ; lhs: UInt<2> + ; rhs: UInt<8> + connect `mem`.w1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1] + connect `mem`.w1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1] + connect `mem`.w1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1] + connect `mem`.w1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1] +"#, + "/test/sim_trace_as_string/mem.mem": r"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +", + }; + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m => + options: ExportOptions { + simplify_memories: true, + simplify_enums: None, + ..ExportOptions::default() + }, + "/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0 +circuit sim_trace_as_string: %[[ + { + "class": "firrtl.annotations.MemoryFileInlineAnnotation", + "filename": "/test/sim_trace_as_string/mem.mem", + "hexOrBinary": "b", + "target": "~sim_trace_as_string|sim_trace_as_string>mem" + } +]] + type Ty0 = {|Text: UInt<512>, FmtError|} + type Ty1 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty0[2]} + type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]} + type Ty3 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty0[2]} + type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]} + type Ty5 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: UInt<513>[2]} + type Ty6 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: UInt<513>[2], mask: UInt<1>[2]} + module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1] + input clk: Clock @[module-XXXXXXXXXX.rs 2:1] + input `read`: Ty1 @[module-XXXXXXXXXX.rs 3:1] + input `write`: Ty2 @[module-XXXXXXXXXX.rs 4:1] + mem `mem`: @[module-XXXXXXXXXX.rs 5:1] + data-type => UInt<513>[2] + depth => 4 + read-latency => 0 + write-latency => 1 + read-under-write => old + reader => r0 + writer => w1 + wire mem_r0: Ty3 @[module-XXXXXXXXXX.rs 6:1] + wire mem_w1: Ty4 @[module-XXXXXXXXXX.rs 11:1] + wire _cast_bits_to_enum_expr: Ty0 + wire _cast_bits_to_enum_expr_body: UInt<512> + connect _cast_bits_to_enum_expr_body, head(`mem`.r0.data[0], 512) + when eq(UInt<1>(0), tail(`mem`.r0.data[0], 512)): + connect _cast_bits_to_enum_expr, {|Text: UInt<512>, FmtError|}(Text, _cast_bits_to_enum_expr_body) + else: + connect _cast_bits_to_enum_expr, {|Text: UInt<512>, FmtError|}(FmtError) + connect mem_r0.data[0], _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 6:1] + wire _cast_bits_to_enum_expr_1: Ty0 + wire _cast_bits_to_enum_expr_body_1: UInt<512> + connect _cast_bits_to_enum_expr_body_1, head(`mem`.r0.data[1], 512) + when eq(UInt<1>(0), tail(`mem`.r0.data[1], 512)): + connect _cast_bits_to_enum_expr_1, {|Text: UInt<512>, FmtError|}(Text, _cast_bits_to_enum_expr_body_1) + else: + connect _cast_bits_to_enum_expr_1, {|Text: UInt<512>, FmtError|}(FmtError) + connect mem_r0.data[1], _cast_bits_to_enum_expr_1 @[module-XXXXXXXXXX.rs 6:1] + wire _cast_enum_to_bits_expr: UInt<513> + match mem_w1.data[0]: + Text(_cast_enum_to_bits_expr_Text): + connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_Text, UInt<1>(0)), 513) + FmtError: + connect _cast_enum_to_bits_expr, UInt<513>(1) + connect `mem`.w1.data[0], _cast_enum_to_bits_expr @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.mask[0], mem_w1.mask[0] @[module-XXXXXXXXXX.rs 11:1] + wire _cast_enum_to_bits_expr_1: UInt<513> + match mem_w1.data[1]: + Text(_cast_enum_to_bits_expr_Text_1): + connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_Text_1, UInt<1>(0)), 513) + FmtError: + connect _cast_enum_to_bits_expr_1, UInt<513>(1) + connect `mem`.w1.data[1], _cast_enum_to_bits_expr_1 @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.mask[1], mem_w1.mask[1] @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1] + connect `mem`.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1] + connect `mem`.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1] + connect `mem`.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1] + connect mem_r0.clk, clk @[module-XXXXXXXXXX.rs 7:1] + ; connect different types: + ; lhs: UInt<2> + ; rhs: UInt<8> + connect mem_r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1] + connect mem_r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1] + connect `read`.data[0], mem_r0.data[0] @[module-XXXXXXXXXX.rs 10:1] + connect `read`.data[1], mem_r0.data[1] @[module-XXXXXXXXXX.rs 10:1] + connect mem_w1.clk, clk @[module-XXXXXXXXXX.rs 12:1] + ; connect different types: + ; lhs: UInt<2> + ; rhs: UInt<8> + connect mem_w1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1] + connect mem_w1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1] + connect mem_w1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1] + connect mem_w1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1] +"#, + "/test/sim_trace_as_string/mem.mem": r"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +", + }; + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m => + options: ExportOptions { + simplify_memories: false, + simplify_enums: Some(SimplifyEnumsKind::SimplifyToEnumsWithNoBody), + ..ExportOptions::default() + }, + "/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0 +circuit sim_trace_as_string: %[[ + { + "class": "firrtl.annotations.MemoryFileInlineAnnotation", + "filename": "/test/sim_trace_as_string/mem.mem", + "hexOrBinary": "b", + "target": "~sim_trace_as_string|sim_trace_as_string>mem" + } +]] + type Ty0 = {|Text, FmtError|} + type Ty1 = {tag: Ty0, body: UInt<512>} + type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty1[2]} + type Ty3 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]} + type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]} + type Ty5 = {tag: UInt<1>, body: UInt<1>} + type Ty6 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: Ty5[2]} + type Ty7 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty1[2]} + module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1] + input clk: Clock @[module-XXXXXXXXXX.rs 2:1] + input `read`: Ty2 @[module-XXXXXXXXXX.rs 3:1] + input `write`: Ty3 @[module-XXXXXXXXXX.rs 4:1] + mem `mem`: @[module-XXXXXXXXXX.rs 5:1] + data-type => Ty1[2] + depth => 4 + read-latency => 0 + write-latency => 1 + read-under-write => old + reader => r0 + writer => w1 + wire mem_w1: Ty4 @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.data, mem_w1.data @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.mask[0].tag, mem_w1.mask[0] @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.mask[0].body, mem_w1.mask[0] @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.mask[1].tag, mem_w1.mask[1] @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.w1.mask[1].body, mem_w1.mask[1] @[module-XXXXXXXXXX.rs 11:1] + connect `mem`.r0.clk, clk @[module-XXXXXXXXXX.rs 7:1] + ; connect different types: + ; lhs: UInt<2> + ; rhs: UInt<8> + connect `mem`.r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1] + connect `mem`.r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1] + connect `read`.data[0], `mem`.r0.data[0] @[module-XXXXXXXXXX.rs 10:1] + connect `read`.data[1], `mem`.r0.data[1] @[module-XXXXXXXXXX.rs 10:1] + connect mem_w1.clk, clk @[module-XXXXXXXXXX.rs 12:1] + ; connect different types: + ; lhs: UInt<2> + ; rhs: UInt<8> + connect mem_w1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1] + connect mem_w1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1] + connect mem_w1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1] + connect mem_w1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1] +"#, + "/test/sim_trace_as_string/mem.mem": r"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +", + }; + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m => + options: ExportOptions { + simplify_memories: true, + simplify_enums: Some(SimplifyEnumsKind::SimplifyToEnumsWithNoBody), + ..ExportOptions::default() + }, + "/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0 +circuit sim_trace_as_string: %[[ + { + "class": "firrtl.annotations.MemoryFileInlineAnnotation", + "filename": "/test/sim_trace_as_string/mem_0_tag.mem", + "hexOrBinary": "b", + "target": "~sim_trace_as_string|sim_trace_as_string>mem_0_tag" + }, + { + "class": "firrtl.annotations.MemoryFileInlineAnnotation", + "filename": "/test/sim_trace_as_string/mem_0_body.mem", + "hexOrBinary": "h", + "target": "~sim_trace_as_string|sim_trace_as_string>mem_0_body" + }, + { + "class": "firrtl.annotations.MemoryFileInlineAnnotation", + "filename": "/test/sim_trace_as_string/mem_1_tag.mem", + "hexOrBinary": "b", + "target": "~sim_trace_as_string|sim_trace_as_string>mem_1_tag" + }, + { + "class": "firrtl.annotations.MemoryFileInlineAnnotation", + "filename": "/test/sim_trace_as_string/mem_1_body.mem", + "hexOrBinary": "h", + "target": "~sim_trace_as_string|sim_trace_as_string>mem_1_body" + } +]] + type Ty0 = {|Text, FmtError|} + type Ty1 = {tag: Ty0, body: UInt<512>} + type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty1[2]} + type Ty3 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]} + type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty1[2]} + type Ty5 = {tag: UInt<1>, body: UInt<1>} + type Ty6 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: Ty5[2]} + type Ty7 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: UInt<1>} + type Ty8 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: UInt<1>, mask: UInt<1>} + type Ty9 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: UInt<512>} + type Ty10 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: UInt<512>, mask: UInt<1>} + type Ty11 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]} + module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1] + input clk: Clock @[module-XXXXXXXXXX.rs 2:1] + input `read`: Ty2 @[module-XXXXXXXXXX.rs 3:1] + input `write`: Ty3 @[module-XXXXXXXXXX.rs 4:1] + mem mem_0_tag: @[module-XXXXXXXXXX.rs 5:1] + data-type => UInt<1> + depth => 4 + read-latency => 0 + write-latency => 1 + read-under-write => old + reader => r0 + writer => w1 + mem mem_0_body: @[module-XXXXXXXXXX.rs 5:1] + data-type => UInt<512> + depth => 4 + read-latency => 0 + write-latency => 1 + read-under-write => old + reader => r0 + writer => w1 + mem mem_1_tag: @[module-XXXXXXXXXX.rs 5:1] + data-type => UInt<1> + depth => 4 + read-latency => 0 + write-latency => 1 + read-under-write => old + reader => r0 + writer => w1 + mem mem_1_body: @[module-XXXXXXXXXX.rs 5:1] + data-type => UInt<512> + depth => 4 + read-latency => 0 + write-latency => 1 + read-under-write => old + reader => r0 + writer => w1 + wire mem_r0: Ty4 @[module-XXXXXXXXXX.rs 6:1] + wire mem_w1: Ty6 @[module-XXXXXXXXXX.rs 11:1] + wire _cast_bits_to_enum_expr: Ty0 + when eq(UInt<1>(0), tail(mem_0_tag.r0.data, 0)): + connect _cast_bits_to_enum_expr, {|Text, FmtError|}(Text) + else: + connect _cast_bits_to_enum_expr, {|Text, FmtError|}(FmtError) + connect mem_r0.data[0].tag, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 6:1] + wire _cast_enum_to_bits_expr: UInt<1> + match mem_w1.data[0].tag: + Text: + connect _cast_enum_to_bits_expr, UInt<1>(0) + FmtError: + connect _cast_enum_to_bits_expr, UInt<1>(1) + connect mem_0_tag.w1.data, _cast_enum_to_bits_expr @[module-XXXXXXXXXX.rs 11:1] + connect mem_0_tag.w1.mask, mem_w1.mask[0].tag @[module-XXXXXXXXXX.rs 11:1] + connect mem_0_tag.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1] + connect mem_0_tag.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1] + connect mem_0_tag.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1] + connect mem_0_tag.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1] + connect mem_0_tag.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1] + connect mem_0_tag.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1] + connect mem_r0.data[0].body, mem_0_body.r0.data @[module-XXXXXXXXXX.rs 6:1] + connect mem_0_body.w1.data, mem_w1.data[0].body @[module-XXXXXXXXXX.rs 11:1] + connect mem_0_body.w1.mask, mem_w1.mask[0].body @[module-XXXXXXXXXX.rs 11:1] + connect mem_0_body.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1] + connect mem_0_body.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1] + connect mem_0_body.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1] + connect mem_0_body.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1] + connect mem_0_body.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1] + connect mem_0_body.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1] + wire _cast_bits_to_enum_expr_1: Ty0 + when eq(UInt<1>(0), tail(mem_1_tag.r0.data, 0)): + connect _cast_bits_to_enum_expr_1, {|Text, FmtError|}(Text) + else: + connect _cast_bits_to_enum_expr_1, {|Text, FmtError|}(FmtError) + connect mem_r0.data[1].tag, _cast_bits_to_enum_expr_1 @[module-XXXXXXXXXX.rs 6:1] + wire _cast_enum_to_bits_expr_1: UInt<1> + match mem_w1.data[1].tag: + Text: + connect _cast_enum_to_bits_expr_1, UInt<1>(0) + FmtError: + connect _cast_enum_to_bits_expr_1, UInt<1>(1) + connect mem_1_tag.w1.data, _cast_enum_to_bits_expr_1 @[module-XXXXXXXXXX.rs 11:1] + connect mem_1_tag.w1.mask, mem_w1.mask[1].tag @[module-XXXXXXXXXX.rs 11:1] + connect mem_1_tag.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1] + connect mem_1_tag.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1] + connect mem_1_tag.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1] + connect mem_1_tag.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1] + connect mem_1_tag.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1] + connect mem_1_tag.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1] + connect mem_r0.data[1].body, mem_1_body.r0.data @[module-XXXXXXXXXX.rs 6:1] + connect mem_1_body.w1.data, mem_w1.data[1].body @[module-XXXXXXXXXX.rs 11:1] + connect mem_1_body.w1.mask, mem_w1.mask[1].body @[module-XXXXXXXXXX.rs 11:1] + connect mem_1_body.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1] + connect mem_1_body.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1] + connect mem_1_body.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1] + connect mem_1_body.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1] + connect mem_1_body.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1] + connect mem_1_body.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1] + wire mem_w1_1: Ty11 @[module-XXXXXXXXXX.rs 11:1] + connect mem_w1.addr, mem_w1_1.addr @[module-XXXXXXXXXX.rs 11:1] + connect mem_w1.en, mem_w1_1.en @[module-XXXXXXXXXX.rs 11:1] + connect mem_w1.clk, mem_w1_1.clk @[module-XXXXXXXXXX.rs 11:1] + connect mem_w1.data, mem_w1_1.data @[module-XXXXXXXXXX.rs 11:1] + connect mem_w1.mask[0].tag, mem_w1_1.mask[0] @[module-XXXXXXXXXX.rs 11:1] + connect mem_w1.mask[0].body, mem_w1_1.mask[0] @[module-XXXXXXXXXX.rs 11:1] + connect mem_w1.mask[1].tag, mem_w1_1.mask[1] @[module-XXXXXXXXXX.rs 11:1] + connect mem_w1.mask[1].body, mem_w1_1.mask[1] @[module-XXXXXXXXXX.rs 11:1] + connect mem_r0.clk, clk @[module-XXXXXXXXXX.rs 7:1] + ; connect different types: + ; lhs: UInt<2> + ; rhs: UInt<8> + connect mem_r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1] + connect mem_r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1] + connect `read`.data[0], mem_r0.data[0] @[module-XXXXXXXXXX.rs 10:1] + connect `read`.data[1], mem_r0.data[1] @[module-XXXXXXXXXX.rs 10:1] + connect mem_w1_1.clk, clk @[module-XXXXXXXXXX.rs 12:1] + ; connect different types: + ; lhs: UInt<2> + ; rhs: UInt<8> + connect mem_w1_1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1] + connect mem_w1_1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1] + connect mem_w1_1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1] + connect mem_w1_1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1] +"#, + "/test/sim_trace_as_string/mem_0_body.mem": r"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +", + "/test/sim_trace_as_string/mem_0_tag.mem": r"0 +0 +0 +0 +", + "/test/sim_trace_as_string/mem_1_body.mem": r"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +", + "/test/sim_trace_as_string/mem_1_tag.mem": r"0 +0 +0 +0 +", + }; +} diff --git a/crates/fayalite/tests/sim/expected/array_rw.txt b/crates/fayalite/tests/sim/expected/array_rw.txt index 2486eaa..271ec3c 100644 --- a/crates/fayalite/tests/sim/expected/array_rw.txt +++ b/crates/fayalite/tests/sim/expected/array_rw.txt @@ -424,8 +424,8 @@ Simulation { }, small_slots: StatePart { value: [ - 16 (modified), - 0 (modified), + 16, + 0, ], }, big_slots: StatePart { @@ -483,7 +483,7 @@ Simulation { 248, 252, 254, - 255 (modified), + 255, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt index 0df7f20..74c03a4 100644 --- a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt +++ b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt @@ -86,8 +86,8 @@ Simulation { value: [ 1, 0, - 1 (modified), - 0 (modified), + 1, + 0, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/connect_const.txt b/crates/fayalite/tests/sim/expected/connect_const.txt index 6cf4014..8193fc5 100644 --- a/crates/fayalite/tests/sim/expected/connect_const.txt +++ b/crates/fayalite/tests/sim/expected/connect_const.txt @@ -63,7 +63,7 @@ Simulation { big_slots: StatePart { value: [ 5, - 5 (modified), + 5, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/connect_const_reset.txt b/crates/fayalite/tests/sim/expected/connect_const_reset.txt index a75ff8a..5a64923 100644 --- a/crates/fayalite/tests/sim/expected/connect_const_reset.txt +++ b/crates/fayalite/tests/sim/expected/connect_const_reset.txt @@ -90,9 +90,9 @@ Simulation { value: [ 1, 1, - 1 (modified), - 1 (modified), - 1 (modified), + 1, + 1, + 1, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/counter_async.txt b/crates/fayalite/tests/sim/expected/counter_async.txt index 256e1b7..20d27ac 100644 --- a/crates/fayalite/tests/sim/expected/counter_async.txt +++ b/crates/fayalite/tests/sim/expected/counter_async.txt @@ -185,10 +185,10 @@ Simulation { }, small_slots: StatePart { value: [ - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), + 0, + 0, + 1, + 0, ], }, big_slots: StatePart { @@ -197,12 +197,12 @@ Simulation { 0, 3, 3, - 4 (modified), - 3 (modified), - 0 (modified), - 1 (modified), - 4 (modified), - 4 (modified), + 4, + 3, + 0, + 1, + 4, + 4, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/counter_sync.txt b/crates/fayalite/tests/sim/expected/counter_sync.txt index 1448f58..baa08e7 100644 --- a/crates/fayalite/tests/sim/expected/counter_sync.txt +++ b/crates/fayalite/tests/sim/expected/counter_sync.txt @@ -167,10 +167,10 @@ Simulation { }, small_slots: StatePart { value: [ - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), + 0, + 0, + 1, + 0, ], }, big_slots: StatePart { @@ -179,11 +179,11 @@ Simulation { 0, 3, 3, - 4 (modified), - 3 (modified), - 1 (modified), - 4 (modified), - 4 (modified), + 4, + 3, + 1, + 4, + 4, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/duplicate_names.txt b/crates/fayalite/tests/sim/expected/duplicate_names.txt index 394cfbb..76338e8 100644 --- a/crates/fayalite/tests/sim/expected/duplicate_names.txt +++ b/crates/fayalite/tests/sim/expected/duplicate_names.txt @@ -81,9 +81,9 @@ Simulation { big_slots: StatePart { value: [ 5, - 5 (modified), + 5, + 6, 6, - 6 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/enum_with_simple_body.txt b/crates/fayalite/tests/sim/expected/enum_with_simple_body.txt new file mode 100644 index 0000000..6b5af1c --- /dev/null +++ b/crates/fayalite/tests/sim/expected/enum_with_simple_body.txt @@ -0,0 +1,749 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Enum { + A, + B, + C, + }, + }, + ], + .. + }, + big_slots: StatePartLayout { + len: 33, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_in", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_in", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_out", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_out", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", + ty: Enum { + A(UInt<8>), + B(UInt<8>), + C(UInt<8>), + }, + }, + SlotDebugData { + name: "", + ty: UInt<10>, + }, + SlotDebugData { + name: "", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: ".0", + ty: UInt<2>, + }, + SlotDebugData { + name: ".1", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "", + ty: UInt<10>, + }, + SlotDebugData { + name: "", + ty: UInt<10>, + }, + SlotDebugData { + name: "", + ty: UInt<10>, + }, + SlotDebugData { + name: "", + ty: Enum { + A(UInt<8>), + B(UInt<8>), + C(UInt<8>), + }, + }, + SlotDebugData { + name: "", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: ".0", + ty: UInt<2>, + }, + SlotDebugData { + name: ".1", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "", + ty: UInt<10>, + }, + SlotDebugData { + name: "", + ty: UInt<10>, + }, + SlotDebugData { + name: "", + ty: UInt<10>, + }, + SlotDebugData { + name: "", + ty: Enum { + A(UInt<8>), + B(UInt<8>), + C(UInt<8>), + }, + }, + SlotDebugData { + name: ".0", + ty: UInt<2>, + }, + SlotDebugData { + name: ".1", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "", + ty: UInt<10>, + }, + SlotDebugData { + name: "", + ty: UInt<10>, + }, + SlotDebugData { + name: "", + ty: UInt<10>, + }, + SlotDebugData { + name: "", + ty: Enum { + A(UInt<8>), + B(UInt<8>), + C(UInt<8>), + }, + }, + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:1:1 + 0: Const { + dest: StatePartIndex(32), // (0x2) SlotDebugData { name: "", ty: UInt<8> }, + value: 0x2, + }, + 1: Const { + dest: StatePartIndex(27), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + value: 0x2, + }, + 2: Copy { + dest: StatePartIndex(25), // (0x2) SlotDebugData { name: ".0", ty: UInt<2> }, + src: StatePartIndex(27), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + }, + 3: Copy { + dest: StatePartIndex(26), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> }, + src: StatePartIndex(1), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_in", ty: UInt<8> }, + }, + 4: Shl { + dest: StatePartIndex(28), // (0x384) SlotDebugData { name: "", ty: UInt<10> }, + lhs: StatePartIndex(26), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> }, + rhs: 2, + }, + 5: Or { + dest: StatePartIndex(29), // (0x386) SlotDebugData { name: "", ty: UInt<10> }, + lhs: StatePartIndex(25), // (0x2) SlotDebugData { name: ".0", ty: UInt<2> }, + rhs: StatePartIndex(28), // (0x384) SlotDebugData { name: "", ty: UInt<10> }, + }, + 6: CastToUInt { + dest: StatePartIndex(30), // (0x386) SlotDebugData { name: "", ty: UInt<10> }, + src: StatePartIndex(29), // (0x386) SlotDebugData { name: "", ty: UInt<10> }, + dest_width: 10, + }, + 7: Copy { + dest: StatePartIndex(31), // (0x386) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + src: StatePartIndex(30), // (0x386) SlotDebugData { name: "", ty: UInt<10> }, + }, + 8: Const { + dest: StatePartIndex(20), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, + value: 0x1, + }, + 9: Copy { + dest: StatePartIndex(18), // (0x1) SlotDebugData { name: ".0", ty: UInt<2> }, + src: StatePartIndex(20), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, + }, + 10: Copy { + dest: StatePartIndex(19), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> }, + src: StatePartIndex(1), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_in", ty: UInt<8> }, + }, + 11: Shl { + dest: StatePartIndex(21), // (0x384) SlotDebugData { name: "", ty: UInt<10> }, + lhs: StatePartIndex(19), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> }, + rhs: 2, + }, + 12: Or { + dest: StatePartIndex(22), // (0x385) SlotDebugData { name: "", ty: UInt<10> }, + lhs: StatePartIndex(18), // (0x1) SlotDebugData { name: ".0", ty: UInt<2> }, + rhs: StatePartIndex(21), // (0x384) SlotDebugData { name: "", ty: UInt<10> }, + }, + 13: CastToUInt { + dest: StatePartIndex(23), // (0x385) SlotDebugData { name: "", ty: UInt<10> }, + src: StatePartIndex(22), // (0x385) SlotDebugData { name: "", ty: UInt<10> }, + dest_width: 10, + }, + 14: Copy { + dest: StatePartIndex(24), // (0x385) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + src: StatePartIndex(23), // (0x385) SlotDebugData { name: "", ty: UInt<10> }, + }, + 15: Const { + dest: StatePartIndex(16), // (0x1) SlotDebugData { name: "", ty: UInt<8> }, + value: 0x1, + }, + 16: CmpEq { + dest: StatePartIndex(17), // (0x0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(0), // (0x2) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_in", ty: UInt<8> }, + rhs: StatePartIndex(16), // (0x1) SlotDebugData { name: "", ty: UInt<8> }, + }, + 17: Const { + dest: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, + value: 0x0, + }, + 18: Copy { + dest: StatePartIndex(9), // (0x0) SlotDebugData { name: ".0", ty: UInt<2> }, + src: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, + }, + 19: Copy { + dest: StatePartIndex(10), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> }, + src: StatePartIndex(1), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_in", ty: UInt<8> }, + }, + 20: Shl { + dest: StatePartIndex(12), // (0x384) SlotDebugData { name: "", ty: UInt<10> }, + lhs: StatePartIndex(10), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> }, + rhs: 2, + }, + 21: Or { + dest: StatePartIndex(13), // (0x384) SlotDebugData { name: "", ty: UInt<10> }, + lhs: StatePartIndex(9), // (0x0) SlotDebugData { name: ".0", ty: UInt<2> }, + rhs: StatePartIndex(12), // (0x384) SlotDebugData { name: "", ty: UInt<10> }, + }, + 22: CastToUInt { + dest: StatePartIndex(14), // (0x384) SlotDebugData { name: "", ty: UInt<10> }, + src: StatePartIndex(13), // (0x384) SlotDebugData { name: "", ty: UInt<10> }, + dest_width: 10, + }, + 23: Copy { + dest: StatePartIndex(15), // (0x384) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + src: StatePartIndex(14), // (0x384) SlotDebugData { name: "", ty: UInt<10> }, + }, + 24: Const { + dest: StatePartIndex(7), // (0x0) SlotDebugData { name: "", ty: UInt<8> }, + value: 0x0, + }, + 25: CmpEq { + dest: StatePartIndex(8), // (0x0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(0), // (0x2) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_in", ty: UInt<8> }, + rhs: StatePartIndex(7), // (0x0) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:7:1 + 26: BranchIfZero { + target: 28, + value: StatePartIndex(8), // (0x0) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:8:1 + 27: Copy { + dest: StatePartIndex(4), // (0x386) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + src: StatePartIndex(15), // (0x384) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + }, + // at: module-XXXXXXXXXX.rs:7:1 + 28: BranchIfNonZero { + target: 33, + value: StatePartIndex(8), // (0x0) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:9:1 + 29: BranchIfZero { + target: 31, + value: StatePartIndex(17), // (0x0) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:10:1 + 30: Copy { + dest: StatePartIndex(4), // (0x386) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + src: StatePartIndex(24), // (0x385) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + }, + // at: module-XXXXXXXXXX.rs:9:1 + 31: BranchIfNonZero { + target: 33, + value: StatePartIndex(17), // (0x0) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:11:1 + 32: Copy { + dest: StatePartIndex(4), // (0x386) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + src: StatePartIndex(31), // (0x386) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 33: Copy { + dest: StatePartIndex(5), // (0x386) SlotDebugData { name: "", ty: UInt<10> }, + src: StatePartIndex(4), // (0x386) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + }, + 34: SliceInt { + dest: StatePartIndex(6), // (0xe1) SlotDebugData { name: "", ty: UInt<8> }, + src: StatePartIndex(5), // (0x386) SlotDebugData { name: "", ty: UInt<10> }, + start: 2, + len: 8, + }, + // at: module-XXXXXXXXXX.rs:6:1 + 35: AndBigWithSmallImmediate { + dest: StatePartIndex(0), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, + lhs: StatePartIndex(4), // (0x386) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} }, + rhs: 0x3, + }, + // at: module-XXXXXXXXXX.rs:12:1 + 36: BranchIfSmallNeImmediate { + target: 39, + lhs: StatePartIndex(0), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, + rhs: 0x0, + }, + // at: module-XXXXXXXXXX.rs:13:1 + 37: Copy { + dest: StatePartIndex(2), // (0x2) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_out", ty: UInt<8> }, + src: StatePartIndex(7), // (0x0) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:14:1 + 38: Copy { + dest: StatePartIndex(3), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_out", ty: UInt<8> }, + src: StatePartIndex(6), // (0xe1) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:12:1 + 39: BranchIfSmallNeImmediate { + target: 42, + lhs: StatePartIndex(0), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, + rhs: 0x1, + }, + // at: module-XXXXXXXXXX.rs:15:1 + 40: Copy { + dest: StatePartIndex(2), // (0x2) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_out", ty: UInt<8> }, + src: StatePartIndex(16), // (0x1) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:16:1 + 41: Copy { + dest: StatePartIndex(3), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_out", ty: UInt<8> }, + src: StatePartIndex(6), // (0xe1) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:12:1 + 42: BranchIfSmallNeImmediate { + target: 45, + lhs: StatePartIndex(0), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, + rhs: 0x2, + }, + // at: module-XXXXXXXXXX.rs:17:1 + 43: Copy { + dest: StatePartIndex(2), // (0x2) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_out", ty: UInt<8> }, + src: StatePartIndex(32), // (0x2) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:18:1 + 44: Copy { + dest: StatePartIndex(3), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_out", ty: UInt<8> }, + src: StatePartIndex(6), // (0xe1) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 45: Return, + ], + .. + }, + pc: 45, + memory_write_log: [], + memories: StatePart { + value: [], + }, + small_slots: StatePart { + value: [ + 2, + ], + }, + big_slots: StatePart { + value: [ + 2, + 225, + 2 (modified), + 225 (modified), + 902, + 902, + 225, + 0, + 0, + 0, + 225, + 0, + 900, + 900, + 900, + 900, + 1, + 0, + 1, + 225, + 1, + 900, + 901, + 901, + 901, + 2, + 225, + 2, + 900, + 902, + 902, + 902, + 2, + ], + }, + sim_only_slots: StatePart { + value: [], + }, + }, + io: Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }.which_in, + Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }.data_in, + Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }.which_out, + Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }.data_out, + Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }.enum_out, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }.data_in, + Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }.data_out, + Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }.enum_out, + Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }.which_in, + Instance { + name: ::enum_with_simple_body, + instantiated: Module { + name: enum_with_simple_body, + .. + }, + }.which_out, + }, + did_initial_settle: true, + clocks_for_past: {}, + }, + extern_modules: [], + trace_decls: TraceModule { + name: "enum_with_simple_body", + children: [ + TraceModuleIO { + name: "which_in", + child: TraceUInt { + location: TraceScalarId(0), + name: "which_in", + ty: UInt<8>, + flow: Source, + }, + ty: UInt<8>, + flow: Source, + }, + TraceModuleIO { + name: "data_in", + child: TraceUInt { + location: TraceScalarId(1), + name: "data_in", + ty: UInt<8>, + flow: Source, + }, + ty: UInt<8>, + flow: Source, + }, + TraceModuleIO { + name: "which_out", + child: TraceUInt { + location: TraceScalarId(2), + name: "which_out", + ty: UInt<8>, + flow: Sink, + }, + ty: UInt<8>, + flow: Sink, + }, + TraceModuleIO { + name: "data_out", + child: TraceUInt { + location: TraceScalarId(3), + name: "data_out", + ty: UInt<8>, + flow: Sink, + }, + ty: UInt<8>, + flow: Sink, + }, + TraceModuleIO { + name: "enum_out", + child: TraceEnumWithFields { + name: "enum_out", + discriminant: TraceEnumDiscriminant { + location: TraceScalarId(4), + name: "$tag", + ty: Enum { + A(UInt<8>), + B(UInt<8>), + C(UInt<8>), + }, + flow: Sink, + }, + non_empty_fields: [ + TraceUInt { + location: TraceScalarId(5), + name: "A", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(6), + name: "B", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(7), + name: "C", + ty: UInt<8>, + flow: Source, + }, + ], + ty: Enum { + A(UInt<8>), + B(UInt<8>), + C(UInt<8>), + }, + flow: Sink, + }, + ty: Enum { + A(UInt<8>), + B(UInt<8>), + C(UInt<8>), + }, + flow: Sink, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigUInt { + index: StatePartIndex(0), + ty: UInt<8>, + }, + maybe_changed: true, + state: 0x02, + last_state: 0x02, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigUInt { + index: StatePartIndex(1), + ty: UInt<8>, + }, + maybe_changed: true, + state: 0xe1, + last_state: 0xb4, + }, + SimTrace { + id: TraceScalarId(2), + kind: BigUInt { + index: StatePartIndex(2), + ty: UInt<8>, + }, + maybe_changed: true, + state: 0x02, + last_state: 0x02, + }, + SimTrace { + id: TraceScalarId(3), + kind: BigUInt { + index: StatePartIndex(3), + ty: UInt<8>, + }, + maybe_changed: true, + state: 0xe1, + last_state: 0xb4, + }, + SimTrace { + id: TraceScalarId(4), + kind: EnumDiscriminant { + index: StatePartIndex(0), + ty: Enum { + A(UInt<8>), + B(UInt<8>), + C(UInt<8>), + }, + }, + maybe_changed: true, + state: 0x2, + last_state: 0x2, + }, + SimTrace { + id: TraceScalarId(5), + kind: BigUInt { + index: StatePartIndex(6), + ty: UInt<8>, + }, + maybe_changed: true, + state: 0xe1, + last_state: 0xb4, + }, + SimTrace { + id: TraceScalarId(6), + kind: BigUInt { + index: StatePartIndex(6), + ty: UInt<8>, + }, + maybe_changed: true, + state: 0xe1, + last_state: 0xb4, + }, + SimTrace { + id: TraceScalarId(7), + kind: BigUInt { + index: StatePartIndex(6), + ty: UInt<8>, + }, + maybe_changed: true, + state: 0xe1, + last_state: 0xb4, + }, + ], + trace_memories: {}, + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + clocks_triggered: [], + event_queue: EventQueue(EventQueueData { + instant: 18 μs, + events: {}, + }), + waiting_sensitivity_sets_by_address: {}, + waiting_sensitivity_sets_by_compiled_value: {}, + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/enum_with_simple_body.vcd b/crates/fayalite/tests/sim/expected/enum_with_simple_body.vcd new file mode 100644 index 0000000..dfe0dc1 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/enum_with_simple_body.vcd @@ -0,0 +1,133 @@ +$timescale 1 ps $end +$scope module enum_with_simple_body $end +$var wire 8 J&-ne which_in $end +$var wire 8 \7mo/ data_in $end +$var wire 8 ,`>ir which_out $end +$var wire 8 0_gMP data_out $end +$scope struct enum_out $end +$var string 1 kFH/w \$tag $end +$var wire 8 |EI_= A $end +$var wire 8 !pRd4 B $end +$var wire 8 &RAbd C $end +$upscope $end +$upscope $end +$enddefinitions $end +$dumpvars +b0 J&-ne +b0 \7mo/ +b0 ,`>ir +b0 0_gMP +sA\x20(0) kFH/w +b0 |EI_= +b0 !pRd4 +b0 &RAbd +$end +#1000000 +b101101 \7mo/ +b101101 0_gMP +b101101 |EI_= +b101101 !pRd4 +b101101 &RAbd +#2000000 +b1011010 \7mo/ +b1011010 0_gMP +b1011010 |EI_= +b1011010 !pRd4 +b1011010 &RAbd +#3000000 +b10000111 \7mo/ +b10000111 0_gMP +b10000111 |EI_= +b10000111 !pRd4 +b10000111 &RAbd +#4000000 +b10110100 \7mo/ +b10110100 0_gMP +b10110100 |EI_= +b10110100 !pRd4 +b10110100 &RAbd +#5000000 +b11100001 \7mo/ +b11100001 0_gMP +b11100001 |EI_= +b11100001 !pRd4 +b11100001 &RAbd +#6000000 +b1 J&-ne +b0 \7mo/ +b1 ,`>ir +b0 0_gMP +sB\x20(1) kFH/w +b0 |EI_= +b0 !pRd4 +b0 &RAbd +#7000000 +b101101 \7mo/ +b101101 0_gMP +b101101 |EI_= +b101101 !pRd4 +b101101 &RAbd +#8000000 +b1011010 \7mo/ +b1011010 0_gMP +b1011010 |EI_= +b1011010 !pRd4 +b1011010 &RAbd +#9000000 +b10000111 \7mo/ +b10000111 0_gMP +b10000111 |EI_= +b10000111 !pRd4 +b10000111 &RAbd +#10000000 +b10110100 \7mo/ +b10110100 0_gMP +b10110100 |EI_= +b10110100 !pRd4 +b10110100 &RAbd +#11000000 +b11100001 \7mo/ +b11100001 0_gMP +b11100001 |EI_= +b11100001 !pRd4 +b11100001 &RAbd +#12000000 +b10 J&-ne +b0 \7mo/ +b10 ,`>ir +b0 0_gMP +sC\x20(2) kFH/w +b0 |EI_= +b0 !pRd4 +b0 &RAbd +#13000000 +b101101 \7mo/ +b101101 0_gMP +b101101 |EI_= +b101101 !pRd4 +b101101 &RAbd +#14000000 +b1011010 \7mo/ +b1011010 0_gMP +b1011010 |EI_= +b1011010 !pRd4 +b1011010 &RAbd +#15000000 +b10000111 \7mo/ +b10000111 0_gMP +b10000111 |EI_= +b10000111 !pRd4 +b10000111 &RAbd +#16000000 +b10110100 \7mo/ +b10110100 0_gMP +b10110100 |EI_= +b10110100 !pRd4 +b10110100 &RAbd +#17000000 +b11100001 \7mo/ +b11100001 0_gMP +b11100001 |EI_= +b11100001 !pRd4 +b11100001 &RAbd +#18000000 diff --git a/crates/fayalite/tests/sim/expected/enums.txt b/crates/fayalite/tests/sim/expected/enums.txt index 2b00f05..d2da2d9 100644 --- a/crates/fayalite/tests/sim/expected/enums.txt +++ b/crates/fayalite/tests/sim/expected/enums.txt @@ -1191,10 +1191,10 @@ Simulation { value: [ 0, 0, - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), + 0, + 0, + 1, + 0, 2, ], }, @@ -1207,110 +1207,110 @@ Simulation { 15, 2, 15, - 0 (modified), 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 62 (modified), - 62 (modified), - 0 (modified), - 0 (modified), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 62, + 62, + 0, + 0, + 1, + 1, + 62, + 3, + 1, 1, 1, - 62 (modified), - 3 (modified), - 1 (modified), - 1 (modified), - 1 (modified), 1, 1, -1, - 1 (modified), - 1 (modified), - 15 (modified), - 3 (modified), - 1 (modified), - 1 (modified), - 3 (modified), - -1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 2 (modified), - 3 (modified), - 12 (modified), - 13 (modified), - 13 (modified), - 13 (modified), - 2 (modified), - 1 (modified), - 1 (modified), - -1 (modified), - 2 (modified), - 1 (modified), - 1 (modified), - -1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 3 (modified), - -1 (modified), - 2 (modified), - 3 (modified), - 3 (modified), - 12 (modified), - 15 (modified), - 60 (modified), - 62 (modified), - 62 (modified), - 62 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 2 (modified), - 3 (modified), - 3 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 2 (modified), - 3 (modified), - 6 (modified), - 7 (modified), - 7 (modified), - 7 (modified), - 2 (modified), - 3 (modified), - 3 (modified), - 12 (modified), - 15 (modified), + 1, + 1, + 15, + 3, + 1, + 1, + 3, + -1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 3, + 12, + 13, + 13, + 13, + 2, + 1, + 1, + -1, + 2, + 1, + 1, + -1, + 1, + 1, + 1, + 3, + -1, + 2, + 3, + 3, + 12, + 15, + 60, + 62, + 62, + 62, + 0, + 0, + 0, + 1, + 2, + 3, + 3, + 1, + 1, + 1, + 1, + 1, + 2, + 3, + 6, + 7, + 7, + 7, + 2, + 3, + 3, + 12, + 15, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/last_connect.txt b/crates/fayalite/tests/sim/expected/last_connect.txt index 297d395..c5d1341 100644 --- a/crates/fayalite/tests/sim/expected/last_connect.txt +++ b/crates/fayalite/tests/sim/expected/last_connect.txt @@ -418,39 +418,39 @@ Simulation { }, big_slots: StatePart { value: [ - 31 (modified), + 31, + 1, + 1, + 1, + 1, + 31, + 15, + 1, + 1, + 1, + 1, 1, 1, 1, 1, - 31 (modified), - 15 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 7 (modified), 7 (modified), + 7, 3, - 0 (modified), - 0 (modified), + 0, + 0, + 3, + 1, + 3, + 1, + 6, + 7, + 7, + 7, + 4, + 0, + 1, + 2, 3, - 1 (modified), - 3 (modified), - 1 (modified), - 6 (modified), - 7 (modified), - 7 (modified), - 7 (modified), - 4 (modified), - 0 (modified), - 1 (modified), - 2 (modified), - 3 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/many_memories.txt b/crates/fayalite/tests/sim/expected/many_memories.txt index 84d9162..0d1a6db 100644 --- a/crates/fayalite/tests/sim/expected/many_memories.txt +++ b/crates/fayalite/tests/sim/expected/many_memories.txt @@ -2910,102 +2910,102 @@ Simulation { }, small_slots: StatePart { value: [ - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 15 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 15 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 15 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 15 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 15 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 15 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 15 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 15 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 15, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 15, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 15, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 15, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 15, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 15, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 15, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 15, + 1, + 0, + 0, + 0, + 0, + 0, + 0, ], }, big_slots: StatePart { @@ -3091,8 +3091,8 @@ Simulation { 0, 0, 1, - 0 (modified), - 1 (modified), + 0, + 1, 15, 1, 0, @@ -3102,8 +3102,8 @@ Simulation { 0, 0, 1, - 0 (modified), - 1 (modified), + 0, + 1, 15, 1, 0, @@ -3113,8 +3113,8 @@ Simulation { 0, 0, 1, - 0 (modified), - 1 (modified), + 0, + 1, 15, 1, 0, @@ -3124,8 +3124,8 @@ Simulation { 0, 0, 1, - 0 (modified), - 1 (modified), + 0, + 1, 15, 1, 0, @@ -3135,8 +3135,8 @@ Simulation { 0, 0, 1, - 0 (modified), - 1 (modified), + 0, + 1, 15, 1, 0, @@ -3146,8 +3146,8 @@ Simulation { 0, 0, 1, - 0 (modified), - 1 (modified), + 0, + 1, 15, 1, 0, @@ -3157,8 +3157,8 @@ Simulation { 0, 0, 1, - 0 (modified), - 1 (modified), + 0, + 1, 15, 1, 0, @@ -3168,8 +3168,8 @@ Simulation { 0, 0, 1, - 0 (modified), - 1 (modified), + 0, + 1, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/memories.txt b/crates/fayalite/tests/sim/expected/memories.txt index db5a2f3..c96da4f 100644 --- a/crates/fayalite/tests/sim/expected/memories.txt +++ b/crates/fayalite/tests/sim/expected/memories.txt @@ -522,18 +522,18 @@ Simulation { }, small_slots: StatePart { value: [ - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 2 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 2 (modified), - 2 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, ], }, big_slots: StatePart { @@ -562,10 +562,10 @@ Simulation { -32, 1, 1, - 208 (modified), - -32 (modified), - 1 (modified), - 1 (modified), + 208, + -32, + 1, + 1, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/memories2.txt b/crates/fayalite/tests/sim/expected/memories2.txt index 5a82b91..1f78fcf 100644 --- a/crates/fayalite/tests/sim/expected/memories2.txt +++ b/crates/fayalite/tests/sim/expected/memories2.txt @@ -545,15 +545,15 @@ Simulation { value: [ 0, 0, - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], }, big_slots: StatePart { @@ -568,32 +568,32 @@ Simulation { 0, 0, 0, - 0 (modified), 0, - 0 (modified), 0, - 0 (modified), - 0 (modified), 0, - 0 (modified), - 0 (modified), 0, - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/memories3.txt b/crates/fayalite/tests/sim/expected/memories3.txt index 7522430..75720a8 100644 --- a/crates/fayalite/tests/sim/expected/memories3.txt +++ b/crates/fayalite/tests/sim/expected/memories3.txt @@ -1356,20 +1356,20 @@ Simulation { }, small_slots: StatePart { value: [ - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], }, big_slots: StatePart { @@ -1415,22 +1415,6 @@ Simulation { 0, 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), 0, 0, 0, @@ -1450,38 +1434,54 @@ Simulation { 0, 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/mod1.txt b/crates/fayalite/tests/sim/expected/mod1.txt index 7f89a66..a1de89a 100644 --- a/crates/fayalite/tests/sim/expected/mod1.txt +++ b/crates/fayalite/tests/sim/expected/mod1.txt @@ -207,11 +207,11 @@ Simulation { -2, -2, 15, - -2 (modified), - 14 (modified), - 5 (modified), - 1 (modified), - 15 (modified), + -2, + 14, + 5, + 1, + 15, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/phantom_const.txt b/crates/fayalite/tests/sim/expected/phantom_const.txt index 864a4f7..c9adae4 100644 --- a/crates/fayalite/tests/sim/expected/phantom_const.txt +++ b/crates/fayalite/tests/sim/expected/phantom_const.txt @@ -185,11 +185,11 @@ Simulation { }, small_slots: StatePart { value: [ - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 0, + 0, ], }, big_slots: StatePart { @@ -197,11 +197,11 @@ Simulation { 0, 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 0, + 0, + 0, + 0, + 0, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_1_false_false.txt b/crates/fayalite/tests/sim/expected/queue_1_false_false.txt index 1ac0403..e349bbd 100644 --- a/crates/fayalite/tests/sim/expected/queue_1_false_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_1_false_false.txt @@ -1098,35 +1098,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 51 (modified), + 51, 0, - 51 (modified), + 51, 25, - 51 (modified), + 51, 0, - 51 (modified), + 51, 25, 1, 0, @@ -1138,56 +1138,56 @@ Simulation { 0, 25, 1, - 25 (modified), - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1, - 1 (modified), - 0 (modified), - 0, - 0, - 0, - 0, - 1, - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 1, - 1 (modified), - 1 (modified), 25, - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 25 (modified), - 1 (modified), - 50 (modified), - 51 (modified), - 51 (modified), - 51 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 25, + 0, + 0, + 1, + 1, + 25, + 1, + 50, + 51, + 51, + 51, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_1_false_true.txt b/crates/fayalite/tests/sim/expected/queue_1_false_true.txt index 5b56068..3a31636 100644 --- a/crates/fayalite/tests/sim/expected/queue_1_false_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_1_false_true.txt @@ -1079,35 +1079,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 63 (modified), + 63, 0, - 63 (modified), + 63, 31, - 63 (modified), + 63, 0, - 63 (modified), + 63, 31, 1, 0, @@ -1119,54 +1119,54 @@ Simulation { 0, 31, 1, - 31 (modified), - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1, - 1 (modified), - 0 (modified), - 0, - 0, - 0, - 0, - 1, - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 1, - 1 (modified), - 1 (modified), 31, - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 31 (modified), - 1 (modified), - 62 (modified), - 63 (modified), - 63 (modified), - 63 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 31, + 0, + 0, + 1, + 1, + 31, + 1, + 62, + 63, + 63, + 63, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_1_true_false.txt b/crates/fayalite/tests/sim/expected/queue_1_true_false.txt index 6076237..9dd3851 100644 --- a/crates/fayalite/tests/sim/expected/queue_1_true_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_1_true_false.txt @@ -1108,35 +1108,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 63 (modified), + 63, 0, - 63 (modified), + 63, 31, - 63 (modified), + 63, 0, - 63 (modified), + 63, 31, 1, 0, @@ -1148,56 +1148,56 @@ Simulation { 0, 31, 1, - 31 (modified), - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1, - 1 (modified), - 0 (modified), - 0, - 0, - 0, - 0, - 1, - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 1, - 1 (modified), - 1 (modified), 31, - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 31 (modified), - 1 (modified), - 62 (modified), - 63 (modified), - 63 (modified), - 63 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 31, + 0, + 0, + 1, + 1, + 31, + 1, + 62, + 63, + 63, + 63, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_1_true_true.txt b/crates/fayalite/tests/sim/expected/queue_1_true_true.txt index 8fe32ad..5762f24 100644 --- a/crates/fayalite/tests/sim/expected/queue_1_true_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_1_true_true.txt @@ -1089,35 +1089,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 71 (modified), + 71, 0, - 71 (modified), + 71, 35, - 71 (modified), + 71, 0, - 71 (modified), + 71, 35, 1, 0, @@ -1129,54 +1129,54 @@ Simulation { 0, 35, 1, - 35 (modified), - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1, - 1 (modified), - 0 (modified), - 0, - 0, - 0, - 0, - 1, - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 1, - 1 (modified), - 1 (modified), 35, - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 35 (modified), - 1 (modified), - 70 (modified), - 71 (modified), - 71 (modified), - 71 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 35, + 0, + 0, + 1, + 1, + 35, + 1, + 70, + 71, + 71, + 71, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_2_false_false.txt b/crates/fayalite/tests/sim/expected/queue_2_false_false.txt index 5a5c47d..c2cb51a 100644 --- a/crates/fayalite/tests/sim/expected/queue_2_false_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_2_false_false.txt @@ -1114,35 +1114,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 71 (modified), + 71, 1, - 71 (modified), + 71, 35, - 71 (modified), + 71, 0, - 71 (modified), + 71, 35, 1, 1, @@ -1154,58 +1154,58 @@ Simulation { 0, 35, 1, - 35 (modified), - 1 (modified), - 0, - 1 (modified), - 0 (modified), - 1, - 1 (modified), - 1, - 1 (modified), - 0 (modified), - 1, - 1, - 0, - 0, - 0, - 0 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1 (modified), 35, - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 35 (modified), - 1 (modified), - 70 (modified), - 71 (modified), - 71 (modified), - 71 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 2 (modified), - 0 (modified), - 2 (modified), - 2 (modified), - 0 (modified), 1, - 3 (modified), - 1 (modified), - 1 (modified), + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 35, + 0, + 1, + 1, + 1, + 35, + 1, + 70, + 71, + 71, + 71, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 3, + 1, + 1, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_2_false_true.txt b/crates/fayalite/tests/sim/expected/queue_2_false_true.txt index 2d9ea3f..f229451 100644 --- a/crates/fayalite/tests/sim/expected/queue_2_false_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_2_false_true.txt @@ -1095,35 +1095,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 77 (modified), + 77, 1, - 77 (modified), + 77, 38, - 77 (modified), + 77, 0, - 77 (modified), + 77, 38, 1, 0, @@ -1135,56 +1135,56 @@ Simulation { 0, 38, 1, - 38 (modified), - 1 (modified), - 1, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1, - 1 (modified), - 0 (modified), - 1, - 1, - 0, - 0, - 0, - 0 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1 (modified), 38, - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 38 (modified), - 1 (modified), - 76 (modified), - 77 (modified), - 77 (modified), - 77 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 2 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 2 (modified), - 2 (modified), - 0 (modified), 1, - 1 (modified), - 1 (modified), - 1 (modified), + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 38, + 0, + 1, + 1, + 1, + 38, + 1, + 76, + 77, + 77, + 77, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_2_true_false.txt b/crates/fayalite/tests/sim/expected/queue_2_true_false.txt index 3d16da2..e137316 100644 --- a/crates/fayalite/tests/sim/expected/queue_2_true_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_2_true_false.txt @@ -1124,35 +1124,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 79 (modified), + 79, 0, - 79 (modified), + 79, 39, - 77 (modified), + 77, 0, - 77 (modified), + 77, 38, 2, 0, @@ -1164,58 +1164,58 @@ Simulation { 0, 39, 1, - 39 (modified), - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1, - 1 (modified), - 0 (modified), - 0, - 0, - 0, - 0, - 1, - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 1, - 1 (modified), - 1 (modified), 39, - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 38 (modified), - 1 (modified), - 76 (modified), - 77 (modified), - 77 (modified), - 77 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 2 (modified), - 2 (modified), - 0 (modified), + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 39, + 0, + 0, + 1, + 1, + 38, + 1, + 76, + 77, + 77, + 77, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_2_true_true.txt b/crates/fayalite/tests/sim/expected/queue_2_true_true.txt index 041e62d..5203027 100644 --- a/crates/fayalite/tests/sim/expected/queue_2_true_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_2_true_true.txt @@ -1105,35 +1105,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 85 (modified), + 85, 0, - 85 (modified), + 85, 42, - 83 (modified), + 83, 0, - 83 (modified), + 83, 41, 2, 1, @@ -1145,56 +1145,56 @@ Simulation { 0, 42, 1, - 42 (modified), - 1 (modified), - 1, - 1 (modified), - 0 (modified), - 1, - 1 (modified), - 1, - 1 (modified), - 0 (modified), - 0, - 0, - 0, - 0, - 1, - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 1, - 1 (modified), - 1 (modified), 42, - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 41 (modified), - 1 (modified), - 82 (modified), - 83 (modified), - 83 (modified), - 83 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 2 (modified), - 0 (modified), - 1 (modified), - 2 (modified), - 0 (modified), - 2 (modified), - 2 (modified), - 0 (modified), + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 42, + 0, + 0, + 1, + 1, + 41, + 1, + 82, + 83, + 83, + 83, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_3_false_false.txt b/crates/fayalite/tests/sim/expected/queue_3_false_false.txt index f9c68cc..f5641ce 100644 --- a/crates/fayalite/tests/sim/expected/queue_3_false_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_3_false_false.txt @@ -1142,35 +1142,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 2 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 81 (modified), + 81, 1, - 81 (modified), + 81, 40, - 79 (modified), + 79, 0, - 79 (modified), + 79, 39, 2, 0, @@ -1182,59 +1182,59 @@ Simulation { 0, 40, 1, - 40 (modified), - 1 (modified), - 2, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1, - 1 (modified), - 0 (modified), - 1, - 1, - 0, - 0, - 0, - 0 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1 (modified), 40, - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 39 (modified), - 1 (modified), - 78 (modified), - 79 (modified), - 79 (modified), - 79 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 2 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 3 (modified), - 3 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 3 (modified), - 3 (modified), - 0 (modified), - 5 (modified), - 5 (modified), - 1 (modified), - 2 (modified), - 2 (modified), + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 40, + 0, + 1, + 1, + 1, + 39, + 1, + 78, + 79, + 79, + 79, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 3, + 3, + 0, + 1, + 1, + 3, + 3, + 0, + 5, + 5, + 1, + 2, + 2, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_3_false_true.txt b/crates/fayalite/tests/sim/expected/queue_3_false_true.txt index 9b0a7ea..cde5489 100644 --- a/crates/fayalite/tests/sim/expected/queue_3_false_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_3_false_true.txt @@ -1123,35 +1123,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 2 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 85 (modified), + 85, 1, - 85 (modified), + 85, 42, - 83 (modified), + 83, 0, - 83 (modified), + 83, 41, 2, 2, @@ -1163,57 +1163,57 @@ Simulation { 0, 42, 1, - 42 (modified), - 1 (modified), - 1, - 2 (modified), - 0 (modified), - 2, - 2 (modified), - 1, - 1 (modified), - 0 (modified), - 1, - 1, - 0, - 0, - 0, - 0 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1 (modified), 42, - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 41 (modified), - 1 (modified), - 82 (modified), - 83 (modified), - 83 (modified), - 83 (modified), - 1 (modified), - 2 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 2 (modified), - 2 (modified), - 1 (modified), - 3 (modified), - 3 (modified), - 3 (modified), - 3 (modified), - 1 (modified), - 4 (modified), - 2 (modified), - 2 (modified), - 7 (modified), - 3 (modified), + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 42, + 0, + 1, + 1, + 1, + 41, + 1, + 82, + 83, + 83, + 83, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 3, + 3, + 3, + 3, + 1, + 4, + 2, + 2, + 7, + 3, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_3_true_false.txt b/crates/fayalite/tests/sim/expected/queue_3_true_false.txt index 1b486d6..d943150 100644 --- a/crates/fayalite/tests/sim/expected/queue_3_true_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_3_true_false.txt @@ -1152,35 +1152,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 2 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 2 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 87 (modified), + 87, 0, - 87 (modified), + 87, 43, - 83 (modified), + 83, 0, - 83 (modified), + 83, 41, 3, 2, @@ -1192,59 +1192,59 @@ Simulation { 0, 43, 1, - 43 (modified), - 1 (modified), - 2, - 2 (modified), - 0 (modified), - 2, - 2 (modified), - 1, - 1 (modified), - 0 (modified), - 0, - 0, - 0, - 0, - 1, - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 1, - 1 (modified), - 1 (modified), 43, - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 41 (modified), - 1 (modified), - 82 (modified), - 83 (modified), - 83 (modified), - 83 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 2 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 3 (modified), - 3 (modified), - 1 (modified), - 3 (modified), - 3 (modified), - 3 (modified), - 3 (modified), - 0 (modified), - 5 (modified), - 3 (modified), - 3 (modified), - 0 (modified), - 0 (modified), + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 43, + 0, + 0, + 1, + 1, + 41, + 1, + 82, + 83, + 83, + 83, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 3, + 3, + 1, + 3, + 3, + 3, + 3, + 0, + 5, + 3, + 3, + 0, + 0, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_3_true_true.txt b/crates/fayalite/tests/sim/expected/queue_3_true_true.txt index 730e7e5..4a0f664 100644 --- a/crates/fayalite/tests/sim/expected/queue_3_true_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_3_true_true.txt @@ -1133,35 +1133,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 2 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 2 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 87 (modified), + 87, 0, - 87 (modified), + 87, 43, - 83 (modified), + 83, 0, - 83 (modified), + 83, 41, 3, 2, @@ -1173,57 +1173,57 @@ Simulation { 0, 43, 1, - 43 (modified), - 1 (modified), - 2, - 2 (modified), - 0 (modified), - 2, - 2 (modified), - 1, - 1 (modified), - 0 (modified), - 0, - 0, - 0, - 0, - 1, - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 1, - 1 (modified), - 1 (modified), 43, - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 41 (modified), - 1 (modified), - 82 (modified), - 83 (modified), - 83 (modified), - 83 (modified), - 0 (modified), - 2 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 3 (modified), - 3 (modified), - 1 (modified), - 3 (modified), - 3 (modified), - 3 (modified), - 3 (modified), - 0 (modified), - 5 (modified), - 3 (modified), - 3 (modified), - 0 (modified), - 0 (modified), + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 43, + 0, + 0, + 1, + 1, + 41, + 1, + 82, + 83, + 83, + 83, + 0, + 2, + 1, + 0, + 0, + 3, + 3, + 1, + 3, + 3, + 3, + 3, + 0, + 5, + 3, + 3, + 0, + 0, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_4_false_false.txt b/crates/fayalite/tests/sim/expected/queue_4_false_false.txt index e549ced..4e0a067 100644 --- a/crates/fayalite/tests/sim/expected/queue_4_false_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_4_false_false.txt @@ -1122,35 +1122,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 3 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 3, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 87 (modified), + 87, 1, - 87 (modified), + 87, 43, - 83 (modified), + 83, 0, - 83 (modified), + 83, 41, 3, 1, @@ -1162,58 +1162,58 @@ Simulation { 0, 43, 1, - 43 (modified), - 1 (modified), - 0, - 1 (modified), - 0 (modified), - 1, - 1 (modified), - 1, - 1 (modified), - 0 (modified), - 1, - 1, - 0, - 0, - 0, - 0 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1 (modified), 43, - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 41 (modified), - 1 (modified), - 82 (modified), - 83 (modified), - 83 (modified), - 83 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 3 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 2 (modified), - 2 (modified), - 4 (modified), - 4 (modified), - 0 (modified), + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 43, + 0, + 1, + 1, + 1, + 41, + 1, + 82, + 83, + 83, + 83, + 0, + 0, + 1, + 3, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 4, + 4, + 0, + 3, + 7, + 3, 3, - 7 (modified), - 3 (modified), - 3 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_4_false_true.txt b/crates/fayalite/tests/sim/expected/queue_4_false_true.txt index 9f1d05b..a374f44 100644 --- a/crates/fayalite/tests/sim/expected/queue_4_false_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_4_false_true.txt @@ -1103,35 +1103,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 3 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 3, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 87 (modified), + 87, 1, - 87 (modified), + 87, 43, - 83 (modified), + 83, 0, - 83 (modified), + 83, 41, 3, 1, @@ -1143,56 +1143,56 @@ Simulation { 0, 43, 1, - 43 (modified), - 1 (modified), - 0, - 1 (modified), - 0 (modified), - 1, - 1 (modified), - 1, - 1 (modified), - 0 (modified), - 1, - 1, - 0, - 0, - 0, - 0 (modified), - 0, - 0 (modified), - 0 (modified), - 0, - 0 (modified), - 1 (modified), 43, - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 41 (modified), - 1 (modified), - 82 (modified), - 83 (modified), - 83 (modified), - 83 (modified), - 1 (modified), - 3 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 2 (modified), - 2 (modified), - 4 (modified), - 4 (modified), - 0 (modified), + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 43, + 0, + 1, + 1, + 1, + 41, + 1, + 82, + 83, + 83, + 83, + 1, + 3, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 4, + 4, + 0, + 3, + 7, + 3, 3, - 7 (modified), - 3 (modified), - 3 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_4_true_false.txt b/crates/fayalite/tests/sim/expected/queue_4_true_false.txt index b37a9cd..7d20f26 100644 --- a/crates/fayalite/tests/sim/expected/queue_4_true_false.txt +++ b/crates/fayalite/tests/sim/expected/queue_4_true_false.txt @@ -1132,35 +1132,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 89 (modified), + 89, 0, - 89 (modified), + 89, 44, - 83 (modified), + 83, 0, - 83 (modified), + 83, 41, 4, 1, @@ -1172,58 +1172,58 @@ Simulation { 0, 44, 1, - 44 (modified), - 1 (modified), - 1, - 1 (modified), - 0 (modified), - 1, - 1 (modified), - 1, - 1 (modified), - 0 (modified), - 0, - 0, - 0, - 0, - 1, - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 1, - 1 (modified), - 1 (modified), 44, - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 41 (modified), - 1 (modified), - 82 (modified), - 83 (modified), - 83 (modified), - 83 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 3 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 2 (modified), - 2 (modified), - 0 (modified), - 2 (modified), - 2 (modified), - 4 (modified), - 4 (modified), - 0 (modified), + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 44, + 0, + 0, + 1, + 1, + 41, + 1, + 82, + 83, + 83, + 83, + 0, + 0, + 0, + 3, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 4, + 4, + 0, + 0, + 0, + 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/queue_4_true_true.txt b/crates/fayalite/tests/sim/expected/queue_4_true_true.txt index 051b203..a0ee509 100644 --- a/crates/fayalite/tests/sim/expected/queue_4_true_true.txt +++ b/crates/fayalite/tests/sim/expected/queue_4_true_true.txt @@ -1113,35 +1113,35 @@ Simulation { value: [ 1, 1, - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 0, ], }, big_slots: StatePart { value: [ 0, 0, - 89 (modified), + 89, 0, - 89 (modified), + 89, 44, - 83 (modified), + 83, 0, - 83 (modified), + 83, 41, 4, 1, @@ -1153,56 +1153,56 @@ Simulation { 0, 44, 1, - 44 (modified), - 1 (modified), - 1, - 1 (modified), - 0 (modified), - 1, - 1 (modified), - 1, - 1 (modified), - 0 (modified), - 0, - 0, - 0, - 0, - 1, - 1 (modified), - 0, - 0 (modified), - 0 (modified), - 1, - 1 (modified), - 1 (modified), 44, - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 41 (modified), - 1 (modified), - 82 (modified), - 83 (modified), - 83 (modified), - 83 (modified), - 0 (modified), - 3 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 2 (modified), - 2 (modified), - 0 (modified), - 2 (modified), - 2 (modified), - 4 (modified), - 4 (modified), - 0 (modified), + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 44, + 0, + 0, + 1, + 1, + 41, + 1, + 82, + 83, + 83, + 83, + 0, + 3, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 4, + 4, + 0, + 0, + 0, + 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/ripple_counter.txt b/crates/fayalite/tests/sim/expected/ripple_counter.txt index 91bbffd..6562d4d 100644 --- a/crates/fayalite/tests/sim/expected/ripple_counter.txt +++ b/crates/fayalite/tests/sim/expected/ripple_counter.txt @@ -641,15 +641,15 @@ Simulation { }, small_slots: StatePart { value: [ - 0 (modified), - 0 (modified), - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, ], }, big_slots: StatePart { @@ -662,56 +662,56 @@ Simulation { 0, 0, 0, - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 0 (modified), 0, - 1 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, 0, 0, 0 (modified), 0, - 0 (modified), 0, - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), + 0, + 1, + 0, + 0, + 0, + 1, 0, 0, 0 (modified), 0, - 0 (modified), 0, - 1 (modified), - 0 (modified), - 0 (modified), - 0 (modified), - 1 (modified), + 0, + 1, + 0, + 0, + 0, + 1, 0, 0, 0 (modified), 0, - 0 (modified), + 0, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/shift_register.txt b/crates/fayalite/tests/sim/expected/shift_register.txt index cc9d95a..1eaa378 100644 --- a/crates/fayalite/tests/sim/expected/shift_register.txt +++ b/crates/fayalite/tests/sim/expected/shift_register.txt @@ -259,10 +259,10 @@ Simulation { }, small_slots: StatePart { value: [ - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), + 0, + 0, + 1, + 0, ], }, big_slots: StatePart { @@ -272,14 +272,14 @@ Simulation { 0, 0, 0, - 0 (modified), - 0 (modified), 0, - 0 (modified), 0, - 0 (modified), 0, - 0 (modified), + 0, + 0, + 0, + 0, + 0, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/sim_only_connects.txt b/crates/fayalite/tests/sim/expected/sim_only_connects.txt index 3b90ca8..2ae2fbe 100644 --- a/crates/fayalite/tests/sim/expected/sim_only_connects.txt +++ b/crates/fayalite/tests/sim/expected/sim_only_connects.txt @@ -380,10 +380,10 @@ Simulation { }, small_slots: StatePart { value: [ - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), + 0, + 0, + 1, + 0, ], }, big_slots: StatePart { @@ -395,9 +395,9 @@ Simulation { 1 (modified), 0, 0, - 0 (modified), - 1 (modified), - 0 (modified), + 0, + 1, + 0, 1, 0, 1 (modified), @@ -443,8 +443,8 @@ Simulation { }, { "extra": "value", - } (modified), - {} (modified), + }, + {}, { "bar": "", "extra": "value", diff --git a/crates/fayalite/tests/sim/expected/sim_read_past.txt b/crates/fayalite/tests/sim/expected/sim_read_past.txt index 17156d0..f771434 100644 --- a/crates/fayalite/tests/sim/expected/sim_read_past.txt +++ b/crates/fayalite/tests/sim/expected/sim_read_past.txt @@ -517,15 +517,15 @@ Simulation { }, small_slots: StatePart { value: [ - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 0 (modified), + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, ], }, big_slots: StatePart { @@ -542,42 +542,42 @@ Simulation { 49 (modified), 49 (modified), 50 (modified), - 1 (modified), - 0 (modified), - 0 (modified), - 48 (modified), - 49 (modified), - 49 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 48 (modified), - 49 (modified), - 48 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 49 (modified), - 49 (modified), - 50 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 49 (modified), - 49 (modified), - 49 (modified), - 0 (modified), - 0 (modified), - 1 (modified), - 49 (modified), - 50 (modified), - 50 (modified), - 0 (modified), - 1 (modified), - 0 (modified), - 49 (modified), - 49 (modified), - 50 (modified), + 1, + 0, + 0, + 48, + 49, + 49, + 0, + 0, + 1, + 48, + 49, + 48, + 0, + 1, + 0, + 49, + 49, + 50, + 0, + 0, + 1, + 49, + 49, + 49, + 0, + 0, + 1, + 49, + 50, + 50, + 0, + 1, + 0, + 49, + 49, + 50, ], }, sim_only_slots: StatePart { diff --git a/crates/fayalite/tests/sim/expected/sim_trace_as_string.txt b/crates/fayalite/tests/sim/expected/sim_trace_as_string.txt new file mode 100644 index 0000000..0dd374c --- /dev/null +++ b/crates/fayalite/tests/sim/expected/sim_trace_as_string.txt @@ -0,0 +1,2254 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 12, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + big_slots: StatePartLayout { + len: 31, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.addr", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.addr", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.mask[0]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.mask[1]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.addr", + ty: UInt<2>, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.addr", + ty: UInt<2>, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.mask[0]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.mask[1]", + ty: Bool, + }, + SlotDebugData { + name: "[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "[0]", + ty: Bool, + }, + SlotDebugData { + name: "[1]", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + SlotDebugData { + name: "", + ty: UInt<2>, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + memories: StatePartLayout { + len: 1, + debug_data: [ + (), + ], + layout_data: [ + MemoryData { + array_type: Array), FmtError}, .. }, 2>, 4>, + data: [ + // len = 0x4 + [0x0]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, + [0x1]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, + [0x2]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, + [0x3]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, + ], + }, + ], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:16:1 + 0: Copy { + dest: StatePartIndex(23), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.mask[0]", ty: Bool }, + src: StatePartIndex(11), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.mask[0]", ty: Bool }, + }, + 1: Copy { + dest: StatePartIndex(24), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.mask[1]", ty: Bool }, + src: StatePartIndex(12), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.mask[1]", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:15:1 + 2: Copy { + dest: StatePartIndex(19), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.en", ty: Bool }, + src: StatePartIndex(7), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.en", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:14:1 + 3: Copy { + dest: StatePartIndex(21), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.data[0]", ty: Enum {Text(UInt<512>), FmtError} }, + src: StatePartIndex(9), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.data[0]", ty: Enum {Text(UInt<512>), FmtError} }, + }, + 4: Copy { + dest: StatePartIndex(22), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.data[1]", ty: Enum {Text(UInt<512>), FmtError} }, + src: StatePartIndex(10), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.data[1]", ty: Enum {Text(UInt<512>), FmtError} }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 5: CastToUInt { + dest: StatePartIndex(30), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(6), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.addr", ty: UInt<8> }, + dest_width: 2, + }, + // at: module-XXXXXXXXXX.rs:13:1 + 6: Copy { + dest: StatePartIndex(18), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.addr", ty: UInt<2> }, + src: StatePartIndex(30), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, + }, + // at: module-XXXXXXXXXX.rs:12:1 + 7: Copy { + dest: StatePartIndex(20), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.clk", ty: Clock }, + src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::clk", ty: Clock }, + }, + // at: module-XXXXXXXXXX.rs:9:1 + 8: Copy { + dest: StatePartIndex(14), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.en", ty: Bool }, + src: StatePartIndex(2), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.en", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 9: CastToUInt { + dest: StatePartIndex(29), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(1), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.addr", ty: UInt<8> }, + dest_width: 2, + }, + // at: module-XXXXXXXXXX.rs:8:1 + 10: Copy { + dest: StatePartIndex(13), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.addr", ty: UInt<2> }, + src: StatePartIndex(29), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, + }, + // at: module-XXXXXXXXXX.rs:7:1 + 11: Copy { + dest: StatePartIndex(15), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.clk", ty: Clock }, + src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::clk", ty: Clock }, + }, + // at: module-XXXXXXXXXX.rs:5:1 + 12: CastBigToArrayIndex { + dest: StatePartIndex(9), // (0x1 1) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(18), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.addr", ty: UInt<2> }, + }, + 13: IsNonZeroDestIsSmall { + dest: StatePartIndex(8), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(19), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.en", ty: Bool }, + }, + 14: IsNonZeroDestIsSmall { + dest: StatePartIndex(7), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(20), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.clk", ty: Clock }, + }, + 15: AndSmall { + dest: StatePartIndex(6), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(7), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, + 16: CastBigToArrayIndex { + dest: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(13), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.addr", ty: UInt<2> }, + }, + 17: IsNonZeroDestIsSmall { + dest: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(14), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.en", ty: Bool }, + }, + 18: BranchIfSmallZero { + target: 22, + value: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + }, + 19: MemoryReadUInt { + dest: StatePartIndex(16), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[0]", ty: Enum {Text(UInt<512>), FmtError} }, + memory: StatePartIndex(0), // (MemoryData { + // array_type: Array), FmtError}, .. }, 2>, 4>, + // data: [ + // // len = 0x4 + // [0x0]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74c16db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba60b6dacada, + // [0x1]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, + // [0x2]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74c96db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba64b6dacada, + // [0x3]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74cd6db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba66b6dacada, + // ], + // }) (), + addr: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: UInt<2> }, + stride: 1026, + start: 0, + width: 513, + }, + 20: MemoryReadUInt { + dest: StatePartIndex(17), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[1]", ty: Enum {Text(UInt<512>), FmtError} }, + memory: StatePartIndex(0), // (MemoryData { + // array_type: Array), FmtError}, .. }, 2>, 4>, + // data: [ + // // len = 0x4 + // [0x0]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74c16db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba60b6dacada, + // [0x1]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, + // [0x2]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74c96db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba64b6dacada, + // [0x3]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74cd6db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba66b6dacada, + // ], + // }) (), + addr: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: UInt<2> }, + stride: 1026, + start: 513, + width: 513, + }, + 21: Branch { + target: 24, + }, + 22: Const { + dest: StatePartIndex(16), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[0]", ty: Enum {Text(UInt<512>), FmtError} }, + value: 0x0, + }, + 23: Const { + dest: StatePartIndex(17), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[1]", ty: Enum {Text(UInt<512>), FmtError} }, + value: 0x0, + }, + // at: module-XXXXXXXXXX.rs:10:1 + 24: Copy { + dest: StatePartIndex(4), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.data[0]", ty: Enum {Text(UInt<512>), FmtError} }, + src: StatePartIndex(16), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[0]", ty: Enum {Text(UInt<512>), FmtError} }, + }, + 25: Copy { + dest: StatePartIndex(5), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.data[1]", ty: Enum {Text(UInt<512>), FmtError} }, + src: StatePartIndex(17), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[1]", ty: Enum {Text(UInt<512>), FmtError} }, + }, + // at: module-XXXXXXXXXX.rs:5:1 + 26: IsNonZeroDestIsSmall { + dest: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(15), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.clk", ty: Clock }, + }, + 27: AndSmall { + dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, + 28: BranchIfSmallZero { + target: 29, + value: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, + 29: BranchIfSmallZero { + target: 41, + value: StatePartIndex(6), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + }, + 30: CopySmall { + dest: StatePartIndex(10), // (0x1 1) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(9), // (0x1 1) SlotDebugData { name: "", ty: UInt<2> }, + }, + 31: CopySmall { + dest: StatePartIndex(11), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(8), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + }, + 32: Copy { + dest: StatePartIndex(25), // (0x1) SlotDebugData { name: "[0]", ty: Enum {Text(UInt<512>), FmtError} }, + src: StatePartIndex(21), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.data[0]", ty: Enum {Text(UInt<512>), FmtError} }, + }, + 33: Copy { + dest: StatePartIndex(26), // (0x1) SlotDebugData { name: "[1]", ty: Enum {Text(UInt<512>), FmtError} }, + src: StatePartIndex(22), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.data[1]", ty: Enum {Text(UInt<512>), FmtError} }, + }, + 34: Copy { + dest: StatePartIndex(27), // (0x1) SlotDebugData { name: "[0]", ty: Bool }, + src: StatePartIndex(23), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.mask[0]", ty: Bool }, + }, + 35: Copy { + dest: StatePartIndex(28), // (0x1) SlotDebugData { name: "[1]", ty: Bool }, + src: StatePartIndex(24), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.mask[1]", ty: Bool }, + }, + 36: BranchIfSmallZero { + target: 41, + value: StatePartIndex(11), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + }, + 37: BranchIfZero { + target: 39, + value: StatePartIndex(27), // (0x1) SlotDebugData { name: "[0]", ty: Bool }, + }, + 38: MemoryWriteUInt { + value: StatePartIndex(25), // (0x1) SlotDebugData { name: "[0]", ty: Enum {Text(UInt<512>), FmtError} }, + memory: StatePartIndex(0), // (MemoryData { + // array_type: Array), FmtError}, .. }, 2>, 4>, + // data: [ + // // len = 0x4 + // [0x0]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74c16db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba60b6dacada, + // [0x1]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, + // [0x2]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74c96db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba64b6dacada, + // [0x3]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74cd6db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba66b6dacada, + // ], + // }) (), + addr: StatePartIndex(10), // (0x1 1) SlotDebugData { name: "", ty: UInt<2> }, + stride: 1026, + start: 0, + width: 513, + }, + 39: BranchIfZero { + target: 41, + value: StatePartIndex(28), // (0x1) SlotDebugData { name: "[1]", ty: Bool }, + }, + 40: MemoryWriteUInt { + value: StatePartIndex(26), // (0x1) SlotDebugData { name: "[1]", ty: Enum {Text(UInt<512>), FmtError} }, + memory: StatePartIndex(0), // (MemoryData { + // array_type: Array), FmtError}, .. }, 2>, 4>, + // data: [ + // // len = 0x4 + // [0x0]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74c16db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba60b6dacada, + // [0x1]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, + // [0x2]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74c96db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba64b6dacada, + // [0x3]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74cd6db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba66b6dacada, + // ], + // }) (), + addr: StatePartIndex(10), // (0x1 1) SlotDebugData { name: "", ty: UInt<2> }, + stride: 1026, + start: 513, + width: 513, + }, + 41: XorSmallImmediate { + dest: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + rhs: 0x1, + }, + 42: XorSmallImmediate { + dest: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(7), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + rhs: 0x1, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 43: Return, + ], + .. + }, + pc: 43, + memory_write_log: [], + memories: StatePart { + value: [ + MemoryData { + array_type: Array), FmtError}, .. }, 2>, 4>, + data: [ + // len = 0x4 + [0x0]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74c16db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba60b6dacada, + [0x1]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001, + [0x2]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74c96db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba64b6dacada, + [0x3]: 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174c56d74cd6db595b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba60b6ba66b6dacada, + ], + }, + ], + }, + small_slots: StatePart { + value: [ + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + ], + }, + big_slots: StatePart { + value: [ + 1, + 1, + 1, + 0, + 1 (modified), + 1 (modified), + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + ], + }, + sim_only_slots: StatePart { + value: [], + }, + }, + io: Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }, + main_module: SimulationModuleState { + base_targets: [ + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.clk, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.read, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write, + ], + uninitialized_ios: {}, + io_targets: { + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.clk, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.read, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.read.addr, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.read.clk, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.read.data, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.read.data., + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.read.data.[0], + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.read.data.[1], + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.read.en, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.addr, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.clk, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.data, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.data[0], + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.data[0]., + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.data[1], + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.data[1]., + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.en, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.mask, + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.mask[0], + Instance { + name: ::sim_trace_as_string, + instantiated: Module { + name: sim_trace_as_string, + .. + }, + }.write.mask[1], + }, + did_initial_settle: true, + clocks_for_past: {}, + }, + extern_modules: [], + trace_decls: TraceModule { + name: "sim_trace_as_string", + children: [ + TraceModuleIO { + name: "clk", + child: TraceClock { + location: TraceScalarId(0), + name: "clk", + flow: Source, + }, + ty: Clock, + flow: Source, + }, + TraceModuleIO { + name: "read", + child: TraceBundle { + name: "read", + fields: [ + TraceUInt { + location: TraceScalarId(1), + name: "addr", + ty: UInt<8>, + flow: Source, + }, + TraceBool { + location: TraceScalarId(2), + name: "en", + flow: Source, + }, + TraceClock { + location: TraceScalarId(3), + name: "clk", + flow: Source, + }, + TraceTraceAsString { + location: TraceScalarId(4), + name: "data", + ty: TraceAsString { + inner_ty: Array), FmtError}, 2>, + .. + }, + flow: Sink, + }, + ], + ty: Bundle { + /* offset = 0 */ + addr: UInt<8>, + /* offset = 8 */ + en: Bool, + /* offset = 9 */ + clk: Clock, + #[hdl(flip)] /* offset = 10 */ + data: TraceAsString { + inner_ty: Array), FmtError}, 2>, + .. + }, + }, + flow: Source, + }, + ty: Bundle { + /* offset = 0 */ + addr: UInt<8>, + /* offset = 8 */ + en: Bool, + /* offset = 9 */ + clk: Clock, + #[hdl(flip)] /* offset = 10 */ + data: TraceAsString { + inner_ty: Array), FmtError}, 2>, + .. + }, + }, + flow: Source, + }, + TraceModuleIO { + name: "write", + child: TraceBundle { + name: "write", + fields: [ + TraceUInt { + location: TraceScalarId(5), + name: "addr", + ty: UInt<8>, + flow: Source, + }, + TraceBool { + location: TraceScalarId(6), + name: "en", + flow: Source, + }, + TraceClock { + location: TraceScalarId(7), + name: "clk", + flow: Source, + }, + TraceArray { + name: "data", + elements: [ + TraceTraceAsString { + location: TraceScalarId(8), + name: "[0]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Source, + }, + TraceTraceAsString { + location: TraceScalarId(9), + name: "[1]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Source, + }, + ], + ty: Array), FmtError}, .. }, 2>, + flow: Source, + }, + TraceArray { + name: "mask", + elements: [ + TraceBool { + location: TraceScalarId(10), + name: "[0]", + flow: Source, + }, + TraceBool { + location: TraceScalarId(11), + name: "[1]", + flow: Source, + }, + ], + ty: Array, + flow: Source, + }, + ], + ty: Bundle { + /* offset = 0 */ + addr: UInt<8>, + /* offset = 8 */ + en: Bool, + /* offset = 9 */ + clk: Clock, + /* offset = 10 */ + data: Array), FmtError}, .. }, 2>, + /* offset = 1036 */ + mask: Array, + }, + flow: Source, + }, + ty: Bundle { + /* offset = 0 */ + addr: UInt<8>, + /* offset = 8 */ + en: Bool, + /* offset = 9 */ + clk: Clock, + /* offset = 10 */ + data: Array), FmtError}, .. }, 2>, + /* offset = 1036 */ + mask: Array, + }, + flow: Source, + }, + TraceMem { + id: TraceMemoryId(0), + name: "mem", + stride: 1026, + element_type: TraceArray { + name: "mem", + elements: [ + TraceTraceAsString { + location: TraceMemoryLocation { + id: TraceMemoryId(0), + depth: 4, + stride: 1026, + start: 0, + len: 513, + }, + name: "[0]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Duplex, + }, + TraceTraceAsString { + location: TraceMemoryLocation { + id: TraceMemoryId(0), + depth: 4, + stride: 1026, + start: 513, + len: 513, + }, + name: "[1]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Duplex, + }, + ], + ty: Array), FmtError}, .. }, 2>, + flow: Duplex, + }, + ports: [ + TraceMemPort { + name: "r0", + bundle: TraceBundle { + name: "r0", + fields: [ + TraceUInt { + location: TraceScalarId(12), + name: "addr", + ty: UInt<2>, + flow: Sink, + }, + TraceBool { + location: TraceScalarId(13), + name: "en", + flow: Sink, + }, + TraceClock { + location: TraceScalarId(14), + name: "clk", + flow: Sink, + }, + TraceArray { + name: "data", + elements: [ + TraceTraceAsString { + location: TraceScalarId(15), + name: "[0]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Source, + }, + TraceTraceAsString { + location: TraceScalarId(16), + name: "[1]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Source, + }, + ], + ty: Array), FmtError}, .. }, 2>, + flow: Source, + }, + ], + ty: Bundle { + /* offset = 0 */ + addr: UInt<2>, + /* offset = 2 */ + en: Bool, + /* offset = 3 */ + clk: Clock, + #[hdl(flip)] /* offset = 4 */ + data: Array), FmtError}, .. }, 2>, + }, + flow: Sink, + }, + ty: Bundle { + /* offset = 0 */ + addr: UInt<2>, + /* offset = 2 */ + en: Bool, + /* offset = 3 */ + clk: Clock, + #[hdl(flip)] /* offset = 4 */ + data: Array), FmtError}, .. }, 2>, + }, + }, + TraceMemPort { + name: "w1", + bundle: TraceBundle { + name: "w1", + fields: [ + TraceUInt { + location: TraceScalarId(17), + name: "addr", + ty: UInt<2>, + flow: Sink, + }, + TraceBool { + location: TraceScalarId(18), + name: "en", + flow: Sink, + }, + TraceClock { + location: TraceScalarId(19), + name: "clk", + flow: Sink, + }, + TraceArray { + name: "data", + elements: [ + TraceTraceAsString { + location: TraceScalarId(20), + name: "[0]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Sink, + }, + TraceTraceAsString { + location: TraceScalarId(21), + name: "[1]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Sink, + }, + ], + ty: Array), FmtError}, .. }, 2>, + flow: Sink, + }, + TraceArray { + name: "mask", + elements: [ + TraceBool { + location: TraceScalarId(22), + name: "[0]", + flow: Sink, + }, + TraceBool { + location: TraceScalarId(23), + name: "[1]", + flow: Sink, + }, + ], + ty: Array, + flow: Sink, + }, + ], + ty: Bundle { + /* offset = 0 */ + addr: UInt<2>, + /* offset = 2 */ + en: Bool, + /* offset = 3 */ + clk: Clock, + /* offset = 4 */ + data: Array), FmtError}, .. }, 2>, + /* offset = 1030 */ + mask: Array, + }, + flow: Sink, + }, + ty: Bundle { + /* offset = 0 */ + addr: UInt<2>, + /* offset = 2 */ + en: Bool, + /* offset = 3 */ + clk: Clock, + /* offset = 4 */ + data: Array), FmtError}, .. }, 2>, + /* offset = 1030 */ + mask: Array, + }, + }, + ], + array_type: Array), FmtError}, .. }, 2>, 4>, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigClock { + index: StatePartIndex(0), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigUInt { + index: StatePartIndex(1), + ty: UInt<8>, + }, + maybe_changed: false, + state: 0x01, + last_state: 0x01, + }, + SimTrace { + id: TraceScalarId(2), + kind: BigBool { + index: StatePartIndex(2), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(3), + kind: BigClock { + index: StatePartIndex(3), + }, + maybe_changed: false, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(4), + kind: TraceAsString { + layout: CompiledTypeLayout { + ty: TraceAsString { + inner_ty: Array), FmtError}, 2>, + .. + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Transparent { + inner: CompiledTypeLayout { + ty: Array), FmtError}, 2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Array { + elements_non_empty: [ + CompiledTypeLayout { + ty: Enum { + Text(UInt<512>), + FmtError, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + CompiledTypeLayout { + ty: Enum { + Text(UInt<512>), + FmtError, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::read.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + ], + }, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 4, len: 2 }, + sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, + }, + }, + maybe_changed: true, + state: OpaqueSimValue { + bits: 0x200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_u1026, + sim_only_values: [], + }, + last_state: OpaqueSimValue { + bits: 0x174C56D74C56DB595B400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BA60B6BA62B6DACADA_u1026, + sim_only_values: [], + }, + }, + SimTrace { + id: TraceScalarId(5), + kind: BigUInt { + index: StatePartIndex(6), + ty: UInt<8>, + }, + maybe_changed: false, + state: 0x01, + last_state: 0x01, + }, + SimTrace { + id: TraceScalarId(6), + kind: BigBool { + index: StatePartIndex(7), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(7), + kind: BigClock { + index: StatePartIndex(8), + }, + maybe_changed: false, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(8), + kind: TraceAsString { + layout: CompiledTypeLayout { + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Transparent { + inner: CompiledTypeLayout { + ty: Enum { + Text(UInt<512>), + FmtError, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 9, len: 1 }, + sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, + }, + }, + maybe_changed: true, + state: OpaqueSimValue { + bits: 0x1_u513, + sim_only_values: [], + }, + last_state: OpaqueSimValue { + bits: 0x1_u513, + sim_only_values: [], + }, + }, + SimTrace { + id: TraceScalarId(9), + kind: TraceAsString { + layout: CompiledTypeLayout { + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Transparent { + inner: CompiledTypeLayout { + ty: Enum { + Text(UInt<512>), + FmtError, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::write.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 10, len: 1 }, + sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, + }, + }, + maybe_changed: true, + state: OpaqueSimValue { + bits: 0x1_u513, + sim_only_values: [], + }, + last_state: OpaqueSimValue { + bits: 0x1_u513, + sim_only_values: [], + }, + }, + SimTrace { + id: TraceScalarId(10), + kind: BigBool { + index: StatePartIndex(11), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(11), + kind: BigBool { + index: StatePartIndex(12), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(12), + kind: BigUInt { + index: StatePartIndex(13), + ty: UInt<2>, + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(13), + kind: BigBool { + index: StatePartIndex(14), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(14), + kind: BigClock { + index: StatePartIndex(15), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(15), + kind: TraceAsString { + layout: CompiledTypeLayout { + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Transparent { + inner: CompiledTypeLayout { + ty: Enum { + Text(UInt<512>), + FmtError, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 16, len: 1 }, + sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, + }, + }, + maybe_changed: true, + state: OpaqueSimValue { + bits: 0x1_u513, + sim_only_values: [], + }, + last_state: OpaqueSimValue { + bits: 0xBA60B6BA62B6DACADA_u513, + sim_only_values: [], + }, + }, + SimTrace { + id: TraceScalarId(16), + kind: TraceAsString { + layout: CompiledTypeLayout { + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Transparent { + inner: CompiledTypeLayout { + ty: Enum { + Text(UInt<512>), + FmtError, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::r0.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 17, len: 1 }, + sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, + }, + }, + maybe_changed: true, + state: OpaqueSimValue { + bits: 0x1_u513, + sim_only_values: [], + }, + last_state: OpaqueSimValue { + bits: 0xBA62B6BA62B6DACADA_u513, + sim_only_values: [], + }, + }, + SimTrace { + id: TraceScalarId(17), + kind: BigUInt { + index: StatePartIndex(18), + ty: UInt<2>, + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(18), + kind: BigBool { + index: StatePartIndex(19), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(19), + kind: BigClock { + index: StatePartIndex(20), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(20), + kind: TraceAsString { + layout: CompiledTypeLayout { + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Transparent { + inner: CompiledTypeLayout { + ty: Enum { + Text(UInt<512>), + FmtError, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.data[0]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 5, len: 0 }, + big_slots: StatePartIndexRange { start: 21, len: 1 }, + sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, + }, + }, + maybe_changed: true, + state: OpaqueSimValue { + bits: 0x1_u513, + sim_only_values: [], + }, + last_state: OpaqueSimValue { + bits: 0x1_u513, + sim_only_values: [], + }, + }, + SimTrace { + id: TraceScalarId(21), + kind: TraceAsString { + layout: CompiledTypeLayout { + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Transparent { + inner: CompiledTypeLayout { + ty: Enum { + Text(UInt<512>), + FmtError, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(sim_trace_as_string: sim_trace_as_string).sim_trace_as_string::mem::w1.data[1]", + ty: Enum { + Text(UInt<512>), + FmtError, + }, + }, + ], + .. + }, + sim_only_slots: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 5, len: 0 }, + big_slots: StatePartIndexRange { start: 22, len: 1 }, + sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, + }, + }, + maybe_changed: true, + state: OpaqueSimValue { + bits: 0x1_u513, + sim_only_values: [], + }, + last_state: OpaqueSimValue { + bits: 0x1_u513, + sim_only_values: [], + }, + }, + SimTrace { + id: TraceScalarId(22), + kind: BigBool { + index: StatePartIndex(23), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(23), + kind: BigBool { + index: StatePartIndex(24), + }, + maybe_changed: true, + state: 0x1, + last_state: 0x1, + }, + ], + trace_memories: { + StatePartIndex(0): TraceMem { + id: TraceMemoryId(0), + name: "mem", + stride: 1026, + element_type: TraceArray { + name: "mem", + elements: [ + TraceTraceAsString { + location: TraceMemoryLocation { + id: TraceMemoryId(0), + depth: 4, + stride: 1026, + start: 0, + len: 513, + }, + name: "[0]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Duplex, + }, + TraceTraceAsString { + location: TraceMemoryLocation { + id: TraceMemoryId(0), + depth: 4, + stride: 1026, + start: 513, + len: 513, + }, + name: "[1]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Duplex, + }, + ], + ty: Array), FmtError}, .. }, 2>, + flow: Duplex, + }, + ports: [ + TraceMemPort { + name: "r0", + bundle: TraceBundle { + name: "r0", + fields: [ + TraceUInt { + location: TraceScalarId(12), + name: "addr", + ty: UInt<2>, + flow: Sink, + }, + TraceBool { + location: TraceScalarId(13), + name: "en", + flow: Sink, + }, + TraceClock { + location: TraceScalarId(14), + name: "clk", + flow: Sink, + }, + TraceArray { + name: "data", + elements: [ + TraceTraceAsString { + location: TraceScalarId(15), + name: "[0]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Source, + }, + TraceTraceAsString { + location: TraceScalarId(16), + name: "[1]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Source, + }, + ], + ty: Array), FmtError}, .. }, 2>, + flow: Source, + }, + ], + ty: Bundle { + /* offset = 0 */ + addr: UInt<2>, + /* offset = 2 */ + en: Bool, + /* offset = 3 */ + clk: Clock, + #[hdl(flip)] /* offset = 4 */ + data: Array), FmtError}, .. }, 2>, + }, + flow: Sink, + }, + ty: Bundle { + /* offset = 0 */ + addr: UInt<2>, + /* offset = 2 */ + en: Bool, + /* offset = 3 */ + clk: Clock, + #[hdl(flip)] /* offset = 4 */ + data: Array), FmtError}, .. }, 2>, + }, + }, + TraceMemPort { + name: "w1", + bundle: TraceBundle { + name: "w1", + fields: [ + TraceUInt { + location: TraceScalarId(17), + name: "addr", + ty: UInt<2>, + flow: Sink, + }, + TraceBool { + location: TraceScalarId(18), + name: "en", + flow: Sink, + }, + TraceClock { + location: TraceScalarId(19), + name: "clk", + flow: Sink, + }, + TraceArray { + name: "data", + elements: [ + TraceTraceAsString { + location: TraceScalarId(20), + name: "[0]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Sink, + }, + TraceTraceAsString { + location: TraceScalarId(21), + name: "[1]", + ty: TraceAsString { + inner_ty: Enum { + Text(UInt<512>), + FmtError, + }, + .. + }, + flow: Sink, + }, + ], + ty: Array), FmtError}, .. }, 2>, + flow: Sink, + }, + TraceArray { + name: "mask", + elements: [ + TraceBool { + location: TraceScalarId(22), + name: "[0]", + flow: Sink, + }, + TraceBool { + location: TraceScalarId(23), + name: "[1]", + flow: Sink, + }, + ], + ty: Array, + flow: Sink, + }, + ], + ty: Bundle { + /* offset = 0 */ + addr: UInt<2>, + /* offset = 2 */ + en: Bool, + /* offset = 3 */ + clk: Clock, + /* offset = 4 */ + data: Array), FmtError}, .. }, 2>, + /* offset = 1030 */ + mask: Array, + }, + flow: Sink, + }, + ty: Bundle { + /* offset = 0 */ + addr: UInt<2>, + /* offset = 2 */ + en: Bool, + /* offset = 3 */ + clk: Clock, + /* offset = 4 */ + data: Array), FmtError}, .. }, 2>, + /* offset = 1030 */ + mask: Array, + }, + }, + ], + array_type: Array), FmtError}, .. }, 2>, 4>, + }, + }, + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + clocks_triggered: [ + StatePartIndex(1), + StatePartIndex(6), + ], + event_queue: EventQueue(EventQueueData { + instant: 7 μs, + events: {}, + }), + waiting_sensitivity_sets_by_address: {}, + waiting_sensitivity_sets_by_compiled_value: {}, + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_trace_as_string.vcd b/crates/fayalite/tests/sim/expected/sim_trace_as_string.vcd new file mode 100644 index 0000000..3338905 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/sim_trace_as_string.vcd @@ -0,0 +1,221 @@ +$timescale 1 ps $end +$scope module sim_trace_as_string $end +$var wire 1 J(7*b clk $end +$scope struct read $end +$var wire 8 @t0}\ addr $end +$var wire 1 78"T5 en $end +$var wire 1 G7v@m clk $end +$var string 1 F&^FN data $end +$upscope $end +$scope struct write $end +$var wire 8 "fUdW addr $end +$var wire 1 r1OK) en $end +$var wire 1 ,ADvU clk $end +$scope struct data $end +$var string 1 pD.mP \[0] $end +$var string 1 !V!em \[1] $end +$upscope $end +$scope struct mask $end +$var wire 1 l8dgD \[0] $end +$var wire 1 1/sDs \[1] $end +$upscope $end +$upscope $end +$scope struct mem $end +$scope struct contents $end +$scope struct \[0] $end +$scope struct mem $end +$var string 1 sz>#| \[0] $end +$var string 1 G._83 \[1] $end +$upscope $end +$upscope $end +$scope struct \[1] $end +$scope struct mem $end +$var string 1 2r3#W \[0] $end +$var string 1 AbGF% \[1] $end +$upscope $end +$upscope $end +$scope struct \[2] $end +$scope struct mem $end +$var string 1 .^<$p \[0] $end +$var string 1 ?s@Dc \[1] $end +$upscope $end +$upscope $end +$scope struct \[3] $end +$scope struct mem $end +$var string 1 {*||o \[0] $end +$var string 1 Bg,vB \[1] $end +$upscope $end +$upscope $end +$upscope $end +$scope struct r0 $end +$var wire 2 .0()- addr $end +$var wire 1 GEbRA en $end +$var wire 1 ;`9BK clk $end +$scope struct data $end +$var string 1 _Xe"P \[0] $end +$var string 1 jXrsx \[1] $end +$upscope $end +$upscope $end +$scope struct w1 $end +$var wire 2 '8u?z addr $end +$var wire 1 ~o=`& en $end +$var wire 1 *q>M1 clk $end +$scope struct data $end +$var string 1 N\zBe \[0] $end +$var string 1 c3h8{ \[1] $end +$upscope $end +$scope struct mask $end +$var wire 1 .SYGD \[0] $end +$var wire 1 />wYd \[1] $end +$upscope $end +$upscope $end +$upscope $end +$upscope $end +$enddefinitions $end +$dumpvars +s sz>#| +s G._83 +s 2r3#W +s AbGF% +s .^<$p +s ?s@Dc +s {*||o +s Bg,vB +0J(7*b +b0 @t0}\ +078"T5 +0G7v@m +s[,\x20] F&^FN +b0 "fUdW +0r1OK) +0,ADvU +s pD.mP +s !V!em +0l8dgD +01/sDs +b0 .0()- +0GEbRA +0;`9BK +s _Xe"P +s jXrsx +b0 '8u?z +0~o=`& +0*q>M1 +s N\zBe +s c3h8{ +0.SYGD +0/>wYd +$end +#500000 +1J(7*b +1;`9BK +1*q>M1 +#1000000 +0J(7*b +1r1OK) +smem[0][0] pD.mP +smem[0][1] !V!em +1l8dgD +11/sDs +0;`9BK +1~o=`& +0*q>M1 +smem[0][0] N\zBe +smem[0][1] c3h8{ +1.SYGD +1/>wYd +#1500000 +smem[0][0] sz>#| +smem[0][1] G._83 +1J(7*b +1;`9BK +1*q>M1 +#2000000 +0J(7*b +b1 "fUdW +smem[1][0] pD.mP +smem[1][1] !V!em +0;`9BK +b1 '8u?z +0*q>M1 +smem[1][0] N\zBe +smem[1][1] c3h8{ +#2500000 +smem[1][0] 2r3#W +smem[1][1] AbGF% +1J(7*b +1;`9BK +1*q>M1 +#3000000 +0J(7*b +b10 "fUdW +smem[2][0] pD.mP +smem[2][1] !V!em +0;`9BK +b10 '8u?z +0*q>M1 +smem[2][0] N\zBe +smem[2][1] c3h8{ +#3500000 +smem[2][0] .^<$p +smem[2][1] ?s@Dc +1J(7*b +1;`9BK +1*q>M1 +#4000000 +0J(7*b +b11 "fUdW +smem[3][0] pD.mP +smem[3][1] !V!em +0;`9BK +b11 '8u?z +0*q>M1 +smem[3][0] N\zBe +smem[3][1] c3h8{ +#4500000 +smem[3][0] {*||o +smem[3][1] Bg,vB +1J(7*b +1;`9BK +1*q>M1 +#5000000 +0J(7*b +b1 @t0}\ +178"T5 +s[mem[1][0],\x20mem[1][1]] F&^FN +b0 "fUdW +0r1OK) +s pD.mP +s !V!em +b1 .0()- +1GEbRA +0;`9BK +smem[1][0] _Xe"P +smem[1][1] jXrsx +b0 '8u?z +0~o=`& +0*q>M1 +s N\zBe +s c3h8{ +#5500000 +1J(7*b +1;`9BK +1*q>M1 +#6000000 +0J(7*b +b1 "fUdW +1r1OK) +0;`9BK +b1 '8u?z +1~o=`& +0*q>M1 +#6500000 +s 2r3#W +s AbGF% +1J(7*b +s F&^FN +1;`9BK +s _Xe"P +s jXrsx +1*q>M1 +#7000000 diff --git a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr b/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr index 44aff3f..8eff725 100644 --- a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr +++ b/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr @@ -55,7 +55,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta note: required because it appears within the type `DynSimOnlyValue` --> src/sim/value/sim_only_value_unsafe.rs | - 271 | pub struct DynSimOnlyValue(Rc); + 281 | pub struct DynSimOnlyValue(Rc); | ^^^^^^^^^^^^^^^ note: required because it appears within the type `PhantomData` --> $RUST/core/src/marker.rs @@ -75,12 +75,12 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 761 | pub struct OpaqueSimValue { + 896 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs | - 52 | struct SimValueInner { + 51 | struct SimValueInner { | ^^^^^^^^^^^^^ note: required because it appears within the type `UnsafeCell>` --> $RUST/core/src/cell.rs @@ -95,7 +95,7 @@ note: required because it appears within the type `util::alternating_cell::Alter note: required because it appears within the type `fayalite::prelude::SimValue<()>` --> src/sim/value.rs | - 161 | pub struct SimValue { + 160 | pub struct SimValue { | ^^^^^^^^ note: required by a bound in `fayalite::intern::Interned` --> src/intern.rs @@ -194,7 +194,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta note: required because it appears within the type `DynSimOnlyValue` --> src/sim/value/sim_only_value_unsafe.rs | - 271 | pub struct DynSimOnlyValue(Rc); + 281 | pub struct DynSimOnlyValue(Rc); | ^^^^^^^^^^^^^^^ note: required because it appears within the type `PhantomData` --> $RUST/core/src/marker.rs @@ -214,12 +214,12 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 761 | pub struct OpaqueSimValue { + 896 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs | - 52 | struct SimValueInner { + 51 | struct SimValueInner { | ^^^^^^^^^^^^^ note: required because it appears within the type `UnsafeCell>` --> $RUST/core/src/cell.rs @@ -234,7 +234,7 @@ note: required because it appears within the type `util::alternating_cell::Alter note: required because it appears within the type `fayalite::prelude::SimValue<()>` --> src/sim/value.rs | - 161 | pub struct SimValue { + 160 | pub struct SimValue { | ^^^^^^^^ note: required by a bound in `intern_sized` --> src/intern.rs @@ -306,7 +306,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta note: required because it appears within the type `DynSimOnlyValue` --> src/sim/value/sim_only_value_unsafe.rs | - 271 | pub struct DynSimOnlyValue(Rc); + 281 | pub struct DynSimOnlyValue(Rc); | ^^^^^^^^^^^^^^^ note: required because it appears within the type `PhantomData` --> $RUST/core/src/marker.rs @@ -326,12 +326,12 @@ note: required because it appears within the type `Vec` note: required because it appears within the type `OpaqueSimValue` --> src/ty.rs | - 761 | pub struct OpaqueSimValue { + 896 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs | - 52 | struct SimValueInner { + 51 | struct SimValueInner { | ^^^^^^^^^^^^^ note: required because it appears within the type `UnsafeCell>` --> $RUST/core/src/cell.rs @@ -346,7 +346,7 @@ note: required because it appears within the type `util::alternating_cell::Alter note: required because it appears within the type `fayalite::prelude::SimValue<()>` --> src/sim/value.rs | - 161 | pub struct SimValue { + 160 | pub struct SimValue { | ^^^^^^^^ note: required by a bound in `fayalite::intern::Interned` --> src/intern.rs diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index a74cef9..fd0e9fe 100644 --- a/crates/fayalite/visit_types.json +++ b/crates/fayalite/visit_types.json @@ -51,7 +51,8 @@ "Reset": "Visible", "Clock": "Visible", "PhantomConst": "Visible", - "DynSimOnly": "Visible" + "DynSimOnly": "Visible", + "TraceAsString": "Visible" } }, "Bundle": { @@ -1021,6 +1022,37 @@ "fold_where": "T: Fold", "visit_where": "T: Visit" }, + "ops::ToTraceAsString": { + "data": { + "$kind": "Struct", + "$constructor": "ops::ToTraceAsString::new", + "inner()": "Visible", + "ty()": "Visible" + }, + "generics": "", + "fold_where": "T: Fold", + "visit_where": "T: Visit" + }, + "ops::TraceAsStringAsInner": { + "data": { + "$kind": "Struct", + "$constructor": "ops::TraceAsStringAsInner::new", + "arg_typed()": "Visible" + }, + "generics": "", + "fold_where": "T: Fold", + "visit_where": "T: Visit" + }, + "ops::FormalInputExpr": { + "data": { + "$kind": "Struct", + "$constructor": "ops::FormalInputExpr::new", + "formal_input()": "Visible" + }, + "generics": "", + "fold_where": "T: Fold", + "visit_where": "T: Visit" + }, "BlockId": { "data": { "$kind": "Opaque" @@ -1255,7 +1287,8 @@ "RegSync": "Visible", "RegAsync": "Visible", "Wire": "Visible", - "Instance": "Visible" + "Instance": "Visible", + "FormalInput": "Visible" } }, "TargetChild": { @@ -1283,12 +1316,25 @@ "$kind": "Struct" } }, + "TargetPathTraceAsStringInner": { + "data": { + "$kind": "Struct" + } + }, + "TargetPathToTraceAsString": { + "data": { + "$kind": "Struct", + "ty": "Visible" + } + }, "TargetPathElement": { "data": { "$kind": "Enum", "BundleField": "Visible", "ArrayElement": "Visible", - "DynArrayElement": "Visible" + "DynArrayElement": "Visible", + "TraceAsStringInner": "Visible", + "ToTraceAsString": "Visible" } }, "PhantomConst": { @@ -1306,6 +1352,29 @@ "data": { "$kind": "ManualImpl" } + }, + "TraceAsString": { + "data": { + "$kind": "ManualImpl" + }, + "generics": "", + "fold_where": "T: Fold", + "visit_where": "T: Visit" + }, + "FormalInput": { + "data": { + "$kind": "Struct", + "$constructor": "FormalInput::new", + "kind": "Visible", + "name_id": "Visible", + "ty": "Visible", + "source_location": "Visible" + } + }, + "FormalInputKind": { + "data": { + "$kind": "Opaque" + } } } } \ No newline at end of file