change CommonMOp to directly contain a generic immediate type

This commit is contained in:
Jacob Lifshay 2026-01-27 16:42:35 -08:00
parent 167bc4b6a6
commit 130c1b2892
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
4 changed files with 145693 additions and 156456 deletions

View file

@ -11,7 +11,7 @@ use fayalite::{
intern::Interned,
module::wire_with_loc,
prelude::*,
ty::StaticType,
ty::{StaticType, TypeProperties},
util::ConstBool,
};
use std::{
@ -130,28 +130,42 @@ pub trait MOpTrait: Type {
pub trait CommonMOpTrait: MOpTrait {
type PrefixPad: KnownSize;
type SrcCount: KnownSize;
type Imm: Type;
type CommonMOpTraitMapped<NewDestReg: Type, NewSrcRegWidth: Size>: CommonMOpTrait<
DestReg = NewDestReg,
SrcRegWidth = NewSrcRegWidth,
PrefixPad = Self::PrefixPad,
SrcCount = Self::SrcCount,
Imm = Self::Imm,
>;
type CommonMOpTraitDestReg: Type;
type CommonMOpTraitSrcRegWidth: Size;
fn common_mop_ty(
self,
) -> CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount>;
) -> CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>;
fn common_mop(
input: impl ToExpr<Type = Self>,
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount>>;
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>>;
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self,
new_common_mop_ty: CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
new_common_mop_ty: CommonMOp<
Self::PrefixPad,
NewDestReg,
NewSrcRegWidth,
Self::SrcCount,
Self::Imm,
>,
) -> Self::Mapped<NewDestReg, NewSrcRegWidth>;
fn with_common_mop<NewDestReg: Type, NewSrcRegWidth: Size>(
input: impl ToExpr<Type = Self>,
new_common_mop: impl ToExpr<
Type = CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
Type = CommonMOp<
Self::PrefixPad,
NewDestReg,
NewSrcRegWidth,
Self::SrcCount,
Self::Imm,
>,
>,
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>>;
}
@ -161,6 +175,7 @@ pub type CommonMOpFor<T> = CommonMOp<
<T as CommonMOpTrait>::CommonMOpTraitDestReg,
<T as CommonMOpTrait>::CommonMOpTraitSrcRegWidth,
<T as CommonMOpTrait>::SrcCount,
<T as CommonMOpTrait>::Imm,
>;
impl<T: CommonMOpTrait> MOpTrait for T {
@ -192,10 +207,15 @@ impl<T: CommonMOpTrait> MOpTrait for T {
new_dest_reg: NewDestReg,
new_src_reg_width: NewSrcRegWidth::SizeType,
) -> Self::Mapped<NewDestReg, NewSrcRegWidth> {
self.with_common_mop_ty(
CommonMOp[T::PrefixPad::SIZE][new_dest_reg][new_src_reg_width][T::SrcCount::SIZE],
)
let common_mop_ty = self.common_mop_ty();
self.with_common_mop_ty(CommonMOp {
prefix_pad: common_mop_ty.prefix_pad,
dest: new_dest_reg,
src: ArrayType[UIntType[new_src_reg_width]][T::SrcCount::SIZE],
imm: common_mop_ty.imm,
})
}
#[hdl]
fn map_regs<NewDestReg: Type, NewSrcRegWidth: Size>(
input: impl ToExpr<Type = Self>,
new_dest: impl ToExpr<Type = NewDestReg>,
@ -207,22 +227,21 @@ impl<T: CommonMOpTrait> MOpTrait for T {
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
let input = input.to_expr();
let common = T::common_mop(input);
let new_dest = new_dest.to_expr();
T::with_common_mop(
input,
CommonMOp::new(
common.prefix_pad,
new_dest,
ArrayLiteral::new(
#[hdl]
CommonMOp {
prefix_pad: common.prefix_pad,
dest: new_dest,
src: ArrayLiteral::new(
UIntType[new_src_reg_width],
Interned::from_iter(
(0..T::SrcCount::VALUE)
.map(|index| Expr::canonical(map_src(common.src[index], index))),
),
)
.to_expr(),
CommonMOp::imm(common),
),
),
imm: common.imm,
},
)
}
}
@ -288,173 +307,269 @@ pub const MOP_IMM_WIDTH: usize = 34;
pub const MOP_MIN_REG_WIDTH: usize = 8;
pub const COMMON_MOP_SRC_LEN: usize = 3;
pub const COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM: usize = 2;
pub const COMMON_MOP_IMM_LOW_WIDTH: usize = CommonMOpWithMaxSrcCount::IMM_WIDTH - 1;
#[hdl(cmp_eq)]
pub struct CommonMOp<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
pub prefix_pad: UIntType<PrefixPad>,
pub dest: DestReg,
pub src: Array<UIntType<SrcRegWidth>, { COMMON_MOP_SRC_LEN }>,
pub imm_low: UInt<{ COMMON_MOP_IMM_LOW_WIDTH }>,
pub imm_sign: SInt<1>,
pub _phantom: PhantomData<SrcCount>,
pub const fn common_mop_max_imm_size(src_count: usize) -> usize {
assert!(src_count <= COMMON_MOP_SRC_LEN, "too many sources");
assert!(COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM <= COMMON_MOP_SRC_LEN);
let sources_that_reduce_imm = src_count.saturating_sub(COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM);
MOP_IMM_WIDTH - sources_that_reduce_imm * MOP_MIN_REG_WIDTH
}
impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> CommonMOpTrait
for CommonMOp<PrefixPad, DestReg, SrcRegWidth, SrcCount>
#[derive(Copy, Clone, PartialEq, Eq, Hash, Default)]
pub struct CommonMOpDefaultImm<SrcCount: KnownSize> {
_phantom: PhantomData<SrcCount>,
}
#[doc(hidden)]
pub struct CommonMOpDefaultImmNoGenerics(());
#[expect(non_upper_case_globals)]
pub const CommonMOpDefaultImm: CommonMOpDefaultImmNoGenerics = CommonMOpDefaultImmNoGenerics(());
impl<SrcCount: fayalite::int::SizeType<Size: KnownSize>> std::ops::Index<SrcCount>
for CommonMOpDefaultImmNoGenerics
{
type Output = CommonMOpDefaultImm<SrcCount::Size>;
fn index(&self, _src_count: SrcCount) -> &Self::Output {
const {
// check generics for validity
let _ = Self::Output::UNDERLYING_TYPE;
&CommonMOpDefaultImm {
_phantom: PhantomData,
}
}
}
}
impl<SrcCount: KnownSize> fmt::Debug for CommonMOpDefaultImm<SrcCount> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"CommonMOpDefaultImm<ConstUsize<{}>>({:?})",
SrcCount::VALUE,
Self::UNDERLYING_TYPE
)
}
}
impl<SrcCount: KnownSize> CommonMOpDefaultImm<SrcCount> {
pub const UNDERLYING_TYPE: SInt = SInt::new_dyn(common_mop_max_imm_size(SrcCount::VALUE));
pub fn as_sint<S: Size>(this: impl ToExpr<Type = Self>) -> Expr<SIntType<S>> {
Expr::from_canonical(Expr::canonical(this.to_expr()))
}
pub fn as_sint_dyn(this: impl ToExpr<Type = Self>) -> Expr<SInt> {
Expr::from_canonical(Expr::canonical(this.to_expr()))
}
pub fn from_sint<S: Size>(v: impl ToExpr<Type = SIntType<S>>) -> Expr<Self> {
Expr::from_canonical(Expr::canonical(v.to_expr()))
}
pub fn cast_from_sint<S: Size>(v: impl ToExpr<Type = SIntType<S>>) -> Expr<Self> {
Expr::from_canonical(Expr::canonical(v.to_expr().cast_to(Self::UNDERLYING_TYPE)))
}
pub fn zero(self) -> SimValue<Self> {
SimValue::from_value(self, Self::UNDERLYING_TYPE.zero())
}
}
impl<SrcCount: KnownSize> ToSimValueWithType<CommonMOpDefaultImm<SrcCount>> for SIntValue {
fn to_sim_value_with_type(
&self,
ty: CommonMOpDefaultImm<SrcCount>,
) -> SimValue<CommonMOpDefaultImm<SrcCount>> {
SimValue::from_value(ty, self.clone())
}
fn into_sim_value_with_type(
self,
ty: CommonMOpDefaultImm<SrcCount>,
) -> SimValue<CommonMOpDefaultImm<SrcCount>> {
SimValue::from_value(ty, self)
}
}
impl<SrcCount: KnownSize> Type for CommonMOpDefaultImm<SrcCount> {
type BaseType = SInt;
type MaskType = <Self::BaseType as Type>::MaskType;
type SimValue = <Self::BaseType as Type>::SimValue;
type MatchVariant = <Self::BaseType as Type>::MatchVariant;
type MatchActiveScope = <Self::BaseType as Type>::MatchActiveScope;
type MatchVariantAndInactiveScope = <Self::BaseType as Type>::MatchVariantAndInactiveScope;
type MatchVariantsIter = <Self::BaseType as Type>::MatchVariantsIter;
fn match_variants(
this: Expr<Self>,
source_location: SourceLocation,
) -> Self::MatchVariantsIter {
Self::BaseType::match_variants(Expr::from_canonical(Expr::canonical(this)), source_location)
}
fn mask_type(&self) -> Self::MaskType {
Self::UNDERLYING_TYPE.mask_type()
}
fn canonical(&self) -> CanonicalType {
Self::UNDERLYING_TYPE.canonical()
}
fn from_canonical(canonical_type: CanonicalType) -> Self {
let underlying_type = Self::BaseType::from_canonical(canonical_type);
assert_eq!(underlying_type, Self::UNDERLYING_TYPE);
Self {
_phantom: PhantomData,
}
}
fn source_location() -> SourceLocation {
SourceLocation::caller()
}
fn sim_value_from_opaque(
&self,
opaque: fayalite::ty::OpaqueSimValueSlice<'_>,
) -> Self::SimValue {
Self::UNDERLYING_TYPE.sim_value_from_opaque(opaque)
}
fn sim_value_clone_from_opaque(
&self,
value: &mut Self::SimValue,
opaque: fayalite::ty::OpaqueSimValueSlice<'_>,
) {
Self::UNDERLYING_TYPE.sim_value_clone_from_opaque(value, opaque)
}
fn sim_value_to_opaque<'w>(
&self,
value: &Self::SimValue,
writer: fayalite::ty::OpaqueSimValueWriter<'w>,
) -> fayalite::ty::OpaqueSimValueWritten<'w> {
Self::UNDERLYING_TYPE.sim_value_to_opaque(value, writer)
}
}
impl<SrcCount: KnownSize> StaticType for CommonMOpDefaultImm<SrcCount> {
const TYPE: Self = Self {
_phantom: PhantomData,
};
const MASK_TYPE: Self::MaskType = Self::MaskType::TYPE;
const TYPE_PROPERTIES: TypeProperties = Self::UNDERLYING_TYPE.type_properties_dyn();
const MASK_TYPE_PROPERTIES: TypeProperties = Self::MaskType::TYPE_PROPERTIES;
}
impl<SrcCount: KnownSize> HdlPartialEqImpl<Self> for CommonMOpDefaultImm<SrcCount> {
#[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())
}
#[track_caller]
fn cmp_expr_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits())
}
}
#[hdl(cmp_eq)]
pub struct CommonMOp<
PrefixPad: KnownSize,
DestReg: Type,
SrcRegWidth: Size,
SrcCount: KnownSize,
Imm: Type,
> {
pub prefix_pad: UIntType<PrefixPad>,
pub dest: DestReg,
pub src: ArrayType<UIntType<SrcRegWidth>, SrcCount>,
pub imm: Imm,
}
impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize, Imm: Type>
CommonMOp<PrefixPad, DestReg, SrcRegWidth, SrcCount, Imm>
{
pub fn validate(self) {
let imm_type_properties = self.imm.canonical().type_properties();
assert!(
imm_type_properties.bit_width <= common_mop_max_imm_size(SrcCount::VALUE),
"{self:#?}",
);
// TODO: reg_alloc tests don't respect the min reg width,
// we should probably add padding to `CommonMOp` after `src` to compensate
// assert!(self.src.element().width() >= MOP_MIN_REG_WIDTH, "{self:#?}");
}
}
impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize, Imm: Type>
CommonMOpTrait for CommonMOp<PrefixPad, DestReg, SrcRegWidth, SrcCount, Imm>
{
type PrefixPad = PrefixPad;
type SrcCount = SrcCount;
type Imm = Imm;
type CommonMOpTraitMapped<NewDestReg: Type, NewSrcRegWidth: Size> =
CommonMOp<PrefixPad, NewDestReg, NewSrcRegWidth, SrcCount>;
CommonMOp<PrefixPad, NewDestReg, NewSrcRegWidth, SrcCount, Imm>;
type CommonMOpTraitDestReg = DestReg;
type CommonMOpTraitSrcRegWidth = SrcRegWidth;
fn common_mop_ty(
self,
) -> CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount> {
) -> CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>
{
self.validate();
self
}
fn common_mop(
input: impl ToExpr<Type = Self>,
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount>> {
input.to_expr()
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>>
{
let input = input.to_expr();
input.ty().validate();
input
}
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self,
new_common_mop_ty: CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
new_common_mop_ty: CommonMOp<
Self::PrefixPad,
NewDestReg,
NewSrcRegWidth,
Self::SrcCount,
Self::Imm,
>,
) -> Self::Mapped<NewDestReg, NewSrcRegWidth> {
self.validate();
new_common_mop_ty.validate();
new_common_mop_ty
}
fn with_common_mop<NewDestReg: Type, NewSrcRegWidth: Size>(
input: impl ToExpr<Type = Self>,
new_common_mop: impl ToExpr<
Type = CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
Type = CommonMOp<
Self::PrefixPad,
NewDestReg,
NewSrcRegWidth,
Self::SrcCount,
Self::Imm,
>,
>,
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
let _ = input.to_expr();
new_common_mop.to_expr()
let input = input.to_expr();
let new_common_mop = new_common_mop.to_expr();
input.ty().validate();
new_common_mop.ty().validate();
new_common_mop
}
}
#[hdl(cmp_eq)]
pub struct CommonMOpImmParts<ImmInSrcCount: Size> {
// fields must be in this exact order
pub imm_low: UInt<{ COMMON_MOP_IMM_LOW_WIDTH }>,
pub reversed_src: ArrayType<UInt<{ MOP_MIN_REG_WIDTH }>, ImmInSrcCount>,
pub imm_sign: SInt<1>,
}
type CommonMOpWithMaxSrcCount = CommonMOpForImm<{ COMMON_MOP_SRC_LEN }>;
type CommonMOpForImm<const SRC_COUNT: usize> =
CommonMOp<ConstUsize<0>, (), ConstUsize<{ MOP_MIN_REG_WIDTH }>, ConstUsize<SRC_COUNT>>;
pub const COMMON_MOP_0_IMM_WIDTH: usize = CommonMOpForImm::<0>::IMM_WIDTH;
pub const COMMON_MOP_1_IMM_WIDTH: usize = CommonMOpForImm::<1>::IMM_WIDTH;
pub const COMMON_MOP_2_IMM_WIDTH: usize = CommonMOpForImm::<2>::IMM_WIDTH;
pub const COMMON_MOP_3_IMM_WIDTH: usize = CommonMOpForImm::<3>::IMM_WIDTH;
const COMMON_MOP_0_IMM_IN_SRC_COUNT: usize = CommonMOpForImm::<0>::IMM_IN_SRC_COUNT;
impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize>
CommonMOp<PrefixPad, DestReg, SrcRegWidth, SrcCount>
{
pub const IMM_IN_SRC_COUNT: usize = {
assert!(SrcCount::VALUE <= COMMON_MOP_SRC_LEN, "too many sources");
const _: () = assert!(COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM <= COMMON_MOP_SRC_LEN);
(COMMON_MOP_SRC_LEN - COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM)
- SrcCount::VALUE.saturating_sub(COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM)
};
pub const IMM_IN_SRC_RANGE: Range<usize> =
(COMMON_MOP_SRC_LEN - Self::IMM_IN_SRC_COUNT)..COMMON_MOP_SRC_LEN;
pub const IMM_WIDTH: usize = {
MOP_IMM_WIDTH - (COMMON_MOP_0_IMM_IN_SRC_COUNT - Self::IMM_IN_SRC_COUNT) * MOP_MIN_REG_WIDTH
};
pub fn imm_ty() -> SInt {
SInt::new(Self::IMM_WIDTH)
}
pub fn imm_parts_ty() -> CommonMOpImmParts<DynSize> {
let retval = CommonMOpImmParts[Self::IMM_IN_SRC_COUNT];
assert_eq!(
retval.canonical().bit_width(),
Self::IMM_WIDTH,
"{retval:#?}"
);
retval
}
#[hdl]
pub fn new(
prefix_pad: impl ToExpr<Type = UIntType<PrefixPad>>,
dest: impl ToExpr<Type = DestReg>,
src: impl ToExpr<Type = ArrayType<UIntType<SrcRegWidth>, SrcCount>>,
imm: impl ToExpr<Type = SInt>,
) -> Expr<Self> {
let prefix_pad = prefix_pad.to_expr();
let dest = dest.to_expr();
let src_in = src.to_expr();
let imm = imm.to_expr();
assert_eq!(imm.ty(), Self::imm_ty());
let src_reg_ty = src_in.ty().element();
let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty());
let mut src = [0_hdl_u0.cast_to(src_reg_ty); COMMON_MOP_SRC_LEN];
for i in 0..SrcCount::VALUE {
src[i] = src_in[i];
}
for (reversed_src_index, src_index) in Self::IMM_IN_SRC_RANGE.rev().enumerate() {
src[src_index] = imm_parts.reversed_src[reversed_src_index].cast_to(src_reg_ty);
}
#[hdl]
Self {
prefix_pad,
dest,
src: ArrayLiteral::new(
src_reg_ty,
Interned::from_iter(src.iter().map(|v| Expr::canonical(*v))),
)
.to_expr(),
imm_low: Expr::from_dyn_int(imm[..COMMON_MOP_IMM_LOW_WIDTH]),
imm_sign: Expr::from_dyn_int(imm >> (Self::IMM_WIDTH - 1)),
_phantom: PhantomData,
}
}
#[hdl]
pub fn imm(expr: impl ToExpr<Type = Self>) -> Expr<SInt> {
let expr = expr.to_expr();
let reversed_src = Vec::from_iter(
Self::IMM_IN_SRC_RANGE
.rev()
.map(|src_index| expr.src[src_index].cast_to_static()),
);
let imm_parts = {
#[hdl]
CommonMOpImmParts {
imm_low: expr.imm_low,
reversed_src,
imm_sign: expr.imm_sign,
}
};
imm_parts.cast_to_bits().cast_bits_to(Self::imm_ty())
}
#[hdl]
pub fn connect_to_imm(expr: impl ToExpr<Type = Self>, imm: impl ToExpr<Type = SInt>) {
let expr = expr.to_expr();
let src_reg_ty = expr.ty().src.element();
let imm = imm.to_expr();
assert_eq!(imm.ty(), Self::imm_ty());
let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty());
let mut src = [Some(0_hdl_u0.cast_to(src_reg_ty)); COMMON_MOP_SRC_LEN];
for i in 0..SrcCount::VALUE {
src[i] = None;
}
for (reversed_src_index, src_index) in Self::IMM_IN_SRC_RANGE.rev().enumerate() {
src[src_index] = Some(imm_parts.reversed_src[reversed_src_index].cast_to(src_reg_ty));
}
for i in 0..COMMON_MOP_SRC_LEN {
if let Some(v) = src[i] {
connect(expr.src[i], v);
}
}
}
}
pub const COMMON_MOP_0_IMM_WIDTH: usize = common_mop_max_imm_size(0);
pub const COMMON_MOP_1_IMM_WIDTH: usize = common_mop_max_imm_size(1);
pub const COMMON_MOP_2_IMM_WIDTH: usize = common_mop_max_imm_size(2);
pub const COMMON_MOP_3_IMM_WIDTH: usize = common_mop_max_imm_size(3);
macro_rules! common_mop_struct {
(
@ -483,23 +598,24 @@ macro_rules! common_mop_struct {
impl<$($Generic: $GenericBound),*> CommonMOpTrait for $MOp<$($Generic),*> {
type PrefixPad = <$common_ty as CommonMOpTrait>::PrefixPad;
type SrcCount = <$common_ty as CommonMOpTrait>::SrcCount;
type Imm = <$common_ty as CommonMOpTrait>::Imm;
type CommonMOpTraitMapped<$NewDestReg: Type, $SrcRegWidth: Size> = $mapped_ty;
type CommonMOpTraitDestReg = <$common_ty as CommonMOpTrait>::CommonMOpTraitDestReg;
type CommonMOpTraitSrcRegWidth = <$common_ty as CommonMOpTrait>::CommonMOpTraitSrcRegWidth;
fn common_mop_ty(
self,
) -> CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount> {
) -> CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm> {
CommonMOpTrait::common_mop_ty(self.$common)
}
fn common_mop(
input: impl ToExpr<Type = Self>,
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount>> {
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>> {
CommonMOpTrait::common_mop(input.to_expr().$common)
}
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self,
new_common_mop_ty: CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
new_common_mop_ty: CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount, Self::Imm>,
) -> Self::Mapped<NewDestReg, NewSrcRegWidth> {
$MOp {
$common: CommonMOpTrait::with_common_mop_ty(self.$common, new_common_mop_ty),
@ -510,7 +626,7 @@ macro_rules! common_mop_struct {
fn with_common_mop<NewDestReg: Type, NewSrcRegWidth: Size>(
input: impl ToExpr<Type = Self>,
new_common_mop: impl ToExpr<
Type = CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
Type = CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount, Self::Imm>,
>,
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
let input = input.to_expr();
@ -818,11 +934,11 @@ macro_rules! mop_enum {
pub(crate) use mop_enum;
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> AluCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
#[mapped(<NewDestReg, NewSrcRegWidth> AluCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount, Imm>)]
#[hdl(cmp_eq)]
pub struct AluCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
pub struct AluCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize, Imm: Type> {
#[common]
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount>,
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount, Imm>,
pub output_integer_mode: OutputIntegerMode,
}
}
@ -832,7 +948,7 @@ common_mop_struct! {
#[hdl(cmp_eq)]
pub struct AddSubMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
#[common]
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount>,
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount, CommonMOpDefaultImm<SrcCount>>,
pub invert_src0: Bool,
/// * if this is `true`, use `alu_common.src[1]`'s [`PRegFlagsPowerISA::xer_ca`] as a carry-in/borrow-in
/// * else, use `alu_common.src[1]` as a normal addend
@ -862,7 +978,13 @@ impl<DestReg: Type, SrcRegWidth: Size> AddSubMOp<DestReg, SrcRegWidth, ConstUsiz
AddSubMOp {
alu_common: #[hdl]
AluCommonMOp {
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
common: #[hdl]
CommonMOp {
prefix_pad: 0_hdl_u0,
dest,
src,
imm: CommonMOpDefaultImm::from_sint(imm.to_expr()),
},
output_integer_mode,
},
invert_src0,
@ -894,7 +1016,13 @@ impl<DestReg: Type, SrcRegWidth: Size> AddSubMOp<DestReg, SrcRegWidth, ConstUsiz
AddSubMOp {
alu_common: #[hdl]
AluCommonMOp {
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
common: #[hdl]
CommonMOp {
prefix_pad: 0_hdl_u0,
dest,
src,
imm: CommonMOpDefaultImm::from_sint(imm.to_expr()),
},
output_integer_mode,
},
invert_src0,
@ -987,18 +1115,6 @@ pub struct LogicalFlagsMOpImm {
pub dest_count: UIntInRangeInclusive<0, { PRegFlags::FLAG_COUNT }>,
}
#[cfg(test)]
#[test]
fn test_logical_flags_mop_imm_fits() {
let needed_width = LogicalFlagsMOpImm.canonical().bit_width();
let imm_width =
CommonMOpFor::<LogicalFlagsMOp<MOpDestReg, ConstUsize<{ MOpRegNum::WIDTH }>>>::IMM_WIDTH;
assert!(
needed_width <= imm_width,
"needed_width={needed_width} imm_width={imm_width}",
);
}
/// intentionally not publicly constructable
#[derive(Copy, Clone)]
pub struct LogicalFlagsMOpImmFromSwizzleFnSrc<const SRC: usize> {
@ -1087,20 +1203,6 @@ impl std::error::Error for LogicalFlagsMopImmTryFromSwizzleFnError {}
impl LogicalFlagsMOpImm {
pub const SWIZZLE_CAPACITY: usize = 4;
#[track_caller]
pub fn from_imm(imm: impl ToExpr<Type = SInt>) -> Expr<Self> {
let imm_ty =
CommonMOpFor::<LogicalFlagsMOp<MOpDestReg, ConstUsize<{ MOpRegNum::WIDTH }>>>::imm_ty();
let imm = imm.to_expr();
assert_eq!(imm_ty, imm.ty(), "imm must have the correct width");
imm.cast_to(UInt[LogicalFlagsMOpImm.canonical().bit_width()])
.cast_bits_to(LogicalFlagsMOpImm)
}
pub fn to_imm(this: impl ToExpr<Type = Self>) -> Expr<SInt> {
let imm_ty =
CommonMOpFor::<LogicalFlagsMOp<MOpDestReg, ConstUsize<{ MOpRegNum::WIDTH }>>>::imm_ty();
this.to_expr().cast_to_bits().cast_to(imm_ty)
}
fn flags_operation_impl<Flags, I, IU, C, CU, Lut, U, B, AF>(
src0_start: I,
src1_start: I,
@ -1464,7 +1566,7 @@ common_mop_struct! {
/// ```
pub struct LogicalFlagsMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, ConstUsize<3>>,
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, ConstUsize<3>, LogicalFlagsMOpImm>,
pub lut: Lut4,
}
}
@ -1477,7 +1579,7 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalFlagsMOp<DestReg, SrcRegWidth> {
) -> Expr<PRegValue> {
let this = this.to_expr();
let flags = LogicalFlagsMOpImm::flags_operation(
Self::imm(this),
this.common.imm,
this.lut,
src.to_expr().map(|v| v.flags),
);
@ -1496,10 +1598,18 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalFlagsMOp<DestReg, SrcRegWidth> {
this: impl ToSimValue<Type = Self>,
src: impl ToSimValue<Type = Array<PRegValue, 3>>,
) -> SimValue<PRegValue> {
let this = this.into_sim_value();
#[hdl(sim)]
let Self { common, lut } = this.into_sim_value();
#[hdl(sim)]
let CommonMOp::<_, _, _, _, _> {
prefix_pad: _,
dest: _,
src: _,
imm,
} = common;
let flags = LogicalFlagsMOpImm::flags_operation_sim(
Self::imm(&this),
SimValue::into_value(this).lut,
imm,
lut,
SimValue::into_value(src.into_sim_value()).map(|v| SimValue::into_value(v).flags),
);
#[hdl(sim)]
@ -1513,10 +1623,6 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalFlagsMOp<DestReg, SrcRegWidth> {
}
}
#[hdl]
pub fn imm(this: impl ToExpr<Type = Self>) -> Expr<LogicalFlagsMOpImm> {
LogicalFlagsMOpImm::from_imm(CommonMOpFor::<Self>::imm(this.to_expr().common))
}
#[hdl]
pub fn logical_flags<Target: MOpTrait>(
dest: impl ToExpr<Type = DestReg>,
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 3>>,
@ -1529,12 +1635,13 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalFlagsMOp<DestReg, SrcRegWidth> {
MOpInto::mop_into(
#[hdl]
LogicalFlagsMOp {
common: CommonMOp::new(
0_hdl_u0,
common: #[hdl]
CommonMOp {
prefix_pad: 0_hdl_u0,
dest,
src,
LogicalFlagsMOpImm::to_imm(imm.to_expr()),
),
imm,
},
lut,
},
)
@ -1546,7 +1653,7 @@ common_mop_struct! {
#[hdl(cmp_eq)]
pub struct LogicalMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
#[common]
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount>,
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount, CommonMOpDefaultImm<SrcCount>>,
pub lut: Lut4,
}
}
@ -1568,7 +1675,13 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth, ConstUsi
LogicalMOp {
alu_common: #[hdl]
AluCommonMOp {
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
common: #[hdl]
CommonMOp {
prefix_pad: 0_hdl_u0,
dest,
src,
imm: CommonMOpDefaultImm::from_sint(imm.to_expr()),
},
output_integer_mode,
},
lut,
@ -1594,7 +1707,13 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth, ConstUsi
LogicalMOp {
alu_common: #[hdl]
AluCommonMOp {
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
common: #[hdl]
CommonMOp {
prefix_pad: 0_hdl_u0,
dest,
src,
imm: CommonMOpDefaultImm::from_sint(imm.to_expr()),
},
output_integer_mode,
},
lut,
@ -1748,50 +1867,17 @@ pub struct ShiftRotateMOpImm {
pub dest_logic_op: HdlOption<ShiftRotateDestLogicOp>,
}
#[cfg(test)]
#[test]
fn test_shift_rotate_mop_imm_fits() {
let needed_width = ShiftRotateMOpImm.canonical().bit_width();
let imm_width =
CommonMOpFor::<ShiftRotateMOp<MOpDestReg, ConstUsize<{ MOpRegNum::WIDTH }>>>::IMM_WIDTH;
assert!(
needed_width <= imm_width,
"needed_width={needed_width} imm_width={imm_width}",
);
}
impl ShiftRotateMOpImm {
#[track_caller]
pub fn from_imm(imm: impl ToExpr<Type = SInt>) -> Expr<Self> {
let imm_ty =
CommonMOpFor::<ShiftRotateMOp<MOpDestReg, ConstUsize<{ MOpRegNum::WIDTH }>>>::imm_ty();
let imm = imm.to_expr();
assert_eq!(imm_ty, imm.ty(), "imm must have the correct width");
imm.cast_to(UInt[ShiftRotateMOpImm.canonical().bit_width()])
.cast_bits_to(ShiftRotateMOpImm)
}
pub fn to_imm(this: impl ToExpr<Type = Self>) -> Expr<SInt> {
let imm_ty =
CommonMOpFor::<ShiftRotateMOp<MOpDestReg, ConstUsize<{ MOpRegNum::WIDTH }>>>::imm_ty();
this.to_expr().cast_to_bits().cast_to(imm_ty)
}
}
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> ShiftRotateMOp<NewDestReg, NewSrcRegWidth>)]
#[hdl(cmp_eq)]
pub struct ShiftRotateMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<3>>,
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<3>, ShiftRotateMOpImm>,
pub mode: ShiftRotateMode,
}
}
impl<DestReg: Type, SrcRegWidth: Size> ShiftRotateMOp<DestReg, SrcRegWidth> {
#[hdl]
pub fn imm(this: impl ToExpr<Type = Self>) -> Expr<ShiftRotateMOpImm> {
ShiftRotateMOpImm::from_imm(CommonMOpFor::<Self>::imm(this.to_expr().alu_common.common))
}
#[hdl]
pub fn shift_rotate<Target: MOpTrait>(
dest: impl ToExpr<Type = DestReg>,
@ -1808,12 +1894,13 @@ impl<DestReg: Type, SrcRegWidth: Size> ShiftRotateMOp<DestReg, SrcRegWidth> {
ShiftRotateMOp {
alu_common: #[hdl]
AluCommonMOp {
common: CommonMOp::new(
0_hdl_u0,
common: #[hdl]
CommonMOp {
prefix_pad: 0_hdl_u0,
dest,
src,
ShiftRotateMOpImm::to_imm(imm.to_expr()),
),
imm,
},
output_integer_mode,
},
mode,
@ -1879,7 +1966,7 @@ common_mop_struct! {
#[hdl(cmp_eq)]
pub struct CompareMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
#[common]
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount>,
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount, CommonMOpDefaultImm<SrcCount>>,
pub compare_mode: CompareMode,
}
}
@ -1901,7 +1988,13 @@ impl<DestReg: Type, SrcRegWidth: Size> CompareMOp<DestReg, SrcRegWidth, ConstUsi
CompareMOp {
alu_common: #[hdl]
AluCommonMOp {
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
common: #[hdl]
CommonMOp {
prefix_pad: 0_hdl_u0,
dest,
src,
imm: CommonMOpDefaultImm::from_sint(imm.to_expr()),
},
output_integer_mode,
},
compare_mode,
@ -1927,7 +2020,13 @@ impl<DestReg: Type, SrcRegWidth: Size> CompareMOp<DestReg, SrcRegWidth, ConstUsi
CompareMOp {
alu_common: #[hdl]
AluCommonMOp {
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
common: #[hdl]
CommonMOp {
prefix_pad: 0_hdl_u0,
dest,
src,
imm: CommonMOpDefaultImm::from_sint(imm.to_expr()),
},
output_integer_mode,
},
compare_mode,
@ -1992,7 +2091,7 @@ common_mop_struct! {
/// The output value is the next instruction's address used for a return address when this is a call.
pub struct BranchMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
#[common]
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount>,
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount, CommonMOpDefaultImm<SrcCount>>,
pub invert_src0_cond: Bool,
pub src0_cond_mode: ConditionMode,
/// `src2`'s condition passes if `src2`'s value `== 0`.
@ -2022,7 +2121,13 @@ impl<DestReg: Type, SrcRegWidth: Size> BranchMOp<DestReg, SrcRegWidth, ConstUsiz
MOpInto::mop_into(
#[hdl]
BranchMOp {
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
common: #[hdl]
CommonMOp {
prefix_pad: 0_hdl_u0,
dest,
src,
imm: CommonMOpDefaultImm::from_sint(imm.to_expr()),
},
invert_src0_cond,
src0_cond_mode,
invert_src2_eq_zero: false,
@ -2083,7 +2188,13 @@ impl<DestReg: Type, SrcRegWidth: Size> BranchMOp<DestReg, SrcRegWidth, ConstUsiz
MOpInto::mop_into(
#[hdl]
BranchMOp {
common: CommonMOp::new(0_hdl_u0, dest, src, Expr::as_dyn_int(imm.to_expr())),
common: #[hdl]
CommonMOp {
prefix_pad: 0_hdl_u0,
dest,
src,
imm: CommonMOpDefaultImm::from_sint(imm.to_expr()),
},
invert_src0_cond,
src0_cond_mode,
invert_src2_eq_zero,
@ -2150,7 +2261,7 @@ common_mop_struct! {
#[hdl(cmp_eq)]
pub struct ReadL2RegMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, ConstUsize<0>>,
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, ConstUsize<0>, CommonMOpDefaultImm<ConstUsize<0>>>,
}
}
@ -2159,7 +2270,7 @@ common_mop_struct! {
#[hdl(cmp_eq)]
pub struct WriteL2RegMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, ConstUsize<1>>,
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, ConstUsize<1>, CommonMOpDefaultImm<ConstUsize<1>>>,
}
}
@ -2261,7 +2372,7 @@ common_mop_struct! {
/// `src0` is always the address to load from or store to.
pub struct LoadStoreCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
#[common]
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, SrcCount>,
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, SrcCount, CommonMOpDefaultImm<SrcCount>>,
pub width: LoadStoreWidth,
pub conversion: LoadStoreConversion,
}
@ -2292,12 +2403,13 @@ impl<DestReg: Type, SrcRegWidth: Size> LoadMOp<DestReg, SrcRegWidth> {
LoadMOp {
load_store_common: #[hdl]
LoadStoreCommonMOp {
common: CommonMOp::new(
0.cast_to_static::<UInt<_>>(),
common: #[hdl]
CommonMOp {
prefix_pad: UInt::TYPE.zero(),
dest,
src,
SInt[COMMON_MOP_1_IMM_WIDTH].zero(),
),
imm: CommonMOpDefaultImm::TYPE.zero(),
},
width,
conversion,
},
@ -2332,12 +2444,13 @@ impl<DestReg: Type, SrcRegWidth: Size> StoreMOp<DestReg, SrcRegWidth> {
StoreMOp {
load_store_common: #[hdl]
LoadStoreCommonMOp {
common: CommonMOp::new(
0.cast_to_static::<UInt<_>>(),
common: #[hdl]
CommonMOp {
prefix_pad: UInt::TYPE.zero(),
dest,
src,
SInt[COMMON_MOP_2_IMM_WIDTH].zero(),
),
imm: CommonMOpDefaultImm::TYPE.zero(),
},
width,
conversion,
},
@ -2360,7 +2473,7 @@ common_mop_struct! {
#[hdl(cmp_eq)]
pub struct MoveRegMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub common: CommonMOp<ConstUsize<4>, DestReg, SrcRegWidth, ConstUsize<1>>,
pub common: CommonMOp<ConstUsize<4>, DestReg, SrcRegWidth, ConstUsize<1>, CommonMOpDefaultImm<ConstUsize<1>>>,
}
}
@ -2395,12 +2508,13 @@ impl<DestReg: Type, SrcRegWidth: Size> MoveRegMOp<DestReg, SrcRegWidth> {
MOpInto::mop_into(
#[hdl]
MoveRegMOp {
common: CommonMOp::new(
0.cast_to_static::<UInt<_>>(),
common: #[hdl]
CommonMOp {
prefix_pad: UInt::TYPE.zero(),
dest,
src,
Expr::as_dyn_int(imm.to_expr()),
),
imm: CommonMOpDefaultImm::from_sint(imm),
},
},
)
}

View file

@ -4,7 +4,7 @@
use crate::{
config::CpuConfig,
instruction::{
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOpDefaultImm,
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp,
ShiftRotateMOp, UnitOutRegNum,
},
@ -42,11 +42,11 @@ fn add_sub<SrcCount: KnownSize>(
add_pc,
} = mop;
#[hdl]
let AluCommonMOp::<_, _, _> {
let AluCommonMOp::<_, _, _, _> {
common,
output_integer_mode,
} = alu_common;
let imm: Expr<UInt<64>> = CommonMOp::imm(common).cast_to_static();
let imm = CommonMOpDefaultImm::as_sint_dyn(common.imm).cast_to_static::<UInt<64>>();
#[hdl]
let carry_in_before_inversion = wire();
connect(carry_in_before_inversion, false);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff