WIP: implement more instructions in unit::alu_branch #14

Draft
programmerjake wants to merge 8 commits from programmerjake/cpu:more-alu-branch into master
6 changed files with 133317 additions and 1315 deletions
Showing only changes of commit 99c019431b - Show all commits

View file

@ -6,7 +6,8 @@ use crate::{
instruction::{
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
CommonMOpDefaultImm, CompareMOp, CompareMode, ConditionMode, LogicalFlagsMOp, LogicalMOp,
OutputIntegerMode, PRegNum, ReadSpecialMOp, ShiftRotateMOp,
OutputIntegerMode, PRegNum, ReadSpecialMOp, ShiftRotateDestLogicOp, ShiftRotateMOp,
ShiftRotateMOpImm, ShiftRotateMode,
},
next_pc::CallStackOp,
register::{
@ -280,17 +281,227 @@ fn logical_i<C: PhantomConstCpuConfig>(
PRegValue::zeroed().to_trace_as_string()
}
#[hdl]
fn funnel_shift<W: Size, A: Size>(
high: impl ToExpr<Type = UIntType<W>>,
low: impl ToExpr<Type = UIntType<W>>,
shift_right: impl ToExpr<Type = Bool>,
shift_amount: impl ToExpr<Type = UIntType<A>>,
) -> Expr<UIntType<W>> {
let high = high.to_expr();
let low = low.to_expr();
let shift_right = shift_right.to_expr();
let shift_amount = shift_amount.to_expr();
let int_ty = high.ty();
assert_eq!(int_ty, low.ty());
#[hdl]
let funnel_shift_high = wire(int_ty);
connect(funnel_shift_high, high);
#[hdl]
let funnel_shift_low = wire(int_ty);
connect(funnel_shift_low, low);
#[hdl]
let funnel_shift_right = wire();
connect(funnel_shift_right, shift_right);
#[hdl]
let funnel_shift_amount = wire(
UInt[shift_amount
.ty()
.width()
.min(UInt::range_usize(0..int_ty.width()).width())],
);
connect_any(funnel_shift_amount, shift_amount);
#[hdl]
let funnel_shift_reverse_amount = wire(funnel_shift_amount.ty());
connect_any(
funnel_shift_reverse_amount,
int_ty.width() - funnel_shift_amount,
);
#[hdl]
let funnel_shift_high_left_amount = wire(funnel_shift_amount.ty());
#[hdl]
let funnel_shift_low_right_amount = wire(funnel_shift_amount.ty());
#[hdl]
let funnel_shift_retval = wire(int_ty);
connect_any(
funnel_shift_retval,
(funnel_shift_high << funnel_shift_high_left_amount)
| (funnel_shift_low >> funnel_shift_low_right_amount),
);
#[hdl]
if funnel_shift_right {
connect(funnel_shift_high_left_amount, funnel_shift_reverse_amount);
connect(funnel_shift_low_right_amount, funnel_shift_amount);
#[hdl]
if shift_amount.cmp_eq(0u8) {
connect(funnel_shift_retval, funnel_shift_low);
}
} else {
connect(funnel_shift_high_left_amount, funnel_shift_amount);
connect(funnel_shift_low_right_amount, funnel_shift_reverse_amount);
#[hdl]
if shift_amount.cmp_eq(0u8) {
connect(funnel_shift_retval, funnel_shift_high);
}
}
funnel_shift_retval
}
#[hdl]
fn shift_rotate<C: PhantomConstCpuConfig>(
global_state: Expr<GlobalState>,
pc: Expr<UInt<64>>,
mop: Expr<ShiftRotateMOp<PRegNum<C>, PRegNum<C>>>,
src_values: Expr<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
) -> Expr<TraceAsString<PRegValue>> {
#[hdl]
let GlobalState { flags_mode } = global_state;
// TODO: finish
PRegValue::zeroed().to_trace_as_string()
#[hdl]
let ShiftRotateMOp::<_, _> { alu_common, mode } = mop;
#[hdl]
let AluCommonMOp::<_, _, _, _> {
common,
output_integer_mode,
} = alu_common;
#[hdl]
let ShiftRotateMOpImm {
shift_rotate_amount: shift_rotate_amount_opt,
shift_rotate_right,
shift_amount_overflow_behavior,
dest_logic_op,
} = common.imm;
#[hdl]
let shift_rotate_amount = wire();
#[hdl]
match shift_rotate_amount_opt {
HdlSome(shift_rotate_amount_opt) => connect(
shift_rotate_amount,
shift_rotate_amount_opt.cast_to_static::<UInt<64>>(),
),
HdlNone => connect(shift_rotate_amount, src_values[2].int_fp),
}
#[hdl]
let funnel_shift_2x64_high: UInt<64> = wire();
#[hdl]
let funnel_shift_2x64_low: UInt<64> = wire();
#[hdl]
let funnel_shift_2x64_amount = wire(UInt::range_usize(0..funnel_shift_2x64_high.ty().width()));
#[hdl]
let funnel_shift_2x64_output: UInt<64> = wire();
connect(
funnel_shift_2x64_output,
funnel_shift(
funnel_shift_2x64_high,
funnel_shift_2x64_low,
shift_rotate_right,
funnel_shift_2x64_amount,
),
);
#[hdl]
let shifted_rotated: UInt<64> = wire();
let excess_bits_for_2x64 = |width| funnel_shift_2x64_low.ty().width() - width;
let connect_for_funnel_shift = |width| {
// TODO: handle large shift_rotate_amount >= width
connect(
funnel_shift_2x64_high,
src_values[0]
.int_fp
.cast_to(UInt[width])
.cast_to_static::<UInt<64>>(),
);
connect_any(
funnel_shift_2x64_low,
src_values[1].int_fp.cast_to(UInt[width]) << excess_bits_for_2x64(width),
);
connect_any(funnel_shift_2x64_amount, shift_rotate_amount);
#[hdl]
if shift_rotate_right {
connect_any(
shifted_rotated,
funnel_shift_2x64_output >> excess_bits_for_2x64(8),
);
} else {
connect(
shifted_rotated,
funnel_shift_2x64_output
.cast_to(UInt[width])
.cast_to_static::<UInt<64>>(),
);
}
};
let connect_for_sign_ext_then_shift = |width| {
// TODO: handle large shift_rotate_amount >= 64
let input = src_values[0]
.int_fp
.cast_to(SInt[width])
.cast_to_static::<SInt<64>>();
let input_sign_bit = input >> (input.ty().width() - 1);
#[hdl]
if shift_rotate_right {
connect(funnel_shift_2x64_high, input_sign_bit.cast_to_static());
connect(funnel_shift_2x64_low, input.cast_to_static());
connect_any(funnel_shift_2x64_amount, shift_rotate_amount);
connect(shifted_rotated, funnel_shift_2x64_output);
} else {
connect(funnel_shift_2x64_high, input.cast_to_static());
connect(funnel_shift_2x64_low, 0u64);
connect_any(funnel_shift_2x64_amount, shift_rotate_amount);
connect(shifted_rotated, funnel_shift_2x64_output);
}
};
#[hdl]
match mode {
ShiftRotateMode::FunnelShift2x8Bit => connect_for_funnel_shift(8),
ShiftRotateMode::FunnelShift2x16Bit => connect_for_funnel_shift(16),
ShiftRotateMode::FunnelShift2x32Bit => connect_for_funnel_shift(32),
ShiftRotateMode::FunnelShift2x64Bit => connect_for_funnel_shift(64),
ShiftRotateMode::SignExt8To64BitThenShift => connect_for_sign_ext_then_shift(8),
ShiftRotateMode::SignExt16To64BitThenShift => connect_for_sign_ext_then_shift(16),
ShiftRotateMode::SignExt32To64BitThenShift => connect_for_sign_ext_then_shift(32),
ShiftRotateMode::ShiftSigned64 => connect_for_sign_ext_then_shift(64),
}
#[hdl]
let masked: UInt<64> = wire();
#[hdl]
if let HdlSome(dest_logic_op) = dest_logic_op {
connect(
masked,
ShiftRotateDestLogicOp::operation(dest_logic_op, shifted_rotated, src_values[2].int_fp),
);
} else {
connect(masked, shifted_rotated);
}
#[hdl]
let int_fp: UInt<64> = wire();
fn connect_int_fp_cast<T: IntType + StaticType>(int_fp: Expr<UInt<64>>, masked: Expr<UInt<64>>)
where
UInt<64>: CastToImpl<T>,
T: CastToImpl<UInt<64>>,
{
connect(
int_fp,
masked.cast_to_static::<T>().cast_to_static::<UInt<64>>(),
)
}
#[hdl]
match output_integer_mode {
OutputIntegerMode::Full64 => connect(int_fp, masked),
OutputIntegerMode::DupLow32 => connect_any(
int_fp,
masked.cast_to_static::<UInt<32>>() | (masked.cast_to_static::<UInt<32>>() << 32),
),
OutputIntegerMode::ZeroExt32 => connect_int_fp_cast::<UInt<32>>(int_fp, masked),
OutputIntegerMode::SignExt32 => connect_int_fp_cast::<SInt<32>>(int_fp, masked),
OutputIntegerMode::ZeroExt16 => connect_int_fp_cast::<UInt<16>>(int_fp, masked),
OutputIntegerMode::SignExt16 => connect_int_fp_cast::<SInt<16>>(int_fp, masked),
OutputIntegerMode::ZeroExt8 => connect_int_fp_cast::<UInt<8>>(int_fp, masked),
OutputIntegerMode::SignExt8 => connect_int_fp_cast::<SInt<8>>(int_fp, masked),
}
let retval = #[hdl]
PRegValue {
int_fp,
flags: PRegFlags::zeroed(), // TODO: compute flags
};
retval.into_trace_as_string()
}
#[hdl]
@ -703,10 +914,7 @@ pub fn alu_branch(config: PhantomConst<CpuConfig>, unit_index: usize) {
);
}
AluBranchMOp::<_, _>::ShiftRotate(mop) => {
connect(
dest_value,
shift_rotate(global_state, mop_instance.pc, mop, src_values),
);
connect(dest_value, shift_rotate(global_state, mop, src_values));
}
AluBranchMOp::<_, _>::Compare(mop) => {
connect(dest_value, compare(global_state, mop, src_values));

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1642,7 +1642,7 @@ macro_rules! impl_funnel_shift {
}
fn funnel_shr(high: Self, low: Self, shift: u32) -> Self {
if shift == 0 {
high
low
} else {
(high << ($ty::BITS - shift)) | (low >> shift)
}
@ -4585,6 +4585,42 @@ fn test_rename_execute_retire_head_n1() {
assert!(sim.read_bool(sim.io().all_outputs_written));
}
#[hdl]
#[test]
fn test_rename_execute_retire_head_n1_real() {
let _n = SourceLocation::normalize_files_for_tests();
let mut config = CpuConfig::new(
vec![
UnitConfig::new(UnitKind::AluBranch),
UnitConfig::new(UnitKind::AluBranch),
UnitConfig::new(UnitKind::LoadStore),
UnitConfig::new(UnitKind::TransformedMove),
],
NonZeroUsize::new(20).unwrap(),
);
config.fetch_width = NonZeroUsize::new(2).unwrap();
let m = rename_execute_retire_test_harness::<HeadN1Insns>(
PhantomConst::new_sized(config),
AluBranchKind::Real,
);
let mut sim = Simulation::new(m);
let _checked_vcd_output = checked_vcd_output!(
&mut sim,
"tests/expected/rename_execute_retire_head_n1_real.vcd",
);
sim.write_clock(sim.io().cd.clk, false);
sim.write_reset(sim.io().cd.rst, true);
for cycle in 0..300 {
sim.advance_time(SimDuration::from_nanos(500));
println!("clock tick: {cycle}");
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_nanos(500));
sim.write_clock(sim.io().cd.clk, false);
sim.write_reset(sim.io().cd.rst, false);
}
assert!(sim.read_bool(sim.io().all_outputs_written));
}
struct SaveRestoreGprsInsns;
impl SaveRestoreGprsInsns {