forked from libre-chip/cpu
add shift/rotate MOp definition
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]
|
#[hdl]
|
||||||
pub enum CompareMode {
|
pub enum CompareMode {
|
||||||
U64,
|
U64,
|
||||||
|
|
@ -1918,6 +2132,7 @@ mop_enum! {
|
||||||
LogicalFlags(LogicalFlagsMOp<DestReg, SrcRegWidth>),
|
LogicalFlags(LogicalFlagsMOp<DestReg, SrcRegWidth>),
|
||||||
Logical(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
Logical(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
||||||
LogicalI(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
LogicalI(LogicalMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||||
|
ShiftRotate(ShiftRotateMOp<DestReg, SrcRegWidth>),
|
||||||
Compare(CompareMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
Compare(CompareMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
||||||
CompareI(CompareMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
CompareI(CompareMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||||
Branch(BranchMOp<DestReg, SrcRegWidth, ConstUsize<3>>),
|
Branch(BranchMOp<DestReg, SrcRegWidth, ConstUsize<3>>),
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
|
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
|
||||||
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp,
|
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp,
|
||||||
UnitOutRegNum,
|
ShiftRotateMOp, UnitOutRegNum,
|
||||||
},
|
},
|
||||||
register::{
|
register::{
|
||||||
FlagsMode, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, PRegFlagsX86,
|
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]
|
#[hdl]
|
||||||
fn compare<SrcCount: KnownSize>(
|
fn compare<SrcCount: KnownSize>(
|
||||||
mop: Expr<CompareMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
|
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(
|
AluBranchMOp::<_, _>::Compare(mop) => connect(
|
||||||
unit_base.execute_end,
|
unit_base.execute_end,
|
||||||
HdlSome(
|
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