rename_execute_retire: add a head -n1 test

This commit is contained in:
Jacob Lifshay 2026-05-18 22:12:45 -07:00
parent 0d3c41fa14
commit 79ac190093
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
8 changed files with 100223 additions and 3334 deletions

View file

@ -7,8 +7,8 @@ use crate::{
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion, AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg, LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
MOpRegNum, MoveRegMOp, OutputIntegerMode, ReadSpecialMOp, ReadSpecialMOpImm, MOpRegNum, MoveRegMOp, OutputIntegerMode, ReadSpecialMOp, ReadSpecialMOpImm,
ShiftRotateDestLogicOp, ShiftRotateMOp, ShiftRotateMOpImm, ShiftRotateMode, StoreMOp, ShiftAmountOverflowBehavior, ShiftRotateDestLogicOp, ShiftRotateMOp, ShiftRotateMOpImm,
power_isa::PowerIsaSprEnum, ShiftRotateMode, StoreMOp, power_isa::PowerIsaSprEnum,
}, },
powerisa_instructions_xml::{ powerisa_instructions_xml::{
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem, InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
@ -1953,6 +1953,7 @@ impl DecodeState<'_> {
ShiftRotateMOpImm { ShiftRotateMOpImm {
shift_rotate_amount: HdlNone(), shift_rotate_amount: HdlNone(),
shift_rotate_right: false, shift_rotate_right: false,
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior.WrapToWidth(),
dest_logic_op, dest_logic_op,
}, },
OutputIntegerMode.Full64(), OutputIntegerMode.Full64(),
@ -2003,6 +2004,7 @@ impl DecodeState<'_> {
ShiftRotateMOpImm { ShiftRotateMOpImm {
shift_rotate_amount: HdlSome(rotate_amount), shift_rotate_amount: HdlSome(rotate_amount),
shift_rotate_right: false, shift_rotate_right: false,
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior.WrapToWidth(),
dest_logic_op, dest_logic_op,
}, },
OutputIntegerMode.Full64(), OutputIntegerMode.Full64(),
@ -2153,6 +2155,8 @@ impl DecodeState<'_> {
ShiftRotateMOpImm { ShiftRotateMOpImm {
shift_rotate_amount: HdlSome(sh.cast_to_static::<UInt<_>>()), shift_rotate_amount: HdlSome(sh.cast_to_static::<UInt<_>>()),
shift_rotate_right: true, shift_rotate_right: true,
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior
.WrapToWidth(),
dest_logic_op: HdlNone(), dest_logic_op: HdlNone(),
}, },
OutputIntegerMode.Full64(), OutputIntegerMode.Full64(),
@ -2181,6 +2185,8 @@ impl DecodeState<'_> {
ShiftRotateMOpImm { ShiftRotateMOpImm {
shift_rotate_amount: HdlSome(sh.rotate_right(1)), shift_rotate_amount: HdlSome(sh.rotate_right(1)),
shift_rotate_right: true, shift_rotate_right: true,
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior
.WrapToWidth(),
dest_logic_op: HdlNone(), dest_logic_op: HdlNone(),
}, },
OutputIntegerMode.Full64(), OutputIntegerMode.Full64(),
@ -2222,6 +2228,8 @@ impl DecodeState<'_> {
ShiftRotateMOpImm { ShiftRotateMOpImm {
shift_rotate_amount: HdlNone(), shift_rotate_amount: HdlNone(),
shift_rotate_right: is_right_shift, shift_rotate_right: is_right_shift,
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior
.WrapToTwiceWidth(),
dest_logic_op: HdlNone(), dest_logic_op: HdlNone(),
}, },
OutputIntegerMode.Full64(), OutputIntegerMode.Full64(),
@ -2257,6 +2265,8 @@ impl DecodeState<'_> {
ShiftRotateMOpImm { ShiftRotateMOpImm {
shift_rotate_amount: HdlSome(sh.rotate_right(1)), shift_rotate_amount: HdlSome(sh.rotate_right(1)),
shift_rotate_right: false, shift_rotate_right: false,
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior
.WrapToWidth(),
dest_logic_op: HdlNone(), dest_logic_op: HdlNone(),
}, },
OutputIntegerMode.Full64(), OutputIntegerMode.Full64(),

View file

@ -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`]. /// immediate values for [`ShiftRotateMOp`].
#[hdl(cmp_eq, custom_debug(sim))] #[hdl(cmp_eq, custom_debug(sim))]
pub struct ShiftRotateMOpImm { pub struct ShiftRotateMOpImm {
@ -2280,6 +2288,7 @@ pub struct ShiftRotateMOpImm {
pub shift_rotate_amount: HdlOption<UInt<6>>, pub shift_rotate_amount: HdlOption<UInt<6>>,
/// `false` for shift/rotate left, `true` for shift/rotate right /// `false` for shift/rotate left, `true` for shift/rotate right
pub shift_rotate_right: Bool, pub shift_rotate_right: Bool,
pub shift_amount_overflow_behavior: ShiftAmountOverflowBehavior,
pub dest_logic_op: HdlOption<ShiftRotateDestLogicOp>, pub dest_logic_op: HdlOption<ShiftRotateDestLogicOp>,
} }
@ -2289,20 +2298,24 @@ impl SimValueDebug for ShiftRotateMOpImm {
value: &<Self as Type>::SimValue, value: &<Self as Type>::SimValue,
f: &mut fmt::Formatter<'_>, f: &mut fmt::Formatter<'_>,
) -> fmt::Result { ) -> fmt::Result {
type SimValueT<T> = <T as Type>::SimValue; #[hdl(sim)]
let SimValueT::<Self> { let Self {
shift_rotate_amount, shift_rotate_amount,
shift_rotate_right, shift_rotate_right,
shift_amount_overflow_behavior,
dest_logic_op, dest_logic_op,
} = value; } = value;
let shift_op = if **shift_rotate_right { ">>" } else { "<<" }; let shift_op = if **shift_rotate_right { ">>" } else { "<<" };
#[hdl(sim)] #[hdl(sim)]
match shift_rotate_amount { match shift_rotate_amount {
HdlSome(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 => { HdlNone => {
write!(f, "{shift_op}_")?; write!(f, "{shift_op}_, {shift_amount_overflow_behavior:?}")?;
} }
} }
#[hdl(sim)] #[hdl(sim)]

View file

@ -5211,7 +5211,7 @@ $var string 1 vz0q< range $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct memory $end $scope struct memory $end
$var wire 1 sOSum wrote_output $end $var wire 1 @TBV: wrote_outputs $end
$scope struct memory $end $scope struct memory $end
$var string 1 ix'Be \[0] $end $var string 1 ix'Be \[0] $end
$var string 1 H~H-k \[1] $end $var string 1 H~H-k \[1] $end
@ -5254,7 +5254,7 @@ $var string 1 Z;~$o \[3] $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct speculative_memory $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 $scope struct memory $end
$var string 1 :ZBGp \[0] $end $var string 1 :ZBGp \[0] $end
$var string 1 0>Zml \[1] $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 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> b0 >VIL>
sPhantomConst(\"0..=8\") vz0q< sPhantomConst(\"0..=8\") vz0q<
0sOSum 0@TBV:
s<empty> ix'Be s<empty> ix'Be
s<empty> H~H-k s<empty> H~H-k
s<empty> 5u]|o s<empty> 5u]|o
@ -9091,7 +9091,7 @@ sHdlNone )CVUo
sHdlNone [Y*(@ sHdlNone [Y*(@
sHdlNone Krk/@ sHdlNone Krk/@
sHdlNone Z;~$o sHdlNone Z;~$o
0vnbJY 0Kq]85
s<empty> :ZBGp s<empty> :ZBGp
s<empty> 0>Zml s<empty> 0>Zml
s<empty> ZwL}Q s<empty> ZwL}Q
@ -55513,8 +55513,8 @@ b10110011 ,6\L'
0DReB3 0DReB3
sHdlSome\x20(1) -$362 sHdlSome\x20(1) -$362
1*tV+r 1*tV+r
1sOSum 1@TBV:
1vnbJY 1Kq]85
1BqYmm 1BqYmm
#102000000 #102000000
0spsS) 0spsS)

File diff suppressed because it is too large Load diff

View file

@ -5963,7 +5963,7 @@ $var string 1 B}e,9 range $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct memory $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 $scope struct memory $end
$var string 1 >eAWB \[0] $end $var string 1 >eAWB \[0] $end
$var string 1 ;"Eei \[1] $end $var string 1 ;"Eei \[1] $end
@ -6006,7 +6006,7 @@ $var string 1 \C_K@ \[3] $end
$upscope $end $upscope $end
$upscope $end $upscope $end
$scope struct speculative_memory $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 $scope struct memory $end
$var string 1 NDoVs \[0] $end $var string 1 NDoVs \[0] $end
$var string 1 8P[do \[1] $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 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.? b0 {gg.?
sPhantomConst(\"0..=8\") B}e,9 sPhantomConst(\"0..=8\") B}e,9
0AS:f~ 0%s]xe
s<empty> >eAWB s<empty> >eAWB
s<empty> ;"Eei s<empty> ;"Eei
s<empty> KNqbB s<empty> KNqbB
@ -10241,7 +10241,7 @@ sHdlNone sL!o}
sHdlNone (~TAa sHdlNone (~TAa
sHdlNone }L]aR sHdlNone }L]aR
sHdlNone \C_K@ sHdlNone \C_K@
0sdwYO 017-uK
s<empty> NDoVs s<empty> NDoVs
s<empty> 8P[do s<empty> 8P[do
s<empty> Rys^? s<empty> Rys^?
@ -109795,8 +109795,8 @@ b11101010 nTP#.
0{[(D] 0{[(D]
sHdlSome\x20(1) goXwC sHdlSome\x20(1) goXwC
1\O.%q 1\O.%q
1AS:f~ 1%s]xe
1sdwYO 117-uK
1yhGZ] 1yhGZ]
#443000000 #443000000
0spsS) 0spsS)

View file

@ -10,8 +10,9 @@ use cpu::{
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp, AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
CompareMOp, CompareMode, ConditionMode, L2RegNum, L2RegisterFileMOp, LoadMOp, CompareMOp, CompareMode, ConditionMode, L2RegNum, L2RegisterFileMOp, LoadMOp,
LoadStoreCommonMOp, LoadStoreConversion, LoadStoreMOp, LoadStoreWidth, MOp, MOpDestReg, LoadStoreCommonMOp, LoadStoreConversion, LoadStoreMOp, LoadStoreWidth, MOp, MOpDestReg,
MOpRegNum, MOpTrait, MoveRegMOp, OutputIntegerMode, PRegNum, ReadL2RegMOp, StoreMOp, MOpRegNum, MOpTrait, MoveRegMOp, OutputIntegerMode, PRegNum, ReadL2RegMOp,
UnitNum, WriteL2RegMOp, ShiftAmountOverflowBehavior, ShiftRotateDestLogicOp, ShiftRotateMOp, ShiftRotateMOpImm,
ShiftRotateMode, StoreMOp, UnitNum, WriteL2RegMOp,
}, },
next_pc::CallStackOp, next_pc::CallStackOp,
register::{PRegFlags, PRegFlagsPowerISA, PRegValue}, 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) { fn power_isa_bl(&mut self, target: InsnsBuilderLabel) {
let pc = self.pc; let pc = self.pc;
self.add_insn(Insn::new_lazy( 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) { fn power_isa_ld(&mut self, dest: usize, src: usize, disp: i16) {
self.add_insn(Insn::new( self.add_insn(Insn::new(
4, 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) { fn power_isa_std(&mut self, value_src: usize, addr_src: usize, disp: i16) {
self.add_insn(Insn::new( self.add_insn(Insn::new(
4, 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) { fn power_isa_mflr(&mut self, dest: usize) {
self.add_insn(Insn::new( self.add_insn(Insn::new(
4, 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) { fn power_isa_mr(&mut self, dest: usize, src: usize) {
self.add_insn(Insn::new( self.add_insn(Insn::new(
4, 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 { trait MakeInsns {
@ -499,59 +752,6 @@ trait MakeInsns {
fn make_load_store_execution_state() -> MockMemory; 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] #[hdl]
struct BrPredDebugState { struct BrPredDebugState {
call_stack: ArrayVec<UInt<64>, ConstUsize<{ BrPredState::CALL_STACK_CAPACITY }>>, call_stack: ArrayVec<UInt<64>, ConstUsize<{ BrPredState::CALL_STACK_CAPACITY }>>,
@ -1045,7 +1245,7 @@ type SimOnlyMemoryChunk = SimOnly<MemoryChunk>;
#[hdl(no_static)] #[hdl(no_static)]
struct MockMemoryDebugState<C: PhantomConstGet<()> = PhantomConst<()>> { struct MockMemoryDebugState<C: PhantomConstGet<()> = PhantomConst<()>> {
wrote_output: Bool, wrote_outputs: Bool,
memory: ArrayType<SimOnlyMemoryChunk, MockMemoryDebugStateMemorySize<C>>, memory: ArrayType<SimOnlyMemoryChunk, MockMemoryDebugStateMemorySize<C>>,
l1_cache: l1_cache:
Array<TraceAsString<HdlOption<MockCacheLineDebugState>>, { MockMemory::CACHE_LINE_COUNT }>, Array<TraceAsString<HdlOption<MockCacheLineDebugState>>, { MockMemory::CACHE_LINE_COUNT }>,
@ -1053,9 +1253,9 @@ struct MockMemoryDebugState<C: PhantomConstGet<()> = PhantomConst<()>> {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct MockMemory { struct MockMemory {
input: u64, input: std::vec::IntoIter<u64>,
expected_output: u64, expected_output: Vec<u64>,
wrote_output: bool, output: Vec<u64>,
memory: BTreeMap<u64, SimOnlyValue<MemoryChunk>>, memory: BTreeMap<u64, SimOnlyValue<MemoryChunk>>,
l1_cache: [Option<MockCacheLine>; Self::CACHE_LINE_COUNT], l1_cache: [Option<MockCacheLine>; Self::CACHE_LINE_COUNT],
} }
@ -1106,14 +1306,14 @@ impl MockMemory {
const LOG2_CACHE_LINE_COUNT: usize = 2; const LOG2_CACHE_LINE_COUNT: usize = 2;
const CACHE_LINE_COUNT: usize = 1 << Self::LOG2_CACHE_LINE_COUNT; const CACHE_LINE_COUNT: usize = 1 << Self::LOG2_CACHE_LINE_COUNT;
fn new<'a, I: IntoIterator<Item = (u64, &'a [u8])>>( fn new<'a, I: IntoIterator<Item = (u64, &'a [u8])>>(
input: u64, input: Vec<u64>,
expected_output: u64, expected_output: Vec<u64>,
initial_memory: I, initial_memory: I,
) -> Self { ) -> Self {
let mut retval = Self { let mut retval = Self {
input, input: input.into_iter(),
output: Vec::with_capacity(expected_output.len()),
expected_output, expected_output,
wrote_output: false,
memory: BTreeMap::new(), memory: BTreeMap::new(),
l1_cache: [const { None }; _], l1_cache: [const { None }; _],
}; };
@ -1125,6 +1325,11 @@ impl MockMemory {
retval.cache_flush(); retval.cache_flush();
retval 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) { fn cache_flush(&mut self) {
self.l1_cache.fill(None); self.l1_cache.fill(None);
} }
@ -1179,11 +1384,18 @@ impl MockMemory {
} }
Err(FillCacheError::Uncacheable) => { Err(FillCacheError::Uncacheable) => {
assert!(!is_speculative); assert!(!is_speculative);
let mut value = None;
for (chunk_byte_index, byte) in chunk_range.zip(&mut bytes[load_store_range]) { for (chunk_byte_index, byte) in chunk_range.zip(&mut bytes[load_store_range]) {
let offset = chunk_addr let offset = chunk_addr
.wrapping_add(chunk_byte_index as u64) .wrapping_add(chunk_byte_index as u64)
.wrapping_sub(Self::IO_ADDR); .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); assert!(offset < value.len() as u64);
*byte = value[offset as usize]; *byte = value[offset as usize];
} }
@ -1230,11 +1442,16 @@ impl MockMemory {
value[offset as usize] = *byte; value[offset as usize] = *byte;
} }
let value = u64::from_le_bytes(value); let value = u64::from_le_bytes(value);
assert!(
self.output.len() < self.expected_output.len(),
"too many outputs"
);
assert_eq!( assert_eq!(
self.expected_output, value, self.expected_output[self.output.len()],
value,
"output doesn't match expected output" "output doesn't match expected output"
); );
self.wrote_output = true; self.output.push(value);
} }
Err(FillCacheError::CacheMiss) => return Err(AddressCantBeSpeculativelyAccessed), Err(FillCacheError::CacheMiss) => return Err(AddressCantBeSpeculativelyAccessed),
} }
@ -1267,8 +1484,8 @@ impl MockMemory {
fn debug_state(&self) -> SimValue<MockMemoryDebugState> { fn debug_state(&self) -> SimValue<MockMemoryDebugState> {
let Self { let Self {
input: _, input: _,
output: _,
expected_output: _, expected_output: _,
wrote_output,
memory, memory,
l1_cache, l1_cache,
} = self; } = self;
@ -1276,7 +1493,7 @@ impl MockMemory {
let empty_chunk = SimOnlyValue::new(MemoryChunk::default()); let empty_chunk = SimOnlyValue::new(MemoryChunk::default());
#[hdl(sim)] #[hdl(sim)]
MockMemoryDebugState::<_> { MockMemoryDebugState::<_> {
wrote_output, wrote_outputs: self.wrote_outputs(),
memory: SimValue::from_array_elements( memory: SimValue::from_array_elements(
ret_ty.memory, ret_ty.memory,
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 { trait MockExecutionStateTrait: Default {
type DebugState: BundleType; type DebugState: BundleType;
fn debug_state_ty() -> Self::DebugState; fn debug_state_ty() -> Self::DebugState;
@ -1541,6 +1789,188 @@ trait MockExecutionStateTrait: Default {
} }
} }
#[hdl] #[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>( fn run_branch<C: PhantomConstCpuConfig, SrcCount: KnownSize>(
&mut self, &mut self,
id: &SimValue<MOpId>, id: &SimValue<MOpId>,
@ -1582,9 +2012,11 @@ trait MockExecutionStateTrait: Default {
.get(2) .get(2)
.is_some_and(|src2| *src2 != PRegNum[config].const_zero_sim()); .is_some_and(|src2| *src2 != PRegNum[config].const_zero_sim());
let src2_cond = if has_src2 { let src2_cond = if has_src2 {
let _ = invert_src2_eq_zero; if **invert_src2_eq_zero {
let _ = src2; src2.inner().int_fp.as_int() != 0
todo!("has_src2"); } else {
src2.inner().int_fp.as_int() == 0
}
} else { } else {
true true
}; };
@ -1724,9 +2156,10 @@ trait MockExecutionStateTrait: Default {
AluBranchMOp::<_, _>::LogicalI(mop) => { AluBranchMOp::<_, _>::LogicalI(mop) => {
todo!("implement LogicalI") todo!("implement LogicalI")
} }
AluBranchMOp::<_, _>::ShiftRotate(mop) => { AluBranchMOp::<_, _>::ShiftRotate(mop) => (
todo!("implement ShiftRotate") Some((self.run_shift_rotate(mop, src_values), empty_predictor_op())),
} None,
),
AluBranchMOp::<_, _>::Compare(mop) => ( AluBranchMOp::<_, _>::Compare(mop) => (
Some((self.run_compare(mop, src_values), empty_predictor_op())), Some((self.run_compare(mop, src_values), empty_predictor_op())),
None, None,
@ -3367,7 +3800,7 @@ fn mock_load_store_unit<#[hdl(skip)] MI: MakeInsns>(
.await; .await;
} }
sim.write(debug_state, state.debug_state()).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; .await;
sim.wait_for_clock_edge(cd.clk).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] #[hdl]
#[test] #[test]
fn test_rename_execute_retire_fibonacci() { fn test_rename_execute_retire_fibonacci() {
@ -3613,8 +4099,8 @@ impl MakeInsns for SlowLoopInsns {
}); });
let loop_count = 4; let loop_count = 4;
MockMemory::new( MockMemory::new(
loop_count, vec![loop_count],
expected * loop_count * 2u64.pow(Self::LOG2_RESULT_FACTOR), vec![expected * loop_count * 2u64.pow(Self::LOG2_RESULT_FACTOR)],
[(Self::CONSTANTS_ADDR, constants.as_flattened())], [(Self::CONSTANTS_ADDR, constants.as_flattened())],
) )
} }
@ -3674,3 +4160,139 @@ fn test_rename_execute_retire_slow_loop() {
panic!(); 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

View file

@ -3,8 +3,8 @@
use crate::test_cases::{TestCase, insn_single}; use crate::test_cases::{TestCase, insn_single};
use cpu::instruction::{ use cpu::instruction::{
MOpDestReg, MOpRegNum, OutputIntegerMode, ShiftRotateDestLogicOp, ShiftRotateMOp, MOpDestReg, MOpRegNum, OutputIntegerMode, ShiftAmountOverflowBehavior, ShiftRotateDestLogicOp,
ShiftRotateMOpImm, ShiftRotateMode, ShiftRotateMOp, ShiftRotateMOpImm, ShiftRotateMode,
}; };
use fayalite::prelude::*; use fayalite::prelude::*;
@ -18,6 +18,11 @@ fn shift_imm(amount: Option<u8>, shift_right: bool) -> Expr<ShiftRotateMOpImm> {
HdlNone() HdlNone()
}, },
shift_rotate_right: shift_right, shift_rotate_right: shift_right,
shift_amount_overflow_behavior: if amount.is_some() {
ShiftAmountOverflowBehavior.WrapToWidth()
} else {
ShiftAmountOverflowBehavior.WrapToTwiceWidth()
},
dest_logic_op: HdlNone(), dest_logic_op: HdlNone(),
} }
} }
@ -32,6 +37,7 @@ fn rotate_imm(
ShiftRotateMOpImm { ShiftRotateMOpImm {
shift_rotate_amount: amount.map(|amount| amount.cast_to_static::<UInt<_>>()), shift_rotate_amount: amount.map(|amount| amount.cast_to_static::<UInt<_>>()),
shift_rotate_right: false, shift_rotate_right: false,
shift_amount_overflow_behavior: ShiftAmountOverflowBehavior.WrapToWidth(),
dest_logic_op: if let Some((rotated_output_start, rotated_output_len)) = dest_logic_op: if let Some((rotated_output_start, rotated_output_len)) =
rotated_output_start_and_len rotated_output_start_and_len
{ {