Compare commits

...
Sign in to create a new pull request.

23 commits

Author SHA1 Message Date
bb34aeb7f1
fayalite::build::verilog: tell firtool to only preserve values with significant names 2026-06-14 18:46:06 -07:00
7ddb4780fa
module::transform::deduce_structural_eq_flags: rewrite to use BoolFixedPointSolver for a massive speedup on large inputs 2026-06-14 01:33:04 -07:00
b0e7873a17
add BoolFixedPointSolver 2026-06-12 19:55:48 -07:00
1b16118ce5
deduce_structural_eq_flags: use expressions' literal_bits to improve deduction around cast_bits_to 2026-06-11 20:46:28 -07:00
e2ca80af97
fayalite::sim::compiler: fix compiling StructuralEq work properly on enums where the padding isn't known to be zero 2026-06-11 17:03:56 -07:00
30ffd009f6
WIP: fix simulator StructuralEq of enums 2026-06-11 01:56:27 -07:00
4bd6db3de8
add deduce_structural_eq_flags transform 2026-06-11 01:26:32 -07:00
98e7e91fc9
fayalite::expr::ops: add and automatically generate ops::StructuralEq 2026-06-09 18:33:34 -07:00
ffca1a279d
switch ready_valid::queue formal proofs to use formal_global_clock 2026-06-05 00:56:24 -07:00
d4d9706798
reimplement fayalite::formal and add support to the simulator
Add support to the simulator for running hdl asserts/assumes and being
able to write to the formal global clock/reset and all any/all_const/seq that are used.
This allows you to use the exact same HDL code for running a simulation and for running a formal proof.
2026-06-05 00:56:24 -07:00
5d68885eaf
fayalite::testing: add checked_vcd_output!() 2026-06-05 00:35:19 -07:00
31353862ce
fayalite/src/module: check that expressions are visible where they are used, e.g. erroring when a wire is inside an if but used outside. 2026-06-01 23:10:43 -07:00
b1116c4a1a
simplify_enums: cache folded expressions 2026-06-01 21:45:37 -07:00
6902aea3a6
firrtl: don't generate as many duplicate wires when compiling expressions 2026-06-01 20:53:22 -07:00
1880ed682f
speed up TraceAsString by caching the canonical type for can_substitute_type 2026-06-01 20:41:14 -07:00
cf3e6cfc6b
Add .to_trace_as_string() and clean up code 2026-05-14 22:13:31 -07:00
ea183eac87
add TraceAsString<T> -- sim traces it as a string rather than all its internal fields 2026-05-13 19:43:50 -07:00
26224abe1c
sim: properly update all VCD wires when they share simulation state 2026-05-05 21:12:00 -07:00
2266315944
redo #[hdl(sim)] match/let destructuring to support matching values of type Type::SimValue 2026-05-03 23:23:17 -07:00
7e9d7739fb
use #[hdl(cmp_eq)] for HdlOption and implement conversion <-> Option 2026-05-01 18:46:36 -07:00
7516ec3c24
implement #[hdl(cmp_eq)] for enums 2026-05-01 18:34:49 -07:00
8e4eeef723
add support for custom debug/display formatting of #[hdl] structs/enums
also cleans up default debug formatting to use the struct/enum name
(or MaskType<StructName>) instead of the implementation detail type name.
2026-04-30 23:10:49 -07:00
402f457c68
sim: Speed up updating traces by tracking which traces are written to 2026-04-30 19:12:20 -07:00
116 changed files with 23293 additions and 1756 deletions

View file

@ -257,5 +257,6 @@ no_op_fold!(syn::Token![let]);
no_op_fold!(syn::Token![mut]);
no_op_fold!(syn::Token![static]);
no_op_fold!(syn::Token![struct]);
no_op_fold!(syn::Token![type]);
no_op_fold!(syn::Token![where]);
no_op_fold!(usize);

View file

@ -3,8 +3,9 @@
use crate::{
Errors, HdlAttr, PairsIterExt,
hdl_type_common::{
ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedField, ParsedFieldsNamed, ParsedGenerics,
SplitForImpl, TypesParser, WrappedInConst, common_derives, get_target,
CustomDebugOptions, CustomDebugTrait, ItemOptions, MakeHdlTypeExpr, MaybeParsed,
ParsedField, ParsedFieldsNamed, ParsedGenerics, SplitForImpl, TypesParser, WrappedInConst,
common_derives, create_struct_debug_impl, get_target,
},
kw,
};
@ -30,6 +31,7 @@ pub(crate) struct ParsedBundle {
pub(crate) fields: MaybeParsed<ParsedFieldsNamed, FieldsNamed>,
pub(crate) field_flips: Vec<Option<HdlAttr<kw::flip, kw::hdl>>>,
pub(crate) mask_type_ident: Ident,
pub(crate) mask_type_name: String,
pub(crate) mask_type_match_variant_ident: Ident,
pub(crate) mask_type_sim_value_ident: Ident,
pub(crate) match_variant_ident: Ident,
@ -88,6 +90,8 @@ impl ParsedBundle {
no_runtime_generics: _,
cmp_eq: _,
ref get,
custom_debug: _,
custom_sim_display: _,
} = options.body;
if let Some((get, ..)) = get {
errors.error(get, "#[hdl(get(...))] is not allowed on structs");
@ -131,6 +135,7 @@ impl ParsedBundle {
fields,
field_flips,
mask_type_ident: format_ident!("__{}__MaskType", ident),
mask_type_name: format!("MaskType<{}>", ident),
mask_type_match_variant_ident: format_ident!("__{}__MaskType__MatchVariant", ident),
mask_type_sim_value_ident: format_ident!("__{}__MaskType__SimValue", ident),
match_variant_ident: format_ident!("__{}__MatchVariant", ident),
@ -448,6 +453,7 @@ impl ToTokens for ParsedBundle {
fields,
field_flips,
mask_type_ident,
mask_type_name,
mask_type_match_variant_ident,
mask_type_sim_value_ident,
match_variant_ident,
@ -464,11 +470,20 @@ impl ToTokens for ParsedBundle {
no_runtime_generics,
cmp_eq,
get: _,
custom_debug: _,
custom_sim_display,
} = &options.body;
let CustomDebugOptions {
type_: custom_debug_type,
sim: custom_debug_sim,
mask_type: custom_debug_mask_type,
mask_sim: custom_debug_mask_sim,
} = options.body.custom_debug();
let target = get_target(target, ident);
let struct_name = ident.to_string();
let mut item_attrs = attrs.clone();
item_attrs.push(common_derives(span));
ItemStruct {
item_attrs.push(common_derives(span, false));
let type_struct = ItemStruct {
attrs: item_attrs,
vis: vis.clone(),
struct_token: *struct_token,
@ -476,8 +491,8 @@ impl ToTokens for ParsedBundle {
generics: generics.into(),
fields: Fields::Named(fields.clone().into()),
semi_token: None,
}
.to_tokens(tokens);
};
type_struct.to_tokens(tokens);
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(fields), None) =
(generics, fields, no_runtime_generics)
@ -503,6 +518,9 @@ impl ToTokens for ParsedBundle {
}
let mut wrapped_in_const = WrappedInConst::new(tokens, span);
let tokens = wrapped_in_const.inner();
if custom_debug_type.is_none() {
create_struct_debug_impl(&type_struct, &struct_name, None).to_tokens(tokens);
}
let builder = Builder {
vis: vis.clone(),
struct_token: *struct_token,
@ -530,9 +548,9 @@ impl ToTokens for ParsedBundle {
mask_type_builder.to_tokens(tokens);
let unfilled_mask_type_builder_ty =
mask_type_builder.builder_struct_ty(|_| BuilderFieldState::Unfilled);
ItemStruct {
let mask_type_struct = ItemStruct {
attrs: vec![
common_derives(span),
common_derives(span, false),
parse_quote_spanned! {span=>
#[allow(non_camel_case_types, dead_code)]
},
@ -543,17 +561,20 @@ impl ToTokens for ParsedBundle {
generics: generics.into(),
fields: Fields::Named(mask_type_fields.clone()),
semi_token: None,
};
mask_type_struct.to_tokens(tokens);
if custom_debug_mask_type.is_none() {
create_struct_debug_impl(&mask_type_struct, mask_type_name, None).to_tokens(tokens);
}
.to_tokens(tokens);
let mut mask_type_match_variant_fields = mask_type_fields.clone();
for Field { ty, .. } in &mut mask_type_match_variant_fields.named {
*ty = parse_quote_spanned! {span=>
::fayalite::expr::Expr<#ty>
};
}
ItemStruct {
let mask_type_match_variant_struct = ItemStruct {
attrs: vec![
common_derives(span),
common_derives(span, false),
parse_quote_spanned! {span=>
#[allow(non_camel_case_types, dead_code)]
},
@ -564,17 +585,19 @@ impl ToTokens for ParsedBundle {
generics: generics.into(),
fields: Fields::Named(mask_type_match_variant_fields),
semi_token: None,
}
.to_tokens(tokens);
};
mask_type_match_variant_struct.to_tokens(tokens);
create_struct_debug_impl(&mask_type_match_variant_struct, mask_type_name, None)
.to_tokens(tokens);
let mut match_variant_fields = FieldsNamed::from(fields.clone());
for Field { ty, .. } in &mut match_variant_fields.named {
*ty = parse_quote_spanned! {span=>
::fayalite::expr::Expr<#ty>
};
}
ItemStruct {
let match_variant_struct = ItemStruct {
attrs: vec![
common_derives(span),
common_derives(span, false),
parse_quote_spanned! {span=>
#[allow(non_camel_case_types, dead_code)]
},
@ -585,19 +608,19 @@ impl ToTokens for ParsedBundle {
generics: generics.into(),
fields: Fields::Named(match_variant_fields),
semi_token: None,
}
.to_tokens(tokens);
};
match_variant_struct.to_tokens(tokens);
create_struct_debug_impl(&match_variant_struct, &struct_name, None).to_tokens(tokens);
let mut mask_type_sim_value_fields = mask_type_fields;
for Field { ty, .. } in &mut mask_type_sim_value_fields.named {
*ty = parse_quote_spanned! {span=>
::fayalite::sim::value::SimValue<#ty>
};
}
ItemStruct {
let mask_type_sim_value_struct = ItemStruct {
attrs: vec![
parse_quote_spanned! {span=>
#[::fayalite::__std::prelude::v1::derive(
::fayalite::__std::fmt::Debug,
::fayalite::__std::clone::Clone,
)]
},
@ -611,19 +634,34 @@ impl ToTokens for ParsedBundle {
generics: generics.into(),
fields: Fields::Named(mask_type_sim_value_fields),
semi_token: None,
};
mask_type_sim_value_struct.to_tokens(tokens);
if custom_debug_mask_sim.is_none() {
create_struct_debug_impl(
&mask_type_struct,
mask_type_name,
Some(CustomDebugTrait {
trait_path: &parse_quote_spanned! {span=>
::fayalite::ty::SimValueDebug
},
fn_name: &format_ident!("sim_value_debug", span = span),
this_arg: &parse_quote_spanned! {span=>
value: &<Self as ::fayalite::ty::Type>::SimValue
},
}),
)
.to_tokens(tokens);
}
.to_tokens(tokens);
let mut sim_value_fields = FieldsNamed::from(fields.clone());
for Field { ty, .. } in &mut sim_value_fields.named {
*ty = parse_quote_spanned! {span=>
::fayalite::sim::value::SimValue<#ty>
};
}
ItemStruct {
let sim_value_struct = ItemStruct {
attrs: vec![
parse_quote_spanned! {span=>
#[::fayalite::__std::prelude::v1::derive(
::fayalite::__std::fmt::Debug,
::fayalite::__std::clone::Clone,
)]
},
@ -637,8 +675,36 @@ impl ToTokens for ParsedBundle {
generics: generics.into(),
fields: Fields::Named(sim_value_fields),
semi_token: None,
};
sim_value_struct.to_tokens(tokens);
if custom_debug_sim.is_none() {
create_struct_debug_impl(
&type_struct,
&struct_name,
Some(CustomDebugTrait {
trait_path: &parse_quote_spanned! {span=>
::fayalite::ty::SimValueDebug
},
fn_name: &format_ident!("sim_value_debug", span = span),
this_arg: &parse_quote_spanned! {span=>
value: &<Self as ::fayalite::ty::Type>::SimValue
},
}),
)
.to_tokens(tokens);
}
if custom_sim_display.is_some() {
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
#where_clause
{
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(self, f)
}
}
}.to_tokens(tokens);
}
.to_tokens(tokens);
let this_token = Ident::new("__this", span);
let fields_token = Ident::new("__fields", span);
let self_token = Token![self](span);
@ -820,6 +886,14 @@ impl ToTokens for ParsedBundle {
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::__std::fmt::Debug for #mask_type_sim_value_ident #type_generics
#where_clause
{
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
<#mask_type_ident #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::expr::ValueType for #mask_type_sim_value_ident #type_generics
#where_clause
{
@ -980,6 +1054,14 @@ impl ToTokens for ParsedBundle {
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
#where_clause
{
fn fmt(&self, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::expr::ValueType for #sim_value_ident #type_generics
#where_clause
{
@ -1051,6 +1133,7 @@ impl ToTokens for ParsedBundle {
let mut fields_expr_ne = vec![];
let mut fields_valueless_eq = vec![];
let mut fields_valueless_ne = vec![];
let mut fields_structural_eq = vec![];
for field in fields.named() {
let field_ident = field.ident();
let field_ty = field.ty();
@ -1059,6 +1142,9 @@ impl ToTokens for ParsedBundle {
.push(parse_quote_spanned! {cmp_eq.span=>
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
});
fields_structural_eq.push(quote_spanned! {cmp_eq.span=>
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
});
fields_value_eq.push(quote_spanned! {span=>
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
__lhs.#field_ident,
@ -1106,6 +1192,7 @@ impl ToTokens for ParsedBundle {
let expr_ne_body;
let valueless_eq_body;
let valueless_ne_body;
let structural_eq;
if fields_len == 0 {
value_eq_body = quote_spanned! {span=>
true
@ -1125,6 +1212,9 @@ impl ToTokens for ParsedBundle {
valueless_ne_body = quote_spanned! {span=>
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
};
structural_eq = quote_spanned! {span=>
true
};
} else {
value_eq_body = quote_spanned! {span=>
#(#fields_value_eq)&*
@ -1141,19 +1231,24 @@ impl ToTokens for ParsedBundle {
valueless_eq_body = quote_spanned! {span=>
let __lhs = ::fayalite::expr::ValueType::ty(&__lhs);
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
#(#fields_valueless_eq)|*
#(#fields_valueless_eq)&*
};
valueless_ne_body = quote_spanned! {span=>
let __lhs = ::fayalite::expr::ValueType::ty(&__lhs);
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
#(#fields_valueless_ne)|*
};
structural_eq = quote_spanned! {span=>
#(#fields_structural_eq)&&*
};
};
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
#cmp_eq_where_clause
{
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
#[track_caller]
fn cmp_value_eq(
__lhs: Self,
@ -1179,6 +1274,16 @@ impl ToTokens for ParsedBundle {
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
if let ::fayalite::__std::result::Result::Ok(__retval) =
::fayalite::expr::ops::StructuralEq::try_new(
::fayalite::expr::Expr::canonical(__lhs),
::fayalite::expr::Expr::canonical(__rhs),
)
{
return ::fayalite::expr::ToExpr::to_expr(&__retval);
}
}
#expr_eq_body
}
@ -1187,6 +1292,14 @@ impl ToTokens for ParsedBundle {
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
return !::fayalite::expr::ToExpr::to_expr(
&::fayalite::expr::ops::StructuralEq::new(
::fayalite::expr::Expr::canonical(__lhs),
::fayalite::expr::Expr::canonical(__rhs),
),
);
}
#expr_ne_body
}

View file

@ -3,8 +3,9 @@
use crate::{
Errors, HdlAttr, PairsIterExt,
hdl_type_common::{
ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType, SplitForImpl,
TypesParser, WrappedInConst, common_derives, get_target,
CustomDebugOptions, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType,
SplitForImpl, TypesParser, WrappedInConst, common_derives, create_struct_debug_impl,
get_target,
},
kw,
};
@ -158,15 +159,32 @@ impl ParsedEnum {
custom_bounds,
no_static: _,
no_runtime_generics: _,
cmp_eq,
cmp_eq: _,
ref get,
custom_debug: _,
custom_sim_display: _,
} = options.body;
if let Some((cmp_eq,)) = cmp_eq {
errors.error(cmp_eq, "#[hdl(cmp_eq)] is not yet implemented for enums");
}
if let Some((get, ..)) = get {
errors.error(get, "#[hdl(get(...))] is not allowed on enums");
}
let CustomDebugOptions {
type_: _,
sim: _,
mask_type,
mask_sim,
} = options.body.custom_debug();
if let Some((mask_type,)) = mask_type {
errors.error(
mask_type,
"#[hdl(custom_debug(mask_type)] is not allowed on enums",
);
}
if let Some((mask_sim,)) = mask_sim {
errors.error(
mask_sim,
"#[hdl(custom_debug(mask_sim)] is not allowed on enums",
);
}
attrs.retain(|attr| {
if attr.path().is_ident("repr") {
errors.error(attr, "#[repr] is not supported on #[hdl] enums");
@ -228,12 +246,21 @@ impl ToTokens for ParsedEnum {
custom_bounds: _,
no_static,
no_runtime_generics,
cmp_eq: _, // TODO: implement cmp_eq for enums
cmp_eq,
get: _,
custom_debug: _,
custom_sim_display,
} = &options.body;
let CustomDebugOptions {
type_: custom_debug_type,
sim: custom_debug_sim,
mask_type: _,
mask_sim: _,
} = options.body.custom_debug();
let target = get_target(target, ident);
let enum_name = ident.to_string();
let mut struct_attrs = attrs.clone();
struct_attrs.push(common_derives(span));
struct_attrs.push(common_derives(span, false));
struct_attrs.push(parse_quote_spanned! {span=>
#[allow(non_snake_case)]
});
@ -273,7 +300,7 @@ impl ToTokens for ParsedEnum {
}
},
));
ItemStruct {
let type_struct = ItemStruct {
attrs: struct_attrs,
vis: vis.clone(),
struct_token: Token![struct](enum_token.span),
@ -288,8 +315,8 @@ impl ToTokens for ParsedEnum {
})
},
semi_token: None,
}
.to_tokens(tokens);
};
type_struct.to_tokens(tokens);
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
if let (MaybeParsed::Parsed(generics), None) = (generics, no_runtime_generics) {
generics.make_runtime_generics(tokens, vis, ident, &target, |context| {
@ -373,6 +400,9 @@ impl ToTokens for ParsedEnum {
}
.to_tokens(tokens);
}
if custom_debug_type.is_none() {
create_struct_debug_impl(&type_struct, &enum_name, None).to_tokens(tokens);
}
let mut enum_attrs = attrs.clone();
enum_attrs.push(parse_quote_spanned! {span=>
#[allow(dead_code, non_camel_case_types)]
@ -453,7 +483,6 @@ impl ToTokens for ParsedEnum {
let mut enum_attrs = attrs.clone();
enum_attrs.push(parse_quote_spanned! {span=>
#[::fayalite::__std::prelude::v1::derive(
::fayalite::__std::fmt::Debug,
::fayalite::__std::clone::Clone,
)]
});
@ -614,7 +643,9 @@ impl ToTokens for ParsedEnum {
#where_clause
{
#[allow(non_snake_case, dead_code)]
#vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
#vis fn #ident(
#self_token,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(
#self_token.#sim_builder_ty_field_ident,
#sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()),
@ -838,6 +869,290 @@ impl ToTokens for ParsedEnum {
},
)),
);
if custom_debug_sim.is_none() {
let debug_match_arms = Vec::from_iter(
variants
.iter()
.map(
|ParsedVariant {
attrs: _,
options: _,
ident,
field,
}| {
let variant_name = ident.to_string();
if let Some(_) = field {
quote_spanned! {span=>
#sim_value_ident::#ident(field, _) => {
f.debug_tuple(#variant_name).field(field).finish()
}
}
} else {
quote_spanned! {span=>
#sim_value_ident::#ident(_) => {
f.write_str(#variant_name)
}
}
}
},
)
.chain(sim_value_unknown_variant_name.as_ref().map(
|sim_value_unknown_variant_name| {
let sim_value_unknown_variant_name_str =
sim_value_unknown_variant_name.to_string();
quote_spanned! {span=>
#sim_value_ident::#sim_value_unknown_variant_name(_) => {
f.write_str(#sim_value_unknown_variant_name_str)
}
}
},
)),
);
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics ::fayalite::ty::SimValueDebug for #target #type_generics
#where_clause
{
fn sim_value_debug(
value: &<Self as ::fayalite::ty::Type>::SimValue,
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
) -> ::fayalite::__std::fmt::Result {
match value {
#(#debug_match_arms)*
}
}
}
}
.to_tokens(tokens);
}
if custom_sim_display.is_some() {
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics ::fayalite::__std::fmt::Display for #sim_value_ident #type_generics
#where_clause
{
fn fmt(
&self,
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
) -> ::fayalite::__std::fmt::Result {
<#target #type_generics as ::fayalite::ty::SimValueDisplay>::sim_value_display(
self,
f,
)
}
}
}.to_tokens(tokens);
}
if let Some((cmp_eq,)) = cmp_eq {
let mut cmp_eq_where_clause =
Generics::from(generics)
.where_clause
.unwrap_or_else(|| syn::WhereClause {
where_token: Token![where](span),
predicates: Punctuated::new(),
});
let mut variants_value_eq = vec![];
let mut variants_expr_eq = vec![];
let mut fields_valueless_eq = vec![];
let mut structural_eq: Option<TokenStream> = None;
for (
variant_index,
ParsedVariant {
attrs: _,
options: variant_options,
ident: variant_ident,
field,
},
) in variants.iter().enumerate()
{
let VariantOptions {} = variant_options.body;
if let Some(ParsedVariantField {
paren_token: _,
attrs: _,
options: field_options,
ty: field_ty,
comma_token: _,
}) = field
{
let FieldOptions {} = field_options.body;
cmp_eq_where_clause
.predicates
.push(parse_quote_spanned! {cmp_eq.span=>
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
});
match &mut structural_eq {
Some(structural_eq) => {
structural_eq.extend(quote_spanned! {cmp_eq.span=>
&& <#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
});
}
None => {
structural_eq = Some(quote_spanned! {cmp_eq.span=>
<#field_ty as ::fayalite::expr::HdlPartialEqImpl<#field_ty>>::TRY_STRUCTURAL_EQ
});
}
}
variants_value_eq.push(quote_spanned! {span=>
(
#sim_value_ident::#variant_ident(__lhs_field, _),
#sim_value_ident::#variant_ident(__rhs_field, _),
) => {
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
__lhs.#variant_ident,
::fayalite::__std::borrow::Cow::Borrowed(__lhs_field),
__rhs.#variant_ident,
::fayalite::__std::borrow::Cow::Borrowed(__rhs_field),
)
}
});
variants_expr_eq.push(quote_spanned! {span=>
{
let (#match_variant_ident::#variant_ident(__lhs), __scope) =
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
::fayalite::__std::iter::Iterator::next(&mut __lhs_match_variant_iter)
.expect("known to have enough variants"),
)
else {
::fayalite::__std::unreachable!();
};
let (#match_variant_ident::#variant_ident(__rhs), __scope) =
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
::fayalite::__std::iter::Iterator::nth(
&mut ::fayalite::module::match_(__rhs),
#variant_index,
)
.expect("known to have variant"),
)
else {
::fayalite::__std::unreachable!();
};
::fayalite::module::connect(
__retval,
::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs),
);
}
});
fields_valueless_eq.push(quote_spanned! {span=>
::fayalite::expr::HdlPartialEqImpl::cmp_valueless_eq(
::fayalite::expr::Valueless::new(__lhs.#variant_ident),
::fayalite::expr::Valueless::new(__rhs.#variant_ident),
)
});
} else {
variants_value_eq.push(quote_spanned! {span=>
(#sim_value_ident::#variant_ident(_), #sim_value_ident::#variant_ident(_)) => true,
});
variants_expr_eq.push(quote_spanned! {span=>
{
let (#match_variant_ident::#variant_ident, __scope) =
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
::fayalite::__std::iter::Iterator::next(&mut __lhs_match_variant_iter)
.expect("known to have enough variants"),
)
else {
::fayalite::__std::unreachable!();
};
let (#match_variant_ident::#variant_ident, __scope) =
::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope(
::fayalite::__std::iter::Iterator::nth(
&mut ::fayalite::module::match_(__rhs),
#variant_index,
)
.expect("known to have variant"),
)
else {
::fayalite::__std::unreachable!();
};
::fayalite::module::connect(__retval, true);
}
});
}
}
if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name {
variants_value_eq.push(quote_spanned! {span=>
(
#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown),
#sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown),
) => {
__lhs_unknown == __rhs_unknown
}
});
}
let valueless_eq_body = if fields_valueless_eq.is_empty() {
quote_spanned! {span=>
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
}
} else {
quote_spanned! {span=>
let __lhs = ::fayalite::expr::ValueType::ty(&__lhs);
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
#(#fields_valueless_eq)&*
}
};
let cmp_expr_eq_wire_name = format!("{ident}_cmp_eq");
let structural_eq = structural_eq.unwrap_or_else(|| {
quote_spanned! {span=>
true
}
});
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
#cmp_eq_where_clause
{
const TRY_STRUCTURAL_EQ: ::fayalite::__std::primitive::bool = #structural_eq;
#[track_caller]
fn cmp_value_eq(
__lhs: Self,
__lhs_value: ::fayalite::__std::borrow::Cow<'_,
<Self as ::fayalite::ty::Type>::SimValue>,
__rhs: Self,
__rhs_value: ::fayalite::__std::borrow::Cow<'_,
<Self as ::fayalite::ty::Type>::SimValue>,
) -> ::fayalite::__std::primitive::bool {
match (&*__lhs_value, &*__rhs_value) {
#(#variants_value_eq)*
_ => false,
}
}
#[track_caller]
fn cmp_expr_eq(
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
if <Self as ::fayalite::expr::HdlPartialEqImpl<Self>>::TRY_STRUCTURAL_EQ {
if let ::fayalite::__std::result::Result::Ok(__retval) =
::fayalite::expr::ops::StructuralEq::try_new(
::fayalite::expr::Expr::canonical(__lhs),
::fayalite::expr::Expr::canonical(__rhs),
)
{
return ::fayalite::expr::ToExpr::to_expr(&__retval);
}
}
let __retval = ::fayalite::module::wire(
::fayalite::module::ImplicitName(#cmp_expr_eq_wire_name),
::fayalite::int::Bool,
);
::fayalite::module::connect(__retval, false);
let mut __lhs_match_variant_iter = ::fayalite::module::match_(__lhs);
#(#variants_expr_eq)*
__retval
}
#[track_caller]
fn cmp_valueless_eq(
__lhs: ::fayalite::expr::Valueless<Self>,
__rhs: ::fayalite::expr::Valueless<Self>,
) -> ::fayalite::expr::Valueless<::fayalite::int::Bool> {
#valueless_eq_body
}
}
}
.to_tokens(tokens);
}
let variants_len = variants.len();
quote_spanned! {span=>
#[automatically_derived]
@ -849,7 +1164,8 @@ impl ToTokens for ParsedEnum {
type SimValue = #sim_value_ident #type_generics;
type MatchVariant = #match_variant_ident #type_generics;
type MatchActiveScope = ::fayalite::module::Scope;
type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
type MatchVariantAndInactiveScope =
::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
fn match_variants(
@ -862,7 +1178,9 @@ impl ToTokens for ParsedEnum {
::fayalite::int::Bool
}
fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType {
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(#self_token)))
::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(
::fayalite::enum_::EnumType::variants(#self_token),
))
}
#[track_caller]
#[allow(non_snake_case)]
@ -871,7 +1189,11 @@ impl ToTokens for ParsedEnum {
::fayalite::__std::panic!("expected enum");
};
let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_);
::fayalite::__std::assert_eq!(#variants_token.len(), #variants_len, "enum has wrong number of variants");
::fayalite::__std::assert_eq!(
#variants_token.len(),
#variants_len,
"enum has wrong number of variants",
);
Self {
#(#from_canonical_body_fields)*
}
@ -917,7 +1239,10 @@ impl ToTokens for ParsedEnum {
type SimBuilder = #sim_builder_ident #type_generics;
fn match_activate_scope(
v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) {
) -> (
<Self as ::fayalite::ty::Type>::MatchVariant,
<Self as ::fayalite::ty::Type>::MatchActiveScope,
) {
let (#variant_access_token, scope) = v.activate();
(
match #variant_access_token.variant_index() {
@ -934,6 +1259,17 @@ impl ToTokens for ParsedEnum {
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::__std::fmt::Debug for #sim_value_ident #type_generics
#where_clause
{
fn fmt(
&self,
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
) -> ::fayalite::__std::fmt::Result {
<#target #type_generics as ::fayalite::ty::SimValueDebug>::sim_value_debug(self, f)
}
}
#[automatically_derived]
impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics>
for #sim_value_ident #type_generics
#where_clause
@ -942,7 +1278,10 @@ impl ToTokens for ParsedEnum {
&self,
ty: #target #type_generics,
) -> ::fayalite::sim::value::SimValue<#target #type_generics> {
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
::fayalite::sim::value::SimValue::from_value(
ty,
::fayalite::__std::clone::Clone::clone(self),
)
}
fn into_sim_value_with_type(
self,

View file

@ -215,6 +215,8 @@ impl ParsedTypeAlias {
no_runtime_generics,
cmp_eq,
get: _,
ref custom_debug,
custom_sim_display,
} = options.body;
if let Some((no_static,)) = no_static {
errors.error(no_static, "no_static is not valid on type aliases");
@ -234,6 +236,15 @@ impl ParsedTypeAlias {
if let Some((cmp_eq,)) = cmp_eq {
errors.error(cmp_eq, "cmp_eq is not valid on type aliases");
}
if let Some((custom_debug, _, _)) = custom_debug {
errors.error(custom_debug, "custom_debug is not valid on type aliases");
}
if let Some((custom_sim_display,)) = custom_sim_display {
errors.error(
custom_sim_display,
"custom_sim_display is not valid on type aliases",
);
}
if let Some((custom_bounds,)) = custom_bounds {
errors.error(
custom_bounds,
@ -287,6 +298,8 @@ impl ParsedTypeAlias {
no_runtime_generics: _,
cmp_eq,
ref mut get,
ref custom_debug,
custom_sim_display,
} = options.body;
if let Some(get) = get.take() {
return Self::parse_phantom_const_accessor(
@ -311,6 +324,15 @@ impl ParsedTypeAlias {
if let Some((cmp_eq,)) = cmp_eq {
errors.error(cmp_eq, "cmp_eq is not valid on type aliases");
}
if let Some((custom_debug, _, _)) = custom_debug {
errors.error(custom_debug, "custom_debug is not valid on type aliases");
}
if let Some((custom_sim_display,)) = custom_sim_display {
errors.error(
custom_sim_display,
"custom_sim_display is not valid on type aliases",
);
}
let generics = if custom_bounds.is_some() {
MaybeParsed::Unrecognized(generics)
} else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) {
@ -356,6 +378,8 @@ impl ToTokens for ParsedTypeAlias {
no_runtime_generics,
cmp_eq: _,
get: _,
custom_debug: _,
custom_sim_display: _,
} = &options.body;
let target = get_target(target, ident);
let mut type_attrs = attrs.clone();
@ -402,6 +426,8 @@ impl ToTokens for ParsedTypeAlias {
no_runtime_generics: _,
cmp_eq: _,
get: _,
custom_debug: _,
custom_sim_display: _,
} = &options.body;
let span = ident.span();
let mut type_attrs = attrs.clone();
@ -427,7 +453,7 @@ impl ToTokens for ParsedTypeAlias {
format_ident!("__{}__GenericsAccumulation", ident);
ItemStruct {
attrs: vec![
common_derives(span),
common_derives(span, true),
parse_quote_spanned! {span=>
#[allow(non_camel_case_types)]
},

View file

@ -7,10 +7,10 @@ use std::{collections::HashMap, fmt, mem};
use syn::{
AngleBracketedGenericArguments, Attribute, Block, ConstParam, Expr, ExprBlock, ExprGroup,
ExprIndex, ExprParen, ExprPath, ExprTuple, Field, FieldMutability, Fields, FieldsNamed,
FieldsUnnamed, GenericArgument, GenericParam, Generics, Ident, ImplGenerics, Index, ItemStruct,
Path, PathArguments, PathSegment, PredicateType, QSelf, Stmt, Token, TraitBound, Turbofish,
Type, TypeGenerics, TypeGroup, TypeParam, TypeParamBound, TypeParen, TypePath, TypeTuple,
Visibility, WhereClause, WherePredicate,
FieldsUnnamed, FnArg, GenericArgument, GenericParam, Generics, Ident, ImplGenerics, Index,
ItemStruct, Path, PathArguments, PathSegment, PredicateType, QSelf, Stmt, Token, TraitBound,
Turbofish, Type, TypeGenerics, TypeGroup, TypeParam, TypeParamBound, TypeParen, TypePath,
TypeTuple, Visibility, WhereClause, WherePredicate,
parse::{Parse, ParseStream},
parse_quote, parse_quote_spanned,
punctuated::{Pair, Punctuated},
@ -18,6 +18,17 @@ use syn::{
token::{Brace, Bracket, Paren},
};
crate::options! {
#[options = CustomDebugOptions]
#[no_ident_fragment]
pub(crate) enum CustomDebugOption {
Type(type_),
Sim(sim),
MaskType(mask_type),
MaskSim(mask_sim),
}
}
crate::options! {
#[options = ItemOptions]
pub(crate) enum ItemOption {
@ -28,6 +39,8 @@ crate::options! {
NoRuntimeGenerics(no_runtime_generics),
CmpEq(cmp_eq),
Get(get, Expr),
CustomDebug(custom_debug, CustomDebugOptions),
CustomSimDisplay(custom_sim_display),
}
}
@ -41,8 +54,36 @@ impl ItemOptions {
{
self.no_static = Some((kw::no_static(custom_bounds.span),));
}
if let Some((kw, _, custom_debug)) = &mut self.custom_debug {
if let CustomDebugOptions {
type_: None,
sim: None,
mask_type: None,
mask_sim: None,
} = custom_debug
{
*custom_debug = CustomDebugOptions {
type_: Some((kw::type_(kw.span),)),
sim: Some((kw::sim(kw.span),)),
mask_type: None,
mask_sim: None,
};
}
}
Ok(())
}
pub(crate) fn custom_debug(&self) -> &CustomDebugOptions {
self.custom_debug.as_ref().map(|v| &v.2).unwrap_or(
const {
&CustomDebugOptions {
type_: None,
sim: None,
mask_type: None,
mask_sim: None,
}
},
)
}
}
pub(crate) struct WrappedInConst<'a> {
@ -84,10 +125,17 @@ pub(crate) fn get_target(target: &Option<(kw::target, Paren, Path)>, item_ident:
}
}
pub(crate) fn common_derives(span: Span) -> Attribute {
pub(crate) fn common_derives(span: Span, include_debug: bool) -> Attribute {
let debug = include_debug
.then(|| {
quote_spanned! {span=>
::fayalite::__std::fmt::Debug
}
})
.into_iter();
parse_quote_spanned! {span=>
#[::fayalite::__std::prelude::v1::derive(
::fayalite::__std::fmt::Debug,
#(#debug,)*
::fayalite::__std::cmp::Eq,
::fayalite::__std::cmp::PartialEq,
::fayalite::__std::hash::Hash,
@ -2975,7 +3023,7 @@ impl ParsedGenerics {
let span = ident.span();
ItemStruct {
attrs: vec![
common_derives(span),
common_derives(span, true),
parse_quote_spanned! {span=>
#[allow(non_camel_case_types)]
},
@ -4733,3 +4781,109 @@ impl ParsedVisibility {
.map(|ord| if ord.is_lt() { self } else { other })
}
}
pub(crate) struct CustomDebugTrait<'a> {
pub(crate) trait_path: &'a Path,
pub(crate) fn_name: &'a Ident,
pub(crate) this_arg: &'a FnArg,
}
#[must_use]
pub(crate) fn create_struct_debug_impl(
item_struct: &ItemStruct,
debug_struct_name: &str,
custom_debug_trait: Option<CustomDebugTrait<'_>>,
) -> TokenStream {
let ident = &item_struct.ident;
let span = ident.span();
let (impl_generics, type_generics, where_clause) = item_struct.generics.split_for_impl();
let trait_path;
let fn_name;
let this_arg;
let CustomDebugTrait {
trait_path,
fn_name,
this_arg,
} = match custom_debug_trait {
Some(v) => v,
None => {
trait_path = parse_quote_spanned! {span=>
::fayalite::__std::fmt::Debug
};
fn_name = parse_quote_spanned! {span=>
fmt
};
this_arg = parse_quote_spanned! {span=>
&self
};
CustomDebugTrait {
trait_path: &trait_path,
fn_name: &fn_name,
this_arg: &this_arg,
}
}
};
let this_arg_name = match this_arg {
FnArg::Receiver(this_arg) => this_arg.self_token.to_token_stream(),
FnArg::Typed(this_arg) => match &*this_arg.pat {
syn::Pat::Ident(pat_ident) => pat_ident.ident.to_token_stream(),
_ => unreachable!(),
},
};
match &item_struct.fields {
Fields::Named(fields) => {
let field_idents = fields
.named
.iter()
.map(|v| v.ident.as_ref().expect("known to have field name"));
let field_names = field_idents.clone().map(|v| v.to_string());
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics #trait_path for #ident #type_generics
#where_clause
{
fn #fn_name(#this_arg, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
let _ = #this_arg_name;
f.debug_struct(#debug_struct_name)
#(.field(#field_names, &#this_arg_name.#field_idents))*
.finish()
}
}
}
}
Fields::Unnamed(fields) => {
let field_members = fields
.unnamed
.iter()
.enumerate()
.map(|(index, _)| syn::Index {
index: index as _,
span,
});
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics #trait_path for #ident #type_generics
#where_clause
{
fn #fn_name(#this_arg, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
let _ = #this_arg_name;
f.debug_tuple(#debug_struct_name)
#(.field(&#this_arg_name.#field_members))*
.finish()
}
}
}
}
Fields::Unit => quote_spanned! {ident.span()=>
#[automatically_derived]
impl #impl_generics #trait_path for #ident #type_generics
#where_clause
{
fn #fn_name(#this_arg, f: &mut ::fayalite::__std::fmt::Formatter<'_>) -> ::fayalite::__std::fmt::Result {
let _ = #this_arg_name;
f.write_str(#debug_struct_name)
}
}
},
}
}

View file

@ -42,6 +42,7 @@ pub(crate) trait CustomToken:
mod kw {
pub(crate) use syn::token::Extern as extern_;
pub(crate) use syn::token::Type as type_;
macro_rules! custom_keyword {
($kw:ident) => {
@ -75,6 +76,8 @@ mod kw {
custom_keyword!(cmp_eq);
custom_keyword!(connect_inexact);
custom_keyword!(custom_bounds);
custom_keyword!(custom_debug);
custom_keyword!(custom_sim_display);
custom_keyword!(flip);
custom_keyword!(get);
custom_keyword!(hdl);
@ -83,6 +86,8 @@ mod kw {
custom_keyword!(input);
custom_keyword!(instance);
custom_keyword!(m);
custom_keyword!(mask_sim);
custom_keyword!(mask_type);
custom_keyword!(memory);
custom_keyword!(memory_array);
custom_keyword!(memory_with_init);

View file

@ -1096,11 +1096,9 @@ impl Visitor<'_> {
let (#(#bindings,)*) = {
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
let __match_value = #expr;
let __match_value = {
use ::fayalite::sim::value::match_sim_value::*;
// use method syntax to deduce the correct trait to call
::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value).__fayalite_match_sim_value()
};
// use method syntax to deduce what type to convert to
let __match_value = ::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value)
.__fayalite_match_sim_value();
#let_token #pat #eq_token __match_value #semi_token
(#(#bindings_idents,)*)
};
@ -1172,11 +1170,9 @@ impl Visitor<'_> {
{
type __MatchTy<T> = <T as ::fayalite::ty::Type>::SimValue;
let __match_value = #expr;
let __match_value = {
use ::fayalite::sim::value::match_sim_value::*;
// use method syntax to deduce the correct trait to call
::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value).__fayalite_match_sim_value()
};
// use method syntax to deduce what type to convert to
let __match_value = ::fayalite::sim::value::match_sim_value::MatchSimValueHelper::new(__match_value)
.__fayalite_match_sim_value();
#match_token __match_value {
#(#arms)*
}

View file

@ -95,7 +95,23 @@
//! }
//!
//! #[hdl]
//! fn destructure_to_sim_value<'a, T: Type>(v: impl ToSimValue<Type = MyStruct<T>>) {
//! fn destructure_inner<T: Type>(v: <MyStruct<T> as Type>::SimValue) {
//! #[hdl(sim)]
//! let MyStruct::<T> {
//! a,
//! mut b,
//! c,
//! } = v;
//!
//! // that gives these types:
//! let _: SimValue<UInt<8>> = a;
//! let _: SimValue<Bool> = b;
//! let _: SimValue<T> = c;
//! *b = false; // can modify b since mut was used
//! }
//!
//! #[hdl]
//! fn destructure_inner_ref<'a, T: Type>(v: &'a <MyStruct<T> as Type>::SimValue) {
//! #[hdl(sim)]
//! let MyStruct::<T> {
//! a,
@ -104,8 +120,25 @@
//! } = v;
//!
//! // that gives these types:
//! let _: SimValue<UInt<8>> = a;
//! let _: SimValue<Bool> = b;
//! let _: SimValue<T> = c;
//! let _: &'a SimValue<UInt<8>> = a;
//! let _: &'a SimValue<Bool> = b;
//! let _: &'a SimValue<T> = c;
//! }
//!
//! #[hdl]
//! fn destructure_inner_mut<'a, T: Type>(v: &'a mut <MyStruct<T> as Type>::SimValue) {
//! #[hdl(sim)]
//! let MyStruct::<T> {
//! a,
//! b,
//! c,
//! } = v;
//!
//! **b = true; // you can modify v by modifying b which borrows from it
//!
//! // that gives these types:
//! let _: &'a mut SimValue<UInt<8>> = a;
//! let _: &'a mut SimValue<Bool> = b;
//! let _: &'a mut SimValue<T> = c;
//! }
//! ```

View file

@ -72,15 +72,47 @@
//! }
//!
//! #[hdl]
//! fn match_to_sim_value<'a, T: Type>(v: impl ToSimValue<Type = MyEnum<T>>) {
//! fn match_inner_move<T: Type>(v: <MyEnum<T> as Type>::SimValue) -> String {
//! #[hdl(sim)]
//! match v {
//! MyEnum::<T>::A => println!("got A"),
//! MyEnum::<T>::B(b) => {
//! MyEnum::<T>::A => String::from("got A"),
//! MyEnum::<T>::B(mut b) => {
//! let _: SimValue<Bool> = b; // b has this type
//! println!("got B({b})");
//! let text = format!("got B({b})");
//! *b = true; // can modify b since mut was used
//! text
//! }
//! _ => println!("something else"),
//! _ => String::from("something else"),
//! }
//! }
//!
//! #[hdl]
//! fn match_inner_ref<'a, T: Type>(v: &'a <MyEnum<T> as Type>::SimValue) -> u32 {
//! #[hdl(sim)]
//! match v {
//! MyEnum::<T>::A => 1,
//! MyEnum::<T>::B(b) => {
//! let _: &'a SimValue<Bool> = b; // b has this type
//! println!("got B({b})");
//! 5
//! }
//! _ => 42,
//! }
//! }
//!
//! #[hdl]
//! fn match_inner_mut<'a, T: Type>(v: &'a mut <MyEnum<T> as Type>::SimValue) -> Option<&'a mut SimValue<T>> {
//! #[hdl(sim)]
//! match v {
//! MyEnum::<T>::A => None,
//! MyEnum::<T>::B(b) => {
//! println!("got B({b})");
//! **b = true; // you can modify v by modifying b which borrows from it
//! let _: &'a mut SimValue<Bool> = b; // b has this type
//! None
//! }
//! MyEnum::<T>::C(v) => Some(v), // you can return matched values
//! _ => None, // HDL enums can have invalid discriminants, so we need this extra match arm
//! }
//! }
//! ```

View file

@ -238,7 +238,10 @@ impl TargetedAnnotation {
}
#[track_caller]
pub fn assert_valid_target(target: Interned<Target>) {
assert!(target.is_static(), "can't annotate non-static targets");
assert!(
target.is_valid_annotation_target(),
"not a valid annotation target: {target:?}",
);
}
pub fn target(&self) -> Interned<Target> {
self.target

View file

@ -4,7 +4,7 @@
use crate::{
expr::{
CastToBits, Expr, HdlPartialEq, HdlPartialEqImpl, ReduceBits, ToExpr, ValueType, Valueless,
ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator},
ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator, StructuralEq},
},
int::{Bool, DYN_SIZE, DynSize, KnownSize, Size, SizeType},
intern::{Intern, Interned, LazyInterned},
@ -13,13 +13,13 @@ use crate::{
source_location::SourceLocation,
ty::{
CanonicalType, MatchVariantWithoutScope, OpaqueSimValueSlice, OpaqueSimValueWriter,
OpaqueSimValueWritten, StaticType, Type, TypeProperties, TypeWithDeref,
OpaqueSimValueWritten, SimValueDebug, StaticType, Type, TypeProperties, TypeWithDeref,
serde_impls::SerdeCanonicalType,
},
util::ConstUsize,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
use std::{borrow::Cow, iter::FusedIterator, ops::Index};
use std::{borrow::Cow, fmt, iter::FusedIterator, ops::Index};
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ArrayType<T: Type = CanonicalType, Len: Size = DynSize> {
@ -28,8 +28,8 @@ pub struct ArrayType<T: Type = CanonicalType, Len: Size = DynSize> {
type_properties: TypeProperties,
}
impl<T: Type, Len: Size> std::fmt::Debug for ArrayType<T, Len> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl<T: Type, Len: Size> fmt::Debug for ArrayType<T, Len> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Array<{:?}, {}>", self.element, self.len())
}
}
@ -182,6 +182,15 @@ impl<T: Type + Visit<State>, Len: Size, State: Visitor + ?Sized> Visit<State>
}
}
impl<T: Type, Len: Size> SimValueDebug for ArrayType<T, Len> {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
type BaseType = Array;
type MaskType = ArrayType<T::MaskType, Len>;
@ -358,6 +367,8 @@ impl<Lhs: Type, Rhs: Type, Len: Size> HdlPartialEqImpl<ArrayType<Rhs, Len>> for
where
Lhs: HdlPartialEqImpl<Rhs>,
{
const TRY_STRUCTURAL_EQ: bool = <Lhs as HdlPartialEqImpl<Rhs>>::TRY_STRUCTURAL_EQ;
fn cmp_value_eq(
lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
@ -378,6 +389,11 @@ where
}
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
assert_eq!(lhs.ty().len(), rhs.ty().len());
if Self::TRY_STRUCTURAL_EQ {
if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) {
return retval.to_expr();
}
}
lhs.into_iter()
.zip(rhs)
.map(|(l, r)| l.cmp_eq(r))
@ -387,6 +403,11 @@ where
}
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
assert_eq!(lhs.ty().len(), rhs.ty().len());
if Self::TRY_STRUCTURAL_EQ {
if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) {
return !retval.to_expr();
}
}
lhs.into_iter()
.zip(rhs)
.map(|(l, r)| l.cmp_ne(r))

View file

@ -12,7 +12,7 @@ use crate::{
use eyre::{ContextCompat, eyre};
use petgraph::{
algo::{DfsSpace, kosaraju_scc, toposort},
graph::DiGraph,
graph::{DiGraph, NodeIndex},
visit::{GraphBase, Visitable},
};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error, ser::SerializeSeq};
@ -465,7 +465,7 @@ impl JobGraph {
}
})
.expect("we know there's a cycle");
let cycle_set = HashSet::from_iter(cycle.iter().copied());
let cycle_set = HashSet::<NodeIndex>::from_iter(cycle.iter().copied());
let job = cycle
.into_iter()
.find_map(|node_id| {
@ -701,7 +701,7 @@ impl JobGraph {
job: DynJob,
thread: ScopedJoinHandle<'scope, eyre::Result<Vec<JobItem>>>,
}
let mut running_jobs = HashMap::default();
let mut running_jobs = HashMap::<NodeIndex, RunningJob>::default();
let (finished_jobs_sender, finished_jobs_receiver) = mpsc::channel();
let mut next_finished_job = None;
loop {

View file

@ -211,7 +211,7 @@ impl ExternalCommand for UnadjustedVerilog {
args.write_arg("-o");
args.write_interned_arg(unadjusted_verilog_file_name);
if verilog_debug {
args.write_args(["-g", "--preserve-values=all"]);
args.write_args(["-g", "--preserve-values=named"]);
}
if let Some(dialect) = verilog_dialect {
args.write_args(dialect.firtool_extra_args().iter().copied());

View file

@ -5,7 +5,7 @@ use crate::{
expr::{
CastToBits, Expr, HdlPartialEqImpl, ReduceBits, ToExpr, ToSimValueInner, ValueType,
Valueless,
ops::{ArrayLiteral, BundleLiteral},
ops::{ArrayLiteral, BundleLiteral, StructuralEq},
value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue},
},
int::{Bool, DynSize},
@ -14,8 +14,8 @@ use crate::{
source_location::SourceLocation,
ty::{
CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, OpaqueSimValueSize,
OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type,
TypeProperties, TypeWithDeref, impl_match_variant_as_self,
OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, SimValueDebug,
StaticType, Type, TypeProperties, TypeWithDeref, impl_match_variant_as_self,
},
util::HashMap,
};
@ -271,6 +271,15 @@ impl Type for Bundle {
}
}
impl SimValueDebug for Bundle {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
pub trait BundleType: Type<BaseType = Bundle> {
type Builder: Default;
fn fields(&self) -> Interned<[BundleField]>;
@ -471,6 +480,14 @@ macro_rules! impl_tuples {
#[var($var)]
})*]
}
impl<$($T: Type,)*> SimValueDebug for ($($T,)*) {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl<$($T: Type,)*> Type for ($($T,)*) {
type BaseType = Bundle;
type MaskType = ($($T::MaskType,)*);
@ -691,6 +708,8 @@ macro_rules! impl_tuples {
}
}
impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) {
const TRY_STRUCTURAL_EQ: bool = true $(&& <$Lhs as HdlPartialEqImpl<$Rhs>>::TRY_STRUCTURAL_EQ)*;
#[track_caller]
fn cmp_value_eq(
lhs: Self,
@ -708,6 +727,11 @@ macro_rules! impl_tuples {
#[track_caller]
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
if Self::TRY_STRUCTURAL_EQ {
if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) {
return retval.to_expr();
}
}
let ($($lhs_var,)*) = *lhs;
let ($($rhs_var,)*) = *rhs;
ArrayLiteral::<Bool, DynSize>::new(
@ -720,6 +744,11 @@ macro_rules! impl_tuples {
#[track_caller]
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
if Self::TRY_STRUCTURAL_EQ {
if let Ok(retval) = StructuralEq::try_new(Expr::canonical(lhs), Expr::canonical(rhs)) {
return !retval.to_expr();
}
}
let ($($lhs_var,)*) = *lhs;
let ($($rhs_var,)*) = *rhs;
ArrayLiteral::<Bool, DynSize>::new(
@ -773,6 +802,15 @@ impl_tuples! {
]
}
impl<T: ?Sized + Send + Sync + 'static> SimValueDebug for PhantomData<T> {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> {
type BaseType = Bundle;
type MaskType = ();

View file

@ -1,5 +1,6 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
expr::{Expr, ValueType},
hdl,
@ -9,10 +10,12 @@ use crate::{
source_location::SourceLocation,
ty::{
CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter,
OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self,
OpaqueSimValueWritten, SimValueDebug, StaticType, Type, TypeProperties,
impl_match_variant_as_self,
},
};
use bitvec::{bits, order::Lsb0};
use std::fmt;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct Clock;
@ -69,6 +72,15 @@ impl Type for Clock {
}
}
impl SimValueDebug for Clock {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl Clock {
pub fn type_properties(self) -> TypeProperties {
Self::TYPE_PROPERTIES

View file

@ -2,7 +2,7 @@
// See Notices.txt for copyright information
use crate::{
expr::{Expr, HdlPartialEq, HdlPartialEqImpl, ToExpr, ValueType, ops::VariantAccess},
expr::{Expr, ToExpr, ValueType, ops::VariantAccess},
hdl,
int::{Bool, UIntValue},
intern::{Intern, Interned},
@ -10,18 +10,18 @@ use crate::{
EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, Scope, connect,
enum_match_variants_helper, incomplete_wire, wire,
},
sim::value::SimValue,
sim::value::{SimValue, ToSimValue, ToSimValueWithType},
source_location::SourceLocation,
ty::{
CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, OpaqueSimValueSize,
OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type,
TypeProperties,
OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, SimValueDebug,
StaticType, Type, TypeProperties,
},
util::HashMap,
};
use bitvec::{order::Lsb0, slice::BitSlice, view::BitView};
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, convert::Infallible, fmt, iter::FusedIterator, sync::Arc};
use std::{convert::Infallible, fmt, iter::FusedIterator, sync::Arc};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct EnumVariant {
@ -410,6 +410,15 @@ impl Type for Enum {
}
}
impl SimValueDebug for Enum {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct EnumPaddingSimValue {
bits: Option<UIntValue>,
@ -723,95 +732,12 @@ pub fn enum_type_to_sim_builder<T: EnumType>(v: T) -> T::SimBuilder {
v.into()
}
#[hdl]
#[hdl(cmp_eq)]
pub enum HdlOption<T: Type> {
HdlNone,
HdlSome(T),
}
impl<Lhs: Type + HdlPartialEqImpl<Rhs>, Rhs: Type> HdlPartialEqImpl<HdlOption<Rhs>>
for HdlOption<Lhs>
{
fn cmp_value_eq(
lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
rhs: HdlOption<Rhs>,
rhs_value: Cow<'_, <HdlOption<Rhs> as Type>::SimValue>,
) -> bool {
type SimValueMatch<T> = <T as Type>::SimValue;
match (&*lhs_value, &*rhs_value) {
(SimValueMatch::<Self>::HdlNone(_), SimValueMatch::<HdlOption<Rhs>>::HdlNone(_)) => {
true
}
(SimValueMatch::<Self>::HdlSome(..), SimValueMatch::<HdlOption<Rhs>>::HdlNone(_))
| (SimValueMatch::<Self>::HdlNone(_), SimValueMatch::<HdlOption<Rhs>>::HdlSome(..)) => {
false
}
(
SimValueMatch::<Self>::HdlSome(l, _),
SimValueMatch::<HdlOption<Rhs>>::HdlSome(r, _),
) => HdlPartialEqImpl::cmp_value_eq(
lhs.HdlSome,
Cow::Borrowed(&**l),
rhs.HdlSome,
Cow::Borrowed(&**r),
),
}
}
#[hdl]
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<HdlOption<Rhs>>) -> Expr<Bool> {
#[hdl]
let cmp_eq = wire();
#[hdl]
match lhs {
HdlSome(lhs) =>
{
#[hdl]
match rhs {
HdlSome(rhs) => connect(cmp_eq, lhs.cmp_eq(rhs)),
HdlNone => connect(cmp_eq, false),
}
}
HdlNone =>
{
#[hdl]
match rhs {
HdlSome(_) => connect(cmp_eq, false),
HdlNone => connect(cmp_eq, true),
}
}
}
cmp_eq
}
#[hdl]
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<HdlOption<Rhs>>) -> Expr<Bool> {
#[hdl]
let cmp_ne = wire();
#[hdl]
match lhs {
HdlSome(lhs) =>
{
#[hdl]
match rhs {
HdlSome(rhs) => connect(cmp_ne, lhs.cmp_ne(rhs)),
HdlNone => connect(cmp_ne, true),
}
}
HdlNone =>
{
#[hdl]
match rhs {
HdlSome(_) => connect(cmp_ne, true),
HdlNone => connect(cmp_ne, false),
}
}
}
cmp_ne
}
}
#[allow(non_snake_case)]
pub fn HdlNone<T: StaticType>() -> Expr<HdlOption<T>> {
HdlOption[T::TYPE].HdlNone()
@ -823,6 +749,123 @@ pub fn HdlSome<T: Type>(value: impl ToExpr<Type = T>) -> Expr<HdlOption<T>> {
HdlOption[value.ty()].HdlSome(value)
}
impl<T: Type> From<SimValue<HdlOption<T>>> for Option<SimValue<T>> {
#[hdl]
fn from(value: SimValue<HdlOption<T>>) -> Self {
#[hdl(sim)]
match value {
HdlSome(v) => Some(v),
HdlNone => None,
}
}
}
impl<'a, T: Type> From<&'a SimValue<HdlOption<T>>> for Option<&'a SimValue<T>> {
#[hdl]
fn from(value: &'a SimValue<HdlOption<T>>) -> Self {
#[hdl(sim)]
match value {
HdlSome(v) => Some(v),
HdlNone => None,
}
}
}
impl<'a, T: Type> From<&'a mut SimValue<HdlOption<T>>> for Option<&'a mut SimValue<T>> {
#[hdl]
fn from(value: &'a mut SimValue<HdlOption<T>>) -> Self {
#[hdl(sim)]
match value {
HdlSome(v) => Some(v),
HdlNone => None,
}
}
}
impl<T: ValueType<Type: StaticType<MaskType: StaticType>>> ValueType for Option<T> {
type Type = HdlOption<T::Type>;
type ValueCategory = T::ValueCategory;
fn ty(&self) -> Self::Type {
StaticType::TYPE
}
}
impl<T: Type, V: ToSimValueWithType<T>> ToSimValueWithType<HdlOption<T>> for Option<V> {
#[hdl]
fn to_sim_value_with_type(&self, ty: HdlOption<T>) -> SimValue<HdlOption<T>> {
match self {
Some(v) =>
{
#[hdl(sim)]
ty.HdlSome(v)
}
None =>
{
#[hdl(sim)]
ty.HdlNone()
}
}
}
#[hdl]
fn into_sim_value_with_type(self, ty: HdlOption<T>) -> SimValue<HdlOption<T>> {
match self {
Some(v) =>
{
#[hdl(sim)]
ty.HdlSome(v)
}
None =>
{
#[hdl(sim)]
ty.HdlNone()
}
}
}
}
impl<T: ToSimValue<Type: StaticType<MaskType: StaticType>>> ToSimValue for Option<T> {
#[hdl]
fn to_sim_value(&self) -> SimValue<Self::Type> {
match self {
Some(v) =>
{
#[hdl(sim)]
HdlSome(v)
}
None =>
{
#[hdl(sim)]
HdlNone()
}
}
}
#[hdl]
fn into_sim_value(self) -> SimValue<Self::Type> {
match self {
Some(v) =>
{
#[hdl(sim)]
HdlSome(v)
}
None =>
{
#[hdl(sim)]
HdlNone()
}
}
}
}
impl<T: ToExpr<Type: StaticType<MaskType: StaticType>>> ToExpr for Option<T> {
fn to_expr(&self) -> Expr<Self::Type> {
match self {
Some(v) => HdlSome(v),
None => HdlNone(),
}
}
}
impl<T: Type> HdlOption<T> {
#[track_caller]
pub fn try_map<R: Type, E>(

View file

@ -6,6 +6,7 @@ use crate::{
bundle::{Bundle, BundleType},
enum_::{Enum, EnumType},
expr::target::{GetTarget, Target},
formal::FormalInput,
int::{Bool, DynSize, IntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue},
intern::{Intern, Interned},
memory::{DynPortType, MemPort, PortType},
@ -17,7 +18,7 @@ use crate::{
reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
sim::value::{SimValue, ToSimValue, ToSimValueWithType},
ty::{CanonicalType, OpaqueSimValue, StaticType, Type, TypeWithDeref},
ty::{CanonicalType, OpaqueSimValue, StaticType, TraceAsString, Type, TypeWithDeref},
util::{ConstBool, ConstUsize},
wire::Wire,
};
@ -218,6 +219,9 @@ expr_enum! {
SliceSInt(ops::SliceSInt),
CastToBits(ops::CastToBits),
CastBitsTo(ops::CastBitsTo),
ToTraceAsString(ops::ToTraceAsString),
TraceAsStringAsInner(ops::TraceAsStringAsInner),
StructuralEq(ops::StructuralEq),
ModuleIO(ModuleIO<CanonicalType>),
Instance(Instance<Bundle>),
Wire(Wire<CanonicalType>),
@ -225,6 +229,8 @@ expr_enum! {
RegSync(Reg<CanonicalType, SyncReset>),
RegAsync(Reg<CanonicalType, AsyncReset>),
MemPort(MemPort<DynPortType>),
FormalInput(FormalInput),
SimIoForGlobal(ops::SimIoForGlobal),
}
}
@ -389,6 +395,35 @@ impl<T: Type> Expr<T> {
__flow: this.__flow,
}
}
#[track_caller]
pub fn as_trace_as_string(this: Self, ty: TraceAsString<T>) -> Expr<TraceAsString<T>> {
assert_eq!(this.ty(), ty.inner_ty());
ops::ToTraceAsString::new(Expr::canonical(this), ty).to_expr()
}
}
impl Expr<CanonicalType> {
pub fn unwrap_transparent_types(mut this: Self) -> Expr<CanonicalType> {
loop {
match this.ty() {
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
| CanonicalType::Array(_)
| CanonicalType::Enum(_)
| CanonicalType::Bundle(_)
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => return this,
CanonicalType::TraceAsString(_) => {
this = *Expr::<TraceAsString>::from_canonical(this);
}
}
}
}
}
impl<T: Type> ToLiteralBits for Expr<T> {
@ -667,6 +702,7 @@ macro_rules! impl_hdl_cmp {
impl_helper = $HdlCmpImplHelper:ident,
$(impl_helper_base = $HdlCmpImplHelperBase:ident,)?
impl_helper_sealed = $HdlCmpImplHelperSealed:ident,
$(try_structural_eq = $TRY_STRUCTURAL_EQ:ident,)?
]
$vis:vis trait $HdlCmp:ident<$Rhs:ident: ValueType>:
ValueType<Type: $HdlCmpImpl:ident<Rhs::Type> $(+ $HdlCmpImplBase:ident<Rhs::Type>)?> $(+ $HdlCmpBase:ident<Rhs>)?
@ -695,6 +731,8 @@ macro_rules! impl_hdl_cmp {
}
$vis trait $HdlCmpImpl<$Rhs: Type>: Type $(+ $HdlCmpImplBase<$Rhs>)? {
$(const $TRY_STRUCTURAL_EQ: bool;)?
$(#[track_caller]
fn $cmp_value_fn(
$cmp_value_lhs: Self,
@ -878,6 +916,7 @@ impl_hdl_cmp! {
#[
impl_helper = HdlPartialEqImplHelper,
impl_helper_sealed = HdlPartialEqImplHelperSealed,
try_structural_eq = TRY_STRUCTURAL_EQ,
]
pub trait HdlPartialEq<Rhs: ValueType>:
ValueType<Type: HdlPartialEqImpl<Rhs::Type> >
@ -1692,3 +1731,204 @@ impl<'a, T: Type> ToSimValueInner<'a> for &'a SimValue<T> {
Cow::Borrowed(&**this)
}
}
pub trait ToTraceAsString: ValueType {
type Output: ValueType<Type = TraceAsString<Self::Type>, ValueCategory = Self::ValueCategory>;
fn to_trace_as_string_with_ty(&self, ty: TraceAsString<Self::Type>) -> Self::Output;
fn into_trace_as_string_with_ty(self, ty: TraceAsString<Self::Type>) -> Self::Output
where
Self: Sized;
fn to_trace_as_string(&self) -> Self::Output;
fn into_trace_as_string(self) -> Self::Output
where
Self: Sized;
}
impl<
T: ?Sized
+ ValueType
+ ToTraceAsStringImpl<<Self as ValueType>::Type, <Self as ValueType>::ValueCategory>,
> ToTraceAsString for T
{
type Output = T::ImplOutput;
fn to_trace_as_string_with_ty(&self, ty: TraceAsString<Self::Type>) -> Self::Output {
Self::to_trace_as_string_with_ty_impl(self, ty)
}
fn into_trace_as_string_with_ty(self, ty: TraceAsString<Self::Type>) -> Self::Output
where
Self: Sized,
{
Self::into_trace_as_string_with_ty_impl(self, ty)
}
fn to_trace_as_string(&self) -> Self::Output {
Self::to_trace_as_string_impl(self)
}
fn into_trace_as_string(self) -> Self::Output
where
Self: Sized,
{
Self::into_trace_as_string_impl(self)
}
}
pub trait ToTraceAsStringImpl<Ty: Type, C: value_category::ValueCategory> {
type ImplOutput: ValueType<Type = TraceAsString<Ty>, ValueCategory = C>;
fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput;
fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput
where
Self: Sized;
fn to_trace_as_string_with_ty_impl(this: &Self, ty: TraceAsString<Ty>) -> Self::ImplOutput;
fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString<Ty>) -> Self::ImplOutput
where
Self: Sized;
}
impl<T: ?Sized + crate::sim::value::ToSimValue>
ToTraceAsStringImpl<T::Type, value_category::ValueCategoryValue> for T
{
type ImplOutput = crate::ty::TraceAsStringSimValue<T::Type>;
fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput {
crate::ty::TraceAsStringSimValue::new(this)
}
fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput
where
Self: Sized,
{
crate::ty::TraceAsStringSimValue::new(this)
}
fn to_trace_as_string_with_ty_impl(
this: &Self,
ty: TraceAsString<T::Type>,
) -> Self::ImplOutput {
crate::ty::TraceAsStringSimValue::new_with_ty(this, ty)
}
fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString<T::Type>) -> Self::ImplOutput
where
Self: Sized,
{
crate::ty::TraceAsStringSimValue::new_with_ty(this, ty)
}
}
impl<T: ?Sized + crate::sim::value::ToSimValue>
ToTraceAsStringImpl<T::Type, value_category::ValueCategorySimValue> for T
{
type ImplOutput = SimValue<TraceAsString<T::Type>>;
fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput {
crate::ty::TraceAsStringSimValue::new(this).into_sim_value()
}
fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput
where
Self: Sized,
{
crate::ty::TraceAsStringSimValue::new(this).into_sim_value()
}
fn to_trace_as_string_with_ty_impl(
this: &Self,
ty: TraceAsString<T::Type>,
) -> Self::ImplOutput {
crate::ty::TraceAsStringSimValue::new_with_ty(this, ty).into_sim_value()
}
fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString<T::Type>) -> Self::ImplOutput
where
Self: Sized,
{
crate::ty::TraceAsStringSimValue::new_with_ty(this, ty).into_sim_value()
}
}
impl<T: ?Sized + ToExpr> ToTraceAsStringImpl<T::Type, value_category::ValueCategoryExpr> for T {
type ImplOutput = Expr<TraceAsString<T::Type>>;
fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput {
let this = this.to_expr();
ops::ToTraceAsString::new(Expr::canonical(this), TraceAsString::new(this.ty())).to_expr()
}
fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput
where
Self: Sized,
{
let this = this.to_expr();
ops::ToTraceAsString::new(Expr::canonical(this), TraceAsString::new(this.ty())).to_expr()
}
fn to_trace_as_string_with_ty_impl(
this: &Self,
ty: TraceAsString<T::Type>,
) -> Self::ImplOutput {
let this = this.to_expr();
ops::ToTraceAsString::new(
Expr::canonical(this),
ty.with_new_inner_ty(this.ty().intern_sized()),
)
.to_expr()
}
fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString<T::Type>) -> Self::ImplOutput
where
Self: Sized,
{
let this = this.to_expr();
ops::ToTraceAsString::new(
Expr::canonical(this),
ty.with_new_inner_ty(this.ty().intern_sized()),
)
.to_expr()
}
}
impl<T: ?Sized + ValueType> ToTraceAsStringImpl<T::Type, value_category::ValueCategoryValueless>
for T
{
type ImplOutput = Valueless<TraceAsString<T::Type>>;
fn to_trace_as_string_impl(this: &Self) -> Self::ImplOutput {
Valueless::new(TraceAsString::new(this.ty()))
}
fn into_trace_as_string_impl(this: Self) -> Self::ImplOutput
where
Self: Sized,
{
Valueless::new(TraceAsString::new(this.ty()))
}
fn to_trace_as_string_with_ty_impl(
this: &Self,
ty: TraceAsString<T::Type>,
) -> Self::ImplOutput {
Valueless::new(ty.with_new_inner_ty(this.ty().intern_sized()))
}
fn into_trace_as_string_with_ty_impl(this: Self, ty: TraceAsString<T::Type>) -> Self::ImplOutput
where
Self: Sized,
{
Valueless::new(ty.with_new_inner_ty(this.ty().intern_sized()))
}
}
impl ToLiteralBits for FormalInput {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl ToExpr for FormalInput {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::FormalInput(*self).intern_sized(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}

View file

@ -12,22 +12,24 @@ use crate::{
ToExpr, ToLiteralBits, ToSimValueInner, ToValueless, ValueType, Valueless,
target::{
GetTarget, Target, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement,
TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString,
TargetPathTraceAsStringInner,
},
value_category::ValueCategoryExpr,
},
formal::FormalInput,
int::{
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
UIntType, UIntValue,
},
intern::{Intern, Interned},
intern::{Intern, Interned, MemoizeGeneric},
phantom_const::{PhantomConst, PhantomConstValue},
reset::{
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
ToSyncReset,
},
sim::value::{SimValue, ToSimValue},
ty::{CanonicalType, StaticType, Type},
ty::{CanonicalType, StaticType, TraceAsString, Type},
util::ConstUsize,
};
use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView};
@ -44,6 +46,9 @@ use std::{
},
};
#[cfg(test)]
mod test_ops_impls;
macro_rules! make_impls {
(
$([$($args:tt)*])?
@ -583,9 +588,6 @@ macro_rules! make_impls {
#[cfg(test)]
pub(crate) use make_impls;
#[cfg(test)]
mod test_ops_impls;
macro_rules! impl_simple_binary_op_trait {
(
[$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*),
@ -2982,6 +2984,7 @@ macro_rules! impl_compare_op {
#[to_dyn_type($lhs:ident => $dyn_lhs:expr, $rhs:ident => $dyn_rhs:expr)]
#[to_cmp_value($lhs_compare_value:ident => $lhs_compare_value_expr:expr, $rhs_compare_value:ident => $rhs_compare_value_expr:expr)]
#[type($Lhs:ty, $Rhs:ty)]
$(#[try_structural_eq = $TRY_STRUCTURAL_EQ:ident])?
#[trait($Trait:ident)]
$(
struct $name:ident;
@ -3043,6 +3046,7 @@ macro_rules! impl_compare_op {
})*
impl$(<$LhsWidth: Size, $RhsWidth: Size>)? $Trait<$Rhs> for $Lhs {
$(const $TRY_STRUCTURAL_EQ: bool = true;)?
$(fn $value_method(
_lhs: Self,
$lhs_compare_value: Cow<'_, <Self as Type>::SimValue>,
@ -3063,6 +3067,7 @@ impl_compare_op! {
#[to_dyn_type(lhs => lhs, rhs => rhs)]
#[to_cmp_value(lhs_value => &*lhs_value, rhs_value => &*rhs_value)]
#[type(Bool, Bool)]
#[try_structural_eq = TRY_STRUCTURAL_EQ]
#[trait(HdlPartialEqImpl)]
struct CmpEqB; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
struct CmpNeB; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
@ -3086,6 +3091,7 @@ impl_compare_op! {
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
#[type(UIntType<LhsWidth>, UIntType<RhsWidth>)]
#[try_structural_eq = TRY_STRUCTURAL_EQ]
#[trait(HdlPartialEqImpl)]
struct CmpEqU; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
struct CmpNeU; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
@ -3110,6 +3116,7 @@ impl_compare_op! {
#[to_dyn_type(lhs => Expr::as_dyn_int(lhs), rhs => Expr::as_dyn_int(rhs))]
#[to_cmp_value(lhs_value => &lhs_value.to_bigint(), rhs_value => &rhs_value.to_bigint())]
#[type(SIntType<LhsWidth>, SIntType<RhsWidth>)]
#[try_structural_eq = TRY_STRUCTURAL_EQ]
#[trait(HdlPartialEqImpl)]
struct CmpEqS; fn cmp_value_eq(); fn cmp_expr_eq(); PartialEq::eq();
struct CmpNeS; fn cmp_value_ne(); fn cmp_expr_ne(); PartialEq::ne();
@ -3131,6 +3138,8 @@ impl_compare_op! {
macro_rules! impl_compare_forwards_to_bool {
($ty:ident) => {
impl HdlPartialEqImpl<Self> for $ty {
const TRY_STRUCTURAL_EQ: bool = true;
#[track_caller]
fn cmp_value_eq(
_lhs: Self,
@ -4694,3 +4703,522 @@ impl<This: ExprFromIterator<A>, A> FromIterator<A> for Expr<This> {
This::expr_from_iter(iter)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ToTraceAsString<T: Type = CanonicalType> {
inner: Expr<CanonicalType>,
ty: TraceAsString<T>,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
target: Option<Interned<Target>>,
}
impl<T: Type> fmt::Debug for ToTraceAsString<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
inner,
ty: _,
literal_bits: _,
target: _,
} = self;
f.debug_struct("ToTraceAsString")
.field("inner", inner)
.finish_non_exhaustive()
}
}
impl<T: Type> ToTraceAsString<T> {
pub fn new(inner: Expr<CanonicalType>, ty: TraceAsString<T>) -> Self {
assert_eq!(inner.ty(), ty.inner_ty().canonical());
let literal_bits = inner.to_literal_bits();
let target = inner.target().map(|base| {
Intern::intern_sized(
base.join(TargetPathElement::intern_sized(
TargetPathToTraceAsString {
ty: ty.canonical_trace_as_string(),
}
.into(),
))
.canonicalized(),
)
});
Self {
inner,
ty,
literal_bits,
target,
}
}
pub fn inner(self) -> Expr<CanonicalType> {
self.inner
}
}
impl<T: Type> GetTarget for ToTraceAsString<T> {
fn target(&self) -> Option<Interned<Target>> {
self.target
}
}
impl<T: Type> ToLiteralBits for ToTraceAsString<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl<T: Type> ValueType for ToTraceAsString<T> {
type Type = TraceAsString<T>;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<T: Type> ToExpr for ToTraceAsString<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::ToTraceAsString(ToTraceAsString {
inner: self.inner,
ty: self.ty.canonical_trace_as_string(),
literal_bits: self.literal_bits,
target: self.target,
})
.intern(),
__ty: self.ty,
__flow: Expr::flow(self.inner),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct TraceAsStringAsInner<T: Type = CanonicalType> {
arg: Expr<TraceAsString<CanonicalType>>,
ty: T,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
target: Option<Interned<Target>>,
}
impl<T: Type> fmt::Debug for TraceAsStringAsInner<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
arg,
ty: _,
literal_bits: _,
target: _,
} = self;
f.debug_struct("TraceAsStringAsInner")
.field("arg", arg)
.finish_non_exhaustive()
}
}
impl<T: Type> TraceAsStringAsInner<T> {
pub fn from_arg_and_ty(arg: Expr<TraceAsString<CanonicalType>>, ty: T) -> Self {
assert_eq!(arg.ty().inner_ty(), ty.canonical());
let literal_bits = arg.to_literal_bits();
let target = arg.target().map(|base| {
Intern::intern_sized(
base.join(TargetPathElement::intern_sized(
TargetPathTraceAsStringInner {}.into(),
))
.canonicalized(),
)
});
Self {
arg,
ty,
literal_bits,
target,
}
}
pub fn new(arg: Expr<TraceAsString<T>>) -> Self {
Self::from_arg_and_ty(
Expr {
__enum: arg.__enum,
__ty: arg.__ty.canonical_trace_as_string(),
__flow: arg.__flow,
},
arg.ty().inner_ty(),
)
}
pub fn arg(self) -> Expr<TraceAsString<CanonicalType>> {
self.arg
}
pub fn arg_typed(self) -> Expr<TraceAsString<T>> {
Expr {
__enum: self.arg.__enum,
__ty: TraceAsString::from_canonical_trace_as_string(self.arg.__ty),
__flow: self.arg.__flow,
}
}
}
impl<T: Type> GetTarget for TraceAsStringAsInner<T> {
fn target(&self) -> Option<Interned<Target>> {
self.target
}
}
impl<T: Type> ToLiteralBits for TraceAsStringAsInner<T> {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl<T: Type> ValueType for TraceAsStringAsInner<T> {
type Type = T;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.ty
}
}
impl<T: Type> ToExpr for TraceAsStringAsInner<T> {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::TraceAsStringAsInner(TraceAsStringAsInner {
arg: self.arg,
ty: self.ty.canonical(),
literal_bits: self.literal_bits,
target: self.target,
})
.intern(),
__ty: self.ty,
__flow: Expr::flow(self.arg),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
/// The [`Simulation::io()`] equivalent for a global signal, this is a flipped version of a global signal
/// that allows you to e.g. use [`Simulation::write()`] to write to [`formal_global_clock()`].
///
/// [`Simulation::io()`]: crate::sim::Simulation::io
/// [`Simulation::write()`]: crate::sim::Simulation::write
/// [`formal_global_clock()`]: crate::formal::formal_global_clock
pub struct SimIoForGlobal {
global: FormalInput,
}
impl fmt::Debug for SimIoForGlobal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SimIoForGlobal").field(&self.global).finish()
}
}
impl SimIoForGlobal {
pub fn new(global: FormalInput) -> Self {
Self { global }
}
pub fn global(self) -> FormalInput {
self.global
}
pub(crate) fn must_connect_to(self) -> bool {
true
}
pub fn flow(self) -> Flow {
self.global.flow().flip()
}
pub(crate) fn source_location(self) -> crate::source_location::SourceLocation {
self.global.source_location()
}
}
impl GetTarget for SimIoForGlobal {
fn target(&self) -> Option<Interned<Target>> {
Some(Target::from(*self).intern_sized())
}
}
impl ToLiteralBits for SimIoForGlobal {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
Err(NotALiteralExpr)
}
}
impl ValueType for SimIoForGlobal {
type Type = CanonicalType;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.global.ty()
}
}
impl ToExpr for SimIoForGlobal {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::SimIoForGlobal(*self).intern(),
__ty: self.ty(),
__flow: self.flow(),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub struct StructuralEqFlags {
pub assume_padding_is_zeroed: bool,
}
impl StructuralEqFlags {
pub const DEFAULT: Self = Self {
assume_padding_is_zeroed: false,
};
}
impl Default for StructuralEqFlags {
fn default() -> Self {
Self::DEFAULT
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub enum StructuralEqError {
TypesAreNotEqual {
lhs: CanonicalType,
rhs: CanonicalType,
},
TypeContainsSimOnly {
ty: CanonicalType,
},
}
impl fmt::Display for StructuralEqError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::TypesAreNotEqual { lhs, rhs } => write!(
f,
"StructuralEq lhs type must be the same as rhs type:\nlhs: {lhs:#?}\nrhs: {rhs:#?}\n",
),
Self::TypeContainsSimOnly { ty } => write!(
f,
"StructuralEq input type must not contain SimOnly type: {ty:#?}",
),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct StructuralEq {
lhs: Expr<CanonicalType>,
rhs: Expr<CanonicalType>,
flags: StructuralEqFlags,
literal_bits: Result<Interned<BitSlice>, NotALiteralExpr>,
}
impl StructuralEq {
fn literal_eq(
ty: CanonicalType,
l: Interned<BitSlice>,
r: Interned<BitSlice>,
) -> Result<bool, NotALiteralExpr> {
enum PairRefOrInternedBitSlice<'a> {
Ref(&'a BitSlice, &'a BitSlice),
Interned(Interned<BitSlice>, Interned<BitSlice>),
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct MyMemoize(CanonicalType);
impl MemoizeGeneric for MyMemoize {
type InputRef<'a> = (&'a BitSlice, &'a BitSlice);
type InputOwned = (Interned<BitSlice>, Interned<BitSlice>);
type InputCow<'a> = PairRefOrInternedBitSlice<'a>;
type Output = Result<bool, NotALiteralExpr>;
fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool {
a == b
}
fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
let (l, r) = input;
(l, r)
}
fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned {
match input {
PairRefOrInternedBitSlice::Ref(l, r) => (l.intern(), r.intern()),
PairRefOrInternedBitSlice::Interned(l, r) => (l, r),
}
}
fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> {
match input {
PairRefOrInternedBitSlice::Ref(l, r) => (l, r),
PairRefOrInternedBitSlice::Interned(l, r) => (l, r),
}
}
fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> {
let (l, r) = input;
PairRefOrInternedBitSlice::Interned(l, r)
}
fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> {
let (l, r) = input;
PairRefOrInternedBitSlice::Ref(l, r)
}
fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
let (mut l, mut r) = input;
match self.0 {
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => Ok(l == r),
CanonicalType::Array(ty) => {
let element_ty = ty.element();
let element_bit_width = element_ty.bit_width();
let mut eq = true;
for element_index in 0..ty.len() {
if !Self(element_ty).get((
&l[element_bit_width * element_index..][..element_bit_width],
&r[element_bit_width * element_index..][..element_bit_width],
))? {
eq = false;
break;
}
}
Ok(eq)
}
CanonicalType::Enum(ty) => {
let discriminant_bit_width = ty.discriminant_bit_width();
let (l_discriminant_bits, l_body_bits) = l.split_at(discriminant_bit_width);
let (r_discriminant_bits, r_body_bits) = r.split_at(discriminant_bit_width);
if l_discriminant_bits != r_discriminant_bits {
return Ok(false);
}
let mut discriminant = 0usize;
discriminant.view_bits_mut::<Lsb0>()[..l_discriminant_bits.len()]
.copy_from_bitslice(l_discriminant_bits);
match ty.variants().get(discriminant) {
Some(&EnumVariant {
name: _,
ty: Some(variant_ty),
}) => {
let variant_bit_width = variant_ty.bit_width();
Self(variant_ty).get((
&l_body_bits[..variant_bit_width],
&r_body_bits[..variant_bit_width],
))
}
Some(EnumVariant { name: _, ty: None }) => Ok(true),
None => Err(NotALiteralExpr),
}
}
CanonicalType::Bundle(ty) => {
let mut eq = true;
for field in &ty.fields() {
let field_bit_width = field.ty.bit_width();
let l_field;
let r_field;
(l_field, l) = l.split_at(field_bit_width);
(r_field, r) = r.split_at(field_bit_width);
if !Self(field.ty).get((l_field, r_field))? {
eq = false;
break;
}
}
Ok(eq)
}
CanonicalType::DynSimOnly(_) => unreachable!("doesn't have literal_bits"),
CanonicalType::TraceAsString(ty) => Self(ty.inner_ty()).get((l, r)),
}
}
}
MyMemoize(ty).get_owned((l, r))
}
#[track_caller]
pub fn new(lhs: Expr<CanonicalType>, rhs: Expr<CanonicalType>) -> Self {
Self::with_flags(lhs, rhs, StructuralEqFlags::DEFAULT)
}
#[track_caller]
pub fn with_flags(
lhs: Expr<CanonicalType>,
rhs: Expr<CanonicalType>,
flags: StructuralEqFlags,
) -> Self {
match Self::try_with_flags(lhs, rhs, flags) {
Ok(retval) => retval,
Err(e) => panic!("{e}"),
}
}
pub fn try_new(
lhs: Expr<CanonicalType>,
rhs: Expr<CanonicalType>,
) -> Result<Self, StructuralEqError> {
Self::try_with_flags(lhs, rhs, StructuralEqFlags::DEFAULT)
}
pub fn try_with_flags(
lhs: Expr<CanonicalType>,
rhs: Expr<CanonicalType>,
flags: StructuralEqFlags,
) -> Result<Self, StructuralEqError> {
let ty = lhs.ty();
let rhs_ty = rhs.ty();
if ty != rhs_ty {
return Err(StructuralEqError::TypesAreNotEqual {
lhs: ty,
rhs: rhs_ty,
});
}
if ty.contains_sim_only() {
return Err(StructuralEqError::TypeContainsSimOnly { ty });
}
Ok(Self {
lhs,
rhs,
flags,
literal_bits: lhs.to_literal_bits().and_then(|lhs| {
let rhs = rhs.to_literal_bits()?;
if flags.assume_padding_is_zeroed {
lhs == rhs
} else {
Self::literal_eq(ty, lhs, rhs)?
}
.to_literal_bits()
}),
})
}
pub fn lhs(self) -> Expr<CanonicalType> {
self.lhs
}
pub fn rhs(self) -> Expr<CanonicalType> {
self.rhs
}
pub fn flags(self) -> StructuralEqFlags {
self.flags
}
}
impl ToLiteralBits for StructuralEq {
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
self.literal_bits
}
}
impl_get_target_none!([] StructuralEq);
impl ValueType for StructuralEq {
type Type = Bool;
type ValueCategory = ValueCategoryExpr;
fn ty(&self) -> Self::Type {
Bool
}
}
impl ToExpr for StructuralEq {
fn to_expr(&self) -> Expr<Self::Type> {
Expr {
__enum: ExprEnum::StructuralEq(*self).intern(),
__ty: Bool,
__flow: Flow::Source,
}
}
}

View file

@ -4,13 +4,14 @@ use crate::{
array::Array,
bundle::{Bundle, BundleField},
expr::{Expr, Flow, ToExpr, ValueType, value_category::ValueCategoryExpr},
formal::FormalInput,
intern::{Intern, Interned},
memory::{DynPortType, MemPort},
module::{Instance, ModuleIO, TargetName},
reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
source_location::SourceLocation,
ty::{CanonicalType, Type},
ty::{CanonicalType, TraceAsString, Type},
wire::Wire,
};
use std::fmt;
@ -46,11 +47,33 @@ impl fmt::Display for TargetPathDynArrayElement {
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TargetPathTraceAsStringInner {}
impl fmt::Display for TargetPathTraceAsStringInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, ".<inner>")
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TargetPathToTraceAsString {
pub ty: TraceAsString<CanonicalType>,
}
impl fmt::Display for TargetPathToTraceAsString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, ".to_trace_as_string()")
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TargetPathElement {
BundleField(TargetPathBundleField),
ArrayElement(TargetPathArrayElement),
DynArrayElement(TargetPathDynArrayElement),
TraceAsStringInner(TargetPathTraceAsStringInner),
ToTraceAsString(TargetPathToTraceAsString),
}
impl From<TargetPathBundleField> for TargetPathElement {
@ -71,12 +94,26 @@ impl From<TargetPathDynArrayElement> for TargetPathElement {
}
}
impl From<TargetPathTraceAsStringInner> for TargetPathElement {
fn from(value: TargetPathTraceAsStringInner) -> Self {
Self::TraceAsStringInner(value)
}
}
impl From<TargetPathToTraceAsString> for TargetPathElement {
fn from(value: TargetPathToTraceAsString) -> Self {
Self::ToTraceAsString(value)
}
}
impl fmt::Display for TargetPathElement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BundleField(v) => v.fmt(f),
Self::ArrayElement(v) => v.fmt(f),
Self::DynArrayElement(v) => v.fmt(f),
Self::TraceAsStringInner(v) => v.fmt(f),
Self::ToTraceAsString(v) => v.fmt(f),
}
}
}
@ -100,6 +137,15 @@ impl TargetPathElement {
let parent_ty = Array::<CanonicalType>::from_canonical(parent.canonical_ty());
parent_ty.element()
}
Self::TraceAsStringInner(_) => {
let parent_ty =
TraceAsString::<CanonicalType>::from_canonical(parent.canonical_ty());
parent_ty.inner_ty()
}
&Self::ToTraceAsString(TargetPathToTraceAsString { ty }) => {
assert_eq!(parent.canonical_ty(), ty.inner_ty());
ty.canonical()
}
}
}
pub fn flow(&self, parent: Interned<Target>) -> Flow {
@ -111,13 +157,18 @@ impl TargetPathElement {
.expect("field name is known to be a valid field of parent type");
parent.flow().flip_if(field.flipped)
}
Self::ArrayElement(_) => parent.flow(),
Self::DynArrayElement(_) => parent.flow(),
Self::ArrayElement(_)
| Self::DynArrayElement(_)
| Self::TraceAsStringInner(_)
| Self::ToTraceAsString(_) => parent.flow(),
}
}
pub fn is_static(&self) -> bool {
match self {
Self::BundleField(_) | Self::ArrayElement(_) => true,
Self::BundleField(_)
| Self::ArrayElement(_)
| Self::TraceAsStringInner(_)
| Self::ToTraceAsString(_) => true,
Self::DynArrayElement(_) => false,
}
}
@ -245,6 +296,14 @@ impl_target_base! {
#[is = is_instance]
#[to = instance]
Instance(Instance<Bundle>),
#[from = from]
#[is = is_formal_input]
#[to = formal_input]
FormalInput(FormalInput),
#[from = from]
#[is = is_sim_io_for_global]
#[to = sim_io_for_global]
SimIoForGlobal(crate::expr::ops::SimIoForGlobal),
}
}
@ -293,6 +352,8 @@ impl TargetBase {
TargetBase::RegAsync(v) => TargetName(v.scoped_name(), None),
TargetBase::Wire(v) => TargetName(v.scoped_name(), None),
TargetBase::Instance(v) => TargetName(v.scoped_name(), None),
TargetBase::FormalInput(v) => TargetName(v.scoped_name(), None),
TargetBase::SimIoForGlobal(v) => TargetName(v.global().scoped_name(), None),
}
}
pub fn canonical_ty(&self) -> CanonicalType {
@ -304,6 +365,21 @@ impl TargetBase {
TargetBase::RegAsync(v) => v.ty(),
TargetBase::Wire(v) => v.ty(),
TargetBase::Instance(v) => v.ty().canonical(),
TargetBase::FormalInput(v) => v.ty(),
TargetBase::SimIoForGlobal(v) => v.ty(),
}
}
pub fn is_valid_annotation_target(&self) -> bool {
match self {
Self::ModuleIO(_) => true,
Self::MemPort(_) => true,
Self::Reg(_) => true,
Self::RegSync(_) => true,
Self::RegAsync(_) => true,
Self::Wire(_) => true,
Self::Instance(_) => true,
Self::FormalInput(_) => false,
Self::SimIoForGlobal(_) => false,
}
}
}
@ -314,6 +390,7 @@ pub struct TargetChild {
path_element: Interned<TargetPathElement>,
canonical_ty: CanonicalType,
flow: Flow,
canonicalized_if_different: Option<Interned<Target>>,
}
impl fmt::Debug for TargetChild {
@ -323,6 +400,7 @@ impl fmt::Debug for TargetChild {
path_element,
canonical_ty: _,
flow: _,
canonicalized_if_different: _,
} = self;
parent.fmt(f)?;
fmt::Display::fmt(path_element, f)
@ -336,6 +414,7 @@ impl fmt::Display for TargetChild {
path_element,
canonical_ty: _,
flow: _,
canonicalized_if_different: _,
} = self;
parent.fmt(f)?;
path_element.fmt(f)
@ -343,14 +422,69 @@ impl fmt::Display for TargetChild {
}
impl TargetChild {
pub fn new(parent: Interned<Target>, path_element: Interned<TargetPathElement>) -> Self {
fn new_helper(
parent: Interned<Target>,
path_element: Interned<TargetPathElement>,
canonicalized_if_different: Option<Interned<Target>>,
) -> Self {
Self {
parent,
path_element,
canonical_ty: path_element.canonical_ty(parent),
flow: path_element.flow(parent),
canonicalized_if_different,
}
}
fn make_canonicalized_if_different(
parent: Interned<Target>,
path_element: Interned<TargetPathElement>,
) -> Option<Interned<Target>> {
use TargetPathElement::*;
match *path_element {
BundleField(_) => {}
ArrayElement(_) => {}
DynArrayElement(_) => {}
TraceAsStringInner(_) => {
if let Some(child) = parent.canonicalized().child() {
match *child.path_element() {
BundleField(_)
| ArrayElement(_)
| DynArrayElement(_)
| TraceAsStringInner(_) => {}
ToTraceAsString(_) => return Some(child.parent()),
}
}
}
ToTraceAsString(TargetPathToTraceAsString { ty }) => {
if let Some(child) = parent.canonicalized().child() {
match *child.path_element() {
BundleField(_) | ArrayElement(_) | DynArrayElement(_)
| ToTraceAsString(_) => {}
TraceAsStringInner(_) => {
if ty.canonical() == child.parent().canonical_ty() {
return Some(child.parent());
}
}
}
}
}
}
Some(
Target::Child(Self::new_helper(
parent.canonicalized_if_different()?,
path_element,
None,
))
.intern_sized(),
)
}
pub fn new(parent: Interned<Target>, path_element: Interned<TargetPathElement>) -> Self {
Self::new_helper(
parent,
path_element,
Self::make_canonicalized_if_different(parent, path_element),
)
}
pub fn parent(self) -> Interned<Target> {
self.parent
}
@ -363,6 +497,19 @@ impl TargetChild {
pub fn flow(self) -> Flow {
self.flow
}
pub fn is_canonicalized(self) -> bool {
self.canonicalized_if_different.is_none()
}
pub fn canonicalized_if_different(self) -> Option<Interned<Target>> {
self.canonicalized_if_different
}
#[must_use]
pub fn canonicalized(self) -> Target {
match self.canonicalized_if_different {
Some(v) => *v,
None => Target::Child(self),
}
}
pub fn bundle_field(self) -> Option<BundleField> {
if let TargetPathElement::BundleField(TargetPathBundleField { name }) = *self.path_element {
let parent_ty = Bundle::from_canonical(self.parent.canonical_ty());
@ -427,6 +574,16 @@ impl Target {
}
}
}
pub fn is_valid_annotation_target(&self) -> bool {
let mut target = self;
loop {
match target {
Self::Base(target_base) => return target_base.is_valid_annotation_target(),
Self::Child(v) if !v.path_element().is_static() => return false,
Self::Child(v) => target = &v.parent,
}
}
}
#[must_use]
pub fn join(&self, path_element: Interned<TargetPathElement>) -> Self {
TargetChild::new(self.intern(), path_element).into()
@ -443,6 +600,82 @@ impl Target {
Target::Child(v) => v.canonical_ty(),
}
}
pub fn is_canonicalized(self) -> bool {
match self {
Self::Base(_) => true,
Self::Child(child) => child.is_canonicalized(),
}
}
pub fn canonicalized_if_different(self) -> Option<Interned<Self>> {
match self {
Self::Base(_) => None,
Self::Child(child) => child.canonicalized_if_different(),
}
}
#[must_use]
pub fn canonicalized(self) -> Target {
match self.canonicalized_if_different() {
Some(v) => *v,
None => self,
}
}
#[must_use]
pub fn canonicalized_interned(this: Interned<Target>) -> Interned<Target> {
this.canonicalized_if_different().unwrap_or(this)
}
#[must_use]
pub fn unwrap_transparent_types(mut self) -> Target {
loop {
self = self.canonicalized();
match self.canonical_ty() {
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
| CanonicalType::Array(_)
| CanonicalType::Enum(_)
| CanonicalType::Bundle(_)
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => return self,
CanonicalType::TraceAsString(_) => {
if let Self::Child(child) = self
&& let TargetPathElement::ToTraceAsString(_) = *child.path_element()
{
self = *child.parent();
} else {
self = self.join(TargetPathElement::intern_sized(
TargetPathTraceAsStringInner {}.into(),
));
}
}
}
}
}
#[must_use]
pub fn unwrap_transparent_types_interned(this: Interned<Target>) -> Interned<Target> {
let retval = this.unwrap_transparent_types();
if retval != *this {
retval.intern_sized()
} else {
this
}
}
#[must_use]
pub fn without_trailing_transparent_path_elements(mut self) -> Target {
use TargetPathElement::*;
loop {
match self {
Self::Base(_) => return self,
Self::Child(child) => match *child.path_element() {
BundleField(_) | ArrayElement(_) | DynArrayElement(_) => return self,
TraceAsStringInner(_) | ToTraceAsString(_) => self = *child.parent(),
},
}
}
}
}
impl fmt::Display for Target {
@ -467,6 +700,18 @@ pub trait GetTarget {
fn target(&self) -> Option<Interned<Target>>;
}
impl GetTarget for Target {
fn target(&self) -> Option<Interned<Target>> {
Some(self.intern())
}
}
impl GetTarget for TargetBase {
fn target(&self) -> Option<Interned<Target>> {
Some(Target::Base(self.intern()).intern_sized())
}
}
impl GetTarget for bool {
fn target(&self) -> Option<Interned<Target>> {
None

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,189 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
expr::target::{GetTarget, Target},
int::BoolOrIntType,
intern::{Intern, Interned, Memoize},
intern::{Intern, Interned},
module::{NameId, NameIdOrGlobal, ScopedNameId},
prelude::*,
};
use std::sync::OnceLock;
use std::{fmt, sync::OnceLock};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum FormalInputKind {
FormalGlobalClock,
FormalReset,
AnyConst,
AnySeq,
AllConst,
AllSeq,
}
impl FormalInputKind {
pub fn fixed_ty(self) -> Option<CanonicalType> {
match self {
Self::FormalGlobalClock => Some(Clock.into()),
Self::FormalReset => Some(SyncReset.into()),
Self::AnyConst => None,
Self::AnySeq => None,
Self::AllConst => None,
Self::AllSeq => None,
}
}
pub fn fixed_id(self) -> Option<crate::module::Id> {
struct Cache {
formal_global_clock: crate::module::Id,
formal_reset: crate::module::Id,
}
static CACHE: OnceLock<Cache> = OnceLock::new();
let cache = || {
CACHE.get_or_init(
#[cold]
|| Cache {
formal_global_clock: crate::module::Id::new(),
formal_reset: crate::module::Id::new(),
},
)
};
match self {
Self::FormalGlobalClock => Some(cache().formal_global_clock),
Self::FormalReset => Some(cache().formal_reset),
Self::AnyConst => None,
Self::AnySeq => None,
Self::AllConst => None,
Self::AllSeq => None,
}
}
pub fn fixed_source_location(self) -> Option<SourceLocation> {
match self {
Self::FormalGlobalClock | Self::FormalReset => Some(SourceLocation::builtin()),
Self::AnyConst | Self::AnySeq | Self::AllConst | Self::AllSeq => None,
}
}
pub fn name(self) -> &'static str {
match self {
Self::FormalGlobalClock => "formal_global_clock",
Self::FormalReset => "formal_reset",
Self::AnyConst => "any_const",
Self::AnySeq => "any_seq",
Self::AllConst => "all_const",
Self::AllSeq => "all_seq",
}
}
pub fn interned_name(self) -> Interned<str> {
macro_rules! impl_interned_name {
($($variant:ident,)*) => {
match self {
$(Self::$variant => {
static CACHE: OnceLock<Interned<str>> = OnceLock::new();
*CACHE.get_or_init(|| Self::$variant.name().intern())
})*
}
};
}
impl_interned_name! {
FormalGlobalClock,
FormalReset,
AnyConst,
AnySeq,
AllConst,
AllSeq,
}
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
struct FormalInputData {
kind: FormalInputKind,
name_id: NameId,
ty: CanonicalType,
source_location: SourceLocation,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct FormalInput(Interned<FormalInputData>);
impl fmt::Debug for FormalInput {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.kind().fixed_ty().is_some() {
f.write_str(&self.name())
} else {
f.debug_tuple(&self.name()).field(&self.0.ty).finish()
}
}
}
impl FormalInput {
#[track_caller]
pub fn new(
kind: FormalInputKind,
name_id: NameId,
ty: CanonicalType,
source_location: SourceLocation,
) -> Self {
let NameId(name, id) = name_id;
assert_eq!(kind.interned_name(), name);
if let Some(fixed_ty) = kind.fixed_ty() {
assert_eq!(ty, fixed_ty);
} else {
assert!(
ty.is_castable_from_bits(),
"{name} type must be castable from bits. got:\n{ty:#?}",
);
}
if let Some(fixed_source_location) = kind.fixed_source_location() {
assert_eq!(source_location, fixed_source_location);
}
if let Some(fixed_id) = kind.fixed_id() {
assert_eq!(id, fixed_id);
}
Self(
FormalInputData {
kind,
name_id,
ty,
source_location,
}
.intern_sized(),
)
}
pub fn kind(self) -> FormalInputKind {
self.0.kind
}
pub fn name(self) -> Interned<str> {
self.0.name_id.0
}
pub fn name_id(self) -> NameId {
self.0.name_id
}
pub fn scoped_name(self) -> ScopedNameId {
ScopedNameId(NameIdOrGlobal::Global, self.name_id())
}
pub fn source_location(self) -> SourceLocation {
self.0.source_location
}
pub(crate) fn must_connect_to(self) -> bool {
false
}
pub(crate) fn flow(self) -> crate::expr::Flow {
crate::expr::Flow::Source
}
}
impl ValueType for FormalInput {
type Type = CanonicalType;
type ValueCategory = crate::expr::value_category::ValueCategoryExpr;
fn ty(&self) -> Self::Type {
self.0.ty
}
}
impl GetTarget for FormalInput {
fn target(&self) -> Option<Interned<Target>> {
Some(Target::from(*self).intern_sized())
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum FormalKind {
@ -138,110 +316,76 @@ make_formal!(
hdl_cover
);
pub trait MakeFormalExpr: Type {}
impl<T: Type> MakeFormalExpr for T {}
#[hdl]
pub fn formal_global_clock() -> Expr<Clock> {
#[hdl_module(extern)]
fn formal_global_clock() {
#[hdl]
let clk: Clock = m.output();
m.annotate_module(BlackBoxInlineAnnotation {
path: "fayalite_formal_global_clock.v".intern(),
text: r"module __fayalite_formal_global_clock(output clk);
(* gclk *)
reg clk;
endmodule
"
.intern(),
});
m.verilog_name("__fayalite_formal_global_clock");
}
#[hdl]
let formal_global_clock = instance(formal_global_clock());
formal_global_clock.clk
static CACHE: OnceLock<Expr<Clock>> = OnceLock::new();
*CACHE.get_or_init(|| {
let kind = FormalInputKind::FormalGlobalClock;
Expr::from_canonical(
FormalInput::new(
kind,
NameId(
kind.interned_name(),
kind.fixed_id().expect("known to have a fixed Id"),
),
Clock.into(),
kind.fixed_source_location()
.expect("known to have a fixed SourceLocation"),
)
.to_expr(),
)
})
}
#[hdl]
pub fn formal_reset() -> Expr<SyncReset> {
#[hdl_module(extern)]
fn formal_reset() {
#[hdl]
let rst: SyncReset = m.output();
m.annotate_module(BlackBoxInlineAnnotation {
path: "fayalite_formal_reset.v".intern(),
text: r"module __fayalite_formal_reset(output rst);
assign rst = $initstate;
endmodule
"
.intern(),
});
m.verilog_name("__fayalite_formal_reset");
}
static MOD: OnceLock<Interned<Module<formal_reset>>> = OnceLock::new();
#[hdl]
let formal_reset = instance(*MOD.get_or_init(formal_reset));
formal_reset.rst
static CACHE: OnceLock<Expr<SyncReset>> = OnceLock::new();
*CACHE.get_or_init(|| {
let kind = FormalInputKind::FormalReset;
Expr::from_canonical(
FormalInput::new(
kind,
NameId(
kind.interned_name(),
kind.fixed_id().expect("known to have a fixed Id"),
),
SyncReset.into(),
kind.fixed_source_location()
.expect("known to have a fixed SourceLocation"),
)
.to_expr(),
)
})
}
macro_rules! make_any_const_fn {
($ident:ident, $verilog_attribute:literal) => {
($ident:ident, $ident_with_loc:ident, $verilog_attribute:literal, $kind:ident) => {
#[track_caller]
#[hdl]
pub fn $ident<T: BoolOrIntType>(ty: T) -> Expr<T> {
#[hdl_module(extern)]
pub(super) fn $ident<T: BoolOrIntType>(ty: T) {
#[hdl]
let out: T = m.output(ty);
let width = ty.width();
let verilog_bitslice = if width == 1 {
String::new()
} else {
format!(" [{}:0]", width - 1)
};
m.annotate_module(BlackBoxInlineAnnotation {
path: Intern::intern_owned(format!(
"fayalite_{}_{width}.v",
stringify!($ident),
)),
text: Intern::intern_owned(format!(
r"module __fayalite_{}_{width}(output{verilog_bitslice} out);
(* {} *)
reg{verilog_bitslice} out;
endmodule
",
stringify!($ident),
$verilog_attribute,
)),
});
m.verilog_name(format!("__fayalite_{}_{width}", stringify!($ident)));
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct TheMemoize<T>(T);
impl<T: BoolOrIntType> Memoize for TheMemoize<T> {
type Input = ();
type InputOwned = ();
type Output = Option<Interned<Module<$ident<T>>>>;
fn inner(self, _input: &Self::Input) -> Self::Output {
if self.0.width() == 0 {
None
} else {
Some($ident(self.0))
}
}
}
let Some(module) = TheMemoize(ty).get_owned(()) else {
return 0_hdl_u0.cast_bits_to(ty);
};
#[hdl]
let $ident = instance(module);
$ident.out
$ident_with_loc(ty, SourceLocation::caller())
}
#[track_caller]
#[hdl]
pub fn $ident_with_loc<T: BoolOrIntType>(
ty: T,
source_location: SourceLocation,
) -> Expr<T> {
let kind = FormalInputKind::$kind;
Expr::from_canonical(
FormalInput::new(
kind,
NameId(kind.interned_name(), crate::module::Id::new()),
ty.canonical(),
source_location,
)
.to_expr(),
)
}
};
}
make_any_const_fn!(any_const, "anyconst");
make_any_const_fn!(any_seq, "anyseq");
make_any_const_fn!(all_const, "allconst");
make_any_const_fn!(all_seq, "allseq");
make_any_const_fn!(any_const, any_const_with_loc, "anyconst", AnyConst);
make_any_const_fn!(any_seq, any_seq_with_loc, "anyseq", AnySeq);
make_any_const_fn!(all_const, all_const_with_loc, "allconst", AllConst);
make_any_const_fn!(all_seq, all_seq_with_loc, "allseq", AllSeq);

View file

@ -15,8 +15,8 @@ use crate::{
source_location::SourceLocation,
ty::{
CanonicalType, FillInDefaultedGenerics, OpaqueSimValueSize, OpaqueSimValueSlice,
OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type, TypeProperties,
impl_match_variant_as_self,
OpaqueSimValueWriter, OpaqueSimValueWritten, SimValueDebug, SimValueDisplay, StaticType,
Type, TypeProperties, impl_match_variant_as_self,
},
util::{ConstBool, ConstUsize, GenericConstBool, GenericConstUsize, interned_bit, slice_range},
};
@ -1019,6 +1019,24 @@ macro_rules! impl_int {
}
}
impl<Width: Size> SimValueDebug for $name<Width> {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl<Width: Size> SimValueDisplay for $name<Width> {
fn sim_value_display(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Display::fmt(value, f)
}
}
impl<Width: KnownSize> Default for $name<Width> {
fn default() -> Self {
Self::TYPE
@ -1259,6 +1277,9 @@ macro_rules! impl_int {
pub fn bitvec_mut(&mut self) -> &mut BitVec {
Arc::make_mut(&mut self.bits)
}
pub fn arc_bitvec_mut(&mut self) -> &mut Arc<BitVec> {
&mut self.bits
}
}
};
}
@ -1899,6 +1920,15 @@ impl Type for Bool {
}
}
impl SimValueDebug for Bool {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl StaticType for Bool {
const TYPE: Self = Bool;
const MASK_TYPE: Self::MaskType = Bool;

View file

@ -14,7 +14,7 @@ use crate::{
source_location::SourceLocation,
ty::{
CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
StaticType, Type, TypeProperties, impl_match_variant_as_self,
SimValueDebug, StaticType, Type, TypeProperties, impl_match_variant_as_self,
},
};
use bitvec::{order::Lsb0, view::BitView};
@ -94,6 +94,15 @@ impl Type for UIntInRangeMaskType {
}
}
impl SimValueDebug for UIntInRangeMaskType {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl BundleType for UIntInRangeMaskType {
type Builder = NoBuilder;
@ -168,6 +177,8 @@ impl CastToImpl<UIntInRangeMaskType> for Bool {
}
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
const TRY_STRUCTURAL_EQ: bool = true;
#[track_caller]
fn cmp_value_eq(
_lhs: Self,
@ -339,6 +350,15 @@ macro_rules! define_uint_in_range_type {
}
}
impl<Start: Size, End: Size> SimValueDebug for $UIntInRangeType<Start, End> {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl<Start: Size, End: Size> fmt::Debug for $UIntInRangeType<Start, End> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { value, range } = self;
@ -552,6 +572,8 @@ macro_rules! define_uint_in_range_type {
HdlPartialEqImpl<$UIntInRangeType<RhsStart, RhsEnd>>
for $UIntInRangeType<LhsStart, LhsEnd>
{
const TRY_STRUCTURAL_EQ: bool = true;
fn cmp_value_eq(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
@ -639,6 +661,8 @@ macro_rules! define_uint_in_range_type {
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<UIntType<Width>>
for $UIntInRangeType<Start, End>
{
const TRY_STRUCTURAL_EQ: bool = false;
fn cmp_value_eq(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
@ -658,6 +682,8 @@ macro_rules! define_uint_in_range_type {
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<$UIntInRangeType<Start, End>>
for UIntType<Width>
{
const TRY_STRUCTURAL_EQ: bool = false;
fn cmp_value_eq(
_lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,

View file

@ -682,27 +682,62 @@ impl<T: ?Sized + 'static + Send + Sync + AsRef<U>, U: ?Sized> AsRef<U> for Inter
#[derive(Clone, Debug)]
pub struct InternedSliceIter<T: Clone + 'static + Send + Sync> {
slice: Interned<[T]>,
index: std::ops::Range<usize>,
iter: std::iter::Cloned<std::slice::Iter<'static, T>>,
}
impl<T: Clone + 'static + Send + Sync> Default for InternedSliceIter<T> {
fn default() -> Self {
Self {
iter: [].iter().cloned(),
}
}
}
impl<T: Clone + 'static + Send + Sync> Iterator for InternedSliceIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.index.next().map(|index| self.slice[index].clone())
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.index.size_hint()
self.iter.size_hint()
}
fn count(self) -> usize {
self.iter.count()
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth(n)
}
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.iter.fold(init, f)
}
}
impl<T: Clone + 'static + Send + Sync> DoubleEndedIterator for InternedSliceIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.index
.next_back()
.map(|index| self.slice[index].clone())
self.iter.next_back()
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.iter.nth_back(n)
}
fn rfold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.iter.rfold(init, f)
}
}
@ -716,8 +751,7 @@ impl<T: Clone + 'static + Send + Sync> IntoIterator for Interned<[T]> {
fn into_iter(self) -> Self::IntoIter {
InternedSliceIter {
index: 0..self.len(),
slice: self,
iter: Interned::into_inner(self).iter().cloned(),
}
}
}

View file

@ -1093,6 +1093,7 @@ pub fn splat_mask<T: Type>(ty: T, value: Expr<Bool>) -> Expr<AsMask<T>> {
.to_expr(),
)),
CanonicalType::PhantomConst(_) => Expr::from_canonical(Expr::canonical(().to_expr())),
CanonicalType::TraceAsString(ty) => Expr::from_canonical(splat_mask(ty.inner_ty(), value)),
}
}

View file

@ -8,7 +8,7 @@ use crate::{
clock::{Clock, ClockDomain},
enum_::{Enum, EnumMatchVariantsIter, EnumType},
expr::{
Expr, Flow, ToExpr, ValueType,
Expr, ExprEnum, Flow, ToExpr, ValueType,
ops::VariantAccess,
target::{
GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField,
@ -20,6 +20,7 @@ use crate::{
int::{Bool, DynSize, Size},
intern::{Intern, Interned},
memory::{Mem, MemBuilder, MemBuilderTarget, PortName},
module::transform::visit::{Visit, Visitor},
platform::PlatformIOBuilder,
reg::Reg,
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
@ -726,7 +727,57 @@ impl fmt::Display for NameId {
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct ScopedNameId(pub NameId, pub NameId);
pub enum NameIdOrGlobal {
Global,
NameId(NameId),
}
impl NameIdOrGlobal {
pub fn name_id(self) -> Option<NameId> {
match self {
Self::Global => None,
Self::NameId(v) => Some(v),
}
}
#[track_caller]
pub fn assert_is_name_id(self) {
match self {
Self::Global => panic!("expected a NameId, got NameIdOrGlobal::Global"),
Self::NameId(_) => {}
}
}
#[track_caller]
pub fn unwrap_name_id(self) -> NameId {
match self {
Self::Global => panic!("expected a NameId, got NameIdOrGlobal::Global"),
Self::NameId(v) => v,
}
}
}
impl fmt::Debug for NameIdOrGlobal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for NameIdOrGlobal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Global => f.write_str("<<Global>>"),
Self::NameId(name_id) => fmt::Display::fmt(name_id, f),
}
}
}
impl From<NameId> for NameIdOrGlobal {
fn from(value: NameId) -> Self {
Self::NameId(value)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct ScopedNameId(pub NameIdOrGlobal, pub NameId);
impl fmt::Debug for ScopedNameId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -804,7 +855,7 @@ impl<T: BundleType> Instance<T> {
self.containing_module_name_id().0
}
pub fn containing_module_name_id(self) -> NameId {
self.scoped_name.0
self.scoped_name.0.unwrap_name_id()
}
pub fn name(self) -> Interned<str> {
self.name_id().0
@ -821,11 +872,13 @@ impl<T: BundleType> Instance<T> {
pub fn source_location(self) -> SourceLocation {
self.source_location
}
#[track_caller]
pub fn new_unchecked(
scoped_name: ScopedNameId,
instantiated: Interned<Module<T>>,
source_location: SourceLocation,
) -> Self {
scoped_name.0.assert_is_name_id();
Self {
scoped_name,
instantiated,
@ -1111,7 +1164,10 @@ fn validate_clock_for_past<S: ModuleBuildingStatus>(
let mut target = clock_for_past;
while let Target::Child(child) = target {
match *child.path_element() {
TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) => {}
TargetPathElement::BundleField(_)
| TargetPathElement::ArrayElement(_)
| TargetPathElement::ToTraceAsString(_)
| TargetPathElement::TraceAsStringInner(_) => {}
TargetPathElement::DynArrayElement(_) => {
panic!(
"clock_for_past: clock must be a static target (you can't use `Expr<UInt>` array indexes):\n{clock_for_past:?}"
@ -1535,6 +1591,7 @@ impl TargetState {
}
}
fn new(target: Interned<Target>, declared_in_block: usize) -> Self {
let target = Target::unwrap_transparent_types_interned(target);
Self {
target,
inner: match target.canonical_ty() {
@ -1586,17 +1643,71 @@ impl TargetState {
declared_in_block,
written_in_blocks: RefCell::default(),
},
CanonicalType::TraceAsString(_) => {
unreachable!("handled by Target::unwrap_transparent_types_interned")
}
},
}
}
}
struct VisibleExprsStack {
buf: Vec<HashSet<ExprEnum>>,
len: usize,
}
impl VisibleExprsStack {
fn top(&mut self) -> &mut HashSet<ExprEnum> {
&mut self.buf[self.len - 1]
}
fn slice(&self) -> &[HashSet<ExprEnum>] {
&self.buf[..self.len]
}
fn contains(&self, v: &ExprEnum) -> bool {
self.slice().iter().any(|i| i.contains(v))
}
fn push_empty(&mut self) {
#[cold]
fn push_empty_cold(stack: &mut VisibleExprsStack) {
stack.buf.push(HashSet::default());
assert_eq!(stack.buf.len(), stack.len)
}
self.len += 1;
if self.len > self.buf.len() {
push_empty_cold(self)
}
}
fn pop(&mut self) {
let Some(new_len) = self.len.checked_sub(1) else {
unreachable!("visible exprs stack underflow");
};
self.buf[new_len].clear();
self.len = new_len;
}
}
impl Default for VisibleExprsStack {
fn default() -> Self {
Self {
buf: Vec::new(),
len: 0,
}
}
}
struct AssertValidityState {
module: Module<Bundle>,
blocks: Vec<Block>,
visible_exprs: VisibleExprsStack,
target_states: HashMap<Interned<TargetBase>, TargetState>,
}
enum GetTargetStatesError {
NotFound,
IsGlobal,
FoundSimIoForGlobal(crate::expr::ops::SimIoForGlobal),
}
impl AssertValidityState {
fn make_block_index(&mut self, block: Block) -> usize {
let retval = self.blocks.len();
@ -1605,48 +1716,79 @@ impl AssertValidityState {
}
fn get_target_states<'a>(
&'a self,
target: &Target,
target: Target,
process_target_state: &dyn Fn(&'a TargetState, bool),
) -> Result<(), ()> {
match target {
Target::Base(target_base) => {
let target_state = self.get_base_state(*target_base)?;
process_target_state(target_state, false);
Ok(())
}
Target::Child(target_child) => self.get_target_states(
&target_child.parent(),
&|target_state, exact_target_unknown| {
let TargetStateInner::Decomposed { subtargets } = &target_state.inner else {
unreachable!(
"TargetState::new makes TargetState tree match the Target type"
);
};
match *target_child.path_element() {
TargetPathElement::BundleField(_) => process_target_state(
subtargets
.get(&target_child.path_element())
.expect("bundle fields filled in by TargetState::new"),
exact_target_unknown,
),
TargetPathElement::ArrayElement(_) => process_target_state(
subtargets
.get(&target_child.path_element())
.expect("array elements filled in by TargetState::new"),
exact_target_unknown,
),
TargetPathElement::DynArrayElement(_) => {
for target_state in subtargets.values() {
process_target_state(target_state, true);
) -> Result<(), GetTargetStatesError> {
let mut target = target.unwrap_transparent_types();
loop {
break match target {
Target::Base(target_base) => {
let target_state = self.get_base_state(target_base)?;
process_target_state(target_state, false);
Ok(())
}
Target::Child(target_child) => match *target_child.path_element() {
TargetPathElement::BundleField(_)
| TargetPathElement::ArrayElement(_)
| TargetPathElement::DynArrayElement(_) => self.get_target_states(
*target_child.parent(),
&|target_state, exact_target_unknown| {
let TargetStateInner::Decomposed { subtargets } = &target_state.inner
else {
unreachable!(
"TargetState::new makes TargetState tree match the Target type"
);
};
match *target_child.path_element() {
TargetPathElement::BundleField(_) => process_target_state(
subtargets
.get(&target_child.path_element())
.expect("bundle fields filled in by TargetState::new"),
exact_target_unknown,
),
TargetPathElement::ArrayElement(_) => process_target_state(
subtargets
.get(&target_child.path_element())
.expect("array elements filled in by TargetState::new"),
exact_target_unknown,
),
TargetPathElement::DynArrayElement(_) => {
for target_state in subtargets.values() {
process_target_state(target_state, true);
}
}
TargetPathElement::TraceAsStringInner(_)
| TargetPathElement::ToTraceAsString(_) => unreachable!(),
}
}
},
),
TargetPathElement::TraceAsStringInner(_)
| TargetPathElement::ToTraceAsString(_) => {
target = *target_child.parent();
continue;
}
},
),
};
}
}
fn get_base_state(&self, target_base: Interned<TargetBase>) -> Result<&TargetState, ()> {
self.target_states.get(&target_base).ok_or(())
fn get_base_state(
&self,
target_base: Interned<TargetBase>,
) -> Result<&TargetState, GetTargetStatesError> {
match *target_base {
TargetBase::ModuleIO(_)
| TargetBase::MemPort(_)
| TargetBase::Reg(_)
| TargetBase::RegSync(_)
| TargetBase::RegAsync(_)
| TargetBase::Wire(_)
| TargetBase::Instance(_) => self
.target_states
.get(&target_base)
.ok_or(GetTargetStatesError::NotFound),
TargetBase::FormalInput(_) => Err(GetTargetStatesError::IsGlobal),
TargetBase::SimIoForGlobal(v) => Err(GetTargetStatesError::FoundSimIoForGlobal(v)),
}
}
#[track_caller]
fn insert_new_base(&mut self, target_base: Interned<TargetBase>, declared_in_block: usize) {
@ -1693,6 +1835,7 @@ impl AssertValidityState {
&TargetPathElement::BundleField(_) => {
let field = sub_target_state
.target
.without_trailing_transparent_path_elements()
.child()
.expect("known to be a child")
.bundle_field()
@ -1716,6 +1859,8 @@ impl AssertValidityState {
TargetPathElement::DynArrayElement { .. } => {
Self::set_connect_target_written(sub_target_state, is_lhs, block, true);
}
TargetPathElement::TraceAsStringInner(_)
| TargetPathElement::ToTraceAsString(_) => unreachable!("never added"),
}
}
}
@ -1733,19 +1878,33 @@ impl AssertValidityState {
debug_assert!(!is_lhs, "the ModuleBuilder asserts lhs.target().is_some()");
return;
};
let result = self.get_target_states(&target, &|target_state, exact_target_unknown| {
let result = self.get_target_states(*target, &|target_state, exact_target_unknown| {
Self::set_connect_target_written(target_state, is_lhs, block, exact_target_unknown);
});
if result.is_err() {
if is_lhs {
panic!("at {source_location}: tried to connect to not-yet-defined item: {target}");
} else {
match result {
Ok(()) => {}
Err(GetTargetStatesError::NotFound) => {
if is_lhs {
panic!(
"at {source_location}: tried to connect to not-yet-defined item: {target}"
);
} else {
panic!(
"at {source_location}: tried to connect from not-yet-defined item: {target}"
);
}
}
Err(GetTargetStatesError::IsGlobal) => {
// no error
}
Err(GetTargetStatesError::FoundSimIoForGlobal(v)) => {
panic!(
"at {source_location}: tried to connect from not-yet-defined item: {target}"
);
"at {source_location}: fayalite::expr::ops::SimIoForGlobal is not allowed in Modules: {v:?}"
)
}
}
}
#[track_caller]
fn process_conditional_sub_blocks(
&mut self,
parent_block: usize,
@ -1759,17 +1918,40 @@ impl AssertValidityState {
}
}
#[track_caller]
fn assert_expr_validity<T: Type>(&mut self, expr: Expr<T>, source_location: SourceLocation) {
let mut visitor = AssertExprValidity { state: self };
match visitor.visit_expr(&expr) {
Ok(()) => {}
Err(e) => match e {
InvalidExpr::ExprIsNotVisible(expr) => {
if let Some(target) = expr.target() {
panic!(
"at {source_location}: expression isn't visible here, it's defined:\n\
at {}: {expr:?}",
target.base().source_location(),
);
} else {
panic!("at {source_location}: expression isn't visible here: {expr:?}");
}
}
},
}
}
#[track_caller]
fn assert_subtree_validity(&mut self, block: usize) {
self.visible_exprs.push_empty();
let module = self.module;
if block == 0 {
for module_io in &*module.module_io {
self.insert_new_base(TargetBase::intern_sized(module_io.module_io.into()), block);
self.visible_exprs.top().insert(module_io.module_io.into());
}
}
let Block { memories, stmts } = self.blocks[block];
for m in memories {
for port in m.ports() {
self.insert_new_base(TargetBase::intern_sized(port.into()), block);
self.visible_exprs.top().insert(port.into());
}
}
for stmt in stmts {
@ -1783,44 +1965,104 @@ impl AssertValidityState {
} = connect;
self.set_connect_side_written(lhs, source_location, true, block);
self.set_connect_side_written(rhs, source_location, false, block);
self.assert_expr_validity(lhs, source_location);
self.assert_expr_validity(rhs, source_location);
}
Stmt::Formal(formal) => {
let StmtFormal {
kind: _,
clk,
pred,
en,
text: _,
source_location,
} = formal;
self.assert_expr_validity(clk, source_location);
self.assert_expr_validity(pred, source_location);
self.assert_expr_validity(en, source_location);
}
Stmt::Formal(_) => {}
Stmt::If(if_stmt) => {
let sub_blocks = if_stmt.blocks.map(|block| self.make_block_index(block));
let StmtIf {
cond,
source_location,
blocks: sub_blocks,
} = if_stmt;
self.assert_expr_validity(cond, source_location);
let sub_blocks = sub_blocks.map(|block| self.make_block_index(block));
self.process_conditional_sub_blocks(block, sub_blocks)
}
Stmt::Match(match_stmt) => {
match_stmt.assert_validity();
let StmtMatch {
expr,
source_location,
blocks: sub_blocks,
} = match_stmt;
self.assert_expr_validity(expr, source_location);
let sub_blocks = Vec::from_iter(
match_stmt
.blocks
sub_blocks
.into_iter()
.map(|block| self.make_block_index(block)),
);
self.process_conditional_sub_blocks(block, sub_blocks.iter().copied())
self.visible_exprs.push_empty();
let visible_exprs_top = self.visible_exprs.top();
for variant_index in 0..expr.ty().variants().len() {
visible_exprs_top
.insert(<VariantAccess>::new_by_index(expr, variant_index).into());
}
self.process_conditional_sub_blocks(block, sub_blocks.iter().copied());
self.visible_exprs.pop();
}
Stmt::Declaration(StmtDeclaration::Wire(StmtWire {
annotations: _,
wire,
})) => self.insert_new_base(TargetBase::intern_sized(wire.into()), block),
})) => {
self.insert_new_base(TargetBase::intern_sized(wire.into()), block);
self.visible_exprs.top().insert(wire.into());
}
Stmt::Declaration(StmtDeclaration::Reg(StmtReg {
annotations: _,
reg,
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
})) => {
self.assert_expr_validity(reg.clock_domain(), reg.source_location());
if let Some(init) = reg.init() {
self.assert_expr_validity(init, reg.source_location());
}
self.insert_new_base(TargetBase::intern_sized(reg.into()), block);
self.visible_exprs.top().insert(reg.into());
}
Stmt::Declaration(StmtDeclaration::RegSync(StmtReg {
annotations: _,
reg,
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
})) => {
self.assert_expr_validity(reg.clock_domain(), reg.source_location());
if let Some(init) = reg.init() {
self.assert_expr_validity(init, reg.source_location());
}
self.insert_new_base(TargetBase::intern_sized(reg.into()), block);
self.visible_exprs.top().insert(reg.into());
}
Stmt::Declaration(StmtDeclaration::RegAsync(StmtReg {
annotations: _,
reg,
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
})) => {
self.assert_expr_validity(reg.clock_domain(), reg.source_location());
if let Some(init) = reg.init() {
self.assert_expr_validity(init, reg.source_location());
}
self.insert_new_base(TargetBase::intern_sized(reg.into()), block);
self.visible_exprs.top().insert(reg.into());
}
Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
annotations: _,
instance,
})) => self.insert_new_base(TargetBase::intern_sized(instance.into()), block),
})) => {
self.insert_new_base(TargetBase::intern_sized(instance.into()), block);
self.visible_exprs.top().insert(instance.into());
}
}
}
self.visible_exprs.pop();
}
#[track_caller]
fn assert_validity(&mut self) {
@ -1849,6 +2091,143 @@ impl AssertValidityState {
}
}
struct AssertExprValidity<'a> {
state: &'a mut AssertValidityState,
}
enum InvalidExpr {
ExprIsNotVisible(Expr<CanonicalType>),
}
impl transform::visit::Visitor for AssertExprValidity<'_> {
type Error = InvalidExpr;
fn visit_expr_enum(&mut self, v: &ExprEnum) -> Result<(), Self::Error> {
match v {
ExprEnum::UIntLiteral(_)
| ExprEnum::SIntLiteral(_)
| ExprEnum::BoolLiteral(_)
| ExprEnum::PhantomConst(_)
| ExprEnum::BundleLiteral(_)
| ExprEnum::ArrayLiteral(_)
| ExprEnum::EnumLiteral(_)
| ExprEnum::Uninit(_)
| ExprEnum::NotU(_)
| ExprEnum::NotS(_)
| ExprEnum::NotB(_)
| ExprEnum::Neg(_)
| ExprEnum::BitAndU(_)
| ExprEnum::BitAndS(_)
| ExprEnum::BitAndB(_)
| ExprEnum::BitOrU(_)
| ExprEnum::BitOrS(_)
| ExprEnum::BitOrB(_)
| ExprEnum::BitXorU(_)
| ExprEnum::BitXorS(_)
| ExprEnum::BitXorB(_)
| ExprEnum::AddU(_)
| ExprEnum::AddS(_)
| ExprEnum::SubU(_)
| ExprEnum::SubS(_)
| ExprEnum::MulU(_)
| ExprEnum::MulS(_)
| ExprEnum::DivU(_)
| ExprEnum::DivS(_)
| ExprEnum::RemU(_)
| ExprEnum::RemS(_)
| ExprEnum::DynShlU(_)
| ExprEnum::DynShlS(_)
| ExprEnum::DynShrU(_)
| ExprEnum::DynShrS(_)
| ExprEnum::FixedShlU(_)
| ExprEnum::FixedShlS(_)
| ExprEnum::FixedShrU(_)
| ExprEnum::FixedShrS(_)
| ExprEnum::CmpLtB(_)
| ExprEnum::CmpLeB(_)
| ExprEnum::CmpGtB(_)
| ExprEnum::CmpGeB(_)
| ExprEnum::CmpEqB(_)
| ExprEnum::CmpNeB(_)
| ExprEnum::CmpLtU(_)
| ExprEnum::CmpLeU(_)
| ExprEnum::CmpGtU(_)
| ExprEnum::CmpGeU(_)
| ExprEnum::CmpEqU(_)
| ExprEnum::CmpNeU(_)
| ExprEnum::CmpLtS(_)
| ExprEnum::CmpLeS(_)
| ExprEnum::CmpGtS(_)
| ExprEnum::CmpGeS(_)
| ExprEnum::CmpEqS(_)
| ExprEnum::CmpNeS(_)
| ExprEnum::CastUIntToUInt(_)
| ExprEnum::CastUIntToSInt(_)
| ExprEnum::CastSIntToUInt(_)
| ExprEnum::CastSIntToSInt(_)
| ExprEnum::CastBoolToUInt(_)
| ExprEnum::CastBoolToSInt(_)
| ExprEnum::CastUIntToBool(_)
| ExprEnum::CastSIntToBool(_)
| ExprEnum::CastBoolToSyncReset(_)
| ExprEnum::CastUIntToSyncReset(_)
| ExprEnum::CastSIntToSyncReset(_)
| ExprEnum::CastBoolToAsyncReset(_)
| ExprEnum::CastUIntToAsyncReset(_)
| ExprEnum::CastSIntToAsyncReset(_)
| ExprEnum::CastSyncResetToBool(_)
| ExprEnum::CastSyncResetToUInt(_)
| ExprEnum::CastSyncResetToSInt(_)
| ExprEnum::CastSyncResetToReset(_)
| ExprEnum::CastAsyncResetToBool(_)
| ExprEnum::CastAsyncResetToUInt(_)
| ExprEnum::CastAsyncResetToSInt(_)
| ExprEnum::CastAsyncResetToReset(_)
| ExprEnum::CastResetToBool(_)
| ExprEnum::CastResetToUInt(_)
| ExprEnum::CastResetToSInt(_)
| ExprEnum::CastBoolToClock(_)
| ExprEnum::CastUIntToClock(_)
| ExprEnum::CastSIntToClock(_)
| ExprEnum::CastClockToBool(_)
| ExprEnum::CastClockToUInt(_)
| ExprEnum::CastClockToSInt(_)
| ExprEnum::FieldAccess(_)
| ExprEnum::ArrayIndex(_)
| ExprEnum::DynArrayIndex(_)
| ExprEnum::ReduceBitAndU(_)
| ExprEnum::ReduceBitAndS(_)
| ExprEnum::ReduceBitOrU(_)
| ExprEnum::ReduceBitOrS(_)
| ExprEnum::ReduceBitXorU(_)
| ExprEnum::ReduceBitXorS(_)
| ExprEnum::SliceUInt(_)
| ExprEnum::SliceSInt(_)
| ExprEnum::CastToBits(_)
| ExprEnum::CastBitsTo(_)
| ExprEnum::ToTraceAsString(_)
| ExprEnum::TraceAsStringAsInner(_)
| ExprEnum::StructuralEq(_)
| ExprEnum::FormalInput(_) => v.default_visit(self),
ExprEnum::VariantAccess(_)
| ExprEnum::ModuleIO(_)
| ExprEnum::Instance(_)
| ExprEnum::Wire(_)
| ExprEnum::Reg(_)
| ExprEnum::RegSync(_)
| ExprEnum::RegAsync(_)
| ExprEnum::MemPort(_) => {
if self.state.visible_exprs.contains(v) {
// no need to visit inner expressions, we already checked them before adding them to visible_exprs
Ok(())
} else {
Err(InvalidExpr::ExprIsNotVisible(v.to_expr()))
}
}
ExprEnum::SimIoForGlobal(_) => Err(InvalidExpr::ExprIsNotVisible(v.to_expr())),
}
}
}
impl<T: BundleType> Module<T> {
/// you generally should use the [`#[hdl_module]`][`crate::hdl_module`] proc-macro and [`ModuleBuilder`] instead
#[track_caller]
@ -1869,7 +2248,7 @@ impl<T: BundleType> Module<T> {
clocks_for_past,
simulation: Some(simulation),
}) => {
let mut clocks_for_past_set = HashSet::default();
let mut clocks_for_past_set = HashSet::<Target>::default();
*clocks_for_past = clocks_for_past
.iter()
.copied()
@ -1890,7 +2269,9 @@ impl<T: BundleType> Module<T> {
}
if simulation.sim_io_to_generator_map.len() > module_io.len() {
// if sim_io_to_generator_map is bigger, then there must be a key that's not in module_io
let module_io_set = HashSet::from_iter(module_io.iter().map(|v| v.module_io));
let module_io_set = HashSet::<ModuleIO<CanonicalType>>::from_iter(
module_io.iter().map(|v| v.module_io),
);
for (sim_io, generator_io) in simulation.sim_io_to_generator_map.iter() {
if !module_io_set.contains(&**sim_io) {
panic!(
@ -1974,6 +2355,7 @@ impl<T: BundleType> Module<T> {
AssertValidityState {
module: self.canonical(),
blocks: vec![],
visible_exprs: VisibleExprsStack::default(),
target_states: HashMap::with_capacity_and_hasher(64, Default::default()),
}
.assert_validity();
@ -2079,7 +2461,7 @@ impl<T: Type, R: ResetType> RegBuilder<Expr<ClockDomain<R>>, Option<Expr<T>>, T>
ty,
} = self;
ModuleBuilder::with(|module_builder| {
let scoped_name = ScopedNameId(module_builder.name, NameId(name, Id::new()));
let scoped_name = ScopedNameId(module_builder.name.into(), NameId(name, Id::new()));
let reg = Reg::new_unchecked(scoped_name, source_location, ty, clock_domain, init);
let retval = reg.to_expr();
// convert before borrow_mut since ModuleBuilder could be reentered by T::canonical()
@ -2475,6 +2857,9 @@ pub fn annotate<T: Type>(target: Expr<T>, annotations: impl IntoAnnotations) {
instance,
}
.into(),
TargetBase::FormalInput(_) | TargetBase::SimIoForGlobal(_) => {
unreachable!("not a valid annotation target")
}
};
ModuleBuilder::with(|m| {
unwrap!(m.impl_.borrow_mut().body.builder_normal_body_opt())
@ -2489,7 +2874,7 @@ pub fn annotate<T: Type>(target: Expr<T>, annotations: impl IntoAnnotations) {
#[track_caller]
pub fn wire_with_loc<T: Type>(name: &str, source_location: SourceLocation, ty: T) -> Expr<T> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let wire = Wire::<T>::new_unchecked(scoped_name, source_location, ty);
let retval = wire.to_expr();
let canonical_wire = wire.canonical();
@ -2521,7 +2906,7 @@ fn incomplete_declaration(
source_location: SourceLocation,
) -> Rc<RefCell<IncompleteDeclaration>> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let retval = Rc::new(RefCell::new(IncompleteDeclaration::Incomplete {
name: scoped_name,
source_location,
@ -2697,7 +3082,7 @@ pub fn instance_with_loc<T: BundleType>(
source_location: SourceLocation,
) -> Expr<T> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let instance = Instance::<T> {
scoped_name,
instantiated,
@ -2736,7 +3121,7 @@ fn memory_impl<Element: Type, Len: Size>(
source_location: SourceLocation,
) -> MemBuilder<Element, Len> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let (retval, target_mem) = MemBuilder::new(scoped_name, source_location, mem_element_type);
let mut impl_ = m.impl_.borrow_mut();
let body = impl_.body.builder_normal_body();
@ -2891,7 +3276,7 @@ impl<T: Type> ModuleIO<T> {
NameId(self.bundle_field.name, self.id)
}
pub fn scoped_name(&self) -> ScopedNameId {
ScopedNameId(self.containing_module_name, self.name_id())
ScopedNameId(self.containing_module_name.into(), self.name_id())
}
pub fn source_location(&self) -> SourceLocation {
self.source_location
@ -2964,10 +3349,102 @@ impl fmt::Debug for InstantiatedModule {
}
}
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
pub enum InstantiatedModuleOrGlobal {
Global,
InstantiatedModule(InstantiatedModule),
}
impl InstantiatedModuleOrGlobal {
pub fn leaf_module_source_location(self) -> SourceLocation {
match self {
Self::Global => SourceLocation::builtin(),
Self::InstantiatedModule(v) => v.leaf_module().source_location(),
}
}
}
impl From<InstantiatedModule> for InstantiatedModuleOrGlobal {
fn from(value: InstantiatedModule) -> Self {
Self::InstantiatedModule(value)
}
}
impl fmt::Debug for InstantiatedModuleOrGlobal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Global => f.write_str("Global"),
Self::InstantiatedModule(v) => v.fmt(f),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct TargetInInstantiatedModule {
pub instantiated_module: InstantiatedModule,
pub target: Target,
pub struct TargetInInstantiatedModuleOrGlobal {
instantiated_module_or_global: InstantiatedModuleOrGlobal,
target: Target,
}
impl TargetInInstantiatedModuleOrGlobal {
#[track_caller]
pub fn new(instantiated_module_or_global: InstantiatedModuleOrGlobal, target: Target) -> Self {
match (
instantiated_module_or_global,
target.base().target_name().0.0,
) {
(InstantiatedModuleOrGlobal::Global, NameIdOrGlobal::Global)
| (InstantiatedModuleOrGlobal::InstantiatedModule(_), NameIdOrGlobal::NameId(_)) => {
Self {
instantiated_module_or_global,
target,
}
}
(InstantiatedModuleOrGlobal::Global, NameIdOrGlobal::NameId(_))
| (InstantiatedModuleOrGlobal::InstantiatedModule(_), NameIdOrGlobal::Global) => {
panic!(
"instantiated_module_or_global doesn't match target.base().target_name().0.0:\n\
instantiated_module_or_global: {instantiated_module_or_global:?}\n\
target: {target:?}"
)
}
}
}
#[track_caller]
pub fn from_target(
instantiated_module: impl Into<InstantiatedModuleOrGlobal>,
target: Target,
) -> Self {
let instantiated_module = instantiated_module.into();
Self {
instantiated_module_or_global: match target.base().target_name().0.0 {
NameIdOrGlobal::Global => InstantiatedModuleOrGlobal::Global,
NameIdOrGlobal::NameId(name_id) => {
let InstantiatedModuleOrGlobal::InstantiatedModule(instantiated_module) =
instantiated_module
else {
panic!(
"target is in a module, but no InstantiatedModule was provided: {target:#?}"
);
};
assert_eq!(
name_id,
instantiated_module.leaf_module().name_id(),
"target isn't contained in module:\n\
target: {target:#?}\n\
instantiated_module: {instantiated_module:?}",
);
InstantiatedModuleOrGlobal::InstantiatedModule(instantiated_module)
}
},
target,
}
}
pub fn instantiated_module_or_global(self) -> InstantiatedModuleOrGlobal {
self.instantiated_module_or_global
}
pub fn target(self) -> Target {
self.target
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
pub mod deduce_resets;
pub mod deduce_structural_eq_flags;
pub mod simplify_enums;
pub mod simplify_memories;
pub mod visit;

View file

@ -10,7 +10,8 @@ use crate::{
ops::{self, ArrayLiteral},
target::{
Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement,
TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString,
TargetPathTraceAsStringInner,
},
},
formal::FormalKind,
@ -26,6 +27,7 @@ use crate::{
prelude::*,
reset::{ResetType, ResetTypeDispatch},
sim::ExternModuleSimulation,
ty::TraceAsString,
util::{HashMap, HashSet},
};
use hashbrown::hash_map::Entry;
@ -103,6 +105,10 @@ enum ResetsLayout {
element: Interned<ResetsLayout>,
reset_count: usize,
},
Transparent {
inner: Interned<ResetsLayout>,
reset_count: usize,
},
}
impl ResetsLayout {
@ -112,7 +118,8 @@ impl ResetsLayout {
ResetsLayout::Reset | ResetsLayout::SyncReset | ResetsLayout::AsyncReset => 1,
ResetsLayout::Bundle { reset_count, .. }
| ResetsLayout::Enum { reset_count, .. }
| ResetsLayout::Array { reset_count, .. } => reset_count,
| ResetsLayout::Array { reset_count, .. }
| ResetsLayout::Transparent { reset_count, .. } => reset_count,
}
}
fn new(ty: CanonicalType) -> Self {
@ -166,6 +173,13 @@ impl ResetsLayout {
CanonicalType::Clock(_) => ResetsLayout::NoResets,
CanonicalType::PhantomConst(_) => ResetsLayout::NoResets,
CanonicalType::DynSimOnly(_) => ResetsLayout::NoResets,
CanonicalType::TraceAsString(ty) => {
let inner = ResetsLayout::new(ty.inner_ty()).intern_sized();
ResetsLayout::Transparent {
inner,
reset_count: inner.reset_count(),
}
}
}
}
}
@ -315,6 +329,12 @@ impl ResetGraph {
} => {
self.append_new_nodes_for_layout(*element, node_indexes, source_location);
}
ResetsLayout::Transparent {
inner,
reset_count: _,
} => {
self.append_new_nodes_for_layout(*inner, node_indexes, source_location);
}
}
}
}
@ -357,6 +377,21 @@ impl Resets {
node_indexes: self.node_indexes,
}
}
fn trace_as_string_inner(self) -> Self {
let trace_as_string = TraceAsString::from_canonical(self.ty);
let ResetsLayout::Transparent {
inner,
reset_count: _,
} = self.layout
else {
unreachable!();
};
Self {
ty: trace_as_string.inner_ty(),
layout: *inner,
node_indexes: self.node_indexes,
}
}
fn bundle_fields(self) -> impl Iterator<Item = Self> {
let bundle = Bundle::from_canonical(self.ty);
let ResetsLayout::Bundle {
@ -480,6 +515,17 @@ impl Resets {
CanonicalType::SyncReset(SyncReset)
},
),
CanonicalType::TraceAsString(ty) => Ok(CanonicalType::TraceAsString(
ty.with_new_inner_ty(
self.array_elements()
.substituted_type(
reset_graph,
fallback_to_sync_reset,
fallback_error_source_location,
)?
.intern_sized(),
),
)),
}
}
}
@ -1013,7 +1059,8 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
| CanonicalType::Bundle(_)
| CanonicalType::Reset(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!(),
| CanonicalType::DynSimOnly(_)
| CanonicalType::TraceAsString(_) => unreachable!(),
$(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)*
}
};
@ -1024,7 +1071,8 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
CanonicalType::Array(_)
| CanonicalType::Enum(_)
| CanonicalType::Bundle(_)
| CanonicalType::Reset(_) => unreachable!(),
| CanonicalType::Reset(_)
| CanonicalType::TraceAsString(_) => unreachable!(),
CanonicalType::PhantomConst(_) |
CanonicalType::DynSimOnly(_) => Expr::expr_enum(arg),
$(CanonicalType::$Variant(_) => {
@ -1156,6 +1204,11 @@ impl<P: Pass> RunPass<P> for ExprEnum {
ExprEnum::SliceSInt(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::CastToBits(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::CastBitsTo(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::TraceAsStringAsInner(expr) => {
Ok(expr.run_pass(pass_args)?.map(ExprEnum::from))
}
ExprEnum::ToTraceAsString(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::StructuralEq(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::ModuleIO(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::Instance(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::Wire(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
@ -1163,6 +1216,10 @@ impl<P: Pass> RunPass<P> for ExprEnum {
ExprEnum::RegSync(expr) => reg_expr_run_pass(expr, pass_args),
ExprEnum::RegAsync(expr) => reg_expr_run_pass(expr, pass_args),
ExprEnum::MemPort(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::FormalInput(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)),
ExprEnum::SimIoForGlobal(_) => {
unreachable!("Module is known to not contain SimIoForGlobal from validation")
}
}
}
}
@ -1536,6 +1593,96 @@ impl RunPassExpr for ops::CastBitsTo {
}
}
impl RunPassExpr for ops::TraceAsStringAsInner {
type Args<'a> = [Expr<CanonicalType>; 1];
fn args<'a>(&'a self) -> Self::Args<'a> {
[Expr::canonical(self.arg())]
}
fn source_location(&self) -> Option<SourceLocation> {
None
}
fn union_parts(
&self,
resets: Resets,
args_resets: Vec<Resets>,
mut pass_args: PassArgs<'_, BuildResetGraph>,
) -> Result<(), DeduceResetsError> {
pass_args.union(resets, args_resets[0].trace_as_string_inner(), None)
}
fn new(
&self,
_ty: CanonicalType,
new_args: Vec<Expr<CanonicalType>>,
) -> Result<Self, DeduceResetsError> {
Ok(Self::new(Expr::from_canonical(new_args[0])))
}
}
impl RunPassExpr for ops::ToTraceAsString {
type Args<'a> = [Expr<CanonicalType>; 1];
fn args<'a>(&'a self) -> Self::Args<'a> {
[Expr::canonical(self.inner())]
}
fn source_location(&self) -> Option<SourceLocation> {
None
}
fn union_parts(
&self,
resets: Resets,
args_resets: Vec<Resets>,
mut pass_args: PassArgs<'_, BuildResetGraph>,
) -> Result<(), DeduceResetsError> {
pass_args.union(resets.trace_as_string_inner(), args_resets[0], None)
}
fn new(
&self,
_ty: CanonicalType,
new_args: Vec<Expr<CanonicalType>>,
) -> Result<Self, DeduceResetsError> {
Ok(Self::new(
new_args[0],
self.ty().with_new_inner_ty(new_args[0].ty().intern_sized()),
))
}
}
impl RunPassExpr for ops::StructuralEq {
type Args<'a> = [Expr<CanonicalType>; 2];
fn args<'a>(&'a self) -> Self::Args<'a> {
[self.lhs(), self.rhs()]
}
fn source_location(&self) -> Option<SourceLocation> {
None
}
fn union_parts(
&self,
_resets: Resets,
args_resets: Vec<Resets>,
mut pass_args: PassArgs<'_, BuildResetGraph>,
) -> Result<(), DeduceResetsError> {
pass_args.union(args_resets[0], args_resets[1], None)
}
fn new(
&self,
_ty: CanonicalType,
new_args: Vec<Expr<CanonicalType>>,
) -> Result<Self, DeduceResetsError> {
Ok(Self::with_flags(new_args[0], new_args[1], self.flags()))
}
}
impl RunPassExpr for ModuleIO<CanonicalType> {
type Args<'a> = [Expr<CanonicalType>; 0];
@ -1691,7 +1838,8 @@ impl RunPassDispatch for AnyReg {
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!(),
| CanonicalType::DynSimOnly(_)
| CanonicalType::TraceAsString(_) => unreachable!(),
}
})
}
@ -1818,6 +1966,7 @@ impl_run_pass_copy!([] SVAttributeAnnotation);
impl_run_pass_copy!([] UInt);
impl_run_pass_copy!([] usize);
impl_run_pass_copy!([] FormalKind);
impl_run_pass_copy!([] crate::formal::FormalInput);
impl_run_pass_copy!([] PhantomConst);
macro_rules! impl_run_pass_for_struct {
@ -2134,6 +2283,12 @@ impl<P: Pass> RunPass<P> for TargetBase {
&TargetBase::RegAsync(v) => v.into(),
TargetBase::Wire(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Wire)),
TargetBase::Instance(v) => return Ok(v.run_pass(pass_args)?.map(TargetBase::Instance)),
TargetBase::FormalInput(v) => {
return Ok(v.run_pass(pass_args)?.map(TargetBase::FormalInput));
}
TargetBase::SimIoForGlobal(_) => {
unreachable!("Module is known to not contain SimIoForGlobal from validation")
}
};
Ok(reg.run_pass(pass_args)?.map(|reg| match reg {
AnyReg::Reg(reg) => TargetBase::Reg(reg),
@ -2173,30 +2328,6 @@ impl<P: Pass> RunPass<P> for StmtDeclaration {
}
}
impl_run_pass_for_struct! {
impl[] RunPass for TargetPathBundleField {
name: _,
}
}
impl_run_pass_for_struct! {
impl[] RunPass for TargetPathArrayElement {
index: _,
}
}
impl_run_pass_for_struct! {
impl[] RunPass for TargetPathDynArrayElement {}
}
impl_run_pass_for_enum! {
impl[] RunPass for TargetPathElement {
BundleField(v),
ArrayElement(v),
DynArrayElement(v),
}
}
impl_run_pass_for_enum! {
impl[] RunPass for Target {
Base(v),
@ -2204,11 +2335,28 @@ impl_run_pass_for_enum! {
}
}
impl_run_pass_for_struct! {
#[constructor = TargetChild::new(parent, path_element)]
impl[] RunPass for TargetChild {
parent(): _,
path_element(): _,
impl<P: Pass> RunPass<P> for TargetChild {
fn run_pass(
&self,
mut pass_args: PassArgs<'_, P>,
) -> Result<PassOutput<Self, P>, DeduceResetsError> {
Ok(self.parent().run_pass(pass_args.as_mut())?.map(|parent| {
let path_element = match *self.path_element() {
TargetPathElement::BundleField(TargetPathBundleField { name: _ })
| TargetPathElement::ArrayElement(TargetPathArrayElement { index: _ })
| TargetPathElement::DynArrayElement(TargetPathDynArrayElement {})
| TargetPathElement::TraceAsStringInner(TargetPathTraceAsStringInner {}) => {
self.path_element()
}
TargetPathElement::ToTraceAsString(TargetPathToTraceAsString { ty }) => {
TargetPathElement::from(TargetPathToTraceAsString {
ty: ty.with_new_inner_ty(parent.canonical_ty().intern_sized()),
})
.intern_sized()
}
};
TargetChild::new(parent, path_element)
}))
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,28 +1,26 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
array::{Array, ArrayType},
bundle::{Bundle, BundleField, BundleType},
enum_::{Enum, EnumType, EnumVariant},
bundle::{BundleField, BundleType},
enum_::{EnumType, EnumVariant},
expr::{
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ValueType,
ops::{self, EnumLiteral},
ExprEnum,
ops::{self, EnumLiteral, StructuralEq, StructuralEqFlags},
},
hdl,
int::UInt,
intern::{Intern, InternSlice, Interned, Memoize},
memory::{DynPortType, Mem, MemPort},
memory::{DynPortType, MemPort},
module::{
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
transform::visit::{Fold, Folder},
Block, Id, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
transform::{
deduce_structural_eq_flags::deduce_structural_eq_flags,
visit::{Fold, Folder},
},
},
source_location::SourceLocation,
ty::{CanonicalType, Type},
prelude::*,
util::HashMap,
wire::Wire,
};
use core::fmt;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug)]
pub enum SimplifyEnumsError {
@ -64,6 +62,7 @@ fn contains_any_enum_types(ty: CanonicalType) -> bool {
.fields()
.iter()
.any(|field| contains_any_enum_types(field.ty)),
CanonicalType::TraceAsString(ty) => contains_any_enum_types(ty.inner_ty()),
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
@ -95,11 +94,13 @@ enum EnumTypeState {
struct ModuleState {
module_name: NameId,
expr_cache: HashMap<ExprEnum, ExprEnum>,
source_location: SourceLocation,
}
impl ModuleState {
fn gen_name(&mut self, name: &str) -> ScopedNameId {
ScopedNameId(self.module_name, NameId(name.intern(), Id::new()))
ScopedNameId(self.module_name.into(), NameId(name.intern(), Id::new()))
}
}
@ -108,6 +109,45 @@ struct State {
replacement_mem_ports: HashMap<MemPort<DynPortType>, Wire<CanonicalType>>,
kind: SimplifyEnumsKind,
module_state_stack: Vec<ModuleState>,
new_prefix_stmts_for_block: Vec<Stmt>,
new_suffix_stmts_for_block: Vec<Stmt>,
}
struct BlockScope<'a> {
state: &'a mut State,
parent_new_prefix_stmts_for_block: Vec<Stmt>,
parent_new_suffix_stmts_for_block: Vec<Stmt>,
}
impl<'a> BlockScope<'a> {
fn new(
state: &'a mut State,
new_prefix_stmts_for_block: Vec<Stmt>,
new_suffix_stmts_for_block: Vec<Stmt>,
) -> Self {
let parent_new_prefix_stmts_for_block = std::mem::replace(
&mut state.new_prefix_stmts_for_block,
new_prefix_stmts_for_block,
);
let parent_new_suffix_stmts_for_block = std::mem::replace(
&mut state.new_suffix_stmts_for_block,
new_suffix_stmts_for_block,
);
Self {
state,
parent_new_prefix_stmts_for_block,
parent_new_suffix_stmts_for_block,
}
}
}
impl Drop for BlockScope<'_> {
fn drop(&mut self) {
self.state.new_prefix_stmts_for_block =
std::mem::take(&mut self.parent_new_prefix_stmts_for_block);
self.state.new_suffix_stmts_for_block =
std::mem::take(&mut self.parent_new_suffix_stmts_for_block);
}
}
impl State {
@ -313,6 +353,24 @@ impl State {
}
Ok(())
}
fn handle_stmt_connect_trace_as_string(
&mut self,
unfolded_lhs_ty: TraceAsString,
unfolded_rhs_ty: TraceAsString,
folded_lhs: Expr<TraceAsString>,
folded_rhs: Expr<TraceAsString>,
source_location: SourceLocation,
output_stmts: &mut Vec<Stmt>,
) -> Result<(), SimplifyEnumsError> {
self.handle_stmt_connect(
unfolded_lhs_ty.inner_ty(),
unfolded_rhs_ty.inner_ty(),
ops::TraceAsStringAsInner::new(folded_lhs).to_expr(),
ops::TraceAsStringAsInner::new(folded_rhs).to_expr(),
source_location,
output_stmts,
)
}
fn handle_stmt_connect_bundle(
&mut self,
unfolded_lhs_ty: Bundle,
@ -509,6 +567,15 @@ impl State {
source_location,
output_stmts,
),
CanonicalType::TraceAsString(unfolded_lhs_ty) => self
.handle_stmt_connect_trace_as_string(
unfolded_lhs_ty,
TraceAsString::from_canonical(unfolded_rhs_ty),
Expr::from_canonical(folded_lhs),
Expr::from_canonical(folded_rhs),
source_location,
output_stmts,
),
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
@ -520,6 +587,185 @@ impl State {
| CanonicalType::DynSimOnly(_) => unreachable!(),
}
}
fn handle_enum_structural_eq(
&mut self,
unfolded_ty: Enum,
folded_lhs: Expr<CanonicalType>,
folded_rhs: Expr<CanonicalType>,
flags: StructuralEqFlags,
) -> Result<Expr<Bool>, SimplifyEnumsError> {
if flags.assume_padding_is_zeroed {
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr());
}
let enum_type_state = self.get_or_make_enum_type_state(unfolded_ty)?;
if let EnumTypeState::Unchanged = enum_type_state {
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr());
}
let module_state = self.module_state_stack.last_mut().unwrap();
let source_location = module_state.source_location;
let output_wire = Wire::new_unchecked(
module_state.gen_name("__enum_structural_eq"),
source_location,
Bool,
);
self.new_prefix_stmts_for_block.push(
StmtWire {
annotations: Interned::default(),
wire: output_wire.canonical(),
}
.into(),
);
let output_wire = output_wire.to_expr();
self.new_suffix_stmts_for_block.push(
StmtConnect {
lhs: Expr::canonical(output_wire),
rhs: Expr::canonical(false.to_expr()),
source_location,
}
.into(),
);
let tags_eq = match enum_type_state {
EnumTypeState::TagEnumAndBody(_) => StructuralEq::with_flags(
Expr::canonical(Expr::<TagAndBody<Enum, UInt>>::from_canonical(folded_lhs).tag),
Expr::canonical(Expr::<TagAndBody<Enum, UInt>>::from_canonical(folded_rhs).tag),
StructuralEqFlags {
assume_padding_is_zeroed: true,
},
)
.to_expr(),
EnumTypeState::TagUIntAndBody(_) => {
let lhs = Expr::<TagAndBody<UInt, UInt>>::from_canonical(folded_lhs).tag;
let rhs = Expr::<TagAndBody<UInt, UInt>>::from_canonical(folded_rhs).tag;
lhs.cmp_eq(rhs)
}
EnumTypeState::UInt(_) => {
let lhs_int_tag_expr = Expr::<UInt>::from_canonical(folded_lhs)
[..unfolded_ty.discriminant_bit_width()];
let rhs_int_tag_expr = Expr::<UInt>::from_canonical(folded_rhs)
[..unfolded_ty.discriminant_bit_width()];
lhs_int_tag_expr.cmp_eq(rhs_int_tag_expr)
}
EnumTypeState::Unchanged => unreachable!(),
};
let mut match_arms = Vec::with_capacity(unfolded_ty.variants().len());
for (variant_index, variant) in unfolded_ty.variants().iter().enumerate() {
let block_scope = BlockScope::new(self, vec![], vec![]);
let this = &mut *block_scope.state;
let eq = if let Some(variant_ty) = variant.ty {
let folded_lhs =
this.handle_variant_access(unfolded_ty, folded_lhs, variant_index)?;
let folded_rhs =
this.handle_variant_access(unfolded_ty, folded_rhs, variant_index)?;
this.handle_structural_eq(variant_ty, folded_lhs, folded_rhs, flags)?
} else {
true.to_expr()
};
match_arms.push(Block {
memories: [].intern_slice(),
stmts: this
.new_prefix_stmts_for_block
.drain(..)
.chain([StmtConnect {
lhs: Expr::canonical(output_wire),
rhs: Expr::canonical(eq),
source_location,
}
.into()])
.chain(this.new_suffix_stmts_for_block.drain(..))
.collect(),
});
}
let match_stmt =
self.handle_match(unfolded_ty, folded_lhs, source_location, &match_arms)?;
self.new_suffix_stmts_for_block.push(
StmtIf {
cond: tags_eq,
source_location,
blocks: [
Block {
memories: [].intern_slice(),
stmts: [match_stmt].intern_slice(),
},
Block {
memories: [].intern_slice(),
stmts: [].intern_slice(),
},
],
}
.into(),
);
Ok(output_wire)
}
fn handle_structural_eq(
&mut self,
unfolded_ty: CanonicalType,
folded_lhs: Expr<CanonicalType>,
folded_rhs: Expr<CanonicalType>,
flags: StructuralEqFlags,
) -> Result<Expr<Bool>, SimplifyEnumsError> {
if !contains_any_enum_types(unfolded_ty) {
return Ok(StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr());
}
match unfolded_ty {
CanonicalType::Array(unfolded_ty) => {
let unfolded_element_ty = unfolded_ty.element();
let mut retval = None;
for i in 0..unfolded_ty.len() {
let element_eq = self.handle_structural_eq(
unfolded_element_ty,
ops::ArrayIndex::new(Expr::from_canonical(folded_lhs), i).to_expr(),
ops::ArrayIndex::new(Expr::from_canonical(folded_rhs), i).to_expr(),
flags,
)?;
retval = Some(match retval {
Some(old_eq) => old_eq & element_eq,
None => element_eq,
});
}
Ok(retval.unwrap_or_else(|| {
StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr()
}))
}
CanonicalType::Enum(unfolded_ty) => {
self.handle_enum_structural_eq(unfolded_ty, folded_lhs, folded_rhs, flags)
}
CanonicalType::Bundle(unfolded_ty) => {
let mut retval = None;
for (i, field) in unfolded_ty.fields().iter().enumerate() {
let field_eq = self.handle_structural_eq(
field.ty,
ops::FieldAccess::new_by_index(Expr::from_canonical(folded_lhs), i)
.to_expr(),
ops::FieldAccess::new_by_index(Expr::from_canonical(folded_rhs), i)
.to_expr(),
flags,
)?;
retval = Some(match retval {
Some(old_eq) => old_eq & field_eq,
None => field_eq,
});
}
Ok(retval.unwrap_or_else(|| {
StructuralEq::with_flags(folded_lhs, folded_rhs, flags).to_expr()
}))
}
CanonicalType::TraceAsString(unfolded_ty) => self.handle_structural_eq(
unfolded_ty.inner_ty(),
*Expr::<TraceAsString>::from_canonical(folded_lhs),
*Expr::<TraceAsString>::from_canonical(folded_rhs),
flags,
),
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
| CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => unreachable!("doesn't contain any enum types"),
}
}
}
fn connect_port(
@ -528,6 +774,8 @@ fn connect_port(
rhs: Expr<CanonicalType>,
source_location: SourceLocation,
) {
let lhs = Expr::unwrap_transparent_types(lhs);
let rhs = Expr::unwrap_transparent_types(rhs);
if lhs.ty() == rhs.ty() {
stmts.push(
StmtConnect {
@ -573,6 +821,9 @@ fn connect_port(
connect_port(stmts, lhs[index], rhs[index], source_location);
}
}
(CanonicalType::TraceAsString(_), CanonicalType::TraceAsString(_)) => {
unreachable!("handled by unwrap_transparent_types")
}
(CanonicalType::Bundle(_), _)
| (CanonicalType::Enum(_), _)
| (CanonicalType::Array(_), _)
@ -584,7 +835,8 @@ fn connect_port(
| (CanonicalType::SyncReset(_), _)
| (CanonicalType::Reset(_), _)
| (CanonicalType::PhantomConst(_), _)
| (CanonicalType::DynSimOnly(_), _) => unreachable!(
| (CanonicalType::DynSimOnly(_), _)
| (CanonicalType::TraceAsString(_), _) => unreachable!(
"trying to connect memory ports:\n{:?}\n{:?}",
lhs.ty(),
rhs.ty(),
@ -641,6 +893,8 @@ impl Folder for State {
fn fold_module<T: BundleType>(&mut self, v: Module<T>) -> Result<Module<T>, Self::Error> {
self.module_state_stack.push(ModuleState {
module_name: v.name_id(),
expr_cache: HashMap::default(),
source_location: v.source_location(),
});
let retval = Fold::default_fold(v, self);
self.module_state_stack.pop();
@ -648,30 +902,51 @@ impl Folder for State {
}
fn fold_expr_enum(&mut self, op: ExprEnum) -> Result<ExprEnum, Self::Error> {
match op {
if let Some(folded_op) = self
.module_state_stack
.last()
.expect("known to be in module")
.expr_cache
.get(&op)
{
return Ok(*folded_op);
}
let folded_op = match op {
ExprEnum::EnumLiteral(op) => {
let folded_variant_value = op.variant_value().map(|v| v.fold(self)).transpose()?;
Ok(*Expr::expr_enum(self.handle_enum_literal(
*Expr::expr_enum(self.handle_enum_literal(
op.ty(),
op.variant_index(),
folded_variant_value,
)?))
)?)
}
ExprEnum::VariantAccess(op) => {
let folded_base_expr = Expr::canonical(op.base()).fold(self)?;
Ok(*Expr::expr_enum(self.handle_variant_access(
*Expr::expr_enum(self.handle_variant_access(
op.base().ty(),
folded_base_expr,
op.variant_index(),
)?))
)?)
}
ExprEnum::MemPort(mem_port) => Ok(
ExprEnum::StructuralEq(op) => {
let ty = op.lhs().ty();
assert_eq!(ty, op.rhs().ty());
let folded_lhs = Expr::canonical(op.lhs()).fold(self)?;
let folded_rhs = Expr::canonical(op.rhs()).fold(self)?;
*Expr::expr_enum(self.handle_structural_eq(
ty,
folded_lhs,
folded_rhs,
op.flags(),
)?)
}
ExprEnum::MemPort(mem_port) => {
if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
ExprEnum::Wire(wire)
} else {
ExprEnum::MemPort(mem_port.fold(self)?)
},
),
}
}
ExprEnum::UIntLiteral(_)
| ExprEnum::SIntLiteral(_)
| ExprEnum::BoolLiteral(_)
@ -772,21 +1047,33 @@ impl Folder for State {
| ExprEnum::SliceSInt(_)
| ExprEnum::CastToBits(_)
| ExprEnum::CastBitsTo(_)
| ExprEnum::TraceAsStringAsInner(_)
| ExprEnum::ToTraceAsString(_)
| ExprEnum::ModuleIO(_)
| ExprEnum::Instance(_)
| ExprEnum::Wire(_)
| ExprEnum::Reg(_)
| ExprEnum::RegSync(_)
| ExprEnum::RegAsync(_) => op.default_fold(self),
}
| ExprEnum::RegAsync(_)
| ExprEnum::FormalInput(_)
| ExprEnum::SimIoForGlobal(_) => op.default_fold(self)?,
};
self.module_state_stack
.last_mut()
.expect("known to be in module")
.expr_cache
.insert(op, folded_op);
Ok(folded_op)
}
fn fold_block(&mut self, block: Block) -> Result<Block, Self::Error> {
let block_scope = BlockScope::new(self, vec![], vec![]);
let this = &mut *block_scope.state;
let mut memories = vec![];
let mut stmts = vec![];
for memory in block.memories {
let old_element_ty = memory.array_type().element();
let new_element_ty = memory.array_type().element().fold(self)?;
let new_element_ty = memory.array_type().element().fold(this)?;
if new_element_ty != old_element_ty {
let mut new_ports = vec![];
for port in memory.ports() {
@ -812,7 +1099,7 @@ impl Folder for State {
continue;
}
let wire = Wire::new_unchecked(
self.module_state_stack
this.module_state_stack
.last_mut()
.unwrap()
.gen_name(&format!(
@ -836,7 +1123,7 @@ impl Folder for State {
Expr::canonical(wire.to_expr()),
port.source_location(),
);
self.replacement_mem_ports.insert(port, wire.canonical());
this.replacement_mem_ports.insert(port, wire.canonical());
}
memories.push(Mem::new_unchecked(
memory.scoped_name(),
@ -851,10 +1138,12 @@ impl Folder for State {
memory.mem_annotations(),
));
} else {
memories.push(memory.fold(self)?);
memories.push(memory.fold(this)?);
}
}
stmts.extend_from_slice(&block.stmts.fold(self)?);
stmts.extend_from_slice(&block.stmts.fold(this)?);
stmts.splice(0..0, this.new_prefix_stmts_for_block.drain(..));
stmts.extend_from_slice(&this.new_suffix_stmts_for_block);
Ok(Block {
memories: Intern::intern_owned(memories),
stmts: Intern::intern_owned(stmts),
@ -936,7 +1225,8 @@ impl Folder for State {
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => canonical_type.default_fold(self),
| CanonicalType::DynSimOnly(_)
| CanonicalType::TraceAsString(_) => canonical_type.default_fold(self),
}
}
@ -975,10 +1265,13 @@ pub fn simplify_enums(
module: Interned<Module<Bundle>>,
kind: SimplifyEnumsKind,
) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
let module = deduce_structural_eq_flags(module);
module.fold(&mut State {
enum_types: HashMap::default(),
replacement_mem_ports: HashMap::default(),
kind,
module_state_stack: vec![],
new_prefix_stmts_for_block: vec![],
new_suffix_stmts_for_block: vec![],
})
}

View file

@ -90,7 +90,7 @@ impl MemSplit {
}
}
fn new(element_type: CanonicalType) -> Self {
match element_type {
match element_type.unwrap_transparent_types() {
CanonicalType::Bundle(bundle_ty) => MemSplit::Bundle {
fields: bundle_ty
.fields()
@ -195,6 +195,7 @@ impl MemSplit {
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"),
CanonicalType::DynSimOnly(_) => todo!("memory containing sim-only values"),
CanonicalType::TraceAsString(_) => unreachable!("handled by unwrap_transparent_types"),
}
}
}
@ -306,7 +307,9 @@ impl SplitMemState<'_, '_> {
let outer_mem_name_path_len = self.mem_name_path.len();
match self.split {
MemSplit::Bundle { fields } => {
let CanonicalType::Bundle(bundle_type) = self.element_type else {
let CanonicalType::Bundle(bundle_type) =
self.element_type.unwrap_transparent_types()
else {
unreachable!();
};
for ((field, field_offset), split) in bundle_type
@ -321,7 +324,10 @@ impl SplitMemState<'_, '_> {
let field_ty_bit_width = field.ty.bit_width();
self.split_state_stack.push_map(
|e: Expr<CanonicalType>| {
Expr::field(Expr::<Bundle>::from_canonical(e), &field.name)
Expr::field(
Expr::<Bundle>::from_canonical(Expr::unwrap_transparent_types(e)),
&field.name,
)
},
|initial_value_element| {
let Some(field_offset) = field_offset.only_bit_width() else {
@ -377,8 +383,8 @@ impl SplitMemState<'_, '_> {
};
self.output_stmts.push(
StmtConnect {
lhs: Expr::field(port_expr, name),
rhs: Expr::field(wire_expr, name),
lhs: Expr::unwrap_transparent_types(Expr::field(port_expr, name)),
rhs: Expr::unwrap_transparent_types(Expr::field(wire_expr, name)),
source_location: port.source_location(),
}
.into(),
@ -389,7 +395,8 @@ impl SplitMemState<'_, '_> {
self.output_mems.push(new_mem);
}
MemSplit::Array { elements } => {
let CanonicalType::Array(array_type) = self.element_type else {
let CanonicalType::Array(array_type) = self.element_type.unwrap_transparent_types()
else {
unreachable!();
};
let element_type = array_type.element();
@ -398,7 +405,7 @@ impl SplitMemState<'_, '_> {
self.mem_name_path.truncate(outer_mem_name_path_len);
write!(self.mem_name_path, "_{index}").unwrap();
self.split_state_stack.push_map(
|e| Expr::<Array>::from_canonical(e)[index],
|e| Expr::<Array>::from_canonical(Expr::unwrap_transparent_types(e))[index],
|initial_value_element| {
&initial_value_element[index * element_bit_width..][..element_bit_width]
},
@ -464,7 +471,7 @@ impl ModuleState {
assert_eq!(memory_element_array_range_len % input_array_type.len(), 0);
let chunk_size = memory_element_array_range_len / input_array_type.len();
for index in 0..input_array_type.len() {
let map = |e| Expr::<Array>::from_canonical(e)[index];
let map = |e| Expr::<Array>::from_canonical(Expr::unwrap_transparent_types(e))[index];
let wire_rdata = wire_rdata.map(map);
let wire_wdata = wire_wdata.map(map);
let wire_wmask = wire_wmask.map(map);
@ -505,8 +512,8 @@ impl ModuleState {
port_read: Expr<CanonicalType>| {
output_stmts.push(
StmtConnect {
lhs: wire_read,
rhs: port_read,
lhs: Expr::unwrap_transparent_types(wire_read),
rhs: Expr::unwrap_transparent_types(port_read),
source_location,
}
.into(),
@ -517,8 +524,8 @@ impl ModuleState {
port_write: Expr<CanonicalType>| {
output_stmts.push(
StmtConnect {
lhs: port_write,
rhs: wire_write,
lhs: Expr::unwrap_transparent_types(port_write),
rhs: Expr::unwrap_transparent_types(wire_write),
source_location,
}
.into(),
@ -530,7 +537,8 @@ impl ModuleState {
connect_read(
output_stmts,
wire_read,
Expr::<UInt>::from_canonical(port_read).cast_bits_to(wire_read.ty()),
Expr::<UInt>::from_canonical(Expr::unwrap_transparent_types(port_read))
.cast_bits_to(wire_read.ty()),
);
};
let connect_write_enum =
@ -544,7 +552,7 @@ impl ModuleState {
);
};
loop {
match input_element_type {
match input_element_type.unwrap_transparent_types() {
CanonicalType::Bundle(_) => {
unreachable!("bundle types are always split")
}
@ -625,6 +633,9 @@ impl ModuleState {
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"),
CanonicalType::DynSimOnly(_) => todo!("memory containing sim-only values"),
CanonicalType::TraceAsString(_) => {
unreachable!("handled by unwrap_transparent_types")
}
}
break;
}

View file

@ -14,16 +14,17 @@ use crate::{
Expr, ExprEnum, ValueType, ops,
target::{
Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField,
TargetPathDynArrayElement, TargetPathElement,
TargetPathDynArrayElement, TargetPathElement, TargetPathToTraceAsString,
TargetPathTraceAsStringInner,
},
},
formal::FormalKind,
formal::{FormalInput, FormalInputKind, FormalKind},
int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue},
intern::{Intern, Interned},
memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite},
module::{
AnnotatedModuleIO, Block, BlockId, ExternModuleBody, ExternModuleParameter,
ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId,
ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId, NameIdOrGlobal,
NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf,
StmtInstance, StmtMatch, StmtReg, StmtWire,
},
@ -32,7 +33,7 @@ use crate::{
reset::{AsyncReset, Reset, ResetType, SyncReset},
sim::{ExternModuleSimulation, value::DynSimOnly},
source_location::SourceLocation,
ty::{CanonicalType, Type},
ty::{CanonicalType, TraceAsString, Type},
vendor::xilinx::{
XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation, XilinxAnnotation,
},
@ -481,4 +482,30 @@ impl<T: ?Sized + Visit<State>, State: ?Sized + Visitor> Visit<State> for &'_ mut
}
}
impl<State: ?Sized + Visitor> Visit<State> for NameIdOrGlobal {
fn visit(&self, state: &mut State) -> Result<(), <State>::Error> {
state.visit_name_id_or_global(self)
}
fn default_visit(&self, state: &mut State) -> Result<(), <State>::Error> {
match self {
Self::Global => Ok(()),
Self::NameId(name_id) => name_id.visit(state),
}
}
}
impl<State: ?Sized + Folder> Fold<State> for NameIdOrGlobal {
fn fold(self, state: &mut State) -> Result<Self, <State>::Error> {
state.fold_name_id_or_global(self)
}
fn default_fold(self, state: &mut State) -> Result<Self, <State>::Error> {
match self {
Self::Global => Ok(Self::Global),
Self::NameId(name_id) => Ok(Self::NameId(name_id.fold(state)?)),
}
}
}
include!(concat!(env!("OUT_DIR"), "/visit.rs"));

View file

@ -9,7 +9,7 @@ use crate::{
source_location::SourceLocation,
ty::{
CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
StaticType, Type, TypeProperties, impl_match_variant_as_self,
SimValueDebug, StaticType, Type, TypeProperties, impl_match_variant_as_self,
serde_impls::{SerdeCanonicalType, SerdePhantomConst},
},
};
@ -327,6 +327,15 @@ impl<T: ?Sized + PhantomConstValue> Type for PhantomConst<T> {
}
}
impl<T: ?Sized + PhantomConstValue> SimValueDebug for PhantomConst<T> {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl<T: ?Sized + PhantomConstValue> Default for PhantomConst<T>
where
Interned<T>: Default,
@ -375,6 +384,8 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst<T> {
}
impl<T: ?Sized + PhantomConstValue> HdlPartialEqImpl<Self> for PhantomConst<T> {
const TRY_STRUCTURAL_EQ: bool = true;
#[track_caller]
fn cmp_value_eq(
lhs: Self,

View file

@ -13,11 +13,11 @@ pub use crate::{
enum_::{Enum, HdlNone, HdlOption, HdlSome},
expr::{
CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr,
ReduceBits, ToExpr, ValueType, repeat,
ReduceBits, ToExpr, ToTraceAsString, ValueType, repeat,
},
formal::{
MakeFormalExpr, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset,
hdl_assert, hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover,
all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, hdl_assert,
hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover,
hdl_cover_with_enable,
},
hdl, hdl_module,
@ -37,8 +37,8 @@ pub use crate::{
value::{SimOnly, SimOnlyValue, SimValue, ToSimValue, ToSimValueWithType},
},
source_location::SourceLocation,
testing::{FormalMode, assert_formal},
ty::{AsMask, CanonicalType, Type},
testing::{FormalMode, assert_formal, checked_vcd_output},
ty::{AsMask, CanonicalType, TraceAsString, Type},
util::{ConstUsize, GenericConstUsize},
wire::Wire,
};

View file

@ -79,6 +79,7 @@ impl<T: Type, R: ResetType> Reg<T, R> {
if let Some(init) = init {
assert_eq!(ty, init.ty(), "register's type must match init type");
}
scoped_name.0.assert_is_name_id();
Self {
name: scoped_name,
source_location,
@ -94,7 +95,7 @@ impl<T: Type, R: ResetType> Reg<T, R> {
self.containing_module_name_id().0
}
pub fn containing_module_name_id(&self) -> NameId {
self.name.0
self.name.0.unwrap_name_id()
}
pub fn name(&self) -> Interned<str> {
self.name_id().0

View file

@ -1,5 +1,6 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
clock::Clock,
expr::{CastToImpl, Expr, ValueType},
@ -8,11 +9,13 @@ use crate::{
source_location::SourceLocation,
ty::{
CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter,
OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self,
OpaqueSimValueWritten, SimValueDebug, StaticType, Type, TypeProperties,
impl_match_variant_as_self,
},
util::ConstUsize,
};
use bitvec::{bits, order::Lsb0};
use std::fmt;
mod sealed {
pub trait ResetTypeSealed {}
@ -100,6 +103,15 @@ macro_rules! reset_type {
}
}
impl SimValueDebug for $name {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl $name {
pub fn type_properties(self) -> TypeProperties {
Self::TYPE_PROPERTIES

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6,9 +6,9 @@ use crate::{
int::{BoolOrIntType, SInt, UInt},
intern::{Intern, Interned, Memoize},
sim::interpreter::parts::{
StateLayout, StatePartIndex, StatePartKind, StatePartKindBigSlots, StatePartKindMemories,
StatePartKindSimOnlySlots, StatePartKindSmallSlots, StatePartLen, TypeIndexRange,
TypeLayout, get_state_part_kinds,
StateLayout, StatePartIndex, StatePartIndexRange, StatePartKind, StatePartKindBigSlots,
StatePartKindMemories, StatePartKindSimOnlySlots, StatePartKindSmallSlots, StatePartLen,
TypeIndexRange, TypeLayout, get_state_part_kinds,
},
source_location::SourceLocation,
util::{HashMap, HashSet},
@ -17,12 +17,11 @@ use bitvec::slice::BitSlice;
use num_bigint::BigInt;
use num_traits::{One, Signed, ToPrimitive, Zero};
use std::{
borrow::BorrowMut,
convert::Infallible,
fmt::{self, Write},
hash::Hash,
marker::PhantomData,
ops::{ControlFlow, Deref, DerefMut, Index, IndexMut},
ops::{ControlFlow, Deref, Index, IndexMut},
};
use vec_map::VecMap;
@ -915,6 +914,21 @@ impl<K: StatePartKind> StatePart<K> {
value: K::borrow_state(&mut self.value),
}
}
pub(crate) fn state_index_fetch_maybe_modified_flag(
&self,
part_index: StatePartIndex<K>,
) -> bool {
K::state_index_fetch_maybe_modified_flag(&self.value, part_index)
}
pub(crate) fn state_index_range_fetch_maybe_modified_flags(
&self,
part_index_range: StatePartIndexRange<K>,
) -> bool {
K::state_index_range_fetch_maybe_modified_flags(&self.value, part_index_range)
}
pub(crate) fn clear_all_maybe_modified_flags(&mut self) {
K::clear_all_maybe_modified_flags(&mut self.value)
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
@ -922,56 +936,38 @@ pub(crate) struct BorrowedStatePart<'a, K: StatePartKind> {
pub(crate) value: K::BorrowedState<'a>,
}
impl<
'a,
K: StatePartKind<
BorrowedState<'a>: DerefMut<Target: IndexMut<usize, Output = T> + BorrowMut<[T]>>,
>,
T,
> BorrowedStatePart<'a, K>
{
impl<K: StatePartKind> BorrowedStatePart<'_, K> {
pub(crate) fn get_disjoint_mut<const N: usize>(
&mut self,
indexes: [StatePartIndex<K>; N],
) -> [&mut T; N] {
(*self.value)
.borrow_mut()
.get_disjoint_mut(indexes.map(|v| v.value as usize))
.expect("indexes are disjoint")
) -> [&mut K::StateElement; N] {
K::borrowed_state_get_disjoint_mut(&mut self.value, indexes)
}
}
impl<K: StatePartKind<State: Deref<Target: Index<usize, Output = T>>>, T> Index<StatePartIndex<K>>
for StatePart<K>
{
type Output = T;
impl<K: StatePartKind> Index<StatePartIndex<K>> for StatePart<K> {
type Output = K::StateElement;
fn index(&self, index: StatePartIndex<K>) -> &Self::Output {
&self.value[index.value as usize]
K::state_index(&self.value, index)
}
}
impl<K: StatePartKind<State: DerefMut<Target: IndexMut<usize, Output = T>>>, T>
IndexMut<StatePartIndex<K>> for StatePart<K>
{
impl<K: StatePartKind> IndexMut<StatePartIndex<K>> for StatePart<K> {
fn index_mut(&mut self, index: StatePartIndex<K>) -> &mut Self::Output {
&mut self.value[index.value as usize]
K::state_index_mut(&mut self.value, index)
}
}
impl<'a, K: StatePartKind<BorrowedState<'a>: Deref<Target: Index<usize, Output = T>>>, T>
Index<StatePartIndex<K>> for BorrowedStatePart<'a, K>
{
type Output = T;
impl<K: StatePartKind> Index<StatePartIndex<K>> for BorrowedStatePart<'_, K> {
type Output = K::StateElement;
fn index(&self, index: StatePartIndex<K>) -> &Self::Output {
&self.value[index.value as usize]
K::borrowed_state_index(&self.value, index)
}
}
impl<'a, K: StatePartKind<BorrowedState<'a>: DerefMut<Target: IndexMut<usize, Output = T>>>, T>
IndexMut<StatePartIndex<K>> for BorrowedStatePart<'a, K>
{
impl<K: StatePartKind> IndexMut<StatePartIndex<K>> for BorrowedStatePart<'_, K> {
fn index_mut(&mut self, index: StatePartIndex<K>) -> &mut Self::Output {
&mut self.value[index.value as usize]
K::borrowed_state_index_mut(&mut self.value, index)
}
}
@ -984,6 +980,7 @@ macro_rules! make_state {
pub(crate) insns: Interned<Insns<InsnsBuildingDone>>,
pub(crate) pc: usize,
pub(crate) memory_write_log: Vec<(StatePartIndex<StatePartKindMemories>, usize)>,
pub(crate) assert_failed_log: Vec<usize>,
$(pub(crate) $state_plural_field: StatePart<$state_kind>,)*
$(pub(crate) $type_plural_field: StatePart<$type_kind>,)*
}
@ -994,6 +991,7 @@ macro_rules! make_state {
insns: _,
pc,
memory_write_log,
assert_failed_log,
$($state_plural_field,)*
$($type_plural_field,)*
} = self;
@ -1001,6 +999,7 @@ macro_rules! make_state {
.field("insns", &InsnsOfState(self))
.field("pc", pc)
.field("memory_write_log", memory_write_log)
.field("assert_failed_log", assert_failed_log)
$(.field(stringify!($state_plural_field), $state_plural_field))*
$(.field(stringify!($type_plural_field), $type_plural_field))*
.finish()
@ -1013,6 +1012,7 @@ macro_rules! make_state {
insns,
pc: 0,
memory_write_log: Vec::with_capacity(32),
assert_failed_log: Vec::new(),
$($state_plural_field: StatePart::new(&insns.state_layout.$state_plural_field.layout_data),)*
$($type_plural_field: StatePart::new(&insns.state_layout.ty.$type_plural_field.layout_data),)*
}
@ -1024,10 +1024,20 @@ macro_rules! make_state {
pc: self.pc,
orig_pc: &mut self.pc,
memory_write_log: &mut self.memory_write_log,
assert_failed_log: &mut self.assert_failed_log,
$($state_plural_field: self.$state_plural_field.borrow(),)*
$($type_plural_field: self.$type_plural_field.borrow(),)*
}
}
pub(crate) fn type_index_range_fetch_maybe_modified_flags(&self, range: TypeIndexRange) -> bool {
$(self.$type_plural_field.state_index_range_fetch_maybe_modified_flags(
range.$type_plural_field,
))||*
}
pub(crate) fn clear_all_maybe_modified_flags(&mut self) {
$(self.$state_plural_field.clear_all_maybe_modified_flags();)*
$(self.$type_plural_field.clear_all_maybe_modified_flags();)*
}
}
#[derive(Debug)]
@ -1037,6 +1047,7 @@ macro_rules! make_state {
pub(crate) orig_pc: &'a mut usize,
pub(crate) pc: usize,
pub(crate) memory_write_log: &'a mut Vec<(StatePartIndex<StatePartKindMemories>, usize)>,
pub(crate) assert_failed_log: &'a mut Vec<usize>,
$(pub(crate) $state_plural_field: BorrowedStatePart<'a, $state_kind>,)*
$(pub(crate) $type_plural_field: BorrowedStatePart<'a, $type_kind>,)*
}
@ -1294,6 +1305,7 @@ impl State {
insns: _,
pc,
memory_write_log: _,
assert_failed_log: _,
memories: _,
small_slots: _,
big_slots: _,
@ -1333,6 +1345,10 @@ impl BorrowedState<'_> {
self.memory_write_log.push(log_entry);
}
}
#[cold]
fn assert_failed(&mut self, assert_index: usize) {
self.assert_failed_log.push(assert_index);
}
}
fn bigint_pow2(width: usize) -> Interned<BigInt> {
@ -2100,6 +2116,19 @@ impl_insns! {
state.log_memory_write(memory, addr);
next!();
}
Assert {
#[kind = Input]
clk_triggered: StatePartIndex<StatePartKindSmallSlots>,
#[kind = Input]
pred: StatePartIndex<StatePartKindSmallSlots>,
#[kind = Immediate]
assert_index: usize,
} => {
if state.small_slots[clk_triggered] != 0 && state.small_slots[pred] == 0 {
state.assert_failed(assert_index);
}
next!();
}
Return => {
break RunResult::Return(());
}

View file

@ -236,6 +236,7 @@ pub(crate) trait StatePartKind:
type LayoutData: Send + Sync + Eq + Hash + fmt::Debug + 'static + Copy;
type State: fmt::Debug + 'static + Clone;
type BorrowedState<'a>: 'a;
type StateElement;
fn new_state(layout_data: &[Self::LayoutData]) -> Self::State;
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a>;
fn part_debug_data<BK: InsnsBuildingKind>(
@ -247,6 +248,35 @@ pub(crate) trait StatePartKind:
index: StatePartIndex<Self>,
f: &mut impl fmt::Write,
) -> fmt::Result;
fn state_index<'a>(
state: &'a Self::State,
part_index: StatePartIndex<Self>,
) -> &'a Self::StateElement;
fn state_index_mut<'a>(
state: &'a mut Self::State,
part_index: StatePartIndex<Self>,
) -> &'a mut Self::StateElement;
fn state_index_fetch_maybe_modified_flag(
state: &Self::State,
part_index: StatePartIndex<Self>,
) -> bool;
fn state_index_range_fetch_maybe_modified_flags(
state: &Self::State,
part_index_range: StatePartIndexRange<Self>,
) -> bool;
fn clear_all_maybe_modified_flags(state: &mut Self::State);
fn borrowed_state_index<'a, 'b>(
state: &'a Self::BorrowedState<'b>,
part_index: StatePartIndex<Self>,
) -> &'a Self::StateElement;
fn borrowed_state_index_mut<'a, 'b>(
state: &'a mut Self::BorrowedState<'b>,
part_index: StatePartIndex<Self>,
) -> &'a mut Self::StateElement;
fn borrowed_state_get_disjoint_mut<'a, 'b, const N: usize>(
state: &'a mut Self::BorrowedState<'b>,
part_indexes: [StatePartIndex<Self>; N],
) -> [&'a mut Self::StateElement; N];
}
macro_rules! make_state_part_kinds {
@ -272,6 +302,7 @@ impl StatePartKind for StatePartKindMemories {
type LayoutData = MemoryData<Interned<BitSlice>>;
type State = Box<[MemoryData<BitBox>]>;
type BorrowedState<'a> = &'a mut [MemoryData<BitBox>];
type StateElement = MemoryData<BitBox>;
fn new_state(layout_data: &[Self::LayoutData]) -> Self::State {
layout_data
.iter()
@ -297,19 +328,95 @@ impl StatePartKind for StatePartKindMemories {
) -> fmt::Result {
write!(f, "{:#?}", &state.memories[index])
}
fn state_index<'a>(
state: &'a Self::State,
part_index: StatePartIndex<Self>,
) -> &'a Self::StateElement {
&state[part_index.as_usize()]
}
fn state_index_mut<'a>(
state: &'a mut Self::State,
part_index: StatePartIndex<Self>,
) -> &'a mut Self::StateElement {
&mut state[part_index.as_usize()]
}
fn state_index_fetch_maybe_modified_flag(
_state: &Self::State,
_part_index: StatePartIndex<Self>,
) -> bool {
true
}
fn state_index_range_fetch_maybe_modified_flags(
_state: &Self::State,
part_index_range: StatePartIndexRange<Self>,
) -> bool {
part_index_range.len.value > 0
}
fn clear_all_maybe_modified_flags(_state: &mut Self::State) {}
fn borrowed_state_index<'a, 'b>(
state: &'a Self::BorrowedState<'b>,
part_index: StatePartIndex<Self>,
) -> &'a Self::StateElement {
&state[part_index.as_usize()]
}
fn borrowed_state_index_mut<'a, 'b>(
state: &'a mut Self::BorrowedState<'b>,
part_index: StatePartIndex<Self>,
) -> &'a mut Self::StateElement {
&mut state[part_index.as_usize()]
}
fn borrowed_state_get_disjoint_mut<'a, 'b, const N: usize>(
state: &'a mut Self::BorrowedState<'b>,
part_indexes: [StatePartIndex<Self>; N],
) -> [&'a mut Self::StateElement; N] {
state
.get_disjoint_mut(part_indexes.map(StatePartIndex::as_usize))
.expect("indexes are disjoint")
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Default)]
pub(crate) struct StateAndModified<T, M> {
pub(crate) state: T,
pub(crate) modified: M,
}
impl<T: Deref<Target = [E]>, M: Deref<Target = [bool]>, E: fmt::Debug> fmt::Debug
for StateAndModified<T, M>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list()
.entries(self.state.iter().zip(self.modified.iter().copied()).map(
|(state, modified)| {
fmt::from_fn(move |f| {
state.fmt(f)?;
if modified {
f.write_str(" (modified)")?;
}
Ok(())
})
},
))
.finish()
}
}
impl StatePartKind for StatePartKindSmallSlots {
const NAME: &'static str = "SmallSlots";
type DebugData = SlotDebugData;
type LayoutData = ();
type State = Box<[SmallUInt]>;
type BorrowedState<'a> = &'a mut [SmallUInt];
type State = StateAndModified<Box<[Self::StateElement]>, Box<[bool]>>;
type BorrowedState<'a> = StateAndModified<&'a mut [Self::StateElement], &'a mut [bool]>;
type StateElement = SmallUInt;
fn new_state(layout_data: &[Self::LayoutData]) -> Self::State {
vec![0; layout_data.len()].into_boxed_slice()
StateAndModified {
state: vec![0; layout_data.len()].into_boxed_slice(),
modified: vec![false; layout_data.len()].into_boxed_slice(),
}
}
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
state
let StateAndModified { state, modified } = state;
StateAndModified { state, modified }
}
fn part_debug_data<BK: InsnsBuildingKind>(
state_layout: &StateLayout<BK>,
@ -330,19 +437,80 @@ impl StatePartKind for StatePartKindSmallSlots {
write!(f, "{value:#x} {}", value as SmallSInt)?;
Ok(())
}
fn state_index<'a>(
state: &'a Self::State,
part_index: StatePartIndex<Self>,
) -> &'a Self::StateElement {
&state.state[part_index.as_usize()]
}
fn state_index_mut<'a>(
state: &'a mut Self::State,
part_index: StatePartIndex<Self>,
) -> &'a mut Self::StateElement {
state.modified[part_index.as_usize()] = true;
&mut state.state[part_index.as_usize()]
}
fn state_index_fetch_maybe_modified_flag(
state: &Self::State,
part_index: StatePartIndex<Self>,
) -> bool {
state.modified[part_index.as_usize()]
}
fn state_index_range_fetch_maybe_modified_flags(
state: &Self::State,
part_index_range: StatePartIndexRange<Self>,
) -> bool {
state.modified[part_index_range.start.as_usize()..]
[..part_index_range.len.as_index().as_usize()]
.contains(&true)
}
fn clear_all_maybe_modified_flags(state: &mut Self::State) {
state.modified.fill(false);
}
fn borrowed_state_index<'a, 'b>(
state: &'a Self::BorrowedState<'b>,
part_index: StatePartIndex<Self>,
) -> &'a Self::StateElement {
&state.state[part_index.as_usize()]
}
fn borrowed_state_index_mut<'a, 'b>(
state: &'a mut Self::BorrowedState<'b>,
part_index: StatePartIndex<Self>,
) -> &'a mut Self::StateElement {
state.modified[part_index.as_usize()] = true;
&mut state.state[part_index.as_usize()]
}
fn borrowed_state_get_disjoint_mut<'a, 'b, const N: usize>(
state: &'a mut Self::BorrowedState<'b>,
part_indexes: [StatePartIndex<Self>; N],
) -> [&'a mut Self::StateElement; N] {
for part_index in part_indexes {
state.modified[part_index.as_usize()] = true;
}
state
.state
.get_disjoint_mut(part_indexes.map(StatePartIndex::as_usize))
.expect("indexes are disjoint")
}
}
impl StatePartKind for StatePartKindBigSlots {
const NAME: &'static str = "BigSlots";
type DebugData = SlotDebugData;
type LayoutData = ();
type State = Box<[BigInt]>;
type BorrowedState<'a> = &'a mut [BigInt];
type State = StateAndModified<Box<[Self::StateElement]>, Box<[bool]>>;
type BorrowedState<'a> = StateAndModified<&'a mut [Self::StateElement], &'a mut [bool]>;
type StateElement = BigInt;
fn new_state(layout_data: &[Self::LayoutData]) -> Self::State {
layout_data.iter().map(|_| BigInt::default()).collect()
let state: Box<[_]> = layout_data.iter().map(|_| BigInt::default()).collect();
StateAndModified {
modified: vec![false; state.len()].into_boxed_slice(),
state,
}
}
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
state
let StateAndModified { state, modified } = state;
StateAndModified { state, modified }
}
fn part_debug_data<BK: InsnsBuildingKind>(
state_layout: &StateLayout<BK>,
@ -361,19 +529,80 @@ impl StatePartKind for StatePartKindBigSlots {
) -> fmt::Result {
write!(f, "{:#x}", state.big_slots[index])
}
fn state_index<'a>(
state: &'a Self::State,
part_index: StatePartIndex<Self>,
) -> &'a Self::StateElement {
&state.state[part_index.as_usize()]
}
fn state_index_mut<'a>(
state: &'a mut Self::State,
part_index: StatePartIndex<Self>,
) -> &'a mut Self::StateElement {
state.modified[part_index.as_usize()] = true;
&mut state.state[part_index.as_usize()]
}
fn state_index_fetch_maybe_modified_flag(
state: &Self::State,
part_index: StatePartIndex<Self>,
) -> bool {
state.modified[part_index.as_usize()]
}
fn state_index_range_fetch_maybe_modified_flags(
state: &Self::State,
part_index_range: StatePartIndexRange<Self>,
) -> bool {
state.modified[part_index_range.start.as_usize()..]
[..part_index_range.len.as_index().as_usize()]
.contains(&true)
}
fn clear_all_maybe_modified_flags(state: &mut Self::State) {
state.modified.fill(false);
}
fn borrowed_state_index<'a, 'b>(
state: &'a Self::BorrowedState<'b>,
part_index: StatePartIndex<Self>,
) -> &'a Self::StateElement {
&state.state[part_index.as_usize()]
}
fn borrowed_state_index_mut<'a, 'b>(
state: &'a mut Self::BorrowedState<'b>,
part_index: StatePartIndex<Self>,
) -> &'a mut Self::StateElement {
state.modified[part_index.as_usize()] = true;
&mut state.state[part_index.as_usize()]
}
fn borrowed_state_get_disjoint_mut<'a, 'b, const N: usize>(
state: &'a mut Self::BorrowedState<'b>,
part_indexes: [StatePartIndex<Self>; N],
) -> [&'a mut Self::StateElement; N] {
for part_index in part_indexes {
state.modified[part_index.as_usize()] = true;
}
state
.state
.get_disjoint_mut(part_indexes.map(StatePartIndex::as_usize))
.expect("indexes are disjoint")
}
}
impl StatePartKind for StatePartKindSimOnlySlots {
const NAME: &'static str = "SimOnlySlots";
type DebugData = SlotDebugData;
type LayoutData = DynSimOnly;
type State = Box<[DynSimOnlyValue]>;
type BorrowedState<'a> = &'a mut [DynSimOnlyValue];
type State = StateAndModified<Box<[Self::StateElement]>, Box<[bool]>>;
type BorrowedState<'a> = StateAndModified<&'a mut [Self::StateElement], &'a mut [bool]>;
type StateElement = DynSimOnlyValue;
fn new_state(layout_data: &[Self::LayoutData]) -> Self::State {
layout_data.iter().map(|ty| ty.default_value()).collect()
let state: Box<[_]> = layout_data.iter().map(|ty| ty.default_value()).collect();
StateAndModified {
modified: vec![false; state.len()].into_boxed_slice(),
state,
}
}
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
state
let StateAndModified { state, modified } = state;
StateAndModified { state, modified }
}
fn part_debug_data<BK: InsnsBuildingKind>(
state_layout: &StateLayout<BK>,
@ -392,6 +621,61 @@ impl StatePartKind for StatePartKindSimOnlySlots {
) -> fmt::Result {
write!(f, "{:?}", state.sim_only_slots[index])
}
fn state_index<'a>(
state: &'a Self::State,
part_index: StatePartIndex<Self>,
) -> &'a Self::StateElement {
&state.state[part_index.as_usize()]
}
fn state_index_mut<'a>(
state: &'a mut Self::State,
part_index: StatePartIndex<Self>,
) -> &'a mut Self::StateElement {
state.modified[part_index.as_usize()] = true;
&mut state.state[part_index.as_usize()]
}
fn state_index_fetch_maybe_modified_flag(
state: &Self::State,
part_index: StatePartIndex<Self>,
) -> bool {
state.modified[part_index.as_usize()]
}
fn state_index_range_fetch_maybe_modified_flags(
state: &Self::State,
part_index_range: StatePartIndexRange<Self>,
) -> bool {
state.modified[part_index_range.start.as_usize()..]
[..part_index_range.len.as_index().as_usize()]
.contains(&true)
}
fn clear_all_maybe_modified_flags(state: &mut Self::State) {
state.modified.fill(false);
}
fn borrowed_state_index<'a, 'b>(
state: &'a Self::BorrowedState<'b>,
part_index: StatePartIndex<Self>,
) -> &'a Self::StateElement {
&state.state[part_index.as_usize()]
}
fn borrowed_state_index_mut<'a, 'b>(
state: &'a mut Self::BorrowedState<'b>,
part_index: StatePartIndex<Self>,
) -> &'a mut Self::StateElement {
state.modified[part_index.as_usize()] = true;
&mut state.state[part_index.as_usize()]
}
fn borrowed_state_get_disjoint_mut<'a, 'b, const N: usize>(
state: &'a mut Self::BorrowedState<'b>,
part_indexes: [StatePartIndex<Self>; N],
) -> [&'a mut Self::StateElement; N] {
for part_index in part_indexes {
state.modified[part_index.as_usize()] = true;
}
state
.state
.get_disjoint_mut(part_indexes.map(StatePartIndex::as_usize))
.expect("indexes are disjoint")
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]

View file

@ -15,23 +15,23 @@ use crate::{
source_location::SourceLocation,
ty::{
CanonicalType, OpaqueSimValue, OpaqueSimValueSize, OpaqueSimValueSlice,
OpaqueSimValueWriter, StaticType, Type, TypeProperties, impl_match_variant_as_self,
OpaqueSimValueWriter, SimValueDebug, StaticType, Type, TypeProperties,
impl_match_variant_as_self,
},
util::{
ConstUsize, HashMap,
ConstUsize,
alternating_cell::{AlternatingCell, AlternatingCellMethods},
serde_by_id::{SerdeById, SerdeByIdProperties, SerdeByIdTable, SerdeByIdTrait},
},
};
use bitvec::{slice::BitSlice, vec::BitVec};
use hashbrown::hash_map::Entry;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _};
use std::{
borrow::{Borrow, BorrowMut, Cow},
fmt::{self, Write},
hash::{BuildHasher, Hash, Hasher, RandomState},
fmt,
num::NonZero,
ops::{Deref, DerefMut, Index, IndexMut},
sync::{Arc, Mutex},
sync::Arc,
};
pub(crate) mod sim_only_value_unsafe;
@ -551,113 +551,119 @@ impl_sim_value_cmp_as_bool!(AsyncReset);
#[doc(hidden)]
pub mod match_sim_value {
use crate::{
sim::value::{SimValue, ToSimValue},
ty::Type,
};
use crate::{sim::value::SimValue, ty::Type};
use std::ops::{Deref, DerefMut};
macro_rules! wrapper {
(
$(pub struct $wrapper:ident<$T:ident>($inner:ty);)*
) => {
$(#[doc(hidden)]
pub struct $wrapper<$T>($inner);
impl<$T> $wrapper<$T> {
#[inline(always)]
pub fn new(value: $T) -> Self {
Self(<$inner>::new(value))
}
}
impl<$T> Deref for $wrapper<$T> {
type Target = $inner;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<$T> DerefMut for $wrapper<$T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
})*
};
}
wrapper! {
pub struct MatchSimValueHelperCheckSimValue<T>(MatchSimValueHelperCheckMutSimValue<T>);
pub struct MatchSimValueHelperCheckMutSimValue<T>(MatchSimValueHelperCheckRefSimValue<T>);
pub struct MatchSimValueHelperCheckRefSimValue<T>(MatchSimValueHelperCheckRefRefSimValue<T>);
pub struct MatchSimValueHelperCheckRefRefSimValue<T>(MatchSimValueHelperCheckRefMutSimValue<T>);
pub struct MatchSimValueHelperCheckRefMutSimValue<T>(MatchSimValueHelperCheckMutRefSimValue<T>);
pub struct MatchSimValueHelperCheckMutRefSimValue<T>(MatchSimValueHelperCheckMutMutSimValue<T>);
pub struct MatchSimValueHelperCheckMutMutSimValue<T>(MatchSimValueHelperIdentity<T>);
}
impl<T: Type> MatchSimValueHelperCheckSimValue<SimValue<T>> {
#[inline(always)]
pub fn __fayalite_match_sim_value(&mut self) -> T::SimValue {
SimValue::into_value(self.take())
}
}
impl<'a, T: Type> MatchSimValueHelperCheckMutSimValue<&'a mut SimValue<T>> {
#[inline(always)]
pub fn __fayalite_match_sim_value(&mut self) -> &'a mut T::SimValue {
self.take()
}
}
impl<'a, T: Type> MatchSimValueHelperCheckRefSimValue<&'a SimValue<T>> {
#[inline(always)]
pub fn __fayalite_match_sim_value(&mut self) -> &'a T::SimValue {
self.take()
}
}
impl<'a, 'b, T: Type> MatchSimValueHelperCheckRefRefSimValue<&'a &'b SimValue<T>> {
#[inline(always)]
pub fn __fayalite_match_sim_value(&mut self) -> &'b T::SimValue {
self.take()
}
}
impl<'a, 'b, T: Type> MatchSimValueHelperCheckRefMutSimValue<&'a &'b mut SimValue<T>> {
#[inline(always)]
pub fn __fayalite_match_sim_value(&mut self) -> &'a T::SimValue {
self.take()
}
}
impl<'a, 'b, T: Type> MatchSimValueHelperCheckMutRefSimValue<&'a mut &'b SimValue<T>> {
#[inline(always)]
pub fn __fayalite_match_sim_value(&mut self) -> &'b T::SimValue {
self.take()
}
}
impl<'a, 'b, T: Type> MatchSimValueHelperCheckMutMutSimValue<&'a mut &'b mut SimValue<T>> {
#[inline(always)]
pub fn __fayalite_match_sim_value(&mut self) -> &'a mut T::SimValue {
self.take()
}
}
#[doc(hidden)]
pub struct MatchSimValueHelper<T>(Option<T>);
pub struct MatchSimValueHelperIdentity<T>(Option<T>);
impl<T> MatchSimValueHelper<T> {
pub fn new(v: T) -> Self {
impl<T> MatchSimValueHelperIdentity<T> {
fn new(v: T) -> Self {
Self(Some(v))
}
}
#[doc(hidden)]
pub trait MatchSimValue {
type MatchValue;
/// use `self` so it comes first in the method resolution order
fn __fayalite_match_sim_value(self) -> Self::MatchValue
where
Self: Sized;
}
impl<T: Type> MatchSimValue for MatchSimValueHelper<SimValue<T>> {
type MatchValue = T::SimValue;
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
SimValue::into_value(self.0.expect("should be Some"))
#[inline(always)]
fn take(&mut self) -> T {
self.0.take().expect("known to be Some")
}
}
impl<'a, T: Type> MatchSimValue for MatchSimValueHelper<&'a SimValue<T>> {
type MatchValue = &'a T::SimValue;
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
SimValue::value(self.0.expect("should be Some"))
}
}
impl<'a, T: Type> MatchSimValue for MatchSimValueHelper<&'a mut SimValue<T>> {
type MatchValue = &'a mut T::SimValue;
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
SimValue::value_mut(self.0.expect("should be Some"))
}
}
impl<'a, T> MatchSimValue for MatchSimValueHelper<&'_ &'a T>
where
MatchSimValueHelper<&'a T>: MatchSimValue,
{
type MatchValue = <MatchSimValueHelper<&'a T> as MatchSimValue>::MatchValue;
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| *v)))
}
}
impl<'a, T> MatchSimValue for MatchSimValueHelper<&'_ mut &'a T>
where
MatchSimValueHelper<&'a T>: MatchSimValue,
{
type MatchValue = <MatchSimValueHelper<&'a T> as MatchSimValue>::MatchValue;
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| *v)))
}
}
impl<'a, T> MatchSimValue for MatchSimValueHelper<&'a &'_ mut T>
where
MatchSimValueHelper<&'a T>: MatchSimValue,
{
type MatchValue = <MatchSimValueHelper<&'a T> as MatchSimValue>::MatchValue;
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| &**v)))
}
}
impl<'a, T> MatchSimValue for MatchSimValueHelper<&'a mut &'_ mut T>
where
MatchSimValueHelper<&'a mut T>: MatchSimValue,
{
type MatchValue = <MatchSimValueHelper<&'a mut T> as MatchSimValue>::MatchValue;
fn __fayalite_match_sim_value(self) -> Self::MatchValue {
MatchSimValue::__fayalite_match_sim_value(MatchSimValueHelper(self.0.map(|v| &mut **v)))
#[inline(always)]
pub fn __fayalite_match_sim_value(&mut self) -> T {
self.take()
}
}
#[doc(hidden)]
pub trait MatchSimValueFallback {
type MatchValue;
/// use `&mut self` so it comes later in the method resolution order than MatchSimValue
fn __fayalite_match_sim_value(&mut self) -> Self::MatchValue;
}
impl<T: ToSimValue> MatchSimValueFallback for MatchSimValueHelper<T> {
type MatchValue = <T::Type as Type>::SimValue;
fn __fayalite_match_sim_value(&mut self) -> Self::MatchValue {
SimValue::into_value(self.0.take().expect("should be Some").into_sim_value())
}
}
pub type MatchSimValueHelper<T> = MatchSimValueHelperCheckSimValue<T>;
}
pub trait ToSimValue: ToSimValueWithType<<Self as ValueType>::Type> + ValueType {
@ -1091,7 +1097,8 @@ impl ToSimValueWithType<CanonicalType> for bool {
| CanonicalType::Enum(_)
| CanonicalType::Bundle(_)
| CanonicalType::PhantomConst(_)
| CanonicalType::DynSimOnly(_) => {
| CanonicalType::DynSimOnly(_)
| CanonicalType::TraceAsString(_) => {
panic!("can't create SimValue from bool: expected value of type: {ty:?}");
}
CanonicalType::Bool(_)
@ -1220,80 +1227,17 @@ macro_rules! impl_to_sim_value_for_int_value {
impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType);
impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType);
#[derive(Default)]
struct DynSimOnlySerdeTableRest {
from_serde: HashMap<DynSimOnlySerdeId, DynSimOnly>,
serde_id_random_state: RandomState,
buffer: String,
}
impl DynSimOnlySerdeTableRest {
#[cold]
fn add_new(&mut self, ty: DynSimOnly) -> DynSimOnlySerdeId {
let mut try_number = 0u64;
let mut hasher = self.serde_id_random_state.build_hasher();
// extract more bits of randomness from TypeId -- its Hash impl only hashes 64-bits
write!(self.buffer, "{:?}", ty.type_id()).expect("shouldn't ever fail");
self.buffer.hash(&mut hasher);
loop {
let mut hasher = hasher.clone();
try_number.hash(&mut hasher);
try_number += 1;
let retval = DynSimOnlySerdeId(std::array::from_fn(|i| {
let mut hasher = hasher.clone();
i.hash(&mut hasher);
hasher.finish() as u32
}));
match self.from_serde.entry(retval) {
Entry::Occupied(_) => continue,
Entry::Vacant(e) => {
e.insert(ty);
return retval;
}
}
}
impl SerdeByIdTrait for DynSimOnly {
fn serde_by_id_properties(&self) -> SerdeByIdProperties<Self> {
self.serde_by_id_properties_inner()
}
}
#[derive(Default)]
struct DynSimOnlySerdeTable {
to_serde: HashMap<DynSimOnly, DynSimOnlySerdeId>,
rest: DynSimOnlySerdeTableRest,
}
static DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE: Mutex<Option<DynSimOnlySerdeTable>> = Mutex::new(None);
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
struct DynSimOnlySerdeId([u32; 4]);
impl From<DynSimOnly> for DynSimOnlySerdeId {
fn from(ty: DynSimOnly) -> Self {
let mut locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE
.lock()
.expect("shouldn't be poison");
let DynSimOnlySerdeTable { to_serde, rest } = locked.get_or_insert_default();
match to_serde.entry(ty) {
Entry::Occupied(occupied_entry) => *occupied_entry.get(),
Entry::Vacant(vacant_entry) => *vacant_entry.insert(rest.add_new(ty)),
}
fn static_table() -> &'static SerdeByIdTable<Self> {
static TABLE: SerdeByIdTable<DynSimOnly> = SerdeByIdTable::new();
&TABLE
}
}
impl DynSimOnlySerdeId {
fn ty(self) -> Option<DynSimOnly> {
let locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE
.lock()
.expect("shouldn't be poison");
Some(*locked.as_ref()?.rest.from_serde.get(&self)?)
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
struct DynSimOnlySerde<'a> {
random_id: DynSimOnlySerdeId,
#[serde(borrow)]
type_name: Cow<'a, str>,
const NAME: &'static str = "DynSimOnly";
}
impl Serialize for DynSimOnly {
@ -1301,11 +1245,7 @@ impl Serialize for DynSimOnly {
where
S: Serializer,
{
DynSimOnlySerde {
random_id: (*self).into(),
type_name: Cow::Borrowed(self.type_name()),
}
.serialize(serializer)
SerdeById { inner: *self }.serialize(serializer)
}
}
@ -1314,16 +1254,7 @@ impl<'de> Deserialize<'de> for DynSimOnly {
where
D: Deserializer<'de>,
{
let deserialized = DynSimOnlySerde::deserialize(deserializer)?;
let retval = deserialized
.random_id
.ty()
.filter(|ty| ty.type_name() == deserialized.type_name);
retval.ok_or_else(|| {
D::Error::custom(
"doesn't match any DynSimOnly that was serialized this time this program was run",
)
})
Ok(SerdeById::deserialize(deserializer)?.inner)
}
}
@ -1394,6 +1325,15 @@ impl Type for DynSimOnly {
}
}
impl SimValueDebug for DynSimOnly {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl<T: SimOnlyValueTrait> Type for SimOnly<T> {
type BaseType = DynSimOnly;
type MaskType = Bool;
@ -1459,6 +1399,15 @@ impl<T: SimOnlyValueTrait> Type for SimOnly<T> {
}
}
impl<T: SimOnlyValueTrait> SimValueDebug for SimOnly<T> {
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(value, f)
}
}
impl<T: SimOnlyValueTrait> StaticType for SimOnly<T> {
const TYPE: Self = Self::new();
@ -1559,6 +1508,8 @@ impl<T: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> {
}
impl HdlPartialEqImpl<Self> for DynSimOnly {
const TRY_STRUCTURAL_EQ: bool = false;
#[track_caller]
fn cmp_value_eq(
_lhs: Self,
@ -1578,6 +1529,8 @@ impl HdlPartialEqImpl<Self> for DynSimOnly {
impl<L: SimOnlyValueTrait + PartialEq<R>, R: SimOnlyValueTrait> HdlPartialEqImpl<SimOnly<R>>
for SimOnly<L>
{
const TRY_STRUCTURAL_EQ: bool = false;
#[track_caller]
fn cmp_value_eq(
_lhs: Self,

View file

@ -3,7 +3,10 @@
//! `unsafe` parts of [`DynSimOnlyValue`]
use crate::expr::{ValueType, value_category::ValueCategoryValue};
use crate::{
expr::{ValueType, value_category::ValueCategoryValue},
util::serde_by_id::SerdeByIdProperties,
};
use serde::{Serialize, de::DeserializeOwned};
use std::{
any::{self, TypeId},
@ -33,6 +36,7 @@ unsafe trait DynSimOnlyTrait: 'static + Send + Sync {
&self,
json_str: &str,
) -> serde_json::Result<Rc<dyn DynSimOnlyValueTrait>>;
fn serde_by_id_properties_inner(&self) -> SerdeByIdProperties<DynSimOnly>;
}
/// Safety: `type_id_dyn` is implemented correctly
@ -55,6 +59,9 @@ unsafe impl<T: SimOnlyValueTrait> DynSimOnlyTrait for SimOnly<T> {
) -> serde_json::Result<Rc<dyn DynSimOnlyValueTrait>> {
Ok(Rc::<T>::new(serde_json::from_str(json_str)?))
}
fn serde_by_id_properties_inner(&self) -> SerdeByIdProperties<DynSimOnly> {
SerdeByIdProperties::of::<T>()
}
}
/// Safety:
@ -151,6 +158,9 @@ impl DynSimOnly {
pub fn default_value(self) -> DynSimOnlyValue {
DynSimOnlyValue(self.ty.default_value())
}
pub(super) fn serde_by_id_properties_inner(self) -> SerdeByIdProperties<Self> {
self.ty.serde_by_id_properties_inner()
}
}
impl PartialEq for DynSimOnly {

View file

@ -9,14 +9,15 @@ use crate::{
prelude::PhantomConst,
sim::{
TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl,
TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance,
TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule,
TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, TraceScalar, TraceScalarId,
TraceScope, TraceSimOnly, TraceSyncReset, TraceUInt, TraceWire, TraceWriter,
TraceWriterDecls,
TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceFormalInput,
TraceInstance, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation,
TraceModule, TraceModuleIO, TracePhantomConst, TraceReg, TraceSInt, TraceScalar,
TraceScalarId, TraceScope, TraceSimOnly, TraceSyncReset, TraceTraceAsString, TraceUInt,
TraceWire, TraceWriter, TraceWriterDecls,
time::{SimDuration, SimInstant},
value::DynSimOnlyValue,
},
ty::{OpaqueSimValueSlice, TraceAsString},
util::HashMap,
};
use bitvec::{order::Lsb0, slice::BitSlice};
@ -331,6 +332,7 @@ impl WriteTrace for TraceScalar {
Self::AsyncReset(v) => v.write_trace(writer, arg),
Self::PhantomConst(v) => v.write_trace(writer, arg),
Self::SimOnly(v) => v.write_trace(writer, arg),
Self::TraceAsString(v) => v.write_trace(writer, arg),
}
}
}
@ -726,6 +728,34 @@ impl WriteTrace for TraceSimOnly {
}
}
impl WriteTrace for TraceTraceAsString {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgInType {
source_var_type: _,
sink_var_type: _,
duplex_var_type: _,
properties,
scope,
} = arg.in_type();
let Self {
location,
name,
ty,
flow: _,
} = self;
write_vcd_var(
properties,
scope,
MemoryElementPartBody::TraceAsString { ty },
writer,
"string",
1,
location,
name,
)
}
}
impl WriteTrace for TraceScope {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> {
match self {
@ -736,6 +766,7 @@ impl WriteTrace for TraceScope {
Self::Wire(v) => v.write_trace(writer, arg),
Self::Reg(v) => v.write_trace(writer, arg),
Self::ModuleIO(v) => v.write_trace(writer, arg),
Self::FormalInput(v) => v.write_trace(writer, arg),
Self::Bundle(v) => v.write_trace(writer, arg),
Self::Array(v) => v.write_trace(writer, arg),
Self::EnumWithFields(v) => v.write_trace(writer, arg),
@ -933,6 +964,27 @@ impl WriteTrace for TraceModuleIO {
}
}
impl WriteTrace for TraceFormalInput {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgModuleBody { properties, scope } = arg.module_body();
let Self {
name: _,
child,
formal_input: _,
} = self;
child.write_trace(
writer,
ArgInType {
source_var_type: "wire",
sink_var_type: "wire",
duplex_var_type: "wire",
properties,
scope: Some(scope),
},
)
}
}
impl WriteTrace for TraceBundle {
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, mut arg: A) -> io::Result<()> {
let ArgInType {
@ -1093,6 +1145,7 @@ impl<W: io::Write> TraceWriterDecls for VcdWriterDecls<W> {
finished_init: false,
timescale,
properties,
trace_as_string_buf: String::with_capacity(256),
})
}
}
@ -1100,6 +1153,7 @@ impl<W: io::Write> TraceWriterDecls for VcdWriterDecls<W> {
enum MemoryElementPartBody {
Scalar,
EnumDiscriminant { ty: Enum },
TraceAsString { ty: TraceAsString },
}
struct MemoryElementPart {
@ -1217,6 +1271,7 @@ pub struct VcdWriter<W: io::Write + 'static> {
finished_init: bool,
timescale: SimDuration,
properties: VcdWriterProperties,
trace_as_string_buf: String,
}
impl<W: io::Write + 'static> VcdWriter<W> {
@ -1326,6 +1381,21 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> {
.built_scalar_id_to_vcd_id(first_id + element_index),
)?
}
MemoryElementPartBody::TraceAsString { ty } => {
self.trace_as_string_buf.clear();
ty.trace_fmt_append_to_string(
&mut self.trace_as_string_buf,
OpaqueSimValueSlice::from_bitslice(&element_data[start..start + len]),
);
write_string_value_change(
&mut self.writer,
&self.trace_as_string_buf,
self.properties
.scalar_id_to_vcd_id_map
.built_scalar_id_to_vcd_id(first_id + element_index),
)?;
self.trace_as_string_buf.clear();
}
}
}
Ok(())
@ -1419,6 +1489,16 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> {
.built_scalar_id_to_vcd_id(id.as_usize()),
)
}
fn set_signal_string(&mut self, id: TraceScalarId, value: &str) -> Result<(), Self::Error> {
write_string_value_change(
&mut self.writer,
value,
self.properties
.scalar_id_to_vcd_id_map
.built_scalar_id_to_vcd_id(id.as_usize()),
)
}
}
impl<W: io::Write> fmt::Debug for VcdWriter<W> {
@ -1428,6 +1508,7 @@ impl<W: io::Write> fmt::Debug for VcdWriter<W> {
finished_init,
timescale,
properties: _,
trace_as_string_buf: _,
} = self;
f.debug_struct("VcdWriter")
.field("finished_init", finished_init)

View file

@ -12,11 +12,13 @@ use crate::{
bundle::BundleType,
firrtl::ExportOptions,
module::Module,
util::HashMap,
sim::{Simulation, vcd::VcdWriterDecls},
util::{HashMap, RcWriter},
};
use serde::{Deserialize, Serialize};
use std::{
fmt::{self, Write},
panic::Location,
path::{Path, PathBuf},
process::Command,
sync::{Mutex, OnceLock},
@ -222,3 +224,190 @@ pub fn assert_formal<M: AsRef<Module<T>>, T: BundleType>(
)
.expect("testing::assert_formal() failed");
}
pub struct CheckedVcdOutput {
writer: Option<RcWriter>,
expected_path: PathBuf,
expected_contents: Result<String, (Option<PathBuf>, std::io::Error)>,
location: &'static Location<'static>,
}
impl CheckedVcdOutput {
#[must_use]
#[track_caller]
pub fn new<T: BundleType>(sim: &mut Simulation<T>, expected_path: PathBuf) -> Self {
let writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
Self {
writer: Some(writer),
expected_contents: std::fs::read_to_string(&expected_path).map_err(|e| {
eprintln!(
"error: failed to read expected VCD from: {}",
expected_path.display(),
);
(std::env::current_dir().ok(), e)
}),
expected_path,
location: Location::caller(),
}
}
#[must_use]
#[track_caller]
#[doc(hidden)]
pub fn __checked_vcd_output_macro_helper<T: BundleType>(
sim: &mut Simulation<T>,
cargo_manifest_dir: &'static str,
path: &'static str,
) -> Self {
Self::new(sim, Path::new(cargo_manifest_dir).join(path))
}
pub fn with_vcd_output<R>(&self, f: impl FnOnce(&str) -> R) -> R {
let Some(writer) = &self.writer else {
unreachable!();
};
writer.clone().borrow(|output| {
let Ok(output) = str::from_utf8(output) else {
unreachable!("VcdWriter writes valid UTF-8");
};
f(output)
})
}
#[track_caller]
pub fn finish(mut self) {
let Ok(()) = self.finish_impl(|msg| panic!("{msg}"));
}
fn finish_impl<E>(
&mut self,
error: impl FnOnce(std::fmt::Arguments<'_>) -> E,
) -> Result<(), E> {
let Self {
writer: Some(writer),
expected_path,
expected_contents,
location,
} = self
else {
// already finished
return Ok(());
};
let Ok(vcd) = String::from_utf8(writer.take()) else {
unreachable!("VcdWriter writes valid UTF-8");
};
let expected_path_d = expected_path.display();
if expected_contents
.as_ref()
.is_ok_and(|expected_contents| *expected_contents == vcd)
{
// avoid written output from being split from threads interleaving writes to stdout
let _stdout = std::io::stderr().lock();
// use println to get output captured by tests
println!("\n{location}: generated VCD matches the expected VCD in {expected_path_d}");
return Ok(());
}
// avoid written output from being split from threads interleaving writes to stderr
let _stderr = std::io::stderr().lock();
let error = |msg: std::fmt::Arguments<'_>| {
// print msg at both beginning and end so it's easier to find when the vcd is huge
Err(error(format_args!(
"\n{msg}####### VCD:\n{vcd}\n#######\n{msg}"
)))
};
let error = |msg: std::fmt::Arguments<'_>| match &*expected_contents {
Ok(_) => error(format_args!(
"{location}: generated VCD doesn't match the expected VCD in {expected_path_d}\n\
{msg}",
)),
Err((Some(current_dir), e)) => error(format_args!(
"{location}: generated VCD doesn't match the expected VCD in {expected_path_d}\n\
error: failed to read: {e}\n\
current dir: {current_dir}\n\
{msg}",
current_dir = current_dir.display(),
)),
Err((None, e)) => error(format_args!(
"{location}: generated VCD doesn't match the expected VCD in {expected_path_d}\n\
error: failed to read: {e}\n\
{msg}",
)),
};
const OVERWRITE_VAR_NAME: &str = "OVERWRITE_EXPECTED_VCD";
const OVERWRITE_VAR_VALUE: &str = "overwrite";
match std::env::var_os(OVERWRITE_VAR_NAME) {
Some(v) if v == OVERWRITE_VAR_VALUE => match std::fs::write(&expected_path, &vcd) {
Ok(()) => error(format_args!(
"warning: since `{OVERWRITE_VAR_NAME}={OVERWRITE_VAR_VALUE}` is set -- writing the generated VCD to {expected_path_d}\n"
)),
Err(e) => error(format_args!(
"error: since `{OVERWRITE_VAR_NAME}={OVERWRITE_VAR_VALUE}` is set -- tried to write the generated VCD to {expected_path_d}\n\
error: failed to write: {e}"
)),
},
_ => error(format_args!(
"note: rerun the test with the environment variable `{OVERWRITE_VAR_NAME}={OVERWRITE_VAR_VALUE}`\n\
to update the expected output to match the generated output.\n"
)),
}
}
}
impl Drop for CheckedVcdOutput {
#[track_caller]
fn drop(&mut self) {
let _ = self.finish_impl(|msg| {
if std::thread::panicking() {
eprintln!("{msg}"); // use eprintln to get output captured by tests
} else {
panic!("{msg}");
}
});
}
}
#[macro_export]
/// Use in tests to check that [`Simulation`] generates the expected VCD traces, by comparing to a `.vcd` file containing the expected traces.
///
/// Use like so:
/// ```
/// # use fayalite::prelude::*;
/// #
/// # #[hdl_module]
/// # fn my_module() {
/// # #[hdl]
/// # let a: UInt<8> = m.input();
/// # #[hdl]
/// # let b: UInt<8> = m.output();
/// # connect(b, 0u8);
/// # #[hdl]
/// # if a.cmp_eq(100u8) {
/// # connect(b, 42u8);
/// # }
/// # }
/// // inside your #[test] fn my_test():
///
/// // get the module to simulate:
/// let m = my_module();
/// // create a simulation of the module:
/// let mut sim = Simulation::new(m);
/// // set up the expected VCD traces, the given .vcd path is relative to env!("CARGO_MANIFEST_DIR")
/// let _checked_vcd_output = checked_vcd_output!(
/// &mut sim,
/// "tests/expected/my_test.vcd",
/// );
/// // now run the simulation like normal:
/// sim.write(sim.io().a, 0u8);
/// assert_eq!(sim.read(sim.io().b).as_int(), 0);
/// sim.advance_time(SimDuration::from_micros(1));
/// sim.write(sim.io().a, 100u8);
/// assert_eq!(sim.read(sim.io().b).as_int(), 42);
/// ```
macro_rules! checked_vcd_output {
($sim:expr, $path_relative_to_manifest_dir:expr $(,)?) => {
$crate::testing::CheckedVcdOutput::__checked_vcd_output_macro_helper(
$sim,
$crate::__std::env!("CARGO_MANIFEST_DIR"),
$crate::__std::concat!($path_relative_to_manifest_dir),
)
};
}
pub use checked_vcd_output;

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,8 @@ use crate::{
prelude::PhantomConst,
reset::{AsyncReset, Reset, SyncReset},
sim::value::DynSimOnly,
ty::{BaseType, CanonicalType},
ty::{BaseType, CanonicalType, TraceAsString, TraceAsStringTrait},
util::serde_by_id::SerdeById,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -38,6 +39,7 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for SerdePhantomConst<
#[derive(Serialize, Deserialize)]
#[serde(rename = "CanonicalType")]
#[expect(private_interfaces)]
pub(crate) enum SerdeCanonicalType<
ArrayElement = CanonicalType,
ThePhantomConst = SerdePhantomConst<Interned<PhantomConstCanonicalValue>>,
@ -65,6 +67,10 @@ pub(crate) enum SerdeCanonicalType<
Clock,
PhantomConst(ThePhantomConst),
DynSimOnly(DynSimOnly),
TraceAsString {
inner_ty: Interned<CanonicalType>,
trace_as_string: SerdeById<Interned<dyn TraceAsStringTrait>>,
},
}
impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomConstInner> {
@ -82,6 +88,7 @@ impl<ArrayElement, PhantomConstInner> SerdeCanonicalType<ArrayElement, PhantomCo
Self::Clock => "a Clock",
Self::PhantomConst(_) => "a PhantomConst",
Self::DynSimOnly(_) => "a SimOnlyValue",
Self::TraceAsString { .. } => "a TraceAsString",
}
}
}
@ -109,6 +116,15 @@ impl<T: BaseType> From<T> for SerdeCanonicalType {
CanonicalType::Clock(Clock {}) => Self::Clock,
CanonicalType::PhantomConst(ty) => Self::PhantomConst(SerdePhantomConst(ty.get())),
CanonicalType::DynSimOnly(ty) => Self::DynSimOnly(ty),
CanonicalType::TraceAsString(TraceAsString {
inner_ty,
trace_as_string,
}) => Self::TraceAsString {
inner_ty: inner_ty.interned(),
trace_as_string: SerdeById {
inner: trace_as_string.interned(),
},
},
}
}
}
@ -130,6 +146,13 @@ impl From<SerdeCanonicalType> for CanonicalType {
Self::PhantomConst(PhantomConst::new_interned(value.0))
}
SerdeCanonicalType::DynSimOnly(value) => Self::DynSimOnly(value),
SerdeCanonicalType::TraceAsString {
inner_ty,
trace_as_string,
} => Self::TraceAsString(TraceAsString {
inner_ty: crate::intern::LazyInterned::Interned(inner_ty),
trace_as_string: crate::intern::LazyInterned::Interned(trace_as_string.inner),
}),
}
}
}

View file

@ -16,8 +16,8 @@ pub type DefaultBuildHasher = test_hasher::DefaultBuildHasher;
#[cfg(not(feature = "unstable-test-hasher"))]
pub(crate) type DefaultBuildHasher = hashbrown::DefaultHashBuilder;
pub(crate) type HashMap<K, V> = hashbrown::HashMap<K, V, DefaultBuildHasher>;
pub(crate) type HashSet<T> = hashbrown::HashSet<T, DefaultBuildHasher>;
pub(crate) type HashMap<K, V, H = DefaultBuildHasher> = hashbrown::HashMap<K, V, H>;
pub(crate) type HashSet<T, H = DefaultBuildHasher> = hashbrown::HashSet<T, H>;
#[doc(inline)]
pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool};
@ -43,6 +43,11 @@ pub use misc::{
};
pub(crate) use misc::{InternedStrCompareAsStr, chain, copy_le_bytes_to_bitslice};
pub mod bool_fixed_point_solver;
pub(crate) mod indented_print;
pub mod job_server;
pub mod map_trait;
pub mod prefix_sum;
pub mod ready_valid;
pub(crate) mod serde_by_id;
pub mod union_find_map;

View file

@ -0,0 +1,711 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use petgraph::unionfind::UnionFind;
use std::{collections::BTreeSet, fmt};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Variable(usize);
impl Variable {
pub fn index(self) -> usize {
self.0
}
}
impl fmt::Debug for Variable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for Variable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "v{}", self.0)
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Constraint {
/// `variable` is constrained to be [`!solver.unconstrained_variables_value()`](BoolFixedPointSolver::unconstrained_variables_value())
MaximallyConstrained { variable: Variable },
/// the constraint is `dest == src`
Equal { dest: Variable, src: Variable },
/// the constraint is `dest == dest & src`
And { dest: Variable, src: Variable },
/// the constraint is `dest == dest | src`
Or { dest: Variable, src: Variable },
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
/// the constraint is `dest == dest & src`
struct AndConstraint {
dest: Variable,
src: Variable,
}
impl AndConstraint {
fn from_or_constraint(or_constraint_dest: Variable, or_constraint_src: Variable) -> Self {
// `a == a | b` is equivalent to `b == b & a`
Self {
dest: or_constraint_src,
src: or_constraint_dest,
}
}
}
impl fmt::Debug for AndConstraint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { dest, src } = *self;
write!(f, "{dest} == {dest} & {src}")
}
}
#[derive(Clone)]
pub struct BoolFixedPointSolver {
variables_union_find: UnionFind<usize>,
variables_value: Vec<bool>,
maximally_constrained: Vec<bool>,
unconstrained_variables_value: bool,
solved: bool,
and_constraints: BTreeSet<AndConstraint>,
}
impl fmt::Debug for BoolFixedPointSolver {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
variables_union_find,
variables_value,
maximally_constrained,
unconstrained_variables_value,
solved,
and_constraints,
} = self;
f.debug_struct("BoolFixedPointSolver")
.field(
"variables_union_find",
&fmt::from_fn(|f| {
f.debug_map()
.entries(
(0..variables_union_find.len())
.map(|i| (Variable(i), Variable(variables_union_find.find(i)))),
)
.finish()
}),
)
.field(
"variables_value",
&fmt::from_fn(|f| {
let mut debug_map = f.debug_map();
for (i, v) in variables_value.iter().enumerate() {
if variables_union_find.find(i) == i {
debug_map.entry(&Variable(i), v);
}
}
debug_map.finish()
}),
)
.field(
"maximally_constrained",
&fmt::from_fn(|f| {
let mut debug_map = f.debug_map();
for (i, v) in maximally_constrained.iter().enumerate() {
if variables_union_find.find(i) == i {
debug_map.entry(&Variable(i), v);
}
}
debug_map.finish()
}),
)
.field(
"unconstrained_variables_value",
unconstrained_variables_value,
)
.field("solved", solved)
.field("and_constraints", and_constraints)
.finish()
}
}
impl BoolFixedPointSolver {
pub const fn new(unconstrained_variables_value: bool) -> Self {
Self {
variables_union_find: UnionFind::new_empty(),
variables_value: Vec::new(),
maximally_constrained: Vec::new(),
unconstrained_variables_value,
solved: false,
and_constraints: BTreeSet::new(),
}
}
pub fn unconstrained_variables_value(&self) -> bool {
self.unconstrained_variables_value
}
pub fn new_variable(&mut self) -> Variable {
let index = self.variables_union_find.new_set();
self.variables_value
.push(self.unconstrained_variables_value);
self.maximally_constrained.push(false);
self.solved = false;
Variable(index)
}
pub fn variable_count(&self) -> usize {
self.variables_union_find.len()
}
#[track_caller]
fn assert_variable_in_range(&self, variable: Variable) {
if variable.0 >= self.variable_count() {
panic!("invalid variable {variable:?}");
}
}
#[track_caller]
pub fn add_constraint(&mut self, constraint: Constraint) {
self.solved = false;
match constraint {
Constraint::MaximallyConstrained { variable } => {
self.assert_variable_in_range(variable);
self.maximally_constrained[self.variables_union_find.find_mut(variable.0)] = true;
return;
}
Constraint::Equal { dest, src } => {
self.assert_variable_in_range(dest);
self.assert_variable_in_range(src);
let maximally_constrained = self.maximally_constrained
[self.variables_union_find.find_mut(dest.0)]
| self.maximally_constrained[self.variables_union_find.find_mut(src.0)];
self.variables_union_find.union(dest.0, src.0);
let merged_index = self.variables_union_find.find_mut(dest.0);
self.maximally_constrained[merged_index] = maximally_constrained;
}
Constraint::And { dest, src } => {
self.assert_variable_in_range(src);
self.assert_variable_in_range(dest);
if src != dest {
self.and_constraints.insert(AndConstraint { dest, src });
}
}
Constraint::Or { dest, src } => {
self.assert_variable_in_range(src);
self.assert_variable_in_range(dest);
if src != dest {
self.and_constraints
.insert(AndConstraint::from_or_constraint(dest, src));
}
}
}
}
pub fn solve(&mut self) {
for (value, maximally_constrained) in self
.variables_value
.iter_mut()
.zip(&self.maximally_constrained)
{
*value = self.unconstrained_variables_value ^ *maximally_constrained;
}
let mut variables_to_constraints_map: Vec<Vec<AndConstraint>> =
vec![Vec::new(); self.variable_count()];
for &AndConstraint { mut dest, mut src } in &self.and_constraints {
dest.0 = self.variables_union_find.find_mut(dest.0);
src.0 = self.variables_union_find.find_mut(src.0);
if dest == src {
continue;
}
let constraint = AndConstraint { dest, src };
variables_to_constraints_map[dest.0].push(constraint);
variables_to_constraints_map[src.0].push(constraint);
}
let mut worklist: Vec<Variable> = (0..self.variable_count())
.filter(|&index| self.variables_union_find.find_mut(index) == index)
.map(Variable)
.collect();
while let Some(variable) = worklist.pop() {
for &AndConstraint { dest, src } in &variables_to_constraints_map[variable.0] {
let dest_value = self.variables_value[dest.0];
let src_value = self.variables_value[src.0];
// equivalent to `dest_value != dest_value & src_value`:
let is_unsatisfied = dest_value && !src_value;
if is_unsatisfied {
if self.unconstrained_variables_value {
self.variables_value[dest.0] = false;
worklist.push(dest);
} else {
self.variables_value[src.0] = true;
worklist.push(src);
}
}
}
}
self.solved = true;
}
#[track_caller]
pub fn value(&mut self, variable: Variable) -> bool {
#[cold]
fn solve_cold(this: &mut BoolFixedPointSolver) {
this.solve();
}
self.assert_variable_in_range(variable);
if !self.solved {
solve_cold(self);
}
self.variables_value[self.variables_union_find.find_mut(variable.0)]
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::num::NonZero;
struct TestCase<'a, C, Vars, Vals> {
variable_count: usize,
expected_values: Option<&'a [bool]>,
constraints: C,
variables: Vars,
values: Vals,
solver: BoolFixedPointSolver,
}
impl<'a, C: FnOnce(&[Variable]) -> I, I: IntoIterator<Item = Constraint>> TestCase<'a, C, (), ()> {
fn new_expected(
unconstrained_variables_value: bool,
expected_values: &'a [bool],
constraints: C,
) -> Self {
Self {
variable_count: expected_values.len(),
expected_values: Some(expected_values),
constraints,
variables: (),
values: (),
solver: BoolFixedPointSolver::new(unconstrained_variables_value),
}
}
#[track_caller]
fn get_constraints_and_variables(
self,
) -> TestCase<'a, Vec<Constraint>, Vec<Variable>, [bool; 0]> {
let Self {
variable_count,
expected_values,
constraints,
variables: (),
values: (),
mut solver,
} = self;
assert_eq!(
expected_values.map_or(variable_count, |v| v.len()),
variable_count,
);
let variables = Vec::from_iter((0..variable_count).map(|_| solver.new_variable()));
let constraints = Vec::from_iter(constraints(&variables));
TestCase {
variable_count,
expected_values,
constraints,
variables,
values: [],
solver,
}
}
}
impl<'a> TestCase<'a, Vec<Constraint>, Vec<Variable>, [bool; 0]> {
#[track_caller]
fn add_and_check_constraints(&mut self) {
if let Some(expected_values) = self.expected_values {
self.check_constraints("expected values", expected_values);
}
for &constraint in &self.constraints {
self.solver.add_constraint(constraint);
}
}
#[track_caller]
fn get_values(self) -> TestCase<'a, Vec<Constraint>, Vec<Variable>, Vec<bool>> {
let Self {
variable_count,
expected_values,
constraints,
variables,
values: [],
mut solver,
} = self;
let values = Vec::from_iter(variables.iter().map(|&v| solver.value(v)));
TestCase {
variable_count,
expected_values,
constraints,
variables,
values,
solver,
}
}
}
impl<'a> TestCase<'a, Vec<Constraint>, Vec<Variable>, Vec<bool>> {
#[track_caller]
fn check_values(&self) {
let Self {
variable_count: _,
expected_values,
constraints: _,
variables,
values,
solver: _,
} = self;
if let Some(expected_values) = expected_values {
for ((&expected_value, &variable), &value) in
expected_values.iter().zip(variables).zip(values)
{
if expected_value != value {
self.error(format_args!(
"solver output for {variable} of {value:?} doesn't \
match expected value of {expected_value:?}",
));
}
}
}
self.check_constraints("solved values", values);
}
}
impl<'a, Vals: AsRef<[bool]>> TestCase<'a, Vec<Constraint>, Vec<Variable>, Vals> {
#[track_caller]
fn check_constraints(&self, values_name: &str, values: &[bool]) {
let unconstrained_variables_value = self.solver.unconstrained_variables_value();
let v = |variable: Variable| values[variable.index()];
for &constraint in &self.constraints {
let satisfied = match constraint {
Constraint::MaximallyConstrained { variable } => {
v(variable) != unconstrained_variables_value
}
Constraint::Equal { dest, src } => v(dest) == v(src),
Constraint::And { dest, src } => v(dest) == v(dest) & v(src),
Constraint::Or { dest, src } => v(dest) == v(dest) | v(src),
};
if !satisfied {
self.error(format_args!(
"{values_name} don't satisfy constraint: {constraint:#?}"
));
}
}
}
#[track_caller]
fn error(&self, msg: fmt::Arguments<'_>) -> ! {
let Self {
variable_count,
expected_values,
ref constraints,
ref variables,
ref values,
ref solver,
} = *self;
let values = values.as_ref();
panic!(
"{msg}\n\
values={values:#?}\n\
constraints={constraints:#?}\n\
solver={solver:#?}",
values = fmt::from_fn(|f| {
let mut debug_map = f.debug_map();
for i in 0..variable_count {
debug_map.key(&variables[i]);
if let Some(value) = values.get(i) {
if let Some(expected_values) = expected_values {
debug_map.value(&format_args!(
"{value:?} (expected: {:?})",
expected_values[i],
));
} else {
debug_map.value(value);
}
} else if let Some(expected_values) = expected_values {
debug_map.value(&format_args!("(expected: {:?})", expected_values[i]));
} else {
debug_map.value(&format_args!("None"));
}
}
debug_map.finish()
}),
);
}
}
#[track_caller]
fn test_case<I: IntoIterator<Item = Constraint>>(
test_case: TestCase<'_, impl FnOnce(&[Variable]) -> I, (), ()>,
) {
let mut test_case = test_case.get_constraints_and_variables();
test_case.add_and_check_constraints();
let test_case = test_case.get_values();
test_case.check_values();
}
#[test]
fn test_bool_fixed_point_solver_simple() {
test_case(TestCase::new_expected(false, &[], |_| []));
test_case(TestCase::new_expected(true, &[], |_| []));
test_case(TestCase::new_expected(false, &[false], |_| []));
test_case(TestCase::new_expected(true, &[true], |_| []));
test_case(TestCase::new_expected(false, &[true], |v| {
[Constraint::MaximallyConstrained { variable: v[0] }]
}));
test_case(TestCase::new_expected(true, &[false], |v| {
[Constraint::MaximallyConstrained { variable: v[0] }]
}));
test_case(TestCase::new_expected(false, &[true, true], |v| {
[
Constraint::MaximallyConstrained { variable: v[0] },
Constraint::Equal {
dest: v[1],
src: v[0],
},
]
}));
test_case(TestCase::new_expected(true, &[false, false], |v| {
[
Constraint::MaximallyConstrained { variable: v[0] },
Constraint::Equal {
dest: v[1],
src: v[0],
},
]
}));
test_case(TestCase::new_expected(false, &[true, false], |v| {
[
Constraint::MaximallyConstrained { variable: v[0] },
Constraint::And {
dest: v[1],
src: v[0],
},
]
}));
test_case(TestCase::new_expected(true, &[false, false], |v| {
[
Constraint::MaximallyConstrained { variable: v[0] },
Constraint::And {
dest: v[1],
src: v[0],
},
]
}));
test_case(TestCase::new_expected(false, &[true, true], |v| {
[
Constraint::MaximallyConstrained { variable: v[0] },
Constraint::And {
dest: v[0],
src: v[1],
},
]
}));
test_case(TestCase::new_expected(true, &[false, true], |v| {
[
Constraint::MaximallyConstrained { variable: v[0] },
Constraint::And {
dest: v[0],
src: v[1],
},
]
}));
test_case(TestCase::new_expected(false, &[true, true], |v| {
[
Constraint::MaximallyConstrained { variable: v[0] },
Constraint::Or {
dest: v[1],
src: v[0],
},
]
}));
test_case(TestCase::new_expected(true, &[false, true], |v| {
[
Constraint::MaximallyConstrained { variable: v[0] },
Constraint::Or {
dest: v[1],
src: v[0],
},
]
}));
test_case(TestCase::new_expected(false, &[true, false], |v| {
[
Constraint::MaximallyConstrained { variable: v[0] },
Constraint::Or {
dest: v[0],
src: v[1],
},
]
}));
test_case(TestCase::new_expected(true, &[false, false], |v| {
[
Constraint::MaximallyConstrained { variable: v[0] },
Constraint::Or {
dest: v[0],
src: v[1],
},
]
}));
}
#[derive(Debug)]
struct Rng {
state: u64,
}
impl Rng {
fn new(test_case_index: u32) -> Self {
Self {
state: (test_case_index as u64) << 32,
}
}
fn next_u64(&mut self) -> u64 {
self.state += 1;
// 4 random primes and 4 random rotate amounts
self.state
.wrapping_mul(0xA3C7_8807_EA6D_A4F9)
.rotate_left(43)
.wrapping_mul(0x1CCA_797A_6BF8_8C63)
.rotate_left(8)
.wrapping_mul(0xCC50_AA59_7C41_946F)
.rotate_left(12)
.wrapping_mul(0xFB2A_0137_F878_C4B5)
.rotate_left(58)
}
#[track_caller]
fn next_u64_in_range(&mut self, range: std::ops::Range<u64>) -> u64 {
let Some(len) = range.end.checked_sub(range.start).and_then(NonZero::new) else {
panic!("empty range: {range:?}");
};
let max_quotient = u64::MAX / len;
loop {
let next_u64 = self.next_u64();
let quotient = next_u64 / len;
let remainder = next_u64 % len;
if quotient < max_quotient {
return remainder + range.start;
}
}
}
#[track_caller]
fn next_usize_in_range(&mut self, range: std::ops::Range<usize>) -> usize {
self.next_u64_in_range(range.start as u64..range.end as u64) as usize
}
#[track_caller]
fn next_from_slice<'a, T>(&mut self, slice: &'a [T]) -> &'a T {
assert!(!slice.is_empty());
&slice[self.next_usize_in_range(0..slice.len())]
}
fn next_bool(&mut self) -> bool {
(self.next_u64() & 1) != 0
}
}
#[track_caller]
fn test_bool_fixed_point_solver_random_case(test_case_index: u32) {
println!("test_bool_fixed_point_solver_random_case({test_case_index})");
let mut rng = Rng::new(test_case_index);
// bias towards smaller problems to make them easier to debug
let variable_count = rng
.next_u64_in_range(1..1_000_000)
.pow(2)
.div_ceil(1_000_000_000) as usize;
let constraint_count =
rng.next_usize_in_range(0..(variable_count * variable_count).clamp(0, 10000));
let solver = BoolFixedPointSolver::new(rng.next_bool());
test_case(TestCase {
variable_count,
expected_values: None,
constraints: |variables: &[Variable]| {
Vec::from_iter(
(0..constraint_count).map(|_| match rng.next_usize_in_range(0..4) {
0 => Constraint::MaximallyConstrained {
variable: *rng.next_from_slice(variables),
},
1 => Constraint::Equal {
dest: *rng.next_from_slice(variables),
src: *rng.next_from_slice(variables),
},
2 => Constraint::And {
dest: *rng.next_from_slice(variables),
src: *rng.next_from_slice(variables),
},
3 => Constraint::Or {
dest: *rng.next_from_slice(variables),
src: *rng.next_from_slice(variables),
},
4.. => unreachable!(),
}),
)
},
variables: (),
values: (),
solver,
});
}
const CASES_FULL_RANGE: std::ops::Range<u32> = 0..100_000;
fn mul_div(v: u32, factor: u32, divisor: u32) -> u32 {
((v as u64 * factor as u64) / divisor as u64) as u32
}
#[track_caller]
fn test_bool_fixed_point_solver_random_cases(split_index: u32) {
assert!(split_index < CASES_SPLIT_COUNT);
let full_range_len = CASES_FULL_RANGE.end - CASES_FULL_RANGE.start;
let start = mul_div(split_index, full_range_len, CASES_SPLIT_COUNT);
let end = mul_div(split_index + 1, full_range_len, CASES_SPLIT_COUNT);
for test_case_index in start..end {
test_bool_fixed_point_solver_random_case(test_case_index)
}
}
const CASES_SPLIT_COUNT: u32 = 10;
#[test]
fn test_bool_fixed_point_solver_random_cases_0() {
test_bool_fixed_point_solver_random_cases(0);
}
#[test]
fn test_bool_fixed_point_solver_random_cases_1() {
test_bool_fixed_point_solver_random_cases(1);
}
#[test]
fn test_bool_fixed_point_solver_random_cases_2() {
test_bool_fixed_point_solver_random_cases(2);
}
#[test]
fn test_bool_fixed_point_solver_random_cases_3() {
test_bool_fixed_point_solver_random_cases(3);
}
#[test]
fn test_bool_fixed_point_solver_random_cases_4() {
test_bool_fixed_point_solver_random_cases(4);
}
#[test]
fn test_bool_fixed_point_solver_random_cases_5() {
test_bool_fixed_point_solver_random_cases(5);
}
#[test]
fn test_bool_fixed_point_solver_random_cases_6() {
test_bool_fixed_point_solver_random_cases(6);
}
#[test]
fn test_bool_fixed_point_solver_random_cases_7() {
test_bool_fixed_point_solver_random_cases(7);
}
#[test]
fn test_bool_fixed_point_solver_random_cases_8() {
test_bool_fixed_point_solver_random_cases(8);
}
#[test]
fn test_bool_fixed_point_solver_random_cases_9() {
test_bool_fixed_point_solver_random_cases(9);
}
}

View file

@ -0,0 +1,117 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use std::{
fmt::{self, Write as _},
marker::PhantomData,
};
struct IndentState {
indent: usize,
need_indent: bool,
buf: String,
}
thread_local! {
static INDENT_STATE: std::cell::RefCell<IndentState> = const {
std::cell::RefCell::new(IndentState {
indent: 0,
need_indent: true,
buf: String::new(),
})
};
}
struct IndentedOut;
impl fmt::Write for IndentedOut {
fn write_str(&mut self, s: &str) -> fmt::Result {
INDENT_STATE.with_borrow_mut(|state| {
let IndentState {
indent,
need_indent,
buf,
} = state;
buf.clear();
for ch in s.chars() {
if ch == '\n' {
*need_indent = true;
} else {
if *need_indent {
*need_indent = false;
for _ in 0..*indent {
buf.push_str(" ");
}
}
}
buf.push(ch)
}
std::print!("{buf}");
});
Ok(())
}
}
#[allow(unused)]
pub(crate) struct PushIndent(PhantomData<*const ()>);
impl Drop for PushIndent {
fn drop(&mut self) {
let _ = INDENT_STATE.try_with(|state| state.borrow_mut().indent -= 1);
}
}
impl PushIndent {
#[allow(unused)]
pub(crate) fn new() -> Self {
INDENT_STATE.with_borrow_mut(|state| state.indent += 1);
Self(PhantomData)
}
}
#[allow(unused)]
pub(crate) fn indented_print_fmt<const LN: bool>(args: fmt::Arguments<'_>) {
if LN {
writeln!(IndentedOut, "{args}").expect("writing can't fail")
} else {
IndentedOut.write_fmt(args).expect("writing can't fail")
}
}
#[allow(unused)]
macro_rules! indented_print {
($($args:tt)*) => {
$crate::util::indented_print::indented_print_fmt::<false>($crate::__std::format_args!($($args)*))
};
}
#[allow(unused)]
pub(crate) use indented_print;
#[allow(unused)]
macro_rules! indented_println {
($($args:tt)*) => {
$crate::util::indented_print::indented_print_fmt::<true>($crate::__std::format_args!($($args)*))
};
}
#[allow(unused)]
pub(crate) use indented_println;
#[allow(unused)]
macro_rules! indented_dbg {
($expr:expr) => {{
let v = $expr;
$crate::util::indented_print::indented_println!(
"[{}:{}:{}] {} = {v:#?}",
file!(),
line!(),
column!(),
stringify!($expr),
);
v
}};
}
#[allow(unused)]
pub(crate) use indented_dbg;

View file

@ -0,0 +1,463 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use std::fmt;
pub enum Entry<'a, M: Map + 'a> {
Vacant(M::VacantEntry<'a>),
Occupied(M::OccupiedEntry<'a>),
}
impl<'a, M: Map + 'a> Entry<'a, M> {
pub fn and_modify<F: FnOnce(&mut M::Value)>(mut self, f: F) -> Self {
if let Self::Occupied(entry) = &mut self {
f(entry.get_mut());
}
self
}
pub fn insert_entry(self, v: M::Value) -> M::OccupiedEntry<'a> {
match self {
Self::Vacant(entry) => entry.insert_entry(v),
Self::Occupied(mut entry) => {
entry.insert(v);
entry
}
}
}
pub fn key(&self) -> &M::Key {
match self {
Self::Vacant(entry) => entry.key(),
Self::Occupied(entry) => entry.key(),
}
}
pub fn or_default(self) -> &'a mut M::Value
where
M::Value: Default,
{
self.or_insert_with(Default::default)
}
pub fn or_insert(self, v: M::Value) -> &'a mut M::Value {
match self {
Self::Vacant(entry) => entry.insert(v),
Self::Occupied(entry) => entry.into_mut(),
}
}
pub fn or_insert_with<F: FnOnce() -> M::Value>(self, f: F) -> &'a mut M::Value {
match self {
Self::Vacant(entry) => entry.insert(f()),
Self::Occupied(entry) => entry.into_mut(),
}
}
pub fn or_insert_with_key<F: FnOnce(&M::Key) -> M::Value>(self, f: F) -> &'a mut M::Value {
match self {
Self::Vacant(entry) => {
let v = f(entry.key());
entry.insert(v)
}
Self::Occupied(entry) => entry.into_mut(),
}
}
}
impl<'a, M: Map<OccupiedEntry<'a>: fmt::Debug, VacantEntry<'a>: fmt::Debug> + 'a> fmt::Debug
for Entry<'a, M>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Vacant(v) => f.debug_tuple("Vacant").field(v).finish(),
Self::Occupied(v) => f.debug_tuple("Occupied").field(v).finish(),
}
}
}
pub trait VacantEntry<'a>: Sized {
type Map: Map<VacantEntry<'a> = Self> + 'a;
fn insert(self, v: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value;
fn insert_entry(self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::OccupiedEntry<'a>;
fn into_key(self) -> <Self::Map as Map>::Key;
fn key(&self) -> &<Self::Map as Map>::Key;
}
pub trait OccupiedEntry<'a>: Sized {
type Map: Map<OccupiedEntry<'a> = Self> + 'a;
fn get(&self) -> &<Self::Map as Map>::Value;
fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value;
fn insert(&mut self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value;
fn into_mut(self) -> &'a mut <Self::Map as Map>::Value;
fn key(&self) -> &<Self::Map as Map>::Key;
fn remove(self) -> <Self::Map as Map>::Value;
fn remove_entry(self) -> (<Self::Map as Map>::Key, <Self::Map as Map>::Value);
}
pub trait Map:
Sized
+ IntoIterator<Item = (<Self as Map>::Key, <Self as Map>::Value)>
+ Extend<(<Self as Map>::Key, <Self as Map>::Value)>
+ FromIterator<(<Self as Map>::Key, <Self as Map>::Value)>
{
type Key;
type Value;
type IntoKeys: Iterator<Item = Self::Key>;
type IntoValues: Iterator<Item = Self::Value>;
type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)>
where
Self: 'a,
Self::Key: 'a,
Self::Value: 'a;
type IterMut<'a>: Iterator<Item = (&'a Self::Key, &'a mut Self::Value)>
where
Self: 'a,
Self::Key: 'a,
Self::Value: 'a;
type Keys<'a>: Iterator<Item = &'a Self::Key>
where
Self: 'a,
Self::Key: 'a;
type Values<'a>: Iterator<Item = &'a Self::Value>
where
Self: 'a,
Self::Value: 'a;
type ValuesMut<'a>: Iterator<Item = &'a mut Self::Value>
where
Self: 'a,
Self::Value: 'a;
type OccupiedEntry<'a>: OccupiedEntry<'a, Map = Self>
where
Self: 'a;
type VacantEntry<'a>: VacantEntry<'a, Map = Self>
where
Self: 'a;
fn clear(&mut self);
fn entry(&mut self, k: Self::Key) -> Entry<'_, Self>;
fn insert(&mut self, k: Self::Key, v: Self::Value) -> Option<Self::Value>;
fn into_keys(self) -> Self::IntoKeys;
fn into_values(self) -> Self::IntoValues;
fn is_empty(&self) -> bool;
fn iter(&self) -> Self::Iter<'_>;
fn iter_mut(&mut self) -> Self::IterMut<'_>;
fn keys(&self) -> Self::Keys<'_>;
fn len(&self) -> usize;
fn retain<F: FnMut(&Self::Key, &mut Self::Value) -> bool>(&mut self, f: F);
fn values(&self) -> Self::Values<'_>;
fn values_mut(&mut self) -> Self::ValuesMut<'_>;
}
pub trait MapGet<Q: ?Sized>: Map {
fn contains_key(&self, k: &Q) -> bool;
fn get(&self, k: &Q) -> Option<&Self::Value>;
fn get_mut(&mut self, k: &Q) -> Option<&mut Self::Value>;
fn remove(&mut self, k: &Q) -> Option<Self::Value>;
fn remove_entry(&mut self, k: &Q) -> Option<(Self::Key, Self::Value)>;
}
mod hash_map {
use super::*;
use crate::util::HashMap;
use hashbrown::{Equivalent, hash_map};
use std::hash::{BuildHasher, Hash};
impl<K: Eq + Hash, V, H: BuildHasher + Default> Map for HashMap<K, V, H> {
type Key = K;
type Value = V;
type IntoKeys = hash_map::IntoKeys<K, V>;
type IntoValues = hash_map::IntoValues<K, V>;
type Iter<'a>
= hash_map::Iter<'a, K, V>
where
Self: 'a,
Self::Key: 'a,
Self::Value: 'a;
type IterMut<'a>
= hash_map::IterMut<'a, K, V>
where
Self: 'a,
Self::Key: 'a,
Self::Value: 'a;
type Keys<'a>
= hash_map::Keys<'a, K, V>
where
Self: 'a,
Self::Key: 'a;
type Values<'a>
= hash_map::Values<'a, K, V>
where
Self: 'a,
Self::Value: 'a;
type ValuesMut<'a>
= hash_map::ValuesMut<'a, K, V>
where
Self: 'a,
Self::Value: 'a;
type OccupiedEntry<'a>
= hash_map::OccupiedEntry<'a, K, V, H>
where
Self: 'a;
type VacantEntry<'a>
= hash_map::VacantEntry<'a, K, V, H>
where
Self: 'a;
fn clear(&mut self) {
self.clear();
}
fn entry(&mut self, k: Self::Key) -> Entry<'_, Self> {
use hash_map::Entry::*;
match self.entry(k) {
Occupied(entry) => Entry::Occupied(entry),
Vacant(entry) => Entry::Vacant(entry),
}
}
fn insert(&mut self, k: Self::Key, v: Self::Value) -> Option<Self::Value> {
self.insert(k, v)
}
fn into_keys(self) -> Self::IntoKeys {
self.into_keys()
}
fn into_values(self) -> Self::IntoValues {
self.into_values()
}
fn is_empty(&self) -> bool {
self.is_empty()
}
fn iter(&self) -> Self::Iter<'_> {
self.iter()
}
fn iter_mut(&mut self) -> Self::IterMut<'_> {
self.iter_mut()
}
fn keys(&self) -> Self::Keys<'_> {
self.keys()
}
fn len(&self) -> usize {
self.len()
}
fn retain<F: FnMut(&Self::Key, &mut Self::Value) -> bool>(&mut self, f: F) {
self.retain(f);
}
fn values(&self) -> Self::Values<'_> {
self.values()
}
fn values_mut(&mut self) -> Self::ValuesMut<'_> {
self.values_mut()
}
}
impl<K: Eq + Hash, V, H: BuildHasher + Default, Q: ?Sized + Hash + Equivalent<K>> MapGet<Q>
for HashMap<K, V, H>
{
fn contains_key(&self, k: &Q) -> bool {
self.contains_key(k)
}
fn get(&self, k: &Q) -> Option<&Self::Value> {
self.get(k)
}
fn get_mut(&mut self, k: &Q) -> Option<&mut Self::Value> {
self.get_mut(k)
}
fn remove(&mut self, k: &Q) -> Option<Self::Value> {
self.remove(k)
}
fn remove_entry(&mut self, k: &Q) -> Option<(Self::Key, Self::Value)> {
self.remove_entry(k)
}
}
impl<'a, K: Eq + Hash, V, H: BuildHasher + Default> VacantEntry<'a>
for hash_map::VacantEntry<'a, K, V, H>
{
type Map = HashMap<K, V, H>;
fn insert(self, v: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value {
self.insert(v)
}
fn insert_entry(
self,
v: <Self::Map as Map>::Value,
) -> <Self::Map as Map>::OccupiedEntry<'a> {
self.insert_entry(v)
}
fn into_key(self) -> <Self::Map as Map>::Key {
self.into_key()
}
fn key(&self) -> &<Self::Map as Map>::Key {
self.key()
}
}
impl<'a, K: Eq + Hash, V, H: BuildHasher + Default> OccupiedEntry<'a>
for hash_map::OccupiedEntry<'a, K, V, H>
{
type Map = HashMap<K, V, H>;
fn get(&self) -> &<Self::Map as Map>::Value {
self.get()
}
fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value {
self.get_mut()
}
fn insert(&mut self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value {
self.insert(v)
}
fn into_mut(self) -> &'a mut <Self::Map as Map>::Value {
self.into_mut()
}
fn key(&self) -> &<Self::Map as Map>::Key {
self.key()
}
fn remove(self) -> <Self::Map as Map>::Value {
self.remove()
}
fn remove_entry(self) -> (<Self::Map as Map>::Key, <Self::Map as Map>::Value) {
self.remove_entry()
}
}
}
mod btree_map {
use super::*;
use std::collections::{BTreeMap, btree_map};
impl<K: Ord, V> Map for BTreeMap<K, V> {
type Key = K;
type Value = V;
type IntoKeys = btree_map::IntoKeys<K, V>;
type IntoValues = btree_map::IntoValues<K, V>;
type Iter<'a>
= btree_map::Iter<'a, K, V>
where
Self: 'a,
Self::Key: 'a,
Self::Value: 'a;
type IterMut<'a>
= btree_map::IterMut<'a, K, V>
where
Self: 'a,
Self::Key: 'a,
Self::Value: 'a;
type Keys<'a>
= btree_map::Keys<'a, K, V>
where
Self: 'a,
Self::Key: 'a;
type Values<'a>
= btree_map::Values<'a, K, V>
where
Self: 'a,
Self::Value: 'a;
type ValuesMut<'a>
= btree_map::ValuesMut<'a, K, V>
where
Self: 'a,
Self::Value: 'a;
type OccupiedEntry<'a>
= btree_map::OccupiedEntry<'a, K, V>
where
Self: 'a;
type VacantEntry<'a>
= btree_map::VacantEntry<'a, K, V>
where
Self: 'a;
fn clear(&mut self) {
self.clear();
}
fn entry(&mut self, k: Self::Key) -> Entry<'_, Self> {
use btree_map::Entry::*;
match self.entry(k) {
Occupied(entry) => Entry::Occupied(entry),
Vacant(entry) => Entry::Vacant(entry),
}
}
fn insert(&mut self, k: Self::Key, v: Self::Value) -> Option<Self::Value> {
self.insert(k, v)
}
fn into_keys(self) -> Self::IntoKeys {
self.into_keys()
}
fn into_values(self) -> Self::IntoValues {
self.into_values()
}
fn is_empty(&self) -> bool {
self.is_empty()
}
fn iter(&self) -> Self::Iter<'_> {
self.iter()
}
fn iter_mut(&mut self) -> Self::IterMut<'_> {
self.iter_mut()
}
fn keys(&self) -> Self::Keys<'_> {
self.keys()
}
fn len(&self) -> usize {
self.len()
}
fn retain<F: FnMut(&Self::Key, &mut Self::Value) -> bool>(&mut self, f: F) {
self.retain(f);
}
fn values(&self) -> Self::Values<'_> {
self.values()
}
fn values_mut(&mut self) -> Self::ValuesMut<'_> {
self.values_mut()
}
}
impl<K: Ord + std::borrow::Borrow<Q>, V, Q: ?Sized + Ord> MapGet<Q> for BTreeMap<K, V> {
fn contains_key(&self, k: &Q) -> bool {
self.contains_key(k)
}
fn get(&self, k: &Q) -> Option<&Self::Value> {
self.get(k)
}
fn get_mut(&mut self, k: &Q) -> Option<&mut Self::Value> {
self.get_mut(k)
}
fn remove(&mut self, k: &Q) -> Option<Self::Value> {
self.remove(k)
}
fn remove_entry(&mut self, k: &Q) -> Option<(Self::Key, Self::Value)> {
self.remove_entry(k)
}
}
impl<'a, K: Ord, V> VacantEntry<'a> for btree_map::VacantEntry<'a, K, V> {
type Map = BTreeMap<K, V>;
fn insert(self, v: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value {
self.insert(v)
}
fn insert_entry(
self,
v: <Self::Map as Map>::Value,
) -> <Self::Map as Map>::OccupiedEntry<'a> {
self.insert_entry(v)
}
fn into_key(self) -> <Self::Map as Map>::Key {
self.into_key()
}
fn key(&self) -> &<Self::Map as Map>::Key {
self.key()
}
}
impl<'a, K: Ord, V> OccupiedEntry<'a> for btree_map::OccupiedEntry<'a, K, V> {
type Map = BTreeMap<K, V>;
fn get(&self) -> &<Self::Map as Map>::Value {
self.get()
}
fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value {
self.get_mut()
}
fn insert(&mut self, v: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value {
self.insert(v)
}
fn into_mut(self) -> &'a mut <Self::Map as Map>::Value {
self.into_mut()
}
fn key(&self) -> &<Self::Map as Map>::Key {
self.key()
}
fn remove(self) -> <Self::Map as Map>::Value {
self.remove()
}
fn remove_entry(self) -> (<Self::Map as Map>::Key, <Self::Map as Map>::Value) {
self.remove_entry()
}
}
}

View file

@ -241,15 +241,13 @@ mod tests {
/// 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]
let clk: Clock = m.input();
#[hdl]
let cd = wire();
connect(
cd,
#[hdl]
ClockDomain {
clk,
clk: formal_global_clock(),
rst: formal_reset().to_reset(),
},
);
@ -280,7 +278,7 @@ mod tests {
#[hdl]
let index_to_check = wire(index_ty);
connect(index_to_check, any_const(index_ty));
hdl_assume(clk, index_to_check.cmp_lt(capacity.get()), "");
hdl_assume(cd.clk, index_to_check.cmp_lt(capacity.get()), "");
// instantiate and connect the queue
#[hdl]
@ -300,13 +298,13 @@ mod tests {
let expected_count_reg = reg_builder().clock_domain(cd).reset(count_ty.zero());
#[hdl]
if ReadyValid::firing(dut.inp) & !ReadyValid::firing(dut.out) {
hdl_assert(clk, expected_count_reg.cmp_ne(capacity.get()), "");
hdl_assert(cd.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) {
hdl_assert(clk, expected_count_reg.cmp_ne(count_ty.zero()), "");
hdl_assert(cd.clk, expected_count_reg.cmp_ne(count_ty.zero()), "");
connect_any(expected_count_reg, expected_count_reg - 1u8);
}
hdl_assert(clk, expected_count_reg.cmp_eq(dut.count), "");
hdl_assert(cd.clk, expected_count_reg.cmp_eq(dut.count), "");
// keep an independent write index into the FIFO's circular buffer
#[hdl]
@ -374,7 +372,7 @@ mod tests {
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), ""),
HdlNone => hdl_assert(cd.clk, HdlOption::is_none(out_firing_data), ""),
// If we are indeed receiving some data...
HdlSome(data_in) => {
#[hdl]
@ -382,7 +380,9 @@ mod tests {
// ... 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), ""),
HdlSome(data_out) => {
hdl_assert(cd.clk, data_out.cmp_eq(data_in), "")
}
// If we are receiving, but not transmitting,
// store the received data in the holding
// register.
@ -397,11 +397,11 @@ mod tests {
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), ""),
HdlNone => hdl_assert(cd.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), "");
hdl_assert(cd.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);
@ -417,17 +417,17 @@ mod tests {
connect(dut.dbg.index_to_check, index_to_check);
#[hdl]
if let HdlSome(stored) = stored_reg {
hdl_assert(clk, stored.cmp_eq(dut.dbg.stored), "");
hdl_assert(cd.clk, stored.cmp_eq(dut.dbg.stored), "");
}
// 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), "");
hdl_assert(cd.clk, inp_index_reg.cmp_eq(dut.dbg.inp_index), "");
hdl_assert(cd.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()), "");
hdl_assert(cd.clk, inp_index_reg.cmp_lt(capacity.get()), "");
hdl_assert(cd.clk, out_index_reg.cmp_lt(capacity.get()), "");
// strongly constrain the state of the holding register
//
@ -455,7 +455,7 @@ mod tests {
connect(expected_stored, pending_reads.cmp_lt(dut.count));
// sync with the state of the holding register
hdl_assert(
clk,
cd.clk,
expected_stored.cmp_eq(HdlOption::is_some(stored_reg)),
"",
);

View file

@ -0,0 +1,234 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::util::HashMap;
use hashbrown::hash_map::Entry;
use serde::{Deserialize, Serialize, de::Error};
use std::{
any::TypeId,
borrow::Cow,
fmt::Write,
hash::{BuildHasher, Hash, Hasher},
marker::PhantomData,
sync::Mutex,
};
pub(crate) struct SerdeByIdProperties<T: SerdeByIdTrait> {
type_id: TypeId,
type_name: &'static str,
_phantom: PhantomData<fn(T) -> T>,
}
impl<T: SerdeByIdTrait> Clone for SerdeByIdProperties<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: SerdeByIdTrait> Copy for SerdeByIdProperties<T> {}
impl<T: SerdeByIdTrait> SerdeByIdProperties<T> {
pub fn of<U: ?Sized + 'static>() -> Self {
Self {
type_id: TypeId::of::<U>(),
type_name: std::any::type_name::<U>(),
_phantom: PhantomData,
}
}
}
pub(crate) trait SerdeByIdTrait: Hash + Eq + Clone + 'static + Send {
fn serde_by_id_properties(&self) -> SerdeByIdProperties<Self>;
fn static_table() -> &'static SerdeByIdTable<Self>;
const NAME: &'static str;
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
struct SerdeRandomId([u32; 4]);
#[derive(Serialize, Deserialize)]
pub(crate) struct SerdeId<'a, T: SerdeByIdTrait> {
random_id: SerdeRandomId,
#[serde(borrow)]
type_name: Cow<'a, str>,
#[serde(skip)]
_phantom: PhantomData<fn(T) -> T>,
}
impl<'a, T: SerdeByIdTrait> Clone for SerdeId<'a, T> {
fn clone(&self) -> Self {
Self {
random_id: self.random_id,
type_name: self.type_name.clone(),
_phantom: PhantomData,
}
}
}
impl<'a, T: SerdeByIdTrait> Eq for SerdeId<'a, T> {}
impl<'a, 'b, T: SerdeByIdTrait> PartialEq<SerdeId<'b, T>> for SerdeId<'a, T> {
fn eq(&self, other: &SerdeId<'b, T>) -> bool {
let Self {
random_id,
type_name,
_phantom: _,
} = self;
*random_id == other.random_id && *type_name == other.type_name
}
}
impl<'a, T: SerdeByIdTrait> Hash for SerdeId<'a, T> {
fn hash<H: Hasher>(&self, state: &mut H) {
let Self {
random_id,
type_name: _,
_phantom: _,
} = self;
random_id.hash(state);
}
}
struct SerdeByIdTableRest<T: SerdeByIdTrait> {
from_serde: HashMap<SerdeId<'static, T>, T>,
serde_id_random_state: std::hash::RandomState,
buffer: String,
}
impl<T: SerdeByIdTrait> Default for SerdeByIdTableRest<T> {
fn default() -> Self {
Self {
from_serde: Default::default(),
serde_id_random_state: Default::default(),
buffer: Default::default(),
}
}
}
impl<T: SerdeByIdTrait> SerdeByIdTableRest<T> {
fn add_new(&mut self, value: T) -> SerdeId<'static, T> {
let properties = value.serde_by_id_properties();
let mut try_number = 0u64;
let mut hasher = self.serde_id_random_state.build_hasher();
// extract more bits of randomness from TypeId -- its Hash impl only hashes 64-bits
write!(self.buffer, "{:?}", properties.type_id).expect("shouldn't ever fail");
self.buffer.hash(&mut hasher);
loop {
let mut hasher = hasher.clone();
try_number.hash(&mut hasher);
try_number += 1;
let key = SerdeId {
random_id: SerdeRandomId(std::array::from_fn(|i| {
let mut hasher = hasher.clone();
i.hash(&mut hasher);
hasher.finish() as u32
})),
type_name: Cow::Borrowed(properties.type_name),
_phantom: PhantomData,
};
match self.from_serde.entry(key) {
Entry::Occupied(_) => continue,
Entry::Vacant(e) => {
let key = e.key().clone();
e.insert(value);
return key;
}
}
}
}
}
pub(crate) struct SerdeByIdTableMut<T: SerdeByIdTrait> {
to_serde: HashMap<T, SerdeId<'static, T>>,
rest: SerdeByIdTableRest<T>,
}
impl<T: SerdeByIdTrait> Default for SerdeByIdTableMut<T> {
fn default() -> Self {
Self {
to_serde: Default::default(),
rest: Default::default(),
}
}
}
impl<T: SerdeByIdTrait> SerdeByIdTableMut<T> {
pub(crate) fn to_serde(&mut self, value: &T) -> SerdeId<'static, T> {
if let Some(retval) = self.to_serde.get(value) {
return retval.clone();
}
self.to_serde_insert(value)
}
#[cold]
fn to_serde_insert(&mut self, value: &T) -> SerdeId<'static, T> {
let value = value.clone();
let retval = self.rest.add_new(value.clone());
self.to_serde.insert(value, retval.clone());
retval
}
pub(crate) fn from_serde(&self, id: &SerdeId<'_, T>) -> Option<T> {
self.rest.from_serde.get(id).cloned()
}
}
pub(crate) struct SerdeByIdTable<T: SerdeByIdTrait>(Mutex<Option<SerdeByIdTableMut<T>>>);
impl<T: SerdeByIdTrait> SerdeByIdTable<T> {
pub(crate) const fn new() -> Self {
Self(Mutex::new(None))
}
pub(crate) fn to_serde(&self, value: &T) -> SerdeId<'static, T> {
self.0
.lock()
.expect("shouldn't be poison")
.get_or_insert_with(
#[cold]
|| Default::default(),
)
.to_serde(value)
}
pub(crate) fn from_serde(&self, id: &SerdeId<'_, T>) -> Option<T> {
self.0
.lock()
.expect("shouldn't be poison")
.get_or_insert_with(
#[cold]
|| Default::default(),
)
.from_serde(id)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, Ord, PartialOrd)]
pub(crate) struct SerdeById<T: SerdeByIdTrait> {
pub(crate) inner: T,
}
impl<'de, T: SerdeByIdTrait> Deserialize<'de> for SerdeById<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let id = SerdeId::deserialize(deserializer)?;
let inner = T::static_table().from_serde(&id).ok_or_else(|| {
D::Error::custom(format_args!(
"doesn't match any {} that was serialized this time this program was run: type_name={:?}",
T::NAME,
id.type_name,
))
})?;
Ok(Self { inner })
}
}
impl<T: SerdeByIdTrait> Serialize for SerdeById<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
T::static_table()
.to_serde(&self.inner)
.serialize(serializer)
}
}

View file

@ -0,0 +1,352 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::util::{
HashMap,
map_trait::{self, Map, MapGet, OccupiedEntry as _, VacantEntry as _},
};
use petgraph::unionfind::UnionFind;
use std::{collections::BTreeMap, fmt, marker::PhantomData};
pub struct UnionFindMap<K, V, M = HashMap<K, usize>> {
uf: UnionFind<usize>,
keys_to_indexes: M,
values: Vec<Option<V>>,
_phantom: PhantomData<K>,
}
impl<K: fmt::Debug, V: fmt::Debug, M: Map<Key = K, Value = usize>> fmt::Debug
for UnionFindMap<K, V, M>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut indexes_to_keys = vec![None; self.len()];
for (k, &index) in self.keys_to_indexes.iter() {
indexes_to_keys[index] = Some(k);
}
let mut debug_map = f.debug_map();
for (index, key) in indexes_to_keys.into_iter().enumerate() {
if let Some(key) = key {
debug_map.key(key);
} else {
debug_map.key(&fmt::from_fn(|f| {
f.write_str("<<there's a misbehaving key>>")
}));
}
let set_index = self.uf.find(index);
debug_map.value(&fmt::from_fn(|f| {
write!(f, "@{set_index} ")?;
if set_index == index {
let Some(value) = &self.values[index] else {
unreachable!();
};
value.fmt(f)
} else {
Ok(())
}
}));
}
debug_map.finish()
}
}
impl<K, V, M: Map<Key = K, Value = usize>> UnionFindMap<K, V, M> {
/// returns the number of keys, not the number of sets/values
pub fn len(&self) -> usize {
self.values.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn capacity(&self) -> usize {
self.values.capacity()
}
#[track_caller]
pub fn equiv<K1: ?Sized, K2: ?Sized>(&self, k1: &K1, k2: &K2) -> bool
where
M: MapGet<K1> + MapGet<K2>,
{
self.try_equiv(k1, k2).expect("key not found")
}
pub fn try_equiv<K1: ?Sized, K2: ?Sized>(&self, k1: &K1, k2: &K2) -> Option<bool>
where
M: MapGet<K1> + MapGet<K2>,
{
let &index1 = self.keys_to_indexes.get(k1)?;
let &index2 = self.keys_to_indexes.get(k2)?;
Some(self.uf.equiv(index1, index2))
}
#[track_caller]
pub fn find<Q: ?Sized>(&self, k: &Q) -> &V
where
M: MapGet<Q>,
{
self.try_find(k).expect("key not found")
}
pub fn try_find<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
M: MapGet<Q>,
{
let &index = self.keys_to_indexes.get(k)?;
self.values[self.uf.find(index)].as_ref()
}
#[track_caller]
pub fn find_mut<Q: ?Sized>(&mut self, k: &Q) -> &mut V
where
M: MapGet<Q>,
{
self.try_find_mut(k).expect("key not found")
}
pub fn try_find_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
M: MapGet<Q>,
{
let &index = self.keys_to_indexes.get(k)?;
self.values[self.uf.find_mut(index)].as_mut()
}
/// inserts a new key as a new set, otherwise replaces the value for the set containing the passed-in key
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
match self.entry(k) {
Entry::Vacant(entry) => {
entry.insert(v);
None
}
Entry::Occupied(mut entry) => Some(entry.insert(v)),
}
}
pub fn entry(&mut self, k: K) -> Entry<'_, K, V, M> {
match self.keys_to_indexes.entry(k) {
map_trait::Entry::Vacant(keys_to_indexes_entry) => Entry::Vacant(VacantEntry {
keys_to_indexes_entry,
uf: &mut self.uf,
values: &mut self.values,
}),
map_trait::Entry::Occupied(keys_to_indexes_entry) => {
let set_index = self.uf.find_mut(*keys_to_indexes_entry.get());
Entry::Occupied(OccupiedEntry {
keys_to_indexes_entry,
set_index,
values: &mut self.values,
})
}
}
}
/// Unify the two sets containing `k1` and `k2`.
/// If the sets were the same, returns `Some((false, value))`,
/// otherwise calling `merge` to merge their values and returning `Some((true, value))`.
/// Returns `None` if either of the keys weren't found.
pub fn try_union<K1: ?Sized, K2: ?Sized, F>(
&mut self,
k1: &K1,
k2: &K2,
merge: F,
) -> Option<(bool, &mut V)>
where
M: MapGet<K1> + MapGet<K2>,
F: FnOnce(&K1, V, &K2, V) -> V,
{
let &index1 = self.keys_to_indexes.get(k1)?;
let &index2 = self.keys_to_indexes.get(k2)?;
let index1 = self.uf.find_mut(index1);
let index2 = self.uf.find_mut(index2);
if index1 == index2 {
return Some((false, self.values[index1].as_mut()?));
}
assert!(self.uf.union(index1, index2));
let v1 = self.values[index1].take().expect("known to be Some");
let v2 = self.values[index2].take().expect("known to be Some");
let dest = &mut self.values[self.uf.find_mut(index1)];
let dest = dest.insert(merge(k1, v1, k2, v2));
Some((true, dest))
}
/// Unify the two sets containing `k1` and `k2`.
/// If the sets were the same, returns `(false, value)`,
/// otherwise calling `merge` to merge their values and returning `(true, value)`.
/// panics if either of the keys weren't found.
#[track_caller]
pub fn union<K1: ?Sized, K2: ?Sized, F>(&mut self, k1: &K1, k2: &K2, merge: F) -> (bool, &mut V)
where
M: MapGet<K1> + MapGet<K2>,
F: FnOnce(&K1, V, &K2, V) -> V,
{
self.try_union(k1, k2, merge).expect("key not found")
}
}
impl<K, V> UnionFindMap<K, V> {
pub fn new() -> Self {
Self::with_hasher(Default::default())
}
pub fn with_capacity(capacity: usize) -> Self {
Self::with_capacity_and_hasher(capacity, Default::default())
}
}
impl<K, V> UnionFindMap<K, V, BTreeMap<K, usize>> {
pub const fn new_btree() -> Self {
Self {
uf: UnionFind::new_empty(),
keys_to_indexes: BTreeMap::new(),
values: Vec::new(),
_phantom: PhantomData,
}
}
}
impl<K, V, H> UnionFindMap<K, V, HashMap<K, usize, H>> {
pub const fn with_hasher(hash_builder: H) -> Self {
Self {
uf: UnionFind::new_empty(),
keys_to_indexes: HashMap::with_hasher(hash_builder),
values: Vec::new(),
_phantom: PhantomData,
}
}
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: H) -> Self {
Self {
uf: UnionFind::with_capacity(capacity),
keys_to_indexes: HashMap::with_capacity_and_hasher(capacity, hash_builder),
values: Vec::with_capacity(capacity),
_phantom: PhantomData,
}
}
}
impl<K, V, M: Default> Default for UnionFindMap<K, V, M> {
fn default() -> Self {
Self {
uf: UnionFind::new_empty(),
keys_to_indexes: M::default(),
values: Vec::new(),
_phantom: PhantomData,
}
}
}
pub struct OccupiedEntry<'a, K, V, M: Map<Key = K, Value = usize> + 'a> {
keys_to_indexes_entry: M::OccupiedEntry<'a>,
set_index: usize,
values: &'a mut [Option<V>],
}
impl<'a, K, V, M: Map<Key = K, Value = usize> + 'a> OccupiedEntry<'a, K, V, M> {
pub fn get(&self) -> &V {
let Some(v) = &self.values[self.set_index] else {
unreachable!()
};
v
}
pub fn get_mut(&mut self) -> &mut V {
let Some(v) = &mut self.values[self.set_index] else {
unreachable!()
};
v
}
/// replaces the value for this set
pub fn insert(&mut self, v: V) -> V {
std::mem::replace(self.get_mut(), v)
}
pub fn into_mut(self) -> &'a mut V {
let Some(v) = &mut self.values[self.set_index] else {
unreachable!()
};
v
}
pub fn key(&self) -> &K {
self.keys_to_indexes_entry.key()
}
}
pub struct VacantEntry<'a, K, V, M: Map<Key = K, Value = usize> + 'a> {
keys_to_indexes_entry: M::VacantEntry<'a>,
uf: &'a mut UnionFind<usize>,
values: &'a mut Vec<Option<V>>,
}
impl<'a, K, V, M: Map<Key = K, Value = usize> + 'a> VacantEntry<'a, K, V, M> {
/// inserts a new key as a new set
pub fn insert(self, v: V) -> &'a mut V {
self.insert_entry(v).into_mut()
}
/// inserts a new key as a new set
pub fn insert_entry(self, v: V) -> OccupiedEntry<'a, K, V, M> {
let Self {
keys_to_indexes_entry,
uf,
values,
} = self;
let set_index = uf.new_set();
values.push(Some(v));
OccupiedEntry {
keys_to_indexes_entry: keys_to_indexes_entry.insert_entry(set_index),
set_index,
values,
}
}
pub fn into_key(self) -> K {
self.keys_to_indexes_entry.into_key()
}
pub fn key(&self) -> &K {
self.keys_to_indexes_entry.key()
}
}
pub enum Entry<'a, K, V, M: Map<Key = K, Value = usize> + 'a> {
Vacant(VacantEntry<'a, K, V, M>),
Occupied(OccupiedEntry<'a, K, V, M>),
}
impl<'a, K, V, M: Map<Key = K, Value = usize> + 'a> Entry<'a, K, V, M> {
pub fn and_modify<F: FnOnce(&mut V)>(mut self, f: F) -> Self {
if let Self::Occupied(entry) = &mut self {
f(entry.get_mut());
}
self
}
/// inserts a new key as a new set, otherwise replaces the value for the set containing the passed-in key
pub fn insert_entry(self, v: V) -> OccupiedEntry<'a, K, V, M> {
match self {
Self::Vacant(entry) => entry.insert_entry(v),
Self::Occupied(mut entry) => {
entry.insert(v);
entry
}
}
}
pub fn key(&self) -> &K {
match self {
Self::Vacant(entry) => entry.key(),
Self::Occupied(entry) => entry.key(),
}
}
/// inserts a new key as a new set
pub fn or_default(self) -> &'a mut V
where
V: Default,
{
self.or_insert_with(V::default)
}
/// inserts a new key as a new set
pub fn or_insert(self, v: V) -> &'a mut V {
match self {
Self::Vacant(entry) => entry.insert(v),
Self::Occupied(entry) => entry.into_mut(),
}
}
/// inserts a new key as a new set
pub fn or_insert_with<F: FnOnce() -> V>(self, f: F) -> &'a mut V {
match self {
Self::Vacant(entry) => entry.insert(f()),
Self::Occupied(entry) => entry.into_mut(),
}
}
/// inserts a new key as a new set
pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, f: F) -> &'a mut V {
match self {
Self::Vacant(entry) => {
let v = f(entry.key());
entry.insert(v)
}
Self::Occupied(entry) => entry.into_mut(),
}
}
}

View file

@ -546,7 +546,7 @@ impl<W: fmt::Write> Visitor for XdcFileWriter<W> {
base.source_location(),
)? {},
}
match base.canonical_ty() {
match base.canonical_ty().unwrap_transparent_types() {
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
@ -563,6 +563,9 @@ impl<W: fmt::Write> Visitor for XdcFileWriter<W> {
v,
base.source_location(),
)? {},
CanonicalType::TraceAsString(_) => {
unreachable!("handled by unwrap_transparent_types")
}
}
self.required_dont_touch_targets.insert(target);
match v {
@ -592,6 +595,9 @@ impl<W: fmt::Write> Visitor for XdcFileWriter<W> {
v,
instance.source_location(),
)? {},
TargetBase::FormalInput(_) | TargetBase::SimIoForGlobal(_) => {
unreachable!("base.is_valid_annotation_target() is known to be false")
}
}
}
}

View file

@ -58,11 +58,13 @@ impl<T: Type> Wire<T> {
ty: T::from_canonical(ty),
}
}
#[track_caller]
pub fn new_unchecked(
scoped_name: ScopedNameId,
source_location: SourceLocation,
ty: T,
) -> Self {
scoped_name.0.assert_is_name_id();
Self {
name: scoped_name,
source_location,
@ -76,7 +78,7 @@ impl<T: Type> Wire<T> {
self.containing_module_name_id().0
}
pub fn containing_module_name_id(&self) -> NameId {
self.name.0
self.name.0.unwrap_name_id()
}
pub fn name(&self) -> Interned<str> {
self.name_id().0

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,6 @@
<!--
SPDX-License-Identifier: LGPL-3.0-or-later
See Notices.txt for copyright information
-->
`my_test.vcd` is used in the doctest of `fayalite::testing::checked_vcd_output`

View file

@ -0,0 +1,13 @@
$timescale 1 ps $end
$scope module my_module $end
$var wire 8 gAF7X a $end
$var wire 8 QS=a/ b $end
$upscope $end
$enddefinitions $end
$dumpvars
b0 gAF7X
b0 QS=a/
$end
#1000000
b1100100 gAF7X
b101010 QS=a/

View file

@ -0,0 +1,166 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use fayalite::{prelude::*, ty::SimValueDebug};
use std::fmt;
#[hdl(outline_generated)]
struct MyStruct0<T, S: Size> {
v: T,
a: ArrayType<UInt<8>, S>,
}
#[hdl]
#[test]
fn check_my_struct0() {
let ty = MyStruct0[UInt[8]][3];
assert_eq!(
format!("{ty:?}"),
"MyStruct0 { v: UInt<8>, a: Array<UInt<8>, 3> }",
);
assert_eq!(
format!("{:?}", ty.mask_type()),
"MaskType<MyStruct0> { v: Bool, a: Array<Bool, 3> }",
);
let v = #[hdl(sim)]
MyStruct0::<_, _> {
v: 0x23u8,
a: [1u8, 2, 3],
};
assert_eq!(
format!("{v:?}"),
"MyStruct0 { v: 0x23_u8, a: [0x1_u8, 0x2_u8, 0x3_u8] }",
);
}
#[hdl(outline_generated, custom_debug())]
struct MyStruct1<T, S: Size> {
v: T,
a: ArrayType<UInt<8>, S>,
}
impl<T: Type, S: Size> fmt::Debug for MyStruct1<T, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { v, a } = self;
f.debug_struct("Custom<MyStruct1>")
.field("v", v)
.field("a", a)
.finish()
}
}
impl<T: Type, S: Size> SimValueDebug for MyStruct1<T, S> {
#[hdl]
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
#[hdl(sim)]
let Self { v, a } = value;
f.debug_struct("Custom<MyStruct1>")
.field("v", &v)
.field("a", &a)
.finish()
}
}
#[hdl]
#[test]
fn check_my_struct1() {
let ty = MyStruct1[UInt[8]][3];
assert_eq!(
format!("{ty:?}"),
"Custom<MyStruct1> { v: UInt<8>, a: Array<UInt<8>, 3> }",
);
assert_eq!(
format!("{:?}", ty.mask_type()),
"MaskType<MyStruct1> { v: Bool, a: Array<Bool, 3> }",
);
let v = #[hdl(sim)]
MyStruct1::<_, _> {
v: 0x23u8,
a: [1u8, 2, 3],
};
assert_eq!(
format!("{v:?}"),
"Custom<MyStruct1> { v: 0x23_u8, a: [0x1_u8, 0x2_u8, 0x3_u8] }",
);
}
#[hdl(outline_generated)]
enum MyEnum0<T, S: Size> {
Unit,
V(T),
A(ArrayType<UInt<8>, S>),
}
#[hdl]
#[test]
fn check_my_enum0() {
let ty = MyEnum0[UInt[8]][3];
assert_eq!(
format!("{ty:?}"),
"MyEnum0 { Unit: (), V: UInt<8>, A: Array<UInt<8>, 3> }",
);
let v = #[hdl(sim)]
ty.Unit();
assert_eq!(format!("{v:?}"), "Unit");
let v = #[hdl(sim)]
ty.V(0x23u8);
assert_eq!(format!("{v:?}"), "V(0x23_u8)");
let v = #[hdl(sim)]
ty.A([1u8, 2, 3]);
assert_eq!(format!("{v:?}"), "A([0x1_u8, 0x2_u8, 0x3_u8])");
}
#[hdl(outline_generated, custom_debug())]
enum MyEnum1<T, S: Size> {
Unit,
V(T),
A(ArrayType<UInt<8>, S>),
}
impl<T: Type, S: Size> fmt::Debug for MyEnum1<T, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { Unit, V, A } = self;
f.debug_struct("Custom<MyEnum1>")
.field("Unit", Unit)
.field("V", V)
.field("A", A)
.finish()
}
}
impl<T: Type, S: Size> SimValueDebug for MyEnum1<T, S> {
#[hdl]
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
type SimValueT<T> = <T as Type>::SimValue;
match value {
SimValueT::<Self>::Unit(_) => f.write_str("MyEnum1::Unit"),
SimValueT::<Self>::V(v, _) => f.debug_tuple("MyEnum1::V").field(v).finish(),
SimValueT::<Self>::A(a, _) => f.debug_tuple("MyEnum1::A").field(a).finish(),
SimValueT::<Self>::Unknown(_) => f.write_str("MyEnum1::Unknown"),
}
}
}
#[hdl]
#[test]
fn check_my_enum1() {
let ty = MyEnum1[UInt[8]][3];
assert_eq!(
format!("{ty:?}"),
"Custom<MyEnum1> { Unit: (), V: UInt<8>, A: Array<UInt<8>, 3> }",
);
let v = #[hdl(sim)]
ty.Unit();
assert_eq!(format!("{v:?}"), "MyEnum1::Unit");
let v = #[hdl(sim)]
ty.V(0x23u8);
assert_eq!(format!("{v:?}"), "MyEnum1::V(0x23_u8)");
let v = #[hdl(sim)]
ty.A([1u8, 2, 3]);
assert_eq!(format!("{v:?}"), "MyEnum1::A([0x1_u8, 0x2_u8, 0x3_u8])");
}

View file

@ -13,7 +13,7 @@ use fayalite::{
};
use serde_json::json;
#[hdl(outline_generated)]
#[hdl(outline_generated, cmp_eq)]
pub enum TestEnum {
A,
B(UInt<8>),
@ -679,6 +679,224 @@ circuit check_enum_literals:
};
}
#[hdl_module(outline_generated)]
pub fn check_enum_cmp_eq() {
#[hdl]
let lhs: TestEnum = m.input();
#[hdl]
let rhs: TestEnum = m.input();
#[hdl]
let eq: Bool = m.output();
connect(eq, lhs.cmp_eq(rhs));
}
#[test]
fn test_enum_cmp_eq() {
let _n = SourceLocation::normalize_files_for_tests();
let m = check_enum_cmp_eq();
dbg!(m);
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_enums: None,
..ExportOptions::default()
},
"/test/check_enum_cmp_eq.fir": r"FIRRTL version 3.2.0
circuit check_enum_cmp_eq:
type Ty0 = {|A, B: UInt<8>, C: UInt<1>[3]|}
module check_enum_cmp_eq: @[module-XXXXXXXXXX.rs 1:1]
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
wire _cast_enum_to_bits_expr: UInt<10>
match lhs:
A:
connect _cast_enum_to_bits_expr, UInt<10>(0)
B(_cast_enum_to_bits_expr_B):
connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_B, UInt<2>(1)), 10)
C(_cast_enum_to_bits_expr_C):
wire _cast_array_to_bits_expr: UInt<1>[3]
connect _cast_array_to_bits_expr[0], _cast_enum_to_bits_expr_C[0]
connect _cast_array_to_bits_expr[1], _cast_enum_to_bits_expr_C[1]
connect _cast_array_to_bits_expr[2], _cast_enum_to_bits_expr_C[2]
wire _cast_to_bits_expr: UInt<3>
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
connect _cast_enum_to_bits_expr, pad(cat(_cast_to_bits_expr, UInt<2>(2)), 10)
wire _cast_enum_to_bits_expr_1: UInt<10>
match rhs:
A:
connect _cast_enum_to_bits_expr_1, UInt<10>(0)
B(_cast_enum_to_bits_expr_B_1):
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_B_1, UInt<2>(1)), 10)
C(_cast_enum_to_bits_expr_C_1):
wire _cast_array_to_bits_expr_1: UInt<1>[3]
connect _cast_array_to_bits_expr_1[0], _cast_enum_to_bits_expr_C_1[0]
connect _cast_array_to_bits_expr_1[1], _cast_enum_to_bits_expr_C_1[1]
connect _cast_array_to_bits_expr_1[2], _cast_enum_to_bits_expr_C_1[2]
wire _cast_to_bits_expr_1: UInt<3>
connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0]))
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_to_bits_expr_1, UInt<2>(2)), 10)
connect eq, eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1) @[module-XXXXXXXXXX.rs 5:1]
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_enums: Some(SimplifyEnumsKind::SimplifyToEnumsWithNoBody),
..ExportOptions::default()
},
"/test/check_enum_cmp_eq.fir": r"FIRRTL version 3.2.0
circuit check_enum_cmp_eq:
type Ty0 = {|A, B, C|}
type Ty1 = {tag: Ty0, body: UInt<8>}
module check_enum_cmp_eq: @[module-XXXXXXXXXX.rs 1:1]
input lhs: Ty1 @[module-XXXXXXXXXX.rs 2:1]
input rhs: Ty1 @[module-XXXXXXXXXX.rs 3:1]
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
wire _cast_enum_to_bits_expr: UInt<2>
match lhs.tag:
A:
connect _cast_enum_to_bits_expr, UInt<2>(0)
B:
connect _cast_enum_to_bits_expr, UInt<2>(1)
C:
connect _cast_enum_to_bits_expr, UInt<2>(2)
wire _cast_enum_to_bits_expr_1: UInt<2>
match rhs.tag:
A:
connect _cast_enum_to_bits_expr_1, UInt<2>(0)
B:
connect _cast_enum_to_bits_expr_1, UInt<2>(1)
C:
connect _cast_enum_to_bits_expr_1, UInt<2>(2)
when eq(_cast_enum_to_bits_expr, _cast_enum_to_bits_expr_1): @[module-XXXXXXXXXX.rs 1:1]
match lhs.tag: @[module-XXXXXXXXXX.rs 1:1]
A:
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
B:
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
C:
wire _cast_bits_to_array_expr: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
wire _cast_bits_to_array_expr_1: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
wire _array_structural_eq: UInt<1>
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
wire _array_structural_eq_1: UInt<1>
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts),
..ExportOptions::default()
},
"/test/check_enum_cmp_eq.fir": r"FIRRTL version 3.2.0
circuit check_enum_cmp_eq:
type Ty0 = {tag: UInt<2>, body: UInt<8>}
module check_enum_cmp_eq: @[module-XXXXXXXXXX.rs 1:1]
input lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1]
input rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1]
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
when eq(lhs.tag, rhs.tag): @[module-XXXXXXXXXX.rs 1:1]
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
connect __enum_structural_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
else:
wire _cast_bits_to_array_expr: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
connect _cast_bits_to_array_expr_flattened[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
connect _cast_bits_to_array_expr_flattened[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
wire _cast_bits_to_array_expr_1: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
wire _array_structural_eq: UInt<1>
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
wire _array_structural_eq_1: UInt<1>
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_enums: Some(SimplifyEnumsKind::ReplaceWithUInt),
..ExportOptions::default()
},
"/test/check_enum_cmp_eq.fir": r"FIRRTL version 3.2.0
circuit check_enum_cmp_eq:
module check_enum_cmp_eq: @[module-XXXXXXXXXX.rs 1:1]
input lhs: UInt<10> @[module-XXXXXXXXXX.rs 2:1]
input rhs: UInt<10> @[module-XXXXXXXXXX.rs 3:1]
output eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
wire __enum_structural_eq: UInt<1> @[module-XXXXXXXXXX.rs 1:1]
connect eq, __enum_structural_eq @[module-XXXXXXXXXX.rs 5:1]
connect __enum_structural_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 1:1]
when eq(bits(lhs, 1, 0), bits(rhs, 1, 0)): @[module-XXXXXXXXXX.rs 1:1]
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 1:1]
connect __enum_structural_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 1:1]
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 1:1]
connect __enum_structural_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 1:1]
else:
wire _cast_bits_to_array_expr: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr[0], _cast_bits_to_array_expr_flattened[0]
connect _cast_bits_to_array_expr_flattened[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr[1], _cast_bits_to_array_expr_flattened[1]
connect _cast_bits_to_array_expr_flattened[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr[2], _cast_bits_to_array_expr_flattened[2]
wire _cast_bits_to_array_expr_1: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_1: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_1[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_1[0], _cast_bits_to_array_expr_flattened_1[0]
connect _cast_bits_to_array_expr_flattened_1[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_1[1], _cast_bits_to_array_expr_flattened_1[1]
connect _cast_bits_to_array_expr_flattened_1[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_1[2], _cast_bits_to_array_expr_flattened_1[2]
wire _array_structural_eq: UInt<1>
connect _array_structural_eq, and(eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0]), eq(_cast_bits_to_array_expr[1], _cast_bits_to_array_expr_1[1]))
wire _array_structural_eq_1: UInt<1>
connect _array_structural_eq_1, and(_array_structural_eq, eq(_cast_bits_to_array_expr[2], _cast_bits_to_array_expr_1[2]))
connect __enum_structural_eq, _array_structural_eq_1 @[module-XXXXXXXXXX.rs 1:1]
",
};
}
#[hdl_module(outline_generated)]
pub fn check_struct_enum_match() {
#[hdl]
@ -3419,20 +3637,176 @@ circuit check_formal: %[[
input pred1: UInt<1> @[module-XXXXXXXXXX.rs 6:1]
input pred2: UInt<1> @[module-XXXXXXXXXX.rs 7:1]
input pred3: UInt<1> @[module-XXXXXXXXXX.rs 8:1]
inst formal_reset of formal_reset @[formal.rs 185:24]
inst formal_reset of formal_reset @[builtin 1:1]
assert(clk, pred1, and(en1, not(formal_reset.rst)), "en check 1") @[module-XXXXXXXXXX.rs 9:1]
inst formal_reset_1 of formal_reset @[formal.rs 185:24]
assume(clk, pred2, and(en2, not(formal_reset_1.rst)), "en check 2") @[module-XXXXXXXXXX.rs 10:1]
inst formal_reset_2 of formal_reset @[formal.rs 185:24]
cover(clk, pred3, and(en3, not(formal_reset_2.rst)), "en check 3") @[module-XXXXXXXXXX.rs 11:1]
inst formal_reset_3 of formal_reset @[formal.rs 185:24]
assert(clk, pred1, and(UInt<1>(0h1), not(formal_reset_3.rst)), "check 1") @[module-XXXXXXXXXX.rs 12:1]
inst formal_reset_4 of formal_reset @[formal.rs 185:24]
assume(clk, pred2, and(UInt<1>(0h1), not(formal_reset_4.rst)), "check 2") @[module-XXXXXXXXXX.rs 13:1]
inst formal_reset_5 of formal_reset @[formal.rs 185:24]
cover(clk, pred3, and(UInt<1>(0h1), not(formal_reset_5.rst)), "check 3") @[module-XXXXXXXXXX.rs 14:1]
extmodule formal_reset: @[formal.rs 169:5]
output rst: UInt<1> @[formal.rs 172:32]
assume(clk, pred2, and(en2, not(formal_reset.rst)), "en check 2") @[module-XXXXXXXXXX.rs 10:1]
cover(clk, pred3, and(en3, not(formal_reset.rst)), "en check 3") @[module-XXXXXXXXXX.rs 11:1]
assert(clk, pred1, and(UInt<1>(0h1), not(formal_reset.rst)), "check 1") @[module-XXXXXXXXXX.rs 12:1]
assume(clk, pred2, and(UInt<1>(0h1), not(formal_reset.rst)), "check 2") @[module-XXXXXXXXXX.rs 13:1]
cover(clk, pred3, and(UInt<1>(0h1), not(formal_reset.rst)), "check 3") @[module-XXXXXXXXXX.rs 14:1]
extmodule formal_reset: @[builtin 1:1]
output rst: UInt<1> @[builtin 1:1]
defname = __fayalite_formal_reset
"#,
};
}
#[hdl_module(outline_generated)]
pub fn check_formal_input() {
#[hdl]
let bool_in: Bool = m.input();
#[hdl]
let bool_out: Bool = m.output();
#[hdl]
let any_const_out1: Bool = m.output();
#[hdl]
let any_const_out2: UInt<16> = m.output();
#[hdl]
let any_const_out3: SInt<12> = m.output();
#[hdl]
let any_seq_out: UInt<10> = m.output();
#[hdl]
let all_const_out: UInt<10> = m.output();
#[hdl]
let all_seq_out: UInt<10> = m.output();
#[hdl]
let bool_reg = reg_builder()
.clock_domain(
#[hdl]
ClockDomain {
clk: formal_global_clock(),
rst: formal_reset(),
},
)
.reset(false);
connect(bool_reg, bool_in);
connect(bool_out, bool_reg);
connect(any_const_out1, any_const(StaticType::TYPE));
connect(any_const_out2, any_const(StaticType::TYPE));
connect(any_const_out3, any_const(StaticType::TYPE));
connect(any_seq_out, any_seq(StaticType::TYPE));
connect(all_const_out, all_const(StaticType::TYPE));
connect(all_seq_out, all_seq(StaticType::TYPE));
}
#[test]
fn test_formal_input() {
let _n = SourceLocation::normalize_files_for_tests();
let m = check_formal_input();
dbg!(m);
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
"/test/check_formal_input.fir": r#"FIRRTL version 3.2.0
circuit check_formal_input: %[[
{
"class": "firrtl.AttributeAnnotation",
"description": "gclk",
"target": "~check_formal_input|check_formal_input>formal_global_clock"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>formal_global_clock"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "anyconst",
"target": "~check_formal_input|check_formal_input>any_const"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>any_const"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "anyconst",
"target": "~check_formal_input|check_formal_input>any_const_1"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>any_const_1"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "anyconst",
"target": "~check_formal_input|check_formal_input>any_const_2"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>any_const_2"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "anyseq",
"target": "~check_formal_input|check_formal_input>any_seq"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>any_seq"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "allconst",
"target": "~check_formal_input|check_formal_input>all_const"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>all_const"
},
{
"class": "firrtl.AttributeAnnotation",
"description": "allseq",
"target": "~check_formal_input|check_formal_input>all_seq"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~check_formal_input|check_formal_input>all_seq"
},
{
"class": "firrtl.transforms.BlackBoxInlineAnno",
"name": "fayalite_formal_reset.v",
"text": "module __fayalite_formal_reset(output rst);\n assign rst = $initstate;\nendmodule\n",
"target": "~check_formal_input|formal_reset"
}
]]
type Ty0 = {clk: Clock, rst: UInt<1>}
type Ty1 = {rst: UInt<1>}
module check_formal_input: @[module-XXXXXXXXXX.rs 1:1]
input bool_in: UInt<1> @[module-XXXXXXXXXX.rs 2:1]
output bool_out: UInt<1> @[module-XXXXXXXXXX.rs 3:1]
output any_const_out1: UInt<1> @[module-XXXXXXXXXX.rs 4:1]
output any_const_out2: UInt<16> @[module-XXXXXXXXXX.rs 5:1]
output any_const_out3: SInt<12> @[module-XXXXXXXXXX.rs 6:1]
output any_seq_out: UInt<10> @[module-XXXXXXXXXX.rs 7:1]
output all_const_out: UInt<10> @[module-XXXXXXXXXX.rs 8:1]
output all_seq_out: UInt<10> @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_1: Ty0
connect _bundle_literal_expr_1.clk, asClock(UInt<1>(0h0))
connect _bundle_literal_expr_1.rst, UInt<1>(0h0)
reg formal_global_clock: UInt<1>, _bundle_literal_expr_1.clk @[builtin 1:1]
inst formal_reset of formal_reset @[builtin 1:1]
reg any_const: UInt<1>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 13:1]
reg any_const_1: UInt<16>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 15:1]
reg any_const_2: SInt<12>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 17:1]
reg any_seq: UInt<10>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 19:1]
reg all_const: UInt<10>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 21:1]
reg all_seq: UInt<10>, _bundle_literal_expr_1.clk @[module-XXXXXXXXXX.rs 23:1]
wire _bundle_literal_expr: Ty0
connect _bundle_literal_expr.clk, asClock(formal_global_clock)
connect _bundle_literal_expr.rst, formal_reset.rst
regreset bool_reg: UInt<1>, _bundle_literal_expr.clk, _bundle_literal_expr.rst, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 10:1]
connect bool_reg, bool_in @[module-XXXXXXXXXX.rs 11:1]
connect bool_out, bool_reg @[module-XXXXXXXXXX.rs 12:1]
connect any_const_out1, any_const @[module-XXXXXXXXXX.rs 14:1]
connect any_const_out2, any_const_1 @[module-XXXXXXXXXX.rs 16:1]
connect any_const_out3, any_const_2 @[module-XXXXXXXXXX.rs 18:1]
connect any_seq_out, any_seq @[module-XXXXXXXXXX.rs 20:1]
connect all_const_out, all_const @[module-XXXXXXXXXX.rs 22:1]
connect all_seq_out, all_seq @[module-XXXXXXXXXX.rs 24:1]
extmodule formal_reset: @[builtin 1:1]
output rst: UInt<1> @[builtin 1:1]
defname = __fayalite_formal_reset
"#,
};
@ -3565,21 +3939,10 @@ circuit check_enum_connect_any:
connect __connect_variant_body_1, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 8:1]
HdlSome:
wire __connect_variant_body_2: SInt<1> @[module-XXXXXXXXXX.rs 8:1]
wire _cast_bits_to_bundle_expr_1: Ty5
wire _cast_bits_to_bundle_expr_flattened_1: Ty6
connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 2, 0), 0, 0)
wire _cast_bits_to_enum_expr_1: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.tag, 0)):
connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlNone)
else:
connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_enum_expr_1
connect _cast_bits_to_bundle_expr_flattened_1.body, bits(bits(i2.body, 2, 0), 2, 1)
connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body
; connect different types:
; lhs: SInt<1>
; rhs: SInt<2>
connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr_1.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1]
connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1]
wire _bundle_literal_expr_2: Ty4
connect _bundle_literal_expr_2.tag, {|HdlNone, HdlSome|}(HdlSome)
connect _bundle_literal_expr_2.body, asUInt(__connect_variant_body_2)
@ -3601,18 +3964,18 @@ circuit check_enum_connect_any:
connect o1, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 8:1]
C:
wire __connect_variant_body_3: Ty8 @[module-XXXXXXXXXX.rs 8:1]
wire _cast_bits_to_bundle_expr_2: Ty8
wire _cast_bits_to_bundle_expr_flattened_2: Ty9
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i2.body, 0, 0), 0, 0)
wire _cast_bits_to_enum_expr_2: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)):
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone)
wire _cast_bits_to_bundle_expr_1: Ty8
wire _cast_bits_to_bundle_expr_flattened_1: Ty9
connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 0, 0), 0, 0)
wire _cast_bits_to_enum_expr_1: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_1.tag, 0)):
connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlNone)
else:
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2
connect _cast_bits_to_bundle_expr_flattened_2.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
connect __connect_variant_body_3, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 8:1]
connect _cast_bits_to_enum_expr_1, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_enum_expr_1
connect _cast_bits_to_bundle_expr_flattened_1.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body
connect __connect_variant_body_3, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 8:1]
wire _bundle_literal_expr_4: Ty1
connect _bundle_literal_expr_4.tag, {|A, B, C|}(C)
wire _cast_bundle_to_bits_expr_1: Ty9
@ -3641,18 +4004,18 @@ circuit check_enum_connect_any:
connect o2, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 9:1]
B:
wire __connect_variant_body_5: Ty5 @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_3: Ty4
wire _cast_bits_to_bundle_expr_flattened_3: Ty7
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 1, 0), 0, 0)
wire _cast_bits_to_enum_expr_3: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)):
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone)
wire _cast_bits_to_bundle_expr_2: Ty4
wire _cast_bits_to_bundle_expr_flattened_2: Ty7
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i1.body, 1, 0), 0, 0)
wire _cast_bits_to_enum_expr_2: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_2.tag, 0)):
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlNone)
else:
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3
connect _cast_bits_to_bundle_expr_flattened_3.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body
match _cast_bits_to_bundle_expr_3.tag: @[module-XXXXXXXXXX.rs 9:1]
connect _cast_bits_to_enum_expr_2, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_enum_expr_2
connect _cast_bits_to_bundle_expr_flattened_2.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
match _cast_bits_to_bundle_expr_2.tag: @[module-XXXXXXXXXX.rs 9:1]
HdlNone:
wire _bundle_literal_expr_6: Ty5
connect _bundle_literal_expr_6.tag, {|HdlNone, HdlSome|}(HdlNone)
@ -3660,21 +4023,10 @@ circuit check_enum_connect_any:
connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1]
HdlSome:
wire __connect_variant_body_6: SInt<2> @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_4: Ty4
wire _cast_bits_to_bundle_expr_flattened_4: Ty7
connect _cast_bits_to_bundle_expr_flattened_4.tag, bits(bits(i1.body, 1, 0), 0, 0)
wire _cast_bits_to_enum_expr_4: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_4.tag, 0)):
connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome|}(HdlNone)
else:
connect _cast_bits_to_enum_expr_4, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_4.tag, _cast_bits_to_enum_expr_4
connect _cast_bits_to_bundle_expr_flattened_4.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_4.body, _cast_bits_to_bundle_expr_flattened_4.body
; connect different types:
; lhs: SInt<2>
; rhs: SInt<1>
connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_4.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1]
connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_7: Ty5
connect _bundle_literal_expr_7.tag, {|HdlNone, HdlSome|}(HdlSome)
connect _bundle_literal_expr_7.body, asUInt(__connect_variant_body_6)
@ -3696,18 +4048,18 @@ circuit check_enum_connect_any:
connect o2, _bundle_literal_expr_8 @[module-XXXXXXXXXX.rs 9:1]
C:
wire __connect_variant_body_7: Ty8 @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_5: Ty8
wire _cast_bits_to_bundle_expr_flattened_5: Ty9
connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(bits(i1.body, 0, 0), 0, 0)
wire _cast_bits_to_enum_expr_5: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_5.tag, 0)):
connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlNone)
wire _cast_bits_to_bundle_expr_3: Ty8
wire _cast_bits_to_bundle_expr_flattened_3: Ty9
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 0, 0), 0, 0)
wire _cast_bits_to_enum_expr_3: Ty3
when eq(UInt<1>(0), tail(_cast_bits_to_bundle_expr_flattened_3.tag, 0)):
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlNone)
else:
connect _cast_bits_to_enum_expr_5, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_enum_expr_5
connect _cast_bits_to_bundle_expr_flattened_5.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body
connect __connect_variant_body_7, _cast_bits_to_bundle_expr_5 @[module-XXXXXXXXXX.rs 9:1]
connect _cast_bits_to_enum_expr_3, {|HdlNone, HdlSome|}(HdlSome)
connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_enum_expr_3
connect _cast_bits_to_bundle_expr_flattened_3.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body
connect __connect_variant_body_7, _cast_bits_to_bundle_expr_3 @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_9: Ty2
connect _bundle_literal_expr_9.tag, {|A, B, C|}(C)
wire _cast_bundle_to_bits_expr_3: Ty9
@ -3774,16 +4126,10 @@ circuit check_enum_connect_any:
connect __connect_variant_body_1, _bundle_literal_expr_1 @[module-XXXXXXXXXX.rs 8:1]
else:
wire __connect_variant_body_2: SInt<1> @[module-XXXXXXXXXX.rs 8:1]
wire _cast_bits_to_bundle_expr_1: Ty3
wire _cast_bits_to_bundle_expr_flattened_1: Ty3
connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 2, 0), 0, 0)
connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_bundle_expr_flattened_1.tag
connect _cast_bits_to_bundle_expr_flattened_1.body, bits(bits(i2.body, 2, 0), 2, 1)
connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body
; connect different types:
; lhs: SInt<1>
; rhs: SInt<2>
connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr_1.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1]
connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1]
wire _bundle_literal_expr_2: Ty2
connect _bundle_literal_expr_2.tag, UInt<1>(0h1)
connect _bundle_literal_expr_2.body, asUInt(__connect_variant_body_2)
@ -3799,13 +4145,13 @@ circuit check_enum_connect_any:
connect o1, _bundle_literal_expr_3 @[module-XXXXXXXXXX.rs 8:1]
else:
wire __connect_variant_body_3: Ty4 @[module-XXXXXXXXXX.rs 8:1]
wire _cast_bits_to_bundle_expr_2: Ty4
wire _cast_bits_to_bundle_expr_flattened_2: Ty4
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i2.body, 0, 0), 0, 0)
connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag
connect _cast_bits_to_bundle_expr_flattened_2.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
connect __connect_variant_body_3, _cast_bits_to_bundle_expr_2 @[module-XXXXXXXXXX.rs 8:1]
wire _cast_bits_to_bundle_expr_1: Ty4
wire _cast_bits_to_bundle_expr_flattened_1: Ty4
connect _cast_bits_to_bundle_expr_flattened_1.tag, bits(bits(i2.body, 0, 0), 0, 0)
connect _cast_bits_to_bundle_expr_1.tag, _cast_bits_to_bundle_expr_flattened_1.tag
connect _cast_bits_to_bundle_expr_flattened_1.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_1.body, _cast_bits_to_bundle_expr_flattened_1.body
connect __connect_variant_body_3, _cast_bits_to_bundle_expr_1 @[module-XXXXXXXXXX.rs 8:1]
wire _bundle_literal_expr_4: Ty0
connect _bundle_literal_expr_4.tag, UInt<2>(0h2)
wire _cast_bundle_to_bits_expr_1: Ty4
@ -3827,29 +4173,23 @@ circuit check_enum_connect_any:
connect o2, _bundle_literal_expr_5 @[module-XXXXXXXXXX.rs 9:1]
else when eq(i1.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 9:1]
wire __connect_variant_body_5: Ty3 @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_3: Ty2
wire _cast_bits_to_bundle_expr_flattened_3: Ty2
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 1, 0), 0, 0)
connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag
connect _cast_bits_to_bundle_expr_flattened_3.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body
when eq(_cast_bits_to_bundle_expr_3.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_2: Ty2
wire _cast_bits_to_bundle_expr_flattened_2: Ty2
connect _cast_bits_to_bundle_expr_flattened_2.tag, bits(bits(i1.body, 1, 0), 0, 0)
connect _cast_bits_to_bundle_expr_2.tag, _cast_bits_to_bundle_expr_flattened_2.tag
connect _cast_bits_to_bundle_expr_flattened_2.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_2.body, _cast_bits_to_bundle_expr_flattened_2.body
when eq(_cast_bits_to_bundle_expr_2.tag, UInt<1>(0h0)): @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_6: Ty3
connect _bundle_literal_expr_6.tag, UInt<1>(0h0)
connect _bundle_literal_expr_6.body, UInt<2>(0h0)
connect __connect_variant_body_5, _bundle_literal_expr_6 @[module-XXXXXXXXXX.rs 9:1]
else:
wire __connect_variant_body_6: SInt<2> @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_4: Ty2
wire _cast_bits_to_bundle_expr_flattened_4: Ty2
connect _cast_bits_to_bundle_expr_flattened_4.tag, bits(bits(i1.body, 1, 0), 0, 0)
connect _cast_bits_to_bundle_expr_4.tag, _cast_bits_to_bundle_expr_flattened_4.tag
connect _cast_bits_to_bundle_expr_flattened_4.body, bits(bits(i1.body, 1, 0), 1, 1)
connect _cast_bits_to_bundle_expr_4.body, _cast_bits_to_bundle_expr_flattened_4.body
; connect different types:
; lhs: SInt<2>
; rhs: SInt<1>
connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_4.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1]
connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_7: Ty3
connect _bundle_literal_expr_7.tag, UInt<1>(0h1)
connect _bundle_literal_expr_7.body, asUInt(__connect_variant_body_6)
@ -3865,13 +4205,13 @@ circuit check_enum_connect_any:
connect o2, _bundle_literal_expr_8 @[module-XXXXXXXXXX.rs 9:1]
else:
wire __connect_variant_body_7: Ty4 @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_5: Ty4
wire _cast_bits_to_bundle_expr_flattened_5: Ty4
connect _cast_bits_to_bundle_expr_flattened_5.tag, bits(bits(i1.body, 0, 0), 0, 0)
connect _cast_bits_to_bundle_expr_5.tag, _cast_bits_to_bundle_expr_flattened_5.tag
connect _cast_bits_to_bundle_expr_flattened_5.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_5.body, _cast_bits_to_bundle_expr_flattened_5.body
connect __connect_variant_body_7, _cast_bits_to_bundle_expr_5 @[module-XXXXXXXXXX.rs 9:1]
wire _cast_bits_to_bundle_expr_3: Ty4
wire _cast_bits_to_bundle_expr_flattened_3: Ty4
connect _cast_bits_to_bundle_expr_flattened_3.tag, bits(bits(i1.body, 0, 0), 0, 0)
connect _cast_bits_to_bundle_expr_3.tag, _cast_bits_to_bundle_expr_flattened_3.tag
connect _cast_bits_to_bundle_expr_flattened_3.body, UInt<0>(0)
connect _cast_bits_to_bundle_expr_3.body, _cast_bits_to_bundle_expr_flattened_3.body
connect __connect_variant_body_7, _cast_bits_to_bundle_expr_3 @[module-XXXXXXXXXX.rs 9:1]
wire _bundle_literal_expr_9: Ty1
connect _bundle_literal_expr_9.tag, UInt<2>(0h2)
wire _cast_bundle_to_bits_expr_3: Ty4
@ -4523,34 +4863,20 @@ circuit check_struct_cmp_eq:
input test_struct_3_rhs: Ty3 @[module-XXXXXXXXXX.rs 21:1]
output test_struct_3_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 22:1]
output test_struct_3_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 24:1]
wire _array_literal_expr: UInt<1>[3]
connect _array_literal_expr[0], eq(tuple_lhs.`0`, tuple_rhs.`0`)
connect _array_literal_expr[1], eq(tuple_lhs.`1`, tuple_rhs.`1`)
connect _array_literal_expr[2], eq(tuple_lhs.`2`, tuple_rhs.`2`)
wire _cast_array_to_bits_expr: UInt<1>[3]
connect _cast_array_to_bits_expr[0], _array_literal_expr[0]
connect _cast_array_to_bits_expr[1], _array_literal_expr[1]
connect _cast_array_to_bits_expr[2], _array_literal_expr[2]
wire _cast_to_bits_expr: UInt<3>
connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0]))
connect tuple_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
wire _array_literal_expr_1: UInt<1>[3]
connect _array_literal_expr_1[0], neq(tuple_lhs.`0`, tuple_rhs.`0`)
connect _array_literal_expr_1[1], neq(tuple_lhs.`1`, tuple_rhs.`1`)
connect _array_literal_expr_1[2], neq(tuple_lhs.`2`, tuple_rhs.`2`)
wire _cast_array_to_bits_expr_1: UInt<1>[3]
connect _cast_array_to_bits_expr_1[0], _array_literal_expr_1[0]
connect _cast_array_to_bits_expr_1[1], _array_literal_expr_1[1]
connect _cast_array_to_bits_expr_1[2], _array_literal_expr_1[2]
wire _cast_to_bits_expr_1: UInt<3>
connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0]))
connect tuple_cmp_ne, orr(_cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 7:1]
connect test_struct_cmp_eq, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 11:1]
connect test_struct_cmp_ne, or(neq(test_struct_lhs.a, test_struct_rhs.a), neq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 13:1]
wire _bundle_structural_eq: UInt<1>
connect _bundle_structural_eq, and(eq(tuple_lhs.`0`, tuple_rhs.`0`), eq(tuple_lhs.`1`, tuple_rhs.`1`))
wire _bundle_structural_eq_1: UInt<1>
connect _bundle_structural_eq_1, and(_bundle_structural_eq, eq(tuple_lhs.`2`, tuple_rhs.`2`))
connect tuple_cmp_eq, _bundle_structural_eq_1 @[module-XXXXXXXXXX.rs 5:1]
connect tuple_cmp_ne, not(_bundle_structural_eq_1) @[module-XXXXXXXXXX.rs 7:1]
wire _bundle_structural_eq_2: UInt<1>
connect _bundle_structural_eq_2, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b))
connect test_struct_cmp_eq, _bundle_structural_eq_2 @[module-XXXXXXXXXX.rs 11:1]
connect test_struct_cmp_ne, not(_bundle_structural_eq_2) @[module-XXXXXXXXXX.rs 13:1]
connect test_struct_2_cmp_eq, eq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 17:1]
connect test_struct_2_cmp_ne, neq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 19:1]
connect test_struct_2_cmp_ne, not(eq(test_struct_2_lhs.v, test_struct_2_rhs.v)) @[module-XXXXXXXXXX.rs 19:1]
connect test_struct_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1]
connect test_struct_3_cmp_ne, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 25:1]
connect test_struct_3_cmp_ne, not(UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 25:1]
",
};
}

View file

@ -1,15 +1,28 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use bitvec::{order::Lsb0, view::BitView};
use fayalite::{
memory::{ReadStruct, ReadWriteStruct, WriteStruct},
module::{instance_with_loc, memory_with_init_and_loc, reg_builder_with_loc},
assert_export_firrtl,
firrtl::ExportOptions,
formal::FormalInputKind,
memory::{ReadStruct, ReadWriteStruct, WriteStruct, splat_mask},
module::{
instance_with_loc, memory_with_init_and_loc, reg_builder_with_loc,
transform::simplify_enums::SimplifyEnumsKind,
},
prelude::*,
reset::ResetType,
sim::vcd::VcdWriterDecls,
ty::SimValueDebug,
util::{RcWriter, ready_valid::queue},
};
use std::{collections::BTreeMap, num::NonZeroUsize, rc::Rc};
use std::{
collections::BTreeMap,
num::NonZeroUsize,
panic::{AssertUnwindSafe, catch_unwind, resume_unwind},
rc::Rc,
};
#[hdl_module(outline_generated)]
pub fn connect_const() {
@ -550,6 +563,150 @@ fn test_enums() {
}
}
#[hdl]
pub enum EnumWithSimpleBody {
A(UInt<8>),
B(UInt<8>),
C(UInt<8>),
}
#[hdl_module(outline_generated)]
pub fn enum_with_simple_body() {
#[hdl]
let which_in: UInt<8> = m.input();
#[hdl]
let data_in: UInt<8> = m.input();
#[hdl]
let which_out: UInt<8> = m.output();
#[hdl]
let data_out: UInt<8> = m.output();
#[hdl]
let enum_out: EnumWithSimpleBody = m.output();
#[hdl]
if which_in.cmp_eq(0u8) {
connect(enum_out, EnumWithSimpleBody.A(data_in));
} else if which_in.cmp_eq(1u8) {
connect(enum_out, EnumWithSimpleBody.B(data_in));
} else {
connect(enum_out, EnumWithSimpleBody.C(data_in));
}
#[hdl]
match enum_out {
EnumWithSimpleBody::A(v) => {
connect(which_out, 0u8);
connect(data_out, v);
}
EnumWithSimpleBody::B(v) => {
connect(which_out, 1u8);
connect(data_out, v);
}
EnumWithSimpleBody::C(v) => {
connect(which_out, 2u8);
connect(data_out, v);
}
}
}
#[hdl]
#[test]
fn test_enum_with_simple_body() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(enum_with_simple_body());
let mut writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
for which in 0u8..=2 {
for data in (0..u8::MAX).step_by(45) {
sim.write(sim.io().which_in, which);
sim.write(sim.io().data_in, data);
sim.advance_time(SimDuration::from_micros(1));
assert_eq!(sim.read(sim.io().which_out).as_int(), which);
assert_eq!(sim.read(sim.io().data_out).as_int(), data);
}
}
sim.flush_traces().unwrap();
let vcd = String::from_utf8(writer.take()).unwrap();
println!("####### VCD:\n{vcd}\n#######");
#[derive(Debug)]
struct WireState<'a> {
name: &'a str,
space_then_id: Option<&'a str>,
value: Option<&'a str>,
}
impl<'a> WireState<'a> {
fn new(name: &'a str) -> Self {
Self {
name,
space_then_id: None,
value: None,
}
}
}
let mut variant_wires = [
WireState::new("A"),
WireState::new("B"),
WireState::new("C"),
];
// check that output .vcd has the proper values for all variants' wires
for (is_last, line) in vcd.lines().map(|line| (false, line)).chain([(true, "")]) {
if let Some(line) = line.strip_prefix("$var wire 8")
&& let Some(line) = line.strip_suffix(" $end")
&& let Some((space_then_id, state)) = variant_wires
.iter_mut()
.find_map(|state| Some((line.strip_suffix(state.name)?.strip_suffix(" ")?, state)))
{
assert_eq!(space_then_id.chars().next(), Some(' '));
assert!(
space_then_id
.chars()
.skip(1)
.all(|ch| matches!(ch, '!'..='~'))
);
assert_eq!(state.space_then_id.replace(space_then_id), None);
} else if line.starts_with("#") || is_last {
let Some(expected_value) = variant_wires[0].value else {
panic!(
"variant {} hasn't been initialized before a timestamp or EOF: {variant_wires:#?}\n\
line={line:?}",
variant_wires[0].name,
);
};
for state in &variant_wires {
assert_eq!(
state.value,
Some(expected_value),
"at a timestamp or EOF: variant value for {} doesn't match expected value.\n\
{variant_wires:#?}\nline={line:?}",
state.name,
);
}
} else if line.starts_with("b") {
for state in &mut variant_wires {
let Some(space_then_id) = state.space_then_id else {
let name = state.name;
panic!(
"variant {name} hasn't had an id assigned yet: {variant_wires:#?}\n\
line={line:?}",
);
};
if let Some(value) = line.strip_suffix(space_then_id) {
state.value = Some(value);
break;
}
}
}
}
if vcd != include_str!("sim/expected/enum_with_simple_body.vcd") {
panic!();
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/enum_with_simple_body.txt") {
panic!();
}
}
#[hdl_module(outline_generated)]
pub fn memories() {
#[hdl]
@ -2841,3 +2998,818 @@ fn test_queue_4_true_true() {
include_str!("sim/expected/queue_4_true_true.txt"),
);
}
#[hdl(outline_generated, custom_debug(sim), cmp_eq)]
pub enum HasCustomDebug {
Text(UInt<512>),
FmtError,
}
impl HasCustomDebug {
#[hdl]
pub fn new_sim(text: Result<&str, std::fmt::Error>) -> SimValue<Self> {
match text {
Ok(text) => {
let mut retval = HasCustomDebug.Text.zero();
let src = text.as_bytes().view_bits::<Lsb0>();
let dest = retval.bits_mut();
let len = src.len().min(dest.len());
dest[..len].clone_from_bitslice(&src[..len]);
#[hdl(sim)]
HasCustomDebug.Text(retval)
}
Err(std::fmt::Error) =>
{
#[hdl(sim)]
HasCustomDebug.FmtError()
}
}
}
pub fn new(text: Result<&str, std::fmt::Error>) -> Expr<Self> {
Self::new_sim(text).to_expr()
}
}
impl SimValueDebug for HasCustomDebug {
#[hdl]
fn sim_value_debug(
value: &<Self as Type>::SimValue,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
if f.alternate() {
return #[hdl(sim)]
match value {
Self::FmtError => f.write_str("FmtError"),
Self::Text(text) => f.debug_tuple("Text").field(text).finish(),
};
}
#[hdl(sim)]
match value {
Self::FmtError => Err(std::fmt::Error),
Self::Text(text) => {
assert_eq!(text.ty().width() % u8::BITS as usize, 0);
let mut bytes = vec![0u8; text.ty().width() / u8::BITS as usize];
bytes
.view_bits_mut::<Lsb0>()
.clone_from_bitslice(text.bits());
if let Some(len) = bytes.iter().position(|b| *b == 0) {
bytes.truncate(len);
}
f.write_str(&String::from_utf8_lossy(&bytes))
}
}
}
}
#[hdl_module(outline_generated)]
pub fn sim_trace_as_string() {
#[hdl]
let clk: Clock = m.input();
#[hdl]
let read: ReadStruct<TraceAsString<Array<HasCustomDebug, 2>>, ConstUsize<8>> = m.input();
#[hdl]
let write: WriteStruct<Array<TraceAsString<HasCustomDebug>, 2>, ConstUsize<8>> = m.input();
#[hdl]
let mut mem = memory_with_init([[HasCustomDebug::new(Ok("")).to_trace_as_string(); 2]; 4]);
let read_port = mem.new_read_port();
connect(read_port.clk, clk);
connect_any(read_port.addr, read.addr);
connect(read_port.en, read.en);
for (l, r) in read.data.iter().zip(read_port.data.iter()) {
connect(l, &**r);
}
let write_port = mem.new_write_port();
connect(write_port.clk, clk);
connect_any(write_port.addr, write.addr);
connect(write_port.data, write.data);
connect(write_port.en, write.en);
connect(write_port.mask, write.mask);
}
#[hdl]
#[test]
fn test_sim_trace_as_string() {
let _n = SourceLocation::normalize_files_for_tests();
let m = sim_trace_as_string();
let mut sim = Simulation::new(m);
// sim.set_breakpoints_unstable(Default::default(), true);
let mut writer = RcWriter::default();
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
sim.write(sim.io().clk, false);
sim.write(sim.io().read.clk, false);
sim.write(sim.io().write.clk, false);
#[derive(Debug)]
struct TestCase {
read: Option<(u8, [Result<&'static str, std::fmt::Error>; 2])>,
write_addr: Option<u8>,
write_data: [Result<&'static str, std::fmt::Error>; 2],
write_mask: [bool; 2],
}
const TEST_CASES: &[TestCase] = &[
TestCase {
read: None,
write_addr: None,
write_data: [Ok(""); 2],
write_mask: [false; 2],
},
TestCase {
read: None,
write_addr: Some(0),
write_data: [Ok("mem[0][0]"), Ok("mem[0][1]")],
write_mask: [true; 2],
},
TestCase {
read: None,
write_addr: Some(1),
write_data: [Ok("mem[1][0]"), Ok("mem[1][1]")],
write_mask: [true; 2],
},
TestCase {
read: None,
write_addr: Some(2),
write_data: [Ok("mem[2][0]"), Ok("mem[2][1]")],
write_mask: [true; 2],
},
TestCase {
read: None,
write_addr: Some(3),
write_data: [Ok("mem[3][0]"), Ok("mem[3][1]")],
write_mask: [true; 2],
},
TestCase {
read: Some((1, [Ok("mem[1][0]"), Ok("mem[1][1]")])),
write_addr: None,
write_data: [Err(std::fmt::Error), Err(std::fmt::Error)],
write_mask: [true; 2],
},
TestCase {
read: Some((1, [Err(std::fmt::Error), Err(std::fmt::Error)])),
write_addr: Some(1),
write_data: [Err(std::fmt::Error), Err(std::fmt::Error)],
write_mask: [true; 2],
},
];
for test_case in TEST_CASES {
let TestCase {
read,
write_addr,
write_data,
write_mask,
} = test_case;
sim.write(sim.io().read.addr, read.map(|v| v.0).unwrap_or(0));
sim.write(sim.io().read.en, read.is_some());
sim.write(sim.io().write.addr, write_addr.unwrap_or(0));
sim.write(sim.io().write.en, write_addr.is_some());
sim.write(
sim.io().write.data,
write_data.map(|v| HasCustomDebug::new_sim(v).to_trace_as_string()),
);
sim.write(
sim.io().write.mask,
write_mask.map(|v| splat_mask(TraceAsString[HasCustomDebug], v.to_expr())),
);
sim.write(sim.io().clk, false);
sim.advance_time(SimDuration::from_nanos(500));
sim.write(sim.io().clk, true);
sim.advance_time(SimDuration::from_nanos(500));
if let Some((_, expected_read_data)) = read {
let read_data = sim.read(sim.io().read.data);
let expected_read_data = expected_read_data
.map(HasCustomDebug::new_sim)
.into_sim_value();
assert!(
*read_data.inner() == expected_read_data,
"{read_data:#?}\n!= {expected_read_data:#?}",
);
}
}
sim.flush_traces().unwrap();
let vcd = String::from_utf8(writer.take()).unwrap();
println!("####### VCD:\n{vcd}\n#######");
if vcd != include_str!("sim/expected/sim_trace_as_string.vcd") {
panic!();
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/sim_trace_as_string.txt") {
panic!();
}
}
#[test]
fn test_firrtl_trace_as_string() {
let _n = SourceLocation::normalize_files_for_tests();
let m = sim_trace_as_string();
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_memories: false,
simplify_enums: None,
..ExportOptions::default()
},
"/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0
circuit sim_trace_as_string: %[[
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem.mem",
"hexOrBinary": "b",
"target": "~sim_trace_as_string|sim_trace_as_string>mem"
}
]]
type Ty0 = {|Text: UInt<512>, FmtError|}
type Ty1 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty0[2]}
type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]}
type Ty3 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty0[2]}
type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]}
module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1]
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
input `read`: Ty1 @[module-XXXXXXXXXX.rs 3:1]
input `write`: Ty2 @[module-XXXXXXXXXX.rs 4:1]
mem `mem`: @[module-XXXXXXXXXX.rs 5:1]
data-type => Ty0[2]
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
connect `mem`.r0.clk, clk @[module-XXXXXXXXXX.rs 7:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect `mem`.r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1]
connect `mem`.r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1]
connect `read`.data[0], `mem`.r0.data[0] @[module-XXXXXXXXXX.rs 10:1]
connect `read`.data[1], `mem`.r0.data[1] @[module-XXXXXXXXXX.rs 10:1]
connect `mem`.w1.clk, clk @[module-XXXXXXXXXX.rs 12:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect `mem`.w1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1]
connect `mem`.w1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1]
connect `mem`.w1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1]
connect `mem`.w1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1]
"#,
"/test/sim_trace_as_string/mem.mem": r"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_memories: true,
simplify_enums: None,
..ExportOptions::default()
},
"/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0
circuit sim_trace_as_string: %[[
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem.mem",
"hexOrBinary": "b",
"target": "~sim_trace_as_string|sim_trace_as_string>mem"
}
]]
type Ty0 = {|Text: UInt<512>, FmtError|}
type Ty1 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty0[2]}
type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]}
type Ty3 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty0[2]}
type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty0[2], mask: UInt<1>[2]}
type Ty5 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: UInt<513>[2]}
type Ty6 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: UInt<513>[2], mask: UInt<1>[2]}
module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1]
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
input `read`: Ty1 @[module-XXXXXXXXXX.rs 3:1]
input `write`: Ty2 @[module-XXXXXXXXXX.rs 4:1]
mem `mem`: @[module-XXXXXXXXXX.rs 5:1]
data-type => UInt<513>[2]
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
wire mem_r0: Ty3 @[module-XXXXXXXXXX.rs 6:1]
wire mem_w1: Ty4 @[module-XXXXXXXXXX.rs 11:1]
wire _cast_bits_to_enum_expr: Ty0
wire _cast_bits_to_enum_expr_body: UInt<512>
connect _cast_bits_to_enum_expr_body, head(`mem`.r0.data[0], 512)
when eq(UInt<1>(0), tail(`mem`.r0.data[0], 512)):
connect _cast_bits_to_enum_expr, {|Text: UInt<512>, FmtError|}(Text, _cast_bits_to_enum_expr_body)
else:
connect _cast_bits_to_enum_expr, {|Text: UInt<512>, FmtError|}(FmtError)
connect mem_r0.data[0], _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 6:1]
wire _cast_bits_to_enum_expr_1: Ty0
wire _cast_bits_to_enum_expr_body_1: UInt<512>
connect _cast_bits_to_enum_expr_body_1, head(`mem`.r0.data[1], 512)
when eq(UInt<1>(0), tail(`mem`.r0.data[1], 512)):
connect _cast_bits_to_enum_expr_1, {|Text: UInt<512>, FmtError|}(Text, _cast_bits_to_enum_expr_body_1)
else:
connect _cast_bits_to_enum_expr_1, {|Text: UInt<512>, FmtError|}(FmtError)
connect mem_r0.data[1], _cast_bits_to_enum_expr_1 @[module-XXXXXXXXXX.rs 6:1]
wire _cast_enum_to_bits_expr: UInt<513>
match mem_w1.data[0]:
Text(_cast_enum_to_bits_expr_Text):
connect _cast_enum_to_bits_expr, pad(cat(_cast_enum_to_bits_expr_Text, UInt<1>(0)), 513)
FmtError:
connect _cast_enum_to_bits_expr, UInt<513>(1)
connect `mem`.w1.data[0], _cast_enum_to_bits_expr @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[0], mem_w1.mask[0] @[module-XXXXXXXXXX.rs 11:1]
wire _cast_enum_to_bits_expr_1: UInt<513>
match mem_w1.data[1]:
Text(_cast_enum_to_bits_expr_Text_1):
connect _cast_enum_to_bits_expr_1, pad(cat(_cast_enum_to_bits_expr_Text_1, UInt<1>(0)), 513)
FmtError:
connect _cast_enum_to_bits_expr_1, UInt<513>(1)
connect `mem`.w1.data[1], _cast_enum_to_bits_expr_1 @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[1], mem_w1.mask[1] @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1]
connect `mem`.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1]
connect `mem`.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1]
connect `mem`.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
connect mem_r0.clk, clk @[module-XXXXXXXXXX.rs 7:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect mem_r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1]
connect mem_r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1]
connect `read`.data[0], mem_r0.data[0] @[module-XXXXXXXXXX.rs 10:1]
connect `read`.data[1], mem_r0.data[1] @[module-XXXXXXXXXX.rs 10:1]
connect mem_w1.clk, clk @[module-XXXXXXXXXX.rs 12:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect mem_w1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1]
connect mem_w1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1]
connect mem_w1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1]
connect mem_w1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1]
"#,
"/test/sim_trace_as_string/mem.mem": r"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_memories: false,
simplify_enums: Some(SimplifyEnumsKind::SimplifyToEnumsWithNoBody),
..ExportOptions::default()
},
"/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0
circuit sim_trace_as_string: %[[
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem.mem",
"hexOrBinary": "b",
"target": "~sim_trace_as_string|sim_trace_as_string>mem"
}
]]
type Ty0 = {|Text, FmtError|}
type Ty1 = {tag: Ty0, body: UInt<512>}
type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty1[2]}
type Ty3 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]}
type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]}
type Ty5 = {tag: UInt<1>, body: UInt<1>}
type Ty6 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: Ty5[2]}
type Ty7 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty1[2]}
module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1]
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
input `read`: Ty2 @[module-XXXXXXXXXX.rs 3:1]
input `write`: Ty3 @[module-XXXXXXXXXX.rs 4:1]
mem `mem`: @[module-XXXXXXXXXX.rs 5:1]
data-type => Ty1[2]
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
wire mem_w1: Ty4 @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.data, mem_w1.data @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[0].tag, mem_w1.mask[0] @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[0].body, mem_w1.mask[0] @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[1].tag, mem_w1.mask[1] @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.w1.mask[1].body, mem_w1.mask[1] @[module-XXXXXXXXXX.rs 11:1]
connect `mem`.r0.clk, clk @[module-XXXXXXXXXX.rs 7:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect `mem`.r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1]
connect `mem`.r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1]
connect `read`.data[0], `mem`.r0.data[0] @[module-XXXXXXXXXX.rs 10:1]
connect `read`.data[1], `mem`.r0.data[1] @[module-XXXXXXXXXX.rs 10:1]
connect mem_w1.clk, clk @[module-XXXXXXXXXX.rs 12:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect mem_w1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1]
connect mem_w1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1]
connect mem_w1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1]
connect mem_w1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1]
"#,
"/test/sim_trace_as_string/mem.mem": r"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
assert_export_firrtl! {
m =>
options: ExportOptions {
simplify_memories: true,
simplify_enums: Some(SimplifyEnumsKind::SimplifyToEnumsWithNoBody),
..ExportOptions::default()
},
"/test/sim_trace_as_string.fir": r#"FIRRTL version 3.2.0
circuit sim_trace_as_string: %[[
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem_0_tag.mem",
"hexOrBinary": "b",
"target": "~sim_trace_as_string|sim_trace_as_string>mem_0_tag"
},
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem_0_body.mem",
"hexOrBinary": "h",
"target": "~sim_trace_as_string|sim_trace_as_string>mem_0_body"
},
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem_1_tag.mem",
"hexOrBinary": "b",
"target": "~sim_trace_as_string|sim_trace_as_string>mem_1_tag"
},
{
"class": "firrtl.annotations.MemoryFileInlineAnnotation",
"filename": "/test/sim_trace_as_string/mem_1_body.mem",
"hexOrBinary": "h",
"target": "~sim_trace_as_string|sim_trace_as_string>mem_1_body"
}
]]
type Ty0 = {|Text, FmtError|}
type Ty1 = {tag: Ty0, body: UInt<512>}
type Ty2 = {addr: UInt<8>, en: UInt<1>, clk: Clock, flip data: Ty1[2]}
type Ty3 = {addr: UInt<8>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]}
type Ty4 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: Ty1[2]}
type Ty5 = {tag: UInt<1>, body: UInt<1>}
type Ty6 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: Ty5[2]}
type Ty7 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: UInt<1>}
type Ty8 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: UInt<1>, mask: UInt<1>}
type Ty9 = {addr: UInt<2>, en: UInt<1>, clk: Clock, flip data: UInt<512>}
type Ty10 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: UInt<512>, mask: UInt<1>}
type Ty11 = {addr: UInt<2>, en: UInt<1>, clk: Clock, data: Ty1[2], mask: UInt<1>[2]}
module sim_trace_as_string: @[module-XXXXXXXXXX.rs 1:1]
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
input `read`: Ty2 @[module-XXXXXXXXXX.rs 3:1]
input `write`: Ty3 @[module-XXXXXXXXXX.rs 4:1]
mem mem_0_tag: @[module-XXXXXXXXXX.rs 5:1]
data-type => UInt<1>
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
mem mem_0_body: @[module-XXXXXXXXXX.rs 5:1]
data-type => UInt<512>
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
mem mem_1_tag: @[module-XXXXXXXXXX.rs 5:1]
data-type => UInt<1>
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
mem mem_1_body: @[module-XXXXXXXXXX.rs 5:1]
data-type => UInt<512>
depth => 4
read-latency => 0
write-latency => 1
read-under-write => old
reader => r0
writer => w1
wire mem_r0: Ty4 @[module-XXXXXXXXXX.rs 6:1]
wire mem_w1: Ty6 @[module-XXXXXXXXXX.rs 11:1]
wire _cast_bits_to_enum_expr: Ty0
when eq(UInt<1>(0), tail(mem_0_tag.r0.data, 0)):
connect _cast_bits_to_enum_expr, {|Text, FmtError|}(Text)
else:
connect _cast_bits_to_enum_expr, {|Text, FmtError|}(FmtError)
connect mem_r0.data[0].tag, _cast_bits_to_enum_expr @[module-XXXXXXXXXX.rs 6:1]
wire _cast_enum_to_bits_expr: UInt<1>
match mem_w1.data[0].tag:
Text:
connect _cast_enum_to_bits_expr, UInt<1>(0)
FmtError:
connect _cast_enum_to_bits_expr, UInt<1>(1)
connect mem_0_tag.w1.data, _cast_enum_to_bits_expr @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_tag.w1.mask, mem_w1.mask[0].tag @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_tag.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_tag.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_tag.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_tag.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_tag.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_tag.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
connect mem_r0.data[0].body, mem_0_body.r0.data @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_body.w1.data, mem_w1.data[0].body @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_body.w1.mask, mem_w1.mask[0].body @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_body.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_body.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_body.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1]
connect mem_0_body.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_body.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect mem_0_body.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
wire _cast_bits_to_enum_expr_1: Ty0
when eq(UInt<1>(0), tail(mem_1_tag.r0.data, 0)):
connect _cast_bits_to_enum_expr_1, {|Text, FmtError|}(Text)
else:
connect _cast_bits_to_enum_expr_1, {|Text, FmtError|}(FmtError)
connect mem_r0.data[1].tag, _cast_bits_to_enum_expr_1 @[module-XXXXXXXXXX.rs 6:1]
wire _cast_enum_to_bits_expr_1: UInt<1>
match mem_w1.data[1].tag:
Text:
connect _cast_enum_to_bits_expr_1, UInt<1>(0)
FmtError:
connect _cast_enum_to_bits_expr_1, UInt<1>(1)
connect mem_1_tag.w1.data, _cast_enum_to_bits_expr_1 @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_tag.w1.mask, mem_w1.mask[1].tag @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_tag.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_tag.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_tag.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_tag.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_tag.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_tag.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
connect mem_r0.data[1].body, mem_1_body.r0.data @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_body.w1.data, mem_w1.data[1].body @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_body.w1.mask, mem_w1.mask[1].body @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_body.r0.addr, mem_r0.addr @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_body.r0.clk, mem_r0.clk @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_body.r0.en, mem_r0.en @[module-XXXXXXXXXX.rs 6:1]
connect mem_1_body.w1.addr, mem_w1.addr @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_body.w1.clk, mem_w1.clk @[module-XXXXXXXXXX.rs 11:1]
connect mem_1_body.w1.en, mem_w1.en @[module-XXXXXXXXXX.rs 11:1]
wire mem_w1_1: Ty11 @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.addr, mem_w1_1.addr @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.en, mem_w1_1.en @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.clk, mem_w1_1.clk @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.data, mem_w1_1.data @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.mask[0].tag, mem_w1_1.mask[0] @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.mask[0].body, mem_w1_1.mask[0] @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.mask[1].tag, mem_w1_1.mask[1] @[module-XXXXXXXXXX.rs 11:1]
connect mem_w1.mask[1].body, mem_w1_1.mask[1] @[module-XXXXXXXXXX.rs 11:1]
connect mem_r0.clk, clk @[module-XXXXXXXXXX.rs 7:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect mem_r0.addr, `read`.addr @[module-XXXXXXXXXX.rs 8:1]
connect mem_r0.en, `read`.en @[module-XXXXXXXXXX.rs 9:1]
connect `read`.data[0], mem_r0.data[0] @[module-XXXXXXXXXX.rs 10:1]
connect `read`.data[1], mem_r0.data[1] @[module-XXXXXXXXXX.rs 10:1]
connect mem_w1_1.clk, clk @[module-XXXXXXXXXX.rs 12:1]
; connect different types:
; lhs: UInt<2>
; rhs: UInt<8>
connect mem_w1_1.addr, `write`.addr @[module-XXXXXXXXXX.rs 13:1]
connect mem_w1_1.data, `write`.data @[module-XXXXXXXXXX.rs 14:1]
connect mem_w1_1.en, `write`.en @[module-XXXXXXXXXX.rs 15:1]
connect mem_w1_1.mask, `write`.mask @[module-XXXXXXXXXX.rs 16:1]
"#,
"/test/sim_trace_as_string/mem_0_body.mem": r"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
",
"/test/sim_trace_as_string/mem_0_tag.mem": r"0
0
0
0
",
"/test/sim_trace_as_string/mem_1_body.mem": r"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
",
"/test/sim_trace_as_string/mem_1_tag.mem": r"0
0
0
0
",
};
}
#[hdl_module(outline_generated)]
pub fn formal_counter(count_modulus: u8, asserted_max_count: u8) {
#[hdl]
let cd = wire();
connect(
cd,
#[hdl]
ClockDomain {
clk: formal_global_clock(),
rst: formal_reset(),
},
);
#[hdl]
let count_reg: UInt<8> = reg_builder().clock_domain(cd).reset(0u8);
let next_count = count_reg + 1u8;
#[hdl]
if next_count.cmp_lt(count_modulus) {
connect_any(count_reg, next_count);
} else {
connect(count_reg, 0u8);
}
#[hdl]
let count: UInt<8> = m.output();
connect(count, count_reg);
#[hdl]
let enable_assert: Bool = m.input();
#[hdl]
if enable_assert {
hdl_assert(cd.clk, count_reg.cmp_le(asserted_max_count), "");
}
#[hdl]
let any_seq_out: UInt<16> = m.output();
connect(any_seq_out, any_seq(any_seq_out.ty()));
}
#[hdl]
#[test]
fn test_formal_counter() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(formal_counter(10, 10));
let _checked_vcd_output =
checked_vcd_output!(&mut sim, "tests/sim/expected/test_formal_counter.vcd");
let Some((_, any_seq_in)) = sim
.global_io()
.into_iter()
.find(|(global, _)| global.kind() == FormalInputKind::AnySeq)
else {
panic!("can't find any_seq");
};
let any_seq_in = Expr::<UInt<16>>::from_canonical(any_seq_in);
sim.write_clock(formal_global_clock(), false);
sim.write_reset(formal_reset(), true);
sim.write(any_seq_in, 0u16);
sim.write(sim.io().enable_assert, true);
sim.advance_time(SimDuration::from_micros(1));
assert_eq!(sim.read(sim.io().any_seq_out).as_int(), 0u16);
sim.write_clock(formal_global_clock(), true);
sim.write(any_seq_in, 1234u16);
assert_eq!(sim.read(sim.io().any_seq_out).as_int(), 1234u16);
assert_eq!(sim.read(sim.io().count).as_int(), 0);
sim.write_reset(formal_reset(), false);
sim.advance_time(SimDuration::from_micros(1));
for i in 0..32u8 {
assert_eq!(i % 10, sim.read(sim.io().count).as_int());
sim.write_clock(formal_global_clock(), false);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(formal_global_clock(), true);
sim.advance_time(SimDuration::from_micros(1));
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/test_formal_counter.txt") {
panic!();
}
}
#[cfg(panic = "unwind")]
#[hdl]
#[test]
fn test_formal_counter_assert() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(formal_counter(10, 8));
let _checked_vcd_output = checked_vcd_output!(
&mut sim,
"tests/sim/expected/test_formal_counter_assert.vcd"
);
let Some((_, any_seq_in)) = sim
.global_io()
.into_iter()
.find(|(global, _)| global.kind() == FormalInputKind::AnySeq)
else {
panic!("can't find any_seq");
};
let any_seq_in = Expr::<UInt<16>>::from_canonical(any_seq_in);
let half_us = SimDuration::from_nanos(500);
sim.write_clock(formal_global_clock(), false);
sim.write_reset(formal_reset(), true);
sim.write(any_seq_in, 0u16);
sim.write(sim.io().enable_assert, false);
sim.advance_time(half_us);
assert_eq!(sim.read(sim.io().any_seq_out).as_int(), 0u16);
sim.write_clock(formal_global_clock(), true);
sim.write(any_seq_in, 1234u16);
assert_eq!(sim.read(sim.io().any_seq_out).as_int(), 1234u16);
assert_eq!(sim.read(sim.io().count).as_int(), 0);
sim.write_reset(formal_reset(), false);
sim.advance_time(half_us);
const PANIC_MSG: &str = "Assertions/Assumptions failed at time 20.500000000000 \u{3bc}s:\n\
at module-XXXXXXXXXX.rs:12:1: in InstantiatedModule(formal_counter: formal_counter): assert failed: \n";
const EXPECTED_FAILURE_CYCLE: u8 = 19;
for i in 0.. {
dbg!(i);
assert_eq!(i % 10, sim.read(sim.io().count).as_int());
sim.write(sim.io().enable_assert, i > 15);
sim.write_clock(formal_global_clock(), false);
sim.advance_time(half_us);
match catch_unwind(AssertUnwindSafe(|| {
sim.write_clock(formal_global_clock(), true);
sim.advance_time(half_us);
})) {
Ok(()) => assert!(i < EXPECTED_FAILURE_CYCLE),
Err(e) => match e.downcast::<String>() {
Ok(e) if *e == PANIC_MSG => {
assert_eq!(i, EXPECTED_FAILURE_CYCLE);
break;
}
Ok(e) => resume_unwind(e),
Err(e) => resume_unwind(e),
},
}
}
}
#[hdl_module(outline_generated)]
pub fn enum_structural_eq() {
#[hdl]
let a: HdlOption<UInt<2>> = m.input();
#[hdl]
let b: HdlOption<UInt<2>> = m.input();
#[hdl]
let eq: Bool = m.output();
#[hdl]
let structural_eq: Bool = m.output();
#[hdl]
let bit_eq: Bool = m.output();
connect(eq, a.cmp_eq(b));
// explicitly use StructuralEq (though cmp_eq also uses it above)
connect(
structural_eq,
fayalite::expr::ops::StructuralEq::new(Expr::canonical(a), Expr::canonical(b)),
);
connect(bit_eq, a.cast_to_bits().cmp_eq(b.cast_to_bits()));
}
#[test]
fn test_enum_structural_eq() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(enum_structural_eq());
let _checked_vcd_output =
checked_vcd_output!(&mut sim, "tests/sim/expected/test_enum_structural_eq.vcd");
for a in 0..8u8 {
for b in 0..8u8 {
dbg!(a);
dbg!(b);
let a_sim_value = a.cast_to(UInt[3]).cast_bits_to(sim.io().a.ty());
let b_sim_value = b.cast_to(UInt[3]).cast_bits_to(sim.io().b.ty());
dbg!(&a_sim_value);
dbg!(&b_sim_value);
sim.write(sim.io().a, a_sim_value);
sim.write(sim.io().b, b_sim_value);
let a_with_zeroed_padding = if (a & 1) != 0 { a } else { 0 };
let b_with_zeroed_padding = if (b & 1) != 0 { b } else { 0 };
dbg!(a_with_zeroed_padding);
dbg!(b_with_zeroed_padding);
let expected_eq = a_with_zeroed_padding == b_with_zeroed_padding;
let expected_structural_eq = a_with_zeroed_padding == b_with_zeroed_padding;
let expected_bit_eq = a == b;
dbg!(expected_eq);
dbg!(expected_structural_eq);
dbg!(expected_bit_eq);
sim.advance_time(SimDuration::from_micros(1));
assert_eq!(sim.read_bool(sim.io().eq), expected_eq);
assert_eq!(
sim.read_bool(sim.io().structural_eq),
expected_structural_eq
);
assert_eq!(sim.read_bool(sim.io().bit_eq), expected_bit_eq);
}
}
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug != include_str!("sim/expected/test_enum_structural_eq.txt") {
panic!();
}
}

View file

@ -419,6 +419,7 @@ Simulation {
},
pc: 38,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -497,6 +498,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1218,6 +1220,7 @@ Simulation {
index: StatePartIndex<BigSlots>(0),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xff,
last_state: 0xff,
},
@ -1227,6 +1230,7 @@ Simulation {
index: StatePartIndex<BigSlots>(1),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x7f,
last_state: 0x7f,
},
@ -1236,6 +1240,7 @@ Simulation {
index: StatePartIndex<BigSlots>(2),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x3f,
last_state: 0x3f,
},
@ -1245,6 +1250,7 @@ Simulation {
index: StatePartIndex<BigSlots>(3),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1254,6 +1260,7 @@ Simulation {
index: StatePartIndex<BigSlots>(4),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x0f,
last_state: 0x0f,
},
@ -1263,6 +1270,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x07,
last_state: 0x07,
},
@ -1272,6 +1280,7 @@ Simulation {
index: StatePartIndex<BigSlots>(6),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x03,
last_state: 0x03,
},
@ -1281,6 +1290,7 @@ Simulation {
index: StatePartIndex<BigSlots>(7),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x01,
last_state: 0x01,
},
@ -1290,6 +1300,7 @@ Simulation {
index: StatePartIndex<BigSlots>(8),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -1299,6 +1310,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x80,
last_state: 0x80,
},
@ -1308,6 +1320,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xc0,
last_state: 0xc0,
},
@ -1317,6 +1330,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xe0,
last_state: 0xe0,
},
@ -1326,6 +1340,7 @@ Simulation {
index: StatePartIndex<BigSlots>(12),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xf0,
last_state: 0xf0,
},
@ -1335,6 +1350,7 @@ Simulation {
index: StatePartIndex<BigSlots>(13),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xf8,
last_state: 0xf8,
},
@ -1344,6 +1360,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xfc,
last_state: 0xfc,
},
@ -1353,6 +1370,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xfe,
last_state: 0xfe,
},
@ -1362,6 +1380,7 @@ Simulation {
index: StatePartIndex<BigSlots>(16),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xff,
last_state: 0xff,
},
@ -1371,6 +1390,7 @@ Simulation {
index: StatePartIndex<BigSlots>(17),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x7f,
last_state: 0x7f,
},
@ -1380,6 +1400,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x3f,
last_state: 0x3f,
},
@ -1389,6 +1410,7 @@ Simulation {
index: StatePartIndex<BigSlots>(19),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1398,6 +1420,7 @@ Simulation {
index: StatePartIndex<BigSlots>(20),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x0f,
last_state: 0x0f,
},
@ -1407,6 +1430,7 @@ Simulation {
index: StatePartIndex<BigSlots>(21),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x07,
last_state: 0x07,
},
@ -1416,6 +1440,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x03,
last_state: 0x03,
},
@ -1425,6 +1450,7 @@ Simulation {
index: StatePartIndex<BigSlots>(23),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x01,
last_state: 0x01,
},
@ -1434,6 +1460,7 @@ Simulation {
index: StatePartIndex<BigSlots>(24),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -1443,6 +1470,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x80,
last_state: 0x80,
},
@ -1452,6 +1480,7 @@ Simulation {
index: StatePartIndex<BigSlots>(26),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xc0,
last_state: 0xc0,
},
@ -1461,6 +1490,7 @@ Simulation {
index: StatePartIndex<BigSlots>(27),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xe0,
last_state: 0xe0,
},
@ -1470,6 +1500,7 @@ Simulation {
index: StatePartIndex<BigSlots>(28),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xf0,
last_state: 0xf0,
},
@ -1479,6 +1510,7 @@ Simulation {
index: StatePartIndex<BigSlots>(29),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xf8,
last_state: 0xf8,
},
@ -1488,6 +1520,7 @@ Simulation {
index: StatePartIndex<BigSlots>(30),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xfc,
last_state: 0xfc,
},
@ -1497,6 +1530,7 @@ Simulation {
index: StatePartIndex<BigSlots>(31),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xfe,
last_state: 0xe1,
},
@ -1506,6 +1540,7 @@ Simulation {
index: StatePartIndex<BigSlots>(32),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -1515,6 +1550,7 @@ Simulation {
index: StatePartIndex<BigSlots>(33),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xff,
last_state: 0xff,
},
@ -1524,6 +1560,7 @@ Simulation {
index: StatePartIndex<BigSlots>(34),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x10,
last_state: 0x0f,
},
@ -1533,6 +1570,7 @@ Simulation {
index: StatePartIndex<BigSlots>(35),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0xe1,
},
@ -1541,6 +1579,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1550,6 +1589,7 @@ Simulation {
index: StatePartIndex<BigSlots>(37),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xff,
last_state: 0xff,
},
@ -1559,6 +1599,7 @@ Simulation {
index: StatePartIndex<BigSlots>(38),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x7f,
last_state: 0x7f,
},
@ -1568,6 +1609,7 @@ Simulation {
index: StatePartIndex<BigSlots>(39),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x3f,
last_state: 0x3f,
},
@ -1577,6 +1619,7 @@ Simulation {
index: StatePartIndex<BigSlots>(40),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1586,6 +1629,7 @@ Simulation {
index: StatePartIndex<BigSlots>(41),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x0f,
last_state: 0x0f,
},
@ -1595,6 +1639,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x07,
last_state: 0x07,
},
@ -1604,6 +1649,7 @@ Simulation {
index: StatePartIndex<BigSlots>(43),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x03,
last_state: 0x03,
},
@ -1613,6 +1659,7 @@ Simulation {
index: StatePartIndex<BigSlots>(44),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x01,
last_state: 0x01,
},
@ -1622,6 +1669,7 @@ Simulation {
index: StatePartIndex<BigSlots>(45),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -1631,6 +1679,7 @@ Simulation {
index: StatePartIndex<BigSlots>(46),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x80,
last_state: 0x80,
},
@ -1640,6 +1689,7 @@ Simulation {
index: StatePartIndex<BigSlots>(47),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xc0,
last_state: 0xc0,
},
@ -1649,6 +1699,7 @@ Simulation {
index: StatePartIndex<BigSlots>(48),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xe0,
last_state: 0xe0,
},
@ -1658,6 +1709,7 @@ Simulation {
index: StatePartIndex<BigSlots>(49),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xf0,
last_state: 0xf0,
},
@ -1667,6 +1719,7 @@ Simulation {
index: StatePartIndex<BigSlots>(50),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xf8,
last_state: 0xf8,
},
@ -1676,6 +1729,7 @@ Simulation {
index: StatePartIndex<BigSlots>(51),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xfc,
last_state: 0xfc,
},
@ -1685,6 +1739,7 @@ Simulation {
index: StatePartIndex<BigSlots>(52),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xfe,
last_state: 0xe1,
},
@ -1706,5 +1761,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -76,6 +76,7 @@ Simulation {
},
pc: 5,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -101,6 +102,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -155,6 +157,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
@ -163,6 +166,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -184,5 +188,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -54,6 +54,7 @@ Simulation {
},
pc: 2,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -77,6 +78,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -124,6 +126,7 @@ Simulation {
index: StatePartIndex<BigSlots>(0),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x05,
last_state: 0x05,
},
@ -137,5 +140,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -80,6 +80,7 @@ Simulation {
},
pc: 5,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -106,6 +107,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -175,6 +177,7 @@ Simulation {
kind: BigAsyncReset {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -183,6 +186,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -204,5 +208,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -180,6 +180,7 @@ Simulation {
},
pc: 19,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -216,6 +217,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -332,6 +334,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
@ -340,6 +343,7 @@ Simulation {
kind: BigAsyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -349,6 +353,7 @@ Simulation {
index: StatePartIndex<BigSlots>(2),
ty: UInt<4>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x2,
},
@ -358,6 +363,7 @@ Simulation {
index: StatePartIndex<BigSlots>(3),
ty: UInt<4>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x2,
},
@ -381,5 +387,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -162,6 +162,7 @@ Simulation {
},
pc: 16,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -197,6 +198,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -313,6 +315,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
@ -321,6 +324,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -330,6 +334,7 @@ Simulation {
index: StatePartIndex<BigSlots>(2),
ty: UInt<4>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x2,
},
@ -339,6 +344,7 @@ Simulation {
index: StatePartIndex<BigSlots>(3),
ty: UInt<4>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x2,
},
@ -362,5 +368,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -72,6 +72,7 @@ Simulation {
},
pc: 4,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -97,6 +98,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [],
uninitialized_ios: {},
@ -137,6 +139,7 @@ Simulation {
index: StatePartIndex<BigSlots>(0),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x05,
last_state: 0x05,
},
@ -146,6 +149,7 @@ Simulation {
index: StatePartIndex<BigSlots>(2),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x06,
last_state: 0x06,
},
@ -167,5 +171,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -0,0 +1,752 @@
Simulation {
state: State {
insns: Insns {
state_layout: StateLayout {
ty: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: Enum {
A,
B,
C,
},
},
],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 33,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_in",
ty: UInt<8>,
},
SlotDebugData {
name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_in",
ty: UInt<8>,
},
SlotDebugData {
name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_out",
ty: UInt<8>,
},
SlotDebugData {
name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_out",
ty: UInt<8>,
},
SlotDebugData {
name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out",
ty: Enum {
A(UInt<8>),
B(UInt<8>),
C(UInt<8>),
},
},
SlotDebugData {
name: "",
ty: UInt<10>,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: ".0",
ty: UInt<2>,
},
SlotDebugData {
name: ".1",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<2>,
},
SlotDebugData {
name: "",
ty: UInt<10>,
},
SlotDebugData {
name: "",
ty: UInt<10>,
},
SlotDebugData {
name: "",
ty: UInt<10>,
},
SlotDebugData {
name: "",
ty: Enum {
A(UInt<8>),
B(UInt<8>),
C(UInt<8>),
},
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: ".0",
ty: UInt<2>,
},
SlotDebugData {
name: ".1",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<2>,
},
SlotDebugData {
name: "",
ty: UInt<10>,
},
SlotDebugData {
name: "",
ty: UInt<10>,
},
SlotDebugData {
name: "",
ty: UInt<10>,
},
SlotDebugData {
name: "",
ty: Enum {
A(UInt<8>),
B(UInt<8>),
C(UInt<8>),
},
},
SlotDebugData {
name: ".0",
ty: UInt<2>,
},
SlotDebugData {
name: ".1",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<2>,
},
SlotDebugData {
name: "",
ty: UInt<10>,
},
SlotDebugData {
name: "",
ty: UInt<10>,
},
SlotDebugData {
name: "",
ty: UInt<10>,
},
SlotDebugData {
name: "",
ty: Enum {
A(UInt<8>),
B(UInt<8>),
C(UInt<8>),
},
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
memories: StatePartLayout<Memories> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
insns: [
// at: module-XXXXXXXXXX.rs:1:1
0: Const {
dest: StatePartIndex<BigSlots>(32), // (0x2) SlotDebugData { name: "", ty: UInt<8> },
value: 0x2,
},
1: Const {
dest: StatePartIndex<BigSlots>(27), // (0x2) SlotDebugData { name: "", ty: UInt<2> },
value: 0x2,
},
2: Copy {
dest: StatePartIndex<BigSlots>(25), // (0x2) SlotDebugData { name: ".0", ty: UInt<2> },
src: StatePartIndex<BigSlots>(27), // (0x2) SlotDebugData { name: "", ty: UInt<2> },
},
3: Copy {
dest: StatePartIndex<BigSlots>(26), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> },
src: StatePartIndex<BigSlots>(1), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_in", ty: UInt<8> },
},
4: Shl {
dest: StatePartIndex<BigSlots>(28), // (0x384) SlotDebugData { name: "", ty: UInt<10> },
lhs: StatePartIndex<BigSlots>(26), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> },
rhs: 2,
},
5: Or {
dest: StatePartIndex<BigSlots>(29), // (0x386) SlotDebugData { name: "", ty: UInt<10> },
lhs: StatePartIndex<BigSlots>(25), // (0x2) SlotDebugData { name: ".0", ty: UInt<2> },
rhs: StatePartIndex<BigSlots>(28), // (0x384) SlotDebugData { name: "", ty: UInt<10> },
},
6: CastToUInt {
dest: StatePartIndex<BigSlots>(30), // (0x386) SlotDebugData { name: "", ty: UInt<10> },
src: StatePartIndex<BigSlots>(29), // (0x386) SlotDebugData { name: "", ty: UInt<10> },
dest_width: 10,
},
7: Copy {
dest: StatePartIndex<BigSlots>(31), // (0x386) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
src: StatePartIndex<BigSlots>(30), // (0x386) SlotDebugData { name: "", ty: UInt<10> },
},
8: Const {
dest: StatePartIndex<BigSlots>(20), // (0x1) SlotDebugData { name: "", ty: UInt<2> },
value: 0x1,
},
9: Copy {
dest: StatePartIndex<BigSlots>(18), // (0x1) SlotDebugData { name: ".0", ty: UInt<2> },
src: StatePartIndex<BigSlots>(20), // (0x1) SlotDebugData { name: "", ty: UInt<2> },
},
10: Copy {
dest: StatePartIndex<BigSlots>(19), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> },
src: StatePartIndex<BigSlots>(1), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_in", ty: UInt<8> },
},
11: Shl {
dest: StatePartIndex<BigSlots>(21), // (0x384) SlotDebugData { name: "", ty: UInt<10> },
lhs: StatePartIndex<BigSlots>(19), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> },
rhs: 2,
},
12: Or {
dest: StatePartIndex<BigSlots>(22), // (0x385) SlotDebugData { name: "", ty: UInt<10> },
lhs: StatePartIndex<BigSlots>(18), // (0x1) SlotDebugData { name: ".0", ty: UInt<2> },
rhs: StatePartIndex<BigSlots>(21), // (0x384) SlotDebugData { name: "", ty: UInt<10> },
},
13: CastToUInt {
dest: StatePartIndex<BigSlots>(23), // (0x385) SlotDebugData { name: "", ty: UInt<10> },
src: StatePartIndex<BigSlots>(22), // (0x385) SlotDebugData { name: "", ty: UInt<10> },
dest_width: 10,
},
14: Copy {
dest: StatePartIndex<BigSlots>(24), // (0x385) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
src: StatePartIndex<BigSlots>(23), // (0x385) SlotDebugData { name: "", ty: UInt<10> },
},
15: Const {
dest: StatePartIndex<BigSlots>(16), // (0x1) SlotDebugData { name: "", ty: UInt<8> },
value: 0x1,
},
16: CmpEq {
dest: StatePartIndex<BigSlots>(17), // (0x0) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(0), // (0x2) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_in", ty: UInt<8> },
rhs: StatePartIndex<BigSlots>(16), // (0x1) SlotDebugData { name: "", ty: UInt<8> },
},
17: Const {
dest: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> },
value: 0x0,
},
18: Copy {
dest: StatePartIndex<BigSlots>(9), // (0x0) SlotDebugData { name: ".0", ty: UInt<2> },
src: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> },
},
19: Copy {
dest: StatePartIndex<BigSlots>(10), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> },
src: StatePartIndex<BigSlots>(1), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_in", ty: UInt<8> },
},
20: Shl {
dest: StatePartIndex<BigSlots>(12), // (0x384) SlotDebugData { name: "", ty: UInt<10> },
lhs: StatePartIndex<BigSlots>(10), // (0xe1) SlotDebugData { name: ".1", ty: UInt<8> },
rhs: 2,
},
21: Or {
dest: StatePartIndex<BigSlots>(13), // (0x384) SlotDebugData { name: "", ty: UInt<10> },
lhs: StatePartIndex<BigSlots>(9), // (0x0) SlotDebugData { name: ".0", ty: UInt<2> },
rhs: StatePartIndex<BigSlots>(12), // (0x384) SlotDebugData { name: "", ty: UInt<10> },
},
22: CastToUInt {
dest: StatePartIndex<BigSlots>(14), // (0x384) SlotDebugData { name: "", ty: UInt<10> },
src: StatePartIndex<BigSlots>(13), // (0x384) SlotDebugData { name: "", ty: UInt<10> },
dest_width: 10,
},
23: Copy {
dest: StatePartIndex<BigSlots>(15), // (0x384) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
src: StatePartIndex<BigSlots>(14), // (0x384) SlotDebugData { name: "", ty: UInt<10> },
},
24: Const {
dest: StatePartIndex<BigSlots>(7), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
value: 0x0,
},
25: CmpEq {
dest: StatePartIndex<BigSlots>(8), // (0x0) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(0), // (0x2) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_in", ty: UInt<8> },
rhs: StatePartIndex<BigSlots>(7), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:7:1
26: BranchIfZero {
target: 28,
value: StatePartIndex<BigSlots>(8), // (0x0) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:8:1
27: Copy {
dest: StatePartIndex<BigSlots>(4), // (0x386) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
src: StatePartIndex<BigSlots>(15), // (0x384) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
},
// at: module-XXXXXXXXXX.rs:7:1
28: BranchIfNonZero {
target: 33,
value: StatePartIndex<BigSlots>(8), // (0x0) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:9:1
29: BranchIfZero {
target: 31,
value: StatePartIndex<BigSlots>(17), // (0x0) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:10:1
30: Copy {
dest: StatePartIndex<BigSlots>(4), // (0x386) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
src: StatePartIndex<BigSlots>(24), // (0x385) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
},
// at: module-XXXXXXXXXX.rs:9:1
31: BranchIfNonZero {
target: 33,
value: StatePartIndex<BigSlots>(17), // (0x0) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:11:1
32: Copy {
dest: StatePartIndex<BigSlots>(4), // (0x386) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
src: StatePartIndex<BigSlots>(31), // (0x386) SlotDebugData { name: "", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
},
// at: module-XXXXXXXXXX.rs:1:1
33: Copy {
dest: StatePartIndex<BigSlots>(5), // (0x386) SlotDebugData { name: "", ty: UInt<10> },
src: StatePartIndex<BigSlots>(4), // (0x386) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
},
34: SliceInt {
dest: StatePartIndex<BigSlots>(6), // (0xe1) SlotDebugData { name: "", ty: UInt<8> },
src: StatePartIndex<BigSlots>(5), // (0x386) SlotDebugData { name: "", ty: UInt<10> },
start: 2,
len: 8,
},
// at: module-XXXXXXXXXX.rs:6:1
35: AndBigWithSmallImmediate {
dest: StatePartIndex<SmallSlots>(0), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} },
lhs: StatePartIndex<BigSlots>(4), // (0x386) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::enum_out", ty: Enum {A(UInt<8>), B(UInt<8>), C(UInt<8>)} },
rhs: 0x3,
},
// at: module-XXXXXXXXXX.rs:12:1
36: BranchIfSmallNeImmediate {
target: 39,
lhs: StatePartIndex<SmallSlots>(0), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} },
rhs: 0x0,
},
// at: module-XXXXXXXXXX.rs:13:1
37: Copy {
dest: StatePartIndex<BigSlots>(2), // (0x2) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_out", ty: UInt<8> },
src: StatePartIndex<BigSlots>(7), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:14:1
38: Copy {
dest: StatePartIndex<BigSlots>(3), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_out", ty: UInt<8> },
src: StatePartIndex<BigSlots>(6), // (0xe1) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:12:1
39: BranchIfSmallNeImmediate {
target: 42,
lhs: StatePartIndex<SmallSlots>(0), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} },
rhs: 0x1,
},
// at: module-XXXXXXXXXX.rs:15:1
40: Copy {
dest: StatePartIndex<BigSlots>(2), // (0x2) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_out", ty: UInt<8> },
src: StatePartIndex<BigSlots>(16), // (0x1) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:16:1
41: Copy {
dest: StatePartIndex<BigSlots>(3), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_out", ty: UInt<8> },
src: StatePartIndex<BigSlots>(6), // (0xe1) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:12:1
42: BranchIfSmallNeImmediate {
target: 45,
lhs: StatePartIndex<SmallSlots>(0), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} },
rhs: 0x2,
},
// at: module-XXXXXXXXXX.rs:17:1
43: Copy {
dest: StatePartIndex<BigSlots>(2), // (0x2) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::which_out", ty: UInt<8> },
src: StatePartIndex<BigSlots>(32), // (0x2) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:18:1
44: Copy {
dest: StatePartIndex<BigSlots>(3), // (0xe1) SlotDebugData { name: "InstantiatedModule(enum_with_simple_body: enum_with_simple_body).enum_with_simple_body::data_out", ty: UInt<8> },
src: StatePartIndex<BigSlots>(6), // (0xe1) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:1:1
45: Return,
],
..
},
pc: 45,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
small_slots: StatePart {
value: [
2,
],
},
big_slots: StatePart {
value: [
2,
225,
2 (modified),
225 (modified),
902,
902,
225,
0,
0,
0,
225,
0,
900,
900,
900,
900,
1,
0,
1,
225,
1,
900,
901,
901,
901,
2,
225,
2,
900,
902,
902,
902,
2,
],
},
sim_only_slots: StatePart {
value: [],
},
},
io: Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
}.which_in,
Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
}.data_in,
Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
}.which_out,
Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
}.data_out,
Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
}.enum_out,
],
uninitialized_ios: {},
io_targets: {
Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
}.data_in,
Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
}.data_out,
Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
}.enum_out,
Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
}.which_in,
Instance {
name: <simulator>::enum_with_simple_body,
instantiated: Module {
name: enum_with_simple_body,
..
},
}.which_out,
},
did_initial_settle: true,
clocks_for_past: {},
},
extern_modules: [],
trace_decls: TraceModule {
name: "enum_with_simple_body",
children: [
TraceModuleIO {
name: "which_in",
child: TraceUInt {
location: TraceScalarId(0),
name: "which_in",
ty: UInt<8>,
flow: Source,
},
ty: UInt<8>,
flow: Source,
},
TraceModuleIO {
name: "data_in",
child: TraceUInt {
location: TraceScalarId(1),
name: "data_in",
ty: UInt<8>,
flow: Source,
},
ty: UInt<8>,
flow: Source,
},
TraceModuleIO {
name: "which_out",
child: TraceUInt {
location: TraceScalarId(2),
name: "which_out",
ty: UInt<8>,
flow: Sink,
},
ty: UInt<8>,
flow: Sink,
},
TraceModuleIO {
name: "data_out",
child: TraceUInt {
location: TraceScalarId(3),
name: "data_out",
ty: UInt<8>,
flow: Sink,
},
ty: UInt<8>,
flow: Sink,
},
TraceModuleIO {
name: "enum_out",
child: TraceEnumWithFields {
name: "enum_out",
discriminant: TraceEnumDiscriminant {
location: TraceScalarId(4),
name: "$tag",
ty: Enum {
A(UInt<8>),
B(UInt<8>),
C(UInt<8>),
},
flow: Sink,
},
non_empty_fields: [
TraceUInt {
location: TraceScalarId(5),
name: "A",
ty: UInt<8>,
flow: Source,
},
TraceUInt {
location: TraceScalarId(6),
name: "B",
ty: UInt<8>,
flow: Source,
},
TraceUInt {
location: TraceScalarId(7),
name: "C",
ty: UInt<8>,
flow: Source,
},
],
ty: Enum {
A(UInt<8>),
B(UInt<8>),
C(UInt<8>),
},
flow: Sink,
},
ty: Enum {
A(UInt<8>),
B(UInt<8>),
C(UInt<8>),
},
flow: Sink,
},
],
},
traces: [
SimTrace {
id: TraceScalarId(0),
kind: BigUInt {
index: StatePartIndex<BigSlots>(0),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x02,
last_state: 0x02,
},
SimTrace {
id: TraceScalarId(1),
kind: BigUInt {
index: StatePartIndex<BigSlots>(1),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xe1,
last_state: 0xb4,
},
SimTrace {
id: TraceScalarId(2),
kind: BigUInt {
index: StatePartIndex<BigSlots>(2),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x02,
last_state: 0x02,
},
SimTrace {
id: TraceScalarId(3),
kind: BigUInt {
index: StatePartIndex<BigSlots>(3),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xe1,
last_state: 0xb4,
},
SimTrace {
id: TraceScalarId(4),
kind: EnumDiscriminant {
index: StatePartIndex<SmallSlots>(0),
ty: Enum {
A(UInt<8>),
B(UInt<8>),
C(UInt<8>),
},
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
SimTrace {
id: TraceScalarId(5),
kind: BigUInt {
index: StatePartIndex<BigSlots>(6),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xe1,
last_state: 0xb4,
},
SimTrace {
id: TraceScalarId(6),
kind: BigUInt {
index: StatePartIndex<BigSlots>(6),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xe1,
last_state: 0xb4,
},
SimTrace {
id: TraceScalarId(7),
kind: BigUInt {
index: StatePartIndex<BigSlots>(6),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xe1,
last_state: 0xb4,
},
],
trace_memories: {},
trace_writers: [
Running(
VcdWriter {
finished_init: true,
timescale: 1 ps,
..
},
),
],
clocks_triggered: [],
event_queue: EventQueue(EventQueueData {
instant: 18 μs,
events: {},
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -0,0 +1,133 @@
$timescale 1 ps $end
$scope module enum_with_simple_body $end
$var wire 8 J&-ne which_in $end
$var wire 8 \7mo/ data_in $end
$var wire 8 ,`>ir which_out $end
$var wire 8 0_gMP data_out $end
$scope struct enum_out $end
$var string 1 kFH/w \$tag $end
$var wire 8 |EI_= A $end
$var wire 8 !pRd4 B $end
$var wire 8 &RAbd C $end
$upscope $end
$upscope $end
$enddefinitions $end
$dumpvars
b0 J&-ne
b0 \7mo/
b0 ,`>ir
b0 0_gMP
sA\x20(0) kFH/w
b0 |EI_=
b0 !pRd4
b0 &RAbd
$end
#1000000
b101101 \7mo/
b101101 0_gMP
b101101 |EI_=
b101101 !pRd4
b101101 &RAbd
#2000000
b1011010 \7mo/
b1011010 0_gMP
b1011010 |EI_=
b1011010 !pRd4
b1011010 &RAbd
#3000000
b10000111 \7mo/
b10000111 0_gMP
b10000111 |EI_=
b10000111 !pRd4
b10000111 &RAbd
#4000000
b10110100 \7mo/
b10110100 0_gMP
b10110100 |EI_=
b10110100 !pRd4
b10110100 &RAbd
#5000000
b11100001 \7mo/
b11100001 0_gMP
b11100001 |EI_=
b11100001 !pRd4
b11100001 &RAbd
#6000000
b1 J&-ne
b0 \7mo/
b1 ,`>ir
b0 0_gMP
sB\x20(1) kFH/w
b0 |EI_=
b0 !pRd4
b0 &RAbd
#7000000
b101101 \7mo/
b101101 0_gMP
b101101 |EI_=
b101101 !pRd4
b101101 &RAbd
#8000000
b1011010 \7mo/
b1011010 0_gMP
b1011010 |EI_=
b1011010 !pRd4
b1011010 &RAbd
#9000000
b10000111 \7mo/
b10000111 0_gMP
b10000111 |EI_=
b10000111 !pRd4
b10000111 &RAbd
#10000000
b10110100 \7mo/
b10110100 0_gMP
b10110100 |EI_=
b10110100 !pRd4
b10110100 &RAbd
#11000000
b11100001 \7mo/
b11100001 0_gMP
b11100001 |EI_=
b11100001 !pRd4
b11100001 &RAbd
#12000000
b10 J&-ne
b0 \7mo/
b10 ,`>ir
b0 0_gMP
sC\x20(2) kFH/w
b0 |EI_=
b0 !pRd4
b0 &RAbd
#13000000
b101101 \7mo/
b101101 0_gMP
b101101 |EI_=
b101101 !pRd4
b101101 &RAbd
#14000000
b1011010 \7mo/
b1011010 0_gMP
b1011010 |EI_=
b1011010 !pRd4
b1011010 &RAbd
#15000000
b10000111 \7mo/
b10000111 0_gMP
b10000111 |EI_=
b10000111 !pRd4
b10000111 &RAbd
#16000000
b10110100 \7mo/
b10110100 0_gMP
b10110100 |EI_=
b10110100 !pRd4
b10110100 &RAbd
#17000000
b11100001 \7mo/
b11100001 0_gMP
b11100001 |EI_=
b11100001 !pRd4
b11100001 &RAbd
#18000000

View file

@ -1184,6 +1184,7 @@ Simulation {
},
pc: 133,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -1324,6 +1325,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1746,6 +1748,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
@ -1754,6 +1757,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1762,6 +1766,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(2),
},
maybe_changed: false,
state: 0x1,
last_state: 0x1,
},
@ -1771,6 +1776,7 @@ Simulation {
index: StatePartIndex<BigSlots>(3),
ty: UInt<2>,
},
maybe_changed: false,
state: 0x2,
last_state: 0x2,
},
@ -1780,6 +1786,7 @@ Simulation {
index: StatePartIndex<BigSlots>(4),
ty: UInt<4>,
},
maybe_changed: false,
state: 0xf,
last_state: 0xf,
},
@ -1789,6 +1796,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1798,6 +1806,7 @@ Simulation {
index: StatePartIndex<BigSlots>(6),
ty: UInt<4>,
},
maybe_changed: true,
state: 0xf,
last_state: 0xf,
},
@ -1810,6 +1819,7 @@ Simulation {
HdlSome(Bundle {0: UInt<1>, 1: Bool}),
},
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1819,6 +1829,7 @@ Simulation {
index: StatePartIndex<BigSlots>(8),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1827,6 +1838,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(9),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1839,6 +1851,7 @@ Simulation {
HdlSome(Bundle {0: UInt<1>, 1: Bool}),
},
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1848,6 +1861,7 @@ Simulation {
index: StatePartIndex<BigSlots>(16),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1856,6 +1870,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1869,6 +1884,7 @@ Simulation {
C(Bundle {a: Array<UInt<1>, 2>, b: SInt<2>}),
},
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1878,6 +1894,7 @@ Simulation {
index: StatePartIndex<BigSlots>(27),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1886,6 +1903,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(28),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1895,6 +1913,7 @@ Simulation {
index: StatePartIndex<BigSlots>(34),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1904,6 +1923,7 @@ Simulation {
index: StatePartIndex<BigSlots>(35),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1913,6 +1933,7 @@ Simulation {
index: StatePartIndex<BigSlots>(36),
ty: SInt<2>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x3,
},
@ -1936,5 +1957,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -44,6 +44,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -67,6 +68,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -221,6 +223,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: false,
state: 0x1,
last_state: 0x1,
},
@ -229,6 +232,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
@ -259,5 +263,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -48,6 +48,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -57,7 +58,7 @@ Simulation {
big_slots: StatePart {
value: [
0,
1,
1 (modified),
101,
],
},
@ -72,6 +73,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -280,6 +282,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -288,6 +291,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -297,6 +301,7 @@ Simulation {
index: StatePartIndex<BigSlots>(2),
ty: UInt<8>,
},
maybe_changed: false,
state: 0x65,
last_state: 0x65,
},
@ -413,5 +418,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -407,6 +407,7 @@ Simulation {
},
pc: 44,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -433,7 +434,7 @@ Simulation {
1,
1,
1,
7,
7 (modified),
7,
3,
0,
@ -464,6 +465,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -614,6 +616,7 @@ Simulation {
HdlSome(Array<Bool, 4>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -622,6 +625,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -630,6 +634,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(2),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -638,6 +643,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -646,6 +652,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(4),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
@ -658,6 +665,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -667,6 +675,7 @@ Simulation {
index: StatePartIndex<BigSlots>(17),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x03,
last_state: 0x02,
},
@ -676,6 +685,7 @@ Simulation {
index: StatePartIndex<BigSlots>(20),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x03,
last_state: 0x02,
},
@ -697,5 +707,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

File diff suppressed because it is too large Load diff

View file

@ -494,6 +494,7 @@ Simulation {
},
pc: 41,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -579,6 +580,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1168,6 +1170,7 @@ Simulation {
index: StatePartIndex<BigSlots>(0),
ty: UInt<4>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1176,6 +1179,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1184,6 +1188,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(2),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1193,6 +1198,7 @@ Simulation {
index: StatePartIndex<BigSlots>(3),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xb0,
last_state: 0xb0,
},
@ -1202,6 +1208,7 @@ Simulation {
index: StatePartIndex<BigSlots>(4),
ty: SInt<8>,
},
maybe_changed: true,
state: 0xc0,
last_state: 0xc0,
},
@ -1211,6 +1218,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<4>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1219,6 +1227,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(6),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1227,6 +1236,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1236,6 +1246,7 @@ Simulation {
index: StatePartIndex<BigSlots>(8),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xd0,
last_state: 0xd0,
},
@ -1245,6 +1256,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: SInt<8>,
},
maybe_changed: true,
state: 0xe0,
last_state: 0xe0,
},
@ -1253,6 +1265,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(10),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1261,6 +1274,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(11),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1270,6 +1284,7 @@ Simulation {
index: StatePartIndex<BigSlots>(12),
ty: UInt<4>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1278,6 +1293,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1286,6 +1302,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(14),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1295,6 +1312,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xb0,
last_state: 0xb0,
},
@ -1304,6 +1322,7 @@ Simulation {
index: StatePartIndex<BigSlots>(16),
ty: SInt<8>,
},
maybe_changed: true,
state: 0xc0,
last_state: 0xc0,
},
@ -1313,6 +1332,7 @@ Simulation {
index: StatePartIndex<BigSlots>(17),
ty: UInt<4>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1321,6 +1341,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(18),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1329,6 +1350,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1338,6 +1360,7 @@ Simulation {
index: StatePartIndex<BigSlots>(20),
ty: UInt<8>,
},
maybe_changed: true,
state: 0xd0,
last_state: 0xd0,
},
@ -1347,6 +1370,7 @@ Simulation {
index: StatePartIndex<BigSlots>(21),
ty: SInt<8>,
},
maybe_changed: true,
state: 0xe0,
last_state: 0xe0,
},
@ -1355,6 +1379,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(22),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1363,6 +1388,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(23),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1626,5 +1652,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -526,6 +526,7 @@ Simulation {
},
pc: 52,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -607,6 +608,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -943,6 +945,7 @@ Simulation {
index: StatePartIndex<BigSlots>(0),
ty: UInt<3>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -951,6 +954,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -959,6 +963,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(2),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -968,6 +973,7 @@ Simulation {
index: StatePartIndex<BigSlots>(3),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -976,6 +982,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(4),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -985,6 +992,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<2>,
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -993,6 +1001,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(6),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1002,6 +1011,7 @@ Simulation {
index: StatePartIndex<BigSlots>(7),
ty: UInt<3>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1010,6 +1020,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(8),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1018,6 +1029,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(9),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1030,6 +1042,7 @@ Simulation {
HdlSome(Bool),
},
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1038,6 +1051,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1046,6 +1060,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(11),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1058,6 +1073,7 @@ Simulation {
HdlSome(Bool),
},
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1066,6 +1082,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1074,6 +1091,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1269,5 +1287,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1336,6 +1336,7 @@ Simulation {
},
pc: 129,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1495,6 +1496,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2391,6 +2393,7 @@ Simulation {
index: StatePartIndex<BigSlots>(0),
ty: UInt<3>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2399,6 +2402,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2407,6 +2411,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(2),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -2416,6 +2421,7 @@ Simulation {
index: StatePartIndex<BigSlots>(3),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2425,6 +2431,7 @@ Simulation {
index: StatePartIndex<BigSlots>(4),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2434,6 +2441,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2443,6 +2451,7 @@ Simulation {
index: StatePartIndex<BigSlots>(6),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2452,6 +2461,7 @@ Simulation {
index: StatePartIndex<BigSlots>(7),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2461,6 +2471,7 @@ Simulation {
index: StatePartIndex<BigSlots>(8),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2470,6 +2481,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2479,6 +2491,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2488,6 +2501,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<3>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2496,6 +2510,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2504,6 +2519,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -2513,6 +2529,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2522,6 +2539,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2531,6 +2549,7 @@ Simulation {
index: StatePartIndex<BigSlots>(16),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2540,6 +2559,7 @@ Simulation {
index: StatePartIndex<BigSlots>(17),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2549,6 +2569,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2558,6 +2579,7 @@ Simulation {
index: StatePartIndex<BigSlots>(19),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2567,6 +2589,7 @@ Simulation {
index: StatePartIndex<BigSlots>(20),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2576,6 +2599,7 @@ Simulation {
index: StatePartIndex<BigSlots>(21),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2584,6 +2608,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(22),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2592,6 +2617,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(23),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2600,6 +2626,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(24),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2608,6 +2635,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(25),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2616,6 +2644,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(26),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2624,6 +2653,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2632,6 +2662,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(28),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2640,6 +2671,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(29),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2649,6 +2681,7 @@ Simulation {
index: StatePartIndex<BigSlots>(30),
ty: UInt<3>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2657,6 +2690,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2665,6 +2699,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -2674,6 +2709,7 @@ Simulation {
index: StatePartIndex<BigSlots>(33),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2683,6 +2719,7 @@ Simulation {
index: StatePartIndex<BigSlots>(34),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2692,6 +2729,7 @@ Simulation {
index: StatePartIndex<BigSlots>(35),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2701,6 +2739,7 @@ Simulation {
index: StatePartIndex<BigSlots>(36),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2710,6 +2749,7 @@ Simulation {
index: StatePartIndex<BigSlots>(37),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2719,6 +2759,7 @@ Simulation {
index: StatePartIndex<BigSlots>(38),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2728,6 +2769,7 @@ Simulation {
index: StatePartIndex<BigSlots>(39),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2737,6 +2779,7 @@ Simulation {
index: StatePartIndex<BigSlots>(40),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2746,6 +2789,7 @@ Simulation {
index: StatePartIndex<BigSlots>(57),
ty: UInt<3>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2754,6 +2798,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(58),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2762,6 +2807,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(59),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -2771,6 +2817,7 @@ Simulation {
index: StatePartIndex<BigSlots>(60),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2780,6 +2827,7 @@ Simulation {
index: StatePartIndex<BigSlots>(61),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2789,6 +2837,7 @@ Simulation {
index: StatePartIndex<BigSlots>(62),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2798,6 +2847,7 @@ Simulation {
index: StatePartIndex<BigSlots>(63),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2807,6 +2857,7 @@ Simulation {
index: StatePartIndex<BigSlots>(64),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2816,6 +2867,7 @@ Simulation {
index: StatePartIndex<BigSlots>(65),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2825,6 +2877,7 @@ Simulation {
index: StatePartIndex<BigSlots>(66),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2834,6 +2887,7 @@ Simulation {
index: StatePartIndex<BigSlots>(67),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x00,
last_state: 0x00,
},
@ -2842,6 +2896,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(68),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2850,6 +2905,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(69),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2858,6 +2914,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(70),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2866,6 +2923,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(71),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2874,6 +2932,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(72),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2882,6 +2941,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(73),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2890,6 +2950,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(74),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2898,6 +2959,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(75),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -3285,5 +3347,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -187,6 +187,7 @@ Simulation {
},
pc: 17,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -225,6 +226,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -445,6 +447,7 @@ Simulation {
index: StatePartIndex<BigSlots>(0),
ty: UInt<4>,
},
maybe_changed: true,
state: 0xa,
last_state: 0x3,
},
@ -454,6 +457,7 @@ Simulation {
index: StatePartIndex<BigSlots>(1),
ty: SInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x3,
},
@ -463,6 +467,7 @@ Simulation {
index: StatePartIndex<BigSlots>(2),
ty: SInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -472,6 +477,7 @@ Simulation {
index: StatePartIndex<BigSlots>(3),
ty: UInt<4>,
},
maybe_changed: true,
state: 0xf,
last_state: 0xe,
},
@ -481,6 +487,7 @@ Simulation {
index: StatePartIndex<BigSlots>(8),
ty: UInt<4>,
},
maybe_changed: true,
state: 0xa,
last_state: 0x3,
},
@ -490,6 +497,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: SInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x3,
},
@ -499,6 +507,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: SInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -508,6 +517,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<4>,
},
maybe_changed: true,
state: 0xf,
last_state: 0xe,
},
@ -517,6 +527,7 @@ Simulation {
index: StatePartIndex<BigSlots>(4),
ty: UInt<4>,
},
maybe_changed: true,
state: 0xa,
last_state: 0x3,
},
@ -526,6 +537,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: SInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x3,
},
@ -535,6 +547,7 @@ Simulation {
index: StatePartIndex<BigSlots>(6),
ty: SInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -544,6 +557,7 @@ Simulation {
index: StatePartIndex<BigSlots>(7),
ty: UInt<4>,
},
maybe_changed: true,
state: 0xf,
last_state: 0xe,
},
@ -565,5 +579,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -172,6 +172,7 @@ Simulation {
},
pc: 16,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -215,6 +216,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -373,6 +375,7 @@ Simulation {
["a","b"],
),
},
maybe_changed: true,
state: PhantomConst,
last_state: PhantomConst,
},
@ -383,6 +386,7 @@ Simulation {
["a","b"],
),
},
maybe_changed: true,
state: PhantomConst,
last_state: PhantomConst,
},
@ -392,6 +396,7 @@ Simulation {
index: StatePartIndex<BigSlots>(0),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -400,6 +405,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -408,6 +414,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(2),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -418,6 +425,7 @@ Simulation {
"mem_element",
),
},
maybe_changed: true,
state: PhantomConst,
last_state: PhantomConst,
},
@ -521,5 +529,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1083,6 +1083,7 @@ Simulation {
},
pc: 134,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1201,6 +1202,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1722,6 +1724,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1730,6 +1733,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1742,6 +1746,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1751,6 +1756,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x19,
last_state: 0x19,
},
@ -1759,6 +1765,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1771,6 +1778,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1780,6 +1788,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x19,
last_state: 0x19,
},
@ -1788,6 +1797,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1797,6 +1807,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1806,6 +1817,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1814,6 +1826,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1822,6 +1835,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1831,6 +1845,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x19,
last_state: 0x19,
},
@ -1840,6 +1855,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1848,6 +1864,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1856,6 +1873,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1865,6 +1883,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x19,
last_state: 0x19,
},
@ -1873,6 +1892,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1882,6 +1902,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1891,6 +1912,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1899,6 +1921,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1907,6 +1930,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1915,6 +1939,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1923,6 +1948,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1931,6 +1957,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1939,6 +1966,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1947,6 +1975,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1955,6 +1984,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1964,6 +1994,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x19,
last_state: 0x19,
},
@ -1973,6 +2004,7 @@ Simulation {
index: StatePartIndex<BigSlots>(66),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2130,5 +2162,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1064,6 +1064,7 @@ Simulation {
},
pc: 132,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1180,6 +1181,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1701,6 +1703,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1709,6 +1712,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1721,6 +1725,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1730,6 +1735,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1738,6 +1744,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1750,6 +1757,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1759,6 +1767,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1767,6 +1776,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1776,6 +1786,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1785,6 +1796,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1793,6 +1805,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1801,6 +1814,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1810,6 +1824,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1819,6 +1834,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1827,6 +1843,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1835,6 +1852,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1844,6 +1862,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1852,6 +1871,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1861,6 +1881,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1870,6 +1891,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1878,6 +1900,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1886,6 +1909,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1894,6 +1918,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1902,6 +1927,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1910,6 +1936,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1918,6 +1945,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1926,6 +1954,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1934,6 +1963,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1943,6 +1973,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1952,6 +1983,7 @@ Simulation {
index: StatePartIndex<BigSlots>(64),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2109,5 +2141,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1093,6 +1093,7 @@ Simulation {
},
pc: 136,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1211,6 +1212,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1732,6 +1734,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1740,6 +1743,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1752,6 +1756,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1761,6 +1766,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1769,6 +1775,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1781,6 +1788,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1790,6 +1798,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1798,6 +1807,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1807,6 +1817,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1816,6 +1827,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1824,6 +1836,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1832,6 +1845,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1841,6 +1855,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1850,6 +1865,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1858,6 +1874,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1866,6 +1883,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1875,6 +1893,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1883,6 +1902,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1892,6 +1912,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1901,6 +1922,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1909,6 +1931,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1917,6 +1940,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1925,6 +1949,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1933,6 +1958,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1941,6 +1967,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1949,6 +1976,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1957,6 +1985,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1965,6 +1994,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1974,6 +2004,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x1f,
last_state: 0x1f,
},
@ -1983,6 +2014,7 @@ Simulation {
index: StatePartIndex<BigSlots>(66),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2140,5 +2172,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1074,6 +1074,7 @@ Simulation {
},
pc: 134,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1190,6 +1191,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1711,6 +1713,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1719,6 +1722,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1731,6 +1735,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1740,6 +1745,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x23,
last_state: 0x23,
},
@ -1748,6 +1754,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1760,6 +1767,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1769,6 +1777,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x23,
last_state: 0x23,
},
@ -1777,6 +1786,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1786,6 +1796,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1795,6 +1806,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1803,6 +1815,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1811,6 +1824,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1820,6 +1834,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x23,
last_state: 0x23,
},
@ -1829,6 +1844,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1837,6 +1853,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1845,6 +1862,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1854,6 +1872,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x23,
last_state: 0x23,
},
@ -1862,6 +1881,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1871,6 +1891,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1880,6 +1901,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1888,6 +1910,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1896,6 +1919,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1904,6 +1928,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1912,6 +1937,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1920,6 +1946,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1928,6 +1955,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1936,6 +1964,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1944,6 +1973,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1953,6 +1983,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x23,
last_state: 0x23,
},
@ -1962,6 +1993,7 @@ Simulation {
index: StatePartIndex<BigSlots>(64),
ty: UInt<0>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2119,5 +2151,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1098,6 +1098,7 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1219,6 +1220,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1740,6 +1742,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1748,6 +1751,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1760,6 +1764,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1769,6 +1774,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x23,
last_state: 0x23,
},
@ -1777,6 +1783,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1789,6 +1796,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1798,6 +1806,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x23,
last_state: 0x23,
},
@ -1806,6 +1815,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1815,6 +1825,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1824,6 +1835,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1832,6 +1844,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1840,6 +1853,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1849,6 +1863,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x23,
last_state: 0x23,
},
@ -1858,6 +1873,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1866,6 +1882,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1874,6 +1891,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1883,6 +1901,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x23,
last_state: 0x23,
},
@ -1891,6 +1910,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1900,6 +1920,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1909,6 +1930,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1917,6 +1939,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1925,6 +1948,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1933,6 +1957,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1941,6 +1966,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1949,6 +1975,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1957,6 +1984,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1965,6 +1993,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1973,6 +2002,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1982,6 +2012,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x23,
last_state: 0x23,
},
@ -1991,6 +2022,7 @@ Simulation {
index: StatePartIndex<BigSlots>(68),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -2148,5 +2180,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1079,6 +1079,7 @@ Simulation {
},
pc: 133,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1198,6 +1199,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1719,6 +1721,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1727,6 +1730,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1739,6 +1743,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1748,6 +1753,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x26,
last_state: 0x26,
},
@ -1756,6 +1762,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1768,6 +1775,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1777,6 +1785,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x26,
last_state: 0x26,
},
@ -1785,6 +1794,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1794,6 +1804,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1803,6 +1814,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1811,6 +1823,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1819,6 +1832,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1828,6 +1842,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x26,
last_state: 0x26,
},
@ -1837,6 +1852,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1845,6 +1861,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1853,6 +1870,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1862,6 +1880,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x26,
last_state: 0x26,
},
@ -1870,6 +1889,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1879,6 +1899,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1888,6 +1909,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1896,6 +1918,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1904,6 +1927,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1912,6 +1936,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1920,6 +1945,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1928,6 +1954,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1936,6 +1963,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1944,6 +1972,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1952,6 +1981,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1961,6 +1991,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x26,
last_state: 0x26,
},
@ -1970,6 +2001,7 @@ Simulation {
index: StatePartIndex<BigSlots>(66),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -2127,5 +2159,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1108,6 +1108,7 @@ Simulation {
},
pc: 137,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1229,6 +1230,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1750,6 +1752,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1758,6 +1761,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1770,6 +1774,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1779,6 +1784,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x27,
last_state: 0x27,
},
@ -1787,6 +1793,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1799,6 +1806,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1808,6 +1816,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x26,
last_state: 0x26,
},
@ -1816,6 +1825,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1825,6 +1835,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1834,6 +1845,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1842,6 +1854,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1850,6 +1863,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1859,6 +1873,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x26,
last_state: 0x26,
},
@ -1868,6 +1883,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1876,6 +1892,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1884,6 +1901,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1893,6 +1911,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x27,
last_state: 0x27,
},
@ -1901,6 +1920,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1910,6 +1930,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1919,6 +1940,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1927,6 +1949,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1935,6 +1958,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1943,6 +1967,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1951,6 +1976,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1959,6 +1985,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1967,6 +1994,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1975,6 +2003,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1983,6 +2012,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1992,6 +2022,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x27,
last_state: 0x27,
},
@ -2001,6 +2032,7 @@ Simulation {
index: StatePartIndex<BigSlots>(68),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2158,5 +2190,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1089,6 +1089,7 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1208,6 +1209,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1729,6 +1731,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1737,6 +1740,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1749,6 +1753,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1758,6 +1763,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2a,
last_state: 0x2a,
},
@ -1766,6 +1772,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1778,6 +1785,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1787,6 +1795,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1795,6 +1804,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1804,6 +1814,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1813,6 +1824,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1821,6 +1833,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1829,6 +1842,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1838,6 +1852,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1847,6 +1862,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1855,6 +1871,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1863,6 +1880,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1872,6 +1890,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2a,
last_state: 0x2a,
},
@ -1880,6 +1899,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1889,6 +1909,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1898,6 +1919,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1906,6 +1928,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1914,6 +1937,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1922,6 +1946,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1930,6 +1955,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1938,6 +1964,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1946,6 +1973,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1954,6 +1982,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1962,6 +1991,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1971,6 +2001,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2a,
last_state: 0x2a,
},
@ -1980,6 +2011,7 @@ Simulation {
index: StatePartIndex<BigSlots>(66),
ty: UInt<1>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2137,5 +2169,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1125,6 +1125,7 @@ Simulation {
},
pc: 139,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1248,6 +1249,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1759,6 +1761,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1767,6 +1770,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1779,6 +1783,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1788,6 +1793,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x28,
last_state: 0x28,
},
@ -1796,6 +1802,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1808,6 +1815,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1817,6 +1825,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x27,
last_state: 0x27,
},
@ -1825,6 +1834,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1834,6 +1844,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1843,6 +1854,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1851,6 +1863,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1859,6 +1872,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1868,6 +1882,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x27,
last_state: 0x27,
},
@ -1877,6 +1892,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1885,6 +1901,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1893,6 +1910,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1902,6 +1920,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x28,
last_state: 0x28,
},
@ -1910,6 +1929,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1919,6 +1939,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1928,6 +1949,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1936,6 +1958,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1944,6 +1967,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1952,6 +1976,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1960,6 +1985,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1968,6 +1994,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1976,6 +2003,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1984,6 +2012,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1992,6 +2021,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2001,6 +2031,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x28,
last_state: 0x28,
},
@ -2158,5 +2189,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1106,6 +1106,7 @@ Simulation {
},
pc: 137,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1227,6 +1228,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1738,6 +1740,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1746,6 +1749,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1758,6 +1762,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1767,6 +1772,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2a,
last_state: 0x2a,
},
@ -1775,6 +1781,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1787,6 +1794,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1796,6 +1804,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1804,6 +1813,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1813,6 +1823,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1822,6 +1833,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1830,6 +1842,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1838,6 +1851,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1847,6 +1861,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1856,6 +1871,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1864,6 +1880,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1872,6 +1889,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1881,6 +1899,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2a,
last_state: 0x2a,
},
@ -1889,6 +1908,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1898,6 +1918,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1907,6 +1928,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1915,6 +1937,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1923,6 +1946,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1931,6 +1955,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1939,6 +1964,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1947,6 +1973,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1955,6 +1982,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1963,6 +1991,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1971,6 +2000,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1980,6 +2010,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2a,
last_state: 0x2a,
},
@ -2137,5 +2168,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1135,6 +1135,7 @@ Simulation {
},
pc: 141,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1258,6 +1259,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1769,6 +1771,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1777,6 +1780,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1789,6 +1793,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1798,6 +1803,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -1806,6 +1812,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1818,6 +1825,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1827,6 +1835,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1835,6 +1844,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1844,6 +1854,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x3,
},
@ -1853,6 +1864,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1861,6 +1873,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1869,6 +1882,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1878,6 +1892,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1887,6 +1902,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1895,6 +1911,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1903,6 +1920,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1912,6 +1930,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -1920,6 +1939,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1929,6 +1949,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1938,6 +1959,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1946,6 +1968,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1954,6 +1977,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1962,6 +1986,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1970,6 +1995,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1978,6 +2004,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1986,6 +2013,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1994,6 +2022,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2002,6 +2031,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -2011,6 +2041,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -2168,5 +2199,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1116,6 +1116,7 @@ Simulation {
},
pc: 139,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1237,6 +1238,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1748,6 +1750,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1756,6 +1759,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1768,6 +1772,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1777,6 +1782,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -1785,6 +1791,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1797,6 +1804,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1806,6 +1814,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1814,6 +1823,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1823,6 +1833,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x3,
},
@ -1832,6 +1843,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1840,6 +1852,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1848,6 +1861,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1857,6 +1871,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1866,6 +1881,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1874,6 +1890,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1882,6 +1899,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1891,6 +1909,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -1899,6 +1918,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1908,6 +1928,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1917,6 +1938,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x2,
last_state: 0x2,
},
@ -1925,6 +1947,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1933,6 +1956,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1941,6 +1965,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1949,6 +1974,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1957,6 +1983,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1965,6 +1992,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1973,6 +2001,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1981,6 +2010,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1990,6 +2020,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -2147,5 +2178,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1104,6 +1104,7 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1227,6 +1228,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1748,6 +1750,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1756,6 +1759,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1768,6 +1772,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1777,6 +1782,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -1785,6 +1791,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1797,6 +1804,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1806,6 +1814,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1814,6 +1823,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1823,6 +1833,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<3>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x3,
},
@ -1832,6 +1843,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1840,6 +1852,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1848,6 +1861,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1857,6 +1871,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1866,6 +1881,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1874,6 +1890,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1882,6 +1899,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1891,6 +1909,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -1899,6 +1918,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1908,6 +1928,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1917,6 +1938,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1925,6 +1947,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1933,6 +1956,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1941,6 +1965,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1949,6 +1974,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1957,6 +1983,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1965,6 +1992,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1973,6 +2001,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1981,6 +2010,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1990,6 +2020,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -1999,6 +2030,7 @@ Simulation {
index: StatePartIndex<BigSlots>(68),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x3,
},
@ -2156,5 +2188,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1085,6 +1085,7 @@ Simulation {
},
pc: 133,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1206,6 +1207,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1727,6 +1729,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1735,6 +1738,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1747,6 +1751,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1756,6 +1761,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -1764,6 +1770,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1776,6 +1783,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1785,6 +1793,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1793,6 +1802,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1802,6 +1812,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<3>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x3,
},
@ -1811,6 +1822,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1819,6 +1831,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1827,6 +1840,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1836,6 +1850,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1845,6 +1860,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1853,6 +1869,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1861,6 +1878,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1870,6 +1888,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -1878,6 +1897,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1887,6 +1907,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1896,6 +1917,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1904,6 +1926,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1912,6 +1935,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1920,6 +1944,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1928,6 +1953,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1936,6 +1962,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1944,6 +1971,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1952,6 +1980,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1960,6 +1989,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1969,6 +1999,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2b,
last_state: 0x2b,
},
@ -1978,6 +2009,7 @@ Simulation {
index: StatePartIndex<BigSlots>(66),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x3,
},
@ -2135,5 +2167,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1114,6 +1114,7 @@ Simulation {
},
pc: 137,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1237,6 +1238,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1758,6 +1760,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1766,6 +1769,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1778,6 +1782,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1787,6 +1792,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2c,
last_state: 0x2c,
},
@ -1795,6 +1801,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1807,6 +1814,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1816,6 +1824,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1824,6 +1833,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1833,6 +1843,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<3>,
},
maybe_changed: true,
state: 0x4,
last_state: 0x4,
},
@ -1842,6 +1853,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1850,6 +1862,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1858,6 +1871,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1867,6 +1881,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1876,6 +1891,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1884,6 +1900,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1892,6 +1909,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1901,6 +1919,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2c,
last_state: 0x2c,
},
@ -1909,6 +1928,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1918,6 +1938,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1927,6 +1948,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1935,6 +1957,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1943,6 +1966,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1951,6 +1975,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1959,6 +1984,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1967,6 +1993,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1975,6 +2002,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1983,6 +2011,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1991,6 +2020,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -2000,6 +2030,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2c,
last_state: 0x2c,
},
@ -2009,6 +2040,7 @@ Simulation {
index: StatePartIndex<BigSlots>(68),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2166,5 +2198,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1095,6 +1095,7 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1216,6 +1217,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1737,6 +1739,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1745,6 +1748,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1757,6 +1761,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1766,6 +1771,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2c,
last_state: 0x2c,
},
@ -1774,6 +1780,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1786,6 +1793,7 @@ Simulation {
HdlSome(UInt<8>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1795,6 +1803,7 @@ Simulation {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1803,6 +1812,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1812,6 +1822,7 @@ Simulation {
index: StatePartIndex<BigSlots>(10),
ty: UInt<3>,
},
maybe_changed: true,
state: 0x4,
last_state: 0x4,
},
@ -1821,6 +1832,7 @@ Simulation {
index: StatePartIndex<BigSlots>(11),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1829,6 +1841,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(12),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1837,6 +1850,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(13),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1846,6 +1860,7 @@ Simulation {
index: StatePartIndex<BigSlots>(14),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x29,
last_state: 0x29,
},
@ -1855,6 +1870,7 @@ Simulation {
index: StatePartIndex<BigSlots>(15),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1863,6 +1879,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(16),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1871,6 +1888,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(17),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -1880,6 +1898,7 @@ Simulation {
index: StatePartIndex<BigSlots>(18),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2c,
last_state: 0x2c,
},
@ -1888,6 +1907,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(19),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1897,6 +1917,7 @@ Simulation {
index: StatePartIndex<BigSlots>(22),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1906,6 +1927,7 @@ Simulation {
index: StatePartIndex<BigSlots>(25),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1914,6 +1936,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(27),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1922,6 +1945,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(30),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1930,6 +1954,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1938,6 +1963,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1946,6 +1972,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1954,6 +1981,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1962,6 +1990,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1970,6 +1999,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(39),
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
@ -1979,6 +2009,7 @@ Simulation {
index: StatePartIndex<BigSlots>(42),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x2c,
last_state: 0x2c,
},
@ -1988,6 +2019,7 @@ Simulation {
index: StatePartIndex<BigSlots>(66),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -2145,5 +2177,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -636,6 +636,7 @@ Simulation {
},
pc: 69,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -687,18 +688,7 @@ Simulation {
1,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
1,
0,
0,
0,
0 (modified),
0,
0,
0,
@ -709,9 +699,20 @@ Simulation {
1,
0,
0,
0 (modified),
0,
0,
0,
1,
0,
0,
0,
1,
0,
0,
0 (modified),
0,
0,
],
},
sim_only_slots: StatePart {
@ -725,6 +726,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1284,6 +1286,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: false,
state: 0x1,
last_state: 0x1,
},
@ -1293,6 +1296,7 @@ Simulation {
index: StatePartIndex<BigSlots>(1),
ty: UInt<6>,
},
maybe_changed: false,
state: 0x00,
last_state: 0x00,
},
@ -1301,6 +1305,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(2),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1309,6 +1314,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1317,6 +1323,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(4),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1325,6 +1332,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(5),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1333,6 +1341,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(6),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1341,6 +1350,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1349,6 +1359,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(24),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1357,6 +1368,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(33),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1365,6 +1377,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(34),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1373,6 +1386,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(31),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1381,6 +1395,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(32),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1389,6 +1404,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(36),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1397,6 +1413,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(44),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1405,6 +1422,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(45),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1413,6 +1431,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(42),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1421,6 +1440,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(43),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1429,6 +1449,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(47),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1437,6 +1458,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(55),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -1445,6 +1467,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(56),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1453,6 +1476,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(53),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1461,6 +1485,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(54),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -1767,5 +1792,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -254,6 +254,7 @@ Simulation {
},
pc: 34,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -293,6 +294,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -458,6 +460,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
@ -466,6 +469,7 @@ Simulation {
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -474,6 +478,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(2),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -482,6 +487,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -490,6 +496,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(4),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -498,6 +505,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -506,6 +514,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(9),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -514,6 +523,7 @@ Simulation {
kind: BigBool {
index: StatePartIndex<BigSlots>(11),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -537,5 +547,6 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -60,6 +60,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -68,12 +69,12 @@ Simulation {
},
big_slots: StatePart {
value: [
0 (modified),
0,
0,
0,
49,
50,
50,
49 (modified),
50 (modified),
50 (modified),
],
},
sim_only_slots: StatePart {
@ -87,6 +88,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -356,6 +358,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -364,6 +367,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -372,6 +376,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(2),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -381,6 +386,7 @@ Simulation {
index: StatePartIndex<BigSlots>(3),
ty: UInt<8>,
},
maybe_changed: false,
state: 0x31,
last_state: 0x31,
},
@ -390,6 +396,7 @@ Simulation {
index: StatePartIndex<BigSlots>(4),
ty: UInt<8>,
},
maybe_changed: false,
state: 0x32,
last_state: 0x32,
},
@ -399,6 +406,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: false,
state: 0x32,
last_state: 0x32,
},
@ -515,5 +523,6 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -60,6 +60,7 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -68,12 +69,12 @@ Simulation {
},
big_slots: StatePart {
value: [
0 (modified),
0,
0,
0,
49,
50,
50,
49 (modified),
50 (modified),
50 (modified),
],
},
sim_only_slots: StatePart {
@ -87,6 +88,7 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -356,6 +358,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(0),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
@ -364,6 +367,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: false,
state: 0x0,
last_state: 0x0,
},
@ -372,6 +376,7 @@ Simulation {
kind: BigClock {
index: StatePartIndex<BigSlots>(2),
},
maybe_changed: true,
state: 0x0,
last_state: 0x1,
},
@ -381,6 +386,7 @@ Simulation {
index: StatePartIndex<BigSlots>(3),
ty: UInt<8>,
},
maybe_changed: false,
state: 0x31,
last_state: 0x31,
},
@ -390,6 +396,7 @@ Simulation {
index: StatePartIndex<BigSlots>(4),
ty: UInt<8>,
},
maybe_changed: false,
state: 0x32,
last_state: 0x32,
},
@ -399,6 +406,7 @@ Simulation {
index: StatePartIndex<BigSlots>(5),
ty: UInt<8>,
},
maybe_changed: false,
state: 0x32,
last_state: 0x32,
},
@ -515,5 +523,6 @@ Simulation {
},
),
},
asserts: [],
..
}

Some files were not shown because too many files have changed in this diff Show more