forked from libre-chip/fayalite
795 lines
22 KiB
Rust
795 lines
22 KiB
Rust
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
// See Notices.txt for copyright information
|
|
|
|
use crate::{
|
|
array::{Array, ArrayType},
|
|
bundle::{Bundle, BundleType},
|
|
enum_::{Enum, EnumType},
|
|
expr::{
|
|
ops::ExprCastTo,
|
|
target::{GetTarget, Target},
|
|
},
|
|
int::{Bool, DynSize, IntType, SIntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue},
|
|
intern::{Intern, Interned},
|
|
memory::{DynPortType, MemPort, PortType},
|
|
module::{
|
|
transform::visit::{Fold, Folder, Visit, Visitor},
|
|
Instance, ModuleIO,
|
|
},
|
|
phantom_const::PhantomConst,
|
|
reg::Reg,
|
|
reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset},
|
|
ty::{CanonicalType, StaticType, Type, TypeWithDeref},
|
|
wire::Wire,
|
|
};
|
|
use bitvec::slice::BitSlice;
|
|
use std::{convert::Infallible, fmt, ops::Deref};
|
|
|
|
pub mod ops;
|
|
pub mod target;
|
|
|
|
macro_rules! expr_enum {
|
|
(
|
|
pub enum $ExprEnum:ident {
|
|
$($Variant:ident($VariantTy:ty),)*
|
|
}
|
|
) => {
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
|
pub enum $ExprEnum {
|
|
$($Variant($VariantTy),)*
|
|
}
|
|
|
|
impl fmt::Debug for $ExprEnum {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
$(Self::$Variant(v) => v.fmt(f),)*
|
|
}
|
|
}
|
|
}
|
|
|
|
$(impl From<$VariantTy> for $ExprEnum {
|
|
fn from(v: $VariantTy) -> Self {
|
|
Self::$Variant(v)
|
|
}
|
|
})*
|
|
|
|
impl<State: Folder + ?Sized> Fold<State> for $ExprEnum {
|
|
fn fold(self, state: &mut State) -> Result<Self, State::Error> {
|
|
state.fold_expr_enum(self)
|
|
}
|
|
|
|
fn default_fold(self, state: &mut State) -> Result<Self, State::Error> {
|
|
match self {
|
|
$(Self::$Variant(v) => Fold::fold(v, state).map(Self::$Variant),)*
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<State: Visitor + ?Sized> Visit<State> for $ExprEnum {
|
|
fn visit(&self, state: &mut State) -> Result<(), State::Error> {
|
|
state.visit_expr_enum(self)
|
|
}
|
|
|
|
fn default_visit(&self, state: &mut State) -> Result<(), State::Error> {
|
|
match self {
|
|
$(Self::$Variant(v) => Visit::visit(v, state),)*
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToExpr for $ExprEnum {
|
|
type Type = CanonicalType;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
match self {
|
|
$(Self::$Variant(v) => Expr::canonical(v.to_expr()),)*
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GetTarget for $ExprEnum {
|
|
fn target(&self) -> Option<Interned<Target>> {
|
|
match self {
|
|
$(Self::$Variant(v) => v.target(),)*
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToLiteralBits for $ExprEnum {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
match self {
|
|
$(Self::$Variant(v) => v.to_literal_bits(),)*
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
expr_enum! {
|
|
pub enum ExprEnum {
|
|
UIntLiteral(Interned<UIntValue>),
|
|
SIntLiteral(Interned<SIntValue>),
|
|
BoolLiteral(bool),
|
|
PhantomConst(PhantomConst),
|
|
BundleLiteral(ops::BundleLiteral),
|
|
ArrayLiteral(ops::ArrayLiteral<CanonicalType, DynSize>),
|
|
EnumLiteral(ops::EnumLiteral),
|
|
Uninit(ops::Uninit),
|
|
NotU(ops::NotU),
|
|
NotS(ops::NotS),
|
|
NotB(ops::NotB),
|
|
Neg(ops::Neg),
|
|
BitAndU(ops::BitAndU),
|
|
BitAndS(ops::BitAndS),
|
|
BitAndB(ops::BitAndB),
|
|
BitOrU(ops::BitOrU),
|
|
BitOrS(ops::BitOrS),
|
|
BitOrB(ops::BitOrB),
|
|
BitXorU(ops::BitXorU),
|
|
BitXorS(ops::BitXorS),
|
|
BitXorB(ops::BitXorB),
|
|
AddU(ops::AddU),
|
|
AddS(ops::AddS),
|
|
SubU(ops::SubU),
|
|
SubS(ops::SubS),
|
|
MulU(ops::MulU),
|
|
MulS(ops::MulS),
|
|
DivU(ops::DivU),
|
|
DivS(ops::DivS),
|
|
RemU(ops::RemU),
|
|
RemS(ops::RemS),
|
|
DynShlU(ops::DynShlU),
|
|
DynShlS(ops::DynShlS),
|
|
DynShrU(ops::DynShrU),
|
|
DynShrS(ops::DynShrS),
|
|
FixedShlU(ops::FixedShlU),
|
|
FixedShlS(ops::FixedShlS),
|
|
FixedShrU(ops::FixedShrU),
|
|
FixedShrS(ops::FixedShrS),
|
|
CmpLtB(ops::CmpLtB),
|
|
CmpLeB(ops::CmpLeB),
|
|
CmpGtB(ops::CmpGtB),
|
|
CmpGeB(ops::CmpGeB),
|
|
CmpEqB(ops::CmpEqB),
|
|
CmpNeB(ops::CmpNeB),
|
|
CmpLtU(ops::CmpLtU),
|
|
CmpLeU(ops::CmpLeU),
|
|
CmpGtU(ops::CmpGtU),
|
|
CmpGeU(ops::CmpGeU),
|
|
CmpEqU(ops::CmpEqU),
|
|
CmpNeU(ops::CmpNeU),
|
|
CmpLtS(ops::CmpLtS),
|
|
CmpLeS(ops::CmpLeS),
|
|
CmpGtS(ops::CmpGtS),
|
|
CmpGeS(ops::CmpGeS),
|
|
CmpEqS(ops::CmpEqS),
|
|
CmpNeS(ops::CmpNeS),
|
|
CastUIntToUInt(ops::CastUIntToUInt),
|
|
CastUIntToSInt(ops::CastUIntToSInt),
|
|
CastSIntToUInt(ops::CastSIntToUInt),
|
|
CastSIntToSInt(ops::CastSIntToSInt),
|
|
CastBoolToUInt(ops::CastBoolToUInt),
|
|
CastBoolToSInt(ops::CastBoolToSInt),
|
|
CastUIntToBool(ops::CastUIntToBool),
|
|
CastSIntToBool(ops::CastSIntToBool),
|
|
CastBoolToSyncReset(ops::CastBoolToSyncReset),
|
|
CastUIntToSyncReset(ops::CastUIntToSyncReset),
|
|
CastSIntToSyncReset(ops::CastSIntToSyncReset),
|
|
CastBoolToAsyncReset(ops::CastBoolToAsyncReset),
|
|
CastUIntToAsyncReset(ops::CastUIntToAsyncReset),
|
|
CastSIntToAsyncReset(ops::CastSIntToAsyncReset),
|
|
CastSyncResetToBool(ops::CastSyncResetToBool),
|
|
CastSyncResetToUInt(ops::CastSyncResetToUInt),
|
|
CastSyncResetToSInt(ops::CastSyncResetToSInt),
|
|
CastSyncResetToReset(ops::CastSyncResetToReset),
|
|
CastAsyncResetToBool(ops::CastAsyncResetToBool),
|
|
CastAsyncResetToUInt(ops::CastAsyncResetToUInt),
|
|
CastAsyncResetToSInt(ops::CastAsyncResetToSInt),
|
|
CastAsyncResetToReset(ops::CastAsyncResetToReset),
|
|
CastResetToBool(ops::CastResetToBool),
|
|
CastResetToUInt(ops::CastResetToUInt),
|
|
CastResetToSInt(ops::CastResetToSInt),
|
|
CastBoolToClock(ops::CastBoolToClock),
|
|
CastUIntToClock(ops::CastUIntToClock),
|
|
CastSIntToClock(ops::CastSIntToClock),
|
|
CastClockToBool(ops::CastClockToBool),
|
|
CastClockToUInt(ops::CastClockToUInt),
|
|
CastClockToSInt(ops::CastClockToSInt),
|
|
FieldAccess(ops::FieldAccess),
|
|
VariantAccess(ops::VariantAccess),
|
|
ArrayIndex(ops::ArrayIndex),
|
|
DynArrayIndex(ops::DynArrayIndex),
|
|
ReduceBitAndU(ops::ReduceBitAndU),
|
|
ReduceBitAndS(ops::ReduceBitAndS),
|
|
ReduceBitOrU(ops::ReduceBitOrU),
|
|
ReduceBitOrS(ops::ReduceBitOrS),
|
|
ReduceBitXorU(ops::ReduceBitXorU),
|
|
ReduceBitXorS(ops::ReduceBitXorS),
|
|
SliceUInt(ops::SliceUInt),
|
|
SliceSInt(ops::SliceSInt),
|
|
CastToBits(ops::CastToBits),
|
|
CastBitsTo(ops::CastBitsTo),
|
|
ModuleIO(ModuleIO<CanonicalType>),
|
|
Instance(Instance<Bundle>),
|
|
Wire(Wire<CanonicalType>),
|
|
Reg(Reg<CanonicalType, Reset>),
|
|
RegSync(Reg<CanonicalType, SyncReset>),
|
|
RegAsync(Reg<CanonicalType, AsyncReset>),
|
|
MemPort(MemPort<DynPortType>),
|
|
}
|
|
}
|
|
|
|
impl From<UIntValue> for ExprEnum {
|
|
fn from(value: UIntValue) -> Self {
|
|
ExprEnum::UIntLiteral(Intern::intern_sized(value))
|
|
}
|
|
}
|
|
|
|
impl From<SIntValue> for ExprEnum {
|
|
fn from(value: SIntValue) -> Self {
|
|
ExprEnum::SIntLiteral(Intern::intern_sized(value))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
#[non_exhaustive]
|
|
pub struct NotALiteralExpr;
|
|
|
|
impl fmt::Display for NotALiteralExpr {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "Not a literal expression")
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for NotALiteralExpr {}
|
|
|
|
pub trait ToLiteralBits {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr>;
|
|
}
|
|
|
|
impl ToLiteralBits for Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
*self
|
|
}
|
|
}
|
|
|
|
impl ToLiteralBits for Interned<BitSlice> {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
Ok(*self)
|
|
}
|
|
}
|
|
|
|
impl ToLiteralBits for NotALiteralExpr {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
Err(*self)
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
|
pub struct Expr<T: Type> {
|
|
__enum: Interned<ExprEnum>,
|
|
__ty: T,
|
|
__flow: Flow,
|
|
}
|
|
|
|
impl<T: Type + fmt::Debug> fmt::Debug for Expr<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
let Self {
|
|
__enum,
|
|
__ty,
|
|
__flow,
|
|
} = self;
|
|
let expr_ty = __ty.canonical();
|
|
let enum_ty = __enum.to_expr().__ty;
|
|
assert_eq!(expr_ty, enum_ty, "expr ty mismatch:\nExpr {{\n__enum: {__enum:?},\n__ty: {__ty:?},\n__flow: {__flow:?}\n}}");
|
|
}
|
|
self.__enum.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> Expr<T> {
|
|
pub fn expr_enum(this: Self) -> Interned<ExprEnum> {
|
|
this.__enum
|
|
}
|
|
pub fn ty(this: Self) -> T {
|
|
this.__ty
|
|
}
|
|
pub fn flow(this: Self) -> Flow {
|
|
this.__flow
|
|
}
|
|
pub fn canonical(this: Self) -> Expr<CanonicalType> {
|
|
Expr {
|
|
__enum: this.__enum,
|
|
__ty: this.__ty.canonical(),
|
|
__flow: this.__flow,
|
|
}
|
|
}
|
|
pub fn from_canonical(this: Expr<CanonicalType>) -> Self {
|
|
Expr {
|
|
__enum: this.__enum,
|
|
__ty: T::from_canonical(this.__ty),
|
|
__flow: this.__flow,
|
|
}
|
|
}
|
|
pub fn from_dyn_int(this: Expr<T::Dyn>) -> Self
|
|
where
|
|
T: IntType,
|
|
{
|
|
Expr {
|
|
__enum: this.__enum,
|
|
__ty: T::from_dyn_int(this.__ty),
|
|
__flow: this.__flow,
|
|
}
|
|
}
|
|
pub fn as_dyn_int(this: Self) -> Expr<T::Dyn>
|
|
where
|
|
T: IntType,
|
|
{
|
|
Expr {
|
|
__enum: this.__enum,
|
|
__ty: this.__ty.as_dyn_int(),
|
|
__flow: this.__flow,
|
|
}
|
|
}
|
|
pub fn as_bundle(this: Self) -> Expr<Bundle>
|
|
where
|
|
T: BundleType,
|
|
{
|
|
Expr {
|
|
__enum: this.__enum,
|
|
__ty: Bundle::new(this.__ty.fields()),
|
|
__flow: this.__flow,
|
|
}
|
|
}
|
|
pub fn from_bundle(this: Expr<Bundle>) -> Self
|
|
where
|
|
T: BundleType,
|
|
{
|
|
Expr {
|
|
__enum: this.__enum,
|
|
__ty: T::from_canonical(CanonicalType::Bundle(this.__ty)),
|
|
__flow: this.__flow,
|
|
}
|
|
}
|
|
#[track_caller]
|
|
pub fn field<FieldType: Type>(this: Self, name: &str) -> Expr<FieldType>
|
|
where
|
|
T: BundleType,
|
|
{
|
|
ops::FieldAccess::new_by_name(Self::as_bundle(this), name.intern()).to_expr()
|
|
}
|
|
pub fn as_enum(this: Self) -> Expr<Enum>
|
|
where
|
|
T: EnumType,
|
|
{
|
|
Expr {
|
|
__enum: this.__enum,
|
|
__ty: Enum::new(this.__ty.variants()),
|
|
__flow: this.__flow,
|
|
}
|
|
}
|
|
pub fn from_enum(this: Expr<Enum>) -> Self
|
|
where
|
|
T: EnumType,
|
|
{
|
|
Expr {
|
|
__enum: this.__enum,
|
|
__ty: T::from_canonical(CanonicalType::Enum(this.__ty)),
|
|
__flow: this.__flow,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Type> ToLiteralBits for Expr<T> {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
self.__enum.to_literal_bits()
|
|
}
|
|
}
|
|
|
|
impl<T: Type> GetTarget for Expr<T> {
|
|
fn target(&self) -> Option<Interned<Target>> {
|
|
self.__enum.target()
|
|
}
|
|
}
|
|
|
|
impl<T: TypeWithDeref> Deref for Expr<T> {
|
|
type Target = T::MatchVariant;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
T::expr_deref(self)
|
|
}
|
|
}
|
|
|
|
impl<T: Type, Len: Size> Expr<ArrayType<T, Len>> {
|
|
pub fn as_dyn_array(this: Self) -> Expr<Array> {
|
|
Expr {
|
|
__enum: this.__enum,
|
|
__ty: this.__ty.as_dyn_array(),
|
|
__flow: this.__flow,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Type, State: Folder + ?Sized> Fold<State> for Expr<T> {
|
|
fn fold(self, state: &mut State) -> Result<Self, State::Error> {
|
|
state.fold_expr(self)
|
|
}
|
|
|
|
fn default_fold(self, state: &mut State) -> Result<Self, State::Error> {
|
|
Ok(Expr::from_canonical(self.__enum.fold(state)?.to_expr()))
|
|
}
|
|
}
|
|
|
|
impl<T: Type, State: Visitor + ?Sized> Visit<State> for Expr<T> {
|
|
fn visit(&self, state: &mut State) -> Result<(), State::Error> {
|
|
state.visit_expr(self)
|
|
}
|
|
|
|
fn default_visit(&self, state: &mut State) -> Result<(), State::Error> {
|
|
self.__enum.visit(state)
|
|
}
|
|
}
|
|
|
|
pub trait ToExpr {
|
|
type Type: Type;
|
|
fn to_expr(&self) -> Expr<Self::Type>;
|
|
}
|
|
|
|
impl<T: Type> ToExpr for Expr<T> {
|
|
type Type = T;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
*self
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + ToExpr> ToExpr for &'_ T {
|
|
type Type = T::Type;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
T::to_expr(self)
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + ToExpr> ToExpr for &'_ mut T {
|
|
type Type = T::Type;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
T::to_expr(self)
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + ToExpr> ToExpr for Box<T> {
|
|
type Type = T::Type;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
T::to_expr(self)
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + ToExpr + Send + Sync + 'static> ToExpr for Interned<T> {
|
|
type Type = T::Type;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
T::to_expr(self)
|
|
}
|
|
}
|
|
|
|
impl<Width: Size> ToExpr for UIntValue<Width> {
|
|
type Type = UIntType<Width>;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
Expr {
|
|
__enum: ExprEnum::UIntLiteral(self.clone().as_dyn_int().intern()).intern(),
|
|
__ty: self.ty(),
|
|
__flow: Flow::Source,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Width: Size> ToExpr for SIntValue<Width> {
|
|
type Type = SIntType<Width>;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
Expr {
|
|
__enum: ExprEnum::SIntLiteral(self.clone().as_dyn_int().intern()).intern(),
|
|
__ty: self.ty(),
|
|
__flow: Flow::Source,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToExpr for bool {
|
|
type Type = Bool;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
Expr {
|
|
__enum: ExprEnum::BoolLiteral(*self).intern(),
|
|
__ty: Bool,
|
|
__flow: Flow::Source,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
|
pub enum Flow {
|
|
Source,
|
|
Sink,
|
|
Duplex,
|
|
}
|
|
|
|
impl Flow {
|
|
pub const fn flip(self) -> Flow {
|
|
match self {
|
|
Flow::Source => Flow::Sink,
|
|
Flow::Sink => Flow::Source,
|
|
Flow::Duplex => Flow::Duplex,
|
|
}
|
|
}
|
|
pub const fn flip_if(self, flipped: bool) -> Flow {
|
|
if flipped {
|
|
self.flip()
|
|
} else {
|
|
self
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Type> ToExpr for ModuleIO<T> {
|
|
type Type = T;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
Expr {
|
|
__enum: ExprEnum::ModuleIO(self.canonical()).intern_sized(),
|
|
__ty: self.ty(),
|
|
__flow: self.flow(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Type> ToLiteralBits for ModuleIO<T> {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
Err(NotALiteralExpr)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> GetTarget for ModuleIO<T> {
|
|
fn target(&self) -> Option<Interned<Target>> {
|
|
Some(Intern::intern_sized(self.canonical().into()))
|
|
}
|
|
}
|
|
|
|
impl<T: BundleType> ToExpr for Instance<T> {
|
|
type Type = T;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
Expr {
|
|
__enum: ExprEnum::Instance(self.canonical()).intern_sized(),
|
|
__ty: self.ty(),
|
|
__flow: self.flow(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: BundleType> ToLiteralBits for Instance<T> {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
Err(NotALiteralExpr)
|
|
}
|
|
}
|
|
|
|
impl<T: BundleType> GetTarget for Instance<T> {
|
|
fn target(&self) -> Option<Interned<Target>> {
|
|
Some(Intern::intern_sized(self.canonical().into()))
|
|
}
|
|
}
|
|
|
|
impl<T: Type> ToExpr for Wire<T> {
|
|
type Type = T;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
Expr {
|
|
__enum: ExprEnum::Wire(self.canonical()).intern_sized(),
|
|
__ty: self.ty(),
|
|
__flow: self.flow(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Type> ToLiteralBits for Wire<T> {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
Err(NotALiteralExpr)
|
|
}
|
|
}
|
|
|
|
impl<T: Type> GetTarget for Wire<T> {
|
|
fn target(&self) -> Option<Interned<Target>> {
|
|
Some(Intern::intern_sized(self.canonical().into()))
|
|
}
|
|
}
|
|
|
|
impl<T: Type, R: ResetType> ToExpr for Reg<T, R> {
|
|
type Type = T;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
struct Dispatch;
|
|
impl ResetTypeDispatch for Dispatch {
|
|
type Input<T: ResetType> = Reg<CanonicalType, T>;
|
|
type Output<T: ResetType> = ExprEnum;
|
|
|
|
fn reset(self, input: Self::Input<Reset>) -> Self::Output<Reset> {
|
|
ExprEnum::Reg(input)
|
|
}
|
|
|
|
fn sync_reset(self, input: Self::Input<SyncReset>) -> Self::Output<SyncReset> {
|
|
ExprEnum::RegSync(input)
|
|
}
|
|
|
|
fn async_reset(self, input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> {
|
|
ExprEnum::RegAsync(input)
|
|
}
|
|
}
|
|
Expr {
|
|
__enum: R::dispatch(self.canonical(), Dispatch).intern_sized(),
|
|
__ty: self.ty(),
|
|
__flow: self.flow(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: Type, R: ResetType> ToLiteralBits for Reg<T, R> {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
Err(NotALiteralExpr)
|
|
}
|
|
}
|
|
|
|
impl<T: Type, R: ResetType> GetTarget for Reg<T, R> {
|
|
fn target(&self) -> Option<Interned<Target>> {
|
|
Some(Intern::intern_sized(self.canonical().into()))
|
|
}
|
|
}
|
|
|
|
impl<T: PortType> ToExpr for MemPort<T> {
|
|
type Type = T::Port;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
Expr {
|
|
__enum: ExprEnum::MemPort(self.canonical()).intern_sized(),
|
|
__ty: self.ty(),
|
|
__flow: self.flow(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: PortType> ToLiteralBits for MemPort<T> {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
Err(NotALiteralExpr)
|
|
}
|
|
}
|
|
|
|
impl<T: PortType> GetTarget for MemPort<T> {
|
|
fn target(&self) -> Option<Interned<Target>> {
|
|
Some(Intern::intern_sized(self.canonical().into()))
|
|
}
|
|
}
|
|
|
|
pub trait HdlPartialEq<Rhs> {
|
|
fn cmp_eq(self, rhs: Rhs) -> Expr<Bool>;
|
|
fn cmp_ne(self, rhs: Rhs) -> Expr<Bool>;
|
|
}
|
|
|
|
pub trait HdlPartialOrd<Rhs>: HdlPartialEq<Rhs> {
|
|
fn cmp_lt(self, rhs: Rhs) -> Expr<Bool>;
|
|
fn cmp_le(self, rhs: Rhs) -> Expr<Bool>;
|
|
fn cmp_gt(self, rhs: Rhs) -> Expr<Bool>;
|
|
fn cmp_ge(self, rhs: Rhs) -> Expr<Bool>;
|
|
}
|
|
|
|
pub trait ReduceBits {
|
|
type UIntOutput;
|
|
type BoolOutput;
|
|
fn reduce_bitand(self) -> Self::UIntOutput;
|
|
fn reduce_bitor(self) -> Self::UIntOutput;
|
|
fn reduce_bitxor(self) -> Self::UIntOutput;
|
|
fn any_one_bits(self) -> Self::BoolOutput;
|
|
fn any_zero_bits(self) -> Self::BoolOutput;
|
|
fn all_one_bits(self) -> Self::BoolOutput;
|
|
fn all_zero_bits(self) -> Self::BoolOutput;
|
|
fn parity_odd(self) -> Self::BoolOutput;
|
|
fn parity_even(self) -> Self::BoolOutput;
|
|
}
|
|
|
|
pub trait CastToBits {
|
|
fn cast_to_bits(&self) -> Expr<UInt>;
|
|
}
|
|
|
|
impl<T: ToExpr + ?Sized> CastToBits for T {
|
|
fn cast_to_bits(&self) -> Expr<UInt> {
|
|
ops::CastToBits::new(Expr::canonical(self.to_expr())).to_expr()
|
|
}
|
|
}
|
|
|
|
pub trait CastBitsTo {
|
|
#[track_caller]
|
|
fn cast_bits_to<T: Type>(&self, ty: T) -> Expr<T>;
|
|
}
|
|
|
|
impl<T: ToExpr<Type = UIntType<Width>> + ?Sized, Width: Size> CastBitsTo for T {
|
|
fn cast_bits_to<ToType: Type>(&self, ty: ToType) -> Expr<ToType> {
|
|
ops::CastBitsTo::new(Expr::as_dyn_int(self.to_expr()), ty).to_expr()
|
|
}
|
|
}
|
|
|
|
pub trait CastTo: ToExpr {
|
|
fn cast_to<ToType: Type>(&self, to_type: ToType) -> Expr<ToType>
|
|
where
|
|
Self::Type: ExprCastTo<ToType>,
|
|
{
|
|
ExprCastTo::cast_to(self.to_expr(), to_type)
|
|
}
|
|
fn cast_to_static<ToType: StaticType>(&self) -> Expr<ToType>
|
|
where
|
|
Self::Type: ExprCastTo<ToType>,
|
|
{
|
|
ExprCastTo::cast_to(self.to_expr(), ToType::TYPE)
|
|
}
|
|
}
|
|
|
|
impl<T: ToExpr + ?Sized> CastTo for T {}
|
|
|
|
#[doc(hidden)]
|
|
pub fn check_match_expr<T: Type>(
|
|
_expr: Expr<T>,
|
|
_check_fn: impl FnOnce(T::MatchVariant, Infallible),
|
|
) {
|
|
}
|
|
|
|
pub trait MakeUninitExpr: Type {
|
|
fn uninit(self) -> Expr<Self>;
|
|
}
|
|
|
|
impl<T: Type> MakeUninitExpr for T {
|
|
fn uninit(self) -> Expr<Self> {
|
|
ops::Uninit::new(self).to_expr()
|
|
}
|
|
}
|
|
|
|
pub fn repeat<T: Type, L: SizeType>(
|
|
element: impl ToExpr<Type = T>,
|
|
len: L,
|
|
) -> Expr<ArrayType<T, L::Size>> {
|
|
let element = element.to_expr();
|
|
let canonical_element = Expr::canonical(element);
|
|
ops::ArrayLiteral::new(
|
|
Expr::ty(element),
|
|
std::iter::repeat(canonical_element)
|
|
.take(L::Size::as_usize(len))
|
|
.collect(),
|
|
)
|
|
.to_expr()
|
|
}
|
|
|
|
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> ToExpr for PhantomConst<T> {
|
|
type Type = Self;
|
|
|
|
fn to_expr(&self) -> Expr<Self::Type> {
|
|
Expr {
|
|
__enum: ExprEnum::PhantomConst(self.canonical_phantom_const()).intern_sized(),
|
|
__ty: *self,
|
|
__flow: Flow::Source,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> GetTarget for PhantomConst<T> {
|
|
fn target(&self) -> Option<Interned<Target>> {
|
|
None
|
|
}
|
|
}
|
|
|
|
impl<T: ?Sized + crate::phantom_const::PhantomConstValue> ToLiteralBits for PhantomConst<T> {
|
|
fn to_literal_bits(&self) -> Result<Interned<BitSlice>, NotALiteralExpr> {
|
|
Ok(Interned::default())
|
|
}
|
|
}
|