support operations directly on SimValue, UIntValue, and SIntValue, and shared references to those
This commit is contained in:
parent
2a65aa2bd5
commit
9e803223d0
42 changed files with 6076 additions and 1486 deletions
|
|
@ -396,15 +396,29 @@ impl ToTokens for Builder {
|
|||
quote_spanned! {self.ident.span()=>
|
||||
#[automatically_derived]
|
||||
#[allow(non_camel_case_types, dead_code, private_interfaces)]
|
||||
impl #filled_impl_generics ::fayalite::expr::ToExpr for #filled_ty
|
||||
impl #filled_impl_generics ::fayalite::expr::ValueType for #filled_ty
|
||||
#filled_where_clause
|
||||
{
|
||||
type Type = #target #type_generics;
|
||||
type ValueCategory = ::fayalite::expr::value_category::ValueCategoryExpr;
|
||||
|
||||
fn ty(&self) -> <Self as ::fayalite::expr::ValueType>::Type {
|
||||
#target {
|
||||
#(#field_idents: ::fayalite::expr::ValueType::ty(&self.#field_idents),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
#[allow(non_camel_case_types, dead_code, private_interfaces)]
|
||||
impl #filled_impl_generics ::fayalite::expr::ToExpr for #filled_ty
|
||||
#filled_where_clause
|
||||
{
|
||||
fn to_expr(
|
||||
&self,
|
||||
) -> ::fayalite::expr::Expr<<Self as ::fayalite::expr::ToExpr>::Type> {
|
||||
) -> ::fayalite::expr::Expr<<Self as ::fayalite::expr::ValueType>::Type> {
|
||||
let __ty = #target {
|
||||
#(#field_idents: ::fayalite::expr::Expr::ty(self.#field_idents),)*
|
||||
#(#field_idents: ::fayalite::expr::ValueType::ty(&self.#field_idents),)*
|
||||
};
|
||||
let __field_values = [
|
||||
#(::fayalite::expr::Expr::canonical(self.#field_idents),)*
|
||||
|
|
@ -695,10 +709,10 @@ impl ToTokens for ParsedBundle {
|
|||
v.field(&value.#ident);
|
||||
}
|
||||
}));
|
||||
let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
|
||||
let value_type_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
|
||||
let ident: &Ident = field.ident().as_ref().unwrap();
|
||||
quote_spanned! {span=>
|
||||
#ident: ::fayalite::sim::value::SimValue::ty(&self.#ident),
|
||||
#ident: ::fayalite::expr::ValueType::ty(&self.#ident),
|
||||
}
|
||||
}));
|
||||
let fields_len = fields.named().into_iter().len();
|
||||
|
|
@ -806,28 +820,39 @@ impl ToTokens for ParsedBundle {
|
|||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::sim::value::ToSimValue for #mask_type_sim_value_ident #type_generics
|
||||
impl #impl_generics ::fayalite::expr::ValueType for #mask_type_sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
type Type = #mask_type_ident #type_generics;
|
||||
type ValueCategory = ::fayalite::expr::value_category::ValueCategorySimValue;
|
||||
|
||||
fn ty(&self) -> <Self as ::fayalite::expr::ValueType>::Type {
|
||||
#mask_type_ident {
|
||||
#(#value_type_fields)*
|
||||
}
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::sim::value::ToSimValue for #mask_type_sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn to_sim_value(
|
||||
&self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::sim::value::ToSimValue>::Type,
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
let ty = #mask_type_ident {
|
||||
#(#to_sim_value_fields)*
|
||||
#(#value_type_fields)*
|
||||
};
|
||||
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
|
||||
}
|
||||
fn into_sim_value(
|
||||
self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::sim::value::ToSimValue>::Type,
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
let ty = #mask_type_ident {
|
||||
#(#to_sim_value_fields)*
|
||||
#(#value_type_fields)*
|
||||
};
|
||||
::fayalite::sim::value::SimValue::from_value(ty, self)
|
||||
}
|
||||
|
|
@ -955,28 +980,39 @@ impl ToTokens for ParsedBundle {
|
|||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::sim::value::ToSimValue for #sim_value_ident #type_generics
|
||||
impl #impl_generics ::fayalite::expr::ValueType for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
type Type = #target #type_generics;
|
||||
type ValueCategory = ::fayalite::expr::value_category::ValueCategorySimValue;
|
||||
|
||||
fn ty(&self) -> <Self as ::fayalite::expr::ValueType>::Type {
|
||||
#target {
|
||||
#(#value_type_fields)*
|
||||
}
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::sim::value::ToSimValue for #sim_value_ident #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn to_sim_value(
|
||||
&self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::sim::value::ToSimValue>::Type,
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
let ty = #target {
|
||||
#(#to_sim_value_fields)*
|
||||
#(#value_type_fields)*
|
||||
};
|
||||
::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self))
|
||||
}
|
||||
fn into_sim_value(
|
||||
self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::sim::value::ToSimValue>::Type,
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
let ty = #target {
|
||||
#(#to_sim_value_fields)*
|
||||
#(#value_type_fields)*
|
||||
};
|
||||
::fayalite::sim::value::SimValue::from_value(ty, self)
|
||||
}
|
||||
|
|
@ -1002,91 +1038,172 @@ impl ToTokens for ParsedBundle {
|
|||
}
|
||||
.to_tokens(tokens);
|
||||
if let Some((cmp_eq,)) = cmp_eq {
|
||||
let mut expr_where_clause =
|
||||
let mut cmp_eq_where_clause =
|
||||
Generics::from(generics)
|
||||
.where_clause
|
||||
.unwrap_or_else(|| syn::WhereClause {
|
||||
where_token: Token,
|
||||
predicates: Punctuated::new(),
|
||||
});
|
||||
let mut sim_value_where_clause = expr_where_clause.clone();
|
||||
let mut fields_sim_value_eq = vec![];
|
||||
let mut fields_cmp_eq = vec![];
|
||||
let mut fields_cmp_ne = vec![];
|
||||
let mut fields_value_eq = vec![];
|
||||
let mut fields_value_ne = vec![];
|
||||
let mut fields_expr_eq = vec![];
|
||||
let mut fields_expr_ne = vec![];
|
||||
let mut fields_valueless_eq = vec![];
|
||||
let mut fields_valueless_ne = vec![];
|
||||
for field in fields.named() {
|
||||
let field_ident = field.ident();
|
||||
let field_ty = field.ty();
|
||||
expr_where_clause
|
||||
cmp_eq_where_clause
|
||||
.predicates
|
||||
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||
#field_ty: ::fayalite::expr::ops::ExprPartialEq<#field_ty>
|
||||
#field_ty: ::fayalite::expr::HdlPartialEqImpl<#field_ty>
|
||||
});
|
||||
sim_value_where_clause
|
||||
.predicates
|
||||
.push(parse_quote_spanned! {cmp_eq.span=>
|
||||
#field_ty: ::fayalite::sim::value::SimValuePartialEq<#field_ty>
|
||||
});
|
||||
fields_sim_value_eq.push(quote_spanned! {span=>
|
||||
::fayalite::sim::value::SimValuePartialEq::sim_value_eq(&__lhs.#field_ident, &__rhs.#field_ident)
|
||||
fields_value_eq.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_eq(
|
||||
__lhs.#field_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(&__lhs_value.#field_ident),
|
||||
__rhs.#field_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(&__rhs_value.#field_ident),
|
||||
)
|
||||
});
|
||||
fields_cmp_eq.push(quote_spanned! {span=>
|
||||
::fayalite::expr::ops::ExprPartialEq::cmp_eq(__lhs.#field_ident, __rhs.#field_ident)
|
||||
fields_value_ne.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_value_ne(
|
||||
__lhs.#field_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(&__lhs_value.#field_ident),
|
||||
__rhs.#field_ident,
|
||||
::fayalite::__std::borrow::Cow::Borrowed(&__rhs_value.#field_ident),
|
||||
)
|
||||
});
|
||||
fields_cmp_ne.push(quote_spanned! {span=>
|
||||
::fayalite::expr::ops::ExprPartialEq::cmp_ne(__lhs.#field_ident, __rhs.#field_ident)
|
||||
fields_expr_eq.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_expr_eq(
|
||||
__lhs.#field_ident,
|
||||
__rhs.#field_ident,
|
||||
)
|
||||
});
|
||||
fields_expr_ne.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_expr_ne(
|
||||
__lhs.#field_ident,
|
||||
__rhs.#field_ident,
|
||||
)
|
||||
});
|
||||
fields_valueless_eq.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_valueless_eq(
|
||||
::fayalite::expr::Valueless::new(__lhs.#field_ident),
|
||||
::fayalite::expr::Valueless::new(__rhs.#field_ident),
|
||||
)
|
||||
});
|
||||
fields_valueless_ne.push(quote_spanned! {span=>
|
||||
::fayalite::expr::HdlPartialEqImpl::cmp_valueless_ne(
|
||||
::fayalite::expr::Valueless::new(__lhs.#field_ident),
|
||||
::fayalite::expr::Valueless::new(__rhs.#field_ident),
|
||||
)
|
||||
});
|
||||
}
|
||||
let sim_value_eq_body;
|
||||
let cmp_eq_body;
|
||||
let cmp_ne_body;
|
||||
let value_eq_body;
|
||||
let value_ne_body;
|
||||
let expr_eq_body;
|
||||
let expr_ne_body;
|
||||
let valueless_eq_body;
|
||||
let valueless_ne_body;
|
||||
if fields_len == 0 {
|
||||
sim_value_eq_body = quote_spanned! {span=>
|
||||
value_eq_body = quote_spanned! {span=>
|
||||
true
|
||||
};
|
||||
cmp_eq_body = quote_spanned! {span=>
|
||||
value_ne_body = quote_spanned! {span=>
|
||||
false
|
||||
};
|
||||
expr_eq_body = quote_spanned! {span=>
|
||||
::fayalite::expr::ToExpr::to_expr(&true)
|
||||
};
|
||||
cmp_ne_body = quote_spanned! {span=>
|
||||
expr_ne_body = quote_spanned! {span=>
|
||||
::fayalite::expr::ToExpr::to_expr(&false)
|
||||
};
|
||||
valueless_eq_body = quote_spanned! {span=>
|
||||
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
||||
};
|
||||
valueless_ne_body = quote_spanned! {span=>
|
||||
::fayalite::expr::Valueless::new(::fayalite::int::Bool)
|
||||
};
|
||||
} else {
|
||||
sim_value_eq_body = quote_spanned! {span=>
|
||||
#(#fields_sim_value_eq)&&*
|
||||
value_eq_body = quote_spanned! {span=>
|
||||
#(#fields_value_eq)&*
|
||||
};
|
||||
cmp_eq_body = quote_spanned! {span=>
|
||||
#(#fields_cmp_eq)&*
|
||||
value_ne_body = quote_spanned! {span=>
|
||||
#(#fields_value_ne)|*
|
||||
};
|
||||
cmp_ne_body = quote_spanned! {span=>
|
||||
#(#fields_cmp_ne)|*
|
||||
expr_eq_body = quote_spanned! {span=>
|
||||
#(#fields_expr_eq)&*
|
||||
};
|
||||
expr_ne_body = quote_spanned! {span=>
|
||||
#(#fields_expr_ne)|*
|
||||
};
|
||||
valueless_eq_body = quote_spanned! {span=>
|
||||
let __lhs = ::fayalite::expr::ValueType::ty(&__lhs);
|
||||
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
||||
#(#fields_valueless_eq)|*
|
||||
};
|
||||
valueless_ne_body = quote_spanned! {span=>
|
||||
let __lhs = ::fayalite::expr::ValueType::ty(&__lhs);
|
||||
let __rhs = ::fayalite::expr::ValueType::ty(&__rhs);
|
||||
#(#fields_valueless_ne)|*
|
||||
};
|
||||
};
|
||||
quote_spanned! {span=>
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::expr::ops::ExprPartialEq<Self> for #target #type_generics
|
||||
#expr_where_clause
|
||||
impl #impl_generics ::fayalite::expr::HdlPartialEqImpl<Self> for #target #type_generics
|
||||
#cmp_eq_where_clause
|
||||
{
|
||||
fn cmp_eq(
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
__lhs: Self,
|
||||
__lhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||
__rhs: Self,
|
||||
__rhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||
) -> ::fayalite::__std::primitive::bool {
|
||||
#value_eq_body
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_ne(
|
||||
__lhs: Self,
|
||||
__lhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||
__rhs: Self,
|
||||
__rhs_value: ::fayalite::__std::borrow::Cow<'_, <Self as ::fayalite::ty::Type>::SimValue>,
|
||||
) -> ::fayalite::__std::primitive::bool {
|
||||
#value_ne_body
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(
|
||||
__lhs: ::fayalite::expr::Expr<Self>,
|
||||
__rhs: ::fayalite::expr::Expr<Self>,
|
||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||
#cmp_eq_body
|
||||
#expr_eq_body
|
||||
}
|
||||
fn cmp_ne(
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_ne(
|
||||
__lhs: ::fayalite::expr::Expr<Self>,
|
||||
__rhs: ::fayalite::expr::Expr<Self>,
|
||||
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
|
||||
#cmp_ne_body
|
||||
#expr_ne_body
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::fayalite::sim::value::SimValuePartialEq<Self> for #target #type_generics
|
||||
#sim_value_where_clause
|
||||
{
|
||||
fn sim_value_eq(
|
||||
__lhs: &::fayalite::sim::value::SimValue<Self>,
|
||||
__rhs: &::fayalite::sim::value::SimValue<Self>,
|
||||
) -> bool {
|
||||
#sim_value_eq_body
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_valueless_eq(
|
||||
__lhs: ::fayalite::expr::Valueless<Self>,
|
||||
__rhs: ::fayalite::expr::Valueless<Self>,
|
||||
) -> ::fayalite::expr::Valueless<::fayalite::int::Bool> {
|
||||
#valueless_eq_body
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_valueless_ne(
|
||||
__lhs: ::fayalite::expr::Valueless<Self>,
|
||||
__rhs: ::fayalite::expr::Valueless<Self>,
|
||||
) -> ::fayalite::expr::Valueless<::fayalite::int::Bool> {
|
||||
#valueless_ne_body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1024,16 +1024,26 @@ impl ToTokens for ParsedEnum {
|
|||
<::fayalite::int::Bool as ::fayalite::ty::StaticType>::TYPE_PROPERTIES;
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #static_impl_generics ::fayalite::sim::value::ToSimValue
|
||||
impl #static_impl_generics ::fayalite::expr::ValueType
|
||||
for #sim_value_ident #static_type_generics
|
||||
#static_where_clause
|
||||
{
|
||||
type Type = #target #static_type_generics;
|
||||
type ValueCategory = ::fayalite::expr::value_category::ValueCategorySimValue;
|
||||
|
||||
fn ty(&self) -> <Self as ::fayalite::expr::ValueType>::Type {
|
||||
::fayalite::ty::StaticType::TYPE
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl #static_impl_generics ::fayalite::sim::value::ToSimValue
|
||||
for #sim_value_ident #static_type_generics
|
||||
#static_where_clause
|
||||
{
|
||||
fn to_sim_value(
|
||||
&self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::sim::value::ToSimValue>::Type,
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
::fayalite::sim::value::SimValue::from_value(
|
||||
::fayalite::ty::StaticType::TYPE,
|
||||
|
|
@ -1043,7 +1053,7 @@ impl ToTokens for ParsedEnum {
|
|||
fn into_sim_value(
|
||||
self,
|
||||
) -> ::fayalite::sim::value::SimValue<
|
||||
<Self as ::fayalite::sim::value::ToSimValue>::Type,
|
||||
<Self as ::fayalite::expr::ValueType>::Type,
|
||||
> {
|
||||
::fayalite::sim::value::SimValue::from_value(
|
||||
::fayalite::ty::StaticType::TYPE,
|
||||
|
|
|
|||
|
|
@ -887,7 +887,13 @@ pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStr
|
|||
}
|
||||
}
|
||||
let _print_on_panic = PrintOnPanic(&contents);
|
||||
let contents = prettyplease::unparse(&parse_quote! { #contents });
|
||||
let mut parse_err = None;
|
||||
let (Ok(contents) | Err(contents)) = syn::parse2(contents.clone())
|
||||
.map(|file| prettyplease::unparse(&file))
|
||||
.map_err(|e| {
|
||||
parse_err = Some(e);
|
||||
contents.to_string()
|
||||
});
|
||||
let hash = <sha2::Sha256 as sha2::Digest>::digest(&contents);
|
||||
let hash = base16ct::HexDisplay(&hash[..5]);
|
||||
file.write_all(contents.as_bytes()).unwrap();
|
||||
|
|
@ -899,9 +905,26 @@ pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStr
|
|||
e.unwrap();
|
||||
}
|
||||
}
|
||||
eprintln!("generated {}", dest_file.display());
|
||||
let log_msg = if let Some(parse_err) = parse_err {
|
||||
format!(
|
||||
"fayalite-proc-macros-impl internal error:\nfailed to parse generated output: {parse_err}\nunformatted output is in: {}\n",
|
||||
dest_file.display()
|
||||
)
|
||||
} else {
|
||||
format!("generated {}\n", dest_file.display())
|
||||
};
|
||||
// write message atomically if possible
|
||||
let mut stderr = std::io::stderr().lock();
|
||||
let write_result = stderr.write_all(log_msg.as_bytes());
|
||||
let flush_result = stderr.flush();
|
||||
drop(stderr); // unlock before we try to panic
|
||||
write_result.unwrap();
|
||||
flush_result.unwrap();
|
||||
std::io::stderr()
|
||||
.lock()
|
||||
.write_all(log_msg.as_bytes())
|
||||
.unwrap();
|
||||
let dest_file = dest_file.to_str().unwrap();
|
||||
|
||||
quote! {
|
||||
include!(#dest_file);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ fn blinky(platform_io_builder: PlatformIOBuilder<'_>) {
|
|||
clk: clk_input.clk,
|
||||
rst,
|
||||
};
|
||||
let max_value = (Expr::ty(clk_input).frequency() / 2.0).round_ties_even() as u64 - 1;
|
||||
let max_value = (clk_input.ty().frequency() / 2.0).round_ties_even() as u64 - 1;
|
||||
let int_ty = UInt::range_inclusive(0..=max_value);
|
||||
#[hdl]
|
||||
let counter_reg: UInt = reg_builder().clock_domain(cd).reset(0u8.cast_to(int_ty));
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ fn tx_only_uart(
|
|||
connect(tx, tx_bits[uart_state_reg]);
|
||||
|
||||
#[hdl]
|
||||
if uart_state_reg.cmp_eq(Expr::ty(tx_bits).len() - 1) {
|
||||
if uart_state_reg.cmp_eq(tx_bits.ty().len() - 1) {
|
||||
connect(next_uart_state, 0_hdl_u4);
|
||||
let next_addr_val = addr_reg + 1u8;
|
||||
#[hdl]
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
use crate::{
|
||||
expr::{
|
||||
CastToBits, Expr, HdlPartialEq, ReduceBits, ToExpr,
|
||||
ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator, ExprPartialEq},
|
||||
CastToBits, Expr, HdlPartialEq, HdlPartialEqImpl, ReduceBits, ToExpr, ValueType, Valueless,
|
||||
ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator},
|
||||
},
|
||||
int::{Bool, DYN_SIZE, DynSize, KnownSize, Size, SizeType},
|
||||
intern::{Intern, Interned, LazyInterned},
|
||||
module::transform::visit::{Fold, Folder, Visit, Visitor},
|
||||
sim::value::{SimValue, SimValuePartialEq},
|
||||
sim::value::SimValue,
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
CanonicalType, MatchVariantWithoutScope, OpaqueSimValueSlice, OpaqueSimValueWriter,
|
||||
|
|
@ -19,7 +19,7 @@ use crate::{
|
|||
util::ConstUsize,
|
||||
};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
|
||||
use std::{iter::FusedIterator, ops::Index};
|
||||
use std::{borrow::Cow, iter::FusedIterator, ops::Index};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ArrayType<T: Type = CanonicalType, Len: Size = DynSize> {
|
||||
|
|
@ -221,7 +221,7 @@ impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
|
|||
let value = AsMut::<[SimValue<T>]>::as_mut(value);
|
||||
assert_eq!(self.len(), value.len());
|
||||
for element_value in value {
|
||||
assert_eq!(SimValue::ty(element_value), element_ty);
|
||||
assert_eq!(element_value.ty(), element_ty);
|
||||
let (element_opaque, rest) = opaque.split_at(element_size);
|
||||
SimValue::opaque_mut(element_value).clone_from_slice(element_opaque);
|
||||
opaque = rest;
|
||||
|
|
@ -238,7 +238,7 @@ impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
|
|||
let value = AsRef::<[SimValue<T>]>::as_ref(value);
|
||||
assert_eq!(self.len(), value.len());
|
||||
for element_value in value {
|
||||
assert_eq!(SimValue::ty(element_value), element_ty);
|
||||
assert_eq!(element_value.ty(), element_ty);
|
||||
writer.fill_prefix_with(element_size, |writer| {
|
||||
writer.fill_cloned_from_slice(SimValue::opaque(element_value).as_slice())
|
||||
});
|
||||
|
|
@ -326,14 +326,30 @@ impl<T: Type, L: SizeType> Index<L> for ArrayWithoutLen<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Lhs: Type, Rhs: Type, Len: Size> ExprPartialEq<ArrayType<Rhs, Len>> for ArrayType<Lhs, Len>
|
||||
impl<Lhs: Type, Rhs: Type, Len: Size> HdlPartialEqImpl<ArrayType<Rhs, Len>> for ArrayType<Lhs, Len>
|
||||
where
|
||||
Lhs: ExprPartialEq<Rhs>,
|
||||
Lhs: HdlPartialEqImpl<Rhs>,
|
||||
{
|
||||
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
||||
let lhs_ty = Expr::ty(lhs);
|
||||
let rhs_ty = Expr::ty(rhs);
|
||||
assert_eq!(lhs_ty.len(), rhs_ty.len());
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: ArrayType<Rhs, Len>,
|
||||
rhs_value: Cow<'_, <ArrayType<Rhs, Len> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
assert_eq!(lhs.len(), rhs.len());
|
||||
let lhs = lhs.element();
|
||||
let rhs = rhs.element();
|
||||
let lhs_value: &[_] = (*lhs_value).as_ref();
|
||||
let rhs_value: &[_] = (*rhs_value).as_ref();
|
||||
for (lhs_value, rhs_value) in lhs_value.iter().zip(rhs_value) {
|
||||
if !Lhs::cmp_value_eq(lhs, Cow::Borrowed(lhs_value), rhs, Cow::Borrowed(rhs_value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
||||
assert_eq!(lhs.ty().len(), rhs.ty().len());
|
||||
lhs.into_iter()
|
||||
.zip(rhs)
|
||||
.map(|(l, r)| l.cmp_eq(r))
|
||||
|
|
@ -341,11 +357,8 @@ where
|
|||
.cast_to_bits()
|
||||
.all_one_bits()
|
||||
}
|
||||
|
||||
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
||||
let lhs_ty = Expr::ty(lhs);
|
||||
let rhs_ty = Expr::ty(rhs);
|
||||
assert_eq!(lhs_ty.len(), rhs_ty.len());
|
||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<ArrayType<Rhs, Len>>) -> Expr<Bool> {
|
||||
assert_eq!(lhs.ty().len(), rhs.ty().len());
|
||||
lhs.into_iter()
|
||||
.zip(rhs)
|
||||
.map(|(l, r)| l.cmp_ne(r))
|
||||
|
|
@ -353,17 +366,19 @@ where
|
|||
.cast_to_bits()
|
||||
.any_one_bits()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Lhs: Type, Rhs: Type, Len: Size> SimValuePartialEq<ArrayType<Rhs, Len>> for ArrayType<Lhs, Len>
|
||||
where
|
||||
Lhs: SimValuePartialEq<Rhs>,
|
||||
{
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<ArrayType<Rhs, Len>>) -> bool {
|
||||
AsRef::<[_]>::as_ref(&**this)
|
||||
.iter()
|
||||
.zip(AsRef::<[_]>::as_ref(&**other))
|
||||
.all(|(l, r)| SimValuePartialEq::sim_value_eq(l, r))
|
||||
fn cmp_valueless_eq(
|
||||
lhs: Valueless<Self>,
|
||||
rhs: Valueless<ArrayType<Rhs, Len>>,
|
||||
) -> Valueless<Bool> {
|
||||
assert_eq!(lhs.ty().len(), rhs.ty().len());
|
||||
Valueless::new(Bool)
|
||||
}
|
||||
fn cmp_valueless_ne(
|
||||
lhs: Valueless<Self>,
|
||||
rhs: Valueless<ArrayType<Rhs, Len>>,
|
||||
) -> Valueless<Bool> {
|
||||
assert_eq!(lhs.ty().len(), rhs.ty().len());
|
||||
Valueless::new(Bool)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -374,7 +389,7 @@ impl<T: Type, Len: Size> ExprIntoIterator for ArrayType<T, Len> {
|
|||
fn expr_into_iter(e: Expr<Self>) -> Self::ExprIntoIter {
|
||||
ExprArrayIter {
|
||||
base: e,
|
||||
indexes: 0..Expr::ty(e).len(),
|
||||
indexes: 0..e.ty().len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@
|
|||
|
||||
use crate::{
|
||||
expr::{
|
||||
CastToBits, Expr, ReduceBits, ToExpr,
|
||||
ops::{ArrayLiteral, BundleLiteral, ExprPartialEq},
|
||||
CastToBits, Expr, HdlPartialEqImpl, ReduceBits, ToExpr, ToSimValueInner, ValueType,
|
||||
Valueless,
|
||||
ops::{ArrayLiteral, BundleLiteral},
|
||||
value_category::{ValueCategoryCommon, ValueCategoryExpr, ValueCategoryValue},
|
||||
},
|
||||
int::{Bool, DynSize},
|
||||
intern::{Intern, InternSlice, Interned},
|
||||
sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType},
|
||||
sim::value::{SimValue, SimValueEq, ToSimValue, ToSimValueWithType},
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, OpaqueSimValueSize,
|
||||
|
|
@ -18,7 +20,7 @@ use crate::{
|
|||
util::HashMap,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{fmt, marker::PhantomData};
|
||||
use std::{borrow::Cow, fmt, marker::PhantomData};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BundleField {
|
||||
|
|
@ -317,7 +319,7 @@ impl<'a> BundleSimValueFromOpaque<'a> {
|
|||
#[track_caller]
|
||||
pub fn field_clone_from_opaque<T: Type>(&mut self, field_value: &mut SimValue<T>) {
|
||||
let (field_ty, field_opaque) = self.field_ty_and_opaque::<T>();
|
||||
assert_eq!(field_ty, SimValue::ty(field_value));
|
||||
assert_eq!(field_ty, field_value.ty());
|
||||
SimValue::opaque_mut(field_value).clone_from_slice(field_opaque);
|
||||
}
|
||||
}
|
||||
|
|
@ -353,7 +355,7 @@ impl<'a> BundleSimValueToOpaque<'a> {
|
|||
else {
|
||||
panic!("tried to write too many fields with BundleSimValueToOpaque");
|
||||
};
|
||||
assert_eq!(T::from_canonical(ty), SimValue::ty(field_value));
|
||||
assert_eq!(T::from_canonical(ty), field_value.ty());
|
||||
self.writer.fill_prefix_with(ty.size(), |writer| {
|
||||
writer.fill_cloned_from_slice(SimValue::opaque(field_value).as_slice())
|
||||
});
|
||||
|
|
@ -566,23 +568,54 @@ macro_rules! impl_tuples {
|
|||
builder.finish()
|
||||
};
|
||||
}
|
||||
impl<$($T: ToExpr,)*> ToExpr for ($($T,)*) {
|
||||
impl<'a, $($T: ToSimValue,)*> ToSimValueInner<'a> for ($($T,)*)
|
||||
where
|
||||
Self: ValueType<Type = ($($T::Type,)*)>,
|
||||
{
|
||||
fn to_sim_value_inner(this: &Self) -> Cow<'_, <Self::Type as Type>::SimValue> {
|
||||
let ($($var,)*) = this;
|
||||
Cow::Owned(($($var.to_sim_value(),)*))
|
||||
}
|
||||
fn into_sim_value_inner(this: Self) -> Cow<'a, <Self::Type as Type>::SimValue> {
|
||||
let ($($var,)*) = this;
|
||||
Cow::Owned(($($var.into_sim_value(),)*))
|
||||
}
|
||||
}
|
||||
impl<$($T: ValueType,)*> ValueType for ($($T,)*)
|
||||
where
|
||||
ValueCategoryValue: ValueCategoryCommon<($($T::ValueCategory,)*)>,
|
||||
{
|
||||
type Type = ($($T::Type,)*);
|
||||
|
||||
type ValueCategory = <ValueCategoryValue as ValueCategoryCommon<($($T::ValueCategory,)*)>>::Common;
|
||||
fn ty(&self) -> Self::Type {
|
||||
let ($($var,)*) = self;
|
||||
($($var.ty(),)*)
|
||||
}
|
||||
}
|
||||
impl<$($T: ToExpr,)*> ToExpr for ($($T,)*)
|
||||
where
|
||||
Self: ValueType<Type = ($($T::Type,)*)>,
|
||||
{
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
let ($($var,)*) = self;
|
||||
$(let $var = $var.to_expr();)*
|
||||
let ty = ($(Expr::ty($var),)*);
|
||||
let ty = ($($var.ty(),)*);
|
||||
let field_values = [$(Expr::canonical($var)),*];
|
||||
BundleLiteral::new(ty, field_values.intern_slice()).to_expr()
|
||||
}
|
||||
}
|
||||
impl<$($T: Type,)*> ToExpr for TupleBuilder<($(Expr<$T>,)*)> {
|
||||
impl<$($T: Type,)*> ValueType for TupleBuilder<($(Expr<$T>,)*)> {
|
||||
type Type = ($($T,)*);
|
||||
|
||||
type ValueCategory = ValueCategoryExpr;
|
||||
fn ty(&self) -> Self::Type {
|
||||
let ($($var,)*) = self.0;
|
||||
($($var.ty(),)*)
|
||||
}
|
||||
}
|
||||
impl<$($T: Type,)*> ToExpr for TupleBuilder<($(Expr<$T>,)*)> {
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
let ($($var,)*) = self.0;
|
||||
let ty = ($(Expr::ty($var),)*);
|
||||
let ty = ($($var.ty(),)*);
|
||||
let field_values = [$(Expr::canonical($var)),*];
|
||||
BundleLiteral::new(ty, field_values.intern_slice()).to_expr()
|
||||
}
|
||||
|
|
@ -618,7 +651,7 @@ macro_rules! impl_tuples {
|
|||
};
|
||||
let mut opaque = OpaqueSimValue::empty();
|
||||
$(let $var = $var.into_sim_value_with_type($ty_var.ty);
|
||||
assert_eq!(SimValue::ty(&$var), $ty_var.ty);
|
||||
assert_eq!($var.ty(), $ty_var.ty);
|
||||
opaque.extend_from_slice(SimValue::opaque(&$var).as_slice());
|
||||
)*
|
||||
SimValue::from_opaque(ty, opaque)
|
||||
|
|
@ -640,53 +673,82 @@ macro_rules! impl_tuples {
|
|||
SimValue::from_value(ty, ($($var,)*))
|
||||
}
|
||||
}
|
||||
impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) {
|
||||
type Type = ($($T::Type,)*);
|
||||
impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*)
|
||||
where
|
||||
Self: ValueType<Type = ($($T::Type,)*)>,
|
||||
{
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
let ($($var,)*) = self;
|
||||
$(let $var = $var.to_sim_value();)*
|
||||
SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*))
|
||||
SimValue::from_value(($($var.ty(),)*), ($($var,)*))
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value(self) -> SimValue<Self::Type> {
|
||||
let ($($var,)*) = self;
|
||||
$(let $var = $var.to_sim_value();)*
|
||||
SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*))
|
||||
SimValue::from_value(($($var.ty(),)*), ($($var,)*))
|
||||
}
|
||||
}
|
||||
impl<$($Lhs: Type + ExprPartialEq<$Rhs>, $Rhs: Type,)*> ExprPartialEq<($($Rhs,)*)> for ($($Lhs,)*) {
|
||||
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
||||
impl<$($Lhs: Type + HdlPartialEqImpl<$Rhs>, $Rhs: Type,)*> HdlPartialEqImpl<($($Rhs,)*)> for ($($Lhs,)*) {
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: ($($Rhs,)*),
|
||||
rhs_value: Cow<'_, <($($Rhs,)*) as Type>::SimValue>,
|
||||
) -> bool {
|
||||
#![allow(unused_variables)]
|
||||
let ($($lhs_var,)*) = &*lhs_value;
|
||||
let ($($rhs_var,)*) = &*rhs_value;
|
||||
let retval = true;
|
||||
$(let retval = retval && $Lhs::cmp_value_eq(lhs.$num, Cow::Borrowed($lhs_var), rhs.$num, Cow::Borrowed($rhs_var));)*
|
||||
retval
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
||||
let ($($lhs_var,)*) = *lhs;
|
||||
let ($($rhs_var,)*) = *rhs;
|
||||
ArrayLiteral::<Bool, DynSize>::new(
|
||||
Bool,
|
||||
FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_eq($lhs_var, $rhs_var)),)*]),
|
||||
FromIterator::from_iter([$(Expr::canonical($Lhs::cmp_expr_eq($lhs_var, $rhs_var)),)*]),
|
||||
)
|
||||
.cast_to_bits()
|
||||
.all_one_bits()
|
||||
}
|
||||
|
||||
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
||||
#[track_caller]
|
||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<($($Rhs,)*)>) -> Expr<Bool> {
|
||||
let ($($lhs_var,)*) = *lhs;
|
||||
let ($($rhs_var,)*) = *rhs;
|
||||
ArrayLiteral::<Bool, DynSize>::new(
|
||||
Bool,
|
||||
FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_ne($lhs_var, $rhs_var)),)*]),
|
||||
FromIterator::from_iter([$(Expr::canonical($Lhs::cmp_expr_ne($lhs_var, $rhs_var)),)*]),
|
||||
)
|
||||
.cast_to_bits()
|
||||
.any_one_bits()
|
||||
}
|
||||
}
|
||||
impl<$($Lhs: SimValuePartialEq<$Rhs>, $Rhs: Type,)*> SimValuePartialEq<($($Rhs,)*)> for ($($Lhs,)*) {
|
||||
fn sim_value_eq(lhs: &SimValue<Self>, rhs: &SimValue<($($Rhs,)*)>) -> bool {
|
||||
let ($($lhs_var,)*) = &**lhs;
|
||||
let ($($rhs_var,)*) = &**rhs;
|
||||
let retval = true;
|
||||
$(let retval = retval && $lhs_var == $rhs_var;)*
|
||||
retval
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_valueless_eq(lhs: Valueless<Self>, rhs: Valueless<($($Rhs,)*)>) -> Valueless<Bool> {
|
||||
let ($($lhs_var,)*) = lhs.ty();
|
||||
let ($($rhs_var,)*) = rhs.ty();
|
||||
// let them check that the types can be compared
|
||||
$($Lhs::cmp_valueless_eq(Valueless::new($lhs_var), Valueless::new($rhs_var));)*
|
||||
Valueless::new(Bool)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_valueless_ne(lhs: Valueless<Self>, rhs: Valueless<($($Rhs,)*)>) -> Valueless<Bool> {
|
||||
let ($($lhs_var,)*) = lhs.ty();
|
||||
let ($($rhs_var,)*) = rhs.ty();
|
||||
// let them check that the types can be compared
|
||||
$($Lhs::cmp_valueless_ne(Valueless::new($lhs_var), Valueless::new($rhs_var));)*
|
||||
Valueless::new(Bool)
|
||||
}
|
||||
}
|
||||
impl<$($T: SimValueEq + HdlPartialEqImpl<$T>,)*> SimValueEq for ($($T,)*) {}
|
||||
};
|
||||
([$($lhs:tt)*] [$rhs_first:tt $($rhs:tt)*]) => {
|
||||
impl_tuples!([$($lhs)*] []);
|
||||
|
|
@ -775,9 +837,16 @@ impl<T: ?Sized + Send + Sync + 'static> Default for PhantomDataBuilder<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomDataBuilder<T> {
|
||||
impl<T: ?Sized + Send + Sync + 'static> ValueType for PhantomDataBuilder<T> {
|
||||
type Type = PhantomData<T>;
|
||||
type ValueCategory = ValueCategoryValue;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomDataBuilder<T> {
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
PhantomData.to_expr()
|
||||
}
|
||||
|
|
@ -803,17 +872,22 @@ impl<T: ?Sized + Send + Sync + 'static> StaticType for PhantomData<T> {
|
|||
const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomData<T> {
|
||||
impl<T: ?Sized + Send + Sync + 'static> ValueType for PhantomData<T> {
|
||||
type Type = PhantomData<T>;
|
||||
type ValueCategory = ValueCategoryValue;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomData<T> {
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
BundleLiteral::new(PhantomData, Interned::default()).to_expr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Send + Sync + 'static> ToSimValue for PhantomData<T> {
|
||||
type Type = PhantomData<T>;
|
||||
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self) -> SimValue<Self> {
|
||||
SimValue::from_value(*self, *self)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
expr::{Expr, ToExpr},
|
||||
expr::{Expr, ValueType},
|
||||
hdl,
|
||||
int::Bool,
|
||||
reset::{Reset, ResetType},
|
||||
sim::value::SimValue,
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter,
|
||||
|
|
@ -91,29 +92,34 @@ impl StaticType for Clock {
|
|||
}
|
||||
|
||||
pub trait ToClock {
|
||||
fn to_clock(&self) -> Expr<Clock>;
|
||||
type Output: ValueType<Type = Clock>;
|
||||
fn to_clock(&self) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<T: ?Sized + ToClock> ToClock for &'_ T {
|
||||
fn to_clock(&self) -> Expr<Clock> {
|
||||
type Output = T::Output;
|
||||
fn to_clock(&self) -> Self::Output {
|
||||
(**self).to_clock()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + ToClock> ToClock for &'_ mut T {
|
||||
fn to_clock(&self) -> Expr<Clock> {
|
||||
type Output = T::Output;
|
||||
fn to_clock(&self) -> Self::Output {
|
||||
(**self).to_clock()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + ToClock> ToClock for Box<T> {
|
||||
fn to_clock(&self) -> Expr<Clock> {
|
||||
type Output = T::Output;
|
||||
fn to_clock(&self) -> Self::Output {
|
||||
(**self).to_clock()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToClock for Expr<Clock> {
|
||||
fn to_clock(&self) -> Expr<Clock> {
|
||||
type Output = Expr<Clock>;
|
||||
fn to_clock(&self) -> Self::Output {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
|
@ -125,7 +131,25 @@ pub struct ClockDomain<R: ResetType = Reset> {
|
|||
}
|
||||
|
||||
impl ToClock for bool {
|
||||
fn to_clock(&self) -> Expr<Clock> {
|
||||
self.to_expr().to_clock()
|
||||
type Output = SimValue<Clock>;
|
||||
|
||||
fn to_clock(&self) -> Self::Output {
|
||||
SimValue::from_value(Clock, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToClock for SimValue<Bool> {
|
||||
type Output = SimValue<Clock>;
|
||||
|
||||
fn to_clock(&self) -> Self::Output {
|
||||
SimValue::from_value(Clock, **self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToClock for SimValue<Clock> {
|
||||
type Output = SimValue<Clock>;
|
||||
|
||||
fn to_clock(&self) -> Self::Output {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@
|
|||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{
|
||||
expr::{
|
||||
Expr, ToExpr,
|
||||
ops::{ExprPartialEq, VariantAccess},
|
||||
},
|
||||
expr::{Expr, HdlPartialEq, HdlPartialEqImpl, ToExpr, ValueType, ops::VariantAccess},
|
||||
hdl,
|
||||
int::{Bool, UIntValue},
|
||||
intern::{Intern, Interned},
|
||||
|
|
@ -13,7 +10,7 @@ use crate::{
|
|||
EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, Scope, connect,
|
||||
enum_match_variants_helper, incomplete_wire, wire,
|
||||
},
|
||||
sim::value::{SimValue, SimValuePartialEq},
|
||||
sim::value::SimValue,
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, OpaqueSimValueSize,
|
||||
|
|
@ -24,7 +21,7 @@ use crate::{
|
|||
};
|
||||
use bitvec::{order::Lsb0, slice::BitSlice, view::BitView};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{convert::Infallible, fmt, iter::FusedIterator, sync::Arc};
|
||||
use std::{borrow::Cow, convert::Infallible, fmt, iter::FusedIterator, sync::Arc};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
||||
pub struct EnumVariant {
|
||||
|
|
@ -599,7 +596,7 @@ impl<'a> EnumSimValueFromOpaque<'a> {
|
|||
let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(true) else {
|
||||
self.usage_error(true);
|
||||
};
|
||||
assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty));
|
||||
assert_eq!(value.ty(), T::from_canonical(variant_ty));
|
||||
SimValue::bits_mut(value)
|
||||
.bits_mut()
|
||||
.copy_from_bitslice(variant_bits);
|
||||
|
|
@ -711,7 +708,7 @@ impl<'a> EnumSimValueToOpaque<'a> {
|
|||
let Some(variant_ty) = self.variants[discriminant].ty else {
|
||||
panic!("expected variant to have no field");
|
||||
};
|
||||
assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty));
|
||||
assert_eq!(value.ty(), T::from_canonical(variant_ty));
|
||||
self.known_variant(discriminant, Some(SimValue::opaque(value)), padding)
|
||||
}
|
||||
}
|
||||
|
|
@ -732,9 +729,38 @@ pub enum HdlOption<T: Type> {
|
|||
HdlSome(T),
|
||||
}
|
||||
|
||||
impl<Lhs: Type + ExprPartialEq<Rhs>, Rhs: Type> ExprPartialEq<HdlOption<Rhs>> for HdlOption<Lhs> {
|
||||
impl<Lhs: Type + HdlPartialEqImpl<Rhs>, Rhs: Type> HdlPartialEqImpl<HdlOption<Rhs>>
|
||||
for HdlOption<Lhs>
|
||||
{
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: HdlOption<Rhs>,
|
||||
rhs_value: Cow<'_, <HdlOption<Rhs> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
type SimValueMatch<T> = <T as Type>::SimValue;
|
||||
match (&*lhs_value, &*rhs_value) {
|
||||
(SimValueMatch::<Self>::HdlNone(_), SimValueMatch::<HdlOption<Rhs>>::HdlNone(_)) => {
|
||||
true
|
||||
}
|
||||
(SimValueMatch::<Self>::HdlSome(..), SimValueMatch::<HdlOption<Rhs>>::HdlNone(_))
|
||||
| (SimValueMatch::<Self>::HdlNone(_), SimValueMatch::<HdlOption<Rhs>>::HdlSome(..)) => {
|
||||
false
|
||||
}
|
||||
(
|
||||
SimValueMatch::<Self>::HdlSome(l, _),
|
||||
SimValueMatch::<HdlOption<Rhs>>::HdlSome(r, _),
|
||||
) => HdlPartialEqImpl::cmp_value_eq(
|
||||
lhs.HdlSome,
|
||||
Cow::Borrowed(&**l),
|
||||
rhs.HdlSome,
|
||||
Cow::Borrowed(&**r),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<HdlOption<Rhs>>) -> Expr<Bool> {
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<HdlOption<Rhs>>) -> Expr<Bool> {
|
||||
#[hdl]
|
||||
let cmp_eq = wire();
|
||||
#[hdl]
|
||||
|
|
@ -743,7 +769,7 @@ impl<Lhs: Type + ExprPartialEq<Rhs>, Rhs: Type> ExprPartialEq<HdlOption<Rhs>> fo
|
|||
{
|
||||
#[hdl]
|
||||
match rhs {
|
||||
HdlSome(rhs) => connect(cmp_eq, ExprPartialEq::cmp_eq(lhs, rhs)),
|
||||
HdlSome(rhs) => connect(cmp_eq, lhs.cmp_eq(rhs)),
|
||||
HdlNone => connect(cmp_eq, false),
|
||||
}
|
||||
}
|
||||
|
|
@ -760,7 +786,7 @@ impl<Lhs: Type + ExprPartialEq<Rhs>, Rhs: Type> ExprPartialEq<HdlOption<Rhs>> fo
|
|||
}
|
||||
|
||||
#[hdl]
|
||||
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<HdlOption<Rhs>>) -> Expr<Bool> {
|
||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<HdlOption<Rhs>>) -> Expr<Bool> {
|
||||
#[hdl]
|
||||
let cmp_ne = wire();
|
||||
#[hdl]
|
||||
|
|
@ -769,7 +795,7 @@ impl<Lhs: Type + ExprPartialEq<Rhs>, Rhs: Type> ExprPartialEq<HdlOption<Rhs>> fo
|
|||
{
|
||||
#[hdl]
|
||||
match rhs {
|
||||
HdlSome(rhs) => connect(cmp_ne, ExprPartialEq::cmp_ne(lhs, rhs)),
|
||||
HdlSome(rhs) => connect(cmp_ne, lhs.cmp_ne(rhs)),
|
||||
HdlNone => connect(cmp_ne, true),
|
||||
}
|
||||
}
|
||||
|
|
@ -786,25 +812,6 @@ impl<Lhs: Type + ExprPartialEq<Rhs>, Rhs: Type> ExprPartialEq<HdlOption<Rhs>> fo
|
|||
}
|
||||
}
|
||||
|
||||
impl<Lhs: SimValuePartialEq<Rhs>, Rhs: Type> SimValuePartialEq<HdlOption<Rhs>> for HdlOption<Lhs> {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<HdlOption<Rhs>>) -> bool {
|
||||
type SimValueMatch<T> = <T as Type>::SimValue;
|
||||
match (&**this, &**other) {
|
||||
(SimValueMatch::<Self>::HdlNone(_), SimValueMatch::<HdlOption<Rhs>>::HdlNone(_)) => {
|
||||
true
|
||||
}
|
||||
(SimValueMatch::<Self>::HdlSome(..), SimValueMatch::<HdlOption<Rhs>>::HdlNone(_))
|
||||
| (SimValueMatch::<Self>::HdlNone(_), SimValueMatch::<HdlOption<Rhs>>::HdlSome(..)) => {
|
||||
false
|
||||
}
|
||||
(
|
||||
SimValueMatch::<Self>::HdlSome(l, _),
|
||||
SimValueMatch::<HdlOption<Rhs>>::HdlSome(r, _),
|
||||
) => l == r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn HdlNone<T: StaticType>() -> Expr<HdlOption<T>> {
|
||||
HdlOption[T::TYPE].HdlNone()
|
||||
|
|
@ -813,7 +820,7 @@ pub fn HdlNone<T: StaticType>() -> Expr<HdlOption<T>> {
|
|||
#[allow(non_snake_case)]
|
||||
pub fn HdlSome<T: Type>(value: impl ToExpr<Type = T>) -> Expr<HdlOption<T>> {
|
||||
let value = value.to_expr();
|
||||
HdlOption[Expr::ty(value)].HdlSome(value)
|
||||
HdlOption[value.ty()].HdlSome(value)
|
||||
}
|
||||
|
||||
impl<T: Type> HdlOption<T> {
|
||||
|
|
@ -853,7 +860,7 @@ impl<T: Type> HdlOption<T> {
|
|||
let value = f(value).inspect_err(|_| {
|
||||
and_then_out.complete(()); // avoid error
|
||||
})?;
|
||||
let and_then_out = and_then_out.complete(Expr::ty(value));
|
||||
let and_then_out = and_then_out.complete(value.ty());
|
||||
connect(and_then_out, value);
|
||||
drop(some_scope);
|
||||
let (Wrap::<<Self as Type>::MatchVariant>::HdlNone, none_scope) =
|
||||
|
|
@ -861,7 +868,7 @@ impl<T: Type> HdlOption<T> {
|
|||
else {
|
||||
unreachable!();
|
||||
};
|
||||
connect(and_then_out, Expr::ty(and_then_out).HdlNone());
|
||||
connect(and_then_out, and_then_out.ty().HdlNone());
|
||||
drop(none_scope);
|
||||
Ok(and_then_out)
|
||||
}
|
||||
|
|
@ -879,8 +886,8 @@ impl<T: Type> HdlOption<T> {
|
|||
#[track_caller]
|
||||
pub fn and<U: Type>(expr: Expr<Self>, opt_b: Expr<HdlOption<U>>) -> Expr<HdlOption<U>> {
|
||||
#[hdl]
|
||||
let and_out = wire(Expr::ty(opt_b));
|
||||
connect(and_out, Expr::ty(opt_b).HdlNone());
|
||||
let and_out = wire(opt_b.ty());
|
||||
connect(and_out, opt_b.ty().HdlNone());
|
||||
#[hdl]
|
||||
if let HdlSome(_) = expr {
|
||||
connect(and_out, opt_b);
|
||||
|
|
@ -894,8 +901,8 @@ impl<T: Type> HdlOption<T> {
|
|||
f: impl FnOnce(Expr<T>) -> Result<Expr<Bool>, E>,
|
||||
) -> Result<Expr<Self>, E> {
|
||||
#[hdl]
|
||||
let filtered = wire(Expr::ty(expr));
|
||||
connect(filtered, Expr::ty(expr).HdlNone());
|
||||
let filtered = wire(expr.ty());
|
||||
connect(filtered, expr.ty().HdlNone());
|
||||
let mut f = Some(f);
|
||||
#[hdl]
|
||||
if let HdlSome(v) = expr {
|
||||
|
|
@ -969,7 +976,7 @@ impl<T: Type> HdlOption<T> {
|
|||
f: impl FnOnce(Expr<T>) -> Expr<R>,
|
||||
) -> Expr<R> {
|
||||
#[hdl]
|
||||
let mapped = wire(Expr::ty(default));
|
||||
let mapped = wire(default.ty());
|
||||
let mut f = Some(f);
|
||||
#[hdl]
|
||||
match expr {
|
||||
|
|
@ -994,12 +1001,12 @@ impl<T: Type> HdlOption<T> {
|
|||
match expr {
|
||||
HdlSome(v) => {
|
||||
let v = f.take().unwrap()(v);
|
||||
let mapped = *retval.get_or_insert_with(|| mapped.complete(Expr::ty(v)));
|
||||
let mapped = *retval.get_or_insert_with(|| mapped.complete(v.ty()));
|
||||
connect(mapped, v);
|
||||
}
|
||||
HdlNone => {
|
||||
let v = default.take().unwrap()();
|
||||
let mapped = *retval.get_or_insert_with(|| mapped.complete(Expr::ty(v)));
|
||||
let mapped = *retval.get_or_insert_with(|| mapped.complete(v.ty()));
|
||||
connect(mapped, v);
|
||||
}
|
||||
}
|
||||
|
|
@ -1009,7 +1016,7 @@ impl<T: Type> HdlOption<T> {
|
|||
#[track_caller]
|
||||
pub fn or(expr: Expr<Self>, opt_b: Expr<Self>) -> Expr<Self> {
|
||||
#[hdl]
|
||||
let or_out = wire(Expr::ty(expr));
|
||||
let or_out = wire(expr.ty());
|
||||
connect(or_out, opt_b);
|
||||
#[hdl]
|
||||
if let HdlSome(_) = expr {
|
||||
|
|
@ -1021,7 +1028,7 @@ impl<T: Type> HdlOption<T> {
|
|||
#[track_caller]
|
||||
pub fn or_else(expr: Expr<Self>, f: impl FnOnce() -> Expr<Self>) -> Expr<Self> {
|
||||
#[hdl]
|
||||
let or_else_out = wire(Expr::ty(expr));
|
||||
let or_else_out = wire(expr.ty());
|
||||
connect(or_else_out, f());
|
||||
#[hdl]
|
||||
if let HdlSome(_) = expr {
|
||||
|
|
@ -1033,7 +1040,7 @@ impl<T: Type> HdlOption<T> {
|
|||
#[track_caller]
|
||||
pub fn unwrap_or(expr: Expr<Self>, default: Expr<T>) -> Expr<T> {
|
||||
#[hdl]
|
||||
let unwrap_or_else_out = wire(Expr::ty(default));
|
||||
let unwrap_or_else_out = wire(default.ty());
|
||||
connect(unwrap_or_else_out, default);
|
||||
#[hdl]
|
||||
if let HdlSome(v) = expr {
|
||||
|
|
@ -1045,7 +1052,7 @@ impl<T: Type> HdlOption<T> {
|
|||
#[track_caller]
|
||||
pub fn unwrap_or_else(expr: Expr<Self>, f: impl FnOnce() -> Expr<T>) -> Expr<T> {
|
||||
#[hdl]
|
||||
let unwrap_or_else_out = wire(Expr::ty(expr).HdlSome);
|
||||
let unwrap_or_else_out = wire(expr.ty().HdlSome);
|
||||
connect(unwrap_or_else_out, f());
|
||||
#[hdl]
|
||||
if let HdlSome(v) = expr {
|
||||
|
|
@ -1057,14 +1064,14 @@ impl<T: Type> HdlOption<T> {
|
|||
#[track_caller]
|
||||
pub fn xor(expr: Expr<Self>, opt_b: Expr<Self>) -> Expr<Self> {
|
||||
#[hdl]
|
||||
let xor_out = wire(Expr::ty(expr));
|
||||
let xor_out = wire(expr.ty());
|
||||
#[hdl]
|
||||
if let HdlSome(_) = expr {
|
||||
#[hdl]
|
||||
if let HdlNone = opt_b {
|
||||
connect(xor_out, expr);
|
||||
} else {
|
||||
connect(xor_out, Expr::ty(expr).HdlNone());
|
||||
connect(xor_out, expr.ty().HdlNone());
|
||||
}
|
||||
} else {
|
||||
connect(xor_out, opt_b);
|
||||
|
|
@ -1075,8 +1082,8 @@ impl<T: Type> HdlOption<T> {
|
|||
#[track_caller]
|
||||
pub fn zip<U: Type>(expr: Expr<Self>, other: Expr<HdlOption<U>>) -> Expr<HdlOption<(T, U)>> {
|
||||
#[hdl]
|
||||
let zip_out = wire(HdlOption[(Expr::ty(expr).HdlSome, Expr::ty(other).HdlSome)]);
|
||||
connect(zip_out, Expr::ty(zip_out).HdlNone());
|
||||
let zip_out = wire(HdlOption[(expr.ty().HdlSome, other.ty().HdlSome)]);
|
||||
connect(zip_out, zip_out.ty().HdlNone());
|
||||
#[hdl]
|
||||
if let HdlSome(l) = expr {
|
||||
#[hdl]
|
||||
|
|
@ -1093,11 +1100,11 @@ impl<T: Type> HdlOption<HdlOption<T>> {
|
|||
#[track_caller]
|
||||
pub fn flatten(expr: Expr<Self>) -> Expr<HdlOption<T>> {
|
||||
#[hdl]
|
||||
let flattened = wire(Expr::ty(expr).HdlSome);
|
||||
let flattened = wire(expr.ty().HdlSome);
|
||||
#[hdl]
|
||||
match expr {
|
||||
HdlSome(v) => connect(flattened, v),
|
||||
HdlNone => connect(flattened, Expr::ty(expr).HdlSome.HdlNone()),
|
||||
HdlNone => connect(flattened, expr.ty().HdlSome.HdlNone()),
|
||||
}
|
||||
flattened
|
||||
}
|
||||
|
|
@ -1107,7 +1114,7 @@ impl<T: Type, U: Type> HdlOption<(T, U)> {
|
|||
#[hdl]
|
||||
#[track_caller]
|
||||
pub fn unzip(expr: Expr<Self>) -> Expr<(HdlOption<T>, HdlOption<U>)> {
|
||||
let (t, u) = Expr::ty(expr).HdlSome;
|
||||
let (t, u) = expr.ty().HdlSome;
|
||||
#[hdl]
|
||||
let unzipped = wire((HdlOption[t], HdlOption[u]));
|
||||
connect(unzipped, (HdlOption[t].HdlNone(), HdlOption[u].HdlNone()));
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
222
crates/fayalite/src/expr/ops/test_ops_impls.rs
Normal file
222
crates/fayalite/src/expr/ops/test_ops_impls.rs
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{expr::Valueless, expr::ops::make_impls, prelude::*};
|
||||
use std::num::NonZero;
|
||||
|
||||
macro_rules! assert_neg_impls {
|
||||
([$($Lifetimes:tt)*][$($Bounds:tt)*] ($ty:ty),) => {
|
||||
const _: () = {
|
||||
fn _check_neg_impl<$($Lifetimes)*$($Bounds)*>(v: $ty)
|
||||
-> impl ValueType<
|
||||
ValueCategory = <$ty as ValueType>::ValueCategory,
|
||||
Type = <<Valueless<<$ty as ValueType>::Type> as std::ops::Neg>::Output as ValueType>::Type,
|
||||
> {
|
||||
std::ops::Neg::neg(v)
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((sint_local<'a, Width>))]
|
||||
assert_neg_impls! {}
|
||||
}
|
||||
|
||||
macro_rules! assert_not_impls {
|
||||
([$($Lifetimes:tt)*][$($Bounds:tt)*] ($ty:ty),) => {
|
||||
const _: () = {
|
||||
fn _check_not_impl<$($Lifetimes)*$($Bounds)*>(v: $ty)
|
||||
-> impl ValueType<
|
||||
ValueCategory = <$ty as ValueType>::ValueCategory,
|
||||
Type = <<Valueless<<$ty as ValueType>::Type> as std::ops::Not>::Output as ValueType>::Type,
|
||||
> {
|
||||
std::ops::Not::not(v)
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((int_local<'a, Width>), (bool<'a>))]
|
||||
assert_not_impls! {}
|
||||
}
|
||||
|
||||
macro_rules! assert_cast_to_bits_impls {
|
||||
([$($Lifetimes:tt)*][$($Bounds:tt)*] ($ty:ty),) => {
|
||||
const _: () = {
|
||||
fn _check_cast_to_bits_impl<$($Lifetimes)*$($Bounds)*>(v: $ty)
|
||||
-> impl ValueType<
|
||||
ValueCategory = <$ty as ValueType>::ValueCategory,
|
||||
Type = <<Valueless<<$ty as ValueType>::Type> as CastToBits>::Output as ValueType>::Type,
|
||||
> {
|
||||
<$ty as CastToBits>::cast_to_bits(&v)
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((uint<'a, Width>), (sint<'a, Width>), (bool<'a>))]
|
||||
assert_cast_to_bits_impls! {}
|
||||
}
|
||||
|
||||
macro_rules! assert_simple_bin_op_impls {
|
||||
([$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*), [$($RLifetimes:tt)*][$($RBounds:tt)*] ($($R:tt)*), !$Trait:ident::$f:ident) => {
|
||||
#[expect(dead_code)]
|
||||
const _: () = {
|
||||
trait HasImpl {
|
||||
fn check_impl(self);
|
||||
}
|
||||
|
||||
trait NoImpl {
|
||||
fn check_impl(&self) -> &'static dyn NoImpl;
|
||||
}
|
||||
|
||||
impl<L, R> NoImpl for (L, R) {
|
||||
fn check_impl(&self) -> &'static dyn NoImpl {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: std::ops::$Trait<R>, R> HasImpl for (L, R) {
|
||||
fn check_impl(self) {}
|
||||
}
|
||||
|
||||
fn check_simple_bin_op_no_impl<$($LLifetimes)* $($RLifetimes)* $($LBounds)* $($RBounds)*>(l: $($L)*, r: $($R)*) {
|
||||
let _: &'static dyn NoImpl = (l, r).check_impl();
|
||||
}
|
||||
};
|
||||
};
|
||||
([$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*), [$($RLifetimes:tt)*][$($RBounds:tt)*] (usize), Shl::shl) => {
|
||||
const _: () = {
|
||||
#[expect(dead_code)]
|
||||
fn check_simple_bin_op_impl<$($LLifetimes)* $($RLifetimes)* $($LBounds)* $($RBounds)*>(l: $($L)*, r: usize)
|
||||
-> impl ValueType<
|
||||
ValueCategory = <($($L)*, usize) as ValueType>::ValueCategory,
|
||||
Type = <<Valueless<<$($L)* as ValueType>::Type> as std::ops::Shl<usize>>::Output as ValueType>::Type,
|
||||
> {
|
||||
std::ops::Shl::shl(l, r)
|
||||
}
|
||||
};
|
||||
};
|
||||
([$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*), [$($RLifetimes:tt)*][$($RBounds:tt)*] (usize), Shr::shr) => {
|
||||
const _: () = {
|
||||
#[expect(dead_code)]
|
||||
fn check_simple_bin_op_impl<$($LLifetimes)* $($RLifetimes)* $($LBounds)* $($RBounds)*>(l: $($L)*, r: usize)
|
||||
-> impl ValueType<
|
||||
ValueCategory = <($($L)*, usize) as ValueType>::ValueCategory,
|
||||
Type = <<Valueless<<$($L)* as ValueType>::Type> as std::ops::Shr<usize>>::Output as ValueType>::Type,
|
||||
> {
|
||||
std::ops::Shr::shr(l, r)
|
||||
}
|
||||
};
|
||||
};
|
||||
([$($LLifetimes:tt)*][$($LBounds:tt)*] ($($L:tt)*), [$($RLifetimes:tt)*][$($RBounds:tt)*] ($($R:tt)*), $Trait:ident::$f:ident) => {
|
||||
const _: () = {
|
||||
#[expect(dead_code)]
|
||||
fn check_simple_bin_op_impl<$($LLifetimes)* $($RLifetimes)* $($LBounds)* $($RBounds)*>(l: $($L)*, r: $($R)*)
|
||||
-> impl ValueType<
|
||||
ValueCategory = <($($L)*, $($R)*) as ValueType>::ValueCategory,
|
||||
Type = <<Valueless<<$($L)* as ValueType>::Type> as std::ops::$Trait<Valueless<<$($R)* as ValueType>::Type>>>::Output as ValueType>::Type,
|
||||
> {
|
||||
std::ops::$Trait::$f(l, r)
|
||||
}
|
||||
};
|
||||
};
|
||||
($LLifetimes:tt $LBounds:tt ($($L:tt)*), $RLifetimes:tt $RBounds:tt ($($R:tt)*), !$FirstTrait:ident::$first_f:ident, $($rest:tt)*) => {
|
||||
assert_simple_bin_op_impls! {
|
||||
$LLifetimes $LBounds ($($L)*), $RLifetimes $RBounds ($($R)*), !$FirstTrait::$first_f
|
||||
}
|
||||
assert_simple_bin_op_impls! {
|
||||
$LLifetimes $LBounds ($($L)*), $RLifetimes $RBounds ($($R)*), $($rest)*
|
||||
}
|
||||
};
|
||||
($LLifetimes:tt $LBounds:tt ($($L:tt)*), $RLifetimes:tt $RBounds:tt ($($R:tt)*), $FirstTrait:ident::$first_f:ident, $($rest:tt)*) => {
|
||||
assert_simple_bin_op_impls! {
|
||||
$LLifetimes $LBounds ($($L)*), $RLifetimes $RBounds ($($R)*), $FirstTrait::$first_f
|
||||
}
|
||||
assert_simple_bin_op_impls! {
|
||||
$LLifetimes $LBounds ($($L)*), $RLifetimes $RBounds ($($R)*), $($rest)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((uint_local<'l, L>))]
|
||||
#[kinds((uint<'r, R>))]
|
||||
assert_simple_bin_op_impls! {Add::add, Sub::sub, Mul::mul, Div::div, Rem::rem, BitAnd::bitand, BitOr::bitor, BitXor::bitxor}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((uint<'l, L>))]
|
||||
#[kinds((uint_local<'r, R>))]
|
||||
assert_simple_bin_op_impls! {Add::add, Sub::sub, Mul::mul, Div::div, Rem::rem, BitAnd::bitand, BitOr::bitor, BitXor::bitxor, Shl::shl, Shr::shr}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((sint_local<'l, L>))]
|
||||
#[kinds((sint<'r, R>))]
|
||||
assert_simple_bin_op_impls! {Add::add, Sub::sub, Mul::mul, Div::div, Rem::rem, BitAnd::bitand, BitOr::bitor, BitXor::bitxor}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((sint<'l, L>))]
|
||||
#[kinds((sint_local<'r, R>))]
|
||||
assert_simple_bin_op_impls! {Add::add, Sub::sub, Mul::mul, Div::div, Rem::rem, BitAnd::bitand, BitOr::bitor, BitXor::bitxor}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((sint<'l, L>))]
|
||||
#[kinds((uint_local<'r, R>))]
|
||||
assert_simple_bin_op_impls! {Shl::shl, Shr::shr}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((uint_local<'l, L>))]
|
||||
assert_simple_bin_op_impls! {[][] (usize), Shl::shl, Shr::shr}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((sint_local<'l, L>))]
|
||||
assert_simple_bin_op_impls! {[][] (usize), Shl::shl, Shr::shr}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((bool_local<'l>))]
|
||||
#[kinds((bool_local<'r>))]
|
||||
assert_simple_bin_op_impls! {BitAnd::bitand, BitOr::bitor, BitXor::bitxor}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((bool<'l>))]
|
||||
#[kinds((Valueless<Bool>))]
|
||||
assert_simple_bin_op_impls! {BitAnd::bitand, BitOr::bitor, BitXor::bitxor}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((Valueless<Bool>))]
|
||||
#[kinds((bool<'r>))]
|
||||
assert_simple_bin_op_impls! {BitAnd::bitand, BitOr::bitor, BitXor::bitxor}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds((bool_at_most_sim_value<'l>))]
|
||||
#[kinds((bool_at_most_sim_value<'r>))]
|
||||
assert_simple_bin_op_impls! {BitAnd::bitand, BitOr::bitor, BitXor::bitxor}
|
||||
}
|
||||
|
||||
// assert there are no impls of BitAnd/BitOr/BitXor between Expr<Bool> and Rust's bool,
|
||||
// since that helps avoid using `==`/`!=` in hdl boolean expressions, which doesn't do
|
||||
// what is usually wanted.
|
||||
make_impls! {
|
||||
#[kinds((Expr<Bool>))]
|
||||
#[kinds(bool)]
|
||||
assert_simple_bin_op_impls! {!BitAnd::bitand, !BitOr::bitor, !BitXor::bitxor}
|
||||
}
|
||||
|
||||
make_impls! {
|
||||
#[kinds(bool)]
|
||||
#[kinds((Expr<Bool>))]
|
||||
assert_simple_bin_op_impls! {!BitAnd::bitand, !BitOr::bitor, !BitXor::bitxor}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
use crate::{
|
||||
array::Array,
|
||||
bundle::{Bundle, BundleField},
|
||||
expr::{Expr, Flow, ToExpr},
|
||||
expr::{Expr, Flow, ToExpr, ValueType, value_category::ValueCategoryExpr},
|
||||
intern::{Intern, Interned},
|
||||
memory::{DynPortType, MemPort},
|
||||
module::{Instance, ModuleIO, TargetName},
|
||||
|
|
@ -196,9 +196,18 @@ macro_rules! impl_target_base {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToExpr for $TargetBase {
|
||||
impl ValueType for $TargetBase {
|
||||
type Type = CanonicalType;
|
||||
type ValueCategory = ValueCategoryExpr;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
match self {
|
||||
$(Self::$Variant(v) => v.ty().canonical(),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToExpr for $TargetBase {
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
match self {
|
||||
$(Self::$Variant(v) => Expr::canonical(v.to_expr()),)*
|
||||
|
|
|
|||
378
crates/fayalite/src/expr/value_category.rs
Normal file
378
crates/fayalite/src/expr/value_category.rs
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{expr::ValueType, ty::Type};
|
||||
|
||||
trait ValueCategorySealed {}
|
||||
|
||||
#[expect(private_bounds)]
|
||||
pub trait ValueCategory:
|
||||
ValueCategorySealed
|
||||
+ Copy
|
||||
+ Ord
|
||||
+ Default
|
||||
+ std::fmt::Debug
|
||||
+ std::hash::Hash
|
||||
+ 'static
|
||||
+ Send
|
||||
+ Sync
|
||||
{
|
||||
type DispatchOutput<D: ValueCategoryDispatch<InputValueCategory = Self>>: ValueType<Type = D::Type, ValueCategory: ValueCategoryIsValueSimValueExprOrValueless>;
|
||||
#[track_caller]
|
||||
fn dispatch<D: ValueCategoryDispatch<InputValueCategory = Self>>(
|
||||
dispatch: D,
|
||||
) -> Self::DispatchOutput<D>;
|
||||
#[track_caller]
|
||||
fn dispatch_enum<D: ValueCategoryDispatch<InputValueCategory = Self>>(
|
||||
dispatch: D,
|
||||
) -> ValueCategoryDispatchOutputEnum<D>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Debug, Hash)]
|
||||
pub struct ValueCategoryValue;
|
||||
|
||||
impl ValueCategorySealed for ValueCategoryValue {}
|
||||
|
||||
impl ValueCategory for ValueCategoryValue {
|
||||
type DispatchOutput<D: ValueCategoryDispatch<InputValueCategory = Self>> = D::Value;
|
||||
|
||||
#[track_caller]
|
||||
fn dispatch<D: ValueCategoryDispatch<InputValueCategory = Self>>(
|
||||
dispatch: D,
|
||||
) -> Self::DispatchOutput<D> {
|
||||
dispatch.dispatch_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn dispatch_enum<D: ValueCategoryDispatch<InputValueCategory = Self>>(
|
||||
dispatch: D,
|
||||
) -> ValueCategoryDispatchOutputEnum<D> {
|
||||
ValueCategoryDispatchOutputEnum::Value(dispatch.dispatch_value())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Debug, Hash)]
|
||||
pub struct ValueCategorySimValue;
|
||||
|
||||
impl ValueCategorySealed for ValueCategorySimValue {}
|
||||
|
||||
impl ValueCategory for ValueCategorySimValue {
|
||||
type DispatchOutput<D: ValueCategoryDispatch<InputValueCategory = Self>> = D::SimValue;
|
||||
|
||||
#[track_caller]
|
||||
fn dispatch<D: ValueCategoryDispatch<InputValueCategory = Self>>(
|
||||
dispatch: D,
|
||||
) -> Self::DispatchOutput<D> {
|
||||
dispatch.dispatch_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn dispatch_enum<D: ValueCategoryDispatch<InputValueCategory = Self>>(
|
||||
dispatch: D,
|
||||
) -> ValueCategoryDispatchOutputEnum<D> {
|
||||
ValueCategoryDispatchOutputEnum::SimValue(dispatch.dispatch_sim_value())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Debug, Hash)]
|
||||
pub struct ValueCategoryExpr;
|
||||
|
||||
impl ValueCategorySealed for ValueCategoryExpr {}
|
||||
|
||||
impl ValueCategory for ValueCategoryExpr {
|
||||
type DispatchOutput<D: ValueCategoryDispatch<InputValueCategory = Self>> = D::Expr;
|
||||
|
||||
#[track_caller]
|
||||
fn dispatch<D: ValueCategoryDispatch<InputValueCategory = Self>>(
|
||||
dispatch: D,
|
||||
) -> Self::DispatchOutput<D> {
|
||||
dispatch.dispatch_expr()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn dispatch_enum<D: ValueCategoryDispatch<InputValueCategory = Self>>(
|
||||
dispatch: D,
|
||||
) -> ValueCategoryDispatchOutputEnum<D> {
|
||||
ValueCategoryDispatchOutputEnum::Expr(dispatch.dispatch_expr())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Debug, Hash)]
|
||||
pub struct ValueCategoryValueless;
|
||||
|
||||
impl ValueCategorySealed for ValueCategoryValueless {}
|
||||
|
||||
impl ValueCategory for ValueCategoryValueless {
|
||||
type DispatchOutput<D: ValueCategoryDispatch<InputValueCategory = Self>> = D::Valueless;
|
||||
|
||||
#[track_caller]
|
||||
fn dispatch<D: ValueCategoryDispatch<InputValueCategory = Self>>(
|
||||
dispatch: D,
|
||||
) -> Self::DispatchOutput<D> {
|
||||
dispatch.dispatch_valueless()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn dispatch_enum<D: ValueCategoryDispatch<InputValueCategory = Self>>(
|
||||
dispatch: D,
|
||||
) -> ValueCategoryDispatchOutputEnum<D> {
|
||||
ValueCategoryDispatchOutputEnum::Valueless(dispatch.dispatch_valueless())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ValueCategoryIsValue: ValueCategoryIsValueOrSimValue {}
|
||||
|
||||
impl ValueCategoryIsValue for ValueCategoryValue {}
|
||||
|
||||
pub trait ValueCategoryIsValueOrSimValue: ValueCategoryIsValueSimValueOrExpr {}
|
||||
|
||||
impl ValueCategoryIsValueOrSimValue for ValueCategoryValue {}
|
||||
impl ValueCategoryIsValueOrSimValue for ValueCategorySimValue {}
|
||||
|
||||
pub trait ValueCategoryIsValueSimValueOrExpr: ValueCategoryIsValueSimValueExprOrValueless {}
|
||||
|
||||
impl ValueCategoryIsValueSimValueOrExpr for ValueCategoryValue {}
|
||||
impl ValueCategoryIsValueSimValueOrExpr for ValueCategorySimValue {}
|
||||
impl ValueCategoryIsValueSimValueOrExpr for ValueCategoryExpr {}
|
||||
|
||||
pub trait ValueCategoryIsValueSimValueExprOrValueless: ValueCategory {}
|
||||
|
||||
impl ValueCategoryIsValueSimValueExprOrValueless for ValueCategoryValue {}
|
||||
impl ValueCategoryIsValueSimValueExprOrValueless for ValueCategorySimValue {}
|
||||
impl ValueCategoryIsValueSimValueExprOrValueless for ValueCategoryExpr {}
|
||||
impl ValueCategoryIsValueSimValueExprOrValueless for ValueCategoryValueless {}
|
||||
|
||||
pub trait ValueCategoryIsValueless: ValueCategoryIsExprOrValueless {}
|
||||
|
||||
impl ValueCategoryIsValueless for ValueCategoryValueless {}
|
||||
|
||||
pub trait ValueCategoryIsExprOrValueless: ValueCategoryIsValueSimValueExprOrValueless {}
|
||||
|
||||
impl ValueCategoryIsExprOrValueless for ValueCategoryExpr {}
|
||||
impl ValueCategoryIsExprOrValueless for ValueCategoryValueless {}
|
||||
|
||||
pub trait ValueCategoryIsSimValueExprOrValueless:
|
||||
ValueCategoryIsValueSimValueExprOrValueless
|
||||
{
|
||||
}
|
||||
|
||||
impl ValueCategoryIsSimValueExprOrValueless for ValueCategorySimValue {}
|
||||
impl ValueCategoryIsSimValueExprOrValueless for ValueCategoryExpr {}
|
||||
impl ValueCategoryIsSimValueExprOrValueless for ValueCategoryValueless {}
|
||||
|
||||
trait ValueCategoryCommonSealed {}
|
||||
|
||||
#[expect(private_bounds)]
|
||||
pub trait ValueCategoryCommon<
|
||||
T: ValueCategoryCommonSealed
|
||||
+ Copy
|
||||
+ Ord
|
||||
+ Default
|
||||
+ std::fmt::Debug
|
||||
+ std::hash::Hash
|
||||
+ 'static
|
||||
+ Send
|
||||
+ Sync,
|
||||
>: ValueCategory
|
||||
{
|
||||
type Common: ValueCategory;
|
||||
}
|
||||
|
||||
macro_rules! impl_value_category_common {
|
||||
($($T:ident),* $(,)?) => {
|
||||
impl_value_category_common!([$($T,)*]);
|
||||
};
|
||||
([$($A:ident,)?]) => {};
|
||||
([$FirstT:ident, $($T:ident,)+]) => {
|
||||
impl_value_category_common!([$($T,)*]);
|
||||
|
||||
impl<$FirstT: ValueCategory, $($T: ValueCategory),*> ValueCategoryCommonSealed for ($FirstT, $($T),*) {}
|
||||
|
||||
impl<This, $FirstT, $($T),*> ValueCategoryCommon<($FirstT, $($T),*)> for This
|
||||
where
|
||||
$FirstT: ValueCategory,
|
||||
$($T: ValueCategory,)*
|
||||
This: ValueCategoryCommon<($FirstT,), Common: ValueCategoryCommon<($($T,)*)>>,
|
||||
{
|
||||
type Common = <<This as ValueCategoryCommon<($FirstT,)>>::Common as ValueCategoryCommon<($($T,)*)>>::Common;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_value_category_common!(T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1, T0);
|
||||
|
||||
impl<T: ValueCategory> ValueCategoryCommonSealed for (T,) {}
|
||||
|
||||
impl ValueCategoryCommonSealed for () {}
|
||||
|
||||
impl<T: ValueCategory> ValueCategoryCommon<()> for T {
|
||||
type Common = T;
|
||||
}
|
||||
|
||||
impl<T: ValueCategoryIsValue> ValueCategoryCommon<(ValueCategoryValue,)> for T {
|
||||
type Common = ValueCategoryValue;
|
||||
}
|
||||
|
||||
impl<T: ValueCategoryIsValueOrSimValue> ValueCategoryCommon<(ValueCategorySimValue,)> for T {
|
||||
type Common = ValueCategorySimValue;
|
||||
}
|
||||
|
||||
impl<T: ValueCategoryIsValue> ValueCategoryCommon<(T,)> for ValueCategorySimValue {
|
||||
type Common = ValueCategorySimValue;
|
||||
}
|
||||
|
||||
impl<T: ValueCategoryIsValueSimValueOrExpr> ValueCategoryCommon<(ValueCategoryExpr,)> for T {
|
||||
type Common = ValueCategoryExpr;
|
||||
}
|
||||
|
||||
impl<T: ValueCategoryIsValueOrSimValue> ValueCategoryCommon<(T,)> for ValueCategoryExpr {
|
||||
type Common = ValueCategoryExpr;
|
||||
}
|
||||
|
||||
impl<T: ValueCategoryIsValueSimValueExprOrValueless> ValueCategoryCommon<(ValueCategoryValueless,)>
|
||||
for T
|
||||
{
|
||||
type Common = ValueCategoryValueless;
|
||||
}
|
||||
|
||||
impl<T: ValueCategoryIsValueSimValueOrExpr> ValueCategoryCommon<(T,)> for ValueCategoryValueless {
|
||||
type Common = ValueCategoryValueless;
|
||||
}
|
||||
|
||||
pub trait ValueCategoryDispatch: Sized {
|
||||
type Type: Type;
|
||||
type InputValueCategory: ValueCategory;
|
||||
type Value: ValueType<ValueCategory: ValueCategoryIsValueSimValueExprOrValueless, Type = Self::Type>;
|
||||
type SimValue: ValueType<ValueCategory: ValueCategoryIsSimValueExprOrValueless, Type = Self::Type>;
|
||||
type Expr: ValueType<ValueCategory: ValueCategoryIsExprOrValueless, Type = Self::Type>;
|
||||
type Valueless: ValueType<ValueCategory: ValueCategoryIsValueless, Type = Self::Type>;
|
||||
fn dispatch_value(self) -> Self::Value
|
||||
where
|
||||
Self: ValueCategoryDispatch<InputValueCategory = ValueCategoryValue>;
|
||||
fn dispatch_sim_value(self) -> Self::SimValue
|
||||
where
|
||||
Self: ValueCategoryDispatch<InputValueCategory = ValueCategorySimValue>;
|
||||
fn dispatch_expr(self) -> Self::Expr
|
||||
where
|
||||
Self: ValueCategoryDispatch<InputValueCategory = ValueCategoryExpr>;
|
||||
fn dispatch_valueless(self) -> Self::Valueless
|
||||
where
|
||||
Self: ValueCategoryDispatch<InputValueCategory = ValueCategoryValueless>;
|
||||
fn dispatch(self) -> <Self::InputValueCategory as ValueCategory>::DispatchOutput<Self> {
|
||||
Self::InputValueCategory::dispatch(self)
|
||||
}
|
||||
fn dispatch_enum(self) -> ValueCategoryDispatchOutputEnum<Self> {
|
||||
Self::InputValueCategory::dispatch_enum(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ValueCategoryDispatchOutputEnum<T: ValueCategoryDispatch> {
|
||||
Value(T::Value),
|
||||
SimValue(T::SimValue),
|
||||
Expr(T::Expr),
|
||||
Valueless(T::Valueless),
|
||||
}
|
||||
|
||||
impl<T: ValueCategoryDispatch> ValueCategoryDispatchOutputEnum<T> {
|
||||
pub fn try_into_value(self) -> Result<T::Value, Self> {
|
||||
if let Self::Value(v) = self {
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
pub fn try_into_sim_value(self) -> Result<T::SimValue, Self> {
|
||||
if let Self::SimValue(v) = self {
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
pub fn try_into_expr(self) -> Result<T::Expr, Self> {
|
||||
if let Self::Expr(v) = self {
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
pub fn try_into_valueless(self) -> Result<T::Valueless, Self> {
|
||||
if let Self::Valueless(v) = self {
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
fn unwrap_invalid(self, expected_kind: &'static str) -> ! {
|
||||
match self {
|
||||
Self::Value(_) => panic!("expected {expected_kind}, got Value"),
|
||||
Self::SimValue(_) => panic!("expected {expected_kind}, got SimValue"),
|
||||
Self::Expr(_) => panic!("expected {expected_kind}, got Expr"),
|
||||
Self::Valueless(_) => panic!("expected {expected_kind}, got Valueless"),
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn into_value_unwrap(self) -> T::Value {
|
||||
let Self::Value(v) = self else {
|
||||
self.unwrap_invalid("Value");
|
||||
};
|
||||
v
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn into_sim_value_unwrap(self) -> T::SimValue {
|
||||
let Self::SimValue(v) = self else {
|
||||
self.unwrap_invalid("SimValue");
|
||||
};
|
||||
v
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn into_expr_unwrap(self) -> T::Expr {
|
||||
let Self::Expr(v) = self else {
|
||||
self.unwrap_invalid("Expr");
|
||||
};
|
||||
v
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn into_valueless_unwrap(self) -> T::Valueless {
|
||||
let Self::Valueless(v) = self else {
|
||||
self.unwrap_invalid("Valueless");
|
||||
};
|
||||
v
|
||||
}
|
||||
pub fn ty(&self) -> T::Type {
|
||||
match self {
|
||||
Self::Value(v) => v.ty(),
|
||||
Self::SimValue(v) => v.ty(),
|
||||
Self::Expr(v) => v.ty(),
|
||||
Self::Valueless(v) => v.ty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
type Identity<T> = T;
|
||||
|
||||
macro_rules! check_categories {
|
||||
($($Categories:ident,)+) => {
|
||||
check_categories!([] [$($Categories,)+]);
|
||||
};
|
||||
([$($Categories:ident,)*] []) => {};
|
||||
([$($WeakerCategories:ident,)*] [$Category:ident, $($StrongerCategories:ident,)*]) => {
|
||||
$(const _: $Category = Identity::<<$WeakerCategories as ValueCategoryCommon<($Category,)>>::Common> {};
|
||||
const _: $Category = Identity::<<$Category as ValueCategoryCommon<($WeakerCategories,)>>::Common> {};)*
|
||||
const _: $Category = Identity::<<$Category as ValueCategoryCommon<($Category,)>>::Common> {};
|
||||
check_categories!([$($WeakerCategories,)* $Category,] [$($StrongerCategories,)*]);
|
||||
};
|
||||
}
|
||||
|
||||
check_categories!(
|
||||
ValueCategoryValue,
|
||||
ValueCategorySimValue,
|
||||
ValueCategoryExpr,
|
||||
ValueCategoryValueless,
|
||||
);
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
clock::Clock,
|
||||
enum_::{Enum, EnumType, EnumVariant},
|
||||
expr::{
|
||||
CastBitsTo, Expr, ExprEnum,
|
||||
CastBitsTo, Expr, ExprEnum, ToExpr, ValueType,
|
||||
ops::{self, VariantAccess},
|
||||
target::{
|
||||
Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
|
||||
|
|
@ -877,7 +877,7 @@ impl<'a> Exporter<'a> {
|
|||
definitions: &RcDefinitions,
|
||||
const_ty: bool,
|
||||
) -> Result<String> {
|
||||
let from_ty = Expr::ty(value);
|
||||
let from_ty = value.ty();
|
||||
let mut value = self.expr(Expr::canonical(value), definitions, const_ty)?;
|
||||
if from_ty.width().checked_add(1) == Some(to_ty.width())
|
||||
&& !FromTy::Signed::VALUE
|
||||
|
|
@ -926,7 +926,7 @@ impl<'a> Exporter<'a> {
|
|||
definitions: &RcDefinitions,
|
||||
const_ty: bool,
|
||||
) -> Result<String> {
|
||||
let base_width = Expr::ty(base).width();
|
||||
let base_width = base.ty().width();
|
||||
let base = self.expr(Expr::canonical(base), definitions, const_ty)?;
|
||||
if range.is_empty() {
|
||||
Ok(format!("tail({base}, {base_width})"))
|
||||
|
|
@ -1470,7 +1470,7 @@ impl<'a> Exporter<'a> {
|
|||
ExprEnum::SIntLiteral(literal) => Ok(self.sint_literal(&literal)),
|
||||
ExprEnum::BoolLiteral(literal) => Ok(self.bool_literal(literal)),
|
||||
ExprEnum::PhantomConst(ty) => self.expr(
|
||||
UInt[0].zero().cast_bits_to(ty.canonical()),
|
||||
UInt[0].zero().to_expr().cast_bits_to(ty.canonical()),
|
||||
definitions,
|
||||
const_ty,
|
||||
),
|
||||
|
|
@ -1653,7 +1653,7 @@ impl<'a> Exporter<'a> {
|
|||
let value_str = self.expr(expr.arg(), definitions, const_ty)?;
|
||||
self.expr_cast_to_bits(
|
||||
value_str,
|
||||
Expr::ty(expr.arg()),
|
||||
expr.arg().ty(),
|
||||
definitions,
|
||||
Indent {
|
||||
indent_depth: &Cell::new(0),
|
||||
|
|
@ -1776,7 +1776,7 @@ impl<'a> Exporter<'a> {
|
|||
let mut out = self.expr(Expr::canonical(expr.base()), definitions, const_ty)?;
|
||||
let name = self
|
||||
.type_state
|
||||
.get_bundle_field(Expr::ty(expr.base()), expr.field_name())?;
|
||||
.get_bundle_field(expr.base().ty(), expr.field_name())?;
|
||||
write!(out, ".{name}").unwrap();
|
||||
Ok(out)
|
||||
}
|
||||
|
|
@ -2101,12 +2101,12 @@ impl<'a> Exporter<'a> {
|
|||
rhs,
|
||||
source_location,
|
||||
}) => {
|
||||
if Expr::ty(lhs) != Expr::ty(rhs) {
|
||||
if lhs.ty() != rhs.ty() {
|
||||
writeln!(
|
||||
body,
|
||||
"{indent}; connect different types:\n{indent}; lhs: {:?}\n{indent}; rhs: {:?}",
|
||||
Expr::ty(lhs),
|
||||
Expr::ty(rhs),
|
||||
lhs.ty(),
|
||||
rhs.ty(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
|
@ -2200,7 +2200,7 @@ impl<'a> Exporter<'a> {
|
|||
FileInfo::new(source_location),
|
||||
)
|
||||
.unwrap();
|
||||
let enum_ty = Expr::ty(expr);
|
||||
let enum_ty = expr.ty();
|
||||
let match_arms_indent = indent.push();
|
||||
for ((variant_index, variant), match_arm_block) in
|
||||
enum_ty.variants().iter().enumerate().zip(blocks)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
use crate::{
|
||||
array::ArrayType,
|
||||
expr::{
|
||||
Expr, NotALiteralExpr, ToExpr, ToLiteralBits,
|
||||
Expr, NotALiteralExpr, ToExpr, ToLiteralBits, ToSimValueInner, ToValueless, ValueType,
|
||||
Valueless,
|
||||
target::{GetTarget, Target},
|
||||
value_category::ValueCategoryValue,
|
||||
},
|
||||
hdl,
|
||||
intern::{Intern, Interned, Memoize},
|
||||
|
|
@ -31,7 +33,7 @@ use std::{
|
|||
num::NonZero,
|
||||
ops::{Index, Not, Range, RangeBounds, RangeInclusive},
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
sync::{Arc, OnceLock},
|
||||
};
|
||||
|
||||
mod uint_in_range;
|
||||
|
|
@ -60,6 +62,56 @@ mod sealed {
|
|||
pub const DYN_SIZE: usize = !0;
|
||||
pub type DynSize = ConstUsize<DYN_SIZE>;
|
||||
|
||||
trait KnownSizeBaseSealed {}
|
||||
|
||||
impl<const N: usize> KnownSizeBaseSealed for [(); N] {}
|
||||
|
||||
#[expect(private_bounds)]
|
||||
pub trait KnownSizeBase: KnownSizeBaseSealed {}
|
||||
|
||||
macro_rules! impl_known_size_base {
|
||||
($($size:literal),* $(,)?) => {
|
||||
$(impl KnownSizeBase for [(); $size] {})*
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl_known_size_base! {
|
||||
0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, 0x009, 0x00A, 0x00B, 0x00C, 0x00D, 0x00E, 0x00F,
|
||||
0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, 0x018, 0x019, 0x01A, 0x01B, 0x01C, 0x01D, 0x01E, 0x01F,
|
||||
0x020, 0x021, 0x022, 0x023, 0x024, 0x025, 0x026, 0x027, 0x028, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F,
|
||||
0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x03F,
|
||||
0x040, 0x041, 0x042, 0x043, 0x044, 0x045, 0x046, 0x047, 0x048, 0x049, 0x04A, 0x04B, 0x04C, 0x04D, 0x04E, 0x04F,
|
||||
0x050, 0x051, 0x052, 0x053, 0x054, 0x055, 0x056, 0x057, 0x058, 0x059, 0x05A, 0x05B, 0x05C, 0x05D, 0x05E, 0x05F,
|
||||
0x060, 0x061, 0x062, 0x063, 0x064, 0x065, 0x066, 0x067, 0x068, 0x069, 0x06A, 0x06B, 0x06C, 0x06D, 0x06E, 0x06F,
|
||||
0x070, 0x071, 0x072, 0x073, 0x074, 0x075, 0x076, 0x077, 0x078, 0x079, 0x07A, 0x07B, 0x07C, 0x07D, 0x07E, 0x07F,
|
||||
0x080, 0x081, 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, 0x088, 0x089, 0x08A, 0x08B, 0x08C, 0x08D, 0x08E, 0x08F,
|
||||
0x090, 0x091, 0x092, 0x093, 0x094, 0x095, 0x096, 0x097, 0x098, 0x099, 0x09A, 0x09B, 0x09C, 0x09D, 0x09E, 0x09F,
|
||||
0x0A0, 0x0A1, 0x0A2, 0x0A3, 0x0A4, 0x0A5, 0x0A6, 0x0A7, 0x0A8, 0x0A9, 0x0AA, 0x0AB, 0x0AC, 0x0AD, 0x0AE, 0x0AF,
|
||||
0x0B0, 0x0B1, 0x0B2, 0x0B3, 0x0B4, 0x0B5, 0x0B6, 0x0B7, 0x0B8, 0x0B9, 0x0BA, 0x0BB, 0x0BC, 0x0BD, 0x0BE, 0x0BF,
|
||||
0x0C0, 0x0C1, 0x0C2, 0x0C3, 0x0C4, 0x0C5, 0x0C6, 0x0C7, 0x0C8, 0x0C9, 0x0CA, 0x0CB, 0x0CC, 0x0CD, 0x0CE, 0x0CF,
|
||||
0x0D0, 0x0D1, 0x0D2, 0x0D3, 0x0D4, 0x0D5, 0x0D6, 0x0D7, 0x0D8, 0x0D9, 0x0DA, 0x0DB, 0x0DC, 0x0DD, 0x0DE, 0x0DF,
|
||||
0x0E0, 0x0E1, 0x0E2, 0x0E3, 0x0E4, 0x0E5, 0x0E6, 0x0E7, 0x0E8, 0x0E9, 0x0EA, 0x0EB, 0x0EC, 0x0ED, 0x0EE, 0x0EF,
|
||||
0x0F0, 0x0F1, 0x0F2, 0x0F3, 0x0F4, 0x0F5, 0x0F6, 0x0F7, 0x0F8, 0x0F9, 0x0FA, 0x0FB, 0x0FC, 0x0FD, 0x0FE, 0x0FF,
|
||||
0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A, 0x10B, 0x10C, 0x10D, 0x10E, 0x10F,
|
||||
0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, 0x119, 0x11A, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F,
|
||||
0x120, 0x121, 0x122, 0x123, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12A, 0x12B, 0x12C, 0x12D, 0x12E, 0x12F,
|
||||
0x130, 0x131, 0x132, 0x133, 0x134, 0x135, 0x136, 0x137, 0x138, 0x139, 0x13A, 0x13B, 0x13C, 0x13D, 0x13E, 0x13F,
|
||||
0x140, 0x141, 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14A, 0x14B, 0x14C, 0x14D, 0x14E, 0x14F,
|
||||
0x150, 0x151, 0x152, 0x153, 0x154, 0x155, 0x156, 0x157, 0x158, 0x159, 0x15A, 0x15B, 0x15C, 0x15D, 0x15E, 0x15F,
|
||||
0x160, 0x161, 0x162, 0x163, 0x164, 0x165, 0x166, 0x167, 0x168, 0x169, 0x16A, 0x16B, 0x16C, 0x16D, 0x16E, 0x16F,
|
||||
0x170, 0x171, 0x172, 0x173, 0x174, 0x175, 0x176, 0x177, 0x178, 0x179, 0x17A, 0x17B, 0x17C, 0x17D, 0x17E, 0x17F,
|
||||
0x180, 0x181, 0x182, 0x183, 0x184, 0x185, 0x186, 0x187, 0x188, 0x189, 0x18A, 0x18B, 0x18C, 0x18D, 0x18E, 0x18F,
|
||||
0x190, 0x191, 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, 0x198, 0x199, 0x19A, 0x19B, 0x19C, 0x19D, 0x19E, 0x19F,
|
||||
0x1A0, 0x1A1, 0x1A2, 0x1A3, 0x1A4, 0x1A5, 0x1A6, 0x1A7, 0x1A8, 0x1A9, 0x1AA, 0x1AB, 0x1AC, 0x1AD, 0x1AE, 0x1AF,
|
||||
0x1B0, 0x1B1, 0x1B2, 0x1B3, 0x1B4, 0x1B5, 0x1B6, 0x1B7, 0x1B8, 0x1B9, 0x1BA, 0x1BB, 0x1BC, 0x1BD, 0x1BE, 0x1BF,
|
||||
0x1C0, 0x1C1, 0x1C2, 0x1C3, 0x1C4, 0x1C5, 0x1C6, 0x1C7, 0x1C8, 0x1C9, 0x1CA, 0x1CB, 0x1CC, 0x1CD, 0x1CE, 0x1CF,
|
||||
0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, 0x1D5, 0x1D6, 0x1D7, 0x1D8, 0x1D9, 0x1DA, 0x1DB, 0x1DC, 0x1DD, 0x1DE, 0x1DF,
|
||||
0x1E0, 0x1E1, 0x1E2, 0x1E3, 0x1E4, 0x1E5, 0x1E6, 0x1E7, 0x1E8, 0x1E9, 0x1EA, 0x1EB, 0x1EC, 0x1ED, 0x1EE, 0x1EF,
|
||||
0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, 0x1F5, 0x1F6, 0x1F7, 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC, 0x1FD, 0x1FE, 0x1FF,
|
||||
0x200,
|
||||
}
|
||||
|
||||
pub trait KnownSize:
|
||||
GenericConstUsize + sealed::SizeTypeSealed + sealed::SizeSealed + Default
|
||||
{
|
||||
|
|
@ -89,35 +141,15 @@ pub trait KnownSize:
|
|||
+ ToSimValueWithType<ArrayType<Element, Self>>;
|
||||
}
|
||||
|
||||
macro_rules! known_widths {
|
||||
([] $($bits:literal)+) => {
|
||||
impl KnownSize for ConstUsize<{
|
||||
let v = 0;
|
||||
$(let v = v * 2 + $bits;)*
|
||||
v
|
||||
}> {
|
||||
const SIZE: Self = Self;
|
||||
type ArrayMatch<Element: Type> = [Expr<Element>; Self::VALUE];
|
||||
type ArraySimValue<Element: Type> = [SimValue<Element>; Self::VALUE];
|
||||
}
|
||||
};
|
||||
([2 $($rest:tt)*] $($bits:literal)+) => {
|
||||
known_widths!([$($rest)*] $($bits)* 0);
|
||||
known_widths!([$($rest)*] $($bits)* 1);
|
||||
};
|
||||
([2 $($rest:tt)*]) => {
|
||||
known_widths!([$($rest)*] 0);
|
||||
known_widths!([$($rest)*] 1);
|
||||
impl KnownSize for ConstUsize<{2 $(* $rest)*}> {
|
||||
const SIZE: Self = Self;
|
||||
type ArrayMatch<Element: Type> = [Expr<Element>; Self::VALUE];
|
||||
type ArraySimValue<Element: Type> = [SimValue<Element>; Self::VALUE];
|
||||
}
|
||||
};
|
||||
impl<const N: usize> KnownSize for ConstUsize<N>
|
||||
where
|
||||
[(); N]: KnownSizeBase,
|
||||
{
|
||||
const SIZE: Self = Self;
|
||||
type ArrayMatch<Element: Type> = [Expr<Element>; N];
|
||||
type ArraySimValue<Element: Type> = [SimValue<Element>; N];
|
||||
}
|
||||
|
||||
known_widths!([2 2 2 2 2 2 2 2 2]);
|
||||
|
||||
pub trait SizeType:
|
||||
sealed::SizeTypeSealed
|
||||
+ Copy
|
||||
|
|
@ -530,6 +562,23 @@ fn deserialize_int_value<'de, D: Deserializer<'de>>(
|
|||
})
|
||||
}
|
||||
|
||||
macro_rules! impl_valueless_op_forward {
|
||||
(
|
||||
#[forward_to = $ForwardTrait:path]
|
||||
impl<$($G:ident: $Bound:path),*> $TraitPath:ident$(::$TraitPathRest:ident)+<$($Rhs:ty)?> for $SelfTy:ty {
|
||||
$($(type $Output:ident;)?
|
||||
use $forward_fn:path as $fn:ident($self:ident $(, $rhs:ident)?);)?
|
||||
}
|
||||
) => {
|
||||
impl<$($G: $Bound),*> $TraitPath$(::$TraitPathRest)+<$($Rhs)?> for $SelfTy {
|
||||
$($(type $Output = <$SelfTy as $ForwardTrait>::$Output;)?
|
||||
fn $fn($self $(, $rhs: $Rhs)?) $(-> Self::$Output)? {
|
||||
$forward_fn($self $(, $rhs)?)
|
||||
})?
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_int {
|
||||
($pretty_name:ident, $name:ident, $generic_name:ident, $value:ident, $SIGNED:literal) => {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
@ -582,6 +631,176 @@ macro_rules! impl_int {
|
|||
}
|
||||
}
|
||||
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::Add<Valueless<$name<RhsWidth>>>
|
||||
for Valueless<$name<LhsWidth>>
|
||||
{
|
||||
type Output = Valueless<$name>;
|
||||
|
||||
fn add(self, rhs: Valueless<$name<RhsWidth>>) -> Self::Output {
|
||||
Valueless::new($name::new_dyn(
|
||||
self.ty()
|
||||
.width()
|
||||
.max(rhs.ty().width())
|
||||
.checked_add(1)
|
||||
.expect("width too big"),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl_valueless_op_forward! {
|
||||
#[forward_to = std::ops::Add<Valueless<$name<RhsWidth>>>]
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::Sub<Valueless<$name<RhsWidth>>>
|
||||
for Valueless<$name<LhsWidth>>
|
||||
{
|
||||
type Output;
|
||||
|
||||
use std::ops::Add::<Valueless<$name<RhsWidth>>>::add as sub(self, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::BitOr<Valueless<$name<RhsWidth>>>
|
||||
for Valueless<$name<LhsWidth>>
|
||||
{
|
||||
type Output = Valueless<UInt>;
|
||||
|
||||
fn bitor(self, rhs: Valueless<$name<RhsWidth>>) -> Self::Output {
|
||||
Valueless::new(UInt::new_dyn(self.ty().width().max(rhs.ty().width())))
|
||||
}
|
||||
}
|
||||
|
||||
impl_valueless_op_forward! {
|
||||
#[forward_to = std::ops::BitOr<Valueless<$name<RhsWidth>>>]
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::BitAnd<Valueless<$name<RhsWidth>>>
|
||||
for Valueless<$name<LhsWidth>>
|
||||
{
|
||||
type Output;
|
||||
|
||||
use std::ops::BitOr::<Valueless<$name<RhsWidth>>>::bitor as bitand(self, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl_valueless_op_forward! {
|
||||
#[forward_to = std::ops::BitOr<Valueless<$name<RhsWidth>>>]
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::BitXor<Valueless<$name<RhsWidth>>>
|
||||
for Valueless<$name<LhsWidth>>
|
||||
{
|
||||
type Output;
|
||||
|
||||
use std::ops::BitOr::<Valueless<$name<RhsWidth>>>::bitor as bitxor(self, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> std::ops::Not for Valueless<$name<Width>> {
|
||||
type Output = Valueless<UIntType<Width>>;
|
||||
|
||||
fn not(self) -> Self::Output {
|
||||
Valueless::new(self.ty().as_same_width_uint())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> std::ops::Not for $value<Width> {
|
||||
type Output = UIntValue<Width>;
|
||||
|
||||
fn not(mut self) -> Self::Output {
|
||||
// modifies in-place despite using `Not::not`
|
||||
let _ = Not::not(self.bits_mut());
|
||||
UIntValue::new(self.into_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> std::ops::Not for &'_ $value<Width> {
|
||||
type Output = UIntValue<Width>;
|
||||
|
||||
fn not(self) -> Self::Output {
|
||||
$value::not(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::Mul<Valueless<$name<RhsWidth>>>
|
||||
for Valueless<$name<LhsWidth>>
|
||||
{
|
||||
type Output = Valueless<$name>;
|
||||
|
||||
fn mul(self, rhs: Valueless<$name<RhsWidth>>) -> Self::Output {
|
||||
Valueless::new($name::new_dyn(
|
||||
self.ty()
|
||||
.width()
|
||||
.checked_add(rhs.ty().width())
|
||||
.expect("width too big"),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::Rem<Valueless<$name<RhsWidth>>>
|
||||
for Valueless<$name<LhsWidth>>
|
||||
{
|
||||
type Output = Valueless<$name>;
|
||||
|
||||
fn rem(self, rhs: Valueless<$name<RhsWidth>>) -> Self::Output {
|
||||
Valueless::new($name::new_dyn(self.ty().width().min(rhs.ty().width())))
|
||||
}
|
||||
}
|
||||
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::Shl<Valueless<UIntType<RhsWidth>>>
|
||||
for Valueless<$name<LhsWidth>>
|
||||
{
|
||||
type Output = Valueless<$name>;
|
||||
|
||||
#[track_caller]
|
||||
fn shl(self, rhs: Valueless<UIntType<RhsWidth>>) -> Self::Output {
|
||||
let Some(pow2_rhs_width) = rhs
|
||||
.ty()
|
||||
.width()
|
||||
.try_into()
|
||||
.ok()
|
||||
.and_then(|v| 2usize.checked_pow(v))
|
||||
else {
|
||||
panic!(
|
||||
"dynamic left-shift amount's bit-width is too big, try casting the shift \
|
||||
amount to a smaller bit-width before shifting"
|
||||
);
|
||||
};
|
||||
Valueless::new($name::new_dyn(
|
||||
(pow2_rhs_width - 1)
|
||||
.checked_add(self.ty().width())
|
||||
.expect("width too big"),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::Shr<Valueless<UIntType<RhsWidth>>>
|
||||
for Valueless<$name<LhsWidth>>
|
||||
{
|
||||
type Output = Valueless<$name<LhsWidth>>;
|
||||
|
||||
fn shr(self, _rhs: Valueless<UIntType<RhsWidth>>) -> Self::Output {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<LhsWidth: Size> std::ops::Shl<usize> for Valueless<$name<LhsWidth>> {
|
||||
type Output = Valueless<$name>;
|
||||
|
||||
fn shl(self, rhs: usize) -> Self::Output {
|
||||
Valueless::new($name::new_dyn(
|
||||
self.ty().width().checked_add(rhs).expect("width too big"),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<LhsWidth: Size> std::ops::Shr<usize> for Valueless<$name<LhsWidth>> {
|
||||
type Output = Valueless<$name>;
|
||||
|
||||
fn shr(self, rhs: usize) -> Self::Output {
|
||||
let width = self.ty().width().saturating_sub(rhs);
|
||||
Valueless::new($name::new_dyn(if $SIGNED && width == 0 {
|
||||
1
|
||||
} else {
|
||||
width
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> sealed::BoolOrIntTypeSealed for $name<Width> {}
|
||||
|
||||
impl<Width: Size> BoolOrIntType for $name<Width> {
|
||||
|
|
@ -843,6 +1062,12 @@ macro_rules! impl_int {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, Width: Size> From<&'a $value<Width>> for BigInt {
|
||||
fn from(v: &'a $value<Width>) -> BigInt {
|
||||
v.to_bigint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> $value<Width> {
|
||||
pub fn width(&self) -> usize {
|
||||
if let Some(retval) = Width::KNOWN_VALUE {
|
||||
|
|
@ -861,11 +1086,6 @@ macro_rules! impl_int {
|
|||
pub fn into_bits(self) -> Arc<BitVec> {
|
||||
self.bits
|
||||
}
|
||||
pub fn ty(&self) -> $name<Width> {
|
||||
$name {
|
||||
width: Width::from_usize(self.width()),
|
||||
}
|
||||
}
|
||||
pub fn as_dyn_int(self) -> $value {
|
||||
$value {
|
||||
bits: self.bits,
|
||||
|
|
@ -878,6 +1098,38 @@ macro_rules! impl_int {
|
|||
pub fn bits_mut(&mut self) -> &mut BitSlice {
|
||||
Arc::<BitVec>::make_mut(&mut self.bits)
|
||||
}
|
||||
pub fn hdl_cmp<R: Size>(&self, other: &$value<R>) -> std::cmp::Ordering {
|
||||
self.to_bigint().cmp(&other.to_bigint())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> ValueType for $value<Width> {
|
||||
type Type = $name<Width>;
|
||||
type ValueCategory = ValueCategoryValue;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
$name {
|
||||
width: Width::from_usize(self.width()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Width: Size> ToSimValueInner<'a> for $value<Width> {
|
||||
fn to_sim_value_inner(this: &Self) -> Cow<'_, <Self::Type as Type>::SimValue> {
|
||||
Cow::Borrowed(this)
|
||||
}
|
||||
fn into_sim_value_inner(this: Self) -> Cow<'a, <Self::Type as Type>::SimValue> {
|
||||
Cow::Owned(this)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Width: Size> ToSimValueInner<'a> for &'a $value<Width> {
|
||||
fn to_sim_value_inner(this: &Self) -> Cow<'_, <Self::Type as Type>::SimValue> {
|
||||
Cow::Borrowed(&**this)
|
||||
}
|
||||
fn into_sim_value_inner(this: Self) -> Cow<'a, <Self::Type as Type>::SimValue> {
|
||||
Cow::Borrowed(this)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> ToLiteralBits for $value<Width> {
|
||||
|
|
@ -1015,11 +1267,58 @@ impl SInt {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_prim_int {
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::Div<Valueless<UIntType<RhsWidth>>>
|
||||
for Valueless<UIntType<LhsWidth>>
|
||||
{
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, _rhs: Valueless<UIntType<RhsWidth>>) -> Self::Output {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<LhsWidth: Size, RhsWidth: Size> std::ops::Div<Valueless<SIntType<RhsWidth>>>
|
||||
for Valueless<SIntType<LhsWidth>>
|
||||
{
|
||||
type Output = Valueless<SInt>;
|
||||
|
||||
fn div(self, _rhs: Valueless<SIntType<RhsWidth>>) -> Self::Output {
|
||||
Valueless::new(SInt::new_dyn(
|
||||
self.ty().width().checked_add(1).expect("width too big"),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> std::ops::Neg for Valueless<SIntType<Width>> {
|
||||
type Output = Valueless<SInt>;
|
||||
fn neg(self) -> Self::Output {
|
||||
Valueless::new(SInt::new_dyn(
|
||||
self.ty().width().checked_add(1).expect("width too big"),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> std::ops::Neg for SIntValue<Width> {
|
||||
type Output = SIntValue;
|
||||
fn neg(self) -> Self::Output {
|
||||
-&self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> std::ops::Neg for &'_ SIntValue<Width> {
|
||||
type Output = SIntValue;
|
||||
fn neg(self) -> Self::Output {
|
||||
let ty = self.to_valueless().neg().ty();
|
||||
ty.from_bigint_wrapping(&-self.to_bigint())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_prim_int_to_expr {
|
||||
(
|
||||
$(#[$meta:meta])*
|
||||
$prim_int:ident, $ty:ty
|
||||
) => {
|
||||
$(#[$meta])*
|
||||
impl From<$prim_int> for <$ty as BoolOrIntType>::Value {
|
||||
fn from(v: $prim_int) -> Self {
|
||||
<$ty>::le_bytes_to_value_wrapping(
|
||||
|
|
@ -1028,15 +1327,32 @@ macro_rules! impl_prim_int {
|
|||
)
|
||||
}
|
||||
}
|
||||
$(#[$meta])*
|
||||
impl From<NonZero<$prim_int>> for <$ty as BoolOrIntType>::Value {
|
||||
fn from(v: NonZero<$prim_int>) -> Self {
|
||||
v.get().into()
|
||||
}
|
||||
}
|
||||
$(#[$meta])*
|
||||
impl ToExpr for $prim_int {
|
||||
impl<'a> ToSimValueInner<'a> for $prim_int {
|
||||
fn to_sim_value_inner(this: &Self) -> Cow<'_, <Self::Type as Type>::SimValue> {
|
||||
Self::into_sim_value_inner(*this)
|
||||
}
|
||||
fn into_sim_value_inner(this: Self) -> Cow<'a, <Self::Type as Type>::SimValue> {
|
||||
Cow::Owned(this.into())
|
||||
}
|
||||
}
|
||||
$(#[$meta])*
|
||||
impl ValueType for $prim_int {
|
||||
type Type = $ty;
|
||||
type ValueCategory = ValueCategoryValue;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
StaticType::TYPE
|
||||
}
|
||||
}
|
||||
$(#[$meta])*
|
||||
impl ToExpr for $prim_int {
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
<$ty>::le_bytes_to_expr_wrapping(
|
||||
&self.to_le_bytes(),
|
||||
|
|
@ -1045,9 +1361,25 @@ macro_rules! impl_prim_int {
|
|||
}
|
||||
}
|
||||
$(#[$meta])*
|
||||
impl ToExpr for NonZero<$prim_int> {
|
||||
impl<'a> ToSimValueInner<'a> for NonZero<$prim_int> {
|
||||
fn to_sim_value_inner(this: &Self) -> Cow<'_, <Self::Type as Type>::SimValue> {
|
||||
Self::into_sim_value_inner(*this)
|
||||
}
|
||||
fn into_sim_value_inner(this: Self) -> Cow<'a, <Self::Type as Type>::SimValue> {
|
||||
Cow::Owned(this.into())
|
||||
}
|
||||
}
|
||||
$(#[$meta])*
|
||||
impl ValueType for NonZero<$prim_int> {
|
||||
type Type = $ty;
|
||||
type ValueCategory = ValueCategoryValue;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
StaticType::TYPE
|
||||
}
|
||||
}
|
||||
$(#[$meta])*
|
||||
impl ToExpr for NonZero<$prim_int> {
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
self.get().to_expr()
|
||||
}
|
||||
|
|
@ -1055,28 +1387,208 @@ macro_rules! impl_prim_int {
|
|||
};
|
||||
}
|
||||
|
||||
impl_prim_int!(u8, UInt<8>);
|
||||
impl_prim_int!(u16, UInt<16>);
|
||||
impl_prim_int!(u32, UInt<32>);
|
||||
impl_prim_int!(u64, UInt<64>);
|
||||
impl_prim_int!(u128, UInt<128>);
|
||||
impl_prim_int!(i8, SInt<8>);
|
||||
impl_prim_int!(i16, SInt<16>);
|
||||
impl_prim_int!(i32, SInt<32>);
|
||||
impl_prim_int!(i64, SInt<64>);
|
||||
impl_prim_int!(i128, SInt<128>);
|
||||
macro_rules! impl_for_all_prim_uints {
|
||||
(
|
||||
#[size =, $(rest:tt)*]
|
||||
$m:ident!()
|
||||
) => {
|
||||
impl_for_all_prim_uints!(
|
||||
#[usize =, $($rest)*]
|
||||
$m!()
|
||||
);
|
||||
};
|
||||
(
|
||||
#[size = size, $(rest:tt)*]
|
||||
$m:ident!()
|
||||
) => {
|
||||
impl_for_all_prim_uints!(
|
||||
#[usize = usize, $($rest)*]
|
||||
$m!()
|
||||
);
|
||||
};
|
||||
(
|
||||
#[usize = $($usize:ident)?, NonZero = $NonZero:ident]
|
||||
$m:ident!()
|
||||
) => {
|
||||
impl_for_all_prim_uints!(
|
||||
#[usize = $($usize)?, NonZero = $NonZero, NonZero<usize> = $((NonZero<$usize>))?]
|
||||
$m!()
|
||||
);
|
||||
};
|
||||
(
|
||||
#[usize = $($usize:ident)?, NonZero =]
|
||||
$m:ident!()
|
||||
) => {
|
||||
impl_for_all_prim_uints!(
|
||||
#[usize = $($usize)?, NonZero =, NonZero<usize> =]
|
||||
$m!()
|
||||
);
|
||||
};
|
||||
(
|
||||
#[usize = $($usize:ident)?, NonZero = $($NonZero:ident)?, NonZero<usize> = $(($($NonZeroUsize:tt)*))?]
|
||||
$m:ident!()
|
||||
) => {
|
||||
$m!(u8, UInt<8>);
|
||||
$m!(u16, UInt<16>);
|
||||
$m!(u32, UInt<32>);
|
||||
$m!(u64, UInt<64>);
|
||||
$m!(u128, UInt<128>);
|
||||
$($m!($NonZero<u8>, UInt<8>);)?
|
||||
$($m!($NonZero<u16>, UInt<16>);)?
|
||||
$($m!($NonZero<u32>, UInt<32>);)?
|
||||
$($m!($NonZero<u64>, UInt<64>);)?
|
||||
$($m!($NonZero<u128>, UInt<128>);)?
|
||||
$($m!(
|
||||
/// for portability reasons, [`usize`] always translates to [`UInt<64>`][type@UInt]
|
||||
$usize, UInt<64>
|
||||
);)?
|
||||
$($m!(
|
||||
/// for portability reasons, [`usize`] always translates to [`UInt<64>`][type@UInt]
|
||||
$($NonZeroUsize)*, UInt<64>
|
||||
);)?
|
||||
};
|
||||
}
|
||||
|
||||
impl_prim_int!(
|
||||
/// for portability reasons, [`usize`] always translates to [`UInt<64>`][type@UInt]
|
||||
usize, UInt<64>
|
||||
macro_rules! impl_for_all_prim_sints {
|
||||
(
|
||||
#[size =, $(rest:tt)*]
|
||||
$m:ident!()
|
||||
) => {
|
||||
impl_for_all_prim_sints!(
|
||||
#[isize =, $($rest)*]
|
||||
$m!()
|
||||
);
|
||||
};
|
||||
(
|
||||
#[size = size, $(rest:tt)*]
|
||||
$m:ident!()
|
||||
) => {
|
||||
impl_for_all_prim_sints!(
|
||||
#[isize = isize, $($rest)*]
|
||||
$m!()
|
||||
);
|
||||
};
|
||||
(
|
||||
#[isize = $($isize:ident)?, NonZero = $NonZero:ident]
|
||||
$m:ident!()
|
||||
) => {
|
||||
impl_for_all_prim_sints!(
|
||||
#[isize = $($isize)?, NonZero = $NonZero, NonZero<isize> = $((NonZero<$isize>))?]
|
||||
$m!()
|
||||
);
|
||||
};
|
||||
(
|
||||
#[isize = $($isize:ident)?, NonZero =]
|
||||
$m:ident!()
|
||||
) => {
|
||||
impl_for_all_prim_sints!(
|
||||
#[isize = $($isize)?, NonZero =, NonZero<isize> =]
|
||||
$m!()
|
||||
);
|
||||
};
|
||||
(
|
||||
#[isize = $($isize:ident)?, NonZero = $($NonZero:ident)?, NonZero<isize> = $(($($NonZeroIsize:tt)*))?]
|
||||
$m:ident!()
|
||||
) => {
|
||||
$m!(i8, SInt<8>);
|
||||
$m!(i16, SInt<16>);
|
||||
$m!(i32, SInt<32>);
|
||||
$m!(i64, SInt<64>);
|
||||
$m!(i128, SInt<128>);
|
||||
$($m!($NonZero<i8>, SInt<8>);)?
|
||||
$($m!($NonZero<i16>, SInt<16>);)?
|
||||
$($m!($NonZero<i32>, SInt<32>);)?
|
||||
$($m!($NonZero<i64>, SInt<64>);)?
|
||||
$($m!($NonZero<i128>, SInt<128>);)?
|
||||
$($m!(
|
||||
/// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt]
|
||||
$isize, SInt<64>
|
||||
);)?
|
||||
$($m!(
|
||||
/// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt]
|
||||
$($NonZeroIsize)*, SInt<64>
|
||||
);)?
|
||||
};
|
||||
}
|
||||
|
||||
impl_for_all_prim_uints!(
|
||||
#[usize = usize, NonZero =]
|
||||
impl_prim_int_to_expr!()
|
||||
);
|
||||
|
||||
impl_prim_int!(
|
||||
/// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt]
|
||||
isize, SInt<64>
|
||||
impl_for_all_prim_sints!(
|
||||
#[isize = isize, NonZero =]
|
||||
impl_prim_int_to_expr!()
|
||||
);
|
||||
|
||||
pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
|
||||
macro_rules! impl_prim_int_from_value {
|
||||
($prim_int:ident, UInt<$width:literal>) => {
|
||||
impl_prim_int_from_value!($prim_int, UInt<$width>, UIntValue<ConstUsize<$width>>);
|
||||
};
|
||||
($prim_int:ident, SInt<$width:literal>) => {
|
||||
impl_prim_int_from_value!($prim_int, SInt<$width>, SIntValue<ConstUsize<$width>>);
|
||||
};
|
||||
($prim_int:ident, $ty:ty, $value:ty) => {
|
||||
impl From<$value> for $prim_int {
|
||||
fn from(value: $value) -> Self {
|
||||
value.as_int()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a mut $value> for $prim_int {
|
||||
fn from(value: &'a mut $value) -> Self {
|
||||
value.as_int()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SimValue<$ty>> for $prim_int {
|
||||
fn from(value: SimValue<$ty>) -> Self {
|
||||
value.as_int()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a mut SimValue<$ty>> for $prim_int {
|
||||
fn from(value: &'a mut SimValue<$ty>) -> Self {
|
||||
value.as_int()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a SimValue<$ty>> for $prim_int {
|
||||
fn from(value: &'a SimValue<$ty>) -> Self {
|
||||
value.as_int()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a $value> for $prim_int {
|
||||
fn from(value: &'a $value) -> Self {
|
||||
value.as_int()
|
||||
}
|
||||
}
|
||||
|
||||
impl $value {
|
||||
pub fn as_int(&self) -> $prim_int {
|
||||
let mut le_bytes = (0 as $prim_int).to_le_bytes();
|
||||
let bitslice = BitSlice::<u8, Lsb0>::from_slice_mut(&mut le_bytes);
|
||||
bitslice.clone_from_bitslice(self.bits());
|
||||
$prim_int::from_le_bytes(le_bytes)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_for_all_prim_uints!(
|
||||
#[usize =, NonZero =]
|
||||
impl_prim_int_from_value!()
|
||||
);
|
||||
|
||||
impl_for_all_prim_sints!(
|
||||
#[isize =, NonZero =]
|
||||
impl_prim_int_from_value!()
|
||||
);
|
||||
|
||||
pub trait BoolOrIntType:
|
||||
Type<SimValue = <Self as BoolOrIntType>::Value> + sealed::BoolOrIntTypeSealed
|
||||
{
|
||||
type Width: Size;
|
||||
type Signed: GenericConstBool;
|
||||
type Value: Clone
|
||||
|
|
@ -1301,12 +1813,80 @@ impl StaticType for Bool {
|
|||
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
|
||||
}
|
||||
|
||||
impl From<bool> for UIntValue<ConstUsize<1>> {
|
||||
fn from(value: bool) -> Self {
|
||||
static VALUES: OnceLock<[UIntValue<ConstUsize<1>>; 2]> = OnceLock::new();
|
||||
let values = VALUES
|
||||
.get_or_init(|| std::array::from_fn(|i| UInt::<1>::new_static().from_int_wrapping(i)));
|
||||
values[value as usize].clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for SIntValue<ConstUsize<1>> {
|
||||
fn from(value: bool) -> Self {
|
||||
SIntValue::new(UIntValue::<ConstUsize<1>>::from(value).into_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for UIntValue {
|
||||
fn from(value: bool) -> Self {
|
||||
UIntValue::new(UIntValue::<ConstUsize<1>>::from(value).into_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for SIntValue {
|
||||
fn from(value: bool) -> Self {
|
||||
SIntValue::new(UIntValue::<ConstUsize<1>>::from(value).into_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToLiteralBits for bool {
|
||||
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
||||
Ok(interned_bit(*self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToSimValueInner<'a> for bool {
|
||||
fn to_sim_value_inner(this: &Self) -> Cow<'_, <Self::Type as Type>::SimValue> {
|
||||
Cow::Owned(*this)
|
||||
}
|
||||
fn into_sim_value_inner(this: Self) -> Cow<'a, <Self::Type as Type>::SimValue> {
|
||||
Cow::Owned(this)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Not for Valueless<Bool> {
|
||||
type Output = Valueless<Bool>;
|
||||
|
||||
fn not(self) -> Self::Output {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitAnd for Valueless<Bool> {
|
||||
type Output = Valueless<Bool>;
|
||||
|
||||
fn bitand(self, _rhs: Valueless<Bool>) -> Self::Output {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for Valueless<Bool> {
|
||||
type Output = Valueless<Bool>;
|
||||
|
||||
fn bitor(self, _rhs: Valueless<Bool>) -> Self::Output {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitXor for Valueless<Bool> {
|
||||
type Output = Valueless<Bool>;
|
||||
|
||||
fn bitxor(self, _rhs: Valueless<Bool>) -> Self::Output {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
use crate::{
|
||||
bundle::{Bundle, BundleField, BundleType, BundleTypePropertiesBuilder, NoBuilder},
|
||||
expr::{
|
||||
CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd,
|
||||
ops::{ExprCastTo, ExprPartialEq, ExprPartialOrd},
|
||||
CastBitsTo, CastTo, CastToBits, CastToImpl, Expr, HdlPartialEq, HdlPartialEqImpl,
|
||||
HdlPartialOrd, HdlPartialOrdImpl,
|
||||
},
|
||||
int::{Bool, DynSize, KnownSize, Size, SizeType, UInt, UIntType},
|
||||
int::{Bool, DynSize, KnownSize, Size, SizeType, UInt, UIntType, UIntValue},
|
||||
intern::{Intern, InternSlice, Interned},
|
||||
phantom_const::PhantomConst,
|
||||
sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType},
|
||||
sim::value::{SimValue, ToSimValueWithType},
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
|
||||
|
|
@ -22,7 +22,7 @@ use serde::{
|
|||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
de::{Error, Visitor, value::UsizeDeserializer},
|
||||
};
|
||||
use std::{fmt, marker::PhantomData, ops::Index};
|
||||
use std::{borrow::Cow, fmt, marker::PhantomData, ops::Index};
|
||||
|
||||
const UINT_IN_RANGE_TYPE_FIELD_NAMES: [&'static str; 2] = ["value", "range"];
|
||||
|
||||
|
|
@ -135,30 +135,57 @@ impl ToSimValueWithType<UIntInRangeMaskType> for bool {
|
|||
}
|
||||
}
|
||||
|
||||
impl ExprCastTo<Bool> for UIntInRangeMaskType {
|
||||
fn cast_to(src: Expr<Self>, to_type: Bool) -> Expr<Bool> {
|
||||
src.cast_to_bits().cast_to(to_type)
|
||||
impl CastToImpl<Bool> for UIntInRangeMaskType {
|
||||
type ValueOutput = bool;
|
||||
|
||||
fn cast_value_to(
|
||||
_this: Self,
|
||||
value: Cow<'_, Self::SimValue>,
|
||||
_to_type: Bool,
|
||||
) -> Self::ValueOutput {
|
||||
*value
|
||||
}
|
||||
|
||||
fn cast_expr_to(value: Expr<Self>, to_type: Bool) -> Expr<Bool> {
|
||||
value.cast_to_bits().cast_to(to_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExprCastTo<UIntInRangeMaskType> for Bool {
|
||||
fn cast_to(src: Expr<Self>, to_type: UIntInRangeMaskType) -> Expr<UIntInRangeMaskType> {
|
||||
src.cast_to_static::<UInt<1>>().cast_bits_to(to_type)
|
||||
impl CastToImpl<UIntInRangeMaskType> for Bool {
|
||||
type ValueOutput = SimValue<UIntInRangeMaskType>;
|
||||
|
||||
fn cast_value_to(
|
||||
_this: Self,
|
||||
value: Cow<'_, Self::SimValue>,
|
||||
to_type: UIntInRangeMaskType,
|
||||
) -> Self::ValueOutput {
|
||||
SimValue::from_value(to_type, *value)
|
||||
}
|
||||
|
||||
fn cast_expr_to(value: Expr<Self>, to_type: UIntInRangeMaskType) -> Expr<UIntInRangeMaskType> {
|
||||
value.cast_to_static::<UInt<1>>().cast_bits_to(to_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExprPartialEq<Self> for UIntInRangeMaskType {
|
||||
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
impl HdlPartialEqImpl<Self> for UIntInRangeMaskType {
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: Self,
|
||||
rhs_value: Cow<'_, Self::SimValue>,
|
||||
) -> bool {
|
||||
*lhs_value == *rhs_value
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl SimValuePartialEq<Self> for UIntInRangeMaskType {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||
**this == **other
|
||||
#[track_caller]
|
||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -482,36 +509,64 @@ macro_rules! define_uint_in_range_type {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Start: Size, End: Size, Width: Size> ExprCastTo<UIntType<Width>>
|
||||
impl<Start: Size, End: Size, Width: Size> CastToImpl<UIntType<Width>>
|
||||
for $UIntInRangeType<Start, End>
|
||||
{
|
||||
fn cast_to(src: Expr<Self>, to_type: UIntType<Width>) -> Expr<UIntType<Width>> {
|
||||
src.cast_to_bits().cast_to(to_type)
|
||||
type ValueOutput = UIntValue<Width>;
|
||||
|
||||
fn cast_value_to(
|
||||
_this: Self,
|
||||
value: Cow<'_, Self::SimValue>,
|
||||
to_type: UIntType<Width>,
|
||||
) -> Self::ValueOutput {
|
||||
value.cast_to(to_type)
|
||||
}
|
||||
|
||||
fn cast_expr_to(value: Expr<Self>, to_type: UIntType<Width>) -> Expr<UIntType<Width>> {
|
||||
value.cast_to_bits().cast_to(to_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Start: Size, End: Size, Width: Size> ExprCastTo<$UIntInRangeType<Start, End>>
|
||||
impl<Start: Size, End: Size, Width: Size> CastToImpl<$UIntInRangeType<Start, End>>
|
||||
for UIntType<Width>
|
||||
{
|
||||
fn cast_to(
|
||||
src: Expr<Self>,
|
||||
type ValueOutput = SimValue<$UIntInRangeType<Start, End>>;
|
||||
|
||||
fn cast_value_to(
|
||||
_this: Self,
|
||||
value: Cow<'_, Self::SimValue>,
|
||||
to_type: $UIntInRangeType<Start, End>,
|
||||
) -> Self::ValueOutput {
|
||||
value.cast_to(to_type.value).cast_bits_to(to_type)
|
||||
}
|
||||
|
||||
fn cast_expr_to(
|
||||
value: Expr<Self>,
|
||||
to_type: $UIntInRangeType<Start, End>,
|
||||
) -> Expr<$UIntInRangeType<Start, End>> {
|
||||
src.cast_to(to_type.value).cast_bits_to(to_type)
|
||||
value.cast_to(to_type.value).cast_bits_to(to_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl<LhsStart: Size, LhsEnd: Size, RhsStart: Size, RhsEnd: Size>
|
||||
ExprPartialEq<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||
HdlPartialEqImpl<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||
for $UIntInRangeType<LhsStart, LhsEnd>
|
||||
{
|
||||
fn cmp_eq(
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: $UIntInRangeType<RhsStart, RhsEnd>,
|
||||
rhs_value: Cow<'_, <$UIntInRangeType<RhsStart, RhsEnd> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
*lhs_value == *rhs_value
|
||||
}
|
||||
fn cmp_expr_eq(
|
||||
lhs: Expr<Self>,
|
||||
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||
) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
fn cmp_ne(
|
||||
fn cmp_expr_ne(
|
||||
lhs: Expr<Self>,
|
||||
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||
) -> Expr<Bool> {
|
||||
|
|
@ -520,28 +575,60 @@ macro_rules! define_uint_in_range_type {
|
|||
}
|
||||
|
||||
impl<LhsStart: Size, LhsEnd: Size, RhsStart: Size, RhsEnd: Size>
|
||||
ExprPartialOrd<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||
HdlPartialOrdImpl<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||
for $UIntInRangeType<LhsStart, LhsEnd>
|
||||
{
|
||||
fn cmp_lt(
|
||||
fn cmp_value_lt(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: $UIntInRangeType<RhsStart, RhsEnd>,
|
||||
rhs_value: Cow<'_, <$UIntInRangeType<RhsStart, RhsEnd> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
PartialOrd::lt(&*lhs_value, &*rhs_value)
|
||||
}
|
||||
fn cmp_value_le(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: $UIntInRangeType<RhsStart, RhsEnd>,
|
||||
rhs_value: Cow<'_, <$UIntInRangeType<RhsStart, RhsEnd> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
PartialOrd::le(&*lhs_value, &*rhs_value)
|
||||
}
|
||||
fn cmp_value_gt(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: $UIntInRangeType<RhsStart, RhsEnd>,
|
||||
rhs_value: Cow<'_, <$UIntInRangeType<RhsStart, RhsEnd> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
PartialOrd::gt(&*lhs_value, &*rhs_value)
|
||||
}
|
||||
fn cmp_value_ge(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: $UIntInRangeType<RhsStart, RhsEnd>,
|
||||
rhs_value: Cow<'_, <$UIntInRangeType<RhsStart, RhsEnd> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
PartialOrd::ge(&*lhs_value, &*rhs_value)
|
||||
}
|
||||
fn cmp_expr_lt(
|
||||
lhs: Expr<Self>,
|
||||
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||
) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_lt(rhs.cast_to_bits())
|
||||
}
|
||||
fn cmp_le(
|
||||
fn cmp_expr_le(
|
||||
lhs: Expr<Self>,
|
||||
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||
) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_le(rhs.cast_to_bits())
|
||||
}
|
||||
fn cmp_gt(
|
||||
fn cmp_expr_gt(
|
||||
lhs: Expr<Self>,
|
||||
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||
) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_gt(rhs.cast_to_bits())
|
||||
}
|
||||
fn cmp_ge(
|
||||
fn cmp_expr_ge(
|
||||
lhs: Expr<Self>,
|
||||
rhs: Expr<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||
) -> Expr<Bool> {
|
||||
|
|
@ -549,70 +636,138 @@ macro_rules! define_uint_in_range_type {
|
|||
}
|
||||
}
|
||||
|
||||
impl<LhsStart: Size, LhsEnd: Size, RhsStart: Size, RhsEnd: Size>
|
||||
SimValuePartialEq<$UIntInRangeType<RhsStart, RhsEnd>>
|
||||
for $UIntInRangeType<LhsStart, LhsEnd>
|
||||
{
|
||||
fn sim_value_eq(
|
||||
this: &SimValue<Self>,
|
||||
other: &SimValue<$UIntInRangeType<RhsStart, RhsEnd>>,
|
||||
) -> bool {
|
||||
**this == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl<Start: Size, End: Size, Width: Size> ExprPartialEq<UIntType<Width>>
|
||||
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<UIntType<Width>>
|
||||
for $UIntInRangeType<Start, End>
|
||||
{
|
||||
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: UIntType<Width>,
|
||||
rhs_value: Cow<'_, UIntValue<Width>>,
|
||||
) -> bool {
|
||||
HdlPartialEq::cmp_eq(&*lhs_value, &*rhs_value)
|
||||
}
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs)
|
||||
}
|
||||
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_ne(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Start: Size, End: Size, Width: Size> ExprPartialEq<$UIntInRangeType<Start, End>>
|
||||
impl<Start: Size, End: Size, Width: Size> HdlPartialEqImpl<$UIntInRangeType<Start, End>>
|
||||
for UIntType<Width>
|
||||
{
|
||||
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: $UIntInRangeType<Start, End>,
|
||||
rhs_value: Cow<'_, <$UIntInRangeType<Start, End> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
HdlPartialEq::cmp_eq(&*lhs_value, *rhs_value)
|
||||
}
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
lhs.cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
lhs.cmp_ne(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Start: Size, End: Size, Width: Size> ExprPartialOrd<UIntType<Width>>
|
||||
impl<Start: Size, End: Size, Width: Size> HdlPartialOrdImpl<UIntType<Width>>
|
||||
for $UIntInRangeType<Start, End>
|
||||
{
|
||||
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
fn cmp_value_lt(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: UIntType<Width>,
|
||||
rhs_value: Cow<'_, UIntValue<Width>>,
|
||||
) -> bool {
|
||||
HdlPartialOrd::cmp_lt(&*lhs_value, &*rhs_value)
|
||||
}
|
||||
fn cmp_value_le(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: UIntType<Width>,
|
||||
rhs_value: Cow<'_, UIntValue<Width>>,
|
||||
) -> bool {
|
||||
HdlPartialOrd::cmp_le(&*lhs_value, &*rhs_value)
|
||||
}
|
||||
fn cmp_value_gt(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: UIntType<Width>,
|
||||
rhs_value: Cow<'_, UIntValue<Width>>,
|
||||
) -> bool {
|
||||
HdlPartialOrd::cmp_gt(&*lhs_value, &*rhs_value)
|
||||
}
|
||||
fn cmp_value_ge(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: UIntType<Width>,
|
||||
rhs_value: Cow<'_, UIntValue<Width>>,
|
||||
) -> bool {
|
||||
HdlPartialOrd::cmp_ge(&*lhs_value, &*rhs_value)
|
||||
}
|
||||
fn cmp_expr_lt(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_lt(rhs)
|
||||
}
|
||||
fn cmp_le(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
fn cmp_expr_le(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_le(rhs)
|
||||
}
|
||||
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
fn cmp_expr_gt(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_gt(rhs)
|
||||
}
|
||||
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
fn cmp_expr_ge(lhs: Expr<Self>, rhs: Expr<UIntType<Width>>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_ge(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Start: Size, End: Size, Width: Size> ExprPartialOrd<$UIntInRangeType<Start, End>>
|
||||
impl<Start: Size, End: Size, Width: Size> HdlPartialOrdImpl<$UIntInRangeType<Start, End>>
|
||||
for UIntType<Width>
|
||||
{
|
||||
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
fn cmp_value_lt(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: $UIntInRangeType<Start, End>,
|
||||
rhs_value: Cow<'_, <$UIntInRangeType<Start, End> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
HdlPartialOrd::cmp_lt(&*lhs_value, *rhs_value)
|
||||
}
|
||||
fn cmp_value_le(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: $UIntInRangeType<Start, End>,
|
||||
rhs_value: Cow<'_, <$UIntInRangeType<Start, End> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
HdlPartialOrd::cmp_le(&*lhs_value, *rhs_value)
|
||||
}
|
||||
fn cmp_value_gt(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: $UIntInRangeType<Start, End>,
|
||||
rhs_value: Cow<'_, <$UIntInRangeType<Start, End> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
HdlPartialOrd::cmp_gt(&*lhs_value, *rhs_value)
|
||||
}
|
||||
fn cmp_value_ge(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: $UIntInRangeType<Start, End>,
|
||||
rhs_value: Cow<'_, <$UIntInRangeType<Start, End> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
HdlPartialOrd::cmp_ge(&*lhs_value, *rhs_value)
|
||||
}
|
||||
fn cmp_expr_lt(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
lhs.cmp_lt(rhs.cast_to_bits())
|
||||
}
|
||||
fn cmp_le(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
fn cmp_expr_le(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
lhs.cmp_le(rhs.cast_to_bits())
|
||||
}
|
||||
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
fn cmp_expr_gt(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
lhs.cmp_gt(rhs.cast_to_bits())
|
||||
}
|
||||
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
fn cmp_expr_ge(lhs: Expr<Self>, rhs: Expr<$UIntInRangeType<Start, End>>) -> Expr<Bool> {
|
||||
lhs.cmp_ge(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ use crate::{
|
|||
array::{Array, ArrayType},
|
||||
bundle::{Bundle, BundleType},
|
||||
clock::Clock,
|
||||
expr::{Expr, Flow, ToExpr, ToLiteralBits, ops::BundleLiteral, repeat},
|
||||
expr::{
|
||||
Expr, Flow, ToExpr, ToLiteralBits, ValueType, ops::BundleLiteral, repeat,
|
||||
value_category::ValueCategoryExpr,
|
||||
},
|
||||
hdl,
|
||||
int::{Bool, DynSize, Size, UInt, UIntType},
|
||||
intern::{Intern, Interned},
|
||||
|
|
@ -366,10 +369,16 @@ impl<T: PortType> fmt::Debug for MemPort<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: PortType> MemPort<T> {
|
||||
pub fn ty(&self) -> T::Port {
|
||||
impl<T: PortType> ValueType for MemPort<T> {
|
||||
type Type = T::Port;
|
||||
type ValueCategory = ValueCategoryExpr;
|
||||
|
||||
fn ty(&self) -> T::Port {
|
||||
T::port_ty(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PortType> MemPort<T> {
|
||||
pub fn source_location(&self) -> SourceLocation {
|
||||
self.source_location
|
||||
}
|
||||
|
|
@ -830,7 +839,7 @@ impl<Element: Type, Len: Size> MemBuilder<Element, Len> {
|
|||
depth: Option<usize>,
|
||||
initial_value: Expr<Array>,
|
||||
) -> Interned<BitSlice> {
|
||||
let initial_value_ty = Expr::ty(initial_value);
|
||||
let initial_value_ty = initial_value.ty();
|
||||
assert_eq!(
|
||||
*mem_element_type,
|
||||
Element::from_canonical(initial_value_ty.element()),
|
||||
|
|
@ -1011,7 +1020,7 @@ impl<Element: Type, Len: Size> MemBuilder<Element, Len> {
|
|||
target.depth,
|
||||
initial_value,
|
||||
));
|
||||
target.depth = Some(Expr::ty(initial_value).len());
|
||||
target.depth = Some(initial_value.ty().len());
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn initial_value_bit_slice(&mut self, initial_value: Interned<BitSlice>) {
|
||||
|
|
|
|||
|
|
@ -8,12 +8,13 @@ use crate::{
|
|||
clock::{Clock, ClockDomain},
|
||||
enum_::{Enum, EnumMatchVariantsIter, EnumType},
|
||||
expr::{
|
||||
Expr, Flow, ToExpr,
|
||||
Expr, Flow, ToExpr, ValueType,
|
||||
ops::VariantAccess,
|
||||
target::{
|
||||
GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField,
|
||||
TargetPathElement,
|
||||
},
|
||||
value_category::ValueCategoryExpr,
|
||||
},
|
||||
formal::FormalKind,
|
||||
int::{Bool, DynSize, Size},
|
||||
|
|
@ -205,7 +206,7 @@ impl StmtConnect {
|
|||
source_location,
|
||||
} = *self;
|
||||
assert!(
|
||||
Expr::ty(lhs).can_connect(Expr::ty(rhs)),
|
||||
lhs.ty().can_connect(rhs.ty()),
|
||||
"can't connect types that are not equivalent:\nlhs type:\n{lhs_orig_ty:?}\nrhs type:\n{rhs_orig_ty:?}\nat: {source_location}",
|
||||
);
|
||||
assert!(
|
||||
|
|
@ -219,14 +220,14 @@ impl StmtConnect {
|
|||
match Expr::flow(rhs) {
|
||||
Flow::Source | Flow::Duplex => {}
|
||||
Flow::Sink => assert!(
|
||||
Expr::ty(rhs).is_passive(),
|
||||
rhs.ty().is_passive(),
|
||||
"can't connect from sink with non-passive type\nat: {source_location}"
|
||||
),
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
fn assert_validity(&self) {
|
||||
self.assert_validity_with_original_types(Expr::ty(self.lhs), Expr::ty(self.rhs));
|
||||
self.assert_validity_with_original_types(self.lhs.ty(), self.rhs.ty());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -331,7 +332,7 @@ impl Copy for StmtMatch {}
|
|||
impl StmtMatch {
|
||||
#[track_caller]
|
||||
fn assert_validity(&self) {
|
||||
assert_eq!(Expr::ty(self.expr).variants().len(), self.blocks.len());
|
||||
assert_eq!(self.expr.ty().variants().len(), self.blocks.len());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -765,6 +766,15 @@ impl<T: BundleType> fmt::Debug for Instance<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: BundleType> ValueType for Instance<T> {
|
||||
type Type = T;
|
||||
type ValueCategory = ValueCategoryExpr;
|
||||
|
||||
fn ty(&self) -> T {
|
||||
self.instantiated.io_ty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: BundleType> Instance<T> {
|
||||
pub fn canonical(self) -> Instance<Bundle> {
|
||||
let Self {
|
||||
|
|
@ -828,9 +838,6 @@ impl<T: BundleType> Instance<T> {
|
|||
pub fn must_connect_to(&self) -> bool {
|
||||
true
|
||||
}
|
||||
pub fn ty(&self) -> T {
|
||||
self.instantiated.io_ty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
|
|
@ -2028,7 +2035,7 @@ impl<CD> RegBuilder<CD, (), ()> {
|
|||
init: _,
|
||||
ty: _,
|
||||
} = self;
|
||||
let ty = Expr::ty(init);
|
||||
let ty = init.ty();
|
||||
RegBuilder {
|
||||
name,
|
||||
source_location,
|
||||
|
|
@ -2597,7 +2604,7 @@ pub fn enum_match_variants_helper<T: EnumType>(
|
|||
ModuleBuilder::with(|m| {
|
||||
let mut impl_ = m.impl_.borrow_mut();
|
||||
let body = impl_.body.builder_normal_body();
|
||||
let enum_ty = Expr::ty(base);
|
||||
let enum_ty = base.ty();
|
||||
let outer_block: BlockId = m.block_stack.top();
|
||||
let blocks = Interned::from_iter(enum_ty.variants().iter().map(|_| body.new_block()));
|
||||
body.block(outer_block).stmts.push(
|
||||
|
|
@ -2649,7 +2656,7 @@ pub fn connect_any_with_loc<Lhs: ToExpr, Rhs: ToExpr>(
|
|||
rhs,
|
||||
source_location,
|
||||
};
|
||||
connect.assert_validity_with_original_types(Expr::ty(lhs_orig), Expr::ty(rhs_orig));
|
||||
connect.assert_validity_with_original_types(lhs_orig.ty(), rhs_orig.ty());
|
||||
ModuleBuilder::with(|m| {
|
||||
m.impl_
|
||||
.borrow_mut()
|
||||
|
|
@ -2764,7 +2771,7 @@ pub fn memory_with_init_and_loc<Element: Type, Len: Size>(
|
|||
source_location: SourceLocation,
|
||||
) -> MemBuilder<Element, Len> {
|
||||
let initial_value = initial_value.to_expr();
|
||||
let mut retval = memory_array_with_loc(name, Expr::ty(initial_value), source_location);
|
||||
let mut retval = memory_array_with_loc(name, initial_value.ty(), source_location);
|
||||
retval.initial_value(initial_value);
|
||||
retval
|
||||
}
|
||||
|
|
@ -2807,6 +2814,15 @@ pub struct ModuleIO<T: Type> {
|
|||
source_location: SourceLocation,
|
||||
}
|
||||
|
||||
impl<T: Type> ValueType for ModuleIO<T> {
|
||||
type Type = T;
|
||||
type ValueCategory = ValueCategoryExpr;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
self.ty
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type> fmt::Debug for ModuleIO<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ModuleIO")
|
||||
|
|
@ -2908,9 +2924,6 @@ impl<T: Type> ModuleIO<T> {
|
|||
unreachable!()
|
||||
}
|
||||
}
|
||||
pub fn ty(&self) -> T {
|
||||
self.ty
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
bundle::{BundleField, BundleType},
|
||||
enum_::{EnumType, EnumVariant},
|
||||
expr::{
|
||||
ExprEnum,
|
||||
ExprEnum, ValueType,
|
||||
ops::{self, ArrayLiteral},
|
||||
target::{
|
||||
Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField,
|
||||
|
|
@ -521,7 +521,7 @@ impl State {
|
|||
Entry::Vacant(entry) => (
|
||||
*entry.insert(Resets::with_new_nodes(
|
||||
&mut self.reset_graph,
|
||||
Expr::ty(expr),
|
||||
expr.ty(),
|
||||
source_location,
|
||||
)),
|
||||
true,
|
||||
|
|
@ -1020,7 +1020,7 @@ fn cast_bit_op<P: Pass, T: Type, A: Type>(
|
|||
}
|
||||
macro_rules! match_arg_ty {
|
||||
($($Variant:ident),*) => {
|
||||
*match Expr::ty(arg) {
|
||||
*match arg.ty() {
|
||||
CanonicalType::Array(_)
|
||||
| CanonicalType::Enum(_)
|
||||
| CanonicalType::Bundle(_)
|
||||
|
|
@ -1660,7 +1660,8 @@ impl RunPassDispatch for AnyReg {
|
|||
let clock_domain = Expr::<Bundle>::from_canonical(
|
||||
Expr::canonical(reg.clock_domain()).run_pass(pass_args)?.0,
|
||||
);
|
||||
match Expr::ty(clock_domain)
|
||||
match clock_domain
|
||||
.ty()
|
||||
.field_by_name("rst".intern())
|
||||
.expect("ClockDomain has rst field")
|
||||
.ty
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
bundle::{Bundle, BundleField, BundleType},
|
||||
enum_::{Enum, EnumType, EnumVariant},
|
||||
expr::{
|
||||
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr,
|
||||
CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ValueType,
|
||||
ops::{self, EnumLiteral},
|
||||
},
|
||||
hdl,
|
||||
|
|
@ -528,7 +528,7 @@ fn connect_port(
|
|||
rhs: Expr<CanonicalType>,
|
||||
source_location: SourceLocation,
|
||||
) {
|
||||
if Expr::ty(lhs) == Expr::ty(rhs) {
|
||||
if lhs.ty() == rhs.ty() {
|
||||
stmts.push(
|
||||
StmtConnect {
|
||||
lhs,
|
||||
|
|
@ -539,7 +539,7 @@ fn connect_port(
|
|||
);
|
||||
return;
|
||||
}
|
||||
match (Expr::ty(lhs), Expr::ty(rhs)) {
|
||||
match (lhs.ty(), rhs.ty()) {
|
||||
(CanonicalType::Bundle(lhs_type), CanonicalType::UInt(_) | CanonicalType::Bool(_)) => {
|
||||
let lhs = Expr::<Bundle>::from_canonical(lhs);
|
||||
for field in lhs_type.fields() {
|
||||
|
|
@ -586,8 +586,8 @@ fn connect_port(
|
|||
| (CanonicalType::PhantomConst(_), _)
|
||||
| (CanonicalType::DynSimOnly(_), _) => unreachable!(
|
||||
"trying to connect memory ports:\n{:?}\n{:?}",
|
||||
Expr::ty(lhs),
|
||||
Expr::ty(rhs),
|
||||
lhs.ty(),
|
||||
rhs.ty(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -607,14 +607,17 @@ fn match_int_tag(
|
|||
};
|
||||
};
|
||||
let mut retval = StmtIf {
|
||||
cond: int_tag_expr
|
||||
.cmp_eq(Expr::ty(int_tag_expr).from_int_wrapping(next_to_last_variant_index)),
|
||||
cond: int_tag_expr.cmp_eq(
|
||||
int_tag_expr
|
||||
.ty()
|
||||
.from_int_wrapping(next_to_last_variant_index),
|
||||
),
|
||||
source_location,
|
||||
blocks: [next_to_last_block, last_block],
|
||||
};
|
||||
for (variant_index, block) in blocks_iter.rev() {
|
||||
retval = StmtIf {
|
||||
cond: int_tag_expr.cmp_eq(Expr::ty(int_tag_expr).from_int_wrapping(variant_index)),
|
||||
cond: int_tag_expr.cmp_eq(int_tag_expr.ty().from_int_wrapping(variant_index)),
|
||||
source_location,
|
||||
blocks: [
|
||||
block,
|
||||
|
|
@ -657,7 +660,7 @@ impl Folder for State {
|
|||
ExprEnum::VariantAccess(op) => {
|
||||
let folded_base_expr = Expr::canonical(op.base()).fold(self)?;
|
||||
Ok(*Expr::expr_enum(self.handle_variant_access(
|
||||
Expr::ty(op.base()),
|
||||
op.base().ty(),
|
||||
folded_base_expr,
|
||||
op.variant_index(),
|
||||
)?))
|
||||
|
|
@ -867,7 +870,7 @@ impl Folder for State {
|
|||
}) => {
|
||||
let folded_expr = Expr::canonical(expr).fold(self)?;
|
||||
let folded_blocks = blocks.fold(self)?;
|
||||
self.handle_match(Expr::ty(expr), folded_expr, source_location, &folded_blocks)
|
||||
self.handle_match(expr.ty(), folded_expr, source_location, &folded_blocks)
|
||||
}
|
||||
Stmt::Connect(StmtConnect {
|
||||
lhs,
|
||||
|
|
@ -878,8 +881,8 @@ impl Folder for State {
|
|||
let folded_rhs = rhs.fold(self)?;
|
||||
let mut output_stmts = vec![];
|
||||
self.handle_stmt_connect(
|
||||
Expr::ty(lhs),
|
||||
Expr::ty(rhs),
|
||||
lhs.ty(),
|
||||
rhs.ty(),
|
||||
folded_lhs,
|
||||
folded_rhs,
|
||||
source_location,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
annotations::TargetedAnnotation,
|
||||
array::Array,
|
||||
bundle::{Bundle, BundleType},
|
||||
expr::{CastBitsTo, CastToBits, Expr, ExprEnum, ToExpr},
|
||||
expr::{CastBitsTo, CastToBits, Expr, ExprEnum, ToExpr, ValueType},
|
||||
int::{Bool, SInt, Size, UInt},
|
||||
intern::{Intern, Interned},
|
||||
memory::{Mem, MemPort, PortType},
|
||||
|
|
@ -530,7 +530,7 @@ impl ModuleState {
|
|||
connect_read(
|
||||
output_stmts,
|
||||
wire_read,
|
||||
Expr::<UInt>::from_canonical(port_read).cast_bits_to(Expr::ty(wire_read)),
|
||||
Expr::<UInt>::from_canonical(port_read).cast_bits_to(wire_read.ty()),
|
||||
);
|
||||
};
|
||||
let connect_write_enum =
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
clock::Clock,
|
||||
enum_::{Enum, EnumType, EnumVariant},
|
||||
expr::{
|
||||
Expr, ExprEnum, ops,
|
||||
Expr, ExprEnum, ValueType, ops,
|
||||
target::{
|
||||
Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField,
|
||||
TargetPathDynArrayElement, TargetPathElement,
|
||||
|
|
|
|||
|
|
@ -2,13 +2,10 @@
|
|||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{
|
||||
expr::{
|
||||
Expr, ToExpr,
|
||||
ops::{ExprPartialEq, ExprPartialOrd},
|
||||
},
|
||||
expr::{Expr, HdlPartialEqImpl, HdlPartialOrdImpl, ToExpr, ValueType},
|
||||
int::Bool,
|
||||
intern::{Intern, Interned, InternedCompare, LazyInterned, LazyInternedTrait, Memoize},
|
||||
sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType},
|
||||
sim::value::{SimValue, ToSimValue, ToSimValueWithType},
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
|
||||
|
|
@ -22,6 +19,7 @@ use serde::{
|
|||
};
|
||||
use std::{
|
||||
any::Any,
|
||||
borrow::Cow,
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
marker::PhantomData,
|
||||
|
|
@ -372,50 +370,102 @@ impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + PhantomConstValue> ExprPartialEq<Self> for PhantomConst<T> {
|
||||
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
||||
true.to_expr()
|
||||
}
|
||||
|
||||
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
||||
false.to_expr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + PhantomConstValue> ExprPartialOrd<Self> for PhantomConst<T> {
|
||||
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
||||
false.to_expr()
|
||||
}
|
||||
|
||||
fn cmp_le(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
||||
true.to_expr()
|
||||
}
|
||||
|
||||
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
||||
false.to_expr()
|
||||
}
|
||||
|
||||
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(Expr::ty(lhs), Expr::ty(rhs));
|
||||
true.to_expr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + PhantomConstValue> SimValuePartialEq<Self> for PhantomConst<T> {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||
assert_eq!(SimValue::ty(this), SimValue::ty(other));
|
||||
impl<T: ?Sized + PhantomConstValue> HdlPartialEqImpl<Self> for PhantomConst<T> {
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
_lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: Self,
|
||||
_rhs_value: Cow<'_, <Self as Type>::SimValue>,
|
||||
) -> bool {
|
||||
assert_eq!(lhs, rhs);
|
||||
true
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(lhs.ty(), rhs.ty());
|
||||
true.to_expr()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(lhs.ty(), rhs.ty());
|
||||
false.to_expr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + PhantomConstValue> HdlPartialOrdImpl<Self> for PhantomConst<T> {
|
||||
#[track_caller]
|
||||
fn cmp_value_lt(
|
||||
lhs: Self,
|
||||
_lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: Self,
|
||||
_rhs_value: Cow<'_, <Self as Type>::SimValue>,
|
||||
) -> bool {
|
||||
assert_eq!(lhs, rhs);
|
||||
false
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_le(
|
||||
lhs: Self,
|
||||
_lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: Self,
|
||||
_rhs_value: Cow<'_, <Self as Type>::SimValue>,
|
||||
) -> bool {
|
||||
assert_eq!(lhs, rhs);
|
||||
true
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_gt(
|
||||
lhs: Self,
|
||||
_lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: Self,
|
||||
_rhs_value: Cow<'_, <Self as Type>::SimValue>,
|
||||
) -> bool {
|
||||
assert_eq!(lhs, rhs);
|
||||
false
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_ge(
|
||||
lhs: Self,
|
||||
_lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: Self,
|
||||
_rhs_value: Cow<'_, <Self as Type>::SimValue>,
|
||||
) -> bool {
|
||||
assert_eq!(lhs, rhs);
|
||||
true
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_lt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(lhs.ty(), rhs.ty());
|
||||
false.to_expr()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_le(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(lhs.ty(), rhs.ty());
|
||||
true.to_expr()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_gt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(lhs.ty(), rhs.ty());
|
||||
false.to_expr()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_ge(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
assert_eq!(lhs.ty(), rhs.ty());
|
||||
true.to_expr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + PhantomConstValue> ToSimValue for PhantomConst<T> {
|
||||
type Type = PhantomConst<T>;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
SimValue::from_value(*self, *self)
|
||||
}
|
||||
|
|
@ -479,7 +529,7 @@ impl_phantom_const_get! {
|
|||
impl_phantom_const_get! {
|
||||
impl PhantomConstGet<T> for Expr<PhantomConst<T>> {
|
||||
fn get(&self) -> _ {
|
||||
PhantomConst::get(Expr::ty(*self))
|
||||
PhantomConst::get(self.ty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use crate::{
|
||||
bundle::{Bundle, BundleField, BundleType},
|
||||
expr::{Expr, ExprEnum},
|
||||
expr::{Expr, ExprEnum, ValueType},
|
||||
intern::{Intern, Interned},
|
||||
module::{Module, ModuleBuilder, ModuleIO, connect_with_loc, instance_with_loc, wire_with_loc},
|
||||
source_location::SourceLocation,
|
||||
|
|
@ -615,8 +615,8 @@ impl<T: Type> Peripheral<T> {
|
|||
};
|
||||
drop(state);
|
||||
let Self { ty, common } = self;
|
||||
let instance_io_field = Expr::field(output, &common.id.name);
|
||||
assert_eq!(ty, Expr::ty(instance_io_field));
|
||||
let instance_io_field = Expr::field::<T>(output, &common.id.name);
|
||||
assert_eq!(ty, instance_io_field.ty());
|
||||
Ok(UsedPeripheral {
|
||||
instance_io_field,
|
||||
common,
|
||||
|
|
@ -654,7 +654,7 @@ impl<T: Type> UsedPeripheral<T> {
|
|||
ref common,
|
||||
} = *self;
|
||||
PeripheralRef {
|
||||
ty: Expr::ty(instance_io_field),
|
||||
ty: instance_io_field.ty(),
|
||||
common,
|
||||
}
|
||||
}
|
||||
|
|
@ -915,7 +915,7 @@ impl<'a, T: Type> PeripheralRef<'a, T> {
|
|||
main_module_io_fields.push(BundleField {
|
||||
name: self.name(),
|
||||
flipped: self.is_input(),
|
||||
ty: Expr::ty(canonical_wire),
|
||||
ty: canonical_wire.ty(),
|
||||
});
|
||||
on_use_function(&mut **shared_state, self.canonical(), canonical_wire);
|
||||
drop(on_use_state);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ pub use crate::{
|
|||
enum_::{Enum, HdlNone, HdlOption, HdlSome},
|
||||
expr::{
|
||||
CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr,
|
||||
ReduceBits, ToExpr, repeat,
|
||||
ReduceBits, ToExpr, ValueType, repeat,
|
||||
},
|
||||
formal::{
|
||||
MakeFormalExpr, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
clock::ClockDomain,
|
||||
expr::{Expr, Flow},
|
||||
expr::{Expr, Flow, ValueType, value_category::ValueCategoryExpr},
|
||||
intern::Interned,
|
||||
module::{NameId, ScopedNameId},
|
||||
reset::{Reset, ResetType},
|
||||
|
|
@ -20,7 +20,16 @@ pub struct Reg<T: Type, R: ResetType = Reset> {
|
|||
init: Option<Expr<T>>,
|
||||
}
|
||||
|
||||
impl<T: Type + fmt::Debug, R: ResetType> fmt::Debug for Reg<T, R> {
|
||||
impl<T: Type, R: ResetType> ValueType for Reg<T, R> {
|
||||
type Type = T;
|
||||
type ValueCategory = ValueCategoryExpr;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
self.ty
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type, R: ResetType> fmt::Debug for Reg<T, R> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
name,
|
||||
|
|
@ -68,7 +77,7 @@ impl<T: Type, R: ResetType> Reg<T, R> {
|
|||
"register type must be a storable type"
|
||||
);
|
||||
if let Some(init) = init {
|
||||
assert_eq!(ty, Expr::ty(init), "register's type must match init type");
|
||||
assert_eq!(ty, init.ty(), "register's type must match init type");
|
||||
}
|
||||
Self {
|
||||
name: scoped_name,
|
||||
|
|
@ -78,9 +87,6 @@ impl<T: Type, R: ResetType> Reg<T, R> {
|
|||
init,
|
||||
}
|
||||
}
|
||||
pub fn ty(&self) -> T {
|
||||
self.ty
|
||||
}
|
||||
pub fn source_location(&self) -> SourceLocation {
|
||||
self.source_location
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,15 @@
|
|||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
clock::Clock,
|
||||
expr::{Expr, ToExpr, ops},
|
||||
int::{Bool, SInt, UInt},
|
||||
expr::{CastToImpl, Expr, ValueType},
|
||||
int::{Bool, SInt, SIntValue, UInt, UIntValue},
|
||||
sim::value::SimValue,
|
||||
source_location::SourceLocation,
|
||||
ty::{
|
||||
CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter,
|
||||
OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self,
|
||||
},
|
||||
util::ConstUsize,
|
||||
};
|
||||
use bitvec::{bits, order::Lsb0};
|
||||
|
||||
|
|
@ -19,15 +21,15 @@ mod sealed {
|
|||
pub trait ResetType:
|
||||
StaticType<MaskType = Bool>
|
||||
+ sealed::ResetTypeSealed
|
||||
+ ops::ExprCastTo<Bool>
|
||||
+ ops::ExprCastTo<Reset>
|
||||
+ ops::ExprCastTo<SyncReset>
|
||||
+ ops::ExprCastTo<AsyncReset>
|
||||
+ ops::ExprCastTo<Clock>
|
||||
+ ops::ExprCastTo<UInt<1>>
|
||||
+ ops::ExprCastTo<SInt<1>>
|
||||
+ ops::ExprCastTo<UInt>
|
||||
+ ops::ExprCastTo<SInt>
|
||||
+ CastToImpl<Bool, ValueOutput = bool>
|
||||
+ CastToImpl<Reset, ValueOutput = SimValue<Reset>>
|
||||
+ CastToImpl<SyncReset, ValueOutput = SimValue<SyncReset>>
|
||||
+ CastToImpl<AsyncReset, ValueOutput = SimValue<AsyncReset>>
|
||||
+ CastToImpl<Clock, ValueOutput = SimValue<Clock>>
|
||||
+ CastToImpl<UInt<1>, ValueOutput = UIntValue<ConstUsize<1>>>
|
||||
+ CastToImpl<SInt<1>, ValueOutput = SIntValue<ConstUsize<1>>>
|
||||
+ CastToImpl<UInt, ValueOutput = UIntValue>
|
||||
+ CastToImpl<SInt, ValueOutput = SIntValue>
|
||||
{
|
||||
fn dispatch<D: ResetTypeDispatch>(input: D::Input<Self>, dispatch: D) -> D::Output<Self>;
|
||||
}
|
||||
|
|
@ -132,29 +134,34 @@ macro_rules! reset_type {
|
|||
}
|
||||
|
||||
pub trait $Trait {
|
||||
fn $trait_fn(&self) -> Expr<$name>;
|
||||
type Output: ValueType<Type = $name>;
|
||||
fn $trait_fn(&self) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<T: ?Sized + $Trait> $Trait for &'_ T {
|
||||
fn $trait_fn(&self) -> Expr<$name> {
|
||||
type Output = T::Output;
|
||||
fn $trait_fn(&self) -> Self::Output {
|
||||
(**self).$trait_fn()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + $Trait> $Trait for &'_ mut T {
|
||||
fn $trait_fn(&self) -> Expr<$name> {
|
||||
type Output = T::Output;
|
||||
fn $trait_fn(&self) -> Self::Output {
|
||||
(**self).$trait_fn()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + $Trait> $Trait for Box<T> {
|
||||
fn $trait_fn(&self) -> Expr<$name> {
|
||||
type Output = T::Output;
|
||||
fn $trait_fn(&self) -> Self::Output {
|
||||
(**self).$trait_fn()
|
||||
}
|
||||
}
|
||||
|
||||
$($impl_trait $Trait for Expr<$name> {
|
||||
fn $trait_fn(&self) -> Expr<$name> {
|
||||
type Output = Expr<$name>;
|
||||
fn $trait_fn(&self) -> Self::Output {
|
||||
*self
|
||||
}
|
||||
})?
|
||||
|
|
@ -171,13 +178,15 @@ reset_type!(
|
|||
);
|
||||
|
||||
impl ToSyncReset for bool {
|
||||
fn to_sync_reset(&self) -> Expr<SyncReset> {
|
||||
self.to_expr().to_sync_reset()
|
||||
type Output = SimValue<SyncReset>;
|
||||
fn to_sync_reset(&self) -> Self::Output {
|
||||
SimValue::from_value(SyncReset, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToAsyncReset for bool {
|
||||
fn to_async_reset(&self) -> Expr<AsyncReset> {
|
||||
self.to_expr().to_async_reset()
|
||||
type Output = SimValue<AsyncReset>;
|
||||
fn to_async_reset(&self) -> Self::Output {
|
||||
SimValue::from_value(AsyncReset, *self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
use crate::{
|
||||
bundle::{BundleField, BundleType},
|
||||
expr::{
|
||||
Flow, ToLiteralBits,
|
||||
Flow,
|
||||
target::{
|
||||
GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
|
||||
},
|
||||
|
|
@ -47,7 +47,6 @@ use num_bigint::BigInt;
|
|||
use num_traits::{Signed, Zero};
|
||||
use std::{
|
||||
any::Any,
|
||||
borrow::Cow,
|
||||
cell::{Cell, RefCell},
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
fmt,
|
||||
|
|
@ -1504,9 +1503,10 @@ impl<I: BoolOrIntType> MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBo
|
|||
fn call(self, state: &mut interpreter::State) -> Self::Output {
|
||||
let Self { compiled_value, io } = self;
|
||||
match compiled_value.range.len().as_single() {
|
||||
Some(TypeLenSingle::SmallSlot) => Expr::ty(io)
|
||||
Some(TypeLenSingle::SmallSlot) => io
|
||||
.ty()
|
||||
.value_from_int_wrapping(state.small_slots[compiled_value.range.small_slots.start]),
|
||||
Some(TypeLenSingle::BigSlot) => Expr::ty(io).value_from_int_wrapping(
|
||||
Some(TypeLenSingle::BigSlot) => io.ty().value_from_int_wrapping(
|
||||
state.big_slots[compiled_value.range.big_slots.start].clone(),
|
||||
),
|
||||
Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(),
|
||||
|
|
@ -2889,7 +2889,7 @@ impl SimulationImpl {
|
|||
},
|
||||
);
|
||||
}
|
||||
let size = Expr::ty(io).size();
|
||||
let size = io.ty().size();
|
||||
let mut opaque = OpaqueSimValue::with_capacity(size);
|
||||
opaque.rewrite_with(size, |mut writer| {
|
||||
SimulationImpl::read_write_sim_value_helper(
|
||||
|
|
@ -2922,7 +2922,7 @@ impl SimulationImpl {
|
|||
);
|
||||
writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty())
|
||||
});
|
||||
SimValue::from_opaque(Expr::ty(io), opaque)
|
||||
SimValue::from_opaque(io.ty(), opaque)
|
||||
}
|
||||
/// doesn't modify `opaque`
|
||||
fn value_changed(
|
||||
|
|
@ -3006,7 +3006,7 @@ impl SimulationImpl {
|
|||
.get_module_mut(which_module)
|
||||
.write_helper(io, which_module);
|
||||
self.event_queue.add_event_for_now(EventKind::State);
|
||||
assert_eq!(Expr::ty(io), SimValue::ty(value));
|
||||
assert_eq!(io.ty(), value.ty());
|
||||
Self::read_write_sim_value_helper(
|
||||
&mut self.state,
|
||||
compiled_value,
|
||||
|
|
@ -3269,16 +3269,12 @@ macro_rules! impl_simulation_methods {
|
|||
pub $($async)? fn write_bool_or_int<I: BoolOrIntType>(
|
||||
&mut $self,
|
||||
io: Expr<I>,
|
||||
value: impl ToExpr<Type = I>,
|
||||
value: impl ToSimValueWithType<I>,
|
||||
) {
|
||||
let value = value.to_expr();
|
||||
assert_eq!(Expr::ty(io), Expr::ty(value), "type mismatch");
|
||||
let value = value
|
||||
.to_literal_bits()
|
||||
.expect("the value that is being written to an input must be a literal");
|
||||
let value = value.to_sim_value_with_type(io.ty());
|
||||
$self.sim_impl.borrow_mut().write_bool_or_int(
|
||||
io,
|
||||
I::bits_to_value(Cow::Borrowed(&value)),
|
||||
SimValue::into_value(value),
|
||||
$which_module,
|
||||
);
|
||||
}
|
||||
|
|
@ -3343,7 +3339,7 @@ macro_rules! impl_simulation_methods {
|
|||
pub $($async)? fn write<IO: Type, V: value::ToSimValueWithType<IO>>(&mut $self, io: Expr<IO>, value: V) {
|
||||
$self.sim_impl.borrow_mut().write(
|
||||
Expr::canonical(io),
|
||||
&SimValue::into_canonical(value.into_sim_value_with_type(Expr::ty(io))),
|
||||
&SimValue::into_canonical(value.into_sim_value_with_type(io.ty())),
|
||||
$which_module,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
bundle::{BundleField, BundleType},
|
||||
enum_::{EnumType, EnumVariant},
|
||||
expr::{
|
||||
ExprEnum, Flow, ops,
|
||||
ExprEnum, Flow, ValueType, ops,
|
||||
target::{
|
||||
GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField,
|
||||
TargetPathElement,
|
||||
|
|
@ -1714,7 +1714,7 @@ impl MakeTraceDeclTarget {
|
|||
}
|
||||
fn ty(self) -> CanonicalType {
|
||||
match self {
|
||||
MakeTraceDeclTarget::Expr(expr) => Expr::ty(expr),
|
||||
MakeTraceDeclTarget::Expr(expr) => expr.ty(),
|
||||
MakeTraceDeclTarget::Memory { ty, .. } => ty,
|
||||
}
|
||||
}
|
||||
|
|
@ -2771,7 +2771,7 @@ impl Compiler {
|
|||
let retval = parts
|
||||
.into_iter()
|
||||
.map(|part| part.cast_to_bits())
|
||||
.reduce(|accumulator, part| accumulator | (part << Expr::ty(accumulator).width))
|
||||
.reduce(|accumulator, part| accumulator | (part << accumulator.ty().width))
|
||||
.unwrap_or_else(|| UInt[0].zero().to_expr());
|
||||
let retval = self.compile_expr(instantiated_module, Expr::canonical(retval));
|
||||
let retval = self
|
||||
|
|
@ -2783,7 +2783,7 @@ impl Compiler {
|
|||
instantiated_module: InstantiatedModule,
|
||||
expr: ops::CastToBits,
|
||||
) -> CompiledValue<UInt> {
|
||||
match Expr::ty(expr.arg()) {
|
||||
match expr.arg().ty() {
|
||||
CanonicalType::UInt(_) => {
|
||||
self.compile_cast_scalar_to_bits(instantiated_module, expr.arg(), |arg| arg)
|
||||
}
|
||||
|
|
@ -2949,7 +2949,7 @@ impl Compiler {
|
|||
return retval;
|
||||
}
|
||||
let mut cast_bit = |arg: Expr<CanonicalType>| {
|
||||
let src_signed = match Expr::ty(arg) {
|
||||
let src_signed = match arg.ty() {
|
||||
CanonicalType::UInt(_) => false,
|
||||
CanonicalType::SInt(_) => true,
|
||||
CanonicalType::Bool(_) => false,
|
||||
|
|
@ -2963,7 +2963,7 @@ impl Compiler {
|
|||
CanonicalType::PhantomConst(_) => unreachable!(),
|
||||
CanonicalType::DynSimOnly(_) => unreachable!(),
|
||||
};
|
||||
let dest_signed = match Expr::ty(expr) {
|
||||
let dest_signed = match expr.ty() {
|
||||
CanonicalType::UInt(_) => false,
|
||||
CanonicalType::SInt(_) => true,
|
||||
CanonicalType::Bool(_) => false,
|
||||
|
|
@ -2977,22 +2977,23 @@ impl Compiler {
|
|||
CanonicalType::PhantomConst(_) => unreachable!(),
|
||||
CanonicalType::DynSimOnly(_) => unreachable!(),
|
||||
};
|
||||
self.simple_nary_big_expr(instantiated_module, Expr::ty(expr), [arg], |dest, [src]| {
|
||||
match (src_signed, dest_signed) {
|
||||
(false, false) | (true, true) => {
|
||||
vec![Insn::Copy { dest, src }]
|
||||
}
|
||||
(false, true) => vec![Insn::CastToSInt {
|
||||
dest,
|
||||
src,
|
||||
dest_width: 1,
|
||||
}],
|
||||
(true, false) => vec![Insn::CastToUInt {
|
||||
dest,
|
||||
src,
|
||||
dest_width: 1,
|
||||
}],
|
||||
self.simple_nary_big_expr(instantiated_module, expr.ty(), [arg], |dest, [src]| match (
|
||||
src_signed,
|
||||
dest_signed,
|
||||
) {
|
||||
(false, false) | (true, true) => {
|
||||
vec![Insn::Copy { dest, src }]
|
||||
}
|
||||
(false, true) => vec![Insn::CastToSInt {
|
||||
dest,
|
||||
src,
|
||||
dest_width: 1,
|
||||
}],
|
||||
(true, false) => vec![Insn::CastToUInt {
|
||||
dest,
|
||||
src,
|
||||
dest_width: 1,
|
||||
}],
|
||||
})
|
||||
.into()
|
||||
};
|
||||
|
|
@ -3032,21 +3033,13 @@ impl Compiler {
|
|||
})
|
||||
.into(),
|
||||
ExprEnum::PhantomConst(_) => self
|
||||
.compile_aggregate_literal(instantiated_module, Expr::ty(expr), Interned::default())
|
||||
.compile_aggregate_literal(instantiated_module, expr.ty(), Interned::default())
|
||||
.into(),
|
||||
ExprEnum::BundleLiteral(literal) => self
|
||||
.compile_aggregate_literal(
|
||||
instantiated_module,
|
||||
Expr::ty(expr),
|
||||
literal.field_values(),
|
||||
)
|
||||
.compile_aggregate_literal(instantiated_module, expr.ty(), literal.field_values())
|
||||
.into(),
|
||||
ExprEnum::ArrayLiteral(literal) => self
|
||||
.compile_aggregate_literal(
|
||||
instantiated_module,
|
||||
Expr::ty(expr),
|
||||
literal.element_values(),
|
||||
)
|
||||
.compile_aggregate_literal(instantiated_module, expr.ty(), literal.element_values())
|
||||
.into(),
|
||||
ExprEnum::EnumLiteral(expr) => {
|
||||
let enum_bits_ty = UInt[expr.ty().type_properties().bit_width];
|
||||
|
|
@ -3074,13 +3067,13 @@ impl Compiler {
|
|||
ExprEnum::NotU(expr) => self
|
||||
.simple_nary_big_expr(
|
||||
instantiated_module,
|
||||
Expr::ty(expr.arg()).canonical(),
|
||||
expr.arg().ty().canonical(),
|
||||
[Expr::canonical(expr.arg())],
|
||||
|dest, [src]| {
|
||||
vec![Insn::NotU {
|
||||
dest,
|
||||
src,
|
||||
width: Expr::ty(expr.arg()).width(),
|
||||
width: expr.arg().ty().width(),
|
||||
}]
|
||||
},
|
||||
)
|
||||
|
|
@ -3088,7 +3081,7 @@ impl Compiler {
|
|||
ExprEnum::NotS(expr) => self
|
||||
.simple_nary_big_expr(
|
||||
instantiated_module,
|
||||
Expr::ty(expr.arg()).canonical(),
|
||||
expr.arg().ty().canonical(),
|
||||
[Expr::canonical(expr.arg())],
|
||||
|dest, [src]| vec![Insn::NotS { dest, src }],
|
||||
)
|
||||
|
|
@ -3096,7 +3089,7 @@ impl Compiler {
|
|||
ExprEnum::NotB(expr) => self
|
||||
.simple_nary_big_expr(
|
||||
instantiated_module,
|
||||
Expr::ty(expr.arg()).canonical(),
|
||||
expr.arg().ty().canonical(),
|
||||
[Expr::canonical(expr.arg())],
|
||||
|dest, [src]| {
|
||||
vec![Insn::NotU {
|
||||
|
|
@ -3600,12 +3593,12 @@ impl Compiler {
|
|||
.map_ty(Bundle::from_canonical)
|
||||
.field_by_index(expr.field_index()),
|
||||
ExprEnum::VariantAccess(variant_access) => {
|
||||
let start = Expr::ty(variant_access.base()).discriminant_bit_width();
|
||||
let len = Expr::ty(expr).bit_width();
|
||||
let start = variant_access.base().ty().discriminant_bit_width();
|
||||
let len = expr.ty().bit_width();
|
||||
self.compile_expr(
|
||||
instantiated_module,
|
||||
variant_access.base().cast_to_bits()[start..start + len]
|
||||
.cast_bits_to(Expr::ty(expr)),
|
||||
.cast_bits_to(expr.ty()),
|
||||
)
|
||||
}
|
||||
ExprEnum::ArrayIndex(expr) => self
|
||||
|
|
@ -3627,45 +3620,39 @@ impl Compiler {
|
|||
.map_ty(Array::from_canonical)
|
||||
.element_dyn(index_slot)
|
||||
}
|
||||
ExprEnum::ReduceBitAndU(expr) => if Expr::ty(expr.arg()).width() == 0 {
|
||||
ExprEnum::ReduceBitAndU(expr) => if expr.arg().ty().width() == 0 {
|
||||
self.compile_expr(instantiated_module, Expr::canonical(true.to_expr()))
|
||||
} else {
|
||||
self.compile_expr(
|
||||
instantiated_module,
|
||||
Expr::canonical(
|
||||
expr.arg()
|
||||
.cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)),
|
||||
),
|
||||
Expr::canonical(expr.arg().cmp_eq(expr.arg().ty().from_int_wrapping(-1))),
|
||||
)
|
||||
}
|
||||
.into(),
|
||||
ExprEnum::ReduceBitAndS(expr) => if Expr::ty(expr.arg()).width() == 0 {
|
||||
ExprEnum::ReduceBitAndS(expr) => if expr.arg().ty().width() == 0 {
|
||||
self.compile_expr(instantiated_module, Expr::canonical(true.to_expr()))
|
||||
} else {
|
||||
self.compile_expr(
|
||||
instantiated_module,
|
||||
Expr::canonical(
|
||||
expr.arg()
|
||||
.cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)),
|
||||
),
|
||||
Expr::canonical(expr.arg().cmp_eq(expr.arg().ty().from_int_wrapping(-1))),
|
||||
)
|
||||
}
|
||||
.into(),
|
||||
ExprEnum::ReduceBitOrU(expr) => if Expr::ty(expr.arg()).width() == 0 {
|
||||
ExprEnum::ReduceBitOrU(expr) => if expr.arg().ty().width() == 0 {
|
||||
self.compile_expr(instantiated_module, Expr::canonical(false.to_expr()))
|
||||
} else {
|
||||
self.compile_expr(
|
||||
instantiated_module,
|
||||
Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))),
|
||||
Expr::canonical(expr.arg().cmp_ne(expr.arg().ty().from_int_wrapping(0))),
|
||||
)
|
||||
}
|
||||
.into(),
|
||||
ExprEnum::ReduceBitOrS(expr) => if Expr::ty(expr.arg()).width() == 0 {
|
||||
ExprEnum::ReduceBitOrS(expr) => if expr.arg().ty().width() == 0 {
|
||||
self.compile_expr(instantiated_module, Expr::canonical(false.to_expr()))
|
||||
} else {
|
||||
self.compile_expr(
|
||||
instantiated_module,
|
||||
Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))),
|
||||
Expr::canonical(expr.arg().cmp_ne(expr.arg().ty().from_int_wrapping(0))),
|
||||
)
|
||||
}
|
||||
.into(),
|
||||
|
|
@ -3678,7 +3665,7 @@ impl Compiler {
|
|||
vec![Insn::ReduceBitXor {
|
||||
dest,
|
||||
src,
|
||||
input_width: Expr::ty(expr.arg()).width(),
|
||||
input_width: expr.arg().ty().width(),
|
||||
}]
|
||||
},
|
||||
)
|
||||
|
|
@ -3692,7 +3679,7 @@ impl Compiler {
|
|||
vec![Insn::ReduceBitXor {
|
||||
dest,
|
||||
src,
|
||||
input_width: Expr::ty(expr.arg()).width(),
|
||||
input_width: expr.arg().ty().width(),
|
||||
}]
|
||||
},
|
||||
)
|
||||
|
|
@ -3790,8 +3777,8 @@ impl Compiler {
|
|||
mut rhs: Expr<CanonicalType>,
|
||||
source_location: SourceLocation,
|
||||
) {
|
||||
if Expr::ty(lhs) != Expr::ty(rhs) || !Expr::ty(lhs).is_passive() {
|
||||
match Expr::ty(lhs) {
|
||||
if lhs.ty() != rhs.ty() || !lhs.ty().is_passive() {
|
||||
match lhs.ty() {
|
||||
CanonicalType::UInt(lhs_ty) => {
|
||||
rhs = Expr::canonical(Expr::<UInt>::from_canonical(rhs).cast_to(lhs_ty));
|
||||
}
|
||||
|
|
@ -3800,7 +3787,7 @@ impl Compiler {
|
|||
}
|
||||
CanonicalType::Bool(_) => unreachable!(),
|
||||
CanonicalType::Array(lhs_ty) => {
|
||||
let CanonicalType::Array(rhs_ty) = Expr::ty(rhs) else {
|
||||
let CanonicalType::Array(rhs_ty) = rhs.ty() else {
|
||||
unreachable!();
|
||||
};
|
||||
assert_eq!(lhs_ty.len(), rhs_ty.len());
|
||||
|
|
@ -3820,13 +3807,13 @@ impl Compiler {
|
|||
return;
|
||||
}
|
||||
CanonicalType::Enum(lhs_ty) => {
|
||||
let CanonicalType::Enum(rhs_ty) = Expr::ty(rhs) else {
|
||||
let CanonicalType::Enum(rhs_ty) = rhs.ty() else {
|
||||
unreachable!();
|
||||
};
|
||||
todo!("handle connect with different enum types");
|
||||
}
|
||||
CanonicalType::Bundle(lhs_ty) => {
|
||||
let CanonicalType::Bundle(rhs_ty) = Expr::ty(rhs) else {
|
||||
let CanonicalType::Bundle(rhs_ty) = rhs.ty() else {
|
||||
unreachable!();
|
||||
};
|
||||
assert_eq!(lhs_ty.fields().len(), rhs_ty.fields().len());
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{
|
||||
expr::ValueType,
|
||||
int::{BoolOrIntType, SInt, UInt},
|
||||
intern::{Intern, Interned, Memoize},
|
||||
sim::interpreter::parts::{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ use crate::{
|
|||
bundle::{Bundle, BundleType},
|
||||
clock::Clock,
|
||||
enum_::{Enum, EnumType},
|
||||
expr::{CastBitsTo, Expr, ToExpr},
|
||||
expr::{
|
||||
CastBitsTo, Expr, HdlPartialEq, HdlPartialEqImpl, HdlPartialOrd, ToExpr, ValueType,
|
||||
value_category::{ValueCategorySimValue, ValueCategoryValue},
|
||||
},
|
||||
int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue},
|
||||
reset::{AsyncReset, Reset, SyncReset},
|
||||
source_location::SourceLocation,
|
||||
|
|
@ -26,6 +29,7 @@ use std::{
|
|||
borrow::{Borrow, BorrowMut, Cow},
|
||||
fmt::{self, Write},
|
||||
hash::{BuildHasher, Hash, Hasher, RandomState},
|
||||
num::NonZero,
|
||||
ops::{Deref, DerefMut, Index, IndexMut},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
|
@ -136,7 +140,7 @@ impl<T: Type<SimValue: Serialize> + Serialize> Serialize for SimValue<T> {
|
|||
S: Serializer,
|
||||
{
|
||||
SerdeSimValue {
|
||||
ty: SimValue::ty(self),
|
||||
ty: self.ty(),
|
||||
value: std::borrow::Cow::Borrowed(&*self),
|
||||
}
|
||||
.serialize(serializer)
|
||||
|
|
@ -157,6 +161,15 @@ pub struct SimValue<T: Type> {
|
|||
inner: AlternatingCell<SimValueInner<T>>,
|
||||
}
|
||||
|
||||
impl<T: Type> ValueType for SimValue<T> {
|
||||
type Type = T;
|
||||
type ValueCategory = ValueCategorySimValue;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
self.inner.share().ty
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type<SimValue: fmt::Display>> fmt::Display for SimValue<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
T::SimValue::fmt(self, f)
|
||||
|
|
@ -218,9 +231,6 @@ impl<T: Type> SimValue<T> {
|
|||
inner: AlternatingCell::new_unique(inner),
|
||||
}
|
||||
}
|
||||
pub fn ty(this: &Self) -> T {
|
||||
this.inner.share().ty
|
||||
}
|
||||
pub fn into_opaque(this: Self) -> OpaqueSimValue {
|
||||
this.inner.into_inner().into_opaque()
|
||||
}
|
||||
|
|
@ -259,7 +269,7 @@ impl<T: Type> SimValue<T> {
|
|||
SimValue::from_opaque(ty.canonical(), opaque)
|
||||
}
|
||||
pub fn canonical(this: &Self) -> SimValue<CanonicalType> {
|
||||
SimValue::from_opaque(Self::ty(this).canonical(), Self::opaque(this).clone())
|
||||
SimValue::from_opaque(this.ty().canonical(), Self::opaque(this).clone())
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn from_dyn_int(v: SimValue<T::Dyn>) -> Self
|
||||
|
|
@ -280,7 +290,7 @@ impl<T: Type> SimValue<T> {
|
|||
where
|
||||
T: IntType,
|
||||
{
|
||||
SimValue::from_opaque(Self::ty(this).as_dyn_int(), Self::opaque(&this).clone())
|
||||
SimValue::from_opaque(this.ty().as_dyn_int(), Self::opaque(&this).clone())
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn from_bundle(v: SimValue<Bundle>) -> Self
|
||||
|
|
@ -302,7 +312,7 @@ impl<T: Type> SimValue<T> {
|
|||
T: BundleType,
|
||||
{
|
||||
SimValue::from_opaque(
|
||||
Bundle::from_canonical(Self::ty(this).canonical()),
|
||||
Bundle::from_canonical(this.ty().canonical()),
|
||||
Self::opaque(&this).clone(),
|
||||
)
|
||||
}
|
||||
|
|
@ -326,7 +336,7 @@ impl<T: Type> SimValue<T> {
|
|||
T: EnumType,
|
||||
{
|
||||
SimValue::from_opaque(
|
||||
Enum::from_canonical(Self::ty(this).canonical()),
|
||||
Enum::from_canonical(this.ty().canonical()),
|
||||
Self::opaque(&this).clone(),
|
||||
)
|
||||
}
|
||||
|
|
@ -357,8 +367,6 @@ impl<T: Type> fmt::Debug for SimValue<T> {
|
|||
}
|
||||
|
||||
impl<T: Type> ToExpr for SimValue<T> {
|
||||
type Type = T;
|
||||
|
||||
#[track_caller]
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
let inner = self.inner.share();
|
||||
|
|
@ -366,7 +374,7 @@ impl<T: Type> ToExpr for SimValue<T> {
|
|||
inner.sim_only_values_len, 0,
|
||||
"can't convert sim-only values to Expr"
|
||||
);
|
||||
inner.opaque.bits().cast_bits_to(inner.ty)
|
||||
inner.opaque.bits().to_expr().cast_bits_to(inner.ty)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -438,59 +446,112 @@ impl<T: Type, Len: Size> AsMut<[SimValue<T>]> for SimValue<ArrayType<T, Len>> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait SimValuePartialEq<T: Type = Self>: Type {
|
||||
#[track_caller]
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<T>) -> bool;
|
||||
}
|
||||
|
||||
impl<T: SimValuePartialEq<U>, U: Type> PartialEq<SimValue<U>> for SimValue<T> {
|
||||
impl<T: Type, U: Type> PartialEq<SimValue<U>> for SimValue<T>
|
||||
where
|
||||
Self: for<'a> HdlPartialEq<&'a SimValue<U>, Output = SimValue<Bool>>,
|
||||
{
|
||||
#[track_caller]
|
||||
fn eq(&self, other: &SimValue<U>) -> bool {
|
||||
T::sim_value_eq(self, other)
|
||||
*self.cmp_eq(other)
|
||||
}
|
||||
#[track_caller]
|
||||
fn ne(&self, other: &SimValue<U>) -> bool {
|
||||
*self.cmp_ne(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> SimValuePartialEq<Self> for UIntType<Width> {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||
**this == **other
|
||||
pub trait SimValueEq: Type
|
||||
where
|
||||
for<'a> SimValue<Self>: HdlPartialEq<&'a SimValue<Self>, Output = SimValue<Bool>>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: SimValueEq> Eq for SimValue<T> where
|
||||
for<'a> SimValue<T>: HdlPartialEq<&'a SimValue<T>, Output = SimValue<Bool>>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: Type, U: Type> PartialOrd<SimValue<U>> for SimValue<T>
|
||||
where
|
||||
Self: for<'a> HdlPartialOrd<&'a SimValue<U>, Output = SimValue<Bool>>,
|
||||
{
|
||||
#[track_caller]
|
||||
fn partial_cmp(&self, other: &SimValue<U>) -> Option<std::cmp::Ordering> {
|
||||
if *self.cmp_eq(other) {
|
||||
Some(std::cmp::Ordering::Equal)
|
||||
} else if *self.cmp_lt(other) {
|
||||
Some(std::cmp::Ordering::Less)
|
||||
} else if *self.cmp_gt(other) {
|
||||
Some(std::cmp::Ordering::Greater)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn lt(&self, other: &SimValue<U>) -> bool {
|
||||
*self.cmp_lt(other)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn le(&self, other: &SimValue<U>) -> bool {
|
||||
*self.cmp_le(other)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn gt(&self, other: &SimValue<U>) -> bool {
|
||||
*self.cmp_gt(other)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn ge(&self, other: &SimValue<U>) -> bool {
|
||||
*self.cmp_ge(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> SimValuePartialEq<Self> for SIntType<Width> {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||
**this == **other
|
||||
pub trait SimValueOrd: SimValueEq
|
||||
where
|
||||
for<'a> SimValue<Self>: HdlPartialOrd<&'a SimValue<Self>, Output = SimValue<Bool>>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: SimValueOrd> Ord for SimValue<T>
|
||||
where
|
||||
for<'a> SimValue<T>: HdlPartialOrd<&'a SimValue<T>, Output = SimValue<Bool>>,
|
||||
{
|
||||
#[track_caller]
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
if *self.cmp_eq(other) {
|
||||
std::cmp::Ordering::Equal
|
||||
} else if *self.cmp_lt(other) {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SimValuePartialEq<Bool> for Bool {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Bool>) -> bool {
|
||||
**this == **other
|
||||
}
|
||||
impl<Width: Size> SimValueEq for UIntType<Width> {}
|
||||
|
||||
impl<Width: Size> SimValueOrd for UIntType<Width> {}
|
||||
|
||||
impl<Width: Size> SimValueEq for SIntType<Width> {}
|
||||
|
||||
impl<Width: Size> SimValueOrd for SIntType<Width> {}
|
||||
|
||||
macro_rules! impl_sim_value_cmp_as_bool {
|
||||
($ty:ident) => {
|
||||
impl SimValueEq for $ty {}
|
||||
|
||||
impl SimValueOrd for $ty {}
|
||||
};
|
||||
}
|
||||
|
||||
impl SimValuePartialEq for Clock {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||
**this == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl SimValuePartialEq for Reset {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||
**this == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl SimValuePartialEq for SyncReset {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||
**this == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl SimValuePartialEq for AsyncReset {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||
**this == **other
|
||||
}
|
||||
}
|
||||
impl_sim_value_cmp_as_bool!(Bool);
|
||||
impl_sim_value_cmp_as_bool!(Clock);
|
||||
impl_sim_value_cmp_as_bool!(Reset);
|
||||
impl_sim_value_cmp_as_bool!(SyncReset);
|
||||
impl_sim_value_cmp_as_bool!(AsyncReset);
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod match_sim_value {
|
||||
|
|
@ -603,9 +664,7 @@ pub mod match_sim_value {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ToSimValue: ToSimValueWithType<<Self as ToSimValue>::Type> {
|
||||
type Type: Type;
|
||||
|
||||
pub trait ToSimValue: ToSimValueWithType<<Self as ValueType>::Type> + ValueType {
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type>;
|
||||
#[track_caller]
|
||||
|
|
@ -647,31 +706,31 @@ pub trait ToSimValueWithType<T: Type> {
|
|||
|
||||
macro_rules! forward_to_sim_value_with_type {
|
||||
([$($generics:tt)*] $ty:ty) => {
|
||||
impl<$($generics)*> ToSimValueWithType<<Self as ToSimValue>::Type> for $ty {
|
||||
fn to_sim_value_with_type(&self, ty: <Self as ToSimValue>::Type) -> SimValue<<Self as ToSimValue>::Type> {
|
||||
impl<$($generics)*> ToSimValueWithType<<Self as ValueType>::Type> for $ty {
|
||||
fn to_sim_value_with_type(&self, ty: <Self as ValueType>::Type) -> SimValue<<Self as ValueType>::Type> {
|
||||
let retval = Self::to_sim_value(self);
|
||||
assert_eq!(SimValue::ty(&retval), ty);
|
||||
assert_eq!(retval.ty(), ty);
|
||||
retval
|
||||
}
|
||||
#[track_caller]
|
||||
fn into_sim_value_with_type(self, ty: <Self as ToSimValue>::Type) -> SimValue<<Self as ToSimValue>::Type>
|
||||
fn into_sim_value_with_type(self, ty: <Self as ValueType>::Type) -> SimValue<<Self as ValueType>::Type>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let retval = Self::into_sim_value(self);
|
||||
assert_eq!(SimValue::ty(&retval), ty);
|
||||
assert_eq!(retval.ty(), ty);
|
||||
retval
|
||||
}
|
||||
#[track_caller]
|
||||
fn arc_into_sim_value_with_type(self: Arc<Self>, ty: <Self as ToSimValue>::Type) -> SimValue<<Self as ToSimValue>::Type> {
|
||||
fn arc_into_sim_value_with_type(self: Arc<Self>, ty: <Self as ValueType>::Type) -> SimValue<<Self as ValueType>::Type> {
|
||||
let retval = Self::arc_into_sim_value(self);
|
||||
assert_eq!(SimValue::ty(&retval), ty);
|
||||
assert_eq!(retval.ty(), ty);
|
||||
retval
|
||||
}
|
||||
#[track_caller]
|
||||
fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: <Self as ToSimValue>::Type) -> SimValue<<Self as ToSimValue>::Type> {
|
||||
fn arc_to_sim_value_with_type(self: &Arc<Self>, ty: <Self as ValueType>::Type) -> SimValue<<Self as ValueType>::Type> {
|
||||
let retval = Self::arc_to_sim_value(self);
|
||||
assert_eq!(SimValue::ty(&retval), ty);
|
||||
assert_eq!(retval.ty(), ty);
|
||||
retval
|
||||
}
|
||||
}
|
||||
|
|
@ -679,7 +738,6 @@ macro_rules! forward_to_sim_value_with_type {
|
|||
}
|
||||
|
||||
impl<T: Type> ToSimValue for SimValue<T> {
|
||||
type Type = T;
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
self.clone()
|
||||
}
|
||||
|
|
@ -736,8 +794,6 @@ impl<T: Type> ToSimValueWithType<T> for BitSlice {
|
|||
}
|
||||
|
||||
impl<'a, This: ?Sized + ToSimValue> ToSimValue for &'a This {
|
||||
type Type = This::Type;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
This::to_sim_value(self)
|
||||
}
|
||||
|
|
@ -750,8 +806,6 @@ impl<This: ?Sized + ToSimValueWithType<T>, T: Type> ToSimValueWithType<T> for &'
|
|||
}
|
||||
|
||||
impl<This: ?Sized + ToSimValue> ToSimValue for &'_ mut This {
|
||||
type Type = This::Type;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
This::to_sim_value(self)
|
||||
}
|
||||
|
|
@ -764,8 +818,6 @@ impl<This: ?Sized + ToSimValueWithType<T>, T: Type> ToSimValueWithType<T> for &'
|
|||
}
|
||||
|
||||
impl<This: ?Sized + ToSimValue> ToSimValue for Arc<This> {
|
||||
type Type = This::Type;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
This::arc_to_sim_value(self)
|
||||
}
|
||||
|
|
@ -786,7 +838,6 @@ impl<This: ?Sized + ToSimValueWithType<T>, T: Type> ToSimValueWithType<T> for Ar
|
|||
impl<This: ?Sized + ToSimValue + Send + Sync + 'static> ToSimValue
|
||||
for crate::intern::Interned<This>
|
||||
{
|
||||
type Type = This::Type;
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
This::to_sim_value(self)
|
||||
}
|
||||
|
|
@ -801,8 +852,6 @@ impl<This: ?Sized + ToSimValueWithType<T> + Send + Sync + 'static, T: Type> ToSi
|
|||
}
|
||||
|
||||
impl<This: ToSimValue> ToSimValue for Box<This> {
|
||||
type Type = This::Type;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
This::to_sim_value(self)
|
||||
}
|
||||
|
|
@ -845,8 +894,6 @@ impl<Element: ToSimValueWithType<T>, T: Type> ToSimValueWithType<Array<T>> for [
|
|||
}
|
||||
|
||||
impl<Element: ToSimValue<Type: StaticType>> ToSimValue for [Element] {
|
||||
type Type = Array<Element::Type>;
|
||||
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self)
|
||||
|
|
@ -882,8 +929,6 @@ impl<Element: ToSimValue<Type: StaticType>, const N: usize> ToSimValue for [Elem
|
|||
where
|
||||
ConstUsize<N>: KnownSize,
|
||||
{
|
||||
type Type = Array<Element::Type, N>;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
SimValue::from_array_elements(StaticType::TYPE, self)
|
||||
}
|
||||
|
|
@ -937,8 +982,6 @@ impl<Element: ToSimValueWithType<T>, T: Type> ToSimValueWithType<Array<T>> for V
|
|||
}
|
||||
|
||||
impl<Element: ToSimValue<Type: StaticType>> ToSimValue for Vec<Element> {
|
||||
type Type = Array<Element::Type>;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self)
|
||||
}
|
||||
|
|
@ -979,8 +1022,6 @@ impl<Element: ToSimValueWithType<T>, T: Type> ToSimValueWithType<Array<T>> for B
|
|||
}
|
||||
|
||||
impl<Element: ToSimValue<Type: StaticType>> ToSimValue for Box<[Element]> {
|
||||
type Type = Array<Element::Type>;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self)
|
||||
}
|
||||
|
|
@ -1010,11 +1051,10 @@ impl<Element: ToSimValueWithType<CanonicalType>> ToSimValueWithType<CanonicalTyp
|
|||
}
|
||||
|
||||
impl<T: Type> ToSimValue for Expr<T> {
|
||||
type Type = T;
|
||||
#[track_caller]
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
SimValue::from_bitslice(
|
||||
Expr::ty(*self),
|
||||
self.ty(),
|
||||
&crate::expr::ToLiteralBits::to_literal_bits(self)
|
||||
.expect("must be a literal expression"),
|
||||
)
|
||||
|
|
@ -1034,8 +1074,6 @@ macro_rules! impl_to_sim_value_for_bool_like {
|
|||
}
|
||||
|
||||
impl ToSimValue for bool {
|
||||
type Type = Bool;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
SimValue::from_value(Bool, *self)
|
||||
}
|
||||
|
|
@ -1073,10 +1111,8 @@ impl ToSimValueWithType<CanonicalType> for bool {
|
|||
}
|
||||
|
||||
macro_rules! impl_to_sim_value_for_primitive_int {
|
||||
($prim:ident) => {
|
||||
($prim:ty) => {
|
||||
impl ToSimValue for $prim {
|
||||
type Type = <$prim as ToExpr>::Type;
|
||||
|
||||
#[track_caller]
|
||||
fn to_sim_value(
|
||||
&self,
|
||||
|
|
@ -1087,15 +1123,15 @@ macro_rules! impl_to_sim_value_for_primitive_int {
|
|||
|
||||
forward_to_sim_value_with_type!([] $prim);
|
||||
|
||||
impl ToSimValueWithType<<<$prim as ToExpr>::Type as IntType>::Dyn> for $prim {
|
||||
impl ToSimValueWithType<<<$prim as ValueType>::Type as IntType>::Dyn> for $prim {
|
||||
#[track_caller]
|
||||
fn to_sim_value_with_type(
|
||||
&self,
|
||||
ty: <<$prim as ToExpr>::Type as IntType>::Dyn,
|
||||
) -> SimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> {
|
||||
ty: <<$prim as ValueType>::Type as IntType>::Dyn,
|
||||
) -> SimValue<<<$prim as ValueType>::Type as IntType>::Dyn> {
|
||||
SimValue::from_value(
|
||||
ty,
|
||||
<<$prim as ToExpr>::Type as Type>::SimValue::from(*self).as_dyn_int(),
|
||||
<<$prim as ValueType>::Type as Type>::SimValue::from(*self).as_dyn_int(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1103,7 +1139,7 @@ macro_rules! impl_to_sim_value_for_primitive_int {
|
|||
impl ToSimValueWithType<CanonicalType> for $prim {
|
||||
#[track_caller]
|
||||
fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue<CanonicalType> {
|
||||
let ty: <<$prim as ToExpr>::Type as IntType>::Dyn = Type::from_canonical(ty);
|
||||
let ty: <<$prim as ValueType>::Type as IntType>::Dyn = Type::from_canonical(ty);
|
||||
SimValue::into_canonical(self.to_sim_value_with_type(ty))
|
||||
}
|
||||
}
|
||||
|
|
@ -1122,12 +1158,22 @@ impl_to_sim_value_for_primitive_int!(i32);
|
|||
impl_to_sim_value_for_primitive_int!(i64);
|
||||
impl_to_sim_value_for_primitive_int!(i128);
|
||||
impl_to_sim_value_for_primitive_int!(isize);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<u8>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<u16>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<u32>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<u64>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<u128>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<usize>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<i8>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<i16>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<i32>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<i64>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<i128>);
|
||||
impl_to_sim_value_for_primitive_int!(NonZero<isize>);
|
||||
|
||||
macro_rules! impl_to_sim_value_for_int_value {
|
||||
($IntValue:ident, $Int:ident, $IntType:ident) => {
|
||||
impl<Width: Size> ToSimValue for $IntValue<Width> {
|
||||
type Type = $IntType<Width>;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
SimValue::from_value(self.ty(), self.clone())
|
||||
}
|
||||
|
|
@ -1488,8 +1534,6 @@ impl<T: SimOnlyValueTrait> ToSimValueWithType<SimOnly<T>> for SimOnlyValue<T> {
|
|||
}
|
||||
|
||||
impl ToSimValue for DynSimOnlyValue {
|
||||
type Type = DynSimOnly;
|
||||
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
SimValue::from_value(self.ty(), self.clone())
|
||||
}
|
||||
|
|
@ -1499,29 +1543,58 @@ impl ToSimValue for DynSimOnlyValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> {
|
||||
impl<T: SimOnlyValueTrait> ValueType for SimOnlyValue<T> {
|
||||
type Type = SimOnly<T>;
|
||||
type ValueCategory = ValueCategoryValue;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
SimOnly::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SimOnlyValueTrait> ToSimValue for SimOnlyValue<T> {
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
SimValue::from_value(Default::default(), self.clone())
|
||||
SimValue::from_value(self.ty(), self.clone())
|
||||
}
|
||||
|
||||
fn into_sim_value(self) -> SimValue<Self::Type> {
|
||||
SimValue::from_value(Default::default(), self)
|
||||
SimValue::from_value(self.ty(), self)
|
||||
}
|
||||
}
|
||||
|
||||
impl SimValuePartialEq for DynSimOnly {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||
**this == **other
|
||||
impl HdlPartialEqImpl<Self> for DynSimOnly {
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: Self,
|
||||
rhs_value: Cow<'_, Self::SimValue>,
|
||||
) -> bool {
|
||||
*lhs_value == *rhs_value
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(_lhs: Expr<Self>, _rhs: Expr<Self>) -> Expr<Bool> {
|
||||
panic!("can't compare Expr<DynSimOnly>");
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SimOnlyValueTrait + PartialEq<U>, U: SimOnlyValueTrait> SimValuePartialEq<SimOnly<U>>
|
||||
for SimOnly<T>
|
||||
impl<L: SimOnlyValueTrait + PartialEq<R>, R: SimOnlyValueTrait> HdlPartialEqImpl<SimOnly<R>>
|
||||
for SimOnly<L>
|
||||
{
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<SimOnly<U>>) -> bool {
|
||||
***this == ***other
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
_rhs: SimOnly<R>,
|
||||
rhs_value: Cow<'_, <SimOnly<R> as Type>::SimValue>,
|
||||
) -> bool {
|
||||
**lhs_value == **rhs_value
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(_lhs: Expr<Self>, _rhs: Expr<SimOnly<R>>) -> Expr<Bool> {
|
||||
panic!("can't compare Expr<SimOnly<_>>");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
//! `unsafe` parts of [`DynSimOnlyValue`]
|
||||
|
||||
use crate::expr::{ValueType, value_category::ValueCategoryValue};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use std::{
|
||||
any::{self, TypeId},
|
||||
|
|
@ -295,10 +296,16 @@ impl<T: SimOnlyValueTrait> From<SimOnlyValue<T>> for DynSimOnlyValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl DynSimOnlyValue {
|
||||
pub fn ty(&self) -> DynSimOnly {
|
||||
impl ValueType for DynSimOnlyValue {
|
||||
type Type = DynSimOnly;
|
||||
type ValueCategory = ValueCategoryValue;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
self.0.ty()
|
||||
}
|
||||
}
|
||||
|
||||
impl DynSimOnlyValue {
|
||||
pub fn type_id(&self) -> TypeId {
|
||||
self.0.type_id_dyn()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
intern::{Intern, Interned},
|
||||
phantom_const::PhantomConst,
|
||||
reset::{AsyncReset, Reset, SyncReset},
|
||||
sim::value::{DynSimOnlyValue, DynSimOnly, SimValue, ToSimValueWithType},
|
||||
sim::value::{DynSimOnly, DynSimOnlyValue, SimValue, ToSimValueWithType},
|
||||
source_location::SourceLocation,
|
||||
util::{ConstUsize, slice_range, try_slice_range},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ impl<T: Type> ReadyValid<T> {
|
|||
#[hdl]
|
||||
pub fn firing_data(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<T>> {
|
||||
let expr = expr.to_expr();
|
||||
let option_ty = Expr::ty(expr).data;
|
||||
let option_ty = expr.ty().data;
|
||||
#[hdl]
|
||||
let firing_data = wire(option_ty);
|
||||
connect(firing_data, option_ty.HdlNone());
|
||||
|
|
@ -42,7 +42,7 @@ impl<T: Type> ReadyValid<T> {
|
|||
) -> Expr<ReadyValid<R>> {
|
||||
let data = HdlOption::map(expr.data, f);
|
||||
#[hdl]
|
||||
let mapped = wire(ReadyValid[Expr::ty(data).HdlSome]);
|
||||
let mapped = wire(ReadyValid[data.ty().HdlSome]);
|
||||
connect(mapped.data, data);
|
||||
connect(expr.ready, mapped.ready);
|
||||
mapped
|
||||
|
|
@ -81,7 +81,7 @@ pub fn queue<T: Type>(
|
|||
let count: UInt = m.output(count_ty);
|
||||
|
||||
#[hdl]
|
||||
let inp_index_reg = reg_builder().clock_domain(cd).reset(0.cast_to(index_ty));
|
||||
let inp_index_reg: UInt = reg_builder().clock_domain(cd).reset(0.cast_to(index_ty));
|
||||
#[hdl]
|
||||
let out_index_reg = reg_builder().clock_domain(cd).reset(0.cast_to(index_ty));
|
||||
#[hdl]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
expr::{Expr, Flow, ToExpr},
|
||||
expr::{Expr, Flow, ToExpr, ValueType, value_category::ValueCategoryExpr},
|
||||
intern::Interned,
|
||||
module::{IncompleteDeclaration, NameId, ScopedNameId, StmtDeclaration, StmtWire},
|
||||
source_location::SourceLocation,
|
||||
|
|
@ -16,7 +16,16 @@ pub struct Wire<T: Type> {
|
|||
ty: T,
|
||||
}
|
||||
|
||||
impl<T: Type + fmt::Debug> fmt::Debug for Wire<T> {
|
||||
impl<T: Type> ValueType for Wire<T> {
|
||||
type Type = T;
|
||||
type ValueCategory = ValueCategoryExpr;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
self.ty
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type> fmt::Debug for Wire<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Wire({:?}: ", self.name)?;
|
||||
self.ty.fmt(f)?;
|
||||
|
|
@ -49,9 +58,6 @@ impl<T: Type> Wire<T> {
|
|||
ty: T::from_canonical(ty),
|
||||
}
|
||||
}
|
||||
pub fn ty(&self) -> T {
|
||||
self.ty
|
||||
}
|
||||
pub fn new_unchecked(
|
||||
scoped_name: ScopedNameId,
|
||||
source_location: SourceLocation,
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ where
|
|||
let o: Array<T, N> = m.output();
|
||||
let bytes = v.to_string().as_bytes().to_expr();
|
||||
#[hdl]
|
||||
let o2: Array<UInt<8>> = m.output(Expr::ty(bytes));
|
||||
let o2: Array<UInt<8>> = m.output(bytes.ty());
|
||||
connect(
|
||||
o,
|
||||
#[hdl]
|
||||
|
|
@ -1176,7 +1176,7 @@ pub fn check_memory_init() {
|
|||
let waddr2: UInt<4> = m.input();
|
||||
#[hdl]
|
||||
let wdata2: UInt<31> = m.input();
|
||||
let mem_init2 = Vec::from_iter((0..0x10u32).map(|i| (i * i * i).cast_to_static()));
|
||||
let mem_init2 = Vec::from_iter((0..0x10u32).map(|i| (i * i * i).cast_to_static::<UInt<31>>()));
|
||||
#[hdl]
|
||||
let mut mem2 = memory_with_init(mem_init2);
|
||||
let read_port2 = mem2.new_read_port();
|
||||
|
|
@ -1784,7 +1784,7 @@ pub fn check_memory_of_bundle_of_arrays() {
|
|||
[(i * i).wrapping_mul(2), (i * i).wrapping_mul(3)],
|
||||
[(i * i).wrapping_mul(i), i * 2],
|
||||
],
|
||||
i.cast_to_static(),
|
||||
i.cast_to_static::<UInt<2>>(),
|
||||
)
|
||||
}));
|
||||
#[hdl]
|
||||
|
|
@ -1954,9 +1954,9 @@ pub fn check_memory_of_array_of_bundle() {
|
|||
let clk: Clock = m.input();
|
||||
let mem_init = Vec::from_iter((0..0x10u8).map(|i| {
|
||||
[
|
||||
(i, i.cast_to_static()),
|
||||
((i * i), (i / 2).cast_to_static()),
|
||||
((i * i).wrapping_mul(i), (i / 4).cast_to_static()),
|
||||
(i, i.cast_to_static::<SInt<1>>()),
|
||||
((i * i), (i / 2).cast_to_static::<SInt<1>>()),
|
||||
((i * i).wrapping_mul(i), (i / 4).cast_to_static::<SInt<1>>()),
|
||||
]
|
||||
}));
|
||||
#[hdl]
|
||||
|
|
@ -2269,7 +2269,8 @@ pub fn check_memory_of_bundle() {
|
|||
let wmask: (Bool, Bool) = m.input();
|
||||
#[hdl]
|
||||
let clk: Clock = m.input();
|
||||
let mem_init = Vec::from_iter((0..0x10u8).map(|i| (i ^ 3, (i ^ (i / 2)).cast_to_static())));
|
||||
let mem_init =
|
||||
Vec::from_iter((0..0x10u8).map(|i| (i ^ 3, (i ^ (i / 2)).cast_to_static::<SInt<1>>())));
|
||||
#[hdl]
|
||||
let mut mem = memory_with_init(mem_init);
|
||||
let read_port = mem.new_read_port();
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ pub fn mod1() {
|
|||
#[hdl]
|
||||
let child = instance(mod1_child());
|
||||
#[hdl]
|
||||
let o: mod1_child = m.output(Expr::ty(child));
|
||||
let o: mod1_child = m.output(child.ty());
|
||||
connect(o, child);
|
||||
}
|
||||
|
||||
|
|
@ -979,10 +979,10 @@ fn test_memories2() {
|
|||
},
|
||||
) in io_cycles.into_iter().enumerate()
|
||||
{
|
||||
sim.write_bool_or_int(sim.io().rw.addr, addr.cast_to_static());
|
||||
sim.write_bool_or_int(sim.io().rw.addr, addr.cast_to_static::<UInt<3>>());
|
||||
sim.write_bool(sim.io().rw.en, en);
|
||||
sim.write_bool(sim.io().rw.wmode, wmode);
|
||||
sim.write_bool_or_int(sim.io().rw.wdata, wdata.cast_to_static());
|
||||
sim.write_bool_or_int(sim.io().rw.wdata, wdata.cast_to_static::<UInt<2>>());
|
||||
sim.write_bool(sim.io().rw.wmask, wmask);
|
||||
sim.advance_time(SimDuration::from_nanos(250));
|
||||
sim.write_clock(sim.io().rw.clk, true);
|
||||
|
|
@ -1195,9 +1195,9 @@ fn test_memories3() {
|
|||
w_data: [0; 8],
|
||||
w_mask: [false; 8],
|
||||
});
|
||||
sim.write_bool_or_int(sim.io().r.addr, r_addr.cast_to_static());
|
||||
sim.write_bool_or_int(sim.io().r.addr, r_addr.cast_to_static::<UInt<3>>());
|
||||
sim.write_bool(sim.io().r.en, r_en);
|
||||
sim.write_bool_or_int(sim.io().w.addr, w_addr.cast_to_static());
|
||||
sim.write_bool_or_int(sim.io().w.addr, w_addr.cast_to_static::<UInt<3>>());
|
||||
sim.write_bool(sim.io().w.en, w_en);
|
||||
for (i, v) in w_data.into_iter().enumerate() {
|
||||
sim.write_bool_or_int(sim.io().w.data[i], v);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ Simulation {
|
|||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: Bool,
|
||||
ty: UInt<1>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
|
|
@ -51,12 +51,12 @@ Simulation {
|
|||
insns: [
|
||||
// at: module-XXXXXXXXXX.rs:1:1
|
||||
0: Const {
|
||||
dest: StatePartIndex<BigSlots>(2), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||
dest: StatePartIndex<BigSlots>(2), // (0x1) SlotDebugData { name: "", ty: UInt<1> },
|
||||
value: 0x1,
|
||||
},
|
||||
1: Copy {
|
||||
dest: StatePartIndex<BigSlots>(3), // (0x1) SlotDebugData { name: "", ty: AsyncReset },
|
||||
src: StatePartIndex<BigSlots>(2), // (0x1) SlotDebugData { name: "", ty: Bool },
|
||||
src: StatePartIndex<BigSlots>(2), // (0x1) SlotDebugData { name: "", ty: UInt<1> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:4:1
|
||||
2: Copy {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Simulation {
|
|||
..
|
||||
},
|
||||
big_slots: StatePartLayout<BigSlots> {
|
||||
len: 7,
|
||||
len: 8,
|
||||
debug_data: [
|
||||
SlotDebugData {
|
||||
name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.addr",
|
||||
|
|
@ -54,12 +54,16 @@ Simulation {
|
|||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: Bool,
|
||||
ty: UInt<1>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: Clock,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: Bool,
|
||||
},
|
||||
],
|
||||
..
|
||||
},
|
||||
|
|
@ -90,78 +94,83 @@ Simulation {
|
|||
insns: [
|
||||
// at: module-XXXXXXXXXX.rs:1:1
|
||||
0: Const {
|
||||
dest: StatePartIndex<BigSlots>(5), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||
dest: StatePartIndex<BigSlots>(7), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||
value: 0x0,
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:7:1
|
||||
1: Copy {
|
||||
dest: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.en", ty: Bool },
|
||||
src: StatePartIndex<BigSlots>(7), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:1:1
|
||||
2: Const {
|
||||
dest: StatePartIndex<BigSlots>(5), // (0x0) SlotDebugData { name: "", ty: UInt<1> },
|
||||
value: 0x0,
|
||||
},
|
||||
3: Copy {
|
||||
dest: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Clock },
|
||||
src: StatePartIndex<BigSlots>(5), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||
src: StatePartIndex<BigSlots>(5), // (0x0) SlotDebugData { name: "", ty: UInt<1> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:6:1
|
||||
2: Copy {
|
||||
4: Copy {
|
||||
dest: StatePartIndex<BigSlots>(2), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.clk", ty: Clock },
|
||||
src: StatePartIndex<BigSlots>(6), // (0x0) SlotDebugData { name: "", ty: Clock },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:7:1
|
||||
3: Copy {
|
||||
dest: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.en", ty: Bool },
|
||||
src: StatePartIndex<BigSlots>(5), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:1:1
|
||||
4: Const {
|
||||
5: Const {
|
||||
dest: StatePartIndex<BigSlots>(3), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
|
||||
value: 0x0,
|
||||
},
|
||||
5: CastToUInt {
|
||||
6: CastToUInt {
|
||||
dest: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "", ty: UInt<0> },
|
||||
src: StatePartIndex<BigSlots>(3), // (0x0) SlotDebugData { name: "", ty: UInt<8> },
|
||||
dest_width: 0,
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:5:1
|
||||
6: Copy {
|
||||
7: Copy {
|
||||
dest: StatePartIndex<BigSlots>(0), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.addr", ty: UInt<0> },
|
||||
src: StatePartIndex<BigSlots>(4), // (0x0) SlotDebugData { name: "", ty: UInt<0> },
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:3:1
|
||||
7: CastBigToArrayIndex {
|
||||
8: CastBigToArrayIndex {
|
||||
dest: StatePartIndex<SmallSlots>(4), // (0x0 0) SlotDebugData { name: "", ty: UInt<0> },
|
||||
src: StatePartIndex<BigSlots>(0), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.addr", ty: UInt<0> },
|
||||
},
|
||||
8: IsNonZeroDestIsSmall {
|
||||
9: IsNonZeroDestIsSmall {
|
||||
dest: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||
src: StatePartIndex<BigSlots>(1), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.en", ty: Bool },
|
||||
},
|
||||
9: BranchIfSmallZero {
|
||||
target: 11,
|
||||
10: BranchIfSmallZero {
|
||||
target: 12,
|
||||
value: StatePartIndex<SmallSlots>(3), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||
},
|
||||
10: Branch {
|
||||
target: 11,
|
||||
11: Branch {
|
||||
target: 12,
|
||||
},
|
||||
11: IsNonZeroDestIsSmall {
|
||||
12: IsNonZeroDestIsSmall {
|
||||
dest: StatePartIndex<SmallSlots>(2), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||
src: StatePartIndex<BigSlots>(2), // (0x0) SlotDebugData { name: "InstantiatedModule(phantom_const: phantom_const).phantom_const::mem::r0.clk", ty: Clock },
|
||||
},
|
||||
12: AndSmall {
|
||||
13: AndSmall {
|
||||
dest: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||
lhs: StatePartIndex<SmallSlots>(2), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||
rhs: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||
},
|
||||
13: BranchIfSmallZero {
|
||||
target: 14,
|
||||
14: BranchIfSmallZero {
|
||||
target: 15,
|
||||
value: StatePartIndex<SmallSlots>(1), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||
},
|
||||
14: XorSmallImmediate {
|
||||
15: XorSmallImmediate {
|
||||
dest: StatePartIndex<SmallSlots>(0), // (0x1 1) SlotDebugData { name: "", ty: Bool },
|
||||
lhs: StatePartIndex<SmallSlots>(2), // (0x0 0) SlotDebugData { name: "", ty: Bool },
|
||||
rhs: 0x1,
|
||||
},
|
||||
// at: module-XXXXXXXXXX.rs:1:1
|
||||
15: Return,
|
||||
16: Return,
|
||||
],
|
||||
..
|
||||
},
|
||||
pc: 15,
|
||||
pc: 16,
|
||||
memory_write_log: [],
|
||||
memories: StatePart {
|
||||
value: [
|
||||
|
|
@ -192,6 +201,7 @@ Simulation {
|
|||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
},
|
||||
sim_only_slots: StatePart {
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ Simulation {
|
|||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
ty: Bool,
|
||||
ty: UInt<1>,
|
||||
},
|
||||
SlotDebugData {
|
||||
name: "",
|
||||
|
|
@ -429,12 +429,12 @@ Simulation {
|
|||
},
|
||||
// at: module-XXXXXXXXXX.rs:1:1
|
||||
26: Const {
|
||||
dest: StatePartIndex<BigSlots>(28), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||
dest: StatePartIndex<BigSlots>(28), // (0x0) SlotDebugData { name: "", ty: UInt<1> },
|
||||
value: 0x0,
|
||||
},
|
||||
27: Copy {
|
||||
dest: StatePartIndex<BigSlots>(29), // (0x0) SlotDebugData { name: "", ty: SyncReset },
|
||||
src: StatePartIndex<BigSlots>(28), // (0x0) SlotDebugData { name: "", ty: Bool },
|
||||
src: StatePartIndex<BigSlots>(28), // (0x0) SlotDebugData { name: "", ty: UInt<1> },
|
||||
},
|
||||
28: Copy {
|
||||
dest: StatePartIndex<BigSlots>(26), // (0x1) SlotDebugData { name: ".clk", ty: Clock },
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ error[E0277]: `Cell<util::alternating_cell::State>` cannot be shared between thr
|
|||
11 | fn f(v: SimValue<()>) -> Interned<SimValue<()>> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ `Cell<util::alternating_cell::State>` cannot be shared between threads safely
|
||||
|
|
||||
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `Cell<util::alternating_cell::State>`
|
||||
= help: within `fayalite::prelude::SimValue<()>`, the trait `Sync` is not implemented for `Cell<util::alternating_cell::State>`
|
||||
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`
|
||||
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
|
||||
--> src/util/alternating_cell.rs
|
||||
|
|
||||
| pub(crate) struct AlternatingCell<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `SimValue<()>`
|
||||
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
||||
| pub struct SimValue<T: Type> {
|
||||
|
|
@ -28,13 +28,13 @@ error[E0277]: `UnsafeCell<value::SimValueInner<()>>` cannot be shared between th
|
|||
11 | fn f(v: SimValue<()>) -> Interned<SimValue<()>> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<value::SimValueInner<()>>` cannot be shared between threads safely
|
||||
|
|
||||
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell<value::SimValueInner<()>>`
|
||||
= help: within `fayalite::prelude::SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell<value::SimValueInner<()>>`
|
||||
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
|
||||
--> src/util/alternating_cell.rs
|
||||
|
|
||||
| pub(crate) struct AlternatingCell<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `SimValue<()>`
|
||||
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
||||
| pub struct SimValue<T: Type> {
|
||||
|
|
@ -51,7 +51,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta
|
|||
11 | fn f(v: SimValue<()>) -> Interned<SimValue<()>> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
|
||||
= help: within `fayalite::prelude::SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
|
||||
note: required because it appears within the type `DynSimOnlyValue`
|
||||
--> src/sim/value/sim_only_value_unsafe.rs
|
||||
|
|
||||
|
|
@ -92,7 +92,7 @@ note: required because it appears within the type `util::alternating_cell::Alter
|
|||
|
|
||||
| pub(crate) struct AlternatingCell<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `SimValue<()>`
|
||||
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
||||
| pub struct SimValue<T: Type> {
|
||||
|
|
@ -103,29 +103,15 @@ note: required by a bound in `fayalite::intern::Interned`
|
|||
| pub struct Interned<T: ?Sized + 'static + Send + Sync> {
|
||||
| ^^^^ required by this bound in `Interned`
|
||||
|
||||
error[E0277]: the trait bound `SimValue<()>: Intern` is not satisfied
|
||||
error[E0277]: the trait bound `fayalite::prelude::SimValue<()>: Intern` is not satisfied
|
||||
--> tests/ui/simvalue_is_not_internable.rs:12:26
|
||||
|
|
||||
12 | Intern::intern_sized(v)
|
||||
| -------------------- ^ the trait `Hash` is not implemented for `SimValue<()>`
|
||||
| -------------------- ^ the trait `Hash` is not implemented for `fayalite::prelude::SimValue<()>`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: required for `SimValue<()>` to implement `Intern`
|
||||
help: consider dereferencing here
|
||||
|
|
||||
12 | Intern::intern_sized(*v)
|
||||
| +
|
||||
|
||||
error[E0277]: the trait bound `SimValue<()>: Intern` is not satisfied
|
||||
--> tests/ui/simvalue_is_not_internable.rs:12:26
|
||||
|
|
||||
12 | Intern::intern_sized(v)
|
||||
| -------------------- ^ the trait `std::cmp::Eq` is not implemented for `SimValue<()>`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: required for `SimValue<()>` to implement `Intern`
|
||||
= note: required for `fayalite::prelude::SimValue<()>` to implement `Intern`
|
||||
help: consider dereferencing here
|
||||
|
|
||||
12 | Intern::intern_sized(*v)
|
||||
|
|
@ -139,14 +125,14 @@ error[E0277]: `Cell<util::alternating_cell::State>` cannot be shared between thr
|
|||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `Cell<util::alternating_cell::State>`
|
||||
= help: within `fayalite::prelude::SimValue<()>`, the trait `Sync` is not implemented for `Cell<util::alternating_cell::State>`
|
||||
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`
|
||||
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
|
||||
--> src/util/alternating_cell.rs
|
||||
|
|
||||
| pub(crate) struct AlternatingCell<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `SimValue<()>`
|
||||
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
||||
| pub struct SimValue<T: Type> {
|
||||
|
|
@ -172,13 +158,13 @@ error[E0277]: `UnsafeCell<value::SimValueInner<()>>` cannot be shared between th
|
|||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell<value::SimValueInner<()>>`
|
||||
= help: within `fayalite::prelude::SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell<value::SimValueInner<()>>`
|
||||
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
|
||||
--> src/util/alternating_cell.rs
|
||||
|
|
||||
| pub(crate) struct AlternatingCell<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `SimValue<()>`
|
||||
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
||||
| pub struct SimValue<T: Type> {
|
||||
|
|
@ -204,7 +190,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta
|
|||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
|
||||
= help: within `fayalite::prelude::SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
|
||||
note: required because it appears within the type `DynSimOnlyValue`
|
||||
--> src/sim/value/sim_only_value_unsafe.rs
|
||||
|
|
||||
|
|
@ -245,7 +231,7 @@ note: required because it appears within the type `util::alternating_cell::Alter
|
|||
|
|
||||
| pub(crate) struct AlternatingCell<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `SimValue<()>`
|
||||
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
||||
| pub struct SimValue<T: Type> {
|
||||
|
|
@ -269,14 +255,14 @@ error[E0277]: `Cell<util::alternating_cell::State>` cannot be shared between thr
|
|||
12 | Intern::intern_sized(v)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ `Cell<util::alternating_cell::State>` cannot be shared between threads safely
|
||||
|
|
||||
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `Cell<util::alternating_cell::State>`
|
||||
= help: within `fayalite::prelude::SimValue<()>`, the trait `Sync` is not implemented for `Cell<util::alternating_cell::State>`
|
||||
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`
|
||||
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
|
||||
--> src/util/alternating_cell.rs
|
||||
|
|
||||
| pub(crate) struct AlternatingCell<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `SimValue<()>`
|
||||
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
||||
| pub struct SimValue<T: Type> {
|
||||
|
|
@ -293,13 +279,13 @@ error[E0277]: `UnsafeCell<value::SimValueInner<()>>` cannot be shared between th
|
|||
12 | Intern::intern_sized(v)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<value::SimValueInner<()>>` cannot be shared between threads safely
|
||||
|
|
||||
= help: within `SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell<value::SimValueInner<()>>`
|
||||
= help: within `fayalite::prelude::SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell<value::SimValueInner<()>>`
|
||||
note: required because it appears within the type `util::alternating_cell::AlternatingCell<value::SimValueInner<()>>`
|
||||
--> src/util/alternating_cell.rs
|
||||
|
|
||||
| pub(crate) struct AlternatingCell<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `SimValue<()>`
|
||||
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
||||
| pub struct SimValue<T: Type> {
|
||||
|
|
@ -316,7 +302,7 @@ error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'sta
|
|||
12 | Intern::intern_sized(v)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
|
||||
= help: within `fayalite::prelude::SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>`
|
||||
note: required because it appears within the type `DynSimOnlyValue`
|
||||
--> src/sim/value/sim_only_value_unsafe.rs
|
||||
|
|
||||
|
|
@ -357,7 +343,7 @@ note: required because it appears within the type `util::alternating_cell::Alter
|
|||
|
|
||||
| pub(crate) struct AlternatingCell<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `SimValue<()>`
|
||||
note: required because it appears within the type `fayalite::prelude::SimValue<()>`
|
||||
--> src/sim/value.rs
|
||||
|
|
||||
| pub struct SimValue<T: Type> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue