diff --git a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs index 6193dc3..3b2e1ec 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs @@ -2069,11 +2069,16 @@ macro_rules! impl_bounds { $( $Variant:ident, )* + $( + #[unknown] + $Unknown:ident, + )? } ) => { #[derive(Clone, Debug)] $vis enum $enum_type { $($Variant(known_items::$Variant),)* + $($Unknown(syn::TypeParamBound),)? } $(impl From for $enum_type { @@ -2086,28 +2091,54 @@ macro_rules! impl_bounds { fn to_tokens(&self, tokens: &mut TokenStream) { match self { $(Self::$Variant(v) => v.to_tokens(tokens),)* + $(Self::$Unknown(v) => v.to_tokens(tokens),)? } } } impl $enum_type { $vis fn parse_path(path: Path) -> Result { + #![allow(unreachable_code)] $(let path = match known_items::$Variant::parse_path(path) { Ok(v) => return Ok(Self::$Variant(v)), Err(path) => path, };)* + $(return Ok(Self::$Unknown(syn::TraitBound { + paren_token: None, + modifier: syn::TraitBoundModifier::None, + lifetimes: None, + path, + }.into()));)? Err(path) } + $vis fn parse_type_param_bound(mut type_param_bound: syn::TypeParamBound) -> Result { + #![allow(unreachable_code)] + if let syn::TypeParamBound::Trait(mut trait_bound) = type_param_bound { + if let syn::TraitBound { + paren_token: _, + modifier: syn::TraitBoundModifier::None, + lifetimes: None, + path: _, + } = trait_bound { + match Self::parse_path(trait_bound.path) { + Ok(retval) => return Ok(retval), + Err(path) => trait_bound.path = path, + } + } + type_param_bound = trait_bound.into(); + } + $(return Ok(Self::$Unknown(type_param_bound));)? + Err(type_param_bound) + } } impl Parse for $enum_type { fn parse(input: ParseStream) -> syn::Result { - Self::parse_path(Path::parse_mod_style(input)?).map_err(|path| { - syn::Error::new_spanned( - path, + Self::parse_type_param_bound(input.parse()?) + .map_err(|type_param_bound| syn::Error::new_spanned( + type_param_bound, format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")), - ) - }) + )) } } @@ -2115,6 +2146,7 @@ macro_rules! impl_bounds { #[allow(non_snake_case)] $vis struct $struct_type { $($vis $Variant: Option,)* + $($vis $Unknown: Vec,)? } impl ToTokens for $struct_type { @@ -2126,42 +2158,63 @@ macro_rules! impl_bounds { separator = Some(::default()); v.to_tokens(tokens); })* + $(for v in &self.$Unknown { + separator.to_tokens(tokens); + separator = Some(::default()); + v.to_tokens(tokens); + })* } } const _: () = { #[derive(Clone, Debug)] - $vis struct Iter($vis $struct_type); + #[allow(non_snake_case)] + $vis struct Iter { + $($Variant: Option,)* + $($Unknown: std::vec::IntoIter,)? + } impl IntoIterator for $struct_type { type Item = $enum_type; type IntoIter = Iter; fn into_iter(self) -> Self::IntoIter { - Iter(self) + Iter { + $($Variant: self.$Variant,)* + $($Unknown: self.$Unknown.into_iter(),)? + } } } impl Iterator for Iter { type Item = $enum_type; - fn next(&mut self) -> Option { $( - if let Some(value) = self.0.$Variant.take() { + if let Some(value) = self.$Variant.take() { return Some($enum_type::$Variant(value)); } )* + $( + if let Some(value) = self.$Unknown.next() { + return Some($enum_type::$Unknown(value)); + } + )? None } #[allow(unused_mut, unused_variables)] fn fold B>(mut self, mut init: B, mut f: F) -> B { $( - if let Some(value) = self.0.$Variant.take() { + if let Some(value) = self.$Variant.take() { init = f(init, $enum_type::$Variant(value)); } )* + $( + if let Some(value) = self.$Unknown.next() { + init = f(init, $enum_type::$Unknown(value)); + } + )? init } } @@ -2173,6 +2226,9 @@ macro_rules! impl_bounds { $($enum_type::$Variant(v) => { self.$Variant = Some(v); })* + $($enum_type::$Unknown(v) => { + self.$Unknown.push(v); + })? }); } } @@ -2191,6 +2247,7 @@ macro_rules! impl_bounds { $(if let Some(v) = v.$Variant { self.$Variant = Some(v); })* + $(self.$Unknown.extend(v.$Unknown);)* }); } } @@ -2244,6 +2301,8 @@ impl_bounds! { Size, StaticType, Type, + #[unknown] + Unknown, } } @@ -2257,6 +2316,8 @@ impl_bounds! { ResetType, StaticType, Type, + #[unknown] + Unknown, } } @@ -2270,6 +2331,7 @@ impl From for ParsedBound { ParsedTypeBound::ResetType(v) => ParsedBound::ResetType(v), ParsedTypeBound::StaticType(v) => ParsedBound::StaticType(v), ParsedTypeBound::Type(v) => ParsedBound::Type(v), + ParsedTypeBound::Unknown(v) => ParsedBound::Unknown(v), } } } @@ -2284,6 +2346,7 @@ impl From for ParsedBounds { ResetType, StaticType, Type, + Unknown, } = value; Self { BoolOrIntType, @@ -2295,6 +2358,7 @@ impl From for ParsedBounds { Size: None, StaticType, Type, + Unknown, } } } @@ -2330,6 +2394,7 @@ impl ParsedTypeBound { ParsedTypeBound::Type(known_items::Type(span)), ]), Self::Type(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::from(v)]), + Self::Unknown(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::Unknown(v)]), } } } @@ -2364,6 +2429,7 @@ impl From for ParsedBounds { Size, StaticType: None, Type: None, + Unknown: vec![], } } } @@ -2391,6 +2457,7 @@ impl ParsedBounds { fn categorize(self, errors: &mut Errors, span: Span) -> ParsedBoundsCategory { let mut type_bounds = None; let mut size_type_bounds = None; + let mut unknown_bounds = vec![]; self.into_iter().for_each(|bound| match bound.categorize() { ParsedBoundCategory::Type(bound) => { type_bounds @@ -2402,15 +2469,37 @@ impl ParsedBounds { .get_or_insert_with(ParsedSizeTypeBounds::default) .extend([bound]); } + ParsedBoundCategory::Unknown(bound) => unknown_bounds.push(bound), }); - match (type_bounds, size_type_bounds) { - (None, None) => ParsedBoundsCategory::Type(ParsedTypeBounds { + match (type_bounds, size_type_bounds, unknown_bounds.is_empty()) { + (None, None, true) => ParsedBoundsCategory::Type(ParsedTypeBounds { Type: Some(known_items::Type(span)), ..Default::default() }), - (None, Some(bounds)) => ParsedBoundsCategory::SizeType(bounds), - (Some(bounds), None) => ParsedBoundsCategory::Type(bounds), - (Some(type_bounds), Some(size_type_bounds)) => { + (None, None, false) => { + errors.error( + unknown_bounds.remove(0), + "unknown bounds: must use at least one known bound (such as `Type`) with any unknown bounds", + ); + ParsedBoundsCategory::Type(ParsedTypeBounds { + Unknown: unknown_bounds, + ..Default::default() + }) + } + (None, Some(bounds), true) => ParsedBoundsCategory::SizeType(bounds), + (None, Some(bounds), false) => { + // TODO: implement + errors.error( + unknown_bounds.remove(0), + "unknown bounds with `Size` bounds are not implemented", + ); + ParsedBoundsCategory::SizeType(bounds) + } + (Some(bounds), None, _) => ParsedBoundsCategory::Type(ParsedTypeBounds { + Unknown: unknown_bounds, + ..bounds + }), + (Some(type_bounds), Some(size_type_bounds), _) => { errors.error( size_type_bounds .Size @@ -2427,6 +2516,7 @@ impl ParsedBounds { pub(crate) enum ParsedBoundCategory { Type(ParsedTypeBound), SizeType(ParsedSizeTypeBound), + Unknown(syn::TypeParamBound), } impl ParsedBound { @@ -2441,12 +2531,14 @@ impl ParsedBound { Self::Size(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::Size(v)), Self::StaticType(v) => ParsedBoundCategory::Type(ParsedTypeBound::StaticType(v)), Self::Type(v) => ParsedBoundCategory::Type(ParsedTypeBound::Type(v)), + Self::Unknown(v) => ParsedBoundCategory::Unknown(v), } } fn implied_bounds(self) -> ParsedBounds { match self.categorize() { ParsedBoundCategory::Type(v) => v.implied_bounds().into(), ParsedBoundCategory::SizeType(v) => v.implied_bounds().into(), + ParsedBoundCategory::Unknown(v) => ParsedBounds::from_iter([ParsedBound::Unknown(v)]), } } } @@ -3325,7 +3417,7 @@ impl ParsedGenerics { | ParsedTypeBound::EnumType(_) | ParsedTypeBound::IntType(_) | ParsedTypeBound::ResetType(_) => { - errors.error(bound, "bound on mask type not implemented"); + errors.error(bound, "bounds on mask types are not implemented"); } ParsedTypeBound::StaticType(bound) => { if bounds.StaticType.is_none() { @@ -3337,6 +3429,12 @@ impl ParsedGenerics { } } ParsedTypeBound::Type(_) => {} + ParsedTypeBound::Unknown(_) => { + errors.error( + bound, + "unknown bounds on mask types are not implemented", + ); + } } } bounds.add_implied_bounds(); diff --git a/crates/fayalite-proc-macros-impl/src/lib.rs b/crates/fayalite-proc-macros-impl/src/lib.rs index 1b1b61f..6ba177b 100644 --- a/crates/fayalite-proc-macros-impl/src/lib.rs +++ b/crates/fayalite-proc-macros-impl/src/lib.rs @@ -1210,17 +1210,29 @@ fn hdl_main( attr: TokenStream, item: TokenStream, ) -> syn::Result { - let (evaluated_cfgs, attr): (_, TokenStream) = Parser::parse2( + fn parse_evaluated_cfgs_attr( + input: ParseStream, + parse_inner: impl FnOnce(ParseStream) -> syn::Result, + ) -> syn::Result { + let _: Token![#] = input.parse()?; + let bracket_content; + bracketed!(bracket_content in input); + let _: kw::__evaluated_cfgs = bracket_content.parse()?; + let paren_content; + parenthesized!(paren_content in bracket_content); + parse_inner(&paren_content) + } + let (evaluated_cfgs, item): (_, TokenStream) = Parser::parse2( |input: ParseStream| { - if input.peek(Bracket) && input.peek2(kw::__evaluated_cfgs) { - let cfgs = input.parse()?; - let _: kw::__evaluated_cfgs = input.parse()?; - Ok((Some(cfgs), input.parse()?)) + let peek = input.fork(); + if parse_evaluated_cfgs_attr(&peek, |_| Ok(())).is_ok() { + let evaluated_cfgs = parse_evaluated_cfgs_attr(input, Cfgs::::parse)?; + Ok((Some(evaluated_cfgs), input.parse()?)) } else { Ok((None, input.parse()?)) } }, - attr, + item, )?; let cfgs = if let Some(cfgs) = evaluated_cfgs { cfgs @@ -1229,12 +1241,11 @@ fn hdl_main( if cfgs.cfgs_list.is_empty() { Cfgs::default() } else { - let key = kw::__evaluated_cfgs::default(); return Ok(quote! { ::fayalite::__cfg_expansion_helper! { [] #cfgs - #[::fayalite::#kw:(#key #attr)] { #item } + {#[::fayalite::#kw(#attr)]} { #item } } }); } diff --git a/crates/fayalite-proc-macros-impl/src/module/transform_body.rs b/crates/fayalite-proc-macros-impl/src/module/transform_body.rs index 6e99e87..c67f8dc 100644 --- a/crates/fayalite-proc-macros-impl/src/module/transform_body.rs +++ b/crates/fayalite-proc-macros-impl/src/module/transform_body.rs @@ -1109,7 +1109,7 @@ fn parse_quote_let_pat>( } } -fn wrap_ty_with_expr(ty: impl ToTokens) -> Type { +pub(crate) fn wrap_ty_with_expr(ty: impl ToTokens) -> Type { parse_quote_spanned! {ty.span()=> ::fayalite::expr::Expr<#ty> } @@ -1586,7 +1586,7 @@ impl Visitor<'_> { } } -fn empty_let() -> Local { +pub(crate) fn empty_let() -> Local { Local { attrs: vec![], let_token: Default::default(), @@ -1672,7 +1672,7 @@ impl Fold for Visitor<'_> { } } - fn fold_local(&mut self, let_stmt: Local) -> Local { + fn fold_local(&mut self, mut let_stmt: Local) -> Local { match self .errors .ok(HdlAttr::::parse_and_leave_attr( @@ -1682,6 +1682,25 @@ impl Fold for Visitor<'_> { Some(None) => return fold_local(self, let_stmt), Some(Some(HdlAttr { .. })) => {} }; + let mut pat = &let_stmt.pat; + if let Pat::Type(pat_type) = pat { + pat = &pat_type.pat; + } + let Pat::Ident(syn::PatIdent { + attrs: _, + by_ref: None, + mutability: _, + ident: _, + subpat: None, + }) = pat + else { + let hdl_attr = HdlAttr::::parse_and_take_attr(&mut let_stmt.attrs) + .ok() + .flatten() + .expect("already checked above"); + let let_stmt = fold_local(self, let_stmt); + return self.process_hdl_let_pat(hdl_attr, let_stmt); + }; let hdl_let = syn::parse2::>>(let_stmt.into_token_stream()); let Some(hdl_let) = self.errors.ok(hdl_let) else { return empty_let(); diff --git a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs index 1d53104..f1ff2c2 100644 --- a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs +++ b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs @@ -3,22 +3,111 @@ use crate::{ fold::{impl_fold, DoFold}, kw, - module::transform_body::{with_debug_clone_and_fold, Visitor}, + module::transform_body::{empty_let, with_debug_clone_and_fold, wrap_ty_with_expr, Visitor}, Errors, HdlAttr, PairsIterExt, }; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote_spanned, ToTokens, TokenStreamExt}; +use std::collections::BTreeSet; use syn::{ - fold::{fold_arm, fold_expr_match, fold_pat, Fold}, + fold::{fold_arm, fold_expr_match, fold_local, fold_pat, Fold}, parse::Nothing, parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, token::{Brace, Paren}, - Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Member, Pat, PatIdent, PatOr, PatParen, - PatPath, PatRest, PatStruct, PatTupleStruct, PatWild, Path, PathSegment, Token, TypePath, + Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Local, Member, Pat, PatIdent, PatOr, + PatParen, PatPath, PatRest, PatStruct, PatTuple, PatTupleStruct, PatWild, Path, PathSegment, + Token, TypePath, }; +macro_rules! visit_trait { + ( + $($vis:vis fn $fn:ident($state:ident: _, $value:ident: &$Value:ty) $block:block)* + ) => { + trait VisitMatchPat<'a> { + $(fn $fn(&mut self, $value: &'a $Value) { + $fn(self, $value); + })* + } + + $($vis fn $fn<'a>($state: &mut (impl ?Sized + VisitMatchPat<'a>), $value: &'a $Value) $block)* + }; +} + +visit_trait! { + fn visit_match_pat_binding(_state: _, v: &MatchPatBinding) { + let MatchPatBinding { ident: _ } = v; + } + fn visit_match_pat_wild(_state: _, v: &MatchPatWild) { + let MatchPatWild { underscore_token: _ } = v; + } + fn visit_match_pat_rest(_state: _, v: &MatchPatRest) { + let MatchPatRest { dot2_token: _ } = v; + } + fn visit_match_pat_paren(state: _, v: &MatchPatParen) { + let MatchPatParen { paren_token: _, pat } = v; + state.visit_match_pat(pat); + } + fn visit_match_pat_paren_simple(state: _, v: &MatchPatParen) { + let MatchPatParen { paren_token: _, pat } = v; + state.visit_match_pat_simple(pat); + } + fn visit_match_pat_or(state: _, v: &MatchPatOr) { + let MatchPatOr { leading_vert: _, cases } = v; + for v in cases { + state.visit_match_pat(v); + } + } + fn visit_match_pat_or_simple(state: _, v: &MatchPatOr) { + let MatchPatOr { leading_vert: _, cases } = v; + for v in cases { + state.visit_match_pat_simple(v); + } + } + fn visit_match_pat_struct_field(state: _, v: &MatchPatStructField) { + let MatchPatStructField { field_name: _, colon_token: _, pat } = v; + state.visit_match_pat_simple(pat); + } + fn visit_match_pat_struct(state: _, v: &MatchPatStruct) { + let MatchPatStruct { match_span: _, path: _, brace_token: _, fields, rest: _ } = v; + for v in fields { + state.visit_match_pat_struct_field(v); + } + } + fn visit_match_pat_tuple(state: _, v: &MatchPatTuple) { + let MatchPatTuple { paren_token: _, fields } = v; + for v in fields { + state.visit_match_pat_simple(v); + } + } + fn visit_match_pat_enum_variant(state: _, v: &MatchPatEnumVariant) { + let MatchPatEnumVariant {match_span:_, variant_path: _, enum_path: _, variant_name: _, field } = v; + if let Some((_, v)) = field { + state.visit_match_pat_simple(v); + } + } + fn visit_match_pat_simple(state: _, v: &MatchPatSimple) { + match v { + MatchPatSimple::Paren(v) => state.visit_match_pat_paren_simple(v), + MatchPatSimple::Or(v) => state.visit_match_pat_or_simple(v), + MatchPatSimple::Binding(v) => state.visit_match_pat_binding(v), + MatchPatSimple::Wild(v) => state.visit_match_pat_wild(v), + MatchPatSimple::Rest(v) => state.visit_match_pat_rest(v), + } + } + fn visit_match_pat(state: _, v: &MatchPat) { + match v { + MatchPat::Simple(v) => state.visit_match_pat_simple(v), + MatchPat::Or(v) => state.visit_match_pat_or(v), + MatchPat::Paren(v) => state.visit_match_pat_paren(v), + MatchPat::Struct(v) => state.visit_match_pat_struct(v), + MatchPat::Tuple(v) => state.visit_match_pat_tuple(v), + MatchPat::EnumVariant(v) => state.visit_match_pat_enum_variant(v), + } + } +} + with_debug_clone_and_fold! { struct MatchPatBinding<> { ident: Ident, @@ -53,6 +142,15 @@ with_debug_clone_and_fold! { } } +impl

MatchPatOr

{ + /// returns the first `|` between two patterns + fn first_inner_vert(&self) -> Option { + let mut pairs = self.cases.pairs(); + pairs.next_back(); + pairs.next().and_then(|v| v.into_tuple().1.copied()) + } +} + impl ToTokens for MatchPatOr

{ fn to_tokens(&self, tokens: &mut TokenStream) { let Self { @@ -77,6 +175,19 @@ impl ToTokens for MatchPatWild { } } +with_debug_clone_and_fold! { + struct MatchPatRest<> { + dot2_token: Token![..], + } +} + +impl ToTokens for MatchPatRest { + fn to_tokens(&self, tokens: &mut TokenStream) { + let Self { dot2_token } = self; + dot2_token.to_tokens(tokens); + } +} + with_debug_clone_and_fold! { struct MatchPatStructField<> { field_name: Ident, @@ -159,6 +270,25 @@ impl ToTokens for MatchPatStruct { } } +with_debug_clone_and_fold! { + struct MatchPatTuple<> { + paren_token: Paren, + fields: Punctuated, + } +} + +impl ToTokens for MatchPatTuple { + fn to_tokens(&self, tokens: &mut TokenStream) { + let Self { + paren_token, + fields, + } = self; + paren_token.surround(tokens, |tokens| { + fields.to_tokens(tokens); + }) + } +} + with_debug_clone_and_fold! { struct MatchPatEnumVariant<> { match_span: Span, @@ -194,6 +324,7 @@ enum MatchPatSimple { Or(MatchPatOr), Binding(MatchPatBinding), Wild(MatchPatWild), + Rest(MatchPatRest), } impl_fold! { @@ -202,6 +333,7 @@ impl_fold! { Or(MatchPatOr), Binding(MatchPatBinding), Wild(MatchPatWild), + Rest(MatchPatRest), } } @@ -212,6 +344,7 @@ impl ToTokens for MatchPatSimple { Self::Paren(v) => v.to_tokens(tokens), Self::Binding(v) => v.to_tokens(tokens), Self::Wild(v) => v.to_tokens(tokens), + Self::Rest(v) => v.to_tokens(tokens), } } } @@ -278,6 +411,7 @@ trait ParseMatchPat: Sized { fn or(v: MatchPatOr) -> Self; fn paren(v: MatchPatParen) -> Self; fn struct_(state: &mut HdlMatchParseState<'_>, v: MatchPatStruct) -> Result; + fn tuple(state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result; fn enum_variant(state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant) -> Result; fn parse(state: &mut HdlMatchParseState<'_>, pat: Pat) -> Result { @@ -462,7 +596,34 @@ trait ParseMatchPat: Sized { }) => Ok(Self::simple(MatchPatSimple::Wild(MatchPatWild { underscore_token, }))), - Pat::Tuple(_) | Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => { + Pat::Tuple(PatTuple { + attrs: _, + paren_token, + elems, + }) => { + let fields = elems + .into_pairs() + .filter_map_pair_value(|field_pat| { + if let Pat::Rest(PatRest { + attrs: _, + dot2_token, + }) = field_pat + { + Some(MatchPatSimple::Rest(MatchPatRest { dot2_token })) + } else { + MatchPatSimple::parse(state, field_pat).ok() + } + }) + .collect(); + Self::tuple( + state, + MatchPatTuple { + paren_token, + fields, + }, + ) + } + Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => { state .errors .error(pat, "not yet implemented in #[hdl] patterns"); @@ -497,6 +658,14 @@ impl ParseMatchPat for MatchPatSimple { Err(()) } + fn tuple(state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result { + state.errors.push(syn::Error::new( + v.paren_token.span.open(), + "matching tuples is not yet implemented inside structs/enums in #[hdl] patterns", + )); + Err(()) + } + fn enum_variant( state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant, @@ -515,6 +684,7 @@ enum MatchPat { Or(MatchPatOr), Paren(MatchPatParen), Struct(MatchPatStruct), + Tuple(MatchPatTuple), EnumVariant(MatchPatEnumVariant), } @@ -524,6 +694,7 @@ impl_fold! { Or(MatchPatOr), Paren(MatchPatParen), Struct(MatchPatStruct), + Tuple(MatchPatTuple), EnumVariant(MatchPatEnumVariant), } } @@ -545,6 +716,10 @@ impl ParseMatchPat for MatchPat { Ok(Self::Struct(v)) } + fn tuple(_state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result { + Ok(Self::Tuple(v)) + } + fn enum_variant( _state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant, @@ -560,6 +735,7 @@ impl ToTokens for MatchPat { Self::Or(v) => v.to_tokens(tokens), Self::Paren(v) => v.to_tokens(tokens), Self::Struct(v) => v.to_tokens(tokens), + Self::Tuple(v) => v.to_tokens(tokens), Self::EnumVariant(v) => v.to_tokens(tokens), } } @@ -622,10 +798,6 @@ struct RewriteAsCheckMatch { } impl Fold for RewriteAsCheckMatch { - fn fold_field_pat(&mut self, mut i: FieldPat) -> FieldPat { - i.colon_token = Some(Token![:](i.member.span())); - i - } fn fold_pat(&mut self, pat: Pat) -> Pat { match pat { Pat::Ident(mut pat_ident) => match parse_enum_ident(pat_ident.ident) { @@ -740,6 +912,30 @@ impl Fold for RewriteAsCheckMatch { // don't recurse into expressions i } + fn fold_local(&mut self, mut let_stmt: Local) -> Local { + if let Some(syn::LocalInit { + eq_token, + expr: _, + diverge, + }) = let_stmt.init.take() + { + let_stmt.init = Some(syn::LocalInit { + eq_token, + expr: parse_quote_spanned! {self.span=> + __match_value + }, + diverge: diverge.map(|(else_, _expr)| { + ( + else_, + parse_quote_spanned! {self.span=> + match __infallible {} + }, + ) + }), + }); + } + fold_local(self, let_stmt) + } } struct HdlMatchParseState<'a> { @@ -747,7 +943,123 @@ struct HdlMatchParseState<'a> { errors: &'a mut Errors, } +struct HdlLetPatVisitState<'a> { + errors: &'a mut Errors, + bindings: BTreeSet<&'a Ident>, +} + +impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> { + fn visit_match_pat_binding(&mut self, v: &'a MatchPatBinding) { + self.bindings.insert(&v.ident); + } + + fn visit_match_pat_or(&mut self, v: &'a MatchPatOr) { + if let Some(first_inner_vert) = v.first_inner_vert() { + self.errors.error( + first_inner_vert, + "or-patterns are not supported in let statements", + ); + } + visit_match_pat_or(self, v); + } + + fn visit_match_pat_or_simple(&mut self, v: &'a MatchPatOr) { + if let Some(first_inner_vert) = v.first_inner_vert() { + self.errors.error( + first_inner_vert, + "or-patterns are not supported in let statements", + ); + } + visit_match_pat_or_simple(self, v); + } + + fn visit_match_pat_enum_variant(&mut self, v: &'a MatchPatEnumVariant) { + self.errors.error(v, "refutable pattern in let statement"); + } +} + impl Visitor<'_> { + pub(crate) fn process_hdl_let_pat( + &mut self, + _hdl_attr: HdlAttr, + mut let_stmt: Local, + ) -> Local { + let span = let_stmt.let_token.span(); + if let Pat::Type(pat) = &mut let_stmt.pat { + *pat.ty = wrap_ty_with_expr((*pat.ty).clone()); + } + let check_let_stmt = RewriteAsCheckMatch { span }.fold_local(let_stmt.clone()); + let Local { + attrs: _, + let_token, + pat, + init, + semi_token, + } = let_stmt; + self.require_normal_module_or_fn(let_token); + let Some(syn::LocalInit { + eq_token, + expr, + diverge, + }) = init + else { + self.errors + .error(let_token, "#[hdl] let must be assigned a value"); + return empty_let(); + }; + if let Some((else_, _)) = diverge { + // TODO: implement let-else + self.errors + .error(else_, "#[hdl] let ... else { ... } is not implemented"); + return empty_let(); + } + let Ok(pat) = MatchPat::parse( + &mut HdlMatchParseState { + match_span: span, + errors: &mut self.errors, + }, + pat, + ) else { + return empty_let(); + }; + let mut state = HdlLetPatVisitState { + errors: &mut self.errors, + bindings: BTreeSet::new(), + }; + state.visit_match_pat(&pat); + let HdlLetPatVisitState { + errors: _, + bindings, + } = state; + let retval = parse_quote_spanned! {span=> + let (#(#bindings,)* __scope,) = { + type __MatchTy = ::MatchVariant; + let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); + ::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| { + #[allow(unused_variables)] + #check_let_stmt + match __infallible {} + }); + let mut __match_iter = ::fayalite::module::match_(__match_expr); + let ::fayalite::__std::option::Option::Some(__match_variant) = ::fayalite::__std::iter::Iterator::next(&mut __match_iter) else { + ::fayalite::__std::unreachable!("#[hdl] let with uninhabited type"); + }; + let ::fayalite::__std::option::Option::None = ::fayalite::__std::iter::Iterator::next(&mut __match_iter) else { + ::fayalite::__std::unreachable!("#[hdl] let with refutable pattern"); + }; + let (__match_variant, __scope) = + ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( + __match_variant, + ); + #let_token #pat #eq_token __match_variant #semi_token + (#(#bindings,)* __scope,) + }; + }; + match retval { + syn::Stmt::Local(retval) => retval, + _ => unreachable!(), + } + } pub(crate) fn process_hdl_match( &mut self, _hdl_attr: HdlAttr, diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs index 61d29b5..229871b 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs @@ -2,6 +2,7 @@ // See Notices.txt for copyright information //! ## `#[hdl] let` statements +pub mod destructuring; pub mod inputs_outputs; pub mod instances; pub mod memories; diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs new file mode 100644 index 0000000..1fc4705 --- /dev/null +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information +//! ### Destructuring Let +//! +//! You can use `#[hdl] let` to destructure types, similarly to Rust `let` statements with non-trivial patterns. +//! +//! `#[hdl] let` statements can only match one level of struct/tuple pattern for now, +//! e.g. you can match with the pattern `MyStruct { a, b }`, but not `MyStruct { a, b: Struct2 { v } }`. +//! +//! ``` +//! # use fayalite::prelude::*; +//! #[hdl] +//! struct MyStruct { +//! a: UInt<8>, +//! b: Bool, +//! } +//! +//! #[hdl_module] +//! fn my_module() { +//! #[hdl] +//! let my_input: MyStruct = m.input(); +//! #[hdl] +//! let my_output: UInt<8> = m.input(); +//! #[hdl] +//! let MyStruct { a, b } = my_input; +//! #[hdl] +//! if b { +//! connect(my_output, a); +//! } else { +//! connect(my_output, 0_hdl_u8); +//! } +//! } +//! ``` diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs index 9e6c511..6df70f1 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs @@ -7,5 +7,5 @@ //! //! `#[hdl] match` statements' bodies must evaluate to type `()` for now. //! -//! `#[hdl] match` statements can only match one level of struct/enum pattern for now, +//! `#[hdl] match` statements can only match one level of struct/tuple/enum pattern for now, //! e.g. you can match with the pattern `HdlSome(v)`, but not `HdlSome(HdlSome(_))`. diff --git a/crates/fayalite/src/int.rs b/crates/fayalite/src/int.rs index b49ca3f..5d10b29 100644 --- a/crates/fayalite/src/int.rs +++ b/crates/fayalite/src/int.rs @@ -567,12 +567,12 @@ impl_prim_int!(i64, SInt<64>); impl_prim_int!(i128, SInt<128>); impl_prim_int!( - /// for portability reasons, [`usize`] always translates to [`UInt<64>`] + /// for portability reasons, [`usize`] always translates to [`UInt<64>`][type@UInt] usize, UInt<64> ); impl_prim_int!( - /// for portability reasons, [`isize`] always translates to [`SInt<64>`] + /// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt] isize, SInt<64> ); diff --git a/crates/fayalite/src/lib.rs b/crates/fayalite/src/lib.rs index 5b5afb4..88fe169 100644 --- a/crates/fayalite/src/lib.rs +++ b/crates/fayalite/src/lib.rs @@ -22,7 +22,8 @@ macro_rules! __cfg_expansion_helper { $cfg:ident($($expr:tt)*), $($unevaluated_cfgs:ident($($unevaluated_exprs:tt)*),)* ] - #[$after_evaluation:path:($($after_evaluation_attr_args:tt)*)] {$($after_evaluation_args:tt)*} + // pass as tt so we get right span for attribute + $after_evaluation_attr:tt $after_evaluation_body:tt ) => { #[$cfg($($expr)*)] $crate::__cfg_expansion_helper! { @@ -33,7 +34,7 @@ macro_rules! __cfg_expansion_helper { [ $($unevaluated_cfgs($($unevaluated_exprs)*),)* ] - #[$after_evaluation:($($after_evaluation_attr_args)*)] {$($after_evaluation_args)*} + $after_evaluation_attr $after_evaluation_body } #[$cfg(not($($expr)*))] $crate::__cfg_expansion_helper! { @@ -44,7 +45,7 @@ macro_rules! __cfg_expansion_helper { [ $($unevaluated_cfgs($($unevaluated_exprs)*),)* ] - #[$after_evaluation:($($after_evaluation_attr_args)*)] {$($after_evaluation_args)*} + $after_evaluation_attr $after_evaluation_body } }; ( @@ -52,12 +53,14 @@ macro_rules! __cfg_expansion_helper { $($evaluated_cfgs:ident($($evaluated_exprs:tt)*) = $evaluated_results:ident,)* ] [] - #[$after_evaluation:path:($($after_evaluation_attr_args:tt)*)] {$($after_evaluation_args:tt)*} + // don't use #[...] so we get right span for `#` and `[]` of attribute + {$($after_evaluation_attr:tt)*} {$($after_evaluation_body:tt)*} ) => { - #[$after_evaluation([ + $($after_evaluation_attr)* + #[__evaluated_cfgs([ $($evaluated_cfgs($($evaluated_exprs)*) = $evaluated_results,)* - ] $($after_evaluation_attr_args)*)] - $($after_evaluation_args)* + ])] + $($after_evaluation_body)* }; } diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index cb6228d..f630f5a 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -4773,6 +4773,9 @@ impl Compiler { } self.insns.extend(insns.iter().copied(), *source_location); } + for CondStackEntry { cond: _, end_label } in cond_stack { + self.insns.define_label_at_next_insn(end_label); + } } fn process_clocks(&mut self) -> Interned<[StatePartIndex]> { mem::take(&mut self.clock_triggers) diff --git a/crates/fayalite/src/sim/vcd.rs b/crates/fayalite/src/sim/vcd.rs index b8248e3..fde30be 100644 --- a/crates/fayalite/src/sim/vcd.rs +++ b/crates/fayalite/src/sim/vcd.rs @@ -5,6 +5,7 @@ use crate::{ enum_::{Enum, EnumType}, expr::Flow, int::UInt, + intern::{Intern, Interned}, sim::{ time::{SimDuration, SimInstant}, TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl, @@ -15,12 +16,73 @@ use crate::{ }, }; use bitvec::{order::Lsb0, slice::BitSlice}; +use hashbrown::{hash_map::Entry, HashMap}; use std::{ - fmt, - io::{self, Write}, - mem, + fmt::{self, Write as _}, + io, mem, }; +#[derive(Default)] +struct Scope { + last_inserted: HashMap, usize>, +} + +#[derive(Copy, Clone)] +struct VerilogIdentifier { + unescaped_name: Interned, +} + +impl VerilogIdentifier { + fn needs_escape(self) -> bool { + // we only allow ascii, so we can just check bytes + let Some((&first, rest)) = self.unescaped_name.as_bytes().split_first() else { + unreachable!("Scope::new_identifier guarantees a non-empty name"); + }; + if !first.is_ascii_alphabetic() && first != b'_' { + true + } else { + rest.iter() + .any(|&ch| !ch.is_ascii_alphanumeric() && ch != b'_' && ch != b'$') + } + } +} + +impl fmt::Display for VerilogIdentifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.needs_escape() { + f.write_str("\\")?; + } + write!(f, "{}", Escaped(self.unescaped_name)) + } +} + +impl Scope { + fn new_identifier(&mut self, unescaped_name: Interned) -> VerilogIdentifier { + let next_disambiguator = match self.last_inserted.entry(unescaped_name) { + Entry::Vacant(entry) => { + entry.insert(1); + return VerilogIdentifier { unescaped_name }; + } + Entry::Occupied(entry) => entry.get() + 1, + }; + let mut disambiguated_name = String::from(&*unescaped_name); + for disambiguator in next_disambiguator.. { + disambiguated_name.truncate(unescaped_name.len()); + write!(disambiguated_name, "_{disambiguator}").expect("can't fail"); + if let Entry::Vacant(entry) = self.last_inserted.entry((*disambiguated_name).intern()) { + let retval = VerilogIdentifier { + unescaped_name: *entry.key(), + }; + entry.insert(1); + // speed up future searches + self.last_inserted.insert(unescaped_name, disambiguator); + return retval; + } + } + panic!("too many names"); + } +} + pub struct VcdWriterDecls { writer: W, timescale: SimDuration, @@ -97,14 +159,20 @@ impl fmt::Debug for VcdWriterDecls { } } +/// pass in scope to ensure it's not available in child scope fn write_vcd_scope( writer: &mut W, scope_type: &str, - scope_name: &str, - f: impl FnOnce(&mut W) -> io::Result, + scope_name: Interned, + scope: &mut Scope, + f: impl FnOnce(&mut W, &mut Scope) -> io::Result, ) -> io::Result { - writeln!(writer, "$scope {scope_type} {scope_name} $end")?; - let retval = f(writer)?; + writeln!( + writer, + "$scope {scope_type} {} $end", + scope.new_identifier(scope_name), + )?; + let retval = f(writer, &mut Scope::default())?; writeln!(writer, "$upscope $end")?; Ok(retval) } @@ -143,24 +211,28 @@ trait_arg! { struct ArgModule<'a> { properties: &'a mut VcdWriterProperties, + scope: &'a mut Scope, } impl<'a> ArgModule<'a> { fn reborrow(&mut self) -> ArgModule<'_> { ArgModule { properties: self.properties, + scope: self.scope, } } } struct ArgModuleBody<'a> { properties: &'a mut VcdWriterProperties, + scope: &'a mut Scope, } impl<'a> ArgModuleBody<'a> { fn reborrow(&mut self) -> ArgModuleBody<'_> { ArgModuleBody { properties: self.properties, + scope: self.scope, } } } @@ -170,6 +242,7 @@ struct ArgInType<'a> { sink_var_type: &'static str, duplex_var_type: &'static str, properties: &'a mut VcdWriterProperties, + scope: &'a mut Scope, } impl<'a> ArgInType<'a> { @@ -179,6 +252,7 @@ impl<'a> ArgInType<'a> { sink_var_type: self.sink_var_type, duplex_var_type: self.duplex_var_type, properties: self.properties, + scope: self.scope, } } } @@ -226,55 +300,42 @@ fn write_vcd_id(writer: &mut W, mut id: usize) -> io::Result<()> { Ok(()) } -fn write_escaped(writer: &mut W, value: impl fmt::Display) -> io::Result<()> { - // escaping rules from function GTKWave uses to decode VCD strings: - // https://github.com/gtkwave/gtkwave/blob/491f24d7e8619cfc1fcc65704ee5c967d1083c18/lib/libfst/fstapi.c#L7090 - struct Wrapper(W); - impl io::Write for Wrapper { - fn write(&mut self, buf: &[u8]) -> io::Result { - if buf.is_empty() { - return self.0.write(buf); - } - let mut retval = 0; - for &byte in buf { - match byte { - b'\\' | b'\'' | b'"' | b'?' => self.0.write_all(&[b'\\', byte])?, - b'\n' => self.0.write_all(br"\n")?, - b'\r' => self.0.write_all(br"\r")?, - b'\t' => self.0.write_all(br"\t")?, - 0x7 => self.0.write_all(br"\a")?, - 0x8 => self.0.write_all(br"\b")?, - 0xC => self.0.write_all(br"\f")?, - 0xB => self.0.write_all(br"\v")?, - _ => { - if byte.is_ascii_graphic() { - self.0.write_all(&[byte])?; - } else { - write!(self.0, r"\x{byte:02x}")?; +struct Escaped(T); + +impl fmt::Display for Escaped { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // escaping rules from function GTKWave uses to decode VCD strings: + // https://github.com/gtkwave/gtkwave/blob/491f24d7e8619cfc1fcc65704ee5c967d1083c18/lib/libfst/fstapi.c#L7090 + struct Wrapper(W); + impl fmt::Write for Wrapper { + fn write_str(&mut self, s: &str) -> fmt::Result { + for byte in s.bytes() { + match byte { + b'\\' | b'\'' | b'"' | b'?' => { + self.0.write_str("\\")?; + self.0.write_char(byte as char)?; + } + b'\n' => self.0.write_str(r"\n")?, + b'\r' => self.0.write_str(r"\r")?, + b'\t' => self.0.write_str(r"\t")?, + 0x7 => self.0.write_str(r"\a")?, + 0x8 => self.0.write_str(r"\b")?, + 0xC => self.0.write_str(r"\f")?, + 0xB => self.0.write_str(r"\v")?, + _ => { + if byte.is_ascii_graphic() { + self.0.write_char(byte as char)?; + } else { + write!(self.0, r"\x{byte:02x}")?; + } } } } - retval += 1; + Ok(()) } - Ok(retval) - } - - fn flush(&mut self) -> io::Result<()> { - self.0.flush() } + write!(Wrapper(f), "{}", self.0) } - write!(Wrapper(writer), "{value}") -} - -fn is_unescaped_verilog_identifier(ident: &str) -> bool { - // we only allow ascii, so we can just check bytes - let Some((&first, rest)) = ident.as_bytes().split_first() else { - return false; // empty string is not an identifier - }; - (first.is_ascii_alphabetic() || first == b'_') - && rest - .iter() - .all(|&ch| ch.is_ascii_alphanumeric() || ch == b'_' || ch == b'$') } fn write_vcd_var( @@ -284,7 +345,7 @@ fn write_vcd_var( var_type: &str, size: usize, location: TraceLocation, - name: &str, + name: VerilogIdentifier, ) -> io::Result<()> { let id = match location { TraceLocation::Scalar(id) => id.as_usize(), @@ -319,12 +380,7 @@ fn write_vcd_var( }; write!(writer, "$var {var_type} {size} ")?; write_vcd_id(writer, id)?; - writer.write_all(b" ")?; - if !is_unescaped_verilog_identifier(name) { - writer.write_all(b"\\")?; - } - write_escaped(writer, name)?; - writer.write_all(b" $end\n") + writeln!(writer, " {name} $end") } impl WriteTrace for TraceUInt { @@ -334,6 +390,7 @@ impl WriteTrace for TraceUInt { sink_var_type, duplex_var_type, properties, + scope, } = arg.in_type(); let Self { location, @@ -356,7 +413,7 @@ impl WriteTrace for TraceUInt { var_type, ty.width(), location, - &name, + scope.new_identifier(name), ) } } @@ -421,6 +478,7 @@ impl WriteTrace for TraceEnumDiscriminant { sink_var_type: _, duplex_var_type: _, properties, + scope, } = arg.in_type(); let Self { location, @@ -435,7 +493,7 @@ impl WriteTrace for TraceEnumDiscriminant { "string", 1, location, - &name, + scope.new_identifier(name), ) } } @@ -507,11 +565,11 @@ impl WriteTrace for TraceScope { impl WriteTrace for TraceModule { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModule { properties } = arg.module(); + let ArgModule { properties, scope } = arg.module(); let Self { name, children } = self; - write_vcd_scope(writer, "module", &name, |writer| { + write_vcd_scope(writer, "module", name, scope, |writer, scope| { for child in children { - child.write_trace(writer, ArgModuleBody { properties })?; + child.write_trace(writer, ArgModuleBody { properties, scope })?; } Ok(()) }) @@ -520,7 +578,7 @@ impl WriteTrace for TraceModule { impl WriteTrace for TraceInstance { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { name: _, instance_io, @@ -534,15 +592,16 @@ impl WriteTrace for TraceInstance { sink_var_type: "wire", duplex_var_type: "wire", properties, + scope, }, )?; - module.write_trace(writer, ArgModule { properties }) + module.write_trace(writer, ArgModule { properties, scope }) } } impl WriteTrace for TraceMem { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { id, name, @@ -551,27 +610,41 @@ impl WriteTrace for TraceMem { ports, array_type, } = self; - write_vcd_scope(writer, "struct", &*name, |writer| { - write_vcd_scope(writer, "struct", "contents", |writer| { - for element_index in 0..array_type.len() { - write_vcd_scope(writer, "struct", &format!("[{element_index}]"), |writer| { - properties.memory_properties[id.as_usize()].element_index = element_index; - properties.memory_properties[id.as_usize()].element_part_index = 0; - element_type.write_trace( + write_vcd_scope(writer, "struct", name, scope, |writer, scope| { + write_vcd_scope( + writer, + "struct", + "contents".intern(), + scope, + |writer, scope| { + for element_index in 0..array_type.len() { + write_vcd_scope( writer, - ArgInType { - source_var_type: "reg", - sink_var_type: "reg", - duplex_var_type: "reg", - properties, + "struct", + Intern::intern_owned(format!("[{element_index}]")), + scope, + |writer, scope| { + properties.memory_properties[id.as_usize()].element_index = + element_index; + properties.memory_properties[id.as_usize()].element_part_index = 0; + element_type.write_trace( + writer, + ArgInType { + source_var_type: "reg", + sink_var_type: "reg", + duplex_var_type: "reg", + properties, + scope, + }, + ) }, - ) - })?; - } - Ok(()) - })?; + )?; + } + Ok(()) + }, + )?; for port in ports { - port.write_trace(writer, ArgModuleBody { properties })?; + port.write_trace(writer, ArgModuleBody { properties, scope })?; } Ok(()) }) @@ -580,7 +653,7 @@ impl WriteTrace for TraceMem { impl WriteTrace for TraceMemPort { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { name: _, bundle, @@ -593,6 +666,7 @@ impl WriteTrace for TraceMemPort { sink_var_type: "wire", duplex_var_type: "wire", properties, + scope, }, ) } @@ -600,7 +674,7 @@ impl WriteTrace for TraceMemPort { impl WriteTrace for TraceWire { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { name: _, child, @@ -613,6 +687,7 @@ impl WriteTrace for TraceWire { sink_var_type: "wire", duplex_var_type: "wire", properties, + scope, }, ) } @@ -620,7 +695,7 @@ impl WriteTrace for TraceWire { impl WriteTrace for TraceReg { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { name: _, child, @@ -633,6 +708,7 @@ impl WriteTrace for TraceReg { sink_var_type: "reg", duplex_var_type: "reg", properties, + scope, }, ) } @@ -640,7 +716,7 @@ impl WriteTrace for TraceReg { impl WriteTrace for TraceModuleIO { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { name: _, child, @@ -654,6 +730,7 @@ impl WriteTrace for TraceModuleIO { sink_var_type: "wire", duplex_var_type: "wire", properties, + scope, }, ) } @@ -661,16 +738,31 @@ impl WriteTrace for TraceModuleIO { impl WriteTrace for TraceBundle { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let mut arg = arg.in_type(); + let ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + } = arg.in_type(); let Self { name, fields, ty: _, flow: _, } = self; - write_vcd_scope(writer, "struct", &name, |writer| { + write_vcd_scope(writer, "struct", name, scope, |writer, scope| { for field in fields { - field.write_trace(writer, arg.reborrow())?; + field.write_trace( + writer, + ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + }, + )?; } Ok(()) }) @@ -679,16 +771,31 @@ impl WriteTrace for TraceBundle { impl WriteTrace for TraceArray { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let mut arg = arg.in_type(); + let ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + } = arg.in_type(); let Self { name, elements, ty: _, flow: _, } = self; - write_vcd_scope(writer, "struct", &name, |writer| { + write_vcd_scope(writer, "struct", name, scope, |writer, scope| { for element in elements { - element.write_trace(writer, arg.reborrow())?; + element.write_trace( + writer, + ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + }, + )?; } Ok(()) }) @@ -697,7 +804,13 @@ impl WriteTrace for TraceArray { impl WriteTrace for TraceEnumWithFields { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let mut arg = arg.in_type(); + let ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + } = arg.in_type(); let Self { name, discriminant, @@ -705,10 +818,28 @@ impl WriteTrace for TraceEnumWithFields { ty: _, flow: _, } = self; - write_vcd_scope(writer, "struct", &name, |writer| { - discriminant.write_trace(writer, arg.reborrow())?; + write_vcd_scope(writer, "struct", name, scope, |writer, scope| { + discriminant.write_trace( + writer, + ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + }, + )?; for field in non_empty_fields { - field.write_trace(writer, arg.reborrow())?; + field.write_trace( + writer, + ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + }, + )?; } Ok(()) }) @@ -744,6 +875,7 @@ impl TraceWriterDecls for VcdWriterDecls { &mut writer, ArgModule { properties: &mut properties, + scope: &mut Scope::default(), }, )?; writeln!(writer, "$enddefinitions $end")?; @@ -798,9 +930,7 @@ fn write_string_value_change( value: impl fmt::Display, id: usize, ) -> io::Result<()> { - writer.write_all(b"s")?; - write_escaped(writer, value)?; - writer.write_all(b" ")?; + write!(writer, "s{} ", Escaped(value))?; write_vcd_id(writer, id)?; writer.write_all(b"\n") } @@ -946,3 +1076,49 @@ impl fmt::Debug for VcdWriter { .finish_non_exhaustive() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_scope() { + let mut scope = Scope::default(); + assert_eq!(&*scope.new_identifier("foo".intern()).unescaped_name, "foo"); + assert_eq!( + &*scope.new_identifier("foo_0".intern()).unescaped_name, + "foo_0" + ); + assert_eq!( + &*scope.new_identifier("foo_1".intern()).unescaped_name, + "foo_1" + ); + assert_eq!( + &*scope.new_identifier("foo_3".intern()).unescaped_name, + "foo_3" + ); + assert_eq!( + &*scope.new_identifier("foo".intern()).unescaped_name, + "foo_2" + ); + assert_eq!( + &*scope.new_identifier("foo".intern()).unescaped_name, + "foo_4" + ); + assert_eq!( + &*scope.new_identifier("foo_0".intern()).unescaped_name, + "foo_0_2" + ); + assert_eq!( + &*scope.new_identifier("foo_1".intern()).unescaped_name, + "foo_1_2" + ); + for i in 5..1000u64 { + // verify it actually picks the next available identifier with no skips or duplicates + assert_eq!( + *scope.new_identifier("foo".intern()).unescaped_name, + format!("foo_{i}"), + ); + } + } +} diff --git a/crates/fayalite/src/util/ready_valid.rs b/crates/fayalite/src/util/ready_valid.rs index 82d3f1e..ac08a64 100644 --- a/crates/fayalite/src/util/ready_valid.rs +++ b/crates/fayalite/src/util/ready_valid.rs @@ -49,6 +49,18 @@ impl ReadyValid { } } +/// This debug port is only meant to assist the formal proof of the queue. +#[cfg(test)] +#[doc(hidden)] +#[hdl] +pub struct QueueDebugPort { + #[hdl(flip)] + index_to_check: Index, + stored: Element, + inp_index: Index, + out_index: Index, +} + #[hdl_module] pub fn queue( ty: T, @@ -178,6 +190,22 @@ pub fn queue( } } } + // These debug ports expose some internal state during the Induction phase + // of Formal Verification. They are not present in normal use. + #[cfg(test)] + { + #[hdl] + let dbg: QueueDebugPort = m.output(QueueDebugPort[ty][index_ty]); + // read the memory word currently stored at some fixed index + let debug_port = mem.new_read_port(); + connect(debug_port.addr, dbg.index_to_check); + connect(debug_port.en, true); + connect(debug_port.clk, cd.clk); + connect(dbg.stored, debug_port.data); + // also expose the current read and write indices + connect(dbg.inp_index, inp_index_reg); + connect(dbg.out_index, out_index_reg); + } } #[cfg(test)] @@ -196,13 +224,23 @@ mod tests { format_args!("test_queue_{capacity}_{inp_ready_is_comb}_{out_valid_is_comb}"), queue_test(capacity, inp_ready_is_comb, out_valid_is_comb), FormalMode::Prove, - 14, + 2, None, ExportOptions { simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts), ..ExportOptions::default() }, ); + /// Formal verification of the FIFO queue + /// + /// The strategy derives from the observation that, if we filter its + /// input and output streams to consider just one in every N reads and + /// writes (where N is the FIFO capacity), then the FIFO effectively + /// behaves as a one-entry FIFO. + /// + /// In particular, any counterexample of the full FIFO behaving badly + /// will also be caught by one of the filtered versions (one which + /// happens to be in phase with the offending input or output). #[hdl_module] fn queue_test(capacity: NonZeroUsize, inp_ready_is_comb: bool, out_valid_is_comb: bool) { #[hdl] @@ -217,6 +255,8 @@ mod tests { rst: formal_reset().to_reset(), }, ); + + // random input data #[hdl] let inp_data: HdlOption> = wire(); #[hdl] @@ -225,16 +265,26 @@ mod tests { } else { connect(inp_data, HdlNone()); } + + // assert output ready at random #[hdl] let out_ready: Bool = wire(); connect(out_ready, any_seq(Bool)); - let index_ty: UInt<32> = UInt::TYPE; + + // The current number of elements in the FIFO ranges from zero to + // maximum capacity, inclusive. + let count_ty = UInt::range_inclusive(0..=capacity.get()); + // type for counters that wrap around at the FIFO capacity + let index_ty = UInt::range(0..capacity.get()); + + // among all entries of the FIFO internal circular memory, choose + // one at random to check #[hdl] - let index_to_check = wire(); + let index_to_check = wire(index_ty); connect(index_to_check, any_const(index_ty)); - let index_max = !index_ty.zero(); - // we saturate at index_max, so only check indexes where we properly maintain position - hdl_assume(clk, index_to_check.cmp_ne(index_max), ""); + hdl_assume(clk, index_to_check.cmp_lt(capacity.get()), ""); + + // instantiate and connect the queue #[hdl] let dut = instance(queue( UInt[ConstUsize::<8>], @@ -245,109 +295,172 @@ mod tests { connect(dut.cd, cd); connect(dut.inp.data, inp_data); connect(dut.out.ready, out_ready); - hdl_assume( - clk, - index_to_check.cmp_ne(!Expr::ty(index_to_check).zero()), - "", - ); + // Keep an independent count of words in the FIFO. Ensure that + // it's always correct, and never overflows. #[hdl] - let expected_count_reg = reg_builder().clock_domain(cd).reset(0u32); - #[hdl] - let next_expected_count = wire(); - connect(next_expected_count, expected_count_reg); - connect(expected_count_reg, next_expected_count); + let expected_count_reg = reg_builder().clock_domain(cd).reset(count_ty.zero()); #[hdl] if ReadyValid::firing(dut.inp) & !ReadyValid::firing(dut.out) { - connect_any(next_expected_count, expected_count_reg + 1u8); + hdl_assert(clk, expected_count_reg.cmp_ne(capacity.get()), ""); + connect_any(expected_count_reg, expected_count_reg + 1u8); } else if !ReadyValid::firing(dut.inp) & ReadyValid::firing(dut.out) { - connect_any(next_expected_count, expected_count_reg - 1u8); + hdl_assert(clk, expected_count_reg.cmp_ne(count_ty.zero()), ""); + connect_any(expected_count_reg, expected_count_reg - 1u8); } - hdl_assert(cd.clk, expected_count_reg.cmp_eq(dut.count), ""); - - #[hdl] - let prev_out_ready_reg = reg_builder().clock_domain(cd).reset(!0_hdl_u3); - connect_any( - prev_out_ready_reg, - (prev_out_ready_reg << 1) | out_ready.cast_to(UInt[1]), - ); - #[hdl] - let prev_inp_valid_reg = reg_builder().clock_domain(cd).reset(!0_hdl_u3); - connect_any( - prev_inp_valid_reg, - (prev_inp_valid_reg << 1) | HdlOption::is_some(inp_data).cast_to(UInt[1]), - ); - hdl_assume( - clk, - (prev_out_ready_reg & prev_inp_valid_reg).cmp_ne(0u8), - "", - ); + hdl_assert(clk, expected_count_reg.cmp_eq(dut.count), ""); + // keep an independent write index into the FIFO's circular buffer #[hdl] let inp_index_reg = reg_builder().clock_domain(cd).reset(index_ty.zero()); #[hdl] - let stored_inp_data_reg = reg_builder().clock_domain(cd).reset(0u8); - - #[hdl] - if let HdlSome(data) = ReadyValid::firing_data(dut.inp) { + if ReadyValid::firing(dut.inp) { #[hdl] - if inp_index_reg.cmp_lt(index_max) { + if inp_index_reg.cmp_ne(capacity.get() - 1) { connect_any(inp_index_reg, inp_index_reg + 1u8); - #[hdl] - if inp_index_reg.cmp_eq(index_to_check) { - connect(stored_inp_data_reg, data); - } + } else { + connect_any(inp_index_reg, 0_hdl_u0); } } - #[hdl] - if inp_index_reg.cmp_lt(index_to_check) { - hdl_assert(clk, stored_inp_data_reg.cmp_eq(0u8), ""); - } - + // keep an independent read index into the FIFO's circular buffer #[hdl] let out_index_reg = reg_builder().clock_domain(cd).reset(index_ty.zero()); #[hdl] - let stored_out_data_reg = reg_builder().clock_domain(cd).reset(0u8); - - #[hdl] - if let HdlSome(data) = ReadyValid::firing_data(dut.out) { + if ReadyValid::firing(dut.out) { #[hdl] - if out_index_reg.cmp_lt(index_max) { + if out_index_reg.cmp_ne(capacity.get() - 1) { connect_any(out_index_reg, out_index_reg + 1u8); + } else { + connect_any(out_index_reg, 0_hdl_u0); + } + } + + // filter the input data stream, predicated by the read index + // matching the chosen position in the FIFO's circular buffer + #[hdl] + let inp_index_matches = wire(); + connect(inp_index_matches, inp_index_reg.cmp_eq(index_to_check)); + #[hdl] + let inp_firing_data = wire(); + connect(inp_firing_data, HdlNone()); + #[hdl] + if inp_index_matches { + connect(inp_firing_data, ReadyValid::firing_data(dut.inp)); + } + + // filter the output data stream, predicated by the write index + // matching the chosen position in the FIFO's circular buffer + #[hdl] + let out_index_matches = wire(); + connect(out_index_matches, out_index_reg.cmp_eq(index_to_check)); + #[hdl] + let out_firing_data = wire(); + connect(out_firing_data, HdlNone()); + #[hdl] + if out_index_matches { + connect(out_firing_data, ReadyValid::firing_data(dut.out)); + } + + // Implement a one-entry FIFO and ensure its equivalence to the + // filtered FIFO. + // + // the holding register for our one-entry FIFO + #[hdl] + let stored_reg = reg_builder().clock_domain(cd).reset(HdlNone()); + #[hdl] + match stored_reg { + // If the holding register is empty... + HdlNone => { #[hdl] - if out_index_reg.cmp_eq(index_to_check) { - connect(stored_out_data_reg, data); + match inp_firing_data { + // ... and we are not receiving data, then we must not + // transmit any data. + HdlNone => hdl_assert(clk, HdlOption::is_none(out_firing_data), ""), + // If we are indeed receiving some data... + HdlSome(data_in) => { + #[hdl] + match out_firing_data { + // ... and transmitting at the same time, we + // must be transmitting the input data itself, + // since the holding register is empty. + HdlSome(data_out) => hdl_assert(clk, data_out.cmp_eq(data_in), ""), + // If we are receiving, but not transmitting, + // store the received data in the holding + // register. + HdlNone => connect(stored_reg, HdlSome(data_in)), + } + } + } + } + // If there is some value stored in the holding register... + HdlSome(stored) => { + #[hdl] + match out_firing_data { + // ... and we are not transmitting it, we cannot + // receive any more data. + HdlNone => hdl_assert(clk, HdlOption::is_none(inp_firing_data), ""), + // If we are transmitting a previously stored value... + HdlSome(data_out) => { + // ... it must be the same data we stored earlier. + hdl_assert(clk, data_out.cmp_eq(stored), ""); + // Also, accept new data, if any. Otherwise, + // let the holding register become empty. + connect(stored_reg, inp_firing_data); + } } } } + // from now on, some extra assertions in order to pass induction + + // sync the holding register, when it's occupied, to the + // corresponding entry in the FIFO's circular buffer + connect(dut.dbg.index_to_check, index_to_check); #[hdl] - if out_index_reg.cmp_lt(index_to_check) { - hdl_assert(clk, stored_out_data_reg.cmp_eq(0u8), ""); + if let HdlSome(stored) = stored_reg { + hdl_assert(clk, stored.cmp_eq(dut.dbg.stored), ""); } - hdl_assert(clk, inp_index_reg.cmp_ge(out_index_reg), ""); + // sync the read and write indices + hdl_assert(clk, inp_index_reg.cmp_eq(dut.dbg.inp_index), ""); + hdl_assert(clk, out_index_reg.cmp_eq(dut.dbg.out_index), ""); + // the indices should never go past the capacity, but induction + // doesn't know that... + hdl_assert(clk, inp_index_reg.cmp_lt(capacity.get()), ""); + hdl_assert(clk, out_index_reg.cmp_lt(capacity.get()), ""); + + // strongly constrain the state of the holding register + // + // The holding register is full if and only if the corresponding + // FIFO entry was written to and not yet read. In other words, if + // the number of pending reads until the chosen entry is read out + // is greater than the current FIFO count, then the entry couldn't + // be in the FIFO in the first place. #[hdl] - if inp_index_reg.cmp_lt(index_max) & out_index_reg.cmp_lt(index_max) { - hdl_assert( - clk, - expected_count_reg.cmp_eq(inp_index_reg - out_index_reg), - "", - ); + let pending_reads: UInt = wire(index_ty); + // take care of wrap-around when subtracting indices, add the + // capacity amount to keep the result positive if necessary + #[hdl] + if index_to_check.cmp_ge(out_index_reg) { + connect(pending_reads, index_to_check - out_index_reg); } else { - hdl_assert( - clk, - expected_count_reg.cmp_ge(inp_index_reg - out_index_reg), - "", + connect( + pending_reads, + index_to_check + capacity.get() - out_index_reg, ); } - + // check whether the chosen entry is in the FIFO #[hdl] - if inp_index_reg.cmp_gt(index_to_check) & out_index_reg.cmp_gt(index_to_check) { - hdl_assert(clk, stored_inp_data_reg.cmp_eq(stored_out_data_reg), ""); - } + let expected_stored: Bool = wire(); + connect(expected_stored, pending_reads.cmp_lt(dut.count)); + // sync with the state of the holding register + hdl_assert( + clk, + expected_stored.cmp_eq(HdlOption::is_some(stored_reg)), + "", + ); } } @@ -430,4 +543,24 @@ mod tests { fn test_4_true_true() { test_queue(NonZero::new(4).unwrap(), true, true); } + + #[test] + fn test_many_false_false() { + test_queue(NonZero::new((2 << 16) - 5).unwrap(), false, false); + } + + #[test] + fn test_many_false_true() { + test_queue(NonZero::new((2 << 16) - 5).unwrap(), false, true); + } + + #[test] + fn test_many_true_false() { + test_queue(NonZero::new((2 << 16) - 5).unwrap(), true, false); + } + + #[test] + fn test_many_true_true() { + test_queue(NonZero::new((2 << 16) - 5).unwrap(), true, true); + } } diff --git a/crates/fayalite/tests/module.rs b/crates/fayalite/tests/module.rs index 42cc528..2f93fa5 100644 --- a/crates/fayalite/tests/module.rs +++ b/crates/fayalite/tests/module.rs @@ -191,10 +191,14 @@ circuit check_array_repeat: }; } +pub trait UnknownTrait {} + +impl UnknownTrait for T {} + #[hdl_module(outline_generated)] pub fn check_skipped_generics(v: U) where - T: StaticType, + T: StaticType + UnknownTrait, ConstUsize: KnownSize, U: std::fmt::Display, { @@ -4288,7 +4292,8 @@ circuit check_deduce_resets: }; } -#[hdl_module(outline_generated)] +// intentionally not outline_generated to ensure we get correct macro hygiene +#[hdl_module] pub fn check_cfgs<#[cfg(cfg_false_for_tests)] A: Type, #[cfg(cfg_true_for_tests)] B: Type>( #[cfg(cfg_false_for_tests)] a: A, #[cfg(cfg_true_for_tests)] b: B, @@ -4335,12 +4340,88 @@ fn test_cfgs() { "/test/check_cfgs.fir": r"FIRRTL version 3.2.0 circuit check_cfgs: type Ty0 = {b: UInt<8>} - module check_cfgs: @[module-XXXXXXXXXX.rs 1:1] - input i_b: UInt<8> @[module-XXXXXXXXXX.rs 2:1] - output o_b: UInt<8> @[module-XXXXXXXXXX.rs 4:1] - wire w: Ty0 @[module-XXXXXXXXXX.rs 3:1] - connect o_b, w.b @[module-XXXXXXXXXX.rs 5:1] - connect w.b, i_b @[module-XXXXXXXXXX.rs 6:1] + module check_cfgs: @[the_test_file.rs 9962:1] + input i_b: UInt<8> @[the_test_file.rs 9979:20] + output o_b: UInt<8> @[the_test_file.rs 9992:24] + wire w: Ty0 @[the_test_file.rs 9981:25] + connect o_b, w.b @[the_test_file.rs 9993:9] + connect w.b, i_b @[the_test_file.rs 9994:9] +", + }; +} + +#[hdl_module(outline_generated)] +pub fn check_let_patterns() { + #[hdl] + let tuple_in: (UInt<1>, SInt<1>, Bool) = m.input(); + #[hdl] + let (tuple_0, tuple_1, tuple_2) = tuple_in; + #[hdl] + let tuple_0_out: UInt<1> = m.output(); + connect(tuple_0_out, tuple_0); + #[hdl] + let tuple_1_out: SInt<1> = m.output(); + connect(tuple_1_out, tuple_1); + #[hdl] + let tuple_2_out: Bool = m.output(); + connect(tuple_2_out, tuple_2); + + #[hdl] + let test_struct_in: TestStruct> = m.input(); + #[hdl] + let TestStruct::<_> { a, b } = test_struct_in; + #[hdl] + let test_struct_a_out: SInt<8> = m.output(); + connect(test_struct_a_out, a); + #[hdl] + let test_struct_b_out: UInt<8> = m.output(); + connect(test_struct_b_out, b); + + #[hdl] + let test_struct_2_in: TestStruct2 = m.input(); + #[hdl] + let TestStruct2 { v } = test_struct_2_in; + #[hdl] + let test_struct_2_v_out: UInt<8> = m.output(); + connect(test_struct_2_v_out, v); + + #[hdl] + let test_struct_3_in: TestStruct3 = m.input(); + #[hdl] + let TestStruct3 {} = test_struct_3_in; +} + +#[test] +fn test_let_patterns() { + let _n = SourceLocation::normalize_files_for_tests(); + let m = check_let_patterns(); + dbg!(m); + #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + assert_export_firrtl! { + m => + "/test/check_let_patterns.fir": r"FIRRTL version 3.2.0 +circuit check_let_patterns: + type Ty0 = {`0`: UInt<1>, `1`: SInt<1>, `2`: UInt<1>} + type Ty1 = {a: SInt<8>, b: UInt<8>} + type Ty2 = {v: UInt<8>} + type Ty3 = {} + module check_let_patterns: @[module-XXXXXXXXXX.rs 1:1] + input tuple_in: Ty0 @[module-XXXXXXXXXX.rs 2:1] + output tuple_0_out: UInt<1> @[module-XXXXXXXXXX.rs 4:1] + output tuple_1_out: SInt<1> @[module-XXXXXXXXXX.rs 6:1] + output tuple_2_out: UInt<1> @[module-XXXXXXXXXX.rs 8:1] + input test_struct_in: Ty1 @[module-XXXXXXXXXX.rs 10:1] + output test_struct_a_out: SInt<8> @[module-XXXXXXXXXX.rs 12:1] + output test_struct_b_out: UInt<8> @[module-XXXXXXXXXX.rs 14:1] + input test_struct_2_in: Ty2 @[module-XXXXXXXXXX.rs 16:1] + output test_struct_2_v_out: UInt<8> @[module-XXXXXXXXXX.rs 18:1] + input test_struct_3_in: Ty3 @[module-XXXXXXXXXX.rs 20:1] + connect tuple_0_out, tuple_in.`0` @[module-XXXXXXXXXX.rs 5:1] + connect tuple_1_out, tuple_in.`1` @[module-XXXXXXXXXX.rs 7:1] + connect tuple_2_out, tuple_in.`2` @[module-XXXXXXXXXX.rs 9:1] + connect test_struct_a_out, test_struct_in.a @[module-XXXXXXXXXX.rs 13:1] + connect test_struct_b_out, test_struct_in.b @[module-XXXXXXXXXX.rs 15:1] + connect test_struct_2_v_out, test_struct_2_in.v @[module-XXXXXXXXXX.rs 19:1] ", }; } diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index a249235..8c8a10f 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -1246,3 +1246,200 @@ fn test_memories3() { panic!(); } } + +#[hdl_module(outline_generated)] +pub fn duplicate_names() { + #[hdl] + let w = wire(); + connect(w, 5u8); + #[hdl] + let w = wire(); + connect(w, 6u8); +} + +#[test] +fn test_duplicate_names() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(duplicate_names()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + sim.advance_time(SimDuration::from_micros(1)); + sim.flush_traces().unwrap(); + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + if vcd != include_str!("sim/expected/duplicate_names.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/duplicate_names.txt") { + panic!(); + } +} + +#[hdl_module(outline_generated)] +pub fn array_rw() { + #[hdl] + let array_in: Array, 16> = m.input(); + #[hdl] + let array_out: Array, 16> = m.output(); + #[hdl] + let read_index: UInt<8> = m.input(); + #[hdl] + let read_data: UInt<8> = m.output(); + #[hdl] + let write_index: UInt<8> = m.input(); + #[hdl] + let write_data: UInt<8> = m.input(); + #[hdl] + let write_en: Bool = m.input(); + #[hdl] + let array_wire = wire(); + connect(array_wire, array_in); + connect(array_out, array_wire); + #[hdl] + if write_en { + connect(array_wire[write_index], write_data); + } + connect(read_data, array_wire[read_index]); +} + +#[test] +fn test_array_rw() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(array_rw()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + #[derive(Debug, PartialEq)] + struct State { + array_in: [u8; 16], + array_out: [u8; 16], + read_index: u8, + read_data: u8, + write_index: u8, + write_data: u8, + write_en: bool, + } + let mut states = Vec::new(); + let array_in = [ + 0xFFu8, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, // + 0x00u8, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, + ]; + for i in 0..=16 { + states.push(State { + array_in, + array_out: array_in, + read_index: i, + read_data: array_in.get(i as usize).copied().unwrap_or(0), + write_index: 0, + write_data: 0, + write_en: false, + }); + } + for i in 0..=16u8 { + let mut array_out = array_in; + let write_data = i.wrapping_mul(i); + if let Some(v) = array_out.get_mut(i as usize) { + *v = write_data; + } + states.push(State { + array_in, + array_out, + read_index: 0, + read_data: array_out[0], + write_index: i, + write_data, + write_en: true, + }); + } + for (cycle, expected) in states.into_iter().enumerate() { + let State { + array_in, + array_out: _, + read_index, + read_data: _, + write_index, + write_data, + write_en, + } = expected; + sim.write(sim.io().array_in, array_in); + sim.write(sim.io().read_index, read_index); + sim.write(sim.io().write_index, write_index); + sim.write(sim.io().write_data, write_data); + sim.write(sim.io().write_en, write_en); + sim.advance_time(SimDuration::from_micros(1)); + let array_out = std::array::from_fn(|index| { + sim.read_bool_or_int(sim.io().array_out[index]) + .to_bigint() + .try_into() + .expect("known to be in range") + }); + let read_data = sim + .read_bool_or_int(sim.io().read_data) + .to_bigint() + .try_into() + .expect("known to be in range"); + let state = State { + array_in, + array_out, + read_index, + read_data, + write_index, + write_data, + write_en, + }; + assert_eq!( + state, + expected, + "vcd:\n{}\ncycle: {cycle}", + String::from_utf8(writer.take()).unwrap(), + ); + } + sim.flush_traces().unwrap(); + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + if vcd != include_str!("sim/expected/array_rw.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/array_rw.txt") { + panic!(); + } +} + +#[hdl_module(outline_generated)] +pub fn conditional_assignment_last() { + #[hdl] + let i: Bool = m.input(); + #[hdl] + let w = wire(); + connect(w, true); + #[hdl] + if i { + connect(w, false); + } +} + +#[test] +fn test_conditional_assignment_last() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(conditional_assignment_last()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + sim.write(sim.io().i, false); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().i, true); + sim.advance_time(SimDuration::from_micros(1)); + sim.flush_traces().unwrap(); + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + if vcd != include_str!("sim/expected/conditional_assignment_last.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/conditional_assignment_last.txt") { + panic!(); + } +} diff --git a/crates/fayalite/tests/sim/expected/array_rw.txt b/crates/fayalite/tests/sim/expected/array_rw.txt new file mode 100644 index 0000000..f016e72 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/array_rw.txt @@ -0,0 +1,2859 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + big_slots: StatePartLayout { + len: 54, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[7]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[8]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[9]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[10]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[11]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[12]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[13]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[14]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[15]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[7]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[8]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[9]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[10]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[11]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[12]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[13]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[14]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[15]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::read_index", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::read_data", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::write_index", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::write_data", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::write_en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[7]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[8]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[9]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[10]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[11]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[12]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[13]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[14]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[15]", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:1:1 + 0: CastBigToArrayIndex { + dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: UInt<8> }, + src: StatePartIndex(32), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::read_index", ty: UInt<8> }, + }, + 1: CastBigToArrayIndex { + dest: StatePartIndex(0), // (0x10 16) SlotDebugData { name: "", ty: UInt<8> }, + src: StatePartIndex(34), // (0x10) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::write_index", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:10:1 + 2: Copy { + dest: StatePartIndex(37), // (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[0]", ty: UInt<8> }, + src: StatePartIndex(0), // (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[0]", ty: UInt<8> }, + }, + 3: Copy { + dest: StatePartIndex(38), // (0x7f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[1]", ty: UInt<8> }, + src: StatePartIndex(1), // (0x7f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[1]", ty: UInt<8> }, + }, + 4: Copy { + dest: StatePartIndex(39), // (0x3f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[2]", ty: UInt<8> }, + src: StatePartIndex(2), // (0x3f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[2]", ty: UInt<8> }, + }, + 5: Copy { + dest: StatePartIndex(40), // (0x1f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[3]", ty: UInt<8> }, + src: StatePartIndex(3), // (0x1f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[3]", ty: UInt<8> }, + }, + 6: Copy { + dest: StatePartIndex(41), // (0xf) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[4]", ty: UInt<8> }, + src: StatePartIndex(4), // (0xf) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[4]", ty: UInt<8> }, + }, + 7: Copy { + dest: StatePartIndex(42), // (0x7) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[5]", ty: UInt<8> }, + src: StatePartIndex(5), // (0x7) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[5]", ty: UInt<8> }, + }, + 8: Copy { + dest: StatePartIndex(43), // (0x3) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[6]", ty: UInt<8> }, + src: StatePartIndex(6), // (0x3) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[6]", ty: UInt<8> }, + }, + 9: Copy { + dest: StatePartIndex(44), // (0x1) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[7]", ty: UInt<8> }, + src: StatePartIndex(7), // (0x1) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[7]", ty: UInt<8> }, + }, + 10: Copy { + dest: StatePartIndex(45), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[8]", ty: UInt<8> }, + src: StatePartIndex(8), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[8]", ty: UInt<8> }, + }, + 11: Copy { + dest: StatePartIndex(46), // (0x80) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[9]", ty: UInt<8> }, + src: StatePartIndex(9), // (0x80) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[9]", ty: UInt<8> }, + }, + 12: Copy { + dest: StatePartIndex(47), // (0xc0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[10]", ty: UInt<8> }, + src: StatePartIndex(10), // (0xc0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[10]", ty: UInt<8> }, + }, + 13: Copy { + dest: StatePartIndex(48), // (0xe0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[11]", ty: UInt<8> }, + src: StatePartIndex(11), // (0xe0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[11]", ty: UInt<8> }, + }, + 14: Copy { + dest: StatePartIndex(49), // (0xf0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[12]", ty: UInt<8> }, + src: StatePartIndex(12), // (0xf0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[12]", ty: UInt<8> }, + }, + 15: Copy { + dest: StatePartIndex(50), // (0xf8) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[13]", ty: UInt<8> }, + src: StatePartIndex(13), // (0xf8) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[13]", ty: UInt<8> }, + }, + 16: Copy { + dest: StatePartIndex(51), // (0xfc) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[14]", ty: UInt<8> }, + src: StatePartIndex(14), // (0xfc) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[14]", ty: UInt<8> }, + }, + 17: Copy { + dest: StatePartIndex(52), // (0xfe) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[15]", ty: UInt<8> }, + src: StatePartIndex(15), // (0xfe) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[15]", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:12:1 + 18: BranchIfZero { + target: 20, + value: StatePartIndex(36), // (0x1) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::write_en", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:13:1 + 19: WriteIndexed { + dest: StatePartIndex(37) /* (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[0]", ty: UInt<8> } */ [StatePartIndex(0) /* (0x10 16) SlotDebugData { name: "", ty: UInt<8> } */ , len=16, stride=1],, + src: StatePartIndex(35), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::write_data", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:11:1 + 20: Copy { + dest: StatePartIndex(16), // (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[0]", ty: UInt<8> }, + src: StatePartIndex(37), // (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[0]", ty: UInt<8> }, + }, + 21: Copy { + dest: StatePartIndex(17), // (0x7f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[1]", ty: UInt<8> }, + src: StatePartIndex(38), // (0x7f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[1]", ty: UInt<8> }, + }, + 22: Copy { + dest: StatePartIndex(18), // (0x3f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[2]", ty: UInt<8> }, + src: StatePartIndex(39), // (0x3f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[2]", ty: UInt<8> }, + }, + 23: Copy { + dest: StatePartIndex(19), // (0x1f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[3]", ty: UInt<8> }, + src: StatePartIndex(40), // (0x1f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[3]", ty: UInt<8> }, + }, + 24: Copy { + dest: StatePartIndex(20), // (0xf) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[4]", ty: UInt<8> }, + src: StatePartIndex(41), // (0xf) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[4]", ty: UInt<8> }, + }, + 25: Copy { + dest: StatePartIndex(21), // (0x7) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[5]", ty: UInt<8> }, + src: StatePartIndex(42), // (0x7) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[5]", ty: UInt<8> }, + }, + 26: Copy { + dest: StatePartIndex(22), // (0x3) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[6]", ty: UInt<8> }, + src: StatePartIndex(43), // (0x3) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[6]", ty: UInt<8> }, + }, + 27: Copy { + dest: StatePartIndex(23), // (0x1) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[7]", ty: UInt<8> }, + src: StatePartIndex(44), // (0x1) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[7]", ty: UInt<8> }, + }, + 28: Copy { + dest: StatePartIndex(24), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[8]", ty: UInt<8> }, + src: StatePartIndex(45), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[8]", ty: UInt<8> }, + }, + 29: Copy { + dest: StatePartIndex(25), // (0x80) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[9]", ty: UInt<8> }, + src: StatePartIndex(46), // (0x80) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[9]", ty: UInt<8> }, + }, + 30: Copy { + dest: StatePartIndex(26), // (0xc0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[10]", ty: UInt<8> }, + src: StatePartIndex(47), // (0xc0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[10]", ty: UInt<8> }, + }, + 31: Copy { + dest: StatePartIndex(27), // (0xe0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[11]", ty: UInt<8> }, + src: StatePartIndex(48), // (0xe0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[11]", ty: UInt<8> }, + }, + 32: Copy { + dest: StatePartIndex(28), // (0xf0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[12]", ty: UInt<8> }, + src: StatePartIndex(49), // (0xf0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[12]", ty: UInt<8> }, + }, + 33: Copy { + dest: StatePartIndex(29), // (0xf8) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[13]", ty: UInt<8> }, + src: StatePartIndex(50), // (0xf8) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[13]", ty: UInt<8> }, + }, + 34: Copy { + dest: StatePartIndex(30), // (0xfc) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[14]", ty: UInt<8> }, + src: StatePartIndex(51), // (0xfc) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[14]", ty: UInt<8> }, + }, + 35: Copy { + dest: StatePartIndex(31), // (0xfe) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[15]", ty: UInt<8> }, + src: StatePartIndex(52), // (0xfe) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[15]", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:14:1 + 36: ReadIndexed { + dest: StatePartIndex(53), // (0xff) SlotDebugData { name: "", ty: UInt<8> }, + src: StatePartIndex(37) /* (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[0]", ty: UInt<8> } */ [StatePartIndex(1) /* (0x0 0) SlotDebugData { name: "", ty: UInt<8> } */ , len=16, stride=1],, + }, + 37: Copy { + dest: StatePartIndex(33), // (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::read_data", ty: UInt<8> }, + src: StatePartIndex(53), // (0xff) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 38: Return, + ], + .. + }, + pc: 38, + memory_write_log: [], + memories: StatePart { + value: [], + }, + small_slots: StatePart { + value: [ + 16, + 0, + ], + }, + big_slots: StatePart { + value: [ + 255, + 127, + 63, + 31, + 15, + 7, + 3, + 1, + 0, + 128, + 192, + 224, + 240, + 248, + 252, + 254, + 255, + 127, + 63, + 31, + 15, + 7, + 3, + 1, + 0, + 128, + 192, + 224, + 240, + 248, + 252, + 254, + 0, + 255, + 16, + 0, + 1, + 255, + 127, + 63, + 31, + 15, + 7, + 3, + 1, + 0, + 128, + 192, + 224, + 240, + 248, + 252, + 254, + 255, + ], + }, + }, + io: Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }, + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in: CompiledValue { + layout: CompiledTypeLayout { + ty: Array, 16>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 16, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[7]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[8]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[9]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[10]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[11]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[12]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[13]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[14]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[15]", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Array { + element: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 16 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[0]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[10]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 10, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[11]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 11, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[12]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 12, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[13]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 13, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[14]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 14, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[15]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 15, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[1]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[2]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[3]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 3, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[4]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 4, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[5]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 5, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[6]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 6, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[7]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 7, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[8]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 8, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_in[9]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 9, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out: CompiledValue { + layout: CompiledTypeLayout { + ty: Array, 16>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 16, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[7]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[8]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[9]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[10]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[11]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[12]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[13]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[14]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[15]", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Array { + element: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 16, len: 16 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[0]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 16, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[10]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 26, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[11]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 27, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[12]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 28, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[13]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 29, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[14]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 30, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[15]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 31, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[1]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 17, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[2]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 18, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[3]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 19, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[4]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 20, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[5]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 21, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[6]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 22, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[7]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 23, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[8]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 24, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.array_out[9]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 25, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.read_data: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::read_data", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 33, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.read_index: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::read_index", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 32, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.write_data: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::write_data", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 35, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.write_en: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::write_en", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 36, len: 1 }, + }, + write: None, + }, + Instance { + name: ::array_rw, + instantiated: Module { + name: array_rw, + .. + }, + }.write_index: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(array_rw: array_rw).array_rw::write_index", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 34, len: 1 }, + }, + write: None, + }, + }, + made_initial_step: true, + needs_settle: false, + trace_decls: TraceModule { + name: "array_rw", + children: [ + TraceModuleIO { + name: "array_in", + child: TraceArray { + name: "array_in", + elements: [ + TraceUInt { + location: TraceScalarId(0), + name: "[0]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(1), + name: "[1]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(2), + name: "[2]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(3), + name: "[3]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(4), + name: "[4]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(5), + name: "[5]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(6), + name: "[6]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(7), + name: "[7]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(8), + name: "[8]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(9), + name: "[9]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(10), + name: "[10]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(11), + name: "[11]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(12), + name: "[12]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(13), + name: "[13]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(14), + name: "[14]", + ty: UInt<8>, + flow: Source, + }, + TraceUInt { + location: TraceScalarId(15), + name: "[15]", + ty: UInt<8>, + flow: Source, + }, + ], + ty: Array, 16>, + flow: Source, + }, + ty: Array, 16>, + flow: Source, + }, + TraceModuleIO { + name: "array_out", + child: TraceArray { + name: "array_out", + elements: [ + TraceUInt { + location: TraceScalarId(16), + name: "[0]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(17), + name: "[1]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(18), + name: "[2]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(19), + name: "[3]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(20), + name: "[4]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(21), + name: "[5]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(22), + name: "[6]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(23), + name: "[7]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(24), + name: "[8]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(25), + name: "[9]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(26), + name: "[10]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(27), + name: "[11]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(28), + name: "[12]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(29), + name: "[13]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(30), + name: "[14]", + ty: UInt<8>, + flow: Sink, + }, + TraceUInt { + location: TraceScalarId(31), + name: "[15]", + ty: UInt<8>, + flow: Sink, + }, + ], + ty: Array, 16>, + flow: Sink, + }, + ty: Array, 16>, + flow: Sink, + }, + TraceModuleIO { + name: "read_index", + child: TraceUInt { + location: TraceScalarId(32), + name: "read_index", + ty: UInt<8>, + flow: Source, + }, + ty: UInt<8>, + flow: Source, + }, + TraceModuleIO { + name: "read_data", + child: TraceUInt { + location: TraceScalarId(33), + name: "read_data", + ty: UInt<8>, + flow: Sink, + }, + ty: UInt<8>, + flow: Sink, + }, + TraceModuleIO { + name: "write_index", + child: TraceUInt { + location: TraceScalarId(34), + name: "write_index", + ty: UInt<8>, + flow: Source, + }, + ty: UInt<8>, + flow: Source, + }, + TraceModuleIO { + name: "write_data", + child: TraceUInt { + location: TraceScalarId(35), + name: "write_data", + ty: UInt<8>, + flow: Source, + }, + ty: UInt<8>, + flow: Source, + }, + TraceModuleIO { + name: "write_en", + child: TraceBool { + location: TraceScalarId(36), + name: "write_en", + flow: Source, + }, + ty: Bool, + flow: Source, + }, + TraceWire { + name: "array_wire", + child: TraceArray { + name: "array_wire", + elements: [ + TraceUInt { + location: TraceScalarId(37), + name: "[0]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(38), + name: "[1]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(39), + name: "[2]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(40), + name: "[3]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(41), + name: "[4]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(42), + name: "[5]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(43), + name: "[6]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(44), + name: "[7]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(45), + name: "[8]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(46), + name: "[9]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(47), + name: "[10]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(48), + name: "[11]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(49), + name: "[12]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(50), + name: "[13]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(51), + name: "[14]", + ty: UInt<8>, + flow: Duplex, + }, + TraceUInt { + location: TraceScalarId(52), + name: "[15]", + ty: UInt<8>, + flow: Duplex, + }, + ], + ty: Array, 16>, + flow: Duplex, + }, + ty: Array, 16>, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigUInt { + index: StatePartIndex(0), + ty: UInt<8>, + }, + state: 0xff, + last_state: 0xff, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigUInt { + index: StatePartIndex(1), + ty: UInt<8>, + }, + state: 0x7f, + last_state: 0x7f, + }, + SimTrace { + id: TraceScalarId(2), + kind: BigUInt { + index: StatePartIndex(2), + ty: UInt<8>, + }, + state: 0x3f, + last_state: 0x3f, + }, + SimTrace { + id: TraceScalarId(3), + kind: BigUInt { + index: StatePartIndex(3), + ty: UInt<8>, + }, + state: 0x1f, + last_state: 0x1f, + }, + SimTrace { + id: TraceScalarId(4), + kind: BigUInt { + index: StatePartIndex(4), + ty: UInt<8>, + }, + state: 0x0f, + last_state: 0x0f, + }, + SimTrace { + id: TraceScalarId(5), + kind: BigUInt { + index: StatePartIndex(5), + ty: UInt<8>, + }, + state: 0x07, + last_state: 0x07, + }, + SimTrace { + id: TraceScalarId(6), + kind: BigUInt { + index: StatePartIndex(6), + ty: UInt<8>, + }, + state: 0x03, + last_state: 0x03, + }, + SimTrace { + id: TraceScalarId(7), + kind: BigUInt { + index: StatePartIndex(7), + ty: UInt<8>, + }, + state: 0x01, + last_state: 0x01, + }, + SimTrace { + id: TraceScalarId(8), + kind: BigUInt { + index: StatePartIndex(8), + ty: UInt<8>, + }, + state: 0x00, + last_state: 0x00, + }, + SimTrace { + id: TraceScalarId(9), + kind: BigUInt { + index: StatePartIndex(9), + ty: UInt<8>, + }, + state: 0x80, + last_state: 0x80, + }, + SimTrace { + id: TraceScalarId(10), + kind: BigUInt { + index: StatePartIndex(10), + ty: UInt<8>, + }, + state: 0xc0, + last_state: 0xc0, + }, + SimTrace { + id: TraceScalarId(11), + kind: BigUInt { + index: StatePartIndex(11), + ty: UInt<8>, + }, + state: 0xe0, + last_state: 0xe0, + }, + SimTrace { + id: TraceScalarId(12), + kind: BigUInt { + index: StatePartIndex(12), + ty: UInt<8>, + }, + state: 0xf0, + last_state: 0xf0, + }, + SimTrace { + id: TraceScalarId(13), + kind: BigUInt { + index: StatePartIndex(13), + ty: UInt<8>, + }, + state: 0xf8, + last_state: 0xf8, + }, + SimTrace { + id: TraceScalarId(14), + kind: BigUInt { + index: StatePartIndex(14), + ty: UInt<8>, + }, + state: 0xfc, + last_state: 0xfc, + }, + SimTrace { + id: TraceScalarId(15), + kind: BigUInt { + index: StatePartIndex(15), + ty: UInt<8>, + }, + state: 0xfe, + last_state: 0xfe, + }, + SimTrace { + id: TraceScalarId(16), + kind: BigUInt { + index: StatePartIndex(16), + ty: UInt<8>, + }, + state: 0xff, + last_state: 0xff, + }, + SimTrace { + id: TraceScalarId(17), + kind: BigUInt { + index: StatePartIndex(17), + ty: UInt<8>, + }, + state: 0x7f, + last_state: 0x7f, + }, + SimTrace { + id: TraceScalarId(18), + kind: BigUInt { + index: StatePartIndex(18), + ty: UInt<8>, + }, + state: 0x3f, + last_state: 0x3f, + }, + SimTrace { + id: TraceScalarId(19), + kind: BigUInt { + index: StatePartIndex(19), + ty: UInt<8>, + }, + state: 0x1f, + last_state: 0x1f, + }, + SimTrace { + id: TraceScalarId(20), + kind: BigUInt { + index: StatePartIndex(20), + ty: UInt<8>, + }, + state: 0x0f, + last_state: 0x0f, + }, + SimTrace { + id: TraceScalarId(21), + kind: BigUInt { + index: StatePartIndex(21), + ty: UInt<8>, + }, + state: 0x07, + last_state: 0x07, + }, + SimTrace { + id: TraceScalarId(22), + kind: BigUInt { + index: StatePartIndex(22), + ty: UInt<8>, + }, + state: 0x03, + last_state: 0x03, + }, + SimTrace { + id: TraceScalarId(23), + kind: BigUInt { + index: StatePartIndex(23), + ty: UInt<8>, + }, + state: 0x01, + last_state: 0x01, + }, + SimTrace { + id: TraceScalarId(24), + kind: BigUInt { + index: StatePartIndex(24), + ty: UInt<8>, + }, + state: 0x00, + last_state: 0x00, + }, + SimTrace { + id: TraceScalarId(25), + kind: BigUInt { + index: StatePartIndex(25), + ty: UInt<8>, + }, + state: 0x80, + last_state: 0x80, + }, + SimTrace { + id: TraceScalarId(26), + kind: BigUInt { + index: StatePartIndex(26), + ty: UInt<8>, + }, + state: 0xc0, + last_state: 0xc0, + }, + SimTrace { + id: TraceScalarId(27), + kind: BigUInt { + index: StatePartIndex(27), + ty: UInt<8>, + }, + state: 0xe0, + last_state: 0xe0, + }, + SimTrace { + id: TraceScalarId(28), + kind: BigUInt { + index: StatePartIndex(28), + ty: UInt<8>, + }, + state: 0xf0, + last_state: 0xf0, + }, + SimTrace { + id: TraceScalarId(29), + kind: BigUInt { + index: StatePartIndex(29), + ty: UInt<8>, + }, + state: 0xf8, + last_state: 0xf8, + }, + SimTrace { + id: TraceScalarId(30), + kind: BigUInt { + index: StatePartIndex(30), + ty: UInt<8>, + }, + state: 0xfc, + last_state: 0xfc, + }, + SimTrace { + id: TraceScalarId(31), + kind: BigUInt { + index: StatePartIndex(31), + ty: UInt<8>, + }, + state: 0xfe, + last_state: 0xe1, + }, + SimTrace { + id: TraceScalarId(32), + kind: BigUInt { + index: StatePartIndex(32), + ty: UInt<8>, + }, + state: 0x00, + last_state: 0x00, + }, + SimTrace { + id: TraceScalarId(33), + kind: BigUInt { + index: StatePartIndex(33), + ty: UInt<8>, + }, + state: 0xff, + last_state: 0xff, + }, + SimTrace { + id: TraceScalarId(34), + kind: BigUInt { + index: StatePartIndex(34), + ty: UInt<8>, + }, + state: 0x10, + last_state: 0x0f, + }, + SimTrace { + id: TraceScalarId(35), + kind: BigUInt { + index: StatePartIndex(35), + ty: UInt<8>, + }, + state: 0x00, + last_state: 0xe1, + }, + SimTrace { + id: TraceScalarId(36), + kind: BigBool { + index: StatePartIndex(36), + }, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(37), + kind: BigUInt { + index: StatePartIndex(37), + ty: UInt<8>, + }, + state: 0xff, + last_state: 0xff, + }, + SimTrace { + id: TraceScalarId(38), + kind: BigUInt { + index: StatePartIndex(38), + ty: UInt<8>, + }, + state: 0x7f, + last_state: 0x7f, + }, + SimTrace { + id: TraceScalarId(39), + kind: BigUInt { + index: StatePartIndex(39), + ty: UInt<8>, + }, + state: 0x3f, + last_state: 0x3f, + }, + SimTrace { + id: TraceScalarId(40), + kind: BigUInt { + index: StatePartIndex(40), + ty: UInt<8>, + }, + state: 0x1f, + last_state: 0x1f, + }, + SimTrace { + id: TraceScalarId(41), + kind: BigUInt { + index: StatePartIndex(41), + ty: UInt<8>, + }, + state: 0x0f, + last_state: 0x0f, + }, + SimTrace { + id: TraceScalarId(42), + kind: BigUInt { + index: StatePartIndex(42), + ty: UInt<8>, + }, + state: 0x07, + last_state: 0x07, + }, + SimTrace { + id: TraceScalarId(43), + kind: BigUInt { + index: StatePartIndex(43), + ty: UInt<8>, + }, + state: 0x03, + last_state: 0x03, + }, + SimTrace { + id: TraceScalarId(44), + kind: BigUInt { + index: StatePartIndex(44), + ty: UInt<8>, + }, + state: 0x01, + last_state: 0x01, + }, + SimTrace { + id: TraceScalarId(45), + kind: BigUInt { + index: StatePartIndex(45), + ty: UInt<8>, + }, + state: 0x00, + last_state: 0x00, + }, + SimTrace { + id: TraceScalarId(46), + kind: BigUInt { + index: StatePartIndex(46), + ty: UInt<8>, + }, + state: 0x80, + last_state: 0x80, + }, + SimTrace { + id: TraceScalarId(47), + kind: BigUInt { + index: StatePartIndex(47), + ty: UInt<8>, + }, + state: 0xc0, + last_state: 0xc0, + }, + SimTrace { + id: TraceScalarId(48), + kind: BigUInt { + index: StatePartIndex(48), + ty: UInt<8>, + }, + state: 0xe0, + last_state: 0xe0, + }, + SimTrace { + id: TraceScalarId(49), + kind: BigUInt { + index: StatePartIndex(49), + ty: UInt<8>, + }, + state: 0xf0, + last_state: 0xf0, + }, + SimTrace { + id: TraceScalarId(50), + kind: BigUInt { + index: StatePartIndex(50), + ty: UInt<8>, + }, + state: 0xf8, + last_state: 0xf8, + }, + SimTrace { + id: TraceScalarId(51), + kind: BigUInt { + index: StatePartIndex(51), + ty: UInt<8>, + }, + state: 0xfc, + last_state: 0xfc, + }, + SimTrace { + id: TraceScalarId(52), + kind: BigUInt { + index: StatePartIndex(52), + ty: UInt<8>, + }, + state: 0xfe, + last_state: 0xe1, + }, + ], + trace_memories: {}, + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + instant: 34 μs, + clocks_triggered: [], + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/array_rw.vcd b/crates/fayalite/tests/sim/expected/array_rw.vcd new file mode 100644 index 0000000..8ede394 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/array_rw.vcd @@ -0,0 +1,283 @@ +$timescale 1 ps $end +$scope module array_rw $end +$scope struct array_in $end +$var wire 8 ! \[0] $end +$var wire 8 " \[1] $end +$var wire 8 # \[2] $end +$var wire 8 $ \[3] $end +$var wire 8 % \[4] $end +$var wire 8 & \[5] $end +$var wire 8 ' \[6] $end +$var wire 8 ( \[7] $end +$var wire 8 ) \[8] $end +$var wire 8 * \[9] $end +$var wire 8 + \[10] $end +$var wire 8 , \[11] $end +$var wire 8 - \[12] $end +$var wire 8 . \[13] $end +$var wire 8 / \[14] $end +$var wire 8 0 \[15] $end +$upscope $end +$scope struct array_out $end +$var wire 8 1 \[0] $end +$var wire 8 2 \[1] $end +$var wire 8 3 \[2] $end +$var wire 8 4 \[3] $end +$var wire 8 5 \[4] $end +$var wire 8 6 \[5] $end +$var wire 8 7 \[6] $end +$var wire 8 8 \[7] $end +$var wire 8 9 \[8] $end +$var wire 8 : \[9] $end +$var wire 8 ; \[10] $end +$var wire 8 < \[11] $end +$var wire 8 = \[12] $end +$var wire 8 > \[13] $end +$var wire 8 ? \[14] $end +$var wire 8 @ \[15] $end +$upscope $end +$var wire 8 A read_index $end +$var wire 8 B read_data $end +$var wire 8 C write_index $end +$var wire 8 D write_data $end +$var wire 1 E write_en $end +$scope struct array_wire $end +$var wire 8 F \[0] $end +$var wire 8 G \[1] $end +$var wire 8 H \[2] $end +$var wire 8 I \[3] $end +$var wire 8 J \[4] $end +$var wire 8 K \[5] $end +$var wire 8 L \[6] $end +$var wire 8 M \[7] $end +$var wire 8 N \[8] $end +$var wire 8 O \[9] $end +$var wire 8 P \[10] $end +$var wire 8 Q \[11] $end +$var wire 8 R \[12] $end +$var wire 8 S \[13] $end +$var wire 8 T \[14] $end +$var wire 8 U \[15] $end +$upscope $end +$upscope $end +$enddefinitions $end +$dumpvars +b11111111 ! +b1111111 " +b111111 # +b11111 $ +b1111 % +b111 & +b11 ' +b1 ( +b0 ) +b10000000 * +b11000000 + +b11100000 , +b11110000 - +b11111000 . +b11111100 / +b11111110 0 +b11111111 1 +b1111111 2 +b111111 3 +b11111 4 +b1111 5 +b111 6 +b11 7 +b1 8 +b0 9 +b10000000 : +b11000000 ; +b11100000 < +b11110000 = +b11111000 > +b11111100 ? +b11111110 @ +b0 A +b11111111 B +b0 C +b0 D +0E +b11111111 F +b1111111 G +b111111 H +b11111 I +b1111 J +b111 K +b11 L +b1 M +b0 N +b10000000 O +b11000000 P +b11100000 Q +b11110000 R +b11111000 S +b11111100 T +b11111110 U +$end +#1000000 +b1 A +b1111111 B +#2000000 +b10 A +b111111 B +#3000000 +b11 A +b11111 B +#4000000 +b100 A +b1111 B +#5000000 +b101 A +b111 B +#6000000 +b110 A +b11 B +#7000000 +b111 A +b1 B +#8000000 +b1000 A +b0 B +#9000000 +b1001 A +b10000000 B +#10000000 +b1010 A +b11000000 B +#11000000 +b1011 A +b11100000 B +#12000000 +b1100 A +b11110000 B +#13000000 +b1101 A +b11111000 B +#14000000 +b1110 A +b11111100 B +#15000000 +b1111 A +b11111110 B +#16000000 +b10000 A +b0 B +#17000000 +b0 1 +b0 A +1E +b0 F +#18000000 +b11111111 1 +b1 2 +b11111111 B +b1 C +b1 D +b11111111 F +b1 G +#19000000 +b1111111 2 +b100 3 +b10 C +b100 D +b1111111 G +b100 H +#20000000 +b111111 3 +b1001 4 +b11 C +b1001 D +b111111 H +b1001 I +#21000000 +b11111 4 +b10000 5 +b100 C +b10000 D +b11111 I +b10000 J +#22000000 +b1111 5 +b11001 6 +b101 C +b11001 D +b1111 J +b11001 K +#23000000 +b111 6 +b100100 7 +b110 C +b100100 D +b111 K +b100100 L +#24000000 +b11 7 +b110001 8 +b111 C +b110001 D +b11 L +b110001 M +#25000000 +b1 8 +b1000000 9 +b1000 C +b1000000 D +b1 M +b1000000 N +#26000000 +b0 9 +b1010001 : +b1001 C +b1010001 D +b0 N +b1010001 O +#27000000 +b10000000 : +b1100100 ; +b1010 C +b1100100 D +b10000000 O +b1100100 P +#28000000 +b11000000 ; +b1111001 < +b1011 C +b1111001 D +b11000000 P +b1111001 Q +#29000000 +b11100000 < +b10010000 = +b1100 C +b10010000 D +b11100000 Q +b10010000 R +#30000000 +b11110000 = +b10101001 > +b1101 C +b10101001 D +b11110000 R +b10101001 S +#31000000 +b11111000 > +b11000100 ? +b1110 C +b11000100 D +b11111000 S +b11000100 T +#32000000 +b11111100 ? +b11100001 @ +b1111 C +b11100001 D +b11111100 T +b11100001 U +#33000000 +b11111110 @ +b10000 C +b0 D +b11111110 U +#34000000 diff --git a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt new file mode 100644 index 0000000..186e5a5 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt @@ -0,0 +1,189 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 4, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::i", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::w", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:1:1 + 0: Const { + dest: StatePartIndex(3), // (0x0) SlotDebugData { name: "", ty: Bool }, + value: 0x0, + }, + 1: Const { + dest: StatePartIndex(2), // (0x1) SlotDebugData { name: "", ty: Bool }, + value: 0x1, + }, + // at: module-XXXXXXXXXX.rs:4:1 + 2: Copy { + dest: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::w", ty: Bool }, + src: StatePartIndex(2), // (0x1) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:5:1 + 3: BranchIfZero { + target: 5, + value: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::i", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:6:1 + 4: Copy { + dest: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::w", ty: Bool }, + src: StatePartIndex(3), // (0x0) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 5: Return, + ], + .. + }, + pc: 5, + memory_write_log: [], + memories: StatePart { + value: [], + }, + small_slots: StatePart { + value: [], + }, + big_slots: StatePart { + value: [ + 1, + 0, + 1, + 0, + ], + }, + }, + io: Instance { + name: ::conditional_assignment_last, + instantiated: Module { + name: conditional_assignment_last, + .. + }, + }, + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::conditional_assignment_last, + instantiated: Module { + name: conditional_assignment_last, + .. + }, + }.i: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::i", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + }, + made_initial_step: true, + needs_settle: false, + trace_decls: TraceModule { + name: "conditional_assignment_last", + children: [ + TraceModuleIO { + name: "i", + child: TraceBool { + location: TraceScalarId(0), + name: "i", + flow: Source, + }, + ty: Bool, + flow: Source, + }, + TraceWire { + name: "w", + child: TraceBool { + location: TraceScalarId(1), + name: "w", + flow: Duplex, + }, + ty: Bool, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigBool { + index: StatePartIndex(0), + }, + state: 0x1, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigBool { + index: StatePartIndex(1), + }, + state: 0x0, + last_state: 0x1, + }, + ], + trace_memories: {}, + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + instant: 2 μs, + clocks_triggered: [], + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/conditional_assignment_last.vcd b/crates/fayalite/tests/sim/expected/conditional_assignment_last.vcd new file mode 100644 index 0000000..dd9a85a --- /dev/null +++ b/crates/fayalite/tests/sim/expected/conditional_assignment_last.vcd @@ -0,0 +1,14 @@ +$timescale 1 ps $end +$scope module conditional_assignment_last $end +$var wire 1 ! i $end +$var wire 1 " w $end +$upscope $end +$enddefinitions $end +$dumpvars +0! +1" +$end +#1000000 +1! +0" +#2000000 diff --git a/crates/fayalite/tests/sim/expected/duplicate_names.txt b/crates/fayalite/tests/sim/expected/duplicate_names.txt new file mode 100644 index 0000000..8a59861 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/duplicate_names.txt @@ -0,0 +1,153 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 4, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:1:1 + 0: Const { + dest: StatePartIndex(3), // (0x6) SlotDebugData { name: "", ty: UInt<8> }, + value: 0x6, + }, + // at: module-XXXXXXXXXX.rs:5:1 + 1: Copy { + dest: StatePartIndex(2), // (0x6) SlotDebugData { name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", ty: UInt<8> }, + src: StatePartIndex(3), // (0x6) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 2: Const { + dest: StatePartIndex(1), // (0x5) SlotDebugData { name: "", ty: UInt<8> }, + value: 0x5, + }, + // at: module-XXXXXXXXXX.rs:3:1 + 3: Copy { + dest: StatePartIndex(0), // (0x5) SlotDebugData { name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", ty: UInt<8> }, + src: StatePartIndex(1), // (0x5) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 4: Return, + ], + .. + }, + pc: 4, + memory_write_log: [], + memories: StatePart { + value: [], + }, + small_slots: StatePart { + value: [], + }, + big_slots: StatePart { + value: [ + 5, + 5, + 6, + 6, + ], + }, + }, + io: Instance { + name: ::duplicate_names, + instantiated: Module { + name: duplicate_names, + .. + }, + }, + uninitialized_inputs: {}, + io_targets: {}, + made_initial_step: true, + needs_settle: false, + trace_decls: TraceModule { + name: "duplicate_names", + children: [ + TraceWire { + name: "w", + child: TraceUInt { + location: TraceScalarId(0), + name: "w", + ty: UInt<8>, + flow: Duplex, + }, + ty: UInt<8>, + }, + TraceWire { + name: "w", + child: TraceUInt { + location: TraceScalarId(1), + name: "w", + ty: UInt<8>, + flow: Duplex, + }, + ty: UInt<8>, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigUInt { + index: StatePartIndex(0), + ty: UInt<8>, + }, + state: 0x05, + last_state: 0x05, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigUInt { + index: StatePartIndex(2), + ty: UInt<8>, + }, + state: 0x06, + last_state: 0x06, + }, + ], + trace_memories: {}, + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + instant: 1 μs, + clocks_triggered: [], + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/duplicate_names.vcd b/crates/fayalite/tests/sim/expected/duplicate_names.vcd new file mode 100644 index 0000000..1e9f6c6 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/duplicate_names.vcd @@ -0,0 +1,11 @@ +$timescale 1 ps $end +$scope module duplicate_names $end +$var wire 8 ! w $end +$var wire 8 " w_2 $end +$upscope $end +$enddefinitions $end +$dumpvars +b101 ! +b110 " +$end +#1000000 diff --git a/crates/fayalite/tests/sim/expected/memories.vcd b/crates/fayalite/tests/sim/expected/memories.vcd index 72af410..bedc354 100644 --- a/crates/fayalite/tests/sim/expected/memories.vcd +++ b/crates/fayalite/tests/sim/expected/memories.vcd @@ -24,97 +24,97 @@ $upscope $end $upscope $end $scope struct mem $end $scope struct contents $end -$scope struct [0] $end +$scope struct \[0] $end $scope struct mem $end $var reg 8 9 \0 $end $var reg 8 I \1 $end $upscope $end $upscope $end -$scope struct [1] $end +$scope struct \[1] $end $scope struct mem $end $var reg 8 : \0 $end $var reg 8 J \1 $end $upscope $end $upscope $end -$scope struct [2] $end +$scope struct \[2] $end $scope struct mem $end $var reg 8 ; \0 $end $var reg 8 K \1 $end $upscope $end $upscope $end -$scope struct [3] $end +$scope struct \[3] $end $scope struct mem $end $var reg 8 < \0 $end $var reg 8 L \1 $end $upscope $end $upscope $end -$scope struct [4] $end +$scope struct \[4] $end $scope struct mem $end $var reg 8 = \0 $end $var reg 8 M \1 $end $upscope $end $upscope $end -$scope struct [5] $end +$scope struct \[5] $end $scope struct mem $end $var reg 8 > \0 $end $var reg 8 N \1 $end $upscope $end $upscope $end -$scope struct [6] $end +$scope struct \[6] $end $scope struct mem $end $var reg 8 ? \0 $end $var reg 8 O \1 $end $upscope $end $upscope $end -$scope struct [7] $end +$scope struct \[7] $end $scope struct mem $end $var reg 8 @ \0 $end $var reg 8 P \1 $end $upscope $end $upscope $end -$scope struct [8] $end +$scope struct \[8] $end $scope struct mem $end $var reg 8 A \0 $end $var reg 8 Q \1 $end $upscope $end $upscope $end -$scope struct [9] $end +$scope struct \[9] $end $scope struct mem $end $var reg 8 B \0 $end $var reg 8 R \1 $end $upscope $end $upscope $end -$scope struct [10] $end +$scope struct \[10] $end $scope struct mem $end $var reg 8 C \0 $end $var reg 8 S \1 $end $upscope $end $upscope $end -$scope struct [11] $end +$scope struct \[11] $end $scope struct mem $end $var reg 8 D \0 $end $var reg 8 T \1 $end $upscope $end $upscope $end -$scope struct [12] $end +$scope struct \[12] $end $scope struct mem $end $var reg 8 E \0 $end $var reg 8 U \1 $end $upscope $end $upscope $end -$scope struct [13] $end +$scope struct \[13] $end $scope struct mem $end $var reg 8 F \0 $end $var reg 8 V \1 $end $upscope $end $upscope $end -$scope struct [14] $end +$scope struct \[14] $end $scope struct mem $end $var reg 8 G \0 $end $var reg 8 W \1 $end $upscope $end $upscope $end -$scope struct [15] $end +$scope struct \[15] $end $scope struct mem $end $var reg 8 H \0 $end $var reg 8 X \1 $end diff --git a/crates/fayalite/tests/sim/expected/memories2.vcd b/crates/fayalite/tests/sim/expected/memories2.vcd index bd48f24..4039754 100644 --- a/crates/fayalite/tests/sim/expected/memories2.vcd +++ b/crates/fayalite/tests/sim/expected/memories2.vcd @@ -11,31 +11,31 @@ $var wire 1 ' wmask $end $upscope $end $scope struct mem $end $scope struct contents $end -$scope struct [0] $end +$scope struct \[0] $end $scope struct mem $end $var string 1 1 \$tag $end $var reg 1 6 HdlSome $end $upscope $end $upscope $end -$scope struct [1] $end +$scope struct \[1] $end $scope struct mem $end $var string 1 2 \$tag $end $var reg 1 7 HdlSome $end $upscope $end $upscope $end -$scope struct [2] $end +$scope struct \[2] $end $scope struct mem $end $var string 1 3 \$tag $end $var reg 1 8 HdlSome $end $upscope $end $upscope $end -$scope struct [3] $end +$scope struct \[3] $end $scope struct mem $end $var string 1 4 \$tag $end $var reg 1 9 HdlSome $end $upscope $end $upscope $end -$scope struct [4] $end +$scope struct \[4] $end $scope struct mem $end $var string 1 5 \$tag $end $var reg 1 : HdlSome $end diff --git a/crates/fayalite/tests/sim/expected/memories3.vcd b/crates/fayalite/tests/sim/expected/memories3.vcd index 328fcaa..5768560 100644 --- a/crates/fayalite/tests/sim/expected/memories3.vcd +++ b/crates/fayalite/tests/sim/expected/memories3.vcd @@ -42,7 +42,7 @@ $upscope $end $upscope $end $scope struct mem $end $scope struct contents $end -$scope struct [0] $end +$scope struct \[0] $end $scope struct mem $end $var reg 8 ] \[0] $end $var reg 8 e \[1] $end @@ -54,7 +54,7 @@ $var reg 8 /" \[6] $end $var reg 8 7" \[7] $end $upscope $end $upscope $end -$scope struct [1] $end +$scope struct \[1] $end $scope struct mem $end $var reg 8 ^ \[0] $end $var reg 8 f \[1] $end @@ -66,7 +66,7 @@ $var reg 8 0" \[6] $end $var reg 8 8" \[7] $end $upscope $end $upscope $end -$scope struct [2] $end +$scope struct \[2] $end $scope struct mem $end $var reg 8 _ \[0] $end $var reg 8 g \[1] $end @@ -78,7 +78,7 @@ $var reg 8 1" \[6] $end $var reg 8 9" \[7] $end $upscope $end $upscope $end -$scope struct [3] $end +$scope struct \[3] $end $scope struct mem $end $var reg 8 ` \[0] $end $var reg 8 h \[1] $end @@ -90,7 +90,7 @@ $var reg 8 2" \[6] $end $var reg 8 :" \[7] $end $upscope $end $upscope $end -$scope struct [4] $end +$scope struct \[4] $end $scope struct mem $end $var reg 8 a \[0] $end $var reg 8 i \[1] $end @@ -102,7 +102,7 @@ $var reg 8 3" \[6] $end $var reg 8 ;" \[7] $end $upscope $end $upscope $end -$scope struct [5] $end +$scope struct \[5] $end $scope struct mem $end $var reg 8 b \[0] $end $var reg 8 j \[1] $end @@ -114,7 +114,7 @@ $var reg 8 4" \[6] $end $var reg 8 <" \[7] $end $upscope $end $upscope $end -$scope struct [6] $end +$scope struct \[6] $end $scope struct mem $end $var reg 8 c \[0] $end $var reg 8 k \[1] $end @@ -126,7 +126,7 @@ $var reg 8 5" \[6] $end $var reg 8 =" \[7] $end $upscope $end $upscope $end -$scope struct [7] $end +$scope struct \[7] $end $scope struct mem $end $var reg 8 d \[0] $end $var reg 8 l \[1] $end