support operations directly on SimValue, UIntValue, and SIntValue, and shared references to those
All checks were successful
/ test (pull_request) Successful in 3m59s
/ test (push) Successful in 4m38s

This commit is contained in:
Jacob Lifshay 2025-11-18 03:50:06 -08:00
parent 2a65aa2bd5
commit 9e803223d0
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
42 changed files with 6076 additions and 1486 deletions

View file

@ -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![where](span),
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
}
}
}

View file

@ -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,

View file

@ -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);
}

View 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));

View file

@ -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]

View file

@ -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(),
}
}
}

View file

@ -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)

View file

@ -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()
}
}

View file

@ -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

View 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}
}

View file

@ -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()),)*

View 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,
);
}

View file

@ -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)

View file

@ -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::*;

View file

@ -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())
}
}

View file

@ -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>) {

View file

@ -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)]

View file

@ -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

View file

@ -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,

View file

@ -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 =

View file

@ -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,

View file

@ -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())
}
}
}

View file

@ -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);

View file

@ -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,

View file

@ -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
}

View file

@ -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)
}
}

View file

@ -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,
);
}

View file

@ -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());

View file

@ -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::{

View file

@ -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<_>>");
}
}

View file

@ -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()
}

View file

@ -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},
};

View file

@ -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]

View file

@ -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,

View file

@ -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();

View file

@ -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);

View file

@ -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 {

View file

@ -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 {

View file

@ -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 },

View file

@ -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> {