add a procedural implementation of rename_execute_retire #12
8 changed files with 100223 additions and 3334 deletions
|
|
@ -7,8 +7,8 @@ use crate::{
|
|||
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
|
||||
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
|
||||
MOpRegNum, MoveRegMOp, OutputIntegerMode, ReadSpecialMOp, ReadSpecialMOpImm,
|
||||
ShiftRotateDestLogicOp, ShiftRotateMOp, ShiftRotateMOpImm, ShiftRotateMode, StoreMOp,
|
||||
power_isa::PowerIsaSprEnum,
|
||||
ShiftAmountOverflowBehavior, ShiftRotateDestLogicOp, ShiftRotateMOp, ShiftRotateMOpImm,
|
||||
ShiftRotateMode, StoreMOp, power_isa::PowerIsaSprEnum,
|
||||
},
|
||||
powerisa_instructions_xml::{
|
||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||
|
|
@ -1953,6 +1953,7 @@ impl DecodeState<'_> {
|
|||
ShiftRotateMOpImm {
|
||||
shift_rotate_amount: HdlNone(),
|
||||
shift_rotate_right: false,
|
||||
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior.WrapToWidth(),
|
||||
dest_logic_op,
|
||||
},
|
||||
OutputIntegerMode.Full64(),
|
||||
|
|
@ -2003,6 +2004,7 @@ impl DecodeState<'_> {
|
|||
ShiftRotateMOpImm {
|
||||
shift_rotate_amount: HdlSome(rotate_amount),
|
||||
shift_rotate_right: false,
|
||||
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior.WrapToWidth(),
|
||||
dest_logic_op,
|
||||
},
|
||||
OutputIntegerMode.Full64(),
|
||||
|
|
@ -2153,6 +2155,8 @@ impl DecodeState<'_> {
|
|||
ShiftRotateMOpImm {
|
||||
shift_rotate_amount: HdlSome(sh.cast_to_static::<UInt<_>>()),
|
||||
shift_rotate_right: true,
|
||||
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior
|
||||
.WrapToWidth(),
|
||||
dest_logic_op: HdlNone(),
|
||||
},
|
||||
OutputIntegerMode.Full64(),
|
||||
|
|
@ -2181,6 +2185,8 @@ impl DecodeState<'_> {
|
|||
ShiftRotateMOpImm {
|
||||
shift_rotate_amount: HdlSome(sh.rotate_right(1)),
|
||||
shift_rotate_right: true,
|
||||
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior
|
||||
.WrapToWidth(),
|
||||
dest_logic_op: HdlNone(),
|
||||
},
|
||||
OutputIntegerMode.Full64(),
|
||||
|
|
@ -2222,6 +2228,8 @@ impl DecodeState<'_> {
|
|||
ShiftRotateMOpImm {
|
||||
shift_rotate_amount: HdlNone(),
|
||||
shift_rotate_right: is_right_shift,
|
||||
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior
|
||||
.WrapToTwiceWidth(),
|
||||
dest_logic_op: HdlNone(),
|
||||
},
|
||||
OutputIntegerMode.Full64(),
|
||||
|
|
@ -2257,6 +2265,8 @@ impl DecodeState<'_> {
|
|||
ShiftRotateMOpImm {
|
||||
shift_rotate_amount: HdlSome(sh.rotate_right(1)),
|
||||
shift_rotate_right: false,
|
||||
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior
|
||||
.WrapToWidth(),
|
||||
dest_logic_op: HdlNone(),
|
||||
},
|
||||
OutputIntegerMode.Full64(),
|
||||
|
|
|
|||
|
|
@ -2273,6 +2273,14 @@ impl ShiftRotateDestLogicOp {
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq)]
|
||||
pub enum ShiftAmountOverflowBehavior {
|
||||
/// wrap shift amount to width specified by [`ShiftRotateMode`]
|
||||
WrapToWidth,
|
||||
/// wrap shift amount to twice the width specified by [`ShiftRotateMode`]
|
||||
WrapToTwiceWidth,
|
||||
}
|
||||
|
||||
/// immediate values for [`ShiftRotateMOp`].
|
||||
#[hdl(cmp_eq, custom_debug(sim))]
|
||||
pub struct ShiftRotateMOpImm {
|
||||
|
|
@ -2280,6 +2288,7 @@ pub struct ShiftRotateMOpImm {
|
|||
pub shift_rotate_amount: HdlOption<UInt<6>>,
|
||||
/// `false` for shift/rotate left, `true` for shift/rotate right
|
||||
pub shift_rotate_right: Bool,
|
||||
pub shift_amount_overflow_behavior: ShiftAmountOverflowBehavior,
|
||||
pub dest_logic_op: HdlOption<ShiftRotateDestLogicOp>,
|
||||
}
|
||||
|
||||
|
|
@ -2289,20 +2298,24 @@ impl SimValueDebug for ShiftRotateMOpImm {
|
|||
value: &<Self as Type>::SimValue,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
type SimValueT<T> = <T as Type>::SimValue;
|
||||
let SimValueT::<Self> {
|
||||
#[hdl(sim)]
|
||||
let Self {
|
||||
shift_rotate_amount,
|
||||
shift_rotate_right,
|
||||
shift_amount_overflow_behavior,
|
||||
dest_logic_op,
|
||||
} = value;
|
||||
let shift_op = if **shift_rotate_right { ">>" } else { "<<" };
|
||||
#[hdl(sim)]
|
||||
match shift_rotate_amount {
|
||||
HdlSome(shift_rotate_amount) => {
|
||||
write!(f, "{shift_op}{shift_rotate_amount}")?;
|
||||
write!(
|
||||
f,
|
||||
"{shift_op}{shift_rotate_amount}, {shift_amount_overflow_behavior:?}"
|
||||
)?;
|
||||
}
|
||||
HdlNone => {
|
||||
write!(f, "{shift_op}_")?;
|
||||
write!(f, "{shift_op}_, {shift_amount_overflow_behavior:?}")?;
|
||||
}
|
||||
}
|
||||
#[hdl(sim)]
|
||||
|
|
|
|||
|
|
@ -5211,7 +5211,7 @@ $var string 1 vz0q< range $end
|
|||
$upscope $end
|
||||
$upscope $end
|
||||
$scope struct memory $end
|
||||
$var wire 1 sOSum wrote_output $end
|
||||
$var wire 1 @TBV: wrote_outputs $end
|
||||
$scope struct memory $end
|
||||
$var string 1 ix'Be \[0] $end
|
||||
$var string 1 H~H-k \[1] $end
|
||||
|
|
@ -5254,7 +5254,7 @@ $var string 1 Z;~$o \[3] $end
|
|||
$upscope $end
|
||||
$upscope $end
|
||||
$scope struct speculative_memory $end
|
||||
$var wire 1 vnbJY wrote_output $end
|
||||
$var wire 1 Kq]85 wrote_outputs $end
|
||||
$scope struct memory $end
|
||||
$var string 1 :ZBGp \[0] $end
|
||||
$var string 1 0>Zml \[1] $end
|
||||
|
|
@ -9054,7 +9054,7 @@ sPRegValue\x20{\x20int_fp:\x200x0_u64,\x20flags:\x20Pwr\x20{\x20..\x20}\x20} `gT
|
|||
sPhantomConst({\"units\":[{\"kind\":\"AluBranch\",\"max_in_flight\":null},{\"kind\":\"AluBranch\",\"max_in_flight\":null},{\"kind\":\"AluBranch\",\"max_in_flight\":null},{\"kind\":\"LoadStore\",\"max_in_flight\":null},{\"kind\":\"TransformedMove\",\"max_in_flight\":null}],\"out_reg_num_width\":4,\"fetch_width\":3,\"max_branches_per_fetch\":1,\"max_fetches_in_flight\":16,\"log2_fetch_width_in_bytes\":3,\"log2_cache_line_size_in_bytes\":6,\"log2_l1_i_cache_line_count\":8,\"l1_i_cache_max_misses_in_flight\":2,\"default_unit_max_in_flight\":8,\"rob_size\":20}) 4Zy)W
|
||||
b0 >VIL>
|
||||
sPhantomConst(\"0..=8\") vz0q<
|
||||
0sOSum
|
||||
0@TBV:
|
||||
s<empty> ix'Be
|
||||
s<empty> H~H-k
|
||||
s<empty> 5u]|o
|
||||
|
|
@ -9091,7 +9091,7 @@ sHdlNone )CVUo
|
|||
sHdlNone [Y*(@
|
||||
sHdlNone Krk/@
|
||||
sHdlNone Z;~$o
|
||||
0vnbJY
|
||||
0Kq]85
|
||||
s<empty> :ZBGp
|
||||
s<empty> 0>Zml
|
||||
s<empty> ZwL}Q
|
||||
|
|
@ -55513,8 +55513,8 @@ b10110011 ,6\L'
|
|||
0DReB3
|
||||
sHdlSome\x20(1) -$362
|
||||
1*tV+r
|
||||
1sOSum
|
||||
1vnbJY
|
||||
1@TBV:
|
||||
1Kq]85
|
||||
1BqYmm
|
||||
#102000000
|
||||
0spsS)
|
||||
|
|
|
|||
95580
crates/cpu/tests/expected/rename_execute_retire_head_n1.vcd
generated
Normal file
95580
crates/cpu/tests/expected/rename_execute_retire_head_n1.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -5963,7 +5963,7 @@ $var string 1 B}e,9 range $end
|
|||
$upscope $end
|
||||
$upscope $end
|
||||
$scope struct memory $end
|
||||
$var wire 1 AS:f~ wrote_output $end
|
||||
$var wire 1 %s]xe wrote_outputs $end
|
||||
$scope struct memory $end
|
||||
$var string 1 >eAWB \[0] $end
|
||||
$var string 1 ;"Eei \[1] $end
|
||||
|
|
@ -6006,7 +6006,7 @@ $var string 1 \C_K@ \[3] $end
|
|||
$upscope $end
|
||||
$upscope $end
|
||||
$scope struct speculative_memory $end
|
||||
$var wire 1 sdwYO wrote_output $end
|
||||
$var wire 1 17-uK wrote_outputs $end
|
||||
$scope struct memory $end
|
||||
$var string 1 NDoVs \[0] $end
|
||||
$var string 1 8P[do \[1] $end
|
||||
|
|
@ -10204,7 +10204,7 @@ sPRegValue\x20{\x20int_fp:\x200x0_u64,\x20flags:\x20Pwr\x20{\x20..\x20}\x20} u(t
|
|||
sPhantomConst({\"units\":[{\"kind\":\"AluBranch\",\"max_in_flight\":null},{\"kind\":\"AluBranch\",\"max_in_flight\":null},{\"kind\":\"AluBranch\",\"max_in_flight\":null},{\"kind\":\"AluBranch\",\"max_in_flight\":null},{\"kind\":\"LoadStore\",\"max_in_flight\":null},{\"kind\":\"TransformedMove\",\"max_in_flight\":null}],\"out_reg_num_width\":4,\"fetch_width\":4,\"max_branches_per_fetch\":1,\"max_fetches_in_flight\":16,\"log2_fetch_width_in_bytes\":3,\"log2_cache_line_size_in_bytes\":6,\"log2_l1_i_cache_line_count\":8,\"l1_i_cache_max_misses_in_flight\":2,\"default_unit_max_in_flight\":8,\"rob_size\":20}) jP^cy
|
||||
b0 {gg.?
|
||||
sPhantomConst(\"0..=8\") B}e,9
|
||||
0AS:f~
|
||||
0%s]xe
|
||||
s<empty> >eAWB
|
||||
s<empty> ;"Eei
|
||||
s<empty> KNqbB
|
||||
|
|
@ -10241,7 +10241,7 @@ sHdlNone sL!o}
|
|||
sHdlNone (~TAa
|
||||
sHdlNone }L]aR
|
||||
sHdlNone \C_K@
|
||||
0sdwYO
|
||||
017-uK
|
||||
s<empty> NDoVs
|
||||
s<empty> 8P[do
|
||||
s<empty> Rys^?
|
||||
|
|
@ -109795,8 +109795,8 @@ b11101010 nTP#.
|
|||
0{[(D]
|
||||
sHdlSome\x20(1) goXwC
|
||||
1\O.%q
|
||||
1AS:f~
|
||||
1sdwYO
|
||||
1%s]xe
|
||||
117-uK
|
||||
1yhGZ]
|
||||
#443000000
|
||||
0spsS)
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ use cpu::{
|
|||
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
|
||||
CompareMOp, CompareMode, ConditionMode, L2RegNum, L2RegisterFileMOp, LoadMOp,
|
||||
LoadStoreCommonMOp, LoadStoreConversion, LoadStoreMOp, LoadStoreWidth, MOp, MOpDestReg,
|
||||
MOpRegNum, MOpTrait, MoveRegMOp, OutputIntegerMode, PRegNum, ReadL2RegMOp, StoreMOp,
|
||||
UnitNum, WriteL2RegMOp,
|
||||
MOpRegNum, MOpTrait, MoveRegMOp, OutputIntegerMode, PRegNum, ReadL2RegMOp,
|
||||
ShiftAmountOverflowBehavior, ShiftRotateDestLogicOp, ShiftRotateMOp, ShiftRotateMOpImm,
|
||||
ShiftRotateMode, StoreMOp, UnitNum, WriteL2RegMOp,
|
||||
},
|
||||
next_pc::CallStackOp,
|
||||
register::{PRegFlags, PRegFlagsPowerISA, PRegValue},
|
||||
|
|
@ -331,6 +332,43 @@ impl InsnsBuilder {
|
|||
},
|
||||
));
|
||||
}
|
||||
fn power_isa_bdnz(&mut self, target: InsnsBuilderLabel) {
|
||||
let pc = self.pc;
|
||||
self.add_insn(Insn::new_lazy(
|
||||
4,
|
||||
format!("bdnz {}", self.labels[target.0].name),
|
||||
move |labels| {
|
||||
[
|
||||
AddSubMOp::add_sub_i::<MOp>(
|
||||
MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []),
|
||||
[MOpRegNum::power_isa_ctr_reg(), MOpRegNum::const_zero()],
|
||||
(-1).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
BranchMOp::branch_ctr(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::power_isa_ctr_reg(),
|
||||
],
|
||||
labels[target.0]
|
||||
.pc()
|
||||
.wrapping_sub(pc)
|
||||
.cast_to_static::<SInt<_>>(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
]
|
||||
},
|
||||
));
|
||||
}
|
||||
fn power_isa_bl(&mut self, target: InsnsBuilderLabel) {
|
||||
let pc = self.pc;
|
||||
self.add_insn(Insn::new_lazy(
|
||||
|
|
@ -402,6 +440,45 @@ impl InsnsBuilder {
|
|||
)],
|
||||
));
|
||||
}
|
||||
fn power_isa_cmplwi(&mut self, dest: usize, src: usize, imm: u16) {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
format!("cmplwi {dest}, {src}, {imm:#x}"),
|
||||
[CompareMOp::compare_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(dest)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(src)],
|
||||
imm.cast_to_static::<SInt<_>>(),
|
||||
CompareMode.U32(),
|
||||
)],
|
||||
));
|
||||
}
|
||||
fn power_isa_lbzu(&mut self, dest: usize, src: usize, disp: i16) {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
format!("lbzu {dest}, {}({src})", signed_hex(disp)),
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(src)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(src),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
disp.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(dest)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(src)],
|
||||
LoadStoreWidth.Width8Bit(),
|
||||
LoadStoreConversion.ZeroExt(),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
fn power_isa_ld(&mut self, dest: usize, src: usize, disp: i16) {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
|
|
@ -429,6 +506,36 @@ impl InsnsBuilder {
|
|||
],
|
||||
));
|
||||
}
|
||||
fn power_isa_stb(&mut self, value_src: usize, addr_src: usize, disp: i16) {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
format!("stb {value_src}, {}({addr_src})", signed_hex(disp)),
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_or_zero_reg_imm(addr_src),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
disp.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
StoreMOp::store(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_temp_reg(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm(value_src),
|
||||
],
|
||||
LoadStoreWidth.Width8Bit(),
|
||||
LoadStoreConversion.ZeroExt(),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
fn power_isa_std(&mut self, value_src: usize, addr_src: usize, disp: i16) {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
|
|
@ -459,6 +566,72 @@ impl InsnsBuilder {
|
|||
],
|
||||
));
|
||||
}
|
||||
fn power_isa_stdu(&mut self, value_src: usize, addr_src: usize, disp: i16) {
|
||||
if value_src == addr_src {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
format!("stdu {value_src}, {}({addr_src})", signed_hex(disp)),
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(addr_src),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
disp.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
StoreMOp::store(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_temp_reg(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm(value_src),
|
||||
],
|
||||
LoadStoreWidth.Width64Bit(),
|
||||
LoadStoreConversion.ZeroExt(),
|
||||
),
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(addr_src)], &[]),
|
||||
[MOpRegNum::power_isa_temp_reg()],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
],
|
||||
));
|
||||
} else {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
format!("stdu {value_src}, {}({addr_src})", signed_hex(disp)),
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(addr_src)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(addr_src),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
disp.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
StoreMOp::store(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(addr_src),
|
||||
MOpRegNum::power_isa_gpr_reg_imm(value_src),
|
||||
],
|
||||
LoadStoreWidth.Width64Bit(),
|
||||
LoadStoreConversion.ZeroExt(),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
fn power_isa_mflr(&mut self, dest: usize) {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
|
|
@ -481,6 +654,28 @@ impl InsnsBuilder {
|
|||
)],
|
||||
));
|
||||
}
|
||||
fn power_isa_mfctr(&mut self, dest: usize) {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
format!("mfctr {dest}"),
|
||||
[MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(dest)], &[]),
|
||||
[MOpRegNum::power_isa_ctr_reg()],
|
||||
0i8.cast_to_static::<SInt<_>>(),
|
||||
)],
|
||||
));
|
||||
}
|
||||
fn power_isa_mtctr(&mut self, src: usize) {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
format!("mtctr {src}"),
|
||||
[MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_CTR_REG_NUM], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(src)],
|
||||
0i8.cast_to_static::<SInt<_>>(),
|
||||
)],
|
||||
));
|
||||
}
|
||||
fn power_isa_mr(&mut self, dest: usize, src: usize) {
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
|
|
@ -492,6 +687,64 @@ impl InsnsBuilder {
|
|||
)],
|
||||
));
|
||||
}
|
||||
#[hdl]
|
||||
fn power_isa_rlwinm(
|
||||
&mut self,
|
||||
dest: usize,
|
||||
src: usize,
|
||||
shift: u32,
|
||||
msb0_mask_begin: u32,
|
||||
msb0_mask_end: u32,
|
||||
) {
|
||||
assert!(shift < 32);
|
||||
assert!(msb0_mask_begin < 32);
|
||||
assert!(msb0_mask_end < 32);
|
||||
let insn = format!("rlwinm {dest}, {src}, {shift}, {msb0_mask_begin}, {msb0_mask_end}");
|
||||
let msb0_mask_begin = msb0_mask_begin + 32;
|
||||
let msb0_mask_end = msb0_mask_end + 32;
|
||||
// gives the correct value modulo 2^6 even when `msb0_mask_begin > msb0_mask_end`
|
||||
let rotated_output_len = msb0_mask_end.wrapping_sub(msb0_mask_begin).wrapping_add(1) % 64;
|
||||
// account for lsb0 vs. msb0
|
||||
let rotated_output_start = !msb0_mask_end % 64;
|
||||
self.add_insn(Insn::new(
|
||||
4,
|
||||
insn,
|
||||
[ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(dest)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(src),
|
||||
MOpRegNum::power_isa_gpr_reg_imm(src),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
#[hdl]
|
||||
ShiftRotateMOpImm {
|
||||
shift_rotate_amount: HdlSome(shift.cast_to_static::<UInt<_>>()),
|
||||
shift_rotate_right: false,
|
||||
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior.WrapToWidth(),
|
||||
dest_logic_op: if rotated_output_len == 0 {
|
||||
// rotated_output_len wrapped around to 64
|
||||
HdlNone()
|
||||
} else {
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ShiftRotateDestLogicOp {
|
||||
rotated_output_start: rotated_output_start
|
||||
.cast_to_static::<UInt<_>>(),
|
||||
rotated_output_len: rotated_output_len.cast_to_static::<UInt<_>>(),
|
||||
fallback_is_src2: false,
|
||||
},
|
||||
)
|
||||
},
|
||||
},
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.FunnelShift2x32Bit(),
|
||||
)],
|
||||
));
|
||||
}
|
||||
fn power_isa_clrlwi(&mut self, dest: usize, src: usize, width: u32) {
|
||||
assert!(width < 32);
|
||||
self.power_isa_rlwinm(dest, src, 0, width, 31);
|
||||
}
|
||||
}
|
||||
|
||||
trait MakeInsns {
|
||||
|
|
@ -499,59 +752,6 @@ trait MakeInsns {
|
|||
fn make_load_store_execution_state() -> MockMemory;
|
||||
}
|
||||
|
||||
struct FibonacciInsns;
|
||||
|
||||
impl MakeInsns for FibonacciInsns {
|
||||
fn make_insns() -> Insns {
|
||||
let mut b = InsnsBuilder::new();
|
||||
|
||||
let fib = b.new_label("fib");
|
||||
let fib_small = b.new_label("fib_small");
|
||||
b.power_isa_ld(3, 0, MockMemory::IO_ADDR as i16); // load input
|
||||
b.power_isa_addi(1, 0, 0x4000); // setup stack pointer
|
||||
b.power_isa_bl(fib);
|
||||
b.power_isa_std(3, 0, MockMemory::IO_ADDR as i16); // store output
|
||||
let done = b.new_defined_label("done");
|
||||
b.power_isa_b(done);
|
||||
|
||||
b.set_pc(0x1000);
|
||||
b.define_label(fib);
|
||||
b.power_isa_cmpldi(0, 3, 1);
|
||||
b.power_isa_ble(fib_small); // if input <= 1 goto fib_small
|
||||
|
||||
// push stack frame
|
||||
b.power_isa_mflr(0);
|
||||
b.power_isa_addi(1, 1, -16);
|
||||
b.power_isa_std(0, 1, 0);
|
||||
b.power_isa_std(30, 1, 8);
|
||||
|
||||
b.power_isa_addi(30, 3, -2);
|
||||
b.power_isa_addi(3, 3, -1);
|
||||
b.power_isa_bl(fib); // fib(input - 1)
|
||||
b.power_isa_mr(2, 3);
|
||||
b.power_isa_mr(3, 30);
|
||||
b.power_isa_mr(30, 2);
|
||||
b.power_isa_bl(fib); // fib(input - 2)
|
||||
b.power_isa_add(3, 3, 30); // set output to fib(input - 1) + fib(input - 2)
|
||||
|
||||
// pop stack frame and return
|
||||
b.power_isa_ld(0, 1, 0);
|
||||
b.power_isa_ld(30, 1, 8);
|
||||
b.power_isa_addi(1, 1, 16);
|
||||
b.power_isa_mtlr(0);
|
||||
b.power_isa_blr();
|
||||
|
||||
b.define_label(fib_small);
|
||||
b.power_isa_addi(3, 0, 1); // set output to 1
|
||||
b.power_isa_blr(); // return
|
||||
|
||||
b.build()
|
||||
}
|
||||
fn make_load_store_execution_state() -> MockMemory {
|
||||
MockMemory::new(4, 5, [])
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
struct BrPredDebugState {
|
||||
call_stack: ArrayVec<UInt<64>, ConstUsize<{ BrPredState::CALL_STACK_CAPACITY }>>,
|
||||
|
|
@ -1045,7 +1245,7 @@ type SimOnlyMemoryChunk = SimOnly<MemoryChunk>;
|
|||
|
||||
#[hdl(no_static)]
|
||||
struct MockMemoryDebugState<C: PhantomConstGet<()> = PhantomConst<()>> {
|
||||
wrote_output: Bool,
|
||||
wrote_outputs: Bool,
|
||||
memory: ArrayType<SimOnlyMemoryChunk, MockMemoryDebugStateMemorySize<C>>,
|
||||
l1_cache:
|
||||
Array<TraceAsString<HdlOption<MockCacheLineDebugState>>, { MockMemory::CACHE_LINE_COUNT }>,
|
||||
|
|
@ -1053,9 +1253,9 @@ struct MockMemoryDebugState<C: PhantomConstGet<()> = PhantomConst<()>> {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
struct MockMemory {
|
||||
input: u64,
|
||||
expected_output: u64,
|
||||
wrote_output: bool,
|
||||
input: std::vec::IntoIter<u64>,
|
||||
expected_output: Vec<u64>,
|
||||
output: Vec<u64>,
|
||||
memory: BTreeMap<u64, SimOnlyValue<MemoryChunk>>,
|
||||
l1_cache: [Option<MockCacheLine>; Self::CACHE_LINE_COUNT],
|
||||
}
|
||||
|
|
@ -1106,14 +1306,14 @@ impl MockMemory {
|
|||
const LOG2_CACHE_LINE_COUNT: usize = 2;
|
||||
const CACHE_LINE_COUNT: usize = 1 << Self::LOG2_CACHE_LINE_COUNT;
|
||||
fn new<'a, I: IntoIterator<Item = (u64, &'a [u8])>>(
|
||||
input: u64,
|
||||
expected_output: u64,
|
||||
input: Vec<u64>,
|
||||
expected_output: Vec<u64>,
|
||||
initial_memory: I,
|
||||
) -> Self {
|
||||
let mut retval = Self {
|
||||
input,
|
||||
input: input.into_iter(),
|
||||
output: Vec::with_capacity(expected_output.len()),
|
||||
expected_output,
|
||||
wrote_output: false,
|
||||
memory: BTreeMap::new(),
|
||||
l1_cache: [const { None }; _],
|
||||
};
|
||||
|
|
@ -1125,6 +1325,11 @@ impl MockMemory {
|
|||
retval.cache_flush();
|
||||
retval
|
||||
}
|
||||
fn wrote_outputs(&self) -> bool {
|
||||
// function filling `output` checks that it matches `expected_output`,
|
||||
// so we just need to check the length here
|
||||
self.output.len() == self.expected_output.len()
|
||||
}
|
||||
fn cache_flush(&mut self) {
|
||||
self.l1_cache.fill(None);
|
||||
}
|
||||
|
|
@ -1179,11 +1384,18 @@ impl MockMemory {
|
|||
}
|
||||
Err(FillCacheError::Uncacheable) => {
|
||||
assert!(!is_speculative);
|
||||
let mut value = None;
|
||||
for (chunk_byte_index, byte) in chunk_range.zip(&mut bytes[load_store_range]) {
|
||||
let offset = chunk_addr
|
||||
.wrapping_add(chunk_byte_index as u64)
|
||||
.wrapping_sub(Self::IO_ADDR);
|
||||
let value = self.input.to_le_bytes();
|
||||
let value = value
|
||||
.get_or_insert_with(|| {
|
||||
self.input
|
||||
.next()
|
||||
.unwrap_or_else(|| panic!("read input too many times"))
|
||||
})
|
||||
.to_le_bytes();
|
||||
assert!(offset < value.len() as u64);
|
||||
*byte = value[offset as usize];
|
||||
}
|
||||
|
|
@ -1230,11 +1442,16 @@ impl MockMemory {
|
|||
value[offset as usize] = *byte;
|
||||
}
|
||||
let value = u64::from_le_bytes(value);
|
||||
assert!(
|
||||
self.output.len() < self.expected_output.len(),
|
||||
"too many outputs"
|
||||
);
|
||||
assert_eq!(
|
||||
self.expected_output, value,
|
||||
self.expected_output[self.output.len()],
|
||||
value,
|
||||
"output doesn't match expected output"
|
||||
);
|
||||
self.wrote_output = true;
|
||||
self.output.push(value);
|
||||
}
|
||||
Err(FillCacheError::CacheMiss) => return Err(AddressCantBeSpeculativelyAccessed),
|
||||
}
|
||||
|
|
@ -1267,8 +1484,8 @@ impl MockMemory {
|
|||
fn debug_state(&self) -> SimValue<MockMemoryDebugState> {
|
||||
let Self {
|
||||
input: _,
|
||||
output: _,
|
||||
expected_output: _,
|
||||
wrote_output,
|
||||
memory,
|
||||
l1_cache,
|
||||
} = self;
|
||||
|
|
@ -1276,7 +1493,7 @@ impl MockMemory {
|
|||
let empty_chunk = SimOnlyValue::new(MemoryChunk::default());
|
||||
#[hdl(sim)]
|
||||
MockMemoryDebugState::<_> {
|
||||
wrote_output,
|
||||
wrote_outputs: self.wrote_outputs(),
|
||||
memory: SimValue::from_array_elements(
|
||||
ret_ty.memory,
|
||||
memory
|
||||
|
|
@ -1409,6 +1626,37 @@ impl MockMemory {
|
|||
}
|
||||
}
|
||||
|
||||
trait FunnelShift {
|
||||
fn funnel_shl(high: Self, low: Self, shift: u32) -> Self;
|
||||
fn funnel_shr(high: Self, low: Self, shift: u32) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! impl_funnel_shift {
|
||||
($ty:ident) => {
|
||||
impl FunnelShift for $ty {
|
||||
fn funnel_shl(high: Self, low: Self, shift: u32) -> Self {
|
||||
if shift == 0 {
|
||||
high
|
||||
} else {
|
||||
(high << shift) | (low >> ($ty::BITS - shift))
|
||||
}
|
||||
}
|
||||
fn funnel_shr(high: Self, low: Self, shift: u32) -> Self {
|
||||
if shift == 0 {
|
||||
high
|
||||
} else {
|
||||
(high << ($ty::BITS - shift)) | (low >> shift)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_funnel_shift!(u8);
|
||||
impl_funnel_shift!(u16);
|
||||
impl_funnel_shift!(u32);
|
||||
impl_funnel_shift!(u64);
|
||||
|
||||
trait MockExecutionStateTrait: Default {
|
||||
type DebugState: BundleType;
|
||||
fn debug_state_ty() -> Self::DebugState;
|
||||
|
|
@ -1541,6 +1789,188 @@ trait MockExecutionStateTrait: Default {
|
|||
}
|
||||
}
|
||||
#[hdl]
|
||||
fn run_shift_rotate<C: PhantomConstCpuConfig>(
|
||||
&mut self,
|
||||
mop: &SimValue<ShiftRotateMOp<PRegNum<C>, PRegNum<C>>>,
|
||||
src_values: &[SimValue<TraceAsString<PRegValue>>; COMMON_MOP_SRC_LEN],
|
||||
) -> SimValue<TraceAsString<PRegValue>> {
|
||||
#[hdl(sim)]
|
||||
let ShiftRotateMOp::<_, _> { alu_common, mode } = mop;
|
||||
#[hdl(sim)]
|
||||
let AluCommonMOp::<_, _, _, _> {
|
||||
common,
|
||||
output_integer_mode,
|
||||
} = alu_common;
|
||||
#[hdl(sim)]
|
||||
let CommonMOp::<_, _, _, _, _> {
|
||||
prefix_pad: _,
|
||||
dest: _,
|
||||
src: _,
|
||||
imm,
|
||||
} = common;
|
||||
#[hdl(sim)]
|
||||
let ShiftRotateMOpImm {
|
||||
shift_rotate_amount,
|
||||
shift_rotate_right,
|
||||
shift_amount_overflow_behavior,
|
||||
dest_logic_op,
|
||||
} = imm;
|
||||
let shift_rotate_amount = #[hdl(sim)]
|
||||
match shift_rotate_amount {
|
||||
HdlSome(shift_rotate_amount) => {
|
||||
shift_rotate_amount.cast_to_static::<UInt<64>>().as_int()
|
||||
}
|
||||
HdlNone => src_values[2].inner().int_fp.as_int(),
|
||||
};
|
||||
let shifted_rotated = #[hdl(sim)]
|
||||
match mode {
|
||||
ShiftRotateMode::FunnelShift2x8Bit => {
|
||||
if shift_rotate_amount >= 8 {
|
||||
todo!("large shift_rotate_amount={shift_rotate_amount}");
|
||||
}
|
||||
if **shift_rotate_right {
|
||||
FunnelShift::funnel_shr(
|
||||
src_values[0].inner().int_fp.as_int() as u8,
|
||||
src_values[1].inner().int_fp.as_int() as u8,
|
||||
shift_rotate_amount as _,
|
||||
) as u64
|
||||
} else {
|
||||
FunnelShift::funnel_shl(
|
||||
src_values[0].inner().int_fp.as_int() as u8,
|
||||
src_values[1].inner().int_fp.as_int() as u8,
|
||||
shift_rotate_amount as _,
|
||||
) as u64
|
||||
}
|
||||
}
|
||||
ShiftRotateMode::FunnelShift2x16Bit => {
|
||||
if shift_rotate_amount >= 16 {
|
||||
todo!("large shift_rotate_amount={shift_rotate_amount}");
|
||||
}
|
||||
if **shift_rotate_right {
|
||||
FunnelShift::funnel_shr(
|
||||
src_values[0].inner().int_fp.as_int() as u16,
|
||||
src_values[1].inner().int_fp.as_int() as u16,
|
||||
shift_rotate_amount as _,
|
||||
) as u64
|
||||
} else {
|
||||
FunnelShift::funnel_shl(
|
||||
src_values[0].inner().int_fp.as_int() as u16,
|
||||
src_values[1].inner().int_fp.as_int() as u16,
|
||||
shift_rotate_amount as _,
|
||||
) as u64
|
||||
}
|
||||
}
|
||||
ShiftRotateMode::FunnelShift2x32Bit => {
|
||||
if shift_rotate_amount >= 32 {
|
||||
todo!("large shift_rotate_amount={shift_rotate_amount}");
|
||||
}
|
||||
if **shift_rotate_right {
|
||||
FunnelShift::funnel_shr(
|
||||
src_values[0].inner().int_fp.as_int() as u32,
|
||||
src_values[1].inner().int_fp.as_int() as u32,
|
||||
shift_rotate_amount as _,
|
||||
) as u64
|
||||
} else {
|
||||
FunnelShift::funnel_shl(
|
||||
src_values[0].inner().int_fp.as_int() as u32,
|
||||
src_values[1].inner().int_fp.as_int() as u32,
|
||||
shift_rotate_amount as _,
|
||||
) as u64
|
||||
}
|
||||
}
|
||||
ShiftRotateMode::FunnelShift2x64Bit => {
|
||||
if shift_rotate_amount >= 64 {
|
||||
todo!("large shift_rotate_amount={shift_rotate_amount}");
|
||||
}
|
||||
if **shift_rotate_right {
|
||||
FunnelShift::funnel_shr(
|
||||
src_values[0].inner().int_fp.as_int(),
|
||||
src_values[1].inner().int_fp.as_int(),
|
||||
shift_rotate_amount as _,
|
||||
)
|
||||
} else {
|
||||
FunnelShift::funnel_shl(
|
||||
src_values[0].inner().int_fp.as_int(),
|
||||
src_values[1].inner().int_fp.as_int(),
|
||||
shift_rotate_amount as _,
|
||||
)
|
||||
}
|
||||
}
|
||||
ShiftRotateMode::SignExt8To64BitThenShift => {
|
||||
if shift_rotate_amount >= 64 {
|
||||
todo!("large shift_rotate_amount={shift_rotate_amount}");
|
||||
}
|
||||
let input = src_values[0].inner().int_fp.as_int() as i8 as i64;
|
||||
if **shift_rotate_right {
|
||||
(input >> shift_rotate_amount) as u64
|
||||
} else {
|
||||
(input << shift_rotate_amount) as u64
|
||||
}
|
||||
}
|
||||
ShiftRotateMode::SignExt16To64BitThenShift => {
|
||||
if shift_rotate_amount >= 64 {
|
||||
todo!("large shift_rotate_amount={shift_rotate_amount}");
|
||||
}
|
||||
let input = src_values[0].inner().int_fp.as_int() as i16 as i64;
|
||||
if **shift_rotate_right {
|
||||
(input >> shift_rotate_amount) as u64
|
||||
} else {
|
||||
(input << shift_rotate_amount) as u64
|
||||
}
|
||||
}
|
||||
ShiftRotateMode::SignExt32To64BitThenShift => {
|
||||
if shift_rotate_amount >= 64 {
|
||||
todo!("large shift_rotate_amount={shift_rotate_amount}");
|
||||
}
|
||||
let input = src_values[0].inner().int_fp.as_int() as i32 as i64;
|
||||
if **shift_rotate_right {
|
||||
(input >> shift_rotate_amount) as u64
|
||||
} else {
|
||||
(input << shift_rotate_amount) as u64
|
||||
}
|
||||
}
|
||||
ShiftRotateMode::ShiftSigned64 => {
|
||||
if shift_rotate_amount >= 64 {
|
||||
todo!("large shift_rotate_amount={shift_rotate_amount}");
|
||||
}
|
||||
let input = src_values[0].inner().int_fp.as_int() as i64;
|
||||
if **shift_rotate_right {
|
||||
(input >> shift_rotate_amount) as u64
|
||||
} else {
|
||||
(input << shift_rotate_amount) as u64
|
||||
}
|
||||
}
|
||||
};
|
||||
let masked = #[hdl(sim)]
|
||||
if let HdlSome(dest_logic_op) = dest_logic_op {
|
||||
ShiftRotateDestLogicOp::operation_sim(
|
||||
dest_logic_op,
|
||||
shifted_rotated,
|
||||
&src_values[2].inner().int_fp,
|
||||
)
|
||||
.as_int()
|
||||
} else {
|
||||
shifted_rotated
|
||||
};
|
||||
let int_fp = #[hdl(sim)]
|
||||
match output_integer_mode {
|
||||
OutputIntegerMode::Full64 => masked,
|
||||
OutputIntegerMode::DupLow32 => (masked & 0xFFFFFFFF) | (masked << 32),
|
||||
OutputIntegerMode::ZeroExt32 => masked as u32 as u64,
|
||||
OutputIntegerMode::SignExt32 => masked as i32 as u64,
|
||||
OutputIntegerMode::ZeroExt16 => masked as u16 as u64,
|
||||
OutputIntegerMode::SignExt16 => masked as i16 as u64,
|
||||
OutputIntegerMode::ZeroExt8 => masked as u8 as u64,
|
||||
OutputIntegerMode::SignExt8 => masked as i8 as u64,
|
||||
};
|
||||
let retval = #[hdl(sim)]
|
||||
PRegValue {
|
||||
int_fp,
|
||||
flags: PRegFlags::zeroed_sim(), // TODO: compute flags
|
||||
};
|
||||
retval.into_trace_as_string()
|
||||
}
|
||||
#[hdl]
|
||||
fn run_branch<C: PhantomConstCpuConfig, SrcCount: KnownSize>(
|
||||
&mut self,
|
||||
id: &SimValue<MOpId>,
|
||||
|
|
@ -1582,9 +2012,11 @@ trait MockExecutionStateTrait: Default {
|
|||
.get(2)
|
||||
.is_some_and(|src2| *src2 != PRegNum[config].const_zero_sim());
|
||||
let src2_cond = if has_src2 {
|
||||
let _ = invert_src2_eq_zero;
|
||||
let _ = src2;
|
||||
todo!("has_src2");
|
||||
if **invert_src2_eq_zero {
|
||||
src2.inner().int_fp.as_int() != 0
|
||||
} else {
|
||||
src2.inner().int_fp.as_int() == 0
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
|
@ -1724,9 +2156,10 @@ trait MockExecutionStateTrait: Default {
|
|||
AluBranchMOp::<_, _>::LogicalI(mop) => {
|
||||
todo!("implement LogicalI")
|
||||
}
|
||||
AluBranchMOp::<_, _>::ShiftRotate(mop) => {
|
||||
todo!("implement ShiftRotate")
|
||||
}
|
||||
AluBranchMOp::<_, _>::ShiftRotate(mop) => (
|
||||
Some((self.run_shift_rotate(mop, src_values), empty_predictor_op())),
|
||||
None,
|
||||
),
|
||||
AluBranchMOp::<_, _>::Compare(mop) => (
|
||||
Some((self.run_compare(mop, src_values), empty_predictor_op())),
|
||||
None,
|
||||
|
|
@ -3367,7 +3800,7 @@ fn mock_load_store_unit<#[hdl(skip)] MI: MakeInsns>(
|
|||
.await;
|
||||
}
|
||||
sim.write(debug_state, state.debug_state()).await;
|
||||
sim.write(all_outputs_written, state.memory.wrote_output)
|
||||
sim.write(all_outputs_written, state.memory.wrote_outputs())
|
||||
.await;
|
||||
sim.wait_for_clock_edge(cd.clk).await;
|
||||
{
|
||||
|
|
@ -3489,6 +3922,59 @@ fn rename_execute_retire_test_harness<#[hdl(skip)] MI: MakeInsns>(config: Phanto
|
|||
}
|
||||
}
|
||||
|
||||
struct FibonacciInsns;
|
||||
|
||||
impl MakeInsns for FibonacciInsns {
|
||||
fn make_insns() -> Insns {
|
||||
let mut b = InsnsBuilder::new();
|
||||
|
||||
let fib = b.new_label("fib");
|
||||
let fib_small = b.new_label("fib_small");
|
||||
b.power_isa_ld(3, 0, MockMemory::IO_ADDR as i16); // load input
|
||||
b.power_isa_addi(1, 0, 0x4000); // setup stack pointer
|
||||
b.power_isa_bl(fib);
|
||||
b.power_isa_std(3, 0, MockMemory::IO_ADDR as i16); // store output
|
||||
let done = b.new_defined_label("done");
|
||||
b.power_isa_b(done);
|
||||
|
||||
b.set_pc(0x1000);
|
||||
b.define_label(fib);
|
||||
b.power_isa_cmpldi(0, 3, 1);
|
||||
b.power_isa_ble(fib_small); // if input <= 1 goto fib_small
|
||||
|
||||
// push stack frame
|
||||
b.power_isa_mflr(0);
|
||||
b.power_isa_addi(1, 1, -16);
|
||||
b.power_isa_std(0, 1, 0);
|
||||
b.power_isa_std(30, 1, 8);
|
||||
|
||||
b.power_isa_addi(30, 3, -2);
|
||||
b.power_isa_addi(3, 3, -1);
|
||||
b.power_isa_bl(fib); // fib(input - 1)
|
||||
b.power_isa_mr(2, 3);
|
||||
b.power_isa_mr(3, 30);
|
||||
b.power_isa_mr(30, 2);
|
||||
b.power_isa_bl(fib); // fib(input - 2)
|
||||
b.power_isa_add(3, 3, 30); // set output to fib(input - 1) + fib(input - 2)
|
||||
|
||||
// pop stack frame and return
|
||||
b.power_isa_ld(0, 1, 0);
|
||||
b.power_isa_ld(30, 1, 8);
|
||||
b.power_isa_addi(1, 1, 16);
|
||||
b.power_isa_mtlr(0);
|
||||
b.power_isa_blr();
|
||||
|
||||
b.define_label(fib_small);
|
||||
b.power_isa_addi(3, 0, 1); // set output to 1
|
||||
b.power_isa_blr(); // return
|
||||
|
||||
b.build()
|
||||
}
|
||||
fn make_load_store_execution_state() -> MockMemory {
|
||||
MockMemory::new(vec![4], vec![5], [])
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[test]
|
||||
fn test_rename_execute_retire_fibonacci() {
|
||||
|
|
@ -3613,8 +4099,8 @@ impl MakeInsns for SlowLoopInsns {
|
|||
});
|
||||
let loop_count = 4;
|
||||
MockMemory::new(
|
||||
loop_count,
|
||||
expected * loop_count * 2u64.pow(Self::LOG2_RESULT_FACTOR),
|
||||
vec![loop_count],
|
||||
vec![expected * loop_count * 2u64.pow(Self::LOG2_RESULT_FACTOR)],
|
||||
[(Self::CONSTANTS_ADDR, constants.as_flattened())],
|
||||
)
|
||||
}
|
||||
|
|
@ -3674,3 +4160,139 @@ fn test_rename_execute_retire_slow_loop() {
|
|||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
/// equivalent of Unix's `head -n1`
|
||||
struct HeadN1Insns;
|
||||
|
||||
impl HeadN1Insns {
|
||||
const BUFFER_SIZE: u64 = 0x100;
|
||||
const MAIN_STACK_FRAME_SIZE: u64 = (Self::BUFFER_SIZE + 0x20).next_multiple_of(0x10);
|
||||
const BUFFER_OFFSET_FROM_SP: i16 = (Self::MAIN_STACK_FRAME_SIZE - Self::BUFFER_SIZE) as i16;
|
||||
const TEST_INPUT: &str = "Test input.\nLine 2";
|
||||
}
|
||||
|
||||
impl MakeInsns for HeadN1Insns {
|
||||
fn make_insns() -> Insns {
|
||||
let mut b = InsnsBuilder::new();
|
||||
|
||||
let main = b.new_label("main");
|
||||
b.power_isa_addi(1, 0, 0x4000); // setup stack pointer
|
||||
b.power_isa_bl(main);
|
||||
let done = b.new_defined_label("done");
|
||||
b.power_isa_b(done);
|
||||
|
||||
b.set_pc(0xF00);
|
||||
let error = b.new_defined_label("error");
|
||||
b.power_isa_addi(3, 0, -1);
|
||||
b.power_isa_std(3, 0, MockMemory::IO_ADDR as i16);
|
||||
b.power_isa_b(error);
|
||||
|
||||
b.set_pc(0x1000);
|
||||
b.define_label(main);
|
||||
b.power_isa_stdu(1, 1, -(Self::MAIN_STACK_FRAME_SIZE as i16));
|
||||
b.power_isa_ld(4, 0, MockMemory::IO_ADDR as i16);
|
||||
b.power_isa_addi(3, 0, Self::BUFFER_SIZE as i16);
|
||||
b.power_isa_addi(5, 1, Self::BUFFER_OFFSET_FROM_SP - 1);
|
||||
b.power_isa_mtctr(3);
|
||||
b.power_isa_addi(3, 0, 0);
|
||||
|
||||
let read_loop = b.new_defined_label("read_loop");
|
||||
b.power_isa_clrlwi(6, 4, 24);
|
||||
b.power_isa_cmplwi(0, 6, b'\n' as u16);
|
||||
let done_reading = b.new_label("done_reading");
|
||||
b.power_isa_beq(done_reading);
|
||||
|
||||
b.power_isa_stb(4, 5, 1);
|
||||
b.power_isa_addi(5, 5, 1);
|
||||
b.power_isa_addi(3, 3, 1);
|
||||
b.power_isa_ld(4, 0, MockMemory::IO_ADDR as i16);
|
||||
b.power_isa_bdnz(read_loop);
|
||||
|
||||
b.power_isa_bl(error);
|
||||
|
||||
b.define_label(done_reading);
|
||||
b.power_isa_cmpldi(0, 3, 0);
|
||||
let done_writing = b.new_label("done_writing");
|
||||
b.power_isa_beq(done_writing);
|
||||
|
||||
b.power_isa_addi(4, 1, Self::BUFFER_OFFSET_FROM_SP - 1);
|
||||
b.power_isa_mtctr(3);
|
||||
|
||||
let write_loop = b.new_defined_label("write_loop");
|
||||
b.power_isa_lbzu(3, 4, 1);
|
||||
b.power_isa_std(3, 0, MockMemory::IO_ADDR as i16);
|
||||
b.power_isa_bdnz(write_loop);
|
||||
|
||||
b.define_label(done_writing);
|
||||
b.power_isa_addi(3, 0, b'\n' as i16);
|
||||
b.power_isa_std(3, 0, MockMemory::IO_ADDR as i16);
|
||||
b.power_isa_addi(1, 1, Self::MAIN_STACK_FRAME_SIZE as i16);
|
||||
b.power_isa_blr();
|
||||
|
||||
b.build()
|
||||
}
|
||||
fn make_load_store_execution_state() -> MockMemory {
|
||||
MockMemory::new(
|
||||
Self::TEST_INPUT.bytes().map(|b| b as u64).collect(),
|
||||
Self::TEST_INPUT
|
||||
.split_inclusive('\n')
|
||||
.next()
|
||||
.expect("known to contain a newline")
|
||||
.bytes()
|
||||
.map(|b| b as u64)
|
||||
.collect(),
|
||||
[],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[test]
|
||||
fn test_rename_execute_retire_head_n1() {
|
||||
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));
|
||||
let mut sim = Simulation::new(m);
|
||||
let writer = RcWriter::default();
|
||||
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
||||
struct DumpVcdOnDrop {
|
||||
writer: Option<RcWriter>,
|
||||
}
|
||||
impl Drop for DumpVcdOnDrop {
|
||||
fn drop(&mut self) {
|
||||
if let Some(mut writer) = self.writer.take() {
|
||||
let vcd = String::from_utf8(writer.take()).unwrap();
|
||||
println!("####### VCD:\n{vcd}\n#######");
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut writer = DumpVcdOnDrop {
|
||||
writer: Some(writer),
|
||||
};
|
||||
sim.write_clock(sim.io().cd.clk, false);
|
||||
sim.write_reset(sim.io().cd.rst, true);
|
||||
for cycle in 0..200 {
|
||||
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));
|
||||
// FIXME: vcd is just whatever rename_execute_retire does now, which isn't known to be correct
|
||||
let vcd = String::from_utf8(writer.writer.take().unwrap().take()).unwrap();
|
||||
println!("####### VCD:\n{vcd}\n#######");
|
||||
if vcd != include_str!("expected/rename_execute_retire_head_n1.vcd") {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
use crate::test_cases::{TestCase, insn_single};
|
||||
use cpu::instruction::{
|
||||
MOpDestReg, MOpRegNum, OutputIntegerMode, ShiftRotateDestLogicOp, ShiftRotateMOp,
|
||||
ShiftRotateMOpImm, ShiftRotateMode,
|
||||
MOpDestReg, MOpRegNum, OutputIntegerMode, ShiftAmountOverflowBehavior, ShiftRotateDestLogicOp,
|
||||
ShiftRotateMOp, ShiftRotateMOpImm, ShiftRotateMode,
|
||||
};
|
||||
use fayalite::prelude::*;
|
||||
|
||||
|
|
@ -18,6 +18,11 @@ fn shift_imm(amount: Option<u8>, shift_right: bool) -> Expr<ShiftRotateMOpImm> {
|
|||
HdlNone()
|
||||
},
|
||||
shift_rotate_right: shift_right,
|
||||
shift_amount_overflow_behavior: if amount.is_some() {
|
||||
ShiftAmountOverflowBehavior.WrapToWidth()
|
||||
} else {
|
||||
ShiftAmountOverflowBehavior.WrapToTwiceWidth()
|
||||
},
|
||||
dest_logic_op: HdlNone(),
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +37,7 @@ fn rotate_imm(
|
|||
ShiftRotateMOpImm {
|
||||
shift_rotate_amount: amount.map(|amount| amount.cast_to_static::<UInt<_>>()),
|
||||
shift_rotate_right: false,
|
||||
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior.WrapToWidth(),
|
||||
dest_logic_op: if let Some((rotated_output_start, rotated_output_len)) =
|
||||
rotated_output_start_and_len
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue