Compare commits

..

1 commit

Author SHA1 Message Date
Tobias Alexandra Platen
e0623c9b0f copy vendor/xilinx to vendor/lattice 2026-05-24 21:01:35 +02:00
106 changed files with 4753 additions and 13929 deletions

30
Makefile Normal file
View file

@ -0,0 +1,30 @@
DIRU=/home/alex/Hacking/FPGA/libre-chip/fayalite/target/blinky-out
NEXTPNR_DENSITY:=--85k
# --nextpnr /home/alex/.guix-profile/bin/nextpnr-ecp5 \
# --ecppack /home/alex/.guix-profile/bin/ecppack \
# --yosys /home/alex/.guix-profile/bin/yosys
# firtool executed with qemu
#FIXME --placeholder-dir
all:
#cp $(DIRU)/*.pcf /tmp
RUST_BACKTRACE=full cargo run --example blinky yosys-nextpnr-ecp5 \
--platform orangecrab-85k -o target/blinky-out \
--placeholder-dir /home/alex/Hacking/FPGA/orangecrab/orangecrab-examples/fayalite/orangecrab_r0.2.1.pcf \
--nextpnr /usr/bin/nextpnr-ecp5
#ls -1 $(DIRU)/*.bit
ls:
ls -1 $(DIRU)
clean:
rm $(DIRU)/*
nextpnr:
cd $(DIRU) && nextpnr-ecp5 --json blinky.json --textcfg blinky.nextpnr.out $(NEXTPNR_DENSITY) \
--package CSFBGA285 --lpf /home/alex/Hacking/FPGA/orangecrab/orangecrab-examples/fayalite/orangecrab_r0.2.1.pcf --lpf-allow-unconstrained
pack:
cd $(DIRU) && ecppack --compress --freq 38.8 --input blinky.nextpnr.out --bit blinky.nextpnr.bit
cd $(DIRU) && file *.bit
clean2:
find . -name "*.bit" -exec rm {} \;
ls2:
find . -name "*.bit"

View file

@ -1133,7 +1133,6 @@ 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();
@ -1142,9 +1141,6 @@ 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,
@ -1192,7 +1188,6 @@ 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
@ -1212,9 +1207,6 @@ 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)&*
@ -1238,17 +1230,12 @@ impl ToTokens for ParsedBundle {
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,
@ -1274,16 +1261,6 @@ 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
}
@ -1292,14 +1269,6 @@ 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

@ -643,9 +643,7 @@ 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()),
@ -931,14 +929,8 @@ impl ToTokens for ParsedEnum {
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,
)
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);
@ -954,7 +946,6 @@ impl ToTokens for ParsedEnum {
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 {
@ -980,23 +971,8 @@ impl ToTokens for ParsedEnum {
.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, _),
) => {
(#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),
@ -1026,10 +1002,7 @@ impl ToTokens for ParsedEnum {
else {
::fayalite::__std::unreachable!();
};
::fayalite::module::connect(
__retval,
::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs),
);
::fayalite::module::connect(__retval, ::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(__lhs, __rhs));
}
});
fields_valueless_eq.push(quote_spanned! {span=>
@ -1070,10 +1043,7 @@ impl ToTokens for ParsedEnum {
}
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),
) => {
(#sim_value_ident::#sim_value_unknown_variant_name(__lhs_unknown), #sim_value_ident::#sim_value_unknown_variant_name(__rhs_unknown)) => {
__lhs_unknown == __rhs_unknown
}
});
@ -1090,26 +1060,17 @@ impl ToTokens for ParsedEnum {
}
};
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>,
__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>,
__rhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
) -> ::fayalite::__std::primitive::bool {
match (&*__lhs_value, &*__rhs_value) {
#(#variants_value_eq)*
@ -1122,20 +1083,7 @@ impl ToTokens for ParsedEnum {
__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,
);
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)*
@ -1164,8 +1112,7 @@ 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(
@ -1178,9 +1125,7 @@ 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)]
@ -1189,11 +1134,7 @@ 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)*
}
@ -1239,10 +1180,7 @@ 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() {
@ -1262,10 +1200,7 @@ impl ToTokens for ParsedEnum {
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 {
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)
}
}
@ -1278,10 +1213,7 @@ 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

@ -238,10 +238,7 @@ impl TargetedAnnotation {
}
#[track_caller]
pub fn assert_valid_target(target: Interned<Target>) {
assert!(
target.is_valid_annotation_target(),
"not a valid annotation target: {target:?}",
);
assert!(target.is_static(), "can't annotate non-static targets");
}
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, StructuralEq},
ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator},
},
int::{Bool, DYN_SIZE, DynSize, KnownSize, Size, SizeType},
intern::{Intern, Interned, LazyInterned},
@ -367,8 +367,6 @@ 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>,
@ -389,11 +387,6 @@ 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))
@ -403,11 +396,6 @@ 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, NodeIndex},
graph::DiGraph,
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::<NodeIndex>::from_iter(cycle.iter().copied());
let cycle_set = HashSet::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::<NodeIndex, RunningJob>::default();
let mut running_jobs = HashMap::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=named"]);
args.write_args(["-g", "--preserve-values=all"]);
}
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, StructuralEq},
ops::{ArrayLiteral, BundleLiteral},
value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue},
},
int::{Bool, DynSize},
@ -708,8 +708,6 @@ 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,
@ -727,11 +725,6 @@ 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(
@ -744,11 +737,6 @@ 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(

View file

@ -6,7 +6,6 @@ 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},
@ -221,7 +220,6 @@ expr_enum! {
CastBitsTo(ops::CastBitsTo),
ToTraceAsString(ops::ToTraceAsString),
TraceAsStringAsInner(ops::TraceAsStringAsInner),
StructuralEq(ops::StructuralEq),
ModuleIO(ModuleIO<CanonicalType>),
Instance(Instance<Bundle>),
Wire(Wire<CanonicalType>),
@ -229,8 +227,6 @@ expr_enum! {
RegSync(Reg<CanonicalType, SyncReset>),
RegAsync(Reg<CanonicalType, AsyncReset>),
MemPort(MemPort<DynPortType>),
FormalInput(FormalInput),
SimIoForGlobal(ops::SimIoForGlobal),
}
}
@ -702,7 +698,6 @@ 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>)?
@ -731,8 +726,6 @@ 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,
@ -916,7 +909,6 @@ 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> >
@ -1916,19 +1908,3 @@ impl<T: ?Sized + ValueType> ToTraceAsStringImpl<T::Type, value_category::ValueCa
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

@ -17,12 +17,11 @@ use crate::{
},
value_category::ValueCategoryExpr,
},
formal::FormalInput,
int::{
Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt,
UIntType, UIntValue,
},
intern::{Intern, Interned, MemoizeGeneric},
intern::{Intern, Interned},
phantom_const::{PhantomConst, PhantomConstValue},
reset::{
AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset,
@ -2984,7 +2983,6 @@ 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;
@ -3046,7 +3044,6 @@ 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>,
@ -3067,7 +3064,6 @@ 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();
@ -3091,7 +3087,6 @@ 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();
@ -3116,7 +3111,6 @@ 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();
@ -3138,8 +3132,6 @@ 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,
@ -4889,336 +4881,3 @@ impl<T: Type> ToExpr for TraceAsStringAsInner<T> {
}
}
}
#[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,7 +4,6 @@ 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},
@ -63,7 +62,7 @@ pub struct TargetPathToTraceAsString {
impl fmt::Display for TargetPathToTraceAsString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, ".to_trace_as_string()")
write!(f, ".to_trace_as_string(...)")
}
}
@ -296,14 +295,6 @@ 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),
}
}
@ -352,8 +343,6 @@ 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 {
@ -365,21 +354,6 @@ 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,
}
}
}
@ -574,16 +548,6 @@ 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()
@ -700,18 +664,6 @@ 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,189 +1,11 @@
// 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},
module::{NameId, NameIdOrGlobal, ScopedNameId},
intern::{Intern, Interned, Memoize},
prelude::*,
};
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())
}
}
use std::sync::OnceLock;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum FormalKind {
@ -316,76 +138,110 @@ make_formal!(
hdl_cover
);
pub trait MakeFormalExpr: Type {}
impl<T: Type> MakeFormalExpr for T {}
#[hdl]
pub fn formal_global_clock() -> Expr<Clock> {
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_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
}
#[hdl]
pub fn formal_reset() -> Expr<SyncReset> {
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(),
)
})
#[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
}
macro_rules! make_any_const_fn {
($ident:ident, $ident_with_loc:ident, $verilog_attribute:literal, $kind:ident) => {
#[track_caller]
($ident:ident, $verilog_attribute:literal) => {
#[hdl]
pub fn $ident<T: BoolOrIntType>(ty: T) -> Expr<T> {
$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(),
)
#[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
}
};
}
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);
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");

View file

@ -177,8 +177,6 @@ impl CastToImpl<UIntInRangeMaskType> for Bool {
}
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
const TRY_STRUCTURAL_EQ: bool = true;
#[track_caller]
fn cmp_value_eq(
_lhs: Self,
@ -572,8 +570,6 @@ 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>,
@ -661,8 +657,6 @@ 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>,
@ -682,8 +676,6 @@ 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,62 +682,27 @@ 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> {
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(),
}
}
slice: Interned<[T]>,
index: std::ops::Range<usize>,
}
impl<T: Clone + 'static + Send + Sync> Iterator for InternedSliceIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
self.index.next().map(|index| self.slice[index].clone())
}
fn size_hint(&self) -> (usize, Option<usize>) {
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)
self.index.size_hint()
}
}
impl<T: Clone + 'static + Send + Sync> DoubleEndedIterator for InternedSliceIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
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)
self.index
.next_back()
.map(|index| self.slice[index].clone())
}
}
@ -751,7 +716,8 @@ impl<T: Clone + 'static + Send + Sync> IntoIterator for Interned<[T]> {
fn into_iter(self) -> Self::IntoIter {
InternedSliceIter {
iter: Interned::into_inner(self).iter().cloned(),
index: 0..self.len(),
slice: self,
}
}
}

View file

@ -8,7 +8,7 @@ use crate::{
clock::{Clock, ClockDomain},
enum_::{Enum, EnumMatchVariantsIter, EnumType},
expr::{
Expr, ExprEnum, Flow, ToExpr, ValueType,
Expr, Flow, ToExpr, ValueType,
ops::VariantAccess,
target::{
GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField,
@ -20,7 +20,6 @@ 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},
@ -727,57 +726,7 @@ impl fmt::Display for NameId {
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
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);
pub struct ScopedNameId(pub NameId, pub NameId);
impl fmt::Debug for ScopedNameId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -855,7 +804,7 @@ impl<T: BundleType> Instance<T> {
self.containing_module_name_id().0
}
pub fn containing_module_name_id(self) -> NameId {
self.scoped_name.0.unwrap_name_id()
self.scoped_name.0
}
pub fn name(self) -> Interned<str> {
self.name_id().0
@ -872,13 +821,11 @@ 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,
@ -1651,63 +1598,12 @@ impl TargetState {
}
}
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();
@ -1718,7 +1614,7 @@ impl AssertValidityState {
&'a self,
target: Target,
process_target_state: &dyn Fn(&'a TargetState, bool),
) -> Result<(), GetTargetStatesError> {
) -> Result<(), ()> {
let mut target = target.unwrap_transparent_types();
loop {
break match target {
@ -1771,24 +1667,8 @@ impl AssertValidityState {
};
}
}
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)),
}
fn get_base_state(&self, target_base: Interned<TargetBase>) -> Result<&TargetState, ()> {
self.target_states.get(&target_base).ok_or(())
}
#[track_caller]
fn insert_new_base(&mut self, target_base: Interned<TargetBase>, declared_in_block: usize) {
@ -1881,30 +1761,16 @@ impl AssertValidityState {
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);
});
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)) => {
if result.is_err() {
if is_lhs {
panic!("at {source_location}: tried to connect to not-yet-defined item: {target}");
} else {
panic!(
"at {source_location}: fayalite::expr::ops::SimIoForGlobal is not allowed in Modules: {v:?}"
)
"at {source_location}: tried to connect from not-yet-defined item: {target}"
);
}
}
}
#[track_caller]
fn process_conditional_sub_blocks(
&mut self,
parent_block: usize,
@ -1918,40 +1784,17 @@ 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 {
@ -1965,104 +1808,44 @@ 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 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));
let sub_blocks = if_stmt.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(
sub_blocks
match_stmt
.blocks
.into_iter()
.map(|block| self.make_block_index(block)),
);
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();
self.process_conditional_sub_blocks(block, sub_blocks.iter().copied())
}
Stmt::Declaration(StmtDeclaration::Wire(StmtWire {
annotations: _,
wire,
})) => {
self.insert_new_base(TargetBase::intern_sized(wire.into()), block);
self.visible_exprs.top().insert(wire.into());
}
})) => self.insert_new_base(TargetBase::intern_sized(wire.into()), block),
Stmt::Declaration(StmtDeclaration::Reg(StmtReg {
annotations: _,
reg,
})) => {
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());
}
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
Stmt::Declaration(StmtDeclaration::RegSync(StmtReg {
annotations: _,
reg,
})) => {
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());
}
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
Stmt::Declaration(StmtDeclaration::RegAsync(StmtReg {
annotations: _,
reg,
})) => {
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());
}
})) => self.insert_new_base(TargetBase::intern_sized(reg.into()), block),
Stmt::Declaration(StmtDeclaration::Instance(StmtInstance {
annotations: _,
instance,
})) => {
self.insert_new_base(TargetBase::intern_sized(instance.into()), block);
self.visible_exprs.top().insert(instance.into());
}
})) => self.insert_new_base(TargetBase::intern_sized(instance.into()), block),
}
}
self.visible_exprs.pop();
}
#[track_caller]
fn assert_validity(&mut self) {
@ -2091,143 +1874,6 @@ 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]
@ -2248,7 +1894,7 @@ impl<T: BundleType> Module<T> {
clocks_for_past,
simulation: Some(simulation),
}) => {
let mut clocks_for_past_set = HashSet::<Target>::default();
let mut clocks_for_past_set = HashSet::default();
*clocks_for_past = clocks_for_past
.iter()
.copied()
@ -2269,9 +1915,7 @@ 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::<ModuleIO<CanonicalType>>::from_iter(
module_io.iter().map(|v| v.module_io),
);
let module_io_set = HashSet::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!(
@ -2355,7 +1999,6 @@ 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();
@ -2461,7 +2104,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.into(), NameId(name, Id::new()));
let scoped_name = ScopedNameId(module_builder.name, 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()
@ -2857,9 +2500,6 @@ 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())
@ -2874,7 +2514,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.into(), NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name, 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();
@ -2906,7 +2546,7 @@ fn incomplete_declaration(
source_location: SourceLocation,
) -> Rc<RefCell<IncompleteDeclaration>> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new()));
let retval = Rc::new(RefCell::new(IncompleteDeclaration::Incomplete {
name: scoped_name,
source_location,
@ -3082,7 +2722,7 @@ pub fn instance_with_loc<T: BundleType>(
source_location: SourceLocation,
) -> Expr<T> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name, NameId(name.intern(), Id::new()));
let instance = Instance::<T> {
scoped_name,
instantiated,
@ -3121,7 +2761,7 @@ fn memory_impl<Element: Type, Len: Size>(
source_location: SourceLocation,
) -> MemBuilder<Element, Len> {
ModuleBuilder::with(|m| {
let scoped_name = ScopedNameId(m.name.into(), NameId(name.intern(), Id::new()));
let scoped_name = ScopedNameId(m.name, 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();
@ -3276,7 +2916,7 @@ impl<T: Type> ModuleIO<T> {
NameId(self.bundle_field.name, self.id)
}
pub fn scoped_name(&self) -> ScopedNameId {
ScopedNameId(self.containing_module_name.into(), self.name_id())
ScopedNameId(self.containing_module_name, self.name_id())
}
pub fn source_location(&self) -> SourceLocation {
self.source_location
@ -3349,102 +2989,10 @@ 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 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
}
pub struct TargetInInstantiatedModule {
pub instantiated_module: InstantiatedModule,
pub target: Target,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]

View file

@ -1,7 +1,6 @@
// 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

@ -1208,7 +1208,6 @@ impl<P: Pass> RunPass<P> for ExprEnum {
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)),
@ -1216,10 +1215,6 @@ 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")
}
}
}
}
@ -1654,35 +1649,6 @@ impl RunPassExpr for ops::ToTraceAsString {
}
}
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];
@ -1966,7 +1932,6 @@ 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 {
@ -2283,12 +2248,6 @@ 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),

View file

@ -1,26 +1,28 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
bundle::{BundleField, BundleType},
enum_::{EnumType, EnumVariant},
array::{Array, ArrayType},
bundle::{Bundle, BundleField, BundleType},
enum_::{Enum, EnumType, EnumVariant},
expr::{
ExprEnum,
ops::{self, EnumLiteral, StructuralEq, StructuralEqFlags},
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ValueType,
ops::{self, EnumLiteral},
},
hdl,
int::UInt,
intern::{Intern, InternSlice, Interned, Memoize},
memory::{DynPortType, MemPort},
memory::{DynPortType, Mem, MemPort},
module::{
Block, Id, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
transform::{
deduce_structural_eq_flags::deduce_structural_eq_flags,
visit::{Fold, Folder},
},
Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
transform::visit::{Fold, Folder},
},
prelude::*,
source_location::SourceLocation,
ty::{CanonicalType, TraceAsString, Type},
util::HashMap,
wire::Wire,
};
use core::fmt;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug)]
pub enum SimplifyEnumsError {
@ -94,13 +96,11 @@ 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.into(), NameId(name.intern(), Id::new()))
ScopedNameId(self.module_name, NameId(name.intern(), Id::new()))
}
}
@ -109,45 +109,6 @@ 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 {
@ -587,185 +548,6 @@ 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(
@ -893,8 +675,6 @@ 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();
@ -902,51 +682,30 @@ impl Folder for State {
}
fn fold_expr_enum(&mut self, op: ExprEnum) -> Result<ExprEnum, Self::Error> {
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 {
match op {
ExprEnum::EnumLiteral(op) => {
let folded_variant_value = op.variant_value().map(|v| v.fold(self)).transpose()?;
*Expr::expr_enum(self.handle_enum_literal(
Ok(*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)?;
*Expr::expr_enum(self.handle_variant_access(
Ok(*Expr::expr_enum(self.handle_variant_access(
op.base().ty(),
folded_base_expr,
op.variant_index(),
)?)
)?))
}
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) => {
ExprEnum::MemPort(mem_port) => Ok(
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(_)
@ -1054,26 +813,16 @@ impl Folder for State {
| ExprEnum::Wire(_)
| ExprEnum::Reg(_)
| ExprEnum::RegSync(_)
| 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)
| ExprEnum::RegAsync(_) => op.default_fold(self),
}
}
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(this)?;
let new_element_ty = memory.array_type().element().fold(self)?;
if new_element_ty != old_element_ty {
let mut new_ports = vec![];
for port in memory.ports() {
@ -1099,7 +848,7 @@ impl Folder for State {
continue;
}
let wire = Wire::new_unchecked(
this.module_state_stack
self.module_state_stack
.last_mut()
.unwrap()
.gen_name(&format!(
@ -1123,7 +872,7 @@ impl Folder for State {
Expr::canonical(wire.to_expr()),
port.source_location(),
);
this.replacement_mem_ports.insert(port, wire.canonical());
self.replacement_mem_ports.insert(port, wire.canonical());
}
memories.push(Mem::new_unchecked(
memory.scoped_name(),
@ -1138,12 +887,10 @@ impl Folder for State {
memory.mem_annotations(),
));
} else {
memories.push(memory.fold(this)?);
memories.push(memory.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);
stmts.extend_from_slice(&block.stmts.fold(self)?);
Ok(Block {
memories: Intern::intern_owned(memories),
stmts: Intern::intern_owned(stmts),
@ -1265,13 +1012,10 @@ 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

@ -18,13 +18,13 @@ use crate::{
TargetPathTraceAsStringInner,
},
},
formal::{FormalInput, FormalInputKind, FormalKind},
formal::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, NameIdOrGlobal,
ExternModuleParameterValue, Instance, Module, ModuleBody, ModuleIO, NameId,
NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf,
StmtInstance, StmtMatch, StmtReg, StmtWire,
},
@ -482,30 +482,4 @@ 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

@ -384,8 +384,6 @@ 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

@ -16,8 +16,8 @@ pub use crate::{
ReduceBits, ToExpr, ToTraceAsString, ValueType, repeat,
},
formal::{
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,
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,
hdl_cover_with_enable,
},
hdl, hdl_module,
@ -37,7 +37,7 @@ pub use crate::{
value::{SimOnly, SimOnlyValue, SimValue, ToSimValue, ToSimValueWithType},
},
source_location::SourceLocation,
testing::{FormalMode, assert_formal, checked_vcd_output},
testing::{FormalMode, assert_formal},
ty::{AsMask, CanonicalType, TraceAsString, Type},
util::{ConstUsize, GenericConstUsize},
wire::Wire,

View file

@ -79,7 +79,6 @@ 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,
@ -95,7 +94,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.unwrap_name_id()
self.name.0
}
pub fn name(&self) -> Interned<str> {
self.name_id().0

View file

@ -6,29 +6,26 @@
use crate::{
bundle::{BundleField, BundleType},
expr::{
ExprEnum, Flow,
ops::SimIoForGlobal,
Flow,
target::{
GetTarget, Target, TargetBase, TargetChild, TargetPathArrayElement,
TargetPathBundleField, TargetPathElement, TargetPathTraceAsStringInner,
GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
TargetPathTraceAsStringInner,
},
},
formal::FormalInput,
int::BoolOrIntType,
intern::{
Intern, InternSlice, Interned, InternedCompare, InternedSliceIter, Memoize,
PtrEqWithTypeId, SupportsPtrEqWithTypeId,
Intern, InternSlice, Interned, InternedCompare, PtrEqWithTypeId, SupportsPtrEqWithTypeId,
},
module::{
ModuleIO, StmtFormal,
ModuleIO,
transform::visit::{Fold, Folder, Visit, Visitor},
},
prelude::*,
reset::ResetType,
sim::{
compiler::{
Compiled, CompiledAssert, CompiledBundleField, CompiledExternModule,
CompiledTypeLayoutBody, CompiledValue, ExternModuleClockForPast,
Compiled, CompiledBundleField, CompiledExternModule, CompiledTypeLayoutBody,
CompiledValue, ExternModuleClockForPast,
},
interpreter::{
BreakAction, BreakpointsSet, RunResult, SmallUInt, State,
@ -53,7 +50,7 @@ use std::{
any::Any,
cell::{Cell, RefCell},
collections::{BTreeMap, BTreeSet},
fmt::{self, Write},
fmt,
future::{Future, IntoFuture},
hash::Hash,
mem,
@ -318,14 +315,6 @@ impl_trace_decl! {
ty: CanonicalType,
flow: Flow,
}),
FormalInput(TraceFormalInput {
fn children(self) -> _ {
[*self.child].intern_slice()
}
name: Interned<str>,
child: Interned<TraceDecl>,
formal_input: FormalInput,
}),
Bundle(TraceBundle {
fn children(self) -> _ {
self.fields
@ -1299,14 +1288,9 @@ impl SimulationModuleState {
#[track_caller]
fn get_io(
&self,
target: &mut Interned<Target>,
which_module: WhichModule<'_>,
mut target: Target,
which_module: WhichModule,
) -> CompiledValue<CanonicalType> {
match which_module {
WhichModule::Main { global_io } => *target = global_io.to_sim_io_target(*target),
WhichModule::Extern { .. } => {}
}
let mut target = **target;
assert!(
target.canonical_ty().is_passive(),
"simulator read/write expression must have a passive type \
@ -1333,9 +1317,9 @@ impl SimulationModuleState {
};
}
match which_module {
WhichModule::Main { .. } => panic!(
WhichModule::Main => panic!(
"simulator read/write expression must be \
an array element/field of `Simulation::io()` or `Simulation::global_io()`"
an array element/field of `Simulation::io()`"
),
WhichModule::Extern { .. } => panic!(
"simulator read/write expression must be \
@ -1345,18 +1329,18 @@ impl SimulationModuleState {
}
}
#[track_caller]
fn is_reset_async(&self, io: Expr<CanonicalType>, which_module: WhichModule<'_>) -> bool {
let Some(mut target) = io.target() else {
fn is_reset_async(&self, io: Expr<CanonicalType>, which_module: WhichModule) -> bool {
let Some(target) = io.target() else {
match which_module {
WhichModule::Main { .. } => panic!(
"can't read from an expression that's not a field/element of `Simulation::io()` or `Simulation::global_io()`"
WhichModule::Main => panic!(
"can't read from an expression that's not a field/element of `Simulation::io()`"
),
WhichModule::Extern { .. } => panic!(
"can't read from an expression that's not based on one of this module's inputs/outputs"
),
}
};
match self.get_io(&mut target, which_module).layout.ty {
match self.get_io(*target, which_module).layout.ty {
CanonicalType::UInt(_)
| CanonicalType::SInt(_)
| CanonicalType::Bool(_)
@ -1376,24 +1360,24 @@ impl SimulationModuleState {
fn read_helper_current(
&self,
io: Expr<CanonicalType>,
which_module: WhichModule<'_>,
which_module: WhichModule,
) -> MaybeNeedsSettle<CompiledValue<CanonicalType>> {
let Some(mut target) = io.target() else {
let Some(target) = io.target() else {
match which_module {
WhichModule::Main { .. } => panic!(
"can't read from an expression that's not a field/element of `Simulation::io()` or `Simulation::global_io()`"
WhichModule::Main => panic!(
"can't read from an expression that's not a field/element of `Simulation::io()`"
),
WhichModule::Extern { .. } => panic!(
"can't read from an expression that's not based on one of this module's inputs/outputs"
),
}
};
let compiled_value = self.get_io(&mut target, which_module);
let compiled_value = self.get_io(*target, which_module);
match target.flow() {
Flow::Source => {
if !self.uninitialized_ios.is_empty() {
match which_module {
WhichModule::Main { .. } => {
WhichModule::Main => {
panic!(
"can't read from an output before initializing all inputs\nuninitialized_ios={:#?}",
SortedSetDebug(&self.uninitialized_ios),
@ -1412,9 +1396,7 @@ impl SimulationModuleState {
Flow::Sink => {
if self.uninitialized_ios.contains_key(&*target) {
match which_module {
WhichModule::Main { .. } => {
panic!("can't read from an uninitialized input")
}
WhichModule::Main => panic!("can't read from an uninitialized input"),
WhichModule::Extern { .. } => {
panic!("can't read from an uninitialized output");
}
@ -1430,7 +1412,7 @@ impl SimulationModuleState {
&self,
io: Expr<CanonicalType>,
read_time: ReadTime,
which_module: WhichModule<'_>,
which_module: WhichModule,
) -> MaybeNeedsSettle<CompiledValue<CanonicalType>> {
match read_time {
ReadTime::Current => self.read_helper_current(io, which_module),
@ -1456,22 +1438,22 @@ impl SimulationModuleState {
fn write_helper(
&mut self,
io: Expr<CanonicalType>,
which_module: WhichModule<'_>,
which_module: WhichModule,
) -> CompiledValue<CanonicalType> {
let Some(mut target) = io.target() else {
let Some(target) = io.target() else {
match which_module {
WhichModule::Main { .. } => panic!(
"can't write to an expression that's not a field/element of `Simulation::io()` or `Simulation::global_io()`"
WhichModule::Main => panic!(
"can't write to an expression that's not a field/element of `Simulation::io()`"
),
WhichModule::Extern { .. } => panic!(
"can't write to an expression that's not based on one of this module's outputs"
),
}
};
let compiled_value = self.get_io(&mut target, which_module);
let compiled_value = self.get_io(*target, which_module);
match target.flow() {
Flow::Source => match which_module {
WhichModule::Main { .. } => panic!("can't write to an output"),
WhichModule::Main => panic!("can't write to an output"),
WhichModule::Extern { .. } => panic!("can't write to an input"),
},
Flow::Sink => {}
@ -1591,9 +1573,9 @@ impl fmt::Debug for SimulationExternModuleState {
}
}
#[derive(Copy, Clone)]
enum WhichModule<'a> {
Main { global_io: &'a SimulationGlobalIo },
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
enum WhichModule {
Main,
Extern { module_index: usize },
}
@ -2004,7 +1986,6 @@ impl SensitivitySet {
struct SimulationImpl {
state: interpreter::State,
io: Expr<Bundle>,
global_io: SimulationGlobalIo,
main_module: SimulationModuleState,
extern_modules: Box<[SimulationExternModuleState]>,
trace_decls: TraceModule,
@ -2024,7 +2005,6 @@ struct SimulationImpl {
>,
waiting_sensitivity_sets_by_address: HashMap<*const SensitivitySet, Rc<SensitivitySet>>,
trace_as_string_buf: String,
asserts: Interned<[CompiledAssert]>,
}
impl fmt::Debug for SimulationImpl {
@ -2102,7 +2082,6 @@ impl SimulationImpl {
let Self {
state,
io: self_io,
global_io,
main_module,
extern_modules,
trace_decls,
@ -2116,15 +2095,10 @@ impl SimulationImpl {
waiting_sensitivity_sets_by_compiled_value,
waiting_sensitivity_sets_by_address,
trace_as_string_buf: _,
asserts,
} = self;
f.debug_struct("Simulation")
.field("state", state)
.field("io", io.unwrap_or(self_io))
.field(
"global_io",
&fmt::from_fn(|f| f.debug_map().entries(global_io.global_io).finish()),
)
.field("main_module", main_module)
.field("extern_modules", extern_modules)
.field("trace_decls", trace_decls)
@ -2144,7 +2118,6 @@ impl SimulationImpl {
"waiting_sensitivity_sets_by_compiled_value",
&DebugSensitivitySetsByCompiledValue(waiting_sensitivity_sets_by_compiled_value),
)
.field("asserts", asserts)
.finish_non_exhaustive()
}
fn new(compiled: Compiled<Bundle>) -> Self {
@ -2187,29 +2160,22 @@ impl SimulationImpl {
Self {
state: State::new(compiled.insns),
io: compiled.io.to_expr(),
global_io: SimulationGlobalIo::new(compiled.global_io),
main_module: SimulationModuleState::new(
compiled
.global_io
.iter()
.map(|&(global_io, value)| (global_io.into(), value))
.chain(
compiled
.io
.ty()
.fields()
.into_iter()
.zip(compiled.base_module.module_io)
.map(|(BundleField { name, .. }, value)| {
(
io_target.join(
TargetPathElement::from(TargetPathBundleField { name })
.intern_sized(),
),
value,
)
}),
),
.io
.ty()
.fields()
.into_iter()
.zip(compiled.base_module.module_io)
.map(|(BundleField { name, .. }, value)| {
(
io_target.join(
TargetPathElement::from(TargetPathBundleField { name })
.intern_sized(),
),
value,
)
}),
&[],
),
extern_modules,
@ -2236,7 +2202,6 @@ impl SimulationImpl {
waiting_sensitivity_sets_by_compiled_value: HashMap::default(),
waiting_sensitivity_sets_by_address: HashMap::default(),
trace_as_string_buf: String::with_capacity(256),
asserts: compiled.asserts,
}
}
fn write_traces<const ONLY_IF_CHANGED: bool>(
@ -2764,50 +2729,6 @@ impl SimulationImpl {
self.cancel_wake_after_change(&sensitivity_set);
}
}
#[track_caller]
#[cold]
fn handle_failed_asserts(&mut self, assert_failed_log: Vec<usize>) -> ! {
let mut message = format!(
"Assertions/Assumptions failed at time {:?}:\n",
self.event_queue.lock().instant,
);
for assert_failed_index in assert_failed_log {
let CompiledAssert {
instantiated_module,
stmt_formal:
StmtFormal {
kind,
clk: _,
pred: _,
en: _,
text,
source_location,
},
} = self.asserts[assert_failed_index];
writeln!(
message,
"at {source_location}: in {instantiated_module:?}: {} failed: {text}",
kind.as_str()
)
.unwrap();
}
panic!("{message}")
}
#[track_caller]
fn check_for_failed_asserts(&mut self) {
if self.state.assert_failed_log.is_empty() {
return;
}
if let Some(Event {
instant: _,
kind: EventKind::State,
}) = self.event_queue.peek_first_event_for_now()
{
return;
}
let assert_failed_log = mem::take(&mut self.state.assert_failed_log);
self.handle_failed_asserts(assert_failed_log);
}
fn write_traces_after_event(&mut self) {
if let Some(Event {
instant: _,
@ -2910,7 +2831,6 @@ impl SimulationImpl {
}
}
this.write_traces_after_event();
this.check_for_failed_asserts();
this.check_waiting_sensitivity_sets();
} else {
event_queue = first_entry.into_event_queue_lock();
@ -2932,23 +2852,18 @@ impl SimulationImpl {
fn settle(this_ref: &Rc<RefCell<Self>>) {
Self::run_until(this_ref, &mut Some);
}
fn get_module(&self, which_module: WhichModule<'_>) -> &SimulationModuleState {
fn get_module(&self, which_module: WhichModule) -> &SimulationModuleState {
match which_module {
WhichModule::Main { .. } => &self.main_module,
WhichModule::Main => &self.main_module,
WhichModule::Extern { module_index } => &self.extern_modules[module_index].module_state,
}
}
fn get_module_mut_and_which_module(
&mut self,
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
) -> (&mut SimulationModuleState, WhichModule<'_>) {
let which_module = which_module(&self.global_io);
fn get_module_mut(&mut self, which_module: WhichModule) -> &mut SimulationModuleState {
match which_module {
WhichModule::Main { .. } => (&mut self.main_module, which_module),
WhichModule::Extern { module_index } => (
&mut self.extern_modules[module_index].module_state,
which_module,
),
WhichModule::Main => &mut self.main_module,
WhichModule::Extern { module_index } => {
&mut self.extern_modules[module_index].module_state
}
}
}
#[track_caller]
@ -2956,23 +2871,18 @@ impl SimulationImpl {
&mut self,
io: Expr<CanonicalType>,
read_time: ReadTime,
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
which_module: WhichModule,
) -> MaybeNeedsSettle<ReadBitFn, bool> {
let which_module = which_module(&self.global_io);
self.get_module(which_module)
.read_helper(Expr::canonical(io), read_time, which_module)
.map(|compiled_value| ReadBitFn { compiled_value })
.apply_no_settle(&mut self.state)
}
#[track_caller]
fn write_bit(
&mut self,
io: Expr<CanonicalType>,
value: bool,
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
) {
let (module, which_module) = self.get_module_mut_and_which_module(which_module);
let compiled_value = module.write_helper(io, which_module);
fn write_bit(&mut self, io: Expr<CanonicalType>, value: bool, which_module: WhichModule) {
let compiled_value = self
.get_module_mut(which_module)
.write_helper(io, which_module);
self.event_queue.add_event_for_now(EventKind::State);
match compiled_value.range.len().as_single() {
Some(TypeLenSingle::SmallSlot) => {
@ -2990,9 +2900,8 @@ impl SimulationImpl {
&mut self,
io: Expr<I>,
read_time: ReadTime,
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
which_module: WhichModule,
) -> MaybeNeedsSettle<ReadBoolOrIntFn<I>, I::Value> {
let which_module = which_module(&self.global_io);
self.get_module(which_module)
.read_helper(Expr::canonical(io), read_time, which_module)
.map(|compiled_value| ReadBoolOrIntFn { compiled_value, io })
@ -3003,10 +2912,11 @@ impl SimulationImpl {
&mut self,
io: Expr<I>,
value: I::Value,
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
which_module: WhichModule,
) {
let (module, which_module) = self.get_module_mut_and_which_module(which_module);
let compiled_value = module.write_helper(Expr::canonical(io), which_module);
let compiled_value = self
.get_module_mut(which_module)
.write_helper(Expr::canonical(io), which_module);
self.event_queue.add_event_for_now(EventKind::State);
let value: BigInt = value.into();
match compiled_value.range.len().as_single() {
@ -3238,12 +3148,7 @@ impl SimulationImpl {
any_change.get()
}
#[track_caller]
fn is_reset_async(
&self,
io: Expr<CanonicalType>,
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
) -> bool {
let which_module = which_module(&self.global_io);
fn is_reset_async(&self, io: Expr<CanonicalType>, which_module: WhichModule) -> bool {
self.get_module(which_module)
.is_reset_async(io, which_module)
}
@ -3252,12 +3157,11 @@ impl SimulationImpl {
&mut self,
io: Expr<CanonicalType>,
read_time: ReadTime,
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
which_module: WhichModule,
) -> (
CompiledValue<CanonicalType>,
MaybeNeedsSettle<ReadFn, SimValue<CanonicalType>>,
) {
let which_module = which_module(&self.global_io);
let compiled_value = self
.get_module(which_module)
.read_helper(io, read_time, which_module);
@ -3285,10 +3189,11 @@ impl SimulationImpl {
&mut self,
io: Expr<CanonicalType>,
value: &SimValue<CanonicalType>,
which_module: impl for<'a> Fn(&'a SimulationGlobalIo) -> WhichModule<'a>,
which_module: WhichModule,
) {
let (module, which_module) = self.get_module_mut_and_which_module(which_module);
let compiled_value = module.write_helper(io, which_module);
let compiled_value = self
.get_module_mut(which_module)
.write_helper(io, which_module);
self.event_queue.add_event_for_now(EventKind::State);
assert_eq!(io.ty(), value.ty());
Self::read_write_sim_value_helper(
@ -3465,318 +3370,6 @@ impl Drop for SimulationImpl {
}
}
#[derive(Clone)]
pub struct SimulationGlobalIo {
global_io: Interned<[(SimIoForGlobal, CompiledValue<CanonicalType>)]>,
global_io_map: Rc<HashMap<SimIoForGlobal, usize>>,
}
impl Default for SimulationGlobalIo {
fn default() -> Self {
Self {
global_io: Interned::default(),
global_io_map: Rc::default(),
}
}
}
impl fmt::Debug for SimulationGlobalIo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.global_io).finish()
}
}
impl SimulationGlobalIo {
fn new(global_io: Interned<[(SimIoForGlobal, CompiledValue<CanonicalType>)]>) -> Self {
Self {
global_io,
global_io_map: Rc::new(HashMap::from_iter(
global_io
.iter()
.enumerate()
.map(|(index, &(global, _))| (global, index)),
)),
}
}
#[must_use]
pub fn iter(&self) -> SimulationGlobalIoIter {
SimulationGlobalIoIter {
global_io: self.global_io.into_iter(),
}
}
#[must_use]
pub fn globals(&self) -> SimulationGlobalIoGlobalsIter {
SimulationGlobalIoGlobalsIter {
global_io: self.global_io.into_iter(),
}
}
#[must_use]
pub fn exprs(&self) -> SimulationGlobalIoExprsIter {
SimulationGlobalIoExprsIter {
global_io: self.global_io.into_iter(),
}
}
#[must_use]
pub fn len(&self) -> usize {
self.global_io.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[must_use]
pub fn contains(&self, global: FormalInput) -> bool {
self.global_io_map
.contains_key(&SimIoForGlobal::new(global))
}
#[must_use]
pub fn get(&self, global: FormalInput) -> Option<Expr<CanonicalType>> {
self.contains(global)
.then(|| SimIoForGlobal::new(global).to_expr())
}
#[must_use]
pub fn expr_to_global(&self, expr: Expr<CanonicalType>) -> Option<FormalInput> {
let global = match *Expr::expr_enum(expr) {
ExprEnum::FormalInput(global) => global,
ExprEnum::SimIoForGlobal(expr) => expr.global(),
_ => return None,
};
self.global_io_map
.contains_key(&SimIoForGlobal::new(global))
.then_some(global)
}
#[must_use]
fn to_sim_io_target(&self, target: Interned<Target>) -> Interned<Target> {
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct FormalInputExprToSimIoExpr;
impl Memoize for FormalInputExprToSimIoExpr {
type Input = Interned<Target>;
type InputOwned = Interned<Target>;
type Output = Interned<Target>;
fn inner(self, input: &Self::Input) -> Self::Output {
match **input {
Target::Base(base) => match *base {
TargetBase::ModuleIO(_)
| TargetBase::MemPort(_)
| TargetBase::Reg(_)
| TargetBase::RegSync(_)
| TargetBase::RegAsync(_)
| TargetBase::Wire(_)
| TargetBase::Instance(_)
| TargetBase::SimIoForGlobal(_) => *input,
TargetBase::FormalInput(global) => {
Target::from(SimIoForGlobal::new(global)).intern()
}
},
Target::Child(child) => Target::Child(TargetChild::new(
self.get_owned(child.parent()),
child.path_element(),
))
.intern_sized(),
}
}
}
match *target.base() {
TargetBase::ModuleIO(_)
| TargetBase::MemPort(_)
| TargetBase::Reg(_)
| TargetBase::RegSync(_)
| TargetBase::RegAsync(_)
| TargetBase::Wire(_)
| TargetBase::Instance(_)
| TargetBase::SimIoForGlobal(_) => target,
TargetBase::FormalInput(global) => {
if self.contains(global) {
FormalInputExprToSimIoExpr.get_owned(target)
} else {
target
}
}
}
}
}
impl IntoIterator for SimulationGlobalIo {
type Item = (FormalInput, Expr<CanonicalType>);
type IntoIter = SimulationGlobalIoIter;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl IntoIterator for &'_ SimulationGlobalIo {
type Item = (FormalInput, Expr<CanonicalType>);
type IntoIter = SimulationGlobalIoIter;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl IntoIterator for &'_ mut SimulationGlobalIo {
type Item = (FormalInput, Expr<CanonicalType>);
type IntoIter = SimulationGlobalIoIter;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
macro_rules! make_simulation_global_io_iter {
(
impl $SimulationGlobalIoIter:ident {
fn $global_io_to_item:ident(
$global_io_to_item_arg:ident: (SimIoForGlobal, CompiledValue<CanonicalType>),
) -> $item_ty:ty
$global_io_to_item_block:block
}
) => {
#[derive(Clone, Default)]
pub struct $SimulationGlobalIoIter {
global_io: InternedSliceIter<(SimIoForGlobal, CompiledValue<CanonicalType>)>,
}
impl $SimulationGlobalIoIter {
fn $global_io_to_item(
$global_io_to_item_arg: (SimIoForGlobal, CompiledValue<CanonicalType>),
) -> $item_ty
$global_io_to_item_block
}
impl Iterator for $SimulationGlobalIoIter {
type Item = $item_ty;
fn next(&mut self) -> Option<Self::Item> {
self.global_io.next().map(Self::global_io_to_item)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.global_io.size_hint()
}
fn count(self) -> usize {
self.global_io.count()
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.global_io.nth(n).map(Self::global_io_to_item)
}
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.global_io.map(Self::global_io_to_item).fold(init, f)
}
}
impl std::iter::FusedIterator for $SimulationGlobalIoIter {}
impl DoubleEndedIterator for $SimulationGlobalIoIter {
fn next_back(&mut self) -> Option<Self::Item> {
self.global_io.next_back().map(Self::global_io_to_item)
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.global_io.nth_back(n).map(Self::global_io_to_item)
}
fn rfold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.global_io.map(Self::global_io_to_item).rfold(init, f)
}
}
impl ExactSizeIterator for $SimulationGlobalIoIter {}
};
}
make_simulation_global_io_iter! {
impl SimulationGlobalIoIter {
fn global_io_to_item(
v: (SimIoForGlobal, CompiledValue<CanonicalType>),
) -> (FormalInput, Expr<CanonicalType>) {
let (global, _) = v;
(global.global(), global.to_expr())
}
}
}
impl SimulationGlobalIoIter {
#[must_use]
pub fn globals(self) -> SimulationGlobalIoGlobalsIter {
SimulationGlobalIoGlobalsIter {
global_io: self.global_io,
}
}
#[must_use]
pub fn exprs(self) -> SimulationGlobalIoExprsIter {
SimulationGlobalIoExprsIter {
global_io: self.global_io,
}
}
}
impl fmt::Debug for SimulationGlobalIoIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SimulationGlobalIoIter")
.field(&fmt::from_fn(|f| {
f.debug_map().entries(self.clone()).finish()
}))
.finish()
}
}
make_simulation_global_io_iter! {
impl SimulationGlobalIoGlobalsIter {
fn global_io_to_item(
v: (SimIoForGlobal, CompiledValue<CanonicalType>),
) -> FormalInput {
let (global, _) = v;
global.global()
}
}
}
impl fmt::Debug for SimulationGlobalIoGlobalsIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SimulationGlobalIoGlobalsIter")
.field(&fmt::from_fn(|f| {
f.debug_set().entries(self.clone()).finish()
}))
.finish()
}
}
make_simulation_global_io_iter! {
impl SimulationGlobalIoExprsIter {
fn global_io_to_item(
v: (SimIoForGlobal, CompiledValue<CanonicalType>),
) -> Expr<CanonicalType> {
let (global, _) = v;
global.to_expr()
}
}
}
impl fmt::Debug for SimulationGlobalIoExprsIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SimulationGlobalIoExprsIter")
.field(&fmt::from_fn(|f| {
f.debug_set().entries(self.clone()).finish()
}))
.finish()
}
}
pub struct Simulation<T: BundleType> {
sim_impl: Rc<RefCell<SimulationImpl>>,
io: Expr<T>,
@ -3851,15 +3444,14 @@ macro_rules! impl_simulation_methods {
(
async_await = ($($async:tt, $await:tt)?),
track_caller = ($(#[$track_caller:tt])?),
which_module = |$self:ident, $global_io:ident| $which_module:expr,
which_module = |$self:ident| $which_module:expr,
) => {
$(#[$track_caller])?
pub $($async)? fn read_bool_or_int<I: BoolOrIntType>(&mut $self, io: Expr<I>) -> I::Value {
let retval = $self.sim_impl.borrow_mut().read_bool_or_int(
io,
ReadTime::Current,
|$global_io: &SimulationGlobalIo| $which_module,
);
let retval = $self
.sim_impl
.borrow_mut()
.read_bool_or_int(io, ReadTime::Current, $which_module);
$self.settle_if_needed(retval)$(.$await)?
}
$(#[$track_caller])?
@ -3872,74 +3464,64 @@ macro_rules! impl_simulation_methods {
$self.sim_impl.borrow_mut().write_bool_or_int(
io,
SimValue::into_value(value),
|$global_io: &SimulationGlobalIo| $which_module,
$which_module,
);
}
$(#[$track_caller])?
pub $($async)? fn write_clock(&mut $self, io: Expr<Clock>, value: bool) {
$self.sim_impl.borrow_mut().write_bit(
Expr::canonical(io),
value,
|$global_io: &SimulationGlobalIo| $which_module,
);
$self.sim_impl
.borrow_mut()
.write_bit(Expr::canonical(io), value, $which_module);
}
$(#[$track_caller])?
pub $($async)? fn read_clock(&mut $self, io: Expr<Clock>) -> bool {
let retval = $self.sim_impl.borrow_mut().read_bit(
Expr::canonical(io),
ReadTime::Current,
|$global_io: &SimulationGlobalIo| $which_module,
);
let retval = $self
.sim_impl
.borrow_mut()
.read_bit(Expr::canonical(io), ReadTime::Current, $which_module);
$self.settle_if_needed(retval)$(.$await)?
}
$(#[$track_caller])?
pub $($async)? fn write_bool(&mut $self, io: Expr<Bool>, value: bool) {
$self.sim_impl.borrow_mut().write_bit(
Expr::canonical(io),
value,
|$global_io: &SimulationGlobalIo| $which_module,
);
$self.sim_impl
.borrow_mut()
.write_bit(Expr::canonical(io), value, $which_module);
}
$(#[$track_caller])?
pub $($async)? fn read_bool(&mut $self, io: Expr<Bool>) -> bool {
let retval = $self.sim_impl.borrow_mut().read_bit(
Expr::canonical(io),
ReadTime::Current,
|$global_io: &SimulationGlobalIo| $which_module,
);
let retval = $self
.sim_impl
.borrow_mut()
.read_bit(Expr::canonical(io), ReadTime::Current, $which_module);
$self.settle_if_needed(retval)$(.$await)?
}
$(#[$track_caller])?
pub $($async)? fn write_reset<R: ResetType>(&mut $self, io: Expr<R>, value: bool) {
$self.sim_impl.borrow_mut().write_bit(
Expr::canonical(io),
value,
|$global_io: &SimulationGlobalIo| $which_module,
);
$self.sim_impl
.borrow_mut()
.write_bit(Expr::canonical(io), value, $which_module);
}
$(#[$track_caller])?
pub $($async)? fn read_reset<R: ResetType>(&mut $self, io: Expr<R>) -> bool {
let retval = $self.sim_impl.borrow_mut().read_bit(
Expr::canonical(io),
ReadTime::Current,
|$global_io: &SimulationGlobalIo| $which_module,
);
let retval = $self
.sim_impl
.borrow_mut()
.read_bit(Expr::canonical(io), ReadTime::Current, $which_module);
$self.settle_if_needed(retval)$(.$await)?
}
#[track_caller]
pub fn is_reset_async<R: ResetType>(&$self, io: Expr<R>) -> bool {
$self.sim_impl.borrow().is_reset_async(
Expr::canonical(io),
|$global_io: &SimulationGlobalIo| $which_module,
)
$self
.sim_impl
.borrow_mut()
.is_reset_async(Expr::canonical(io), $which_module)
}
$(#[$track_caller])?
pub $($async)? fn read<IO: Type>(&mut $self, io: Expr<IO>) -> SimValue<IO> {
let retval = $self.sim_impl.borrow_mut().read(
Expr::canonical(io),
ReadTime::Current,
|$global_io: &SimulationGlobalIo| $which_module,
).1;
let retval = $self
.sim_impl
.borrow_mut()
.read(Expr::canonical(io), ReadTime::Current, $which_module).1;
SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?)
}
$(#[$track_caller])?
@ -3947,7 +3529,7 @@ macro_rules! impl_simulation_methods {
$self.sim_impl.borrow_mut().write(
Expr::canonical(io),
&SimValue::into_canonical(value.into_sim_value_with_type(io.ty())),
|$global_io: &SimulationGlobalIo| $which_module,
$which_module,
);
}
};
@ -3986,9 +3568,6 @@ impl<T: BundleType> Simulation<T> {
pub fn io(&self) -> Expr<T> {
self.io.to_expr()
}
pub fn global_io(&self) -> SimulationGlobalIo {
self.sim_impl.borrow().global_io.clone()
}
pub fn from_compiled(compiled: Compiled<T>) -> Self {
let sim_impl = SimulationImpl::new(compiled.canonical());
Self {
@ -4014,7 +3593,7 @@ impl<T: BundleType> Simulation<T> {
impl_simulation_methods!(
async_await = (),
track_caller = (#[track_caller]),
which_module = |self, global_io| WhichModule::Main { global_io },
which_module = |self| WhichModule::Main,
);
#[doc(hidden)]
/// This is explicitly unstable and may be changed/removed at any time
@ -4083,7 +3662,7 @@ impl ExternModuleSimulationState {
let (key, value) = self
.sim_impl
.borrow_mut()
.read(io, ReadTime::Current, |_| which_module);
.read(io, ReadTime::Current, which_module);
let value = self.settle_if_needed(value).await;
let key = Rc::new(key);
if sensitivity_set.compiled_values.insert(key.clone()) {
@ -4355,7 +3934,7 @@ impl ExternModuleSimulationState {
let retval = self.sim_impl.borrow_mut().read_bool_or_int(
io,
ReadTime::Past { clock_for_past },
|_| WhichModule::Extern {
WhichModule::Extern {
module_index: self.module_index,
},
);
@ -4371,7 +3950,7 @@ impl ExternModuleSimulationState {
let retval = self.sim_impl.borrow_mut().read_bit(
Expr::canonical(io),
ReadTime::Past { clock_for_past },
|_| WhichModule::Extern {
WhichModule::Extern {
module_index: self.module_index,
},
);
@ -4387,7 +3966,7 @@ impl ExternModuleSimulationState {
let retval = self.sim_impl.borrow_mut().read_bit(
Expr::canonical(io),
ReadTime::Past { clock_for_past },
|_| WhichModule::Extern {
WhichModule::Extern {
module_index: self.module_index,
},
);
@ -4407,7 +3986,7 @@ impl ExternModuleSimulationState {
let retval = self.sim_impl.borrow_mut().read_bit(
Expr::canonical(io),
ReadTime::Past { clock_for_past },
|_| WhichModule::Extern {
WhichModule::Extern {
module_index: self.module_index,
},
);
@ -4430,7 +4009,7 @@ impl ExternModuleSimulationState {
.read(
Expr::canonical(io),
ReadTime::Past { clock_for_past },
|_| WhichModule::Extern {
WhichModule::Extern {
module_index: self.module_index,
},
)
@ -4440,7 +4019,7 @@ impl ExternModuleSimulationState {
impl_simulation_methods!(
async_await = (async, await),
track_caller = (),
which_module = |self, _global_io| WhichModule::Extern { module_index: self.module_index },
which_module = |self| WhichModule::Extern { module_index: self.module_index },
);
}

File diff suppressed because it is too large Load diff

View file

@ -980,7 +980,6 @@ 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>,)*
}
@ -991,7 +990,6 @@ macro_rules! make_state {
insns: _,
pc,
memory_write_log,
assert_failed_log,
$($state_plural_field,)*
$($type_plural_field,)*
} = self;
@ -999,7 +997,6 @@ 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()
@ -1012,7 +1009,6 @@ 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,7 +1020,6 @@ 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(),)*
}
@ -1047,7 +1042,6 @@ 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>,)*
}
@ -1305,7 +1299,6 @@ impl State {
insns: _,
pc,
memory_write_log: _,
assert_failed_log: _,
memories: _,
small_slots: _,
big_slots: _,
@ -1345,10 +1338,6 @@ 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> {
@ -2116,19 +2105,6 @@ 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

@ -1508,8 +1508,6 @@ 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,
@ -1529,8 +1527,6 @@ 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

@ -9,11 +9,11 @@ use crate::{
prelude::PhantomConst,
sim::{
TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl,
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,
TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, 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,
},
@ -766,7 +766,6 @@ 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),
@ -964,27 +963,6 @@ 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 {

View file

@ -12,13 +12,11 @@ use crate::{
bundle::BundleType,
firrtl::ExportOptions,
module::Module,
sim::{Simulation, vcd::VcdWriterDecls},
util::{HashMap, RcWriter},
util::HashMap,
};
use serde::{Deserialize, Serialize};
use std::{
fmt::{self, Write},
panic::Location,
path::{Path, PathBuf},
process::Command,
sync::{Mutex, OnceLock},
@ -224,190 +222,3 @@ 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;

View file

@ -354,39 +354,6 @@ impl CanonicalType {
}
MyMemoize.get_owned((self, other))
}
pub fn contains_sim_only(self) -> bool {
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct MyMemoize;
impl Memoize for MyMemoize {
type Input = CanonicalType;
type InputOwned = CanonicalType;
type Output = bool;
fn inner(self, input: &Self::Input) -> Self::Output {
match input {
CanonicalType::UInt(_) | CanonicalType::SInt(_) | CanonicalType::Bool(_) => {
false
}
CanonicalType::Array(ty) => ty.element().contains_sim_only(),
CanonicalType::Enum(ty) => ty
.variants()
.iter()
.any(|v| v.ty.is_some_and(CanonicalType::contains_sim_only)),
CanonicalType::Bundle(ty) => {
ty.fields().iter().any(|v| v.ty.contains_sim_only())
}
CanonicalType::AsyncReset(_)
| CanonicalType::SyncReset(_)
| CanonicalType::Reset(_)
| CanonicalType::Clock(_)
| CanonicalType::PhantomConst(_) => false,
CanonicalType::DynSimOnly(_) => true,
CanonicalType::TraceAsString(ty) => ty.inner_ty().contains_sim_only(),
}
}
}
MyMemoize.get_owned(self)
}
}
pub trait MatchVariantAndInactiveScope: Sized {
@ -1342,49 +1309,16 @@ trait TraceAsStringTrait: fmt::Debug + 'static + Send + Sync + SupportsPtrEqWith
fn can_substitute_type(&self, new_type: CanonicalType) -> bool;
}
#[derive(Clone, PartialEq, Eq, Hash)]
struct TraceAsStringState<T: Type> {
ty: Interned<T>,
canonical_ty: CanonicalType,
}
impl<T: Type> TraceAsStringState<T> {
fn new(ty: Interned<T>) -> Interned<Self> {
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct MyMemoize<T: Type>(PhantomData<T>);
impl<T: Type> Memoize for MyMemoize<T> {
type Input = Interned<T>;
type InputOwned = Interned<T>;
type Output = Interned<TraceAsStringState<T>>;
fn inner(self, input: &Self::Input) -> Self::Output {
TraceAsStringState {
ty: *input,
canonical_ty: input.canonical(),
}
.intern_sized()
}
}
MyMemoize(PhantomData).get_owned(ty)
}
}
impl<T: Type> fmt::Debug for TraceAsStringState<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.ty.fmt(f)
}
}
impl<T: Type> TraceAsStringTrait for TraceAsStringState<T> {
impl<T: Type> TraceAsStringTrait for T {
fn trace_fmt(
&self,
opaque: OpaqueSimValueSlice<'_>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
fmt::Debug::fmt(&Type::sim_value_from_opaque(&*self.ty, opaque), f)
fmt::Debug::fmt(&Type::sim_value_from_opaque(self, opaque), f)
}
fn can_substitute_type(&self, new_type: CanonicalType) -> bool {
self.canonical_ty.is_layout_equivalent(new_type)
self.canonical().is_layout_equivalent(new_type)
}
}
@ -1440,7 +1374,7 @@ impl<T: Type> TraceAsString<T> {
Self {
inner_ty: LazyInterned::Interned(inner_ty),
trace_as_string: LazyInterned::Interned(Interned::cast_unchecked(
TraceAsStringState::new(inner_ty),
inner_ty,
|v| -> &dyn TraceAsStringTrait { v },
)),
}
@ -1614,10 +1548,7 @@ impl<T: StaticType> Default for TraceAsStringStaticTypeHelper<T> {
impl<T: StaticType> From<TraceAsStringStaticTypeHelper<T>> for Interned<dyn TraceAsStringTrait> {
fn from(_value: TraceAsStringStaticTypeHelper<T>) -> Self {
Interned::cast_unchecked(
TraceAsStringState::new(T::TYPE.intern_sized()),
|v| -> &dyn TraceAsStringTrait { v },
)
Interned::cast_unchecked(T::TYPE.intern_sized(), |v| -> &dyn TraceAsStringTrait { v })
}
}
@ -1915,8 +1846,6 @@ fn trace_as_string_cow_into_inner_value<T: Type>(
}
impl<T: HdlPartialEqImpl<U>, U: Type> HdlPartialEqImpl<TraceAsString<U>> for TraceAsString<T> {
const TRY_STRUCTURAL_EQ: bool = <T as HdlPartialEqImpl<U>>::TRY_STRUCTURAL_EQ;
#[track_caller]
fn cmp_value_eq(
lhs: Self,

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, H = DefaultBuildHasher> = hashbrown::HashMap<K, V, H>;
pub(crate) type HashSet<T, H = DefaultBuildHasher> = hashbrown::HashSet<T, H>;
pub(crate) type HashMap<K, V> = hashbrown::HashMap<K, V, DefaultBuildHasher>;
pub(crate) type HashSet<T> = hashbrown::HashSet<T, DefaultBuildHasher>;
#[doc(inline)]
pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool};
@ -43,11 +43,7 @@ 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

@ -1,711 +0,0 @@
// 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

@ -1,117 +0,0 @@
// 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

@ -1,463 +0,0 @@
// 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,13 +241,15 @@ 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: formal_global_clock(),
clk,
rst: formal_reset().to_reset(),
},
);
@ -278,7 +280,7 @@ mod tests {
#[hdl]
let index_to_check = wire(index_ty);
connect(index_to_check, any_const(index_ty));
hdl_assume(cd.clk, index_to_check.cmp_lt(capacity.get()), "");
hdl_assume(clk, index_to_check.cmp_lt(capacity.get()), "");
// instantiate and connect the queue
#[hdl]
@ -298,13 +300,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(cd.clk, expected_count_reg.cmp_ne(capacity.get()), "");
hdl_assert(clk, expected_count_reg.cmp_ne(capacity.get()), "");
connect_any(expected_count_reg, expected_count_reg + 1u8);
} else if !ReadyValid::firing(dut.inp) & ReadyValid::firing(dut.out) {
hdl_assert(cd.clk, expected_count_reg.cmp_ne(count_ty.zero()), "");
hdl_assert(clk, expected_count_reg.cmp_ne(count_ty.zero()), "");
connect_any(expected_count_reg, expected_count_reg - 1u8);
}
hdl_assert(cd.clk, expected_count_reg.cmp_eq(dut.count), "");
hdl_assert(clk, expected_count_reg.cmp_eq(dut.count), "");
// keep an independent write index into the FIFO's circular buffer
#[hdl]
@ -372,7 +374,7 @@ mod tests {
match inp_firing_data {
// ... and we are not receiving data, then we must not
// transmit any data.
HdlNone => hdl_assert(cd.clk, HdlOption::is_none(out_firing_data), ""),
HdlNone => hdl_assert(clk, HdlOption::is_none(out_firing_data), ""),
// If we are indeed receiving some data...
HdlSome(data_in) => {
#[hdl]
@ -380,9 +382,7 @@ 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(cd.clk, data_out.cmp_eq(data_in), "")
}
HdlSome(data_out) => hdl_assert(clk, data_out.cmp_eq(data_in), ""),
// If we are receiving, but not transmitting,
// store the received data in the holding
// register.
@ -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(cd.clk, HdlOption::is_none(inp_firing_data), ""),
HdlNone => hdl_assert(clk, HdlOption::is_none(inp_firing_data), ""),
// If we are transmitting a previously stored value...
HdlSome(data_out) => {
// ... it must be the same data we stored earlier.
hdl_assert(cd.clk, data_out.cmp_eq(stored), "");
hdl_assert(clk, data_out.cmp_eq(stored), "");
// Also, accept new data, if any. Otherwise,
// let the holding register become empty.
connect(stored_reg, inp_firing_data);
@ -417,17 +417,17 @@ mod tests {
connect(dut.dbg.index_to_check, index_to_check);
#[hdl]
if let HdlSome(stored) = stored_reg {
hdl_assert(cd.clk, stored.cmp_eq(dut.dbg.stored), "");
hdl_assert(clk, stored.cmp_eq(dut.dbg.stored), "");
}
// sync the read and write indices
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), "");
hdl_assert(clk, inp_index_reg.cmp_eq(dut.dbg.inp_index), "");
hdl_assert(clk, out_index_reg.cmp_eq(dut.dbg.out_index), "");
// the indices should never go past the capacity, but induction
// doesn't know that...
hdl_assert(cd.clk, inp_index_reg.cmp_lt(capacity.get()), "");
hdl_assert(cd.clk, out_index_reg.cmp_lt(capacity.get()), "");
hdl_assert(clk, inp_index_reg.cmp_lt(capacity.get()), "");
hdl_assert(clk, out_index_reg.cmp_lt(capacity.get()), "");
// strongly constrain the state of the holding register
//
@ -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(
cd.clk,
clk,
expected_stored.cmp_eq(HdlOption::is_some(stored_reg)),
"",
);

View file

@ -1,352 +0,0 @@
// 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

@ -2,11 +2,14 @@
// See Notices.txt for copyright information
pub mod xilinx;
pub mod lattice;
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::DynJobKind> {
xilinx::built_in_job_kinds()
xilinx::built_in_job_kinds();
lattice::built_in_job_kinds()
}
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = crate::platform::DynPlatform> {
xilinx::built_in_platforms()
xilinx::built_in_platforms();
lattice::built_in_platforms()
}

187
crates/fayalite/src/vendor/lattice.rs vendored Normal file
View file

@ -0,0 +1,187 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
annotations::make_annotation_enum,
build::{GlobalParams, ToArgs, WriteArgs},
intern::Interned,
prelude::{DynPlatform, Platform},
};
use clap::ValueEnum;
use ordered_float::NotNan;
use serde::{Deserialize, Serialize};
use std::fmt;
pub mod orangecrab;
pub mod primitives;
pub mod yosys_nextpnr;
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
pub struct LatticeArgs {
#[arg(long)]
pub device: Option<Device>,
}
impl LatticeArgs {
pub fn require_device(
&self,
platform: Option<&DynPlatform>,
global_params: &GlobalParams,
) -> clap::error::Result<Device> {
if let Some(device) = self.device {
return Ok(device);
}
if let Some(device) =
platform.and_then(|platform| platform.aspects().get_single_by_type::<Device>().copied())
{
return Ok(device);
}
Err(global_params.clap_error(
clap::error::ErrorKind::MissingRequiredArgument,
"missing --device option",
))
}
}
impl ToArgs for LatticeArgs {
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
if let Some(device) = self.device {
args.write_long_option_eq("device", device.as_str());
}
}
}
macro_rules! make_device_enum {
($vis:vis enum $Device:ident {
$(
#[
name = $name:literal,
lattice_part = $lattice_part:literal,
lattice_device = $lattice_device:literal,
lattice_family = $lattice_family:literal,
]
$variant:ident,
)*
}) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, ValueEnum)]
$vis enum $Device {
$(
#[value(name = $name, alias = $lattice_part)]
$variant,
)*
}
impl $Device {
$vis fn as_str(self) -> &'static str {
match self {
$(Self::$variant => $name,)*
}
}
$vis fn lattice_part(self) -> &'static str {
match self {
$(Self::$variant => $lattice_part,)*
}
}
$vis fn lattice_device(self) -> &'static str {
match self {
$(Self::$variant => $lattice_device,)*
}
}
$vis fn lattice_family(self) -> &'static str {
match self {
$(Self::$variant => $lattice_family,)*
}
}
}
struct DeviceVisitor;
impl<'de> serde::de::Visitor<'de> for DeviceVisitor {
type Value = $Device;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a Lattice device string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match $Device::from_str(v, false) {
Ok(v) => Ok(v),
Err(_) => Err(E::invalid_value(serde::de::Unexpected::Str(v), &self)),
}
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match str::from_utf8(v).ok().and_then(|v| $Device::from_str(v, false).ok()) {
Some(v) => Ok(v),
None => Err(E::invalid_value(serde::de::Unexpected::Bytes(v), &self)),
}
}
}
impl<'de> Deserialize<'de> for $Device {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_string(DeviceVisitor)
}
}
impl Serialize for $Device {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.as_str().serialize(serializer)
}
}
};
}
//ECP5 variants -- needs fixme
make_device_enum! {
pub enum Device {
#[
name = "placeholder25k",
lattice_part = "fixme",
lattice_device = "fixme",
lattice_family = "fixme",
]
Placeholder25k,
#[
name = "placeholder85k",
lattice_part = "fixme",
lattice_device = "fimxe",
lattice_family = "fixme",
]
Placeholder85k,
}
}
//rest looks good
impl fmt::Display for Device {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::DynJobKind> {
orangecrab::built_in_job_kinds()
.into_iter()
.chain(yosys_nextpnr::built_in_job_kinds())
}
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = crate::platform::DynPlatform> {
orangecrab::built_in_platforms()
.into_iter()
.chain(yosys_nextpnr::built_in_platforms())
}
//first step yosys -p "read_verilog $<; synth_ecp5 -json $@"

View file

@ -0,0 +1,396 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
intern::{Intern, Interned},
module::{instance_with_loc, reg_builder_with_loc, wire_with_loc},
platform::{
DynPlatform, Peripheral, PeripheralRef, Peripherals, PeripheralsBuilderFactory,
PeripheralsBuilderFinished, Platform, PlatformAspectSet,
peripherals::{ClockInput, Led, RgbLed, Uart},
},
prelude::*,
vendor::lattice::{
Device,
primitives,
},
};
use ordered_float::NotNan;
use std::sync::OnceLock;
//keep unchanged
macro_rules! orangecrab_platform {
(
$vis:vis enum $OrangeCrabPlatform:ident {
$(#[name = $name:literal, device = $device:ident]
$Variant:ident,)*
}
) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
$vis enum $OrangeCrabPlatform {
$($Variant,)*
}
impl $OrangeCrabPlatform {
$vis const VARIANTS: &'static [Self] = &[$(Self::$Variant,)*];
$vis fn device(self) -> Device {
match self {
$(Self::$Variant => Device::$device,)*
}
}
$vis const fn as_str(self) -> &'static str {
match self {
$(Self::$Variant => $name,)*
}
}
fn get_aspects(self) -> &'static PlatformAspectSet {
match self {
$(Self::$Variant => {
static ASPECTS_SET: OnceLock<PlatformAspectSet> = OnceLock::new();
ASPECTS_SET.get_or_init(|| self.make_aspects())
})*
}
}
}
};
}
//untested
orangecrab_platform! {
pub enum OrangeCrabPlatform {
#[name = "orangecrab-25k", device = Placeholder25k]
OrangeCrab_25k,
#[name = "orangecrab-85k", device = Placeholder85k]
OrangeCrab_85k,
}
}
//FIXME rename
#[derive(Debug)]
pub struct ArtyA7Peripherals {
clk100_div_pow2: [Peripheral<ClockInput>; 4],
rst: Peripheral<Reset>,
rst_sync: Peripheral<SyncReset>,
ld0: Peripheral<RgbLed>,
//ld1: Peripheral<RgbLed>,
//ld2: Peripheral<RgbLed>,
//ld3: Peripheral<RgbLed>,
//ld4: Peripheral<Led>,
//ld5: Peripheral<Led>,
//ld6: Peripheral<Led>,
//ld7: Peripheral<Led>,
uart: Peripheral<Uart>,
// TODO: add rest of peripherals when we need them
}
impl Peripherals for ArtyA7Peripherals {
fn append_peripherals<'a>(&'a self, peripherals: &mut Vec<PeripheralRef<'a, CanonicalType>>) {
let Self {
clk100_div_pow2,
rst,
rst_sync,
ld0,
//ld1,
//ld2,
//ld3,
//ld4,
//ld5,
//ld6,
//ld7,
uart,
} = self;
clk100_div_pow2.append_peripherals(peripherals);
rst.append_peripherals(peripherals);
rst_sync.append_peripherals(peripherals);
ld0.append_peripherals(peripherals);
//ld1.append_peripherals(peripherals);
//ld2.append_peripherals(peripherals);
//ld3.append_peripherals(peripherals);
//ld4.append_peripherals(peripherals);
//ld5.append_peripherals(peripherals);
//ld6.append_peripherals(peripherals);
//ld7.append_peripherals(peripherals);
uart.append_peripherals(peripherals);
}
}
impl OrangeCrabPlatform {
fn make_aspects(self) -> PlatformAspectSet {
let mut retval = PlatformAspectSet::new();
retval.insert_new(self.device());
retval
}
}
#[hdl_module(extern)]
fn reset_sync() {
#[hdl]
let clk: Clock = m.input();
#[hdl]
let inp: Bool = m.input();
#[hdl]
let out: SyncReset = m.output();
m.annotate_module(BlackBoxInlineAnnotation {
path: "fayalite_orangecrab_reset_sync.v".intern(),
text: r#"module __fayalite_orangecrab_reset_sync(input clk, input inp, output out);
wire reset_0_out;
always @(posedge clk) begin
reset_0_out <= inp;
outp <= reset_0_out;
end
endmodule
"#
.intern(),
});
m.verilog_name("__fayalite_orangecrab_reset_sync");
}
impl Platform for OrangeCrabPlatform {
type Peripherals = ArtyA7Peripherals;
fn name(&self) -> Interned<str> {
self.as_str().intern()
}
fn new_peripherals<'builder>(
&self,
builder_factory: PeripheralsBuilderFactory<'builder>,
) -> (Self::Peripherals, PeripheralsBuilderFinished<'builder>) {
let mut builder = builder_factory.builder();
let clk100_div_pow2 = std::array::from_fn(|log2_divisor| {
let divisor = 1u64 << log2_divisor;
let name = if divisor != 1 {
format!("clk100_div_{divisor}")
} else {
"clk100".into()
};
builder.input_peripheral(name, ClockInput::new(100e6 / divisor as f64))
});
builder.add_conflicts(Vec::from_iter(clk100_div_pow2.iter().map(|v| v.id())));
(
ArtyA7Peripherals {
clk100_div_pow2,
rst: builder.input_peripheral("rst", Reset),
rst_sync: builder.input_peripheral("rst_sync", SyncReset),
ld0: builder.output_peripheral("ld0", RgbLed),
//ld1: builder.output_peripheral("ld1", RgbLed),
//ld2: builder.output_peripheral("ld2", RgbLed),
//ld3: builder.output_peripheral("ld3", RgbLed),
//ld4: builder.output_peripheral("ld4", Led),
//ld5: builder.output_peripheral("ld5", Led),
//ld6: builder.output_peripheral("ld6", Led),
//ld7: builder.output_peripheral("ld7", Led),
uart: builder.output_peripheral("uart", Uart),
},
builder.finish(),
)
}
fn source_location(&self) -> SourceLocation {
SourceLocation::builtin()
}
fn add_peripherals_in_wrapper_module(&self, m: &ModuleBuilder, peripherals: Self::Peripherals) {
let ArtyA7Peripherals {
clk100_div_pow2,
rst,
rst_sync,
ld0,
//ld1,
//ld2,
//ld3,
//ld4,
//ld5,
//ld6,
//ld7,
uart,
} = peripherals;
let make_buffered_input = |name: &str, location: &str, io_standard: &str, invert: bool| {
let pin = m.input_with_loc(name, SourceLocation::builtin(), Bool);
/* fixme annotate(
pin,
XdcLocationAnnotation {
location: location.intern(),
},
); */
/* fixme annotate(
pin,
XdcIOStandardAnnotation {
value: io_standard.intern(),
},
); */
//let buf = instance_with_loc(
// &format!("{name}_buf"),
// //primitives::IBUF(),
// SourceLocation::builtin(),
//);
//connect(buf.I, pin);
//if invert { !buf.O } else { buf.O }
if invert { !pin } else { pin }
};
let make_buffered_output = |name: &str, location: &str, io_standard: &str| {
let pin = m.output_with_loc(name, SourceLocation::builtin(), Bool);
/* fixme annotate(
pin,
XdcLocationAnnotation {
location: location.intern(),
},
);
annotate(
pin,
XdcIOStandardAnnotation {
value: io_standard.intern(),
},
); */
//let buf = instance_with_loc(
// &format!("{name}_buf"),
// primitives::OBUFT(),
// SourceLocation::builtin(),
//);
//connect(pin, buf.O);
//connect(buf.T, false);
//buf.I
pin
};
let mut frequency = clk100_div_pow2[0].ty().frequency();
let mut log2_divisor = 0;
let mut clk = None;
for (cur_log2_divisor, p) in clk100_div_pow2.into_iter().enumerate() {
let Some(p) = p.into_used() else {
continue;
};
debug_assert!(
clk.is_none(),
"conflict-handling logic should ensure at most one clock is used",
);
frequency = p.ty().frequency();
clk = Some(p);
log2_divisor = cur_log2_divisor;
}
let clk100_buf = make_buffered_input("clk100", "E3", "LVCMOS33", false);
//let startup = instance_with_loc(
// "startup",
// primitives::STARTUPE2_default_inputs(),
// SourceLocation::builtin(),
//);
//let clk_global_buf = instance_with_loc(
// "clk_global_buf",
// primitives::BUFGCE(),
// SourceLocation::builtin(),
//);
//connect(clk_global_buf.CE, startup.EOS);
let mut clk_global_buf_in = clk100_buf.to_clock();
for prev_log2_divisor in 0..log2_divisor {
let prev_divisor = 1u64 << prev_log2_divisor;
let clk_in = wire_with_loc(
&format!("clk_div_{prev_divisor}"),
SourceLocation::builtin(),
Clock,
);
connect(clk_in, clk_global_buf_in);
/* fixme
annotate(
clk_in,
XdcCreateClockAnnotation {
period: NotNan::new(1e9 / (100e6 / prev_divisor as f64))
.expect("known to be valid"),
},
); */
annotate(clk_in, DontTouchAnnotation);
let cd = wire_with_loc(
&format!("clk_div_{prev_divisor}_in"),
SourceLocation::builtin(),
ClockDomain[AsyncReset],
);
connect(cd.clk, clk_in);
//FIXME connect(cd.rst, (!startup.EOS).to_async_reset());
let divider = reg_builder_with_loc("divider", SourceLocation::builtin())
.clock_domain(cd)
.reset(false)
.build();
connect(divider, !divider);
clk_global_buf_in = divider.to_clock();
}
//connect(clk_global_buf.I, clk_global_buf_in);
let clk_out = wire_with_loc("clk_out", SourceLocation::builtin(), Clock);
//connect(clk_out, clk_global_buf.O);
connect(clk_out, clk_global_buf_in);
/* fixme annotate(
clk_out,
XdcCreateClockAnnotation {
period: NotNan::new(1e9 / frequency).expect("known to be valid"),
},
); */
annotate(clk_out, DontTouchAnnotation);
if let Some(clk) = clk {
connect(clk.instance_io_field().clk, clk_out);
}
//undo 1
let rst_value = {
let rst_buf = make_buffered_input("rst", "C2", "LVCMOS33", true);
let rst_sync = instance_with_loc("rst_sync", reset_sync(), SourceLocation::builtin());
connect(rst_sync.clk, clk_out);
connect(rst_sync.inp, rst_buf/* | !startup.EOS*/); //FIXME
rst_sync.out
};
if let Some(rst) = rst.into_used() {
connect(rst.instance_io_field(), rst_value.to_reset());
}
if let Some(rst_sync) = rst_sync.into_used() {
connect(rst_sync.instance_io_field(), rst_value);
}
let rgb_leds = [
(ld0, ("G6", "F6", "E1")),
//(ld1, ("G3", "J4", "G4")),
//(ld2, ("J3", "J2", "H4")),
//(ld3, ("K1", "H6", "K2")),
];
for (rgb_led, (r_loc, g_loc, b_loc)) in rgb_leds {
let r = make_buffered_output(&format!("{}_r", rgb_led.name()), r_loc, "LVCMOS33");
let g = make_buffered_output(&format!("{}_g", rgb_led.name()), g_loc, "LVCMOS33");
let b = make_buffered_output(&format!("{}_b", rgb_led.name()), b_loc, "LVCMOS33");
if let Some(rgb_led) = rgb_led.into_used() {
connect(r, rgb_led.instance_io_field().r);
connect(g, rgb_led.instance_io_field().g);
connect(b, rgb_led.instance_io_field().b);
} else {
connect(r, false);
connect(g, false);
connect(b, false);
}
}
//let leds = [(ld4, "H5"), (ld5, "J5"), (ld6, "T9"), (ld7, "T10")];
//for (led, loc) in leds {
// let o = make_buffered_output(&led.name(), loc, "LVCMOS33");
// if let Some(led) = led.into_used() {
// connect(o, led.instance_io_field().on);
// } else {
// connect(o, false);
// }
//}
let uart_tx = make_buffered_output("uart_tx", "D10", "LVCMOS33");
let uart_rx = make_buffered_input("uart_rx", "A9", "LVCMOS33", false);
if let Some(uart) = uart.into_used() {
connect(uart_tx, uart.instance_io_field().tx);
connect(uart.instance_io_field().rx, uart_rx);
} else {
connect(uart_tx, true); // idle
}
}
fn aspects(&self) -> PlatformAspectSet {
self.get_aspects().clone()
}
}
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::DynJobKind> {
[]
}
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = DynPlatform> {
OrangeCrabPlatform::VARIANTS
.iter()
.map(|&v| DynPlatform::new(v))
}

View file

@ -0,0 +1,50 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
#![allow(non_snake_case)]
use crate::prelude::*;
//#[hdl_module(extern)]
//pub fn IBUF() {
// m.verilog_name("IBUF");
// #[hdl]
// let O: Bool = m.output();
// #[hdl]
// let I: Bool = m.input();
//}
//#[hdl_module(extern)]
//pub fn OBUFT() {
// m.verilog_name("OBUFT");
// #[hdl]
// let O: Bool = m.output();
// #[hdl]
// let I: Bool = m.input();
// #[hdl]
// let T: Bool = m.input();
//}
//#[hdl_module(extern)]
//pub fn BUFGCE() {
// m.verilog_name("BUFGCE");
// #[hdl]
// let O: Clock = m.output();
// #[hdl]
// let CE: Bool = m.input();
// #[hdl]
// let I: Clock = m.input();
//}
#[hdl_module(extern)]
pub fn FIXME_PLACEHOLDER() {
m.verilog_name("FIXME_PLACEHOLDER");
#[hdl]
let CFGCLK: Clock = m.output();
#[hdl]
let CFGMCLK: Clock = m.output();
#[hdl]
let EOS: Bool = m.output();
#[hdl]
let PREQ: Bool = m.output();
}

View file

@ -0,0 +1,899 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
annotations::{Annotation, TargetedAnnotation},
build::{
BaseJob, CommandParams, DynJobKind, GetJobPositionDependencies, GlobalParams,
JobAndDependencies, JobArgsAndDependencies, JobDependencies, JobItem, JobItemName, JobKind,
JobKindAndDependencies, ToArgs, WriteArgs,
external::{
ExternalCommand, ExternalCommandJob, ExternalCommandJobKind, ExternalProgramTrait,
},
verilog::{UnadjustedVerilog, VerilogDialect, VerilogJob, VerilogJobKind},
},
bundle::{Bundle, BundleType},
expr::target::{Target, TargetBase},
firrtl::{ScalarizedModuleABI, ScalarizedModuleABIAnnotations, ScalarizedModuleABIPort},
intern::{Intern, InternSlice, Interned},
module::{
NameId, ScopedNameId, TargetName,
transform::visit::{Visit, Visitor},
},
prelude::*,
source_location::SourceLocation,
util::{HashSet, job_server::AcquiredJob},
vendor::lattice::{
Device,
/* fixme LatticeAnnotation,*/ LatticeArgs,
},
};
use eyre::Context;
use serde::{Deserialize, Serialize};
use std::{
convert::Infallible,
ffi::{OsStr, OsString},
fmt::{self, Write},
ops::ControlFlow,
path::{Path, PathBuf},
};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
pub struct YosysNextpnrWriteYsFileJobKind;
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
pub struct YosysNextpnrWriteYsFileArgs {}
impl ToArgs for YosysNextpnrWriteYsFileArgs {
fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) {
let Self {} = self;
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct YosysNextpnrWriteYsFile {
main_verilog_file: Interned<Path>,
ys_file: Interned<Path>,
json_file: Interned<Path>,
json_file_name: Interned<OsStr>,
}
impl YosysNextpnrWriteYsFile {
pub fn main_verilog_file(&self) -> Interned<Path> {
self.main_verilog_file
}
pub fn ys_file(&self) -> Interned<Path> {
self.ys_file
}
pub fn json_file(&self) -> Interned<Path> {
self.json_file
}
pub fn json_file_name(&self) -> Interned<OsStr> {
self.json_file_name
}
fn write_ys(
&self,
output: &mut OsString,
additional_files: &[Interned<Path>],
main_module_name_id: NameId,
) -> eyre::Result<()> {
let Self {
main_verilog_file,
ys_file: _,
json_file: _,
json_file_name,
} = self;
for verilog_file in VerilogJob::all_verilog_files(*main_verilog_file, additional_files)? {
output.push("read_verilog -sv \"");
output.push(verilog_file);
output.push("\"\n");
}
let circuit_name = crate::firrtl::get_circuit_name(main_module_name_id);
writeln!(
output,
"synth_ecp5 -top {circuit_name}"
)
.expect("writing to OsString can't fail");
output.push("write_json \"");
output.push(json_file_name);
output.push("\"\n");
Ok(())
}
}
impl JobKind for YosysNextpnrWriteYsFileJobKind {
type Args = YosysNextpnrWriteYsFileArgs;
type Job = YosysNextpnrWriteYsFile;
type Dependencies = JobKindAndDependencies<VerilogJobKind>;
fn dependencies(self) -> Self::Dependencies {
Default::default()
}
fn args_to_jobs(
mut args: JobArgsAndDependencies<Self>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>> {
args.dependencies
.dependencies
.args
.args
.additional_args
.verilog_dialect
.get_or_insert(VerilogDialect::Yosys);
args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| {
let YosysNextpnrWriteYsFileArgs {} = args;
let base_job = dependencies.get_job::<BaseJob, _>();
let verilog_job = dependencies.get_job::<VerilogJob, _>();
let json_file = base_job.file_with_ext("json");
Ok(YosysNextpnrWriteYsFile {
main_verilog_file: verilog_job.main_verilog_file(),
ys_file: base_job.file_with_ext("ys"),
json_file,
json_file_name: json_file
.interned_file_name()
.expect("known to have file name"),
})
})
}
fn inputs(self, _job: &Self::Job) -> Interned<[JobItemName]> {
[JobItemName::DynamicPaths {
source_job_name: VerilogJobKind.name(),
}]
.intern_slice()
}
fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> {
[JobItemName::Path { path: job.ys_file }].intern_slice()
}
fn name(self) -> Interned<str> {
"yosys-nextpnr-ecp5-write-ys-file".intern()
}
fn external_command_params(self, _job: &Self::Job) -> Option<CommandParams> {
None
}
fn run(
self,
job: &Self::Job,
inputs: &[JobItem],
params: &JobParams,
_global_params: &GlobalParams,
_acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job)));
let [additional_files] = inputs else {
unreachable!();
};
let additional_files = VerilogJob::unwrap_additional_files(additional_files);
let mut contents = OsString::new();
job.write_ys(
&mut contents,
additional_files,
params.main_module().name_id(),
)?;
let path = job.ys_file;
std::fs::write(path, contents.as_encoded_bytes())
.wrap_err_with(|| format!("writing {path:?} failed"))?;
Ok(vec![JobItem::Path { path }])
}
fn subcommand_hidden(self) -> bool {
true
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
pub struct YosysNextpnrSynthArgs {}
impl ToArgs for YosysNextpnrSynthArgs {
fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) {
let Self {} = self;
}
}
#[derive(Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct YosysNextpnrSynth {
#[serde(flatten)]
write_ys_file: YosysNextpnrWriteYsFile,
ys_file_name: Interned<OsStr>,
}
impl fmt::Debug for YosysNextpnrSynth {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
write_ys_file:
YosysNextpnrWriteYsFile {
main_verilog_file,
ys_file,
json_file,
json_file_name,
},
ys_file_name,
} = self;
f.debug_struct("YosysNextpnrSynth")
.field("main_verilog_file", main_verilog_file)
.field("ys_file", ys_file)
.field("ys_file_name", ys_file_name)
.field("json_file", json_file)
.field("json_file_name", json_file_name)
.finish()
}
}
impl YosysNextpnrSynth {
pub fn main_verilog_file(&self) -> Interned<Path> {
self.write_ys_file.main_verilog_file()
}
pub fn ys_file(&self) -> Interned<Path> {
self.write_ys_file.ys_file()
}
pub fn ys_file_name(&self) -> Interned<OsStr> {
self.ys_file_name
}
pub fn json_file(&self) -> Interned<Path> {
self.write_ys_file.json_file()
}
pub fn json_file_name(&self) -> Interned<OsStr> {
self.write_ys_file.json_file_name()
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct Yosys;
impl ExternalProgramTrait for Yosys {
fn default_program_name() -> Interned<str> {
"yosys".intern() //must be yosys
}
}
impl ExternalCommand for YosysNextpnrSynth {
type AdditionalArgs = YosysNextpnrSynthArgs;
type AdditionalJobData = Self;
type BaseJobPosition = GetJobPositionDependencies<
GetJobPositionDependencies<
GetJobPositionDependencies<<UnadjustedVerilog as ExternalCommand>::BaseJobPosition>,
>,
>;
type Dependencies = JobKindAndDependencies<YosysNextpnrWriteYsFileJobKind>;
type ExternalProgram = Yosys;
fn dependencies() -> Self::Dependencies {
Default::default()
}
fn args_to_jobs(
args: JobArgsAndDependencies<ExternalCommandJobKind<Self>>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(
Self::AdditionalJobData,
<Self::Dependencies as JobDependencies>::JobsAndKinds,
)> {
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
let YosysNextpnrSynthArgs {} = args.additional_args;
Ok(Self {
write_ys_file: dependencies.job.job.clone(),
ys_file_name: dependencies
.job
.job
.ys_file()
.interned_file_name()
.expect("known to have file name"),
})
})
}
fn inputs(job: &ExternalCommandJob<Self>) -> Interned<[JobItemName]> {
[
JobItemName::Path {
path: job.additional_job_data().ys_file(),
},
JobItemName::Path {
path: job.additional_job_data().main_verilog_file(),
},
JobItemName::DynamicPaths {
source_job_name: VerilogJobKind.name(),
},
]
.intern_slice()
}
fn output_paths(job: &ExternalCommandJob<Self>) -> Interned<[Interned<Path>]> {
[job.additional_job_data().json_file()].intern_slice()
}
fn command_line_args<W: ?Sized + WriteArgs>(job: &ExternalCommandJob<Self>, args: &mut W) {
args.write_arg("-s");
args.write_interned_arg(job.additional_job_data().ys_file_name());
}
fn current_dir(job: &ExternalCommandJob<Self>) -> Option<Interned<Path>> {
Some(job.output_dir())
}
fn job_kind_name() -> Interned<str> {
"yosys-nextpnr-ecp5-synth".intern()
}
fn subcommand_hidden() -> bool {
true
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
pub struct YosysNextpnrWritePcfFileJobKind;
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
pub struct YosysNextpnrWritePcfFileArgs {}
impl ToArgs for YosysNextpnrWritePcfFileArgs {
fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) {
let Self {} = self;
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct YosysNextpnrWritePcfFile {
firrtl_export_options: crate::firrtl::ExportOptions,
output_dir: Interned<Path>,
pcf_file: Interned<Path>,
}
struct WritePcfContentsError(eyre::Report);
impl From<eyre::Report> for WritePcfContentsError {
fn from(v: eyre::Report) -> Self {
Self(v)
}
}
impl From<fmt::Error> for WritePcfContentsError {
fn from(_v: fmt::Error) -> Self {
unreachable!("String write can't fail")
}
}
fn tcl_escape(s: impl AsRef<str>) -> String {
let s = s.as_ref();
if !s.contains(|ch: char| !ch.is_alphanumeric() && ch != '_') {
return s.into();
}
let mut retval = String::with_capacity(s.len().saturating_add(2));
retval.push('"');
for ch in s.chars() {
if let '$' | '\\' | '[' = ch {
retval.push('\\');
}
retval.push(ch);
}
retval.push('"');
retval
}
#[derive(Copy, Clone, Debug)]
enum AnnotationTarget {
None,
Module(Module<Bundle>),
Mem(Mem),
Target(Interned<Target>),
}
impl AnnotationTarget {
fn source_location(self) -> SourceLocation {
match self {
AnnotationTarget::None => unreachable!(),
AnnotationTarget::Module(module) => module.source_location(),
AnnotationTarget::Mem(mem) => mem.source_location(),
AnnotationTarget::Target(target) => target.base().source_location(),
}
}
}
struct PcfFileWriter<W: fmt::Write> { //TODO
output: W,
module_depth: usize,
annotation_target: AnnotationTarget,
dont_touch_targets: HashSet<Interned<Target>>,
required_dont_touch_targets: HashSet<Interned<Target>>,
}
impl<W: fmt::Write> PcfFileWriter<W> {
fn run(output: W, top_module: Module<Bundle>) -> Result<(), WritePcfContentsError> {
let mut this = Self {
output,
module_depth: 0,
annotation_target: AnnotationTarget::None,
dont_touch_targets: HashSet::default(),
required_dont_touch_targets: HashSet::default(),
};
top_module.visit(&mut this)?;
let Self {
output: _,
module_depth: _,
annotation_target: _,
dont_touch_targets,
required_dont_touch_targets,
} = this;
for &target in required_dont_touch_targets.difference(&dont_touch_targets) {
return Err(eyre::eyre!(
"a DontTouchAnnotation is required since the target is also annotated with a LatticeAnnotation:\ntarget: {target:?}\nat: {}",
target.base().source_location(),
).into());
}
Ok(())
}
fn default_visit_with<T: ?Sized + Visit<Self>>(
&mut self,
module_depth: usize,
annotation_target: AnnotationTarget,
v: &T,
) -> Result<(), WritePcfContentsError> {
let Self {
output: _,
module_depth: old_module_depth,
annotation_target: old_annotation_target,
dont_touch_targets: _,
required_dont_touch_targets: _,
} = *self;
self.module_depth = module_depth;
self.annotation_target = annotation_target;
let retval = v.default_visit(self);
self.module_depth = old_module_depth;
self.annotation_target = old_annotation_target;
retval
}
}
impl<W: fmt::Write> Visitor for PcfFileWriter<W> {
type Error = WritePcfContentsError;
fn visit_targeted_annotation(&mut self, v: &TargetedAnnotation) -> Result<(), Self::Error> {
self.default_visit_with(self.module_depth, AnnotationTarget::Target(v.target()), v)
}
fn visit_module<T: BundleType>(&mut self, v: &Module<T>) -> Result<(), Self::Error> {
self.default_visit_with(
self.module_depth + 1,
AnnotationTarget::Module(v.canonical()),
v,
)
}
fn visit_mem<Element: Type, Len: Size>(
&mut self,
v: &Mem<Element, Len>,
) -> Result<(), Self::Error>
where
Element: Visit<Self>,
{
self.default_visit_with(
self.module_depth + 1,
AnnotationTarget::Mem(v.canonical()),
v,
)
}
fn visit_dont_touch_annotation(&mut self, _v: &DontTouchAnnotation) -> Result<(), Self::Error> {
if let AnnotationTarget::Target(target) = self.annotation_target {
self.dont_touch_targets.insert(target);
}
Ok(())
}
/* FIXME fn visit_lattice_annotation(&mut self, v: &LatticeAnnotation) -> Result<(), Self::Error> */
}
impl YosysNextpnrWritePcfFile {
fn write_pcf_contents_for_port_and_annotations(
&self,
output: &mut impl fmt::Write,
port: &ScalarizedModuleABIPort,
annotations: ScalarizedModuleABIAnnotations<'_>,
) -> Result<(), WritePcfContentsError> {
/* fixme for annotation in annotations .. */
Ok(())
}
fn write_pcf_contents(
&self,
output: &mut String,
top_module: &Module<Bundle>,
) -> eyre::Result<()> {
let scalarized_module_abi =
ScalarizedModuleABI::new(top_module, self.firrtl_export_options)
.map_err(eyre::Report::from)?;
match scalarized_module_abi.for_each_port_and_annotations(|port, annotations| {
match self.write_pcf_contents_for_port_and_annotations(output, port, annotations) {
Ok(()) => ControlFlow::Continue(()),
Err(e) => ControlFlow::Break(e),
}
}) {
ControlFlow::Continue(()) => {}
ControlFlow::Break(e) => return Err(e.0),
}
PcfFileWriter::run(output, *top_module).map_err(|e| e.0)
}
}
impl JobKind for YosysNextpnrWritePcfFileJobKind {
type Args = YosysNextpnrWritePcfFileArgs;
type Job = YosysNextpnrWritePcfFile;
type Dependencies = JobKindAndDependencies<ExternalCommandJobKind<YosysNextpnrSynth>>;
fn dependencies(self) -> Self::Dependencies {
Default::default()
}
fn args_to_jobs(
args: JobArgsAndDependencies<Self>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<JobAndDependencies<Self>> {
let firrtl_export_options = args
.dependencies
.dependencies
.dependencies
.dependencies
.dependencies
.args
.args
.export_options;
args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| {
let YosysNextpnrWritePcfFileArgs {} = args;
let base_job = dependencies.get_job::<BaseJob, _>();
Ok(YosysNextpnrWritePcfFile {
firrtl_export_options,
output_dir: base_job.output_dir(),
pcf_file: base_job.file_with_ext("pcf"),
})
})
}
fn inputs(self, job: &Self::Job) -> Interned<[JobItemName]> {
[JobItemName::Path {
path: job.output_dir,
}]
.intern_slice()
}
fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> {
[JobItemName::Path { path: job.pcf_file }].intern_slice()
}
fn name(self) -> Interned<str> {
"yosys-nextpnr-ecp5-write-pcf-file".intern()
}
fn external_command_params(self, _job: &Self::Job) -> Option<CommandParams> {
None
}
fn run(
self,
job: &Self::Job,
inputs: &[JobItem],
params: &JobParams,
_global_params: &GlobalParams,
_acquired_job: &mut AcquiredJob,
) -> eyre::Result<Vec<JobItem>> {
assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job)));
let mut pcf = String::new();
job.write_pcf_contents(&mut pcf, params.main_module())?;
std::fs::write(job.pcf_file, pcf)?;
Ok(vec![JobItem::Path { path: job.pcf_file }])
}
fn subcommand_hidden(self) -> bool {
true
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct NextpnrLattice;
impl ExternalProgramTrait for NextpnrLattice {
fn default_program_name() -> Interned<str> {
"nextpnr".intern()
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
pub struct YosysNextpnrRunNextpnrArgs {
#[command(flatten)]
pub common: LatticeArgs,
#[arg(long, default_value_t = 0)]
pub nextpnr_lattice_seed: i32,
}
impl ToArgs for YosysNextpnrRunNextpnrArgs {
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
let Self {
common,
nextpnr_lattice_seed,
} = self;
common.to_args(args);
args.write_display_arg(format_args!("--nextpnr-lattice-seed={nextpnr_lattice_seed}"));
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct YosysNextpnrRunNextpnr {
device: Device,
nextpnr_lattice_seed: i32,
pcf_file: Interned<Path>,
json_file: Interned<Path>,
json_file_name: Interned<OsStr>,
routed_json_file: Interned<Path>,
routed_json_file_name: Interned<OsStr>,
textcfg_file: Interned<Path>,
textcfg_file_name: Interned<OsStr>,
}
impl ExternalCommand for YosysNextpnrRunNextpnr {
type AdditionalArgs = YosysNextpnrRunNextpnrArgs;
type AdditionalJobData = Self;
type BaseJobPosition = GetJobPositionDependencies<
GetJobPositionDependencies<<YosysNextpnrSynth as ExternalCommand>::BaseJobPosition>,
>;
type Dependencies = JobKindAndDependencies<YosysNextpnrWritePcfFileJobKind>;
type ExternalProgram = NextpnrLattice;
fn dependencies() -> Self::Dependencies {
Default::default()
}
fn args_to_jobs(
args: JobArgsAndDependencies<ExternalCommandJobKind<Self>>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(
Self::AdditionalJobData,
<Self::Dependencies as JobDependencies>::JobsAndKinds,
)> {
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
let YosysNextpnrRunNextpnrArgs {
common,
nextpnr_lattice_seed,
} = args.additional_args;
let base_job = dependencies.get_job::<BaseJob, _>();
let write_pcf_file = dependencies.get_job::<YosysNextpnrWritePcfFile, _>();
let synth = dependencies.get_job::<ExternalCommandJob<YosysNextpnrSynth>, _>();
let routed_json_file = base_job.file_with_ext("routed.json");
let textcfg_file = base_job.file_with_ext("config"); //file must exist
Ok(Self {
device: common.require_device(base_job.platform(), global_params)?,
nextpnr_lattice_seed,
pcf_file: write_pcf_file.pcf_file,
json_file: synth.additional_job_data().json_file(),
json_file_name: synth.additional_job_data().json_file_name(),
routed_json_file: routed_json_file,
routed_json_file_name: routed_json_file
.interned_file_name()
.expect("known to have file name"),
textcfg_file:textcfg_file,
textcfg_file_name: textcfg_file
.interned_file_name()
.expect("known to have file name"),
})
})
}
fn inputs(job: &ExternalCommandJob<Self>) -> Interned<[JobItemName]> {
[
JobItemName::Path {
path: job.additional_job_data().json_file,
},
JobItemName::Path {
path: job.additional_job_data().pcf_file,
},
]
.intern_slice()
}
fn output_paths(job: &ExternalCommandJob<Self>) -> Interned<[Interned<Path>]> {
[
job.additional_job_data().routed_json_file,
]
.intern_slice()
}
fn command_line_args<W: ?Sized + WriteArgs>(job: &ExternalCommandJob<Self>, args: &mut W) {
let job_data @ YosysNextpnrRunNextpnr {
nextpnr_lattice_seed,
json_file_name,
routed_json_file_name,
textcfg_file_name,
..
} = job.additional_job_data();
args.write_long_option_eq("json", json_file_name);
args.write_long_option_eq("textcfg",textcfg_file_name);
args.write_long_option_eq("write",routed_json_file_name);
args.write_arg("--85k"); //FIXME do not hardcode
args.write_long_option_eq("package","CSFBGA285");
args.write_long_option_eq("lpf","/home/alex/Hacking/FPGA/orangecrab/orangecrab-examples/fayalite/orangecrab_r0.2.1.pcf"); //just a quick test
//handwrite before adding new module, ask pj before cont
//HACK: args.write_arg("--lpf-allow-unconstrained");
//???args.write_display_arg(format_args!("--seed={nextpnr_lattice_seed}"));
//fix ERROR: failed to open LPF file '/tmp/orangecrab_r0.2.1.pcf' FIRST
}
fn current_dir(job: &ExternalCommandJob<Self>) -> Option<Interned<Path>> {
Some(job.output_dir())
}
fn job_kind_name() -> Interned<str> {
"yosys-nextpnr-ecp5-run-nextpnr".intern()
}
fn subcommand_hidden() -> bool {
true
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
pub struct YosysNextpnrArgs {
#[arg(long, env = "DB_DIR", value_hint = clap::ValueHint::DirPath)]
pub pcf1: PathBuf,
}
impl ToArgs for YosysNextpnrArgs {
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
let Self { pcf1 } = self;
args.write_long_option_eq("pcf1", pcf1);
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct YosysNextpnr {
pcf1: Interned<Path>,
device: Device,
frames_file: Interned<Path>,
frames_file_name: Interned<OsStr>,
bit_file: Interned<Path>,
bit_file_name: Interned<OsStr>,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct Ecppack;
impl ExternalProgramTrait for Ecppack {
fn default_program_name() -> Interned<str> {
"ecppack".intern()
}
}
//begin
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
pub struct YosysNextpnrRunEcpPackArgs {
#[arg(long, env = "DB_DIR", value_hint = clap::ValueHint::DirPath)]
pub placeholder_dir: PathBuf,
}
impl ToArgs for YosysNextpnrRunEcpPackArgs {
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
let Self { placeholder_dir } = self;
args.write_long_option_eq("placeholder-dir", placeholder_dir);
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
pub struct YosysNextpnrRunEcpPack {
placeholder_dir: Interned<Path>,
device: Device,
routed_json_file: Interned<Path>,
routed_json_file_name: Interned<OsStr>,
textcfg_file: Interned<Path>,
textcfg_file_name: Interned<OsStr>,
frames_file: Interned<Path>,
frames_file_name: Interned<OsStr>,
bit_file: Interned<Path>,
bit_file_name: Interned<OsStr>,
}
impl ExternalCommand for YosysNextpnrRunEcpPack {
type AdditionalArgs = YosysNextpnrRunEcpPackArgs;
type AdditionalJobData = Self;
type BaseJobPosition = GetJobPositionDependencies<
<YosysNextpnrRunNextpnr as ExternalCommand>::BaseJobPosition,
>;
type Dependencies = JobKindAndDependencies<ExternalCommandJobKind<YosysNextpnrRunNextpnr>>;
type ExternalProgram = Ecppack;
fn dependencies() -> Self::Dependencies {
Default::default()
}
fn args_to_jobs(
args: JobArgsAndDependencies<ExternalCommandJobKind<Self>>,
params: &JobParams,
global_params: &GlobalParams,
) -> eyre::Result<(
Self::AdditionalJobData,
<Self::Dependencies as JobDependencies>::JobsAndKinds,
)> {
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
let YosysNextpnrRunEcpPackArgs { placeholder_dir } = args.additional_args;
let base_job = dependencies.get_job::<BaseJob, _>();
let frames_file = base_job.file_with_ext("frames");
let bit_file = base_job.file_with_ext("bit");
Ok(Self {
placeholder_dir: placeholder_dir.intern_deref(),
device: dependencies.job.job.additional_job_data().device,
//fixme glue code
routed_json_file: dependencies.job.job.additional_job_data().routed_json_file,
routed_json_file_name: dependencies.job.job.additional_job_data().routed_json_file_name,
textcfg_file: dependencies.job.job.additional_job_data().textcfg_file,
textcfg_file_name: dependencies.job.job.additional_job_data().textcfg_file_name,
frames_file,
frames_file_name: frames_file
.interned_file_name()
.expect("known to have file name"),
bit_file,
bit_file_name: bit_file
.interned_file_name()
.expect("known to have file name"),
})
})
}
fn inputs(job: &ExternalCommandJob<Self>) -> Interned<[JobItemName]> {
[JobItemName::Path {
path: job.additional_job_data().routed_json_file,
}]
.intern_slice()
}
fn output_paths(job: &ExternalCommandJob<Self>) -> Interned<[Interned<Path>]> {
[
job.additional_job_data().bit_file,
]
.intern_slice()
}
fn command_line_args<W: ?Sized + WriteArgs>(job: &ExternalCommandJob<Self>, args: &mut W) {
let job_data @ YosysNextpnrRunEcpPack {
placeholder_dir,
device,
routed_json_file_name,
textcfg_file_name,
frames_file_name,
bit_file_name,
..
} = job.additional_job_data();
args.write_arg("--compress");
args.write_long_option_eq("freq", "38.8"); //FIXME do not hardcode
args.write_long_option_eq("input",textcfg_file_name);
args.write_long_option_eq("bit",bit_file_name);
}
fn current_dir(job: &ExternalCommandJob<Self>) -> Option<Interned<Path>> {
Some(job.output_dir())
}
fn job_kind_name() -> Interned<str> {
"yosys-nextpnr-ecp5".intern()
}
}
//end
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = DynJobKind> {
[
DynJobKind::new(YosysNextpnrWriteYsFileJobKind), //working
DynJobKind::new(ExternalCommandJobKind::<YosysNextpnrSynth>::new()), //working
DynJobKind::new(YosysNextpnrWritePcfFileJobKind), //TODO
DynJobKind::new(ExternalCommandJobKind::<YosysNextpnrRunNextpnr>::new()), //working
DynJobKind::new(ExternalCommandJobKind::<YosysNextpnrRunEcpPack>::new()), //working
]
}
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = crate::platform::DynPlatform> {
[]
}

View file

@ -595,9 +595,6 @@ 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,13 +58,11 @@ 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,
@ -78,7 +76,7 @@ impl<T: Type> Wire<T> {
self.containing_module_name_id().0
}
pub fn containing_module_name_id(&self) -> NameId {
self.name.0.unwrap_name_id()
self.name.0
}
pub fn name(&self) -> Interned<str> {
self.name_id().0

File diff suppressed because it is too large Load diff

View file

@ -1,6 +0,0 @@
<!--
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

@ -1,13 +0,0 @@
$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

@ -709,35 +709,44 @@ circuit check_enum_cmp_eq:
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:
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
match lhs: @[module-XXXXXXXXXX.rs 5:1]
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]
match rhs: @[module-XXXXXXXXXX.rs 5:1]
A:
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
B(_match_arm_value):
skip
C(_match_arm_value_1):
skip
B(_match_arm_value_2):
match rhs: @[module-XXXXXXXXXX.rs 5:1]
A:
skip
B(_match_arm_value_3):
connect TestEnum_cmp_eq, eq(_match_arm_value_2, _match_arm_value_3) @[module-XXXXXXXXXX.rs 5:1]
C(_match_arm_value_4):
skip
C(_match_arm_value_5):
match rhs: @[module-XXXXXXXXXX.rs 5:1]
A:
skip
B(_match_arm_value_6):
skip
C(_match_arm_value_7):
wire _array_literal_expr: UInt<1>[3]
connect _array_literal_expr[0], eq(_match_arm_value_5[0], _match_arm_value_7[0])
connect _array_literal_expr[1], eq(_match_arm_value_5[1], _match_arm_value_7[1])
connect _array_literal_expr[2], eq(_match_arm_value_5[2], _match_arm_value_7[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 TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
@ -755,53 +764,92 @@ circuit check_enum_cmp_eq:
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:
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
match lhs.tag: @[module-XXXXXXXXXX.rs 5:1]
A:
connect _cast_enum_to_bits_expr, UInt<2>(0)
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
A:
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
B:
skip
C:
skip
B:
connect _cast_enum_to_bits_expr, UInt<2>(1)
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
A:
skip
B:
connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
C:
skip
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]
match rhs.tag: @[module-XXXXXXXXXX.rs 5:1]
A:
skip
B:
skip
C:
wire _array_literal_expr: UInt<1>[3]
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]
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
wire _cast_bits_to_array_expr_2: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0]
connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1]
connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2]
wire _cast_bits_to_array_expr_3: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0]
connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1]
connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2]
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1])
wire _cast_bits_to_array_expr_4: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0]
connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1]
connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2]
wire _cast_bits_to_array_expr_5: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0]
connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1]
connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2]
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2])
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 TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
@ -818,36 +866,83 @@ circuit check_enum_cmp_eq:
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]
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
when eq(lhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(lhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, eq(bits(lhs.body, 7, 0), bits(rhs.body, 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
else when eq(rhs.tag, UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(rhs.tag, UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
skip
else:
wire _array_literal_expr: UInt<1>[3]
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]
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
wire _cast_bits_to_array_expr_2: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0]
connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1]
connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2]
wire _cast_bits_to_array_expr_3: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0]
connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1]
connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2]
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1])
wire _cast_bits_to_array_expr_4: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(lhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0]
connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(lhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1]
connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(lhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2]
wire _cast_bits_to_array_expr_5: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(rhs.body, 2, 0), 0, 0)
connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0]
connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(rhs.body, 2, 0), 1, 1)
connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1]
connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(rhs.body, 2, 0), 2, 2)
connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2]
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2])
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 TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
",
};
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
@ -863,36 +958,83 @@ circuit check_enum_cmp_eq:
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]
wire TestEnum_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 5:1]
when eq(bits(lhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 5:1]
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(bits(lhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
connect TestEnum_cmp_eq, eq(bits(bits(lhs, 9, 2), 7, 0), bits(bits(rhs, 9, 2), 7, 0)) @[module-XXXXXXXXXX.rs 5:1]
else when eq(bits(rhs, 1, 0), UInt<2>(0h0)): @[module-XXXXXXXXXX.rs 5:1]
skip
else when eq(bits(rhs, 1, 0), UInt<2>(0h1)): @[module-XXXXXXXXXX.rs 5:1]
skip
else:
wire _array_literal_expr: UInt<1>[3]
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]
connect _array_literal_expr[0], eq(_cast_bits_to_array_expr[0], _cast_bits_to_array_expr_1[0])
wire _cast_bits_to_array_expr_2: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_2: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_2[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_2[0], _cast_bits_to_array_expr_flattened_2[0]
connect _cast_bits_to_array_expr_flattened_2[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_flattened_2[1]
connect _cast_bits_to_array_expr_flattened_2[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_2[2], _cast_bits_to_array_expr_flattened_2[2]
wire _cast_bits_to_array_expr_3: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_3: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_3[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_3[0], _cast_bits_to_array_expr_flattened_3[0]
connect _cast_bits_to_array_expr_flattened_3[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_3[1], _cast_bits_to_array_expr_flattened_3[1]
connect _cast_bits_to_array_expr_flattened_3[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_3[2], _cast_bits_to_array_expr_flattened_3[2]
connect _array_literal_expr[1], eq(_cast_bits_to_array_expr_2[1], _cast_bits_to_array_expr_3[1])
wire _cast_bits_to_array_expr_4: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_4: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_4[0], bits(bits(bits(lhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_4[0], _cast_bits_to_array_expr_flattened_4[0]
connect _cast_bits_to_array_expr_flattened_4[1], bits(bits(bits(lhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_4[1], _cast_bits_to_array_expr_flattened_4[1]
connect _cast_bits_to_array_expr_flattened_4[2], bits(bits(bits(lhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_flattened_4[2]
wire _cast_bits_to_array_expr_5: UInt<1>[3]
wire _cast_bits_to_array_expr_flattened_5: UInt<1>[3]
connect _cast_bits_to_array_expr_flattened_5[0], bits(bits(bits(rhs, 9, 2), 2, 0), 0, 0)
connect _cast_bits_to_array_expr_5[0], _cast_bits_to_array_expr_flattened_5[0]
connect _cast_bits_to_array_expr_flattened_5[1], bits(bits(bits(rhs, 9, 2), 2, 0), 1, 1)
connect _cast_bits_to_array_expr_5[1], _cast_bits_to_array_expr_flattened_5[1]
connect _cast_bits_to_array_expr_flattened_5[2], bits(bits(bits(rhs, 9, 2), 2, 0), 2, 2)
connect _cast_bits_to_array_expr_5[2], _cast_bits_to_array_expr_flattened_5[2]
connect _array_literal_expr[2], eq(_cast_bits_to_array_expr_4[2], _cast_bits_to_array_expr_5[2])
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 TestEnum_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1]
connect eq, TestEnum_cmp_eq @[module-XXXXXXXXXX.rs 6:1]
",
};
}
@ -3637,176 +3779,20 @@ 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 @[builtin 1:1]
inst formal_reset of formal_reset @[formal.rs 185:24]
assert(clk, pred1, and(en1, not(formal_reset.rst)), "en check 1") @[module-XXXXXXXXXX.rs 9:1]
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]
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]
defname = __fayalite_formal_reset
"#,
};
@ -3939,10 +3925,21 @@ 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.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1]
connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr_1.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)
@ -3964,18 +3961,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_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)
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)
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, 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]
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]
wire _bundle_literal_expr_4: Ty1
connect _bundle_literal_expr_4.tag, {|A, B, C|}(C)
wire _cast_bundle_to_bits_expr_1: Ty9
@ -4004,18 +4001,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_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)
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)
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, 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]
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]
HdlNone:
wire _bundle_literal_expr_6: Ty5
connect _bundle_literal_expr_6.tag, {|HdlNone, HdlSome|}(HdlNone)
@ -4023,10 +4020,21 @@ 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_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1]
connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_4.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)
@ -4048,18 +4056,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_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)
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)
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, 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]
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]
wire _bundle_literal_expr_9: Ty2
connect _bundle_literal_expr_9.tag, {|A, B, C|}(C)
wire _cast_bundle_to_bits_expr_3: Ty9
@ -4126,10 +4134,16 @@ 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.body, 1, 0)) @[module-XXXXXXXXXX.rs 8:1]
connect __connect_variant_body_2, asSInt(bits(_cast_bits_to_bundle_expr_1.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)
@ -4145,13 +4159,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_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 _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 _bundle_literal_expr_4: Ty0
connect _bundle_literal_expr_4.tag, UInt<2>(0h2)
wire _cast_bundle_to_bits_expr_1: Ty4
@ -4173,23 +4187,29 @@ 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_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 _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 _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_2.body, 0, 0)) @[module-XXXXXXXXXX.rs 9:1]
connect __connect_variant_body_6, asSInt(bits(_cast_bits_to_bundle_expr_4.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)
@ -4205,13 +4225,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_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 _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 _bundle_literal_expr_9: Ty1
connect _bundle_literal_expr_9.tag, UInt<2>(0h2)
wire _cast_bundle_to_bits_expr_3: Ty4
@ -4863,20 +4883,34 @@ 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 _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]
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]
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, not(eq(test_struct_2_lhs.v, test_struct_2_rhs.v)) @[module-XXXXXXXXXX.rs 19: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_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1]
connect test_struct_3_cmp_ne, not(UInt<1>(0h1)) @[module-XXXXXXXXXX.rs 25:1]
connect test_struct_3_cmp_ne, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 25:1]
",
};
}

View file

@ -5,7 +5,6 @@ use bitvec::{order::Lsb0, view::BitView};
use fayalite::{
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,
@ -17,12 +16,7 @@ use fayalite::{
ty::SimValueDebug,
util::{RcWriter, ready_valid::queue},
};
use std::{
collections::BTreeMap,
num::NonZeroUsize,
panic::{AssertUnwindSafe, catch_unwind, resume_unwind},
rc::Rc,
};
use std::{collections::BTreeMap, num::NonZeroUsize, rc::Rc};
#[hdl_module(outline_generated)]
pub fn connect_const() {
@ -3616,200 +3610,3 @@ circuit sim_trace_as_string: %[[
",
};
}
#[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,7 +419,6 @@ Simulation {
},
pc: 38,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -498,7 +497,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1761,6 +1759,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -76,7 +76,6 @@ Simulation {
},
pc: 5,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -102,7 +101,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -188,6 +186,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -54,7 +54,6 @@ Simulation {
},
pc: 2,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -78,7 +77,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -140,6 +138,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -80,7 +80,6 @@ Simulation {
},
pc: 5,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -107,7 +106,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -208,6 +206,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -180,7 +180,6 @@ Simulation {
},
pc: 19,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -217,7 +216,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -387,6 +385,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -162,7 +162,6 @@ Simulation {
},
pc: 16,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -198,7 +197,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -368,6 +366,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -72,7 +72,6 @@ Simulation {
},
pc: 4,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -98,7 +97,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [],
uninitialized_ios: {},
@ -171,6 +169,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -409,7 +409,6 @@ Simulation {
},
pc: 45,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -466,7 +465,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -747,6 +745,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1184,7 +1184,6 @@ Simulation {
},
pc: 133,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -1325,7 +1324,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1957,6 +1955,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -44,7 +44,6 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -68,7 +67,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -263,6 +261,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -48,7 +48,6 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -73,7 +72,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -418,6 +416,5 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -407,7 +407,6 @@ Simulation {
},
pc: 44,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -465,7 +464,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -707,6 +705,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -2728,7 +2728,6 @@ Simulation {
},
pc: 256,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -3184,7 +3183,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -7929,6 +7927,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -494,7 +494,6 @@ Simulation {
},
pc: 41,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -580,7 +579,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1652,6 +1650,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -526,7 +526,6 @@ Simulation {
},
pc: 52,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -608,7 +607,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1287,6 +1285,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1336,7 +1336,6 @@ Simulation {
},
pc: 129,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1496,7 +1495,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -3347,6 +3345,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -187,7 +187,6 @@ Simulation {
},
pc: 17,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -226,7 +225,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -579,6 +577,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -172,7 +172,6 @@ Simulation {
},
pc: 16,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -216,7 +215,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -529,6 +527,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1083,7 +1083,6 @@ Simulation {
},
pc: 134,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1202,7 +1201,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2162,6 +2160,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1064,7 +1064,6 @@ Simulation {
},
pc: 132,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1181,7 +1180,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2141,6 +2139,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1093,7 +1093,6 @@ Simulation {
},
pc: 136,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1212,7 +1211,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2172,6 +2170,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1074,7 +1074,6 @@ Simulation {
},
pc: 134,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1191,7 +1190,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2151,6 +2149,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1098,7 +1098,6 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1220,7 +1219,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2180,6 +2178,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1079,7 +1079,6 @@ Simulation {
},
pc: 133,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1199,7 +1198,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2159,6 +2157,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1108,7 +1108,6 @@ Simulation {
},
pc: 137,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1230,7 +1229,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2190,6 +2188,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1089,7 +1089,6 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1209,7 +1208,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2169,6 +2167,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1125,7 +1125,6 @@ Simulation {
},
pc: 139,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1249,7 +1248,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2189,6 +2187,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1106,7 +1106,6 @@ Simulation {
},
pc: 137,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1228,7 +1227,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2168,6 +2166,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1135,7 +1135,6 @@ Simulation {
},
pc: 141,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1259,7 +1258,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2199,6 +2197,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1116,7 +1116,6 @@ Simulation {
},
pc: 139,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1238,7 +1237,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2178,6 +2176,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1104,7 +1104,6 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1228,7 +1227,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2188,6 +2186,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1085,7 +1085,6 @@ Simulation {
},
pc: 133,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1207,7 +1206,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2167,6 +2165,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1114,7 +1114,6 @@ Simulation {
},
pc: 137,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1238,7 +1237,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2198,6 +2196,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1095,7 +1095,6 @@ Simulation {
},
pc: 135,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -1217,7 +1216,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2177,6 +2175,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -636,7 +636,6 @@ Simulation {
},
pc: 69,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -726,7 +725,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1792,6 +1790,5 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -254,7 +254,6 @@ Simulation {
},
pc: 34,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -294,7 +293,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -547,6 +545,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -60,7 +60,6 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -88,7 +87,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -523,6 +521,5 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -60,7 +60,6 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -88,7 +87,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -523,6 +521,5 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -375,7 +375,6 @@ Simulation {
},
pc: 41,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -476,7 +475,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -1770,6 +1768,5 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -512,7 +512,6 @@ Simulation {
},
pc: 57,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -592,7 +591,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -9728,6 +9726,5 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -48,7 +48,6 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -73,7 +72,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -541,6 +539,5 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -48,7 +48,6 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -73,7 +72,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -541,6 +539,5 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -48,7 +48,6 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -73,7 +72,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -499,6 +497,5 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -48,7 +48,6 @@ Simulation {
},
pc: 0,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
@ -73,7 +72,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -499,6 +497,5 @@ Simulation {
},
),
},
asserts: [],
..
}

View file

@ -494,7 +494,6 @@ Simulation {
},
pc: 43,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [
MemoryData {
@ -571,7 +570,6 @@ Simulation {
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
@ -2252,6 +2250,5 @@ Simulation {
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1,522 +0,0 @@
Simulation {
state: State {
insns: Insns {
state_layout: StateLayout {
ty: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 2,
debug_data: [
SlotDebugData {
name: "",
ty: Enum {
HdlNone,
HdlSome,
},
},
SlotDebugData {
name: "",
ty: Enum {
HdlNone,
HdlSome,
},
},
],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 13,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::a",
ty: Enum {
HdlNone,
HdlSome(UInt<2>),
},
},
SlotDebugData {
name: "",
ty: UInt<3>,
},
SlotDebugData {
name: "",
ty: UInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::b",
ty: Enum {
HdlNone,
HdlSome(UInt<2>),
},
},
SlotDebugData {
name: "",
ty: UInt<3>,
},
SlotDebugData {
name: "",
ty: UInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::eq",
ty: Bool,
},
SlotDebugData {
name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::structural_eq",
ty: Bool,
},
SlotDebugData {
name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::bit_eq",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
],
..
},
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>(10), // (0x1) SlotDebugData { name: "", ty: Bool },
value: 0x1,
},
1: Const {
dest: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
value: 0x0,
},
2: Copy {
dest: StatePartIndex<BigSlots>(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
src: StatePartIndex<BigSlots>(3), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::b", ty: Enum {HdlNone, HdlSome(UInt<2>)} },
},
3: SliceInt {
dest: StatePartIndex<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
src: StatePartIndex<BigSlots>(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
start: 1,
len: 2,
},
// at: module-XXXXXXXXXX.rs:3:1
4: AndBigWithSmallImmediate {
dest: StatePartIndex<SmallSlots>(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
lhs: StatePartIndex<BigSlots>(3), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::b", ty: Enum {HdlNone, HdlSome(UInt<2>)} },
rhs: 0x1,
},
// at: module-XXXXXXXXXX.rs:1:1
5: Copy {
dest: StatePartIndex<BigSlots>(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
src: StatePartIndex<BigSlots>(0), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::a", ty: Enum {HdlNone, HdlSome(UInt<2>)} },
},
6: SliceInt {
dest: StatePartIndex<BigSlots>(2), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
src: StatePartIndex<BigSlots>(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
start: 1,
len: 2,
},
7: CmpEq {
dest: StatePartIndex<BigSlots>(11), // (0x1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(2), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
rhs: StatePartIndex<BigSlots>(5), // (0x3) SlotDebugData { name: "", ty: UInt<2> },
},
8: CmpEq {
dest: StatePartIndex<BigSlots>(12), // (0x1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(1), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
rhs: StatePartIndex<BigSlots>(4), // (0x7) SlotDebugData { name: "", ty: UInt<3> },
},
// at: module-XXXXXXXXXX.rs:9:1
9: Copy {
dest: StatePartIndex<BigSlots>(8), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::bit_eq", ty: Bool },
src: StatePartIndex<BigSlots>(12), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:2:1
10: AndBigWithSmallImmediate {
dest: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
lhs: StatePartIndex<BigSlots>(0), // (0x7) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::a", ty: Enum {HdlNone, HdlSome(UInt<2>)} },
rhs: 0x1,
},
// at: module-XXXXXXXXXX.rs:1:1
11: BranchIfSmallNeImmediate {
target: 14,
lhs: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
rhs: 0x0,
},
12: BranchIfSmallNeImmediate {
target: 14,
lhs: StatePartIndex<SmallSlots>(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
rhs: 0x0,
},
13: Copy {
dest: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(10), // (0x1) SlotDebugData { name: "", ty: Bool },
},
14: BranchIfSmallNeImmediate {
target: 17,
lhs: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
rhs: 0x1,
},
15: BranchIfSmallNeImmediate {
target: 17,
lhs: StatePartIndex<SmallSlots>(1), // (0x1 1) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} },
rhs: 0x1,
},
16: Copy {
dest: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(11), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:7:1
17: Copy {
dest: StatePartIndex<BigSlots>(6), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::eq", ty: Bool },
src: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:8:1
18: Copy {
dest: StatePartIndex<BigSlots>(7), // (0x1) SlotDebugData { name: "InstantiatedModule(enum_structural_eq: enum_structural_eq).enum_structural_eq::structural_eq", ty: Bool },
src: StatePartIndex<BigSlots>(9), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:1:1
19: Return,
],
..
},
pc: 19,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
small_slots: StatePart {
value: [
1,
1,
],
},
big_slots: StatePart {
value: [
7,
7,
3,
7,
7,
3,
1,
1,
1,
1,
1,
1,
1,
],
},
sim_only_slots: StatePart {
value: [],
},
},
io: Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
},
global_io: {},
main_module: SimulationModuleState {
base_targets: [
Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
}.a,
Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
}.b,
Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
}.eq,
Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
}.structural_eq,
Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
}.bit_eq,
],
uninitialized_ios: {},
io_targets: {
Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
}.a,
Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
}.b,
Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
}.bit_eq,
Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
}.eq,
Instance {
name: <simulator>::enum_structural_eq,
instantiated: Module {
name: enum_structural_eq,
..
},
}.structural_eq,
},
did_initial_settle: true,
clocks_for_past: {},
},
extern_modules: [],
trace_decls: TraceModule {
name: "enum_structural_eq",
children: [
TraceModuleIO {
name: "a",
child: TraceEnumWithFields {
name: "a",
discriminant: TraceEnumDiscriminant {
location: TraceScalarId(0),
name: "$tag",
ty: Enum {
HdlNone,
HdlSome(UInt<2>),
},
flow: Source,
},
non_empty_fields: [
TraceUInt {
location: TraceScalarId(1),
name: "HdlSome",
ty: UInt<2>,
flow: Source,
},
],
ty: Enum {
HdlNone,
HdlSome(UInt<2>),
},
flow: Source,
},
ty: Enum {
HdlNone,
HdlSome(UInt<2>),
},
flow: Source,
},
TraceModuleIO {
name: "b",
child: TraceEnumWithFields {
name: "b",
discriminant: TraceEnumDiscriminant {
location: TraceScalarId(2),
name: "$tag",
ty: Enum {
HdlNone,
HdlSome(UInt<2>),
},
flow: Source,
},
non_empty_fields: [
TraceUInt {
location: TraceScalarId(3),
name: "HdlSome",
ty: UInt<2>,
flow: Source,
},
],
ty: Enum {
HdlNone,
HdlSome(UInt<2>),
},
flow: Source,
},
ty: Enum {
HdlNone,
HdlSome(UInt<2>),
},
flow: Source,
},
TraceModuleIO {
name: "eq",
child: TraceBool {
location: TraceScalarId(4),
name: "eq",
flow: Sink,
},
ty: Bool,
flow: Sink,
},
TraceModuleIO {
name: "structural_eq",
child: TraceBool {
location: TraceScalarId(5),
name: "structural_eq",
flow: Sink,
},
ty: Bool,
flow: Sink,
},
TraceModuleIO {
name: "bit_eq",
child: TraceBool {
location: TraceScalarId(6),
name: "bit_eq",
flow: Sink,
},
ty: Bool,
flow: Sink,
},
],
},
traces: [
SimTrace {
id: TraceScalarId(0),
kind: EnumDiscriminant {
index: StatePartIndex<SmallSlots>(0),
ty: Enum {
HdlNone,
HdlSome(UInt<2>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x1,
},
SimTrace {
id: TraceScalarId(1),
kind: BigUInt {
index: StatePartIndex<BigSlots>(2),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x3,
},
SimTrace {
id: TraceScalarId(2),
kind: EnumDiscriminant {
index: StatePartIndex<SmallSlots>(1),
ty: Enum {
HdlNone,
HdlSome(UInt<2>),
},
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(3),
kind: BigUInt {
index: StatePartIndex<BigSlots>(5),
ty: UInt<2>,
},
maybe_changed: true,
state: 0x3,
last_state: 0x3,
},
SimTrace {
id: TraceScalarId(4),
kind: BigBool {
index: StatePartIndex<BigSlots>(6),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(5),
kind: BigBool {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(6),
kind: BigBool {
index: StatePartIndex<BigSlots>(8),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
],
trace_memories: {},
trace_writers: [
Running(
VcdWriter {
finished_init: true,
timescale: 1 ps,
..
},
),
],
clocks_triggered: [],
event_queue: EventQueue(EventQueueData {
instant: 64 μs,
events: {},
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [],
..
}

View file

@ -1,282 +0,0 @@
$timescale 1 ps $end
$scope module enum_structural_eq $end
$scope struct a $end
$var string 1 +LxwI \$tag $end
$var wire 2 {bf!u HdlSome $end
$upscope $end
$scope struct b $end
$var string 1 O%@#" \$tag $end
$var wire 2 ]xpB, HdlSome $end
$upscope $end
$var wire 1 Yp4xI eq $end
$var wire 1 >R/<6 structural_eq $end
$var wire 1 ,}=e] bit_eq $end
$upscope $end
$enddefinitions $end
$dumpvars
sHdlNone\x20(0) +LxwI
b0 {bf!u
sHdlNone\x20(0) O%@#"
b0 ]xpB,
1Yp4xI
1>R/<6
1,}=e]
$end
#1000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
0,}=e]
#2000000
sHdlNone\x20(0) O%@#"
b1 ]xpB,
1Yp4xI
1>R/<6
#3000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#4000000
sHdlNone\x20(0) O%@#"
b10 ]xpB,
1Yp4xI
1>R/<6
#5000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#6000000
sHdlNone\x20(0) O%@#"
b11 ]xpB,
1Yp4xI
1>R/<6
#7000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#8000000
sHdlSome\x20(1) +LxwI
sHdlNone\x20(0) O%@#"
b0 ]xpB,
#9000000
sHdlSome\x20(1) O%@#"
1Yp4xI
1>R/<6
1,}=e]
#10000000
sHdlNone\x20(0) O%@#"
b1 ]xpB,
0Yp4xI
0>R/<6
0,}=e]
#11000000
sHdlSome\x20(1) O%@#"
#12000000
sHdlNone\x20(0) O%@#"
b10 ]xpB,
#13000000
sHdlSome\x20(1) O%@#"
#14000000
sHdlNone\x20(0) O%@#"
b11 ]xpB,
#15000000
sHdlSome\x20(1) O%@#"
#16000000
sHdlNone\x20(0) +LxwI
b1 {bf!u
sHdlNone\x20(0) O%@#"
b0 ]xpB,
1Yp4xI
1>R/<6
#17000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#18000000
sHdlNone\x20(0) O%@#"
b1 ]xpB,
1Yp4xI
1>R/<6
1,}=e]
#19000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
0,}=e]
#20000000
sHdlNone\x20(0) O%@#"
b10 ]xpB,
1Yp4xI
1>R/<6
#21000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#22000000
sHdlNone\x20(0) O%@#"
b11 ]xpB,
1Yp4xI
1>R/<6
#23000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#24000000
sHdlSome\x20(1) +LxwI
sHdlNone\x20(0) O%@#"
b0 ]xpB,
#25000000
sHdlSome\x20(1) O%@#"
#26000000
sHdlNone\x20(0) O%@#"
b1 ]xpB,
#27000000
sHdlSome\x20(1) O%@#"
1Yp4xI
1>R/<6
1,}=e]
#28000000
sHdlNone\x20(0) O%@#"
b10 ]xpB,
0Yp4xI
0>R/<6
0,}=e]
#29000000
sHdlSome\x20(1) O%@#"
#30000000
sHdlNone\x20(0) O%@#"
b11 ]xpB,
#31000000
sHdlSome\x20(1) O%@#"
#32000000
sHdlNone\x20(0) +LxwI
b10 {bf!u
sHdlNone\x20(0) O%@#"
b0 ]xpB,
1Yp4xI
1>R/<6
#33000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#34000000
sHdlNone\x20(0) O%@#"
b1 ]xpB,
1Yp4xI
1>R/<6
#35000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#36000000
sHdlNone\x20(0) O%@#"
b10 ]xpB,
1Yp4xI
1>R/<6
1,}=e]
#37000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
0,}=e]
#38000000
sHdlNone\x20(0) O%@#"
b11 ]xpB,
1Yp4xI
1>R/<6
#39000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#40000000
sHdlSome\x20(1) +LxwI
sHdlNone\x20(0) O%@#"
b0 ]xpB,
#41000000
sHdlSome\x20(1) O%@#"
#42000000
sHdlNone\x20(0) O%@#"
b1 ]xpB,
#43000000
sHdlSome\x20(1) O%@#"
#44000000
sHdlNone\x20(0) O%@#"
b10 ]xpB,
#45000000
sHdlSome\x20(1) O%@#"
1Yp4xI
1>R/<6
1,}=e]
#46000000
sHdlNone\x20(0) O%@#"
b11 ]xpB,
0Yp4xI
0>R/<6
0,}=e]
#47000000
sHdlSome\x20(1) O%@#"
#48000000
sHdlNone\x20(0) +LxwI
b11 {bf!u
sHdlNone\x20(0) O%@#"
b0 ]xpB,
1Yp4xI
1>R/<6
#49000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#50000000
sHdlNone\x20(0) O%@#"
b1 ]xpB,
1Yp4xI
1>R/<6
#51000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#52000000
sHdlNone\x20(0) O%@#"
b10 ]xpB,
1Yp4xI
1>R/<6
#53000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
#54000000
sHdlNone\x20(0) O%@#"
b11 ]xpB,
1Yp4xI
1>R/<6
1,}=e]
#55000000
sHdlSome\x20(1) O%@#"
0Yp4xI
0>R/<6
0,}=e]
#56000000
sHdlSome\x20(1) +LxwI
sHdlNone\x20(0) O%@#"
b0 ]xpB,
#57000000
sHdlSome\x20(1) O%@#"
#58000000
sHdlNone\x20(0) O%@#"
b1 ]xpB,
#59000000
sHdlSome\x20(1) O%@#"
#60000000
sHdlNone\x20(0) O%@#"
b10 ]xpB,
#61000000
sHdlSome\x20(1) O%@#"
#62000000
sHdlNone\x20(0) O%@#"
b11 ]xpB,
#63000000
sHdlSome\x20(1) O%@#"
1Yp4xI
1>R/<6
1,}=e]
#64000000

View file

@ -1,855 +0,0 @@
Simulation {
state: State {
insns: Insns {
state_layout: StateLayout {
ty: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 5,
debug_data: [
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 26,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count",
ty: UInt<8>,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::enable_assert",
ty: Bool,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::any_seq_out",
ty: UInt<16>,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.clk",
ty: Clock,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.rst",
ty: SyncReset,
},
SlotDebugData {
name: ".clk",
ty: Clock,
},
SlotDebugData {
name: ".rst",
ty: SyncReset,
},
SlotDebugData {
name: "<<Global>>::formal_global_clock",
ty: Clock,
},
SlotDebugData {
name: "<<Global>>::formal_reset",
ty: SyncReset,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg",
ty: UInt<8>,
},
SlotDebugData {
name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<9>,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "<<Global>>::any_seq",
ty: UInt<16>,
},
],
..
},
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:15:1
0: Copy {
dest: StatePartIndex<BigSlots>(2), // (0x4d2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::any_seq_out", ty: UInt<16> },
src: StatePartIndex<BigSlots>(25), // (0x4d2) SlotDebugData { name: "<<Global>>::any_seq", ty: UInt<16> },
},
// at: module-XXXXXXXXXX.rs:1:1
1: Copy {
dest: StatePartIndex<BigSlots>(19), // (0x0) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(8), // (0x0) SlotDebugData { name: "<<Global>>::formal_reset", ty: SyncReset },
},
2: NotU {
dest: StatePartIndex<BigSlots>(20), // (0x1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(19), // (0x0) SlotDebugData { name: "", ty: Bool },
width: 1,
},
3: Const {
dest: StatePartIndex<BigSlots>(18), // (0x1) SlotDebugData { name: "", ty: Bool },
value: 0x1,
},
4: And {
dest: StatePartIndex<BigSlots>(21), // (0x1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(18), // (0x1) SlotDebugData { name: "", ty: Bool },
rhs: StatePartIndex<BigSlots>(20), // (0x1) SlotDebugData { name: "", ty: Bool },
},
5: NotU {
dest: StatePartIndex<BigSlots>(22), // (0x0) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(21), // (0x1) SlotDebugData { name: "", ty: Bool },
width: 1,
},
// at: module-XXXXXXXXXX.rs:12:1
6: Copy {
dest: StatePartIndex<BigSlots>(24), // (0x1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(18), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:9:1
7: Copy {
dest: StatePartIndex<BigSlots>(0), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count", ty: UInt<8> },
src: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:1:1
8: Const {
dest: StatePartIndex<BigSlots>(14), // (0xa) SlotDebugData { name: "", ty: UInt<8> },
value: 0xa,
},
9: CmpLe {
dest: StatePartIndex<BigSlots>(17), // (0x1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
rhs: StatePartIndex<BigSlots>(14), // (0xa) SlotDebugData { name: "", ty: UInt<8> },
},
10: Or {
dest: StatePartIndex<BigSlots>(23), // (0x1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(17), // (0x1) SlotDebugData { name: "", ty: Bool },
rhs: StatePartIndex<BigSlots>(22), // (0x0) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:11:1
11: BranchIfZero {
target: 13,
value: StatePartIndex<BigSlots>(1), // (0x1) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::enable_assert", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:12:1
12: Copy {
dest: StatePartIndex<BigSlots>(24), // (0x1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(23), // (0x1) SlotDebugData { name: "", ty: Bool },
},
13: IsNonZeroDestIsSmall {
dest: StatePartIndex<SmallSlots>(4), // (0x1 1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(24), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:1:1
14: Const {
dest: StatePartIndex<BigSlots>(12), // (0x1) SlotDebugData { name: "", ty: UInt<8> },
value: 0x1,
},
15: Add {
dest: StatePartIndex<BigSlots>(13), // (0x3) SlotDebugData { name: "", ty: UInt<9> },
lhs: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
rhs: StatePartIndex<BigSlots>(12), // (0x1) SlotDebugData { name: "", ty: UInt<8> },
},
16: CmpLt {
dest: StatePartIndex<BigSlots>(15), // (0x1) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(13), // (0x3) SlotDebugData { name: "", ty: UInt<9> },
rhs: StatePartIndex<BigSlots>(14), // (0xa) SlotDebugData { name: "", ty: UInt<8> },
},
17: CastToUInt {
dest: StatePartIndex<BigSlots>(16), // (0x3) SlotDebugData { name: "", ty: UInt<8> },
src: StatePartIndex<BigSlots>(13), // (0x3) SlotDebugData { name: "", ty: UInt<9> },
dest_width: 8,
},
// at: module-XXXXXXXXXX.rs:4:1
18: Copy {
dest: StatePartIndex<BigSlots>(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> },
src: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:5:1
19: BranchIfZero {
target: 21,
value: StatePartIndex<BigSlots>(15), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:6:1
20: Copy {
dest: StatePartIndex<BigSlots>(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> },
src: StatePartIndex<BigSlots>(16), // (0x3) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:1:1
21: Const {
dest: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
value: 0x0,
},
// at: module-XXXXXXXXXX.rs:5:1
22: BranchIfNonZero {
target: 24,
value: StatePartIndex<BigSlots>(15), // (0x1) SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX.rs:7:1
23: Copy {
dest: StatePartIndex<BigSlots>(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> },
src: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:1:1
24: Copy {
dest: StatePartIndex<BigSlots>(5), // (0x1) SlotDebugData { name: ".clk", ty: Clock },
src: StatePartIndex<BigSlots>(7), // (0x1) SlotDebugData { name: "<<Global>>::formal_global_clock", ty: Clock },
},
25: Copy {
dest: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset },
src: StatePartIndex<BigSlots>(8), // (0x0) SlotDebugData { name: "<<Global>>::formal_reset", ty: SyncReset },
},
// at: module-XXXXXXXXXX.rs:3:1
26: Copy {
dest: StatePartIndex<BigSlots>(3), // (0x1) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.clk", ty: Clock },
src: StatePartIndex<BigSlots>(5), // (0x1) SlotDebugData { name: ".clk", ty: Clock },
},
27: Copy {
dest: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.rst", ty: SyncReset },
src: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset },
},
// at: module-XXXXXXXXXX.rs:4:1
28: IsNonZeroDestIsSmall {
dest: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(3), // (0x1) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.clk", ty: Clock },
},
29: AndSmall {
dest: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
rhs: StatePartIndex<SmallSlots>(0), // (0x0 0) SlotDebugData { name: "", ty: Bool },
},
30: IsNonZeroDestIsSmall {
dest: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
src: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::cd.rst", ty: SyncReset },
},
31: BranchIfSmallZero {
target: 36,
value: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
},
32: BranchIfSmallNonZero {
target: 35,
value: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
},
33: Copy {
dest: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
src: StatePartIndex<BigSlots>(10), // (0x3) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg$next", ty: UInt<8> },
},
34: Branch {
target: 36,
},
35: Copy {
dest: StatePartIndex<BigSlots>(9), // (0x2) SlotDebugData { name: "InstantiatedModule(formal_counter: formal_counter).formal_counter::count_reg", ty: UInt<8> },
src: StatePartIndex<BigSlots>(11), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:12:1
36: Assert {
clk_triggered: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
pred: StatePartIndex<SmallSlots>(4), // (0x1 1) SlotDebugData { name: "", ty: Bool },
assert_index: 0,
},
// at: module-XXXXXXXXXX.rs:4:1
37: XorSmallImmediate {
dest: StatePartIndex<SmallSlots>(0), // (0x0 0) SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<SmallSlots>(2), // (0x1 1) SlotDebugData { name: "", ty: Bool },
rhs: 0x1,
},
// at: module-XXXXXXXXXX.rs:1:1
38: Return,
],
..
},
pc: 38,
memory_write_log: [],
assert_failed_log: [],
memories: StatePart {
value: [],
},
small_slots: StatePart {
value: [
0,
0,
1,
0,
1,
],
},
big_slots: StatePart {
value: [
2,
1,
1234,
1,
0,
1,
0,
1,
0,
2,
3,
0,
1,
3,
10,
1,
3,
1,
1,
0,
1,
1,
0,
1,
1,
1234,
],
},
sim_only_slots: StatePart {
value: [],
},
},
io: Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
},
global_io: {
SimIoForGlobal(
formal_global_clock,
): CompiledValue {
layout: CompiledTypeLayout {
ty: Clock,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "<<Global>>::formal_global_clock",
ty: Clock,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 7, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
},
write: None,
},
SimIoForGlobal(
formal_reset,
): CompiledValue {
layout: CompiledTypeLayout {
ty: SyncReset,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "<<Global>>::formal_reset",
ty: SyncReset,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 8, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
},
write: None,
},
SimIoForGlobal(
any_seq(
UInt<16>,
),
): CompiledValue {
layout: CompiledTypeLayout {
ty: UInt<16>,
layout: TypeLayout {
small_slots: StatePartLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "<<Global>>::any_seq",
ty: UInt<16>,
},
],
..
},
sim_only_slots: StatePartLayout<SimOnlySlots> {
len: 0,
debug_data: [],
layout_data: [],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 5, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 25, len: 1 },
sim_only_slots: StatePartIndexRange<SimOnlySlots> { start: 0, len: 0 },
},
write: None,
},
},
main_module: SimulationModuleState {
base_targets: [
SimIoForGlobal(
formal_global_clock,
),
SimIoForGlobal(
formal_reset,
),
SimIoForGlobal(
any_seq(
UInt<16>,
),
),
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.count,
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.enable_assert,
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.any_seq_out,
],
uninitialized_ios: {},
io_targets: {
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.any_seq_out,
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.count,
Instance {
name: <simulator>::formal_counter,
instantiated: Module {
name: formal_counter,
..
},
}.enable_assert,
SimIoForGlobal(
any_seq(
UInt<16>,
),
),
SimIoForGlobal(
formal_global_clock,
),
SimIoForGlobal(
formal_reset,
),
},
did_initial_settle: true,
clocks_for_past: {},
},
extern_modules: [],
trace_decls: TraceModule {
name: "formal_counter",
children: [
TraceFormalInput {
name: "formal_global_clock",
child: TraceClock {
location: TraceScalarId(5),
name: "formal_global_clock",
flow: Source,
},
formal_input: formal_global_clock,
},
TraceFormalInput {
name: "formal_reset",
child: TraceSyncReset {
location: TraceScalarId(6),
name: "formal_reset",
flow: Source,
},
formal_input: formal_reset,
},
TraceFormalInput {
name: "any_seq",
child: TraceUInt {
location: TraceScalarId(8),
name: "any_seq",
ty: UInt<16>,
flow: Source,
},
formal_input: any_seq(
UInt<16>,
),
},
TraceModuleIO {
name: "count",
child: TraceUInt {
location: TraceScalarId(0),
name: "count",
ty: UInt<8>,
flow: Sink,
},
ty: UInt<8>,
flow: Sink,
},
TraceModuleIO {
name: "enable_assert",
child: TraceBool {
location: TraceScalarId(1),
name: "enable_assert",
flow: Source,
},
ty: Bool,
flow: Source,
},
TraceModuleIO {
name: "any_seq_out",
child: TraceUInt {
location: TraceScalarId(2),
name: "any_seq_out",
ty: UInt<16>,
flow: Sink,
},
ty: UInt<16>,
flow: Sink,
},
TraceWire {
name: "cd",
child: TraceBundle {
name: "cd",
fields: [
TraceClock {
location: TraceScalarId(3),
name: "clk",
flow: Duplex,
},
TraceSyncReset {
location: TraceScalarId(4),
name: "rst",
flow: Duplex,
},
],
ty: Bundle {
/* offset = 0 */
clk: Clock,
/* offset = 1 */
rst: SyncReset,
},
flow: Duplex,
},
ty: Bundle {
/* offset = 0 */
clk: Clock,
/* offset = 1 */
rst: SyncReset,
},
},
TraceReg {
name: "count_reg",
child: TraceUInt {
location: TraceScalarId(7),
name: "count_reg",
ty: UInt<8>,
flow: Duplex,
},
ty: UInt<8>,
},
],
},
traces: [
SimTrace {
id: TraceScalarId(0),
kind: BigUInt {
index: StatePartIndex<BigSlots>(0),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x02,
last_state: 0x01,
},
SimTrace {
id: TraceScalarId(1),
kind: BigBool {
index: StatePartIndex<BigSlots>(1),
},
maybe_changed: false,
state: 0x1,
last_state: 0x1,
},
SimTrace {
id: TraceScalarId(2),
kind: BigUInt {
index: StatePartIndex<BigSlots>(2),
ty: UInt<16>,
},
maybe_changed: true,
state: 0x04d2,
last_state: 0x04d2,
},
SimTrace {
id: TraceScalarId(3),
kind: BigClock {
index: StatePartIndex<BigSlots>(3),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(4),
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(4),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(5),
kind: BigClock {
index: StatePartIndex<BigSlots>(7),
},
maybe_changed: true,
state: 0x1,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(6),
kind: BigSyncReset {
index: StatePartIndex<BigSlots>(8),
},
maybe_changed: true,
state: 0x0,
last_state: 0x0,
},
SimTrace {
id: TraceScalarId(7),
kind: BigUInt {
index: StatePartIndex<BigSlots>(9),
ty: UInt<8>,
},
maybe_changed: true,
state: 0x02,
last_state: 0x01,
},
SimTrace {
id: TraceScalarId(8),
kind: BigUInt {
index: StatePartIndex<BigSlots>(25),
ty: UInt<16>,
},
maybe_changed: true,
state: 0x04d2,
last_state: 0x04d2,
},
],
trace_memories: {},
trace_writers: [
Running(
VcdWriter {
finished_init: true,
timescale: 1 ps,
..
},
),
],
clocks_triggered: [
StatePartIndex<SmallSlots>(1),
],
event_queue: EventQueue(EventQueueData {
instant: 66 μs,
events: {},
}),
waiting_sensitivity_sets_by_address: {},
waiting_sensitivity_sets_by_compiled_value: {},
asserts: [
CompiledAssert {
instantiated_module: InstantiatedModule(formal_counter: formal_counter),
stmt_formal: assert {
clk: Wire(formal_counter::cd: Bundle {
/* offset = 0 */
clk: Clock,
/* offset = 1 */
rst: SyncReset,
}).clk,
pred: CmpLeU {
lhs: Reg {
name: formal_counter::count_reg,
ty: UInt<8>,
clock_domain: Wire(formal_counter::cd: Bundle {
/* offset = 0 */
clk: Clock,
/* offset = 1 */
rst: SyncReset,
}),
init: Some(
0x0_u8,
),
..
},
rhs: 0xA_u8,
literal_bits: Err(
NotALiteralExpr,
),
},
en: BitAndB {
lhs: true,
rhs: NotB {
arg: CastSyncResetToBool {
arg: formal_reset,
literal_bits: Err(
NotALiteralExpr,
),
},
literal_bits: Err(
NotALiteralExpr,
),
},
literal_bits: Err(
NotALiteralExpr,
),
},
text: "",
..
},
},
],
..
}

View file

@ -1,290 +0,0 @@
$timescale 1 ps $end
$scope module formal_counter $end
$var wire 1 ekAK2 formal_global_clock $end
$var wire 1 qTY9h formal_reset $end
$var wire 16 /roOY any_seq $end
$var wire 8 }eN0d count $end
$var wire 1 2f=;S enable_assert $end
$var wire 16 L-uG? any_seq_out $end
$scope struct cd $end
$var wire 1 -e"5` clk $end
$var wire 1 IC0;$ rst $end
$upscope $end
$var reg 8 ^:T_4 count_reg $end
$upscope $end
$enddefinitions $end
$dumpvars
b0 }eN0d
12f=;S
b0 L-uG?
0-e"5`
1IC0;$
0ekAK2
1qTY9h
b0 ^:T_4
b0 /roOY
$end
#1000000
b10011010010 L-uG?
1-e"5`
1ekAK2
b10011010010 /roOY
0IC0;$
0qTY9h
#2000000
0-e"5`
0ekAK2
#3000000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#4000000
0-e"5`
0ekAK2
#5000000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#6000000
0-e"5`
0ekAK2
#7000000
b11 }eN0d
1-e"5`
1ekAK2
b11 ^:T_4
#8000000
0-e"5`
0ekAK2
#9000000
b100 }eN0d
1-e"5`
1ekAK2
b100 ^:T_4
#10000000
0-e"5`
0ekAK2
#11000000
b101 }eN0d
1-e"5`
1ekAK2
b101 ^:T_4
#12000000
0-e"5`
0ekAK2
#13000000
b110 }eN0d
1-e"5`
1ekAK2
b110 ^:T_4
#14000000
0-e"5`
0ekAK2
#15000000
b111 }eN0d
1-e"5`
1ekAK2
b111 ^:T_4
#16000000
0-e"5`
0ekAK2
#17000000
b1000 }eN0d
1-e"5`
1ekAK2
b1000 ^:T_4
#18000000
0-e"5`
0ekAK2
#19000000
b1001 }eN0d
1-e"5`
1ekAK2
b1001 ^:T_4
#20000000
0-e"5`
0ekAK2
#21000000
b0 }eN0d
1-e"5`
1ekAK2
b0 ^:T_4
#22000000
0-e"5`
0ekAK2
#23000000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#24000000
0-e"5`
0ekAK2
#25000000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#26000000
0-e"5`
0ekAK2
#27000000
b11 }eN0d
1-e"5`
1ekAK2
b11 ^:T_4
#28000000
0-e"5`
0ekAK2
#29000000
b100 }eN0d
1-e"5`
1ekAK2
b100 ^:T_4
#30000000
0-e"5`
0ekAK2
#31000000
b101 }eN0d
1-e"5`
1ekAK2
b101 ^:T_4
#32000000
0-e"5`
0ekAK2
#33000000
b110 }eN0d
1-e"5`
1ekAK2
b110 ^:T_4
#34000000
0-e"5`
0ekAK2
#35000000
b111 }eN0d
1-e"5`
1ekAK2
b111 ^:T_4
#36000000
0-e"5`
0ekAK2
#37000000
b1000 }eN0d
1-e"5`
1ekAK2
b1000 ^:T_4
#38000000
0-e"5`
0ekAK2
#39000000
b1001 }eN0d
1-e"5`
1ekAK2
b1001 ^:T_4
#40000000
0-e"5`
0ekAK2
#41000000
b0 }eN0d
1-e"5`
1ekAK2
b0 ^:T_4
#42000000
0-e"5`
0ekAK2
#43000000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#44000000
0-e"5`
0ekAK2
#45000000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#46000000
0-e"5`
0ekAK2
#47000000
b11 }eN0d
1-e"5`
1ekAK2
b11 ^:T_4
#48000000
0-e"5`
0ekAK2
#49000000
b100 }eN0d
1-e"5`
1ekAK2
b100 ^:T_4
#50000000
0-e"5`
0ekAK2
#51000000
b101 }eN0d
1-e"5`
1ekAK2
b101 ^:T_4
#52000000
0-e"5`
0ekAK2
#53000000
b110 }eN0d
1-e"5`
1ekAK2
b110 ^:T_4
#54000000
0-e"5`
0ekAK2
#55000000
b111 }eN0d
1-e"5`
1ekAK2
b111 ^:T_4
#56000000
0-e"5`
0ekAK2
#57000000
b1000 }eN0d
1-e"5`
1ekAK2
b1000 ^:T_4
#58000000
0-e"5`
0ekAK2
#59000000
b1001 }eN0d
1-e"5`
1ekAK2
b1001 ^:T_4
#60000000
0-e"5`
0ekAK2
#61000000
b0 }eN0d
1-e"5`
1ekAK2
b0 ^:T_4
#62000000
0-e"5`
0ekAK2
#63000000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#64000000
0-e"5`
0ekAK2
#65000000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#66000000

View file

@ -1,194 +0,0 @@
$timescale 1 ps $end
$scope module formal_counter $end
$var wire 1 ekAK2 formal_global_clock $end
$var wire 1 qTY9h formal_reset $end
$var wire 16 /roOY any_seq $end
$var wire 8 }eN0d count $end
$var wire 1 2f=;S enable_assert $end
$var wire 16 L-uG? any_seq_out $end
$scope struct cd $end
$var wire 1 -e"5` clk $end
$var wire 1 IC0;$ rst $end
$upscope $end
$var reg 8 ^:T_4 count_reg $end
$upscope $end
$enddefinitions $end
$dumpvars
b0 }eN0d
02f=;S
b0 L-uG?
0-e"5`
1IC0;$
0ekAK2
1qTY9h
b0 ^:T_4
b0 /roOY
$end
#500000
b10011010010 L-uG?
1-e"5`
1ekAK2
b10011010010 /roOY
0IC0;$
0qTY9h
#1000000
0-e"5`
0ekAK2
#1500000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#2000000
0-e"5`
0ekAK2
#2500000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#3000000
0-e"5`
0ekAK2
#3500000
b11 }eN0d
1-e"5`
1ekAK2
b11 ^:T_4
#4000000
0-e"5`
0ekAK2
#4500000
b100 }eN0d
1-e"5`
1ekAK2
b100 ^:T_4
#5000000
0-e"5`
0ekAK2
#5500000
b101 }eN0d
1-e"5`
1ekAK2
b101 ^:T_4
#6000000
0-e"5`
0ekAK2
#6500000
b110 }eN0d
1-e"5`
1ekAK2
b110 ^:T_4
#7000000
0-e"5`
0ekAK2
#7500000
b111 }eN0d
1-e"5`
1ekAK2
b111 ^:T_4
#8000000
0-e"5`
0ekAK2
#8500000
b1000 }eN0d
1-e"5`
1ekAK2
b1000 ^:T_4
#9000000
0-e"5`
0ekAK2
#9500000
b1001 }eN0d
1-e"5`
1ekAK2
b1001 ^:T_4
#10000000
0-e"5`
0ekAK2
#10500000
b0 }eN0d
1-e"5`
1ekAK2
b0 ^:T_4
#11000000
0-e"5`
0ekAK2
#11500000
b1 }eN0d
1-e"5`
1ekAK2
b1 ^:T_4
#12000000
0-e"5`
0ekAK2
#12500000
b10 }eN0d
1-e"5`
1ekAK2
b10 ^:T_4
#13000000
0-e"5`
0ekAK2
#13500000
b11 }eN0d
1-e"5`
1ekAK2
b11 ^:T_4
#14000000
0-e"5`
0ekAK2
#14500000
b100 }eN0d
1-e"5`
1ekAK2
b100 ^:T_4
#15000000
0-e"5`
0ekAK2
#15500000
b101 }eN0d
1-e"5`
1ekAK2
b101 ^:T_4
#16000000
0-e"5`
0ekAK2
#16500000
b110 }eN0d
1-e"5`
1ekAK2
b110 ^:T_4
#17000000
12f=;S
0-e"5`
0ekAK2
#17500000
b111 }eN0d
1-e"5`
1ekAK2
b111 ^:T_4
#18000000
0-e"5`
0ekAK2
#18500000
b1000 }eN0d
1-e"5`
1ekAK2
b1000 ^:T_4
#19000000
0-e"5`
0ekAK2
#19500000
b1001 }eN0d
1-e"5`
1ekAK2
b1001 ^:T_4
#20000000
0-e"5`
0ekAK2
#20500000
b0 }eN0d
1-e"5`
1ekAK2
b0 ^:T_4

View file

@ -75,7 +75,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
929 | pub struct OpaqueSimValue {
896 | pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
@ -214,7 +214,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
929 | pub struct OpaqueSimValue {
896 | pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs
@ -326,7 +326,7 @@ note: required because it appears within the type `Vec<DynSimOnlyValue>`
note: required because it appears within the type `OpaqueSimValue`
--> src/ty.rs
|
929 | pub struct OpaqueSimValue {
896 | pub struct OpaqueSimValue {
| ^^^^^^^^^^^^^^
note: required because it appears within the type `value::SimValueInner<()>`
--> src/sim/value.rs

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