From ea183eac8722a8ed1156420f9028364428c792ff Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Mon, 11 May 2026 22:44:54 -0700 Subject: [PATCH] add TraceAsString -- sim traces it as a string rather than all its internal fields --- crates/fayalite/src/expr.rs | 33 +- crates/fayalite/src/expr/ops.rs | 189 +- crates/fayalite/src/expr/target.rs | 58 +- crates/fayalite/src/firrtl.rs | 27 +- crates/fayalite/src/int.rs | 3 + crates/fayalite/src/memory.rs | 1 + crates/fayalite/src/module.rs | 97 +- .../src/module/transform/deduce_resets.rs | 177 +- .../src/module/transform/simplify_enums.rs | 43 +- .../src/module/transform/simplify_memories.rs | 39 +- crates/fayalite/src/module/transform/visit.rs | 7 +- crates/fayalite/src/sim.rs | 157 +- crates/fayalite/src/sim/compiler.rs | 217 +- crates/fayalite/src/sim/interpreter.rs | 17 +- crates/fayalite/src/sim/interpreter/parts.rs | 34 + crates/fayalite/src/sim/value.rs | 3 +- crates/fayalite/src/sim/vcd.rs | 63 +- crates/fayalite/src/ty.rs | 584 ++++- crates/fayalite/src/ty/serde_impls.rs | 24 +- crates/fayalite/src/util.rs | 1 + crates/fayalite/src/util/serde_by_id.rs | 234 ++ .../vendor/xilinx/yosys_nextpnr_prjxray.rs | 5 +- crates/fayalite/tests/sim.rs | 629 ++++- .../sim/expected/sim_trace_as_string.txt | 2254 +++++++++++++++++ .../sim/expected/sim_trace_as_string.vcd | 221 ++ .../ui/simvalue_is_not_internable.stderr | 6 +- crates/fayalite/visit_types.json | 47 +- 27 files changed, 5002 insertions(+), 168 deletions(-) create mode 100644 crates/fayalite/src/util/serde_by_id.rs create mode 100644 crates/fayalite/tests/sim/expected/sim_trace_as_string.txt create mode 100644 crates/fayalite/tests/sim/expected/sim_trace_as_string.vcd diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index 00a0cee..3309fb1 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), + AsTraceAsString(ops::AsTraceAsString), + TraceAsStringAsInner(ops::TraceAsStringAsInner), ModuleIO(ModuleIO), Instance(Instance), Wire(Wire), @@ -389,6 +391,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::AsTraceAsString::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 { diff --git a/crates/fayalite/src/expr/ops.rs b/crates/fayalite/src/expr/ops.rs index f4cfebd..22a0d99 100644 --- a/crates/fayalite/src/expr/ops.rs +++ b/crates/fayalite/src/expr/ops.rs @@ -11,8 +11,9 @@ use crate::{ HdlPartialEqImpl, HdlPartialOrd, HdlPartialOrdImpl, NotALiteralExpr, ReduceBitsImpl, ToExpr, ToLiteralBits, ToSimValueInner, ToValueless, ValueType, Valueless, target::{ - GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, - TargetPathDynArrayElement, TargetPathElement, + GetTarget, Target, TargetPathArrayElement, TargetPathAsTraceAsString, + TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, + TargetPathTraceAsStringInner, }, value_category::ValueCategoryExpr, }, @@ -27,7 +28,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}; @@ -4694,3 +4695,185 @@ impl, A> FromIterator for Expr { This::expr_from_iter(iter) } } + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct AsTraceAsString { + inner: Expr, + ty: TraceAsString, + literal_bits: Result, NotALiteralExpr>, + target: Option>, +} + +impl fmt::Debug for AsTraceAsString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + inner, + ty: _, + literal_bits: _, + target: _, + } = self; + f.debug_struct("AsTraceAsString") + .field("inner", inner) + .finish_non_exhaustive() + } +} + +impl AsTraceAsString { + 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( + TargetPathAsTraceAsString { + ty: ty.canonical_trace_as_string(), + } + .into(), + )), + ) + }); + Self { + inner, + ty, + literal_bits, + target, + } + } + pub fn inner(self) -> Expr { + self.inner + } +} + +impl GetTarget for AsTraceAsString { + fn target(&self) -> Option> { + self.target + } +} + +impl ToLiteralBits for AsTraceAsString { + fn to_literal_bits(&self) -> Result, NotALiteralExpr> { + self.literal_bits + } +} + +impl ValueType for AsTraceAsString { + type Type = TraceAsString; + type ValueCategory = ValueCategoryExpr; + + fn ty(&self) -> Self::Type { + self.ty + } +} + +impl ToExpr for AsTraceAsString { + fn to_expr(&self) -> Expr { + Expr { + __enum: ExprEnum::AsTraceAsString(AsTraceAsString { + 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(), + ))) + }); + 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), + } + } +} diff --git a/crates/fayalite/src/expr/target.rs b/crates/fayalite/src/expr/target.rs index 95d8e0f..5140719 100644 --- a/crates/fayalite/src/expr/target.rs +++ b/crates/fayalite/src/expr/target.rs @@ -10,7 +10,7 @@ use crate::{ 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 +46,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 TargetPathAsTraceAsString { + pub ty: TraceAsString, +} + +impl fmt::Display for TargetPathAsTraceAsString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, ".as_trace_as_string(...)") + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum TargetPathElement { BundleField(TargetPathBundleField), ArrayElement(TargetPathArrayElement), DynArrayElement(TargetPathDynArrayElement), + TraceAsStringInner(TargetPathTraceAsStringInner), + AsTraceAsString(TargetPathAsTraceAsString), } impl From for TargetPathElement { @@ -71,12 +93,26 @@ impl From for TargetPathElement { } } +impl From for TargetPathElement { + fn from(value: TargetPathTraceAsStringInner) -> Self { + Self::TraceAsStringInner(value) + } +} + +impl From for TargetPathElement { + fn from(value: TargetPathAsTraceAsString) -> Self { + Self::AsTraceAsString(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::AsTraceAsString(v) => v.fmt(f), } } } @@ -100,6 +136,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::AsTraceAsString(TargetPathAsTraceAsString { ty }) => { + assert_eq!(parent.canonical_ty(), ty.inner_ty()); + ty.canonical() + } } } pub fn flow(&self, parent: Interned) -> Flow { @@ -111,13 +156,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::AsTraceAsString(_) => parent.flow(), } } pub fn is_static(&self) -> bool { match self { - Self::BundleField(_) | Self::ArrayElement(_) => true, + Self::BundleField(_) + | Self::ArrayElement(_) + | Self::TraceAsStringInner(_) + | Self::AsTraceAsString(_) => true, Self::DynArrayElement(_) => false, } } diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index 383bd95..23aeb2e 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -16,6 +16,7 @@ use crate::{ ops::{self, VariantAccess}, target::{ Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, + TargetPathTraceAsStringInner, }, }, formal::FormalKind, @@ -471,7 +472,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,6 +491,7 @@ impl TypeState { CanonicalType::DynSimOnly(_) => { return Err(FirrtlError::SimOnlyValuesAreNotPermitted); } + CanonicalType::TraceAsString(_) => unreachable!("handled by unwrap_transparent_types"), }) } } @@ -1191,7 +1193,7 @@ impl<'a> Exporter<'a> { definitions: &RcDefinitions, 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,6 +1212,7 @@ 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( @@ -1407,7 +1410,7 @@ impl<'a> Exporter<'a> { definitions: &RcDefinitions, 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) } @@ -1431,6 +1434,7 @@ impl<'a> Exporter<'a> { return Ok(retval.to_string()); } CanonicalType::DynSimOnly(_) => Err(FirrtlError::SimOnlyValuesAreNotPermitted.into()), + CanonicalType::TraceAsString(_) => unreachable!("handled by unwrap_transparent_types"), } } fn expr_unary( @@ -1798,6 +1802,10 @@ impl<'a> Exporter<'a> { write!(out, "[{index}]").unwrap(); Ok(out) } + ExprEnum::AsTraceAsString(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"); @@ -1957,6 +1965,10 @@ impl<'a> Exporter<'a> { .segments .push(AnnotationTargetRefSegment::Index { index }), TargetPathElement::DynArrayElement(_) => unreachable!(), + TargetPathElement::AsTraceAsString(_) + | TargetPathElement::TraceAsStringInner(_) => { + // ignored + } } Ok(retval) } @@ -3211,6 +3223,8 @@ impl ScalarizeTreeNode { TargetPathElement::DynArrayElement(_) => { unreachable!("annotations are only on static targets"); } + TargetPathElement::AsTraceAsString(_) + | TargetPathElement::TraceAsStringInner(_) => parent, } } } @@ -3337,6 +3351,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/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..f39f800 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -12,7 +12,7 @@ use crate::{ ops::VariantAccess, target::{ GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, - TargetPathElement, + TargetPathElement, TargetPathTraceAsStringInner, }, value_category::ValueCategoryExpr, }, @@ -1111,7 +1111,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::AsTraceAsString(_) + | 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:?}" @@ -1586,6 +1589,14 @@ impl TargetState { declared_in_block, written_in_blocks: RefCell::default(), }, + CanonicalType::TraceAsString(_) => { + return Self::new( + target + .join(Intern::intern_sized(TargetPathTraceAsStringInner {}.into())) + .intern_sized(), + declared_in_block, + ); + } }, } } @@ -1605,44 +1616,58 @@ impl AssertValidityState { } fn get_target_states<'a>( &'a self, - target: &Target, + mut 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); + 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::AsTraceAsString(_) => unreachable!(), } - } + }, + ), + TargetPathElement::TraceAsStringInner(_) + | TargetPathElement::AsTraceAsString(_) => { + target = Interned::into_inner(target_child.parent()); + continue; } }, - ), + }; } } fn get_base_state(&self, target_base: Interned) -> Result<&TargetState, ()> { @@ -1716,6 +1741,8 @@ impl AssertValidityState { TargetPathElement::DynArrayElement { .. } => { Self::set_connect_target_written(sub_target_state, is_lhs, block, true); } + TargetPathElement::TraceAsStringInner(_) + | TargetPathElement::AsTraceAsString(_) => unreachable!("never added"), } } } diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs index 61167fd..ef95c1c 100644 --- a/crates/fayalite/src/module/transform/deduce_resets.rs +++ b/crates/fayalite/src/module/transform/deduce_resets.rs @@ -9,8 +9,9 @@ use crate::{ ExprEnum, ValueType, ops::{self, ArrayLiteral}, target::{ - Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, - TargetPathDynArrayElement, TargetPathElement, + Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathAsTraceAsString, + TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, + 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::AsTraceAsString(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)), @@ -1536,6 +1588,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::AsTraceAsString { + 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 +1804,8 @@ impl RunPassDispatch for AnyReg { | CanonicalType::Reset(_) | CanonicalType::Clock(_) | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => unreachable!(), + | CanonicalType::DynSimOnly(_) + | CanonicalType::TraceAsString(_) => unreachable!(), } }) } @@ -2173,30 +2287,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 +2294,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::AsTraceAsString(TargetPathAsTraceAsString { ty }) => { + TargetPathElement::from(TargetPathAsTraceAsString { + 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..02b4dda 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(_) @@ -313,6 +314,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 +528,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 +556,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 +603,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 +617,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(), @@ -772,6 +806,8 @@ impl Folder for State { | ExprEnum::SliceSInt(_) | ExprEnum::CastToBits(_) | ExprEnum::CastBitsTo(_) + | ExprEnum::TraceAsStringAsInner(_) + | ExprEnum::AsTraceAsString(_) | ExprEnum::ModuleIO(_) | ExprEnum::Instance(_) | ExprEnum::Wire(_) @@ -936,7 +972,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..134d9a8 100644 --- a/crates/fayalite/src/module/transform/visit.rs +++ b/crates/fayalite/src/module/transform/visit.rs @@ -13,8 +13,9 @@ use crate::{ expr::{ Expr, ExprEnum, ValueType, ops, target::{ - Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, - TargetPathDynArrayElement, TargetPathElement, + Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathAsTraceAsString, + TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, + TargetPathTraceAsStringInner, }, }, formal::FormalKind, @@ -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/sim.rs b/crates/fayalite/src/sim.rs index 4a7721b..658ae10 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::AsTraceAsString(_) => {} 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) @@ -2233,6 +2343,9 @@ impl SimulationImpl { .sim_only_slots .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,6 +2399,20 @@ 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); @@ -2818,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 { @@ -2833,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(), @@ -2909,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, @@ -2937,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, @@ -2970,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..4f5c571 100644 --- a/crates/fayalite/src/sim/compiler.rs +++ b/crates/fayalite/src/sim/compiler.rs @@ -9,8 +9,8 @@ use crate::{ expr::{ ExprEnum, Flow, ValueType, ops, target::{ - GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, - TargetPathElement, + GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathAsTraceAsString, + TargetPathBundleField, TargetPathElement, 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::AsTraceAsString(TargetPathAsTraceAsString { 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::AsTraceAsString::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::AsTraceAsString(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 e16519b..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}, @@ -920,6 +920,12 @@ impl StatePart { ) -> bool { 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) } @@ -1018,6 +1024,11 @@ 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();)* diff --git a/crates/fayalite/src/sim/interpreter/parts.rs b/crates/fayalite/src/sim/interpreter/parts.rs index 308ac44..0d98c06 100644 --- a/crates/fayalite/src/sim/interpreter/parts.rs +++ b/crates/fayalite/src/sim/interpreter/parts.rs @@ -260,6 +260,10 @@ pub(crate) trait StatePartKind: 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>, @@ -342,6 +346,12 @@ impl StatePartKind for StatePartKindMemories { ) -> 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>, @@ -446,6 +456,14 @@ impl StatePartKind for StatePartKindSmallSlots { ) -> bool { 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); } @@ -530,6 +548,14 @@ impl StatePartKind for StatePartKindBigSlots { ) -> bool { 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); } @@ -614,6 +640,14 @@ impl StatePartKind for StatePartKindSimOnlySlots { ) -> bool { 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); } diff --git a/crates/fayalite/src/sim/value.rs b/crates/fayalite/src/sim/value.rs index eaa3f8d..79515ac 100644 --- a/crates/fayalite/src/sim/value.rs +++ b/crates/fayalite/src/sim/value.rs @@ -1098,7 +1098,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(_) 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..2988a7d 100644 --- a/crates/fayalite/src/ty.rs +++ b/crates/fayalite/src/ty.rs @@ -3,22 +3,27 @@ use crate::{ array::Array, - bundle::Bundle, + bundle::{Bundle, BundleField, BundleType}, clock::Clock, - enum_::Enum, - expr::Expr, + enum_::{Enum, EnumType, EnumVariant}, + expr::{Expr, ToExpr, ValueType, 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, + fmt::{self, Write}, hash::Hash, iter::{FusedIterator, Sum}, marker::PhantomData, @@ -69,6 +74,7 @@ pub enum CanonicalType { Clock(Clock), PhantomConst(PhantomConst), DynSimOnly(DynSimOnly), + TraceAsString(TraceAsString), } impl fmt::Debug for CanonicalType { @@ -86,6 +92,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 +130,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 +225,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 +459,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 +468,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 +606,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 +891,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 { @@ -842,6 +997,9 @@ impl OpaqueSimValue { pub fn sim_only_values(&self) -> &[DynSimOnlyValue] { &self.sim_only_values } + pub(crate) fn sim_only_values_vec(&self) -> &Vec { + &self.sim_only_values + } pub fn sim_only_values_mut(&mut self) -> &mut Vec { &mut self.sim_only_values } @@ -1143,3 +1301,413 @@ 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; +} + +impl TraceAsStringTrait for T { + fn trace_fmt( + &self, + opaque: OpaqueSimValueSlice<'_>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + fmt::Debug::fmt(&Type::sim_value_from_opaque(self, opaque), f) + } + fn can_substitute_type(&self, new_type: CanonicalType) -> bool { + self.canonical().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( + 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, 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: self.inner_ty.sim_value_from_opaque(opaque), + } + } + + 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(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(Copy, Clone, Eq, Ord, Hash, Default, Serialize, Deserialize)] +pub struct TraceAsStringSimValue { + inner: T, +} + +impl TraceAsStringSimValue { + pub const fn new(inner: T) -> Self { + Self { inner } + } + pub fn into_inner(this: Self) -> T { + let Self { inner } = this; + inner + } +} + +impl ValueType for TraceAsStringSimValue { + type Type = TraceAsString; + type ValueCategory = T::ValueCategory; + + fn ty(&self) -> Self::Type { + TraceAsString::new(self.inner.ty()) + } +} + +impl ToExpr for TraceAsStringSimValue { + fn to_expr(&self) -> Expr { + let inner = self.inner.to_expr(); + ops::AsTraceAsString::new(Expr::canonical(inner), TraceAsString::new(inner.ty())).to_expr() + } +} + +impl, Ty: Type> 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()); + let inner = SimValue::into_value(inner); + SimValue::from_value(ty, TraceAsStringSimValue { inner }) + } + fn into_sim_value_with_type(self, ty: TraceAsString) -> SimValue> { + let inner = self.inner.into_sim_value_with_type(ty.inner_ty()); + let inner = SimValue::into_value(inner); + SimValue::from_value(ty, TraceAsStringSimValue { inner }) + } +} + +impl ToSimValue for TraceAsStringSimValue { + fn to_sim_value(&self) -> SimValue { + self.to_sim_value_with_type(self.ty()) + } + fn into_sim_value(self) -> SimValue { + let ty = self.ty(); + self.into_sim_value_with_type(ty) + } +} + +impl std::ops::Deref for TraceAsStringSimValue { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for TraceAsStringSimValue { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl fmt::Debug for TraceAsStringSimValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { inner } = self; + fmt::Debug::fmt(inner, f) + } +} + +impl fmt::Display for TraceAsStringSimValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { inner } = self; + fmt::Display::fmt(inner, f) + } +} + +impl, U> PartialOrd> for TraceAsStringSimValue { + fn partial_cmp(&self, other: &TraceAsStringSimValue) -> Option { + let Self { inner } = self; + inner.partial_cmp(&other.inner) + } +} + +impl, U> PartialEq> for TraceAsStringSimValue { + fn eq(&self, other: &TraceAsStringSimValue) -> bool { + let Self { inner } = 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) + } +} diff --git a/crates/fayalite/src/ty/serde_impls.rs b/crates/fayalite/src/ty/serde_impls.rs index af324f9..126c4b0 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}; @@ -65,6 +66,10 @@ pub(crate) enum SerdeCanonicalType< Clock, PhantomConst(ThePhantomConst), DynSimOnly(DynSimOnly), + TraceAsString { + inner_ty: Interned, + trace_as_string: SerdeById>, + }, } impl SerdeCanonicalType { @@ -82,6 +87,7 @@ impl SerdeCanonicalType "a Clock", Self::PhantomConst(_) => "a PhantomConst", Self::DynSimOnly(_) => "a SimOnlyValue", + Self::TraceAsString { .. } => "a TraceAsString", } } } @@ -109,6 +115,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 +145,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..2d498e7 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 { diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 53f7d9d..238259c 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, StaticType, TraceAsString, TraceAsStringSimValue}, util::{RcWriter, ready_valid::queue}, }; use std::{collections::BTreeMap, num::NonZeroUsize, rc::Rc}; @@ -2985,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() + } + } + } +} + +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( + [[Expr::as_trace_as_string(HasCustomDebug::new_sim(Ok("")).to_expr(), StaticType::TYPE); 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| TraceAsStringSimValue::new(HasCustomDebug::new_sim(v))), + ); + 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 == *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/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..dbdf937 100644 --- a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr +++ b/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr @@ -75,7 +75,7 @@ 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 { + 895 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs @@ -214,7 +214,7 @@ 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 { + 895 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs @@ -326,7 +326,7 @@ 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 { + 895 | pub struct OpaqueSimValue { | ^^^^^^^^^^^^^^ note: required because it appears within the type `value::SimValueInner<()>` --> src/sim/value.rs diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index a74cef9..f5d666c 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,27 @@ "fold_where": "T: Fold", "visit_where": "T: Visit" }, + "ops::AsTraceAsString": { + "data": { + "$kind": "Struct", + "$constructor": "ops::AsTraceAsString::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" + }, "BlockId": { "data": { "$kind": "Opaque" @@ -1283,12 +1305,25 @@ "$kind": "Struct" } }, + "TargetPathTraceAsStringInner": { + "data": { + "$kind": "Struct" + } + }, + "TargetPathAsTraceAsString": { + "data": { + "$kind": "Struct", + "ty": "Visible" + } + }, "TargetPathElement": { "data": { "$kind": "Enum", "BundleField": "Visible", "ArrayElement": "Visible", - "DynArrayElement": "Visible" + "DynArrayElement": "Visible", + "TraceAsStringInner": "Visible", + "AsTraceAsString": "Visible" } }, "PhantomConst": { @@ -1306,6 +1341,14 @@ "data": { "$kind": "ManualImpl" } + }, + "TraceAsString": { + "data": { + "$kind": "ManualImpl" + }, + "generics": "", + "fold_where": "T: Fold", + "visit_where": "T: Visit" } } } \ No newline at end of file