add shift/rotate MOp definition
All checks were successful
/ test (pull_request) Successful in 29m25s

This commit is contained in:
Jacob Lifshay 2026-01-25 20:34:38 -08:00
parent 2ad469e331
commit 59874b9b29
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
4 changed files with 191279 additions and 180374 deletions

View file

@ -1603,6 +1603,220 @@ impl<DestReg: Type, SrcRegWidth: Size> LogicalMOp<DestReg, SrcRegWidth, ConstUsi
}
}
#[hdl]
pub enum ShiftRotateMode {
/// like `llvm.fsh[lr].i8(src0, src1, src2)`
FunnelShift2x8Bit,
/// like `llvm.fsh[lr].i16(src0, src1, src2)`
FunnelShift2x16Bit,
/// like `llvm.fsh[lr].i32(src0, src1, src2)`
FunnelShift2x32Bit,
/// like `llvm.fsh[lr].i64(src0, src1, src2)`
FunnelShift2x64Bit,
SignExt8To64BitThenShift,
SignExt16To64BitThenShift,
SignExt32To64BitThenShift,
}
impl HdlPartialEqImpl<Self> for ShiftRotateMode {
#[track_caller]
fn cmp_value_eq(
lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
rhs: Self,
rhs_value: Cow<'_, Self::SimValue>,
) -> bool {
SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned()))
== SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned()))
}
#[track_caller]
fn cmp_sim_value_eq(
lhs: Cow<'_, SimValue<Self>>,
rhs: Cow<'_, SimValue<Self>>,
) -> SimValue<Bool> {
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
}
#[track_caller]
fn cmp_sim_value_ne(
lhs: Cow<'_, SimValue<Self>>,
rhs: Cow<'_, SimValue<Self>>,
) -> SimValue<Bool> {
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_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())
}
}
#[hdl(cmp_eq)]
pub struct ShiftRotateDestLogicOp {
pub rotated_output_start: UInt<6>,
pub rotated_output_len: UInt<6>,
/// `false` for fallback is zeros, `true` for fallback is `src1`
pub fallback_is_src1: Bool,
}
impl ShiftRotateDestLogicOp {
#[hdl]
fn operation_impl<U64, U6, U, B, S1>(
rotated_output_start: U6,
rotated_output_len: U6,
fallback_is_src1: B,
rotated_output: U64,
src1: U64,
) -> U64
where
U64: ValueType<Type = UInt<64>>
+ Rotate<U6, Output = U64>
+ std::ops::BitAnd<Output = U>
+ std::ops::Not<Output = U64>
+ Clone,
U: CastTo<Type = UInt, Output<UInt<64>> = U64>
+ std::ops::BitAnd<U64, Output = U>
+ std::ops::BitOr<Output = U>,
U6: ValueType<Type = UInt<6>>,
B: CastTo<Type = Bool, Output<SInt<1>> = S1>,
S1: CastTo<Type = SInt<1>, Output<UInt<64>> = U64>,
u8: std::ops::Shl<
U6,
Output: std::ops::Sub<u8, Output: CastTo<Type = UInt, Output<UInt<64>> = U64>>,
>,
{
let unrotated_mask = ((1u8 << rotated_output_len) - 1u8).cast_to_static::<UInt<64>>();
let mask = unrotated_mask.rotate_left(rotated_output_start);
let src1_mask = fallback_is_src1
.cast_to_static::<SInt<1>>()
.cast_to_static::<UInt<64>>();
((rotated_output & mask.clone()) | (src1_mask & src1 & !mask)).cast_to_static::<UInt<64>>()
}
pub fn operation(
this: impl ToExpr<Type = Self>,
rotated_output: impl ToExpr<Type = UInt<64>>,
src1: impl ToExpr<Type = UInt<64>>,
) -> Expr<UInt<64>> {
let this = this.to_expr();
let rotated_output = rotated_output.to_expr();
let src1 = src1.to_expr();
Self::operation_impl(
this.rotated_output_start,
this.rotated_output_len,
this.fallback_is_src1,
rotated_output,
src1,
)
}
#[hdl]
pub fn operation_sim(
this: impl ToSimValue<Type = Self>,
rotated_output: impl ToSimValue<Type = UInt<64>>,
src1: impl ToSimValue<Type = UInt<64>>,
) -> SimValue<UInt<64>> {
#[hdl(sim)]
let Self {
rotated_output_start,
rotated_output_len,
fallback_is_src1,
} = this.into_sim_value();
let rotated_output = rotated_output.into_sim_value();
let src1 = src1.into_sim_value();
Self::operation_impl(
rotated_output_start,
rotated_output_len,
fallback_is_src1,
rotated_output,
src1,
)
}
}
/// immediate values for [`ShiftRotateMOp`].
#[hdl(cmp_eq)]
pub struct ShiftRotateMOpImm {
/// taken from `src2` if this is [`HdlNone`]
pub shift_rotate_amount: HdlOption<UInt<6>>,
/// `false` for shift/rotate left, `true` for shift/rotate right
pub shift_rotate_right: Bool,
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 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>,
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 3>>,
imm: impl ToExpr<Type = ShiftRotateMOpImm>,
output_integer_mode: impl ToExpr<Type = OutputIntegerMode>,
mode: impl ToExpr<Type = ShiftRotateMode>,
) -> Expr<Target>
where
Self: MOpInto<Target>,
{
MOpInto::mop_into(
#[hdl]
ShiftRotateMOp {
alu_common: #[hdl]
AluCommonMOp {
common: CommonMOp::new(
0_hdl_u0,
dest,
src,
ShiftRotateMOpImm::to_imm(imm.to_expr()),
),
output_integer_mode,
},
mode,
},
)
}
}
#[hdl]
pub enum CompareMode {
U64,
@ -1918,6 +2132,7 @@ mop_enum! {
LogicalFlags(LogicalFlagsMOp<DestReg, SrcRegWidth>),
Logical(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
LogicalI(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
ShiftRotate(ShiftRotateMOp<DestReg, SrcRegWidth>),
Compare(CompareMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
CompareI(CompareMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
Branch(BranchMOp<DestReg, SrcRegWidth, ConstUsize<3>>),

View file

@ -6,7 +6,7 @@ use crate::{
instruction::{
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp,
UnitOutRegNum,
ShiftRotateMOp, UnitOutRegNum,
},
register::{
FlagsMode, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, PRegFlagsX86,
@ -285,6 +285,20 @@ fn logical_i(
}
}
#[hdl]
fn shift_rotate(
mop: Expr<ShiftRotateMOp<UnitOutRegNum<DynSize>, DynSize>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
) -> Expr<UnitResultCompleted<()>> {
// TODO: finish
#[hdl]
UnitResultCompleted::<_> {
value: PRegValue::zeroed(),
extra_out: (),
}
}
#[hdl]
fn compare<SrcCount: KnownSize>(
mop: Expr<CompareMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
@ -440,6 +454,23 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
},
),
),
AluBranchMOp::<_, _>::ShiftRotate(mop) => connect(
unit_base.execute_end,
HdlSome(
#[hdl]
ExecuteEnd::<_, _> {
unit_output: #[hdl]
UnitOutput::<_, _> {
which: MOpTrait::dest_reg(mop),
result: UnitResult[()].Completed(shift_rotate(
mop,
global_state.flags_mode,
src_values,
)),
},
},
),
),
AluBranchMOp::<_, _>::Compare(mop) => connect(
unit_base.execute_end,
HdlSome(

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff