add shift/rotate MOp definition
All checks were successful
/ test (pull_request) Successful in 29m25s
All checks were successful
/ test (pull_request) Successful in 29m25s
This commit is contained in:
parent
2ad469e331
commit
59874b9b29
4 changed files with 191279 additions and 180374 deletions
|
|
@ -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>>),
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
116958
crates/cpu/tests/expected/reg_alloc.vcd
generated
116958
crates/cpu/tests/expected/reg_alloc.vcd
generated
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue