Compare commits

..

No commits in common. "decode-and-test-harness" and "master" have entirely different histories.

24 changed files with 89716 additions and 34106 deletions

8
Cargo.lock generated
View file

@ -388,7 +388,7 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
[[package]] [[package]]
name = "fayalite" name = "fayalite"
version = "0.3.0" version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#ffca1a279d79507c025a8d969bfff18295760c02" source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cf3e6cfc6bc33eebf2d2862c7a1948b9cf40ecac"
dependencies = [ dependencies = [
"base64", "base64",
"bitvec", "bitvec",
@ -417,7 +417,7 @@ dependencies = [
[[package]] [[package]]
name = "fayalite-proc-macros" name = "fayalite-proc-macros"
version = "0.3.0" version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#ffca1a279d79507c025a8d969bfff18295760c02" source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cf3e6cfc6bc33eebf2d2862c7a1948b9cf40ecac"
dependencies = [ dependencies = [
"fayalite-proc-macros-impl", "fayalite-proc-macros-impl",
] ]
@ -425,7 +425,7 @@ dependencies = [
[[package]] [[package]]
name = "fayalite-proc-macros-impl" name = "fayalite-proc-macros-impl"
version = "0.3.0" version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#ffca1a279d79507c025a8d969bfff18295760c02" source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cf3e6cfc6bc33eebf2d2862c7a1948b9cf40ecac"
dependencies = [ dependencies = [
"base16ct 0.2.0", "base16ct 0.2.0",
"num-bigint", "num-bigint",
@ -440,7 +440,7 @@ dependencies = [
[[package]] [[package]]
name = "fayalite-visit-gen" name = "fayalite-visit-gen"
version = "0.3.0" version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#ffca1a279d79507c025a8d969bfff18295760c02" source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cf3e6cfc6bc33eebf2d2862c7a1948b9cf40ecac"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"prettyplease", "prettyplease",

View file

@ -16,7 +16,6 @@ use crate::{
register::{ register::{
PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, ViewUnused, PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, ViewUnused,
}, },
test::decode_and_run_single_insn::{DecodeOneInsn, DecodeOneInsnOutput},
util::{ util::{
Rotate, Rotate,
array_vec::{ArrayVec, Length}, array_vec::{ArrayVec, Length},
@ -139,11 +138,10 @@ struct DecodeState<'a> {
conditions: Option<&'static str>, conditions: Option<&'static str>,
header: &'static crate::powerisa_instructions_xml::InstructionHeader, header: &'static crate::powerisa_instructions_xml::InstructionHeader,
insn: &'static crate::powerisa_instructions_xml::Instruction, insn: &'static crate::powerisa_instructions_xml::Instruction,
output: Expr<ArrayVec<TraceAsString<MOp>, ConstUsize<3>>>, output: Expr<ArrayVec<MOp, ConstUsize<3>>>,
is_illegal: Expr<Bool>, is_illegal: Expr<Bool>,
first_input: Expr<UInt<32>>, first_input: Expr<UInt<32>>,
has_second_input: Expr<Bool>, second_input: Expr<HdlOption<UInt<32>>>,
second_input_value: Expr<UInt<32>>,
second_input_used: Expr<Bool>, second_input_used: Expr<Bool>,
field_wires: &'a mut HashMap<String, HashMap<Expr<UInt>, Expr<UInt>>>, field_wires: &'a mut HashMap<String, HashMap<Expr<UInt>, Expr<UInt>>>,
} }
@ -430,9 +428,10 @@ impl DecodeState<'_> {
Entry::Occupied(entry) => *entry.get(), Entry::Occupied(entry) => *entry.get(),
} }
} }
#[hdl]
fn decode_word( fn decode_word(
&mut self, &mut self,
matches: &mut Option<Expr<Bool>>, matches: &mut Expr<Bool>,
fields: &mut BTreeMap<&'static str, Expr<UInt>>, fields: &mut BTreeMap<&'static str, Expr<UInt>>,
word: Expr<UInt<32>>, word: Expr<UInt<32>>,
fields_inner: &'static InstructionBitFieldsInner, fields_inner: &'static InstructionBitFieldsInner,
@ -525,10 +524,7 @@ impl DecodeState<'_> {
} }
} else { } else {
let value: u32 = name.parse().expect("bit field name must have at least one letter, be all `/`, or be a valid decimal number"); let value: u32 = name.parse().expect("bit field name must have at least one letter, be all `/`, or be a valid decimal number");
*matches = match *matches { *matches = *matches & field.cmp_eq(value);
Some(matches) => Some(matches & field.cmp_eq(value)),
None => Some(field.cmp_eq(value)),
};
if orig_name.contains(char::is_alphabetic) { if orig_name.contains(char::is_alphabetic) {
if fields if fields
.insert(orig_name, value.cast_to(field.ty()).to_expr()) .insert(orig_name, value.cast_to(field.ty()).to_expr())
@ -540,19 +536,20 @@ impl DecodeState<'_> {
} }
} }
} }
#[hdl]
#[track_caller] #[track_caller]
fn decode_scope<FS: FieldSet, F: FnOnce(&mut Self, FS)>(&mut self, f: F) { fn decode_scope<FS: FieldSet, F: FnOnce(&mut Self, FS)>(&mut self, f: F) {
let mut fields = BTreeMap::new(); let mut fields = BTreeMap::new();
let mut matches = true.to_expr();
let mut f = Some(f); let mut f = Some(f);
#[hdl] #[hdl]
#[track_caller] #[track_caller]
fn run<'a, FS: FieldSet, F: FnOnce(&mut DecodeState<'a>, FS)>( fn run<'a, FS: FieldSet, F: FnOnce(&mut DecodeState<'a>, FS)>(
this: &mut DecodeState<'a>, this: &mut DecodeState<'a>,
matches: Option<Expr<Bool>>, matches: Expr<Bool>,
fields: &mut BTreeMap<&str, Expr<UInt>>, fields: &mut BTreeMap<&str, Expr<UInt>>,
f: &mut Option<F>, f: &mut Option<F>,
) { ) {
let matches = matches.expect("matches is known to be Some");
#[hdl] #[hdl]
if matches { if matches {
connect( connect(
@ -564,22 +561,23 @@ impl DecodeState<'_> {
} }
} }
if let Some(prefix) = self.header.bit_fields().prefix() { if let Some(prefix) = self.header.bit_fields().prefix() {
let mut matches = Some(self.has_second_input); #[hdl]
self.decode_word( if let HdlSome(suffix_word) = self.second_input {
&mut matches, self.decode_word(
&mut fields, &mut matches,
self.first_input, &mut fields,
prefix.fields_inner(), self.first_input,
); prefix.fields_inner(),
self.decode_word( );
&mut matches, self.decode_word(
&mut fields, &mut matches,
self.second_input_value, &mut fields,
self.header.bit_fields().fields_inner(), suffix_word,
); self.header.bit_fields().fields_inner(),
run(self, matches, &mut fields, &mut f); );
run(self, matches, &mut fields, &mut f);
}
} else { } else {
let mut matches = None;
self.decode_word( self.decode_word(
&mut matches, &mut matches,
&mut fields, &mut fields,
@ -596,7 +594,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
BranchMOp::branch_i( BranchMOp::branch_i(
MOpDestReg::new( MOpDestReg::new(
[if this.mnemonic.contains('l') { [if this.mnemonic.contains('l') {
@ -637,7 +635,7 @@ impl DecodeState<'_> {
let no_cr_bit = bo[4]; // BO_0 in specification let no_cr_bit = bo[4]; // BO_0 in specification
let (cr_field, condition_mode) = cr_bit_cond(bi); let (cr_field, condition_mode) = cr_bit_cond(bi);
#[hdl] #[hdl]
let branch_mop: TraceAsString<MOp> = wire(); let branch_mop = wire();
#[hdl] #[hdl]
let branch_lr_dest_reg = wire(); let branch_lr_dest_reg = wire();
connect(branch_lr_dest_reg, MOpRegNum::const_zero()); connect(branch_lr_dest_reg, MOpRegNum::const_zero());
@ -658,7 +656,7 @@ impl DecodeState<'_> {
#[hdl] #[hdl]
if no_ctr & no_cr_bit { if no_ctr & no_cr_bit {
connect( connect(
*branch_mop, branch_mop,
BranchMOp::branch_i( BranchMOp::branch_i(
dest, dest,
[MOpRegNum::const_zero(), src1], [MOpRegNum::const_zero(), src1],
@ -670,7 +668,7 @@ impl DecodeState<'_> {
); );
} else if no_cr_bit { } else if no_cr_bit {
connect( connect(
*branch_mop, branch_mop,
BranchMOp::branch_ctr( BranchMOp::branch_ctr(
dest, dest,
[MOpRegNum::const_zero(), src1, branch_ctr_reg], [MOpRegNum::const_zero(), src1, branch_ctr_reg],
@ -683,7 +681,7 @@ impl DecodeState<'_> {
); );
} else { } else {
connect( connect(
*branch_mop, branch_mop,
BranchMOp::branch_cond_ctr( BranchMOp::branch_cond_ctr(
dest, dest,
[cr_field, src1, branch_ctr_reg], [cr_field, src1, branch_ctr_reg],
@ -711,7 +709,7 @@ impl DecodeState<'_> {
2usize.cast_to_static::<Length<_>>(), 2usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []), MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []),
[MOpRegNum::power_isa_ctr_reg(), MOpRegNum::const_zero()], [MOpRegNum::power_isa_ctr_reg(), MOpRegNum::const_zero()],
@ -784,7 +782,7 @@ impl DecodeState<'_> {
- bt_flag_index.cast_to(uint_ty)) - bt_flag_index.cast_to(uint_ty))
% PRegFlags::FLAG_COUNT; % PRegFlags::FLAG_COUNT;
connect( connect(
*this.output[0], this.output[0],
LogicalFlagsMOp::logical_flags( LogicalFlagsMOp::logical_flags(
MOpDestReg::new([bt_reg], []), MOpDestReg::new([bt_reg], []),
[ba_reg, bb_reg, bt_reg], [ba_reg, bb_reg, bt_reg],
@ -810,7 +808,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
MoveRegMOp::move_reg( MoveRegMOp::move_reg(
MOpDestReg::new([crf(bf)], []), MOpDestReg::new([crf(bf)], []),
[crf(bfa)], [crf(bfa)],
@ -887,7 +885,7 @@ impl DecodeState<'_> {
#[hdl] #[hdl]
if r { if r {
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new([ea_reg], []), MOpDestReg::new([ea_reg], []),
[MOpRegNum::const_zero(); 2], [MOpRegNum::const_zero(); 2],
@ -901,7 +899,7 @@ impl DecodeState<'_> {
); );
} else { } else {
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new([ea_reg], []), MOpDestReg::new([ea_reg], []),
[gpr_or_zero(ra), MOpRegNum::const_zero()], [gpr_or_zero(ra), MOpRegNum::const_zero()],
@ -915,7 +913,7 @@ impl DecodeState<'_> {
); );
} }
connect( connect(
*this.output[1], this.output[1],
LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion), LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion),
); );
}, },
@ -929,7 +927,7 @@ impl DecodeState<'_> {
); );
let ea_reg = ea_reg(ra); let ea_reg = ea_reg(ra);
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new([ea_reg], []), MOpDestReg::new([ea_reg], []),
[gpr_or_zero(ra), gpr(rb)], [gpr_or_zero(ra), gpr(rb)],
@ -942,7 +940,7 @@ impl DecodeState<'_> {
), ),
); );
connect( connect(
*this.output[1], this.output[1],
LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion), LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion),
); );
}); });
@ -954,7 +952,7 @@ impl DecodeState<'_> {
); );
let ea_reg = ea_reg(ra); let ea_reg = ea_reg(ra);
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new([ea_reg], []), MOpDestReg::new([ea_reg], []),
[gpr_or_zero(ra), MOpRegNum::const_zero()], [gpr_or_zero(ra), MOpRegNum::const_zero()],
@ -967,7 +965,7 @@ impl DecodeState<'_> {
), ),
); );
connect( connect(
*this.output[1], this.output[1],
LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion), LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion),
); );
}); });
@ -985,7 +983,7 @@ impl DecodeState<'_> {
); );
let ea_reg = ea_reg(ra); let ea_reg = ea_reg(ra);
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new([ea_reg], []), MOpDestReg::new([ea_reg], []),
[gpr_or_zero(ra), MOpRegNum::const_zero()], [gpr_or_zero(ra), MOpRegNum::const_zero()],
@ -998,7 +996,7 @@ impl DecodeState<'_> {
), ),
); );
connect( connect(
*this.output[1], this.output[1],
LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion), LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion),
); );
}); });
@ -1065,9 +1063,9 @@ impl DecodeState<'_> {
} else { } else {
(MOpRegNum::power_isa_temp_reg(), false.to_expr()) (MOpRegNum::power_isa_temp_reg(), false.to_expr())
}; };
write_compute_ea_insn(*this.output[0], ea_reg); write_compute_ea_insn(this.output[0], ea_reg);
connect( connect(
*this.output[1], this.output[1],
StoreMOp::store( StoreMOp::store(
MOpDestReg::new([], []), MOpDestReg::new([], []),
[ea_reg, gpr(rs)], [ea_reg, gpr(rs)],
@ -1082,7 +1080,7 @@ impl DecodeState<'_> {
3usize.cast_to_static::<Length<_>>(), 3usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[2], this.output[2],
MoveRegMOp::move_reg( MoveRegMOp::move_reg(
MOpDestReg::new([gpr(ra)], []), MOpDestReg::new([gpr(ra)], []),
[ea_reg], [ea_reg],
@ -1204,7 +1202,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new([gpr(rt)], []), MOpDestReg::new([gpr(rt)], []),
#[hdl] #[hdl]
@ -1227,7 +1225,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new([gpr(rt)], []), MOpDestReg::new([gpr(rt)], []),
#[hdl] #[hdl]
@ -1254,7 +1252,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new([gpr(rt)], []), MOpDestReg::new([gpr(rt)], []),
#[hdl] #[hdl]
@ -1281,7 +1279,7 @@ impl DecodeState<'_> {
+ (d1 << 1).cast_to_static::<SInt<16>>() + (d1 << 1).cast_to_static::<SInt<16>>()
+ d2.cast_to_static::<SInt<16>>(); + d2.cast_to_static::<SInt<16>>();
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new([gpr(rt)], []), MOpDestReg::new([gpr(rt)], []),
#[hdl] #[hdl]
@ -1308,7 +1306,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new( MOpDestReg::new(
[gpr(rt)], [gpr(rt)],
@ -1339,7 +1337,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new( MOpDestReg::new(
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()], [gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
@ -1371,7 +1369,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new( MOpDestReg::new(
[ [
@ -1408,7 +1406,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new( MOpDestReg::new(
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()], [gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
@ -1440,7 +1438,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new( MOpDestReg::new(
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()], [gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
@ -1473,7 +1471,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new( MOpDestReg::new(
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()], [gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
@ -1506,7 +1504,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new( MOpDestReg::new(
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()], [gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
@ -1539,7 +1537,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new( MOpDestReg::new(
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()], [gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
@ -1577,7 +1575,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new( MOpDestReg::new(
[gpr(rt)], [gpr(rt)],
@ -1617,7 +1615,7 @@ impl DecodeState<'_> {
connect(compare_mode, CompareMode.S32()); connect(compare_mode, CompareMode.S32());
} }
connect( connect(
*this.output[0], this.output[0],
CompareMOp::compare_i( CompareMOp::compare_i(
MOpDestReg::new([crf(bf)], []), MOpDestReg::new([crf(bf)], []),
[gpr(ra)], [gpr(ra)],
@ -1645,7 +1643,7 @@ impl DecodeState<'_> {
connect(compare_mode, CompareMode.S32()); connect(compare_mode, CompareMode.S32());
} }
connect( connect(
*this.output[0], this.output[0],
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new([crf(bf)], []), MOpDestReg::new([crf(bf)], []),
[gpr(ra), gpr(rb)], [gpr(ra), gpr(rb)],
@ -1672,7 +1670,7 @@ impl DecodeState<'_> {
connect(compare_mode, CompareMode.U32()); connect(compare_mode, CompareMode.U32());
} }
connect( connect(
*this.output[0], this.output[0],
CompareMOp::compare_i( CompareMOp::compare_i(
MOpDestReg::new([crf(bf)], []), MOpDestReg::new([crf(bf)], []),
[gpr(ra)], [gpr(ra)],
@ -1700,7 +1698,7 @@ impl DecodeState<'_> {
connect(compare_mode, CompareMode.U32()); connect(compare_mode, CompareMode.U32());
} }
connect( connect(
*this.output[0], this.output[0],
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new([crf(bf)], []), MOpDestReg::new([crf(bf)], []),
[gpr(ra), gpr(rb)], [gpr(ra), gpr(rb)],
@ -1727,7 +1725,7 @@ impl DecodeState<'_> {
connect(compare_mode, CompareMode.CmpRBOne()); connect(compare_mode, CompareMode.CmpRBOne());
} }
connect( connect(
*this.output[0], this.output[0],
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new([crf(bf)], []), MOpDestReg::new([crf(bf)], []),
[gpr(ra), gpr(rb)], [gpr(ra), gpr(rb)],
@ -1746,7 +1744,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new([crf(bf)], []), MOpDestReg::new([crf(bf)], []),
[gpr(ra), gpr(rb)], [gpr(ra), gpr(rb)],
@ -1772,7 +1770,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
LogicalMOp::logical_i( LogicalMOp::logical_i(
MOpDestReg::new( MOpDestReg::new(
[gpr(ra)], [gpr(ra)],
@ -1826,7 +1824,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
LogicalMOp::logical( LogicalMOp::logical(
MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]), MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]),
[gpr(rs), gpr(rb)], [gpr(rs), gpr(rb)],
@ -1840,7 +1838,7 @@ impl DecodeState<'_> {
if rs.reg_num.cmp_eq(rb.reg_num) & !rc { if rs.reg_num.cmp_eq(rb.reg_num) & !rc {
// found `mr` // found `mr`
connect( connect(
*this.output[0], this.output[0],
MoveRegMOp::move_reg( MoveRegMOp::move_reg(
MOpDestReg::new([gpr(ra)], []), MOpDestReg::new([gpr(ra)], []),
[gpr(rs)], [gpr(rs)],
@ -1869,7 +1867,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
LogicalMOp::logical_i( LogicalMOp::logical_i(
MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]), MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]),
[gpr(rs)], [gpr(rs)],
@ -1947,7 +1945,7 @@ impl DecodeState<'_> {
); );
let dest_logic_op = self.rotate_dest_logic_op(msb0_mask_begin, msb0_mask_end, false); let dest_logic_op = self.rotate_dest_logic_op(msb0_mask_begin, msb0_mask_end, false);
connect( connect(
*self.output[0], self.output[0],
ShiftRotateMOp::shift_rotate( ShiftRotateMOp::shift_rotate(
MOpDestReg::new([gpr(ra.0)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc.0)]), MOpDestReg::new([gpr(ra.0)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc.0)]),
[gpr(rs.0), gpr(rs.0), gpr(rb.0)], [gpr(rs.0), gpr(rs.0), gpr(rb.0)],
@ -2006,7 +2004,7 @@ impl DecodeState<'_> {
} }
} }
connect( connect(
*self.output[0], self.output[0],
ShiftRotateMOp::shift_rotate( ShiftRotateMOp::shift_rotate(
MOpDestReg::new([gpr(ra.0)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc.0)]), MOpDestReg::new([gpr(ra.0)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc.0)]),
[gpr(rs.0), gpr(rs.0), rotate_imm_src2], [gpr(rs.0), gpr(rs.0), rotate_imm_src2],
@ -2158,7 +2156,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
ShiftRotateMOp::shift_rotate( ShiftRotateMOp::shift_rotate(
MOpDestReg::new( MOpDestReg::new(
[gpr(ra), MOpRegNum::power_isa_xer_ca_ca32_reg()], [gpr(ra), MOpRegNum::power_isa_xer_ca_ca32_reg()],
@ -2188,7 +2186,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
ShiftRotateMOp::shift_rotate( ShiftRotateMOp::shift_rotate(
MOpDestReg::new( MOpDestReg::new(
[gpr(ra), MOpRegNum::power_isa_xer_ca_ca32_reg()], [gpr(ra), MOpRegNum::power_isa_xer_ca_ca32_reg()],
@ -2220,7 +2218,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
ShiftRotateMOp::shift_rotate( ShiftRotateMOp::shift_rotate(
MOpDestReg::new( MOpDestReg::new(
[ [
@ -2282,7 +2280,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
ShiftRotateMOp::shift_rotate( ShiftRotateMOp::shift_rotate(
MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]), MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]),
[gpr(rs), MOpRegNum::const_zero(), MOpRegNum::const_zero()], [gpr(rs), MOpRegNum::const_zero(), MOpRegNum::const_zero()],
@ -2314,7 +2312,7 @@ impl DecodeState<'_> {
); );
if is_write_to_spr { if is_write_to_spr {
connect( connect(
*self.output[0], self.output[0],
MoveRegMOp::move_reg( MoveRegMOp::move_reg(
MOpDestReg::new([spr], []), MOpDestReg::new([spr], []),
[gpr(reg)], [gpr(reg)],
@ -2323,7 +2321,7 @@ impl DecodeState<'_> {
); );
} else { } else {
connect( connect(
*self.output[0], self.output[0],
MoveRegMOp::move_reg( MoveRegMOp::move_reg(
MOpDestReg::new([gpr(reg)], []), MOpDestReg::new([gpr(reg)], []),
[spr], [spr],
@ -2339,7 +2337,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*self.output[0], self.output[0],
ReadSpecialMOp::read_special( ReadSpecialMOp::read_special(
MOpDestReg::new([gpr(reg)], []), MOpDestReg::new([gpr(reg)], []),
[MOpRegNum::const_zero(); 0], [MOpRegNum::const_zero(); 0],
@ -2414,7 +2412,7 @@ impl DecodeState<'_> {
1usize.cast_to_static::<Length<_>>(), 1usize.cast_to_static::<Length<_>>(),
); );
connect( connect(
*this.output[0], this.output[0],
LogicalFlagsMOp::logical_flags( LogicalFlagsMOp::logical_flags(
MOpDestReg::new([crf(bf)], []), MOpDestReg::new([crf(bf)], []),
[ [
@ -2743,12 +2741,10 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
), ),
]; ];
const MAX_MOPS_PER_INSN: usize = 3;
#[hdl_module] #[hdl_module]
pub fn decode_one_insn() { pub fn decode_one_insn() {
#[hdl] #[hdl]
let output: ArrayVec<TraceAsString<MOp>, ConstUsize<{ MAX_MOPS_PER_INSN }>> = m.output(); let output: ArrayVec<MOp, ConstUsize<3>> = m.output();
#[hdl] #[hdl]
let is_illegal: Bool = m.output(); let is_illegal: Bool = m.output();
#[hdl] #[hdl]
@ -2762,20 +2758,6 @@ pub fn decode_one_insn() {
connect(second_input_used, false); connect(second_input_used, false);
connect(is_illegal, true); connect(is_illegal, true);
#[hdl]
let has_second_input = wire();
#[hdl]
let second_input_value = wire();
#[hdl]
if let HdlSome(second_input) = second_input {
connect(has_second_input, true);
connect(second_input_value, second_input);
} else {
connect(has_second_input, false);
connect(second_input_value, 0u32);
}
let mut decode_fns = BTreeMap::new(); let mut decode_fns = BTreeMap::new();
for &(mnemonics, decode_fn) in DECODE_FNS { for &(mnemonics, decode_fn) in DECODE_FNS {
for &mnemonic in mnemonics { for &mnemonic in mnemonics {
@ -2825,8 +2807,7 @@ pub fn decode_one_insn() {
output, output,
is_illegal, is_illegal,
first_input, first_input,
has_second_input, second_input,
second_input_value,
second_input_used, second_input_used,
field_wires: &mut field_wires, field_wires: &mut field_wires,
}); });
@ -2835,49 +2816,6 @@ pub fn decode_one_insn() {
} }
} }
impl DecodeOneInsn for decode_one_insn {
type Input = (UInt<32>, HdlOption<UInt<32>>);
fn input_ty(self) -> Self::Input {
StaticType::TYPE
}
type MaxMOpCount = ConstUsize<{ MAX_MOPS_PER_INSN }>;
fn max_mop_count(self) -> <Self::MaxMOpCount as Size>::SizeType {
ConstUsize
}
#[hdl]
fn connect_io(
this: Expr<Self>,
input: Expr<Self::Input>,
output: Expr<DecodeOneInsnOutput<Self::MaxMOpCount>>,
) {
#[hdl]
let (first_input, second_input) = input;
connect(this.first_input, first_input);
connect(this.second_input, second_input);
#[hdl]
let size_in_bytes = wire();
#[hdl]
if this.second_input_used {
connect(size_in_bytes, 8_hdl_u4);
} else {
connect(size_in_bytes, 4_hdl_u4);
}
connect(
output,
#[hdl]
DecodeOneInsnOutput::<_> {
mops: this.output,
size_in_bytes,
is_illegal: this.is_illegal,
},
);
}
}
#[hdl_module] #[hdl_module]
pub fn simple_power_isa_decoder(config: PhantomConst<CpuConfig>) { pub fn simple_power_isa_decoder(config: PhantomConst<CpuConfig>) {
todo!() todo!()

View file

@ -115,7 +115,7 @@ pub trait MOpTrait: Type {
input: &mut SimValue<Self>, input: &mut SimValue<Self>,
f: &mut impl FnMut(&mut SimValue<Self::SrcReg>, usize), f: &mut impl FnMut(&mut SimValue<Self::SrcReg>, usize),
); );
fn connect_to_src_regs( fn connect_src_regs(
input: impl ToExpr<Type = Self>, input: impl ToExpr<Type = Self>,
src_regs: impl ToExpr<Type = Array<Self::SrcReg, { COMMON_MOP_SRC_LEN }>>, src_regs: impl ToExpr<Type = Array<Self::SrcReg, { COMMON_MOP_SRC_LEN }>>,
) { ) {

View file

@ -11,6 +11,5 @@ pub mod powerisa_instructions_xml;
pub mod reg_alloc; pub mod reg_alloc;
pub mod register; pub mod register;
pub mod rename_execute_retire; pub mod rename_execute_retire;
pub mod test;
pub mod unit; pub mod unit;
pub mod util; pub mod util;

View file

@ -106,7 +106,7 @@ pub struct WipDecodedInsn {
pub kind: WipDecodedInsnKind, pub kind: WipDecodedInsnKind,
} }
#[hdl(cmp_eq)] #[hdl]
pub enum CallStackOp { pub enum CallStackOp {
None, None,
Push(UInt<64>), Push(UInt<64>),

View file

@ -13,7 +13,7 @@ use crate::{
COMMON_MOP_SRC_LEN, L2RegNum, MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, ReadL2RegMOp, COMMON_MOP_SRC_LEN, L2RegNum, MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, ReadL2RegMOp,
UnitNum, UnitOutRegNum, WriteL2RegMOp, UnitNum, UnitOutRegNum, WriteL2RegMOp,
}, },
next_pc::{CallStackOp, FETCH_BLOCK_ID_WIDTH, SimValueDefault}, next_pc::{CallStackOp, SimValueDefault},
register::{FlagsMode, PRegFlagsPowerISA, PRegValue}, register::{FlagsMode, PRegFlagsPowerISA, PRegValue},
rename_execute_retire::{ rename_execute_retire::{
rename_table::{RenameTable, RenameTableDebugState, RenameTableEntry, RenameTableUpdate}, rename_table::{RenameTable, RenameTableDebugState, RenameTableEntry, RenameTableUpdate},
@ -42,7 +42,7 @@ pub type MOpId = UInt<{ MOP_ID_WIDTH }>;
#[hdl(custom_debug(sim))] #[hdl(custom_debug(sim))]
/// A &micro;Op along with the state needed for this instance of the &micro;Op. /// A &micro;Op along with the state needed for this instance of the &micro;Op.
pub struct MOpInstance<MOp> { pub struct MOpInstance<MOp> {
pub fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>, pub fetch_block_id: UInt<8>,
pub id: MOpId, pub id: MOpId,
pub pc: UInt<64>, pub pc: UInt<64>,
/// initialized to 0 by decoder, overwritten by `next_pc()` /// initialized to 0 by decoder, overwritten by `next_pc()`
@ -217,7 +217,6 @@ pub struct UnitMOpCantCauseCancel<C: PhantomConstGet<CpuConfig>> {
pub struct ExecuteToUnitInterface<C: PhantomConstGet<CpuConfig>> { pub struct ExecuteToUnitInterface<C: PhantomConstGet<CpuConfig>> {
pub global_state: GlobalState, pub global_state: GlobalState,
/// Enqueues happen in program order, they are not re-ordered by out-of-order execution. /// Enqueues happen in program order, they are not re-ordered by out-of-order execution.
/// if [`Self::unit_outputs_ready`] is `false`, then `enqueue.data` is always [`HdlNone`].
pub enqueue: ReadyValid<UnitEnqueue<C>>, pub enqueue: ReadyValid<UnitEnqueue<C>>,
/// if [`Self::unit_outputs_ready`] is `false`, then this is always [`HdlNone`] /// if [`Self::unit_outputs_ready`] is `false`, then this is always [`HdlNone`]
pub inputs_ready: HdlOption<UnitInputsReady<C>>, pub inputs_ready: HdlOption<UnitInputsReady<C>>,

View file

@ -1,15 +1,11 @@
// SPDX-License-Identifier: LGPL-3.0-or-later // SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information // See Notices.txt for copyright information
use crate::{ use crate::{config::CpuConfig, rename_execute_retire::ExecuteToUnitInterface};
config::{CpuConfig, CpuConfigUnitCount},
rename_execute_retire::ExecuteToUnitInterface,
};
use fayalite::{ use fayalite::{
bundle::{BundleField, BundleType, NoBuilder}, bundle::{BundleField, BundleType, NoBuilder},
expr::ops::FieldAccess, expr::ops::FieldAccess,
intern::{Intern, Interned, Memoize}, intern::{Intern, Interned, Memoize},
module::{connect_with_loc, wire_with_loc},
prelude::*, prelude::*,
ty::{ ty::{
OpaqueSimValue, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, OpaqueSimValue, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
@ -106,42 +102,6 @@ impl<C: Type + PhantomConstGet<CpuConfig>> ExecuteToUnitInterfaces<C> {
} }
MyMemoize(PhantomData).get_owned(this.to_expr()) MyMemoize(PhantomData).get_owned(this.to_expr())
} }
#[track_caller]
pub fn unit_fields_as_array_wire_with_loc(
this: impl ToExpr<Type = Self>,
wire_name: &str,
source_location: SourceLocation,
array_wire_is_dest: bool,
) -> Expr<ArrayType<ExecuteToUnitInterface<C>, CpuConfigUnitCount<C>>> {
let this = this.to_expr();
let config = this.ty().config;
let array_wire = wire_with_loc(
wire_name,
source_location,
ArrayType[ExecuteToUnitInterface[config]][CpuConfigUnitCount[config]],
);
for (unit_field, array_element) in Self::unit_fields(this).into_iter().zip(array_wire) {
if array_wire_is_dest {
connect_with_loc(array_element, unit_field, source_location);
} else {
connect_with_loc(unit_field, array_element, source_location);
}
}
array_wire
}
#[track_caller]
pub fn unit_fields_as_array_wire(
this: impl ToExpr<Type = Self>,
wire_name: &str,
array_wire_is_dest: bool,
) -> Expr<ArrayType<ExecuteToUnitInterface<C>, CpuConfigUnitCount<C>>> {
Self::unit_fields_as_array_wire_with_loc(
this,
wire_name,
SourceLocation::caller(),
array_wire_is_dest,
)
}
} }
#[doc(hidden)] #[doc(hidden)]

View file

@ -1,4 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
pub mod decode_and_run_single_insn;

View file

@ -1,952 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
config::{CpuConfig, CpuConfigUnitCount, PhantomConstCpuConfig},
instruction::{
COMMON_MOP_SRC_LEN, MOp, MOpDestReg, MOpRegNum, MOpTrait, MoveRegMOp, PRegNum, UnitNum,
UnitOutRegNum,
},
next_pc::{CallStackOp, FETCH_BLOCK_ID_WIDTH},
register::PRegValue,
rename_execute_retire::{
ExecuteToUnitInterface, GlobalState, MOpId, MOpInstance, NextPcPredictorOp, RenamedMOp,
UnitCausedCancel, UnitEnqueue, UnitFinishCauseCancel, UnitInputsReady,
UnitMOpIsNoLongerSpeculative, UnitOutputReady, to_unit_interfaces::ExecuteToUnitInterfaces,
},
unit::{HdlUnitKind, UnitMOp},
util::array_vec::ArrayVec,
};
use fayalite::{
bundle::BundleType,
int::UIntInRangeType,
intern::{Intern, Interned},
module::wire_with_loc,
prelude::*,
util::{prefix_sum::reduce, ready_valid::ReadyValid},
};
/// make arrays dynamically-sized to avoid putting large types on the stack
#[hdl(get(|c| 1 << MOpRegNum::WIDTH))]
type MOpRegCount<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(cmp_eq, no_static)]
pub struct Registers<C: PhantomConstGet<CpuConfig>> {
pub regs: ArrayType<TraceAsString<PRegValue>, MOpRegCount<C>>,
pub config: C,
}
impl<C: PhantomConstCpuConfig> Registers<C> {
#[hdl]
pub fn zeroed(self) -> Expr<Self> {
#[hdl]
Self {
regs: repeat(PRegValue::zeroed().into_trace_as_string(), self.regs.len()),
config: self.config,
}
}
#[hdl]
pub fn zeroed_sim(self) -> SimValue<Self> {
#[hdl(sim)]
Self {
regs: vec![PRegValue::zeroed_sim().into_trace_as_string(); self.regs.len()],
config: self.config,
}
}
}
#[hdl(no_static)]
pub struct DecodeOneInsnOutput<MaxMOpCount: Size> {
pub mops: ArrayVec<TraceAsString<MOp>, MaxMOpCount>,
pub size_in_bytes: UInt<4>,
pub is_illegal: Bool,
}
pub trait DecodeOneInsn: BundleType {
type Input: Type;
fn input_ty(self) -> Self::Input;
type MaxMOpCount: Size;
fn max_mop_count(self) -> <Self::MaxMOpCount as Size>::SizeType;
fn connect_io(
this: Expr<Self>,
input: Expr<Self::Input>,
output: Expr<DecodeOneInsnOutput<Self::MaxMOpCount>>,
);
}
pub type DecodeOneInsnInput<T> = <T as DecodeOneInsn>::Input;
#[doc(hidden)]
#[expect(non_upper_case_globals)]
pub const DecodeOneInsnInput: DecodeOneInsnInputWithoutGenerics =
DecodeOneInsnInputWithoutGenerics {};
#[doc(hidden)]
pub struct DecodeOneInsnInputWithoutGenerics {}
impl<T: DecodeOneInsn> std::ops::Index<T> for DecodeOneInsnInputWithoutGenerics {
type Output = DecodeOneInsnInput<T>;
fn index(&self, index: T) -> &Self::Output {
Interned::into_inner(index.input_ty().intern_sized())
}
}
pub type DecodeOneInsnMaxMOpCount<T> = <T as DecodeOneInsn>::MaxMOpCount;
#[doc(hidden)]
#[expect(non_upper_case_globals)]
pub const DecodeOneInsnMaxMOpCount: DecodeOneInsnMaxMOpCountWithoutGenerics =
DecodeOneInsnMaxMOpCountWithoutGenerics {};
#[doc(hidden)]
pub struct DecodeOneInsnMaxMOpCountWithoutGenerics {}
impl<T: DecodeOneInsn> std::ops::Index<T> for DecodeOneInsnMaxMOpCountWithoutGenerics {
type Output = <T::MaxMOpCount as Size>::SizeType;
fn index(&self, index: T) -> &Self::Output {
Interned::into_inner(index.max_mop_count().intern_sized())
}
}
#[hdl(no_static)]
pub struct DecodeAndRunSingleInsnInput<C: PhantomConstGet<CpuConfig>, I> {
pub decoder_input: I,
pub fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
pub first_id: MOpId,
pub pc: UInt<64>,
pub predicted_next_pc: UInt<64>,
pub regs: Registers<C>,
pub config: C,
}
#[hdl(no_static)]
pub struct DecodeAndRunSingleInsnOutput<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
pub regs: Registers<C>,
pub cancel_and_start_at: HdlOption<UInt<64>>,
pub retired_insns: ArrayVec<NextPcPredictorOp<C>, MaxMOpCount>,
pub config: C,
}
#[hdl(no_static)]
struct UnrenamedMOpState<C: PhantomConstGet<CpuConfig>> {
unrenamed: MOpInstance<MOp>,
renamed: HdlOption<TraceAsString<RenamedMOp<C>>>,
unit_num: TraceAsString<UnitNum<C>>,
}
#[hdl(no_static)]
enum Error {
NoUnitsOfKind(HdlUnitKind),
UnexpectedOutputReadyId(MOpId),
UnexpectedFinishCauseCancelId(MOpId),
InconsistentState,
}
#[hdl(no_static)]
struct CancelState<C: PhantomConstGet<CpuConfig>> {
canceling_units: ArrayType<Bool, CpuConfigUnitCount<C>>,
config: C,
}
#[hdl]
enum UnitState {
NotYetEnqueued,
SentInputsReady,
OutputReady,
FinishedAndOrCausedCancel,
}
#[hdl(no_static)]
struct RunMOpState<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
mop_index: UIntInRangeType<ConstUsize<0>, MaxMOpCount>,
unit_state: UnitState,
config: C,
}
#[hdl(no_static)]
enum RunState<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
RunningMOp(RunMOpState<C, MaxMOpCount>),
CancelingUnits(CancelState<C>),
Finished,
Error(TraceAsString<Error>),
}
#[hdl(no_static)]
struct OutputState<C: PhantomConstGet<CpuConfig>> {
dest_value: TraceAsString<PRegValue>,
predictor_op: NextPcPredictorOp<C>,
}
#[hdl(no_static)]
struct DecodeAndRunSingleInsnState<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
mops: ArrayVec<UnrenamedMOpState<C>, MaxMOpCount>,
regs: Registers<C>,
run_state: RunState<C, MaxMOpCount>,
output_state: HdlOption<OutputState<C>>,
cancel_and_start_at: HdlOption<UInt<64>>,
retired_insns: ArrayVec<NextPcPredictorOp<C>, MaxMOpCount>,
config: C,
}
#[hdl(no_static)]
enum StepOutput<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
Finished(DecodeAndRunSingleInsnOutput<C, MaxMOpCount>),
Step(DecodeAndRunSingleInsnState<C, MaxMOpCount>),
Error(TraceAsString<Error>),
}
#[hdl]
fn connect_to_unit_nop<C: Type + PhantomConstGet<CpuConfig>>(
to_unit: Expr<ExecuteToUnitInterface<C>>,
global_state: impl ToExpr<Type = GlobalState>,
) {
#[hdl]
let ExecuteToUnitInterface::<_> {
global_state: to_unit_global_state,
enqueue,
inputs_ready,
is_no_longer_speculative,
cant_cause_cancel: _,
output_ready: _,
finish_cause_cancel: _,
unit_outputs_ready,
cancel_all,
config: _,
} = to_unit;
connect(to_unit_global_state, global_state);
connect(enqueue.data, enqueue.ty().data.HdlNone());
connect(inputs_ready, inputs_ready.ty().HdlNone());
connect(
is_no_longer_speculative,
is_no_longer_speculative.ty().HdlNone(),
);
connect(unit_outputs_ready, false);
connect(cancel_all.data, HdlNone());
}
impl<C: PhantomConstCpuConfig, MaxMOpCount: Size> DecodeAndRunSingleInsnState<C, MaxMOpCount> {
#[hdl]
fn new(
input: Expr<DecodeAndRunSingleInsnInput<C, impl Type>>,
decoder_output: Expr<DecodeOneInsnOutput<MaxMOpCount>>,
config: C,
max_mop_count: MaxMOpCount::SizeType,
) -> Expr<Self> {
#[hdl]
let new_state = wire(DecodeAndRunSingleInsnState[config][max_mop_count]);
#[hdl]
let Self {
mops,
regs,
run_state,
output_state,
cancel_and_start_at,
retired_insns,
config: _,
} = new_state;
connect(run_state, run_state.ty().Finished());
connect(output_state, output_state.ty().HdlNone());
connect(cancel_and_start_at, HdlNone());
connect(retired_insns, retired_insns.ty().new());
connect(
mops,
ArrayVec::map(
decoder_output.mops,
mops.ty().element(),
|index, decoded_mop| {
if index == 0 {
connect(
run_state,
run_state.ty().RunningMOp(
#[hdl]
RunMOpState::<_, _> {
mop_index: 0usize.cast_to(run_state.ty().RunningMOp.mop_index),
unit_state: UnitState.NotYetEnqueued(),
config,
},
),
);
}
let retval = wire_with_loc(
&format!("mops_{index}"),
SourceLocation::caller(),
UnrenamedMOpState[config],
);
#[hdl]
let UnrenamedMOpState::<_> {
unrenamed,
renamed,
unit_num,
} = retval;
#[hdl]
let MOpInstance::<_> {
fetch_block_id,
id,
pc,
predicted_next_pc,
size_in_bytes,
is_first_mop_in_insn,
is_last_mop_in_insn,
mop,
} = unrenamed;
connect(fetch_block_id, input.fetch_block_id);
connect(id, (input.first_id + index).cast_to_static::<MOpId>());
connect(pc, input.pc);
connect(predicted_next_pc, input.predicted_next_pc);
connect(size_in_bytes, decoder_output.size_in_bytes);
connect(is_first_mop_in_insn, index == 0);
connect(
is_last_mop_in_insn,
ArrayVec::len(decoder_output.mops).cmp_eq(index + 1),
);
connect(mop, decoded_mop);
#[hdl]
let renamed_untransformed_move = wire(
HdlOption[TraceAsString[UnitMOp[PRegNum[config]][PRegNum[config]]
[MoveRegMOp[PRegNum[config]][PRegNum[config]]]]],
);
#[hdl]
if let MOp::TransformedMove(_) = *mop {
connect(
renamed_untransformed_move,
renamed_untransformed_move.ty().HdlNone(),
);
} else {
let unit_kind = MOp::kind(*mop);
let available_units = config.get().available_units_for_kind(unit_kind);
let chosen_unit = reduce(
available_units.into_iter().enumerate().map(
|(unit_index, available_unit)| {
#[hdl]
let chosen_unit = wire(UnitNum[config]);
connect(chosen_unit, chosen_unit.ty().const_zero());
#[hdl]
if available_unit {
connect(
chosen_unit,
chosen_unit.ty().from_index(unit_index),
);
}
chosen_unit
},
),
|a, b| {
#[hdl]
let chosen_unit = wire(UnitNum[config]);
connect(chosen_unit, a);
#[hdl]
if a.cmp_eq(chosen_unit.ty().const_zero()) {
connect(chosen_unit, b);
}
chosen_unit
},
)
.unwrap_or(UnitNum[config].const_zero());
#[hdl]
if chosen_unit.cmp_eq(chosen_unit.ty().const_zero()) {
connect(
run_state,
run_state
.ty()
.Error(Error.NoUnitsOfKind(unit_kind).to_trace_as_string()),
);
}
let unit_out_reg_num_ty = UnitOutRegNum[config];
connect(
renamed_untransformed_move,
HdlSome(
MOpTrait::map_regs(
*mop,
#[hdl]
PRegNum::<_> {
unit_num: chosen_unit,
unit_out_reg: #[hdl]
UnitOutRegNum::<_> {
value: !unit_out_reg_num_ty.value.zero(),
config,
},
},
PRegNum[config],
&mut |src_reg, index| {
#[hdl]
let renamed_src_reg = wire(PRegNum[config]);
#[hdl]
if src_reg.cmp_eq(MOpRegNum::const_zero()) {
connect(
renamed_src_reg,
renamed_src_reg.ty().const_zero(),
);
} else {
connect(
renamed_src_reg,
#[hdl]
PRegNum::<_> {
unit_num: chosen_unit,
unit_out_reg: unit_out_reg_num_ty
.new_sim(index),
},
);
}
renamed_src_reg
},
)
.to_trace_as_string(),
),
);
}
connect(renamed, renamed.ty().HdlNone());
connect(*unit_num, unit_num.ty().inner_ty().const_zero());
#[hdl]
if let HdlSome(renamed_untransformed_move) = renamed_untransformed_move {
let v = UnitMOp::try_with_transformed_move_op(
*renamed_untransformed_move,
renamed.ty().HdlSome.inner_ty().TransformedMove,
|dest, _src| {
connect(dest, dest.ty().HdlNone());
},
);
#[hdl]
if let HdlSome(v) = v {
connect(renamed, HdlSome(v.to_trace_as_string()));
connect(*unit_num, MOpTrait::dest_reg(v).unit_num);
}
}
retval
},
),
);
connect(regs, input.regs);
#[hdl]
if PRegValue::zeroed().cmp_ne(*regs.regs[MOpRegNum::CONST_ZERO_REG_NUM as usize]) {
connect(
run_state,
run_state
.ty()
.Error(Error.InconsistentState().to_trace_as_string()),
);
}
new_state
}
#[hdl]
fn step(
this: Expr<Self>,
to_units: Expr<ExecuteToUnitInterfaces<C>>,
global_state: Expr<GlobalState>,
) -> Expr<StepOutput<C, MaxMOpCount>> {
#[hdl]
let Self {
mops,
regs,
run_state,
output_state,
cancel_and_start_at,
retired_insns,
config,
} = this;
let config = config.ty();
let max_mop_count = MaxMOpCount::from_usize(mops.ty().capacity());
#[hdl]
let stepped = wire(StepOutput[config][max_mop_count]);
let to_units_as_array = ExecuteToUnitInterfaces::unit_fields_as_array_wire(
to_units,
"to_units_as_array",
false,
);
for to_unit in to_units_as_array {
connect_to_unit_nop(to_unit, global_state);
}
#[hdl]
let stepped_step = wire(stepped.ty().Step);
connect(stepped_step, this);
connect(stepped, stepped.ty().Step(stepped_step));
#[hdl]
match run_state {
RunState::<_, _>::RunningMOp(run_mop_state) => {
#[hdl]
let RunMOpState::<_, _> {
mop_index,
unit_state,
config: _,
} = run_mop_state;
let mop_index = mop_index.cast_to(UInt[mop_index.ty().bit_width()]);
#[hdl]
let mop = wire(mops.ty().element());
connect(mop, mops[mop_index]);
#[hdl]
let UnrenamedMOpState::<_> {
unrenamed,
renamed,
unit_num,
} = mop;
#[hdl]
let unrenamed_src_regs = wire();
connect(
unrenamed_src_regs,
repeat(
MOpRegNum::const_zero(),
ConstUsize::<{ COMMON_MOP_SRC_LEN }>,
),
);
MOpTrait::connect_to_src_regs(*unrenamed.mop, unrenamed_src_regs);
#[hdl]
let src_values: Array<
TraceAsString<PRegValue>,
{ COMMON_MOP_SRC_LEN },
> = wire();
for (src_value, src_reg) in src_values.into_iter().zip(unrenamed_src_regs) {
connect(src_value, regs.regs[src_reg.value]);
}
#[hdl]
if let HdlSome(unit_index) = UnitNum::as_index(*unit_num) {
#[hdl]
let to_unit = wire(to_units_as_array.ty().element());
connect(to_units_as_array[unit_index], to_unit);
connect_to_unit_nop(to_unit, global_state);
#[hdl]
let ExecuteToUnitInterface::<_> {
global_state: _,
enqueue,
inputs_ready,
is_no_longer_speculative,
cant_cause_cancel: _, // we don't track if it can cause a cancel
output_ready,
finish_cause_cancel,
unit_outputs_ready,
cancel_all,
config: _,
} = to_unit;
connect(unit_outputs_ready, true);
connect(cancel_all.data, HdlNone());
#[hdl]
let unit_state_after_start = wire();
connect(unit_state_after_start, unit_state);
#[hdl]
if let UnitState::NotYetEnqueued = unit_state {
#[hdl]
if let HdlSome(renamed) = renamed {
let mop = #[hdl]
MOpInstance::<_> {
fetch_block_id: unrenamed.fetch_block_id,
id: unrenamed.id,
pc: unrenamed.pc,
predicted_next_pc: unrenamed.predicted_next_pc,
size_in_bytes: unrenamed.size_in_bytes,
is_first_mop_in_insn: unrenamed.is_first_mop_in_insn,
is_last_mop_in_insn: unrenamed.is_last_mop_in_insn,
mop: renamed,
};
connect(
enqueue.data,
HdlSome(
#[hdl]
UnitEnqueue::<_> { mop, config },
),
);
#[hdl]
if enqueue.ready {
connect(
inputs_ready,
HdlSome(
#[hdl]
UnitInputsReady::<_> {
mop,
src_values,
config,
},
),
);
connect(
is_no_longer_speculative,
HdlSome(
#[hdl]
UnitMOpIsNoLongerSpeculative::<_> {
id: unrenamed.id,
config,
},
),
);
connect(unit_state_after_start, UnitState.SentInputsReady());
}
} else {
connect(
stepped,
stepped
.ty()
.Error(Error.InconsistentState().to_trace_as_string()),
);
}
}
#[hdl]
let unit_state_after_output_ready = wire();
connect(unit_state_after_output_ready, unit_state_after_start);
#[hdl]
let output_state_after_output_ready = wire(output_state.ty());
connect(output_state_after_output_ready, output_state);
#[hdl]
if let HdlSome(output_ready) = output_ready {
#[hdl]
let UnitOutputReady::<_> {
id: output_ready_id,
dest_value,
predictor_op,
} = output_ready;
#[hdl]
match unit_state_after_start {
UnitState::SentInputsReady => {
connect(
output_state_after_output_ready,
HdlSome(
#[hdl]
OutputState::<_> {
dest_value,
predictor_op,
},
),
);
connect(unit_state_after_output_ready, UnitState.OutputReady());
}
UnitState::NotYetEnqueued
| UnitState::OutputReady
| UnitState::FinishedAndOrCausedCancel => connect(
stepped,
stepped
.ty()
.Error(Error.InconsistentState().to_trace_as_string()),
),
}
#[hdl]
if unrenamed.id.cmp_ne(output_ready_id) {
connect(
stepped,
stepped.ty().Error(
Error
.UnexpectedOutputReadyId(output_ready_id)
.to_trace_as_string(),
),
);
}
}
#[hdl]
if let HdlSome(finish_cause_cancel) = finish_cause_cancel {
#[hdl]
let UnitFinishCauseCancel::<_> {
id: finish_cause_cancel_id,
caused_cancel,
config: _,
} = finish_cause_cancel;
connect(stepped_step.output_state, output_state.ty().HdlNone());
#[hdl]
match unit_state_after_output_ready {
UnitState::OutputReady => {}
UnitState::NotYetEnqueued
| UnitState::SentInputsReady
| UnitState::FinishedAndOrCausedCancel => connect(
stepped,
stepped
.ty()
.Error(Error.InconsistentState().to_trace_as_string()),
),
}
#[hdl]
let do_retire = wire();
#[hdl]
if do_retire {
#[hdl]
if let HdlSome(output_state) = output_state_after_output_ready {
#[hdl]
let OutputState::<_> {
dest_value,
predictor_op,
} = output_state;
let old_len = ArrayVec::len(retired_insns);
let len_ty = old_len.ty();
let old_len = old_len.cast_to(UInt[len_ty.bit_width()]);
connect(
ArrayVec::len(stepped_step.retired_insns),
(old_len + 1u8).cast_to(len_ty),
);
connect(stepped_step.retired_insns[old_len], predictor_op);
for dest_reg in MOpDestReg::regs(MOpTrait::dest_reg(*unrenamed.mop))
{
#[hdl]
if MOpRegNum::const_zero().cmp_ne(dest_reg) {
connect(stepped_step.regs.regs[dest_reg.value], dest_value);
}
}
} else {
connect(
stepped,
stepped
.ty()
.Error(Error.InconsistentState().to_trace_as_string()),
);
}
}
#[hdl]
if let HdlSome(caused_cancel) = caused_cancel {
#[hdl]
let UnitCausedCancel::<_> {
start_at_pc,
cancel_after_retire,
config: _,
} = caused_cancel;
connect(stepped_step.cancel_and_start_at, HdlSome(start_at_pc));
connect(do_retire, cancel_after_retire);
connect(
stepped_step.run_state,
stepped_step.ty().run_state.CancelingUnits(
#[hdl]
CancelState::<_> {
canceling_units: repeat(
true,
CancelState[config].canceling_units.len(),
),
config,
},
),
);
} else {
connect(do_retire, true);
#[hdl]
let next_mop_index = wire(mops.ty().len_ty());
connect(
next_mop_index,
(mop_index + 1u8).cast_to(next_mop_index.ty()),
);
#[hdl]
if next_mop_index.cmp_lt(ArrayVec::len(mops)) {
connect(
stepped_step.run_state,
stepped_step.ty().run_state.RunningMOp(
#[hdl]
RunMOpState::<_, _> {
mop_index: next_mop_index
.cast_to(mop_index.ty())
.cast_to(run_mop_state.ty().mop_index),
unit_state: UnitState.NotYetEnqueued(),
config,
},
),
);
} else {
connect(
stepped_step.run_state,
stepped_step.ty().run_state.Finished(),
);
}
}
#[hdl]
if unrenamed.id.cmp_ne(finish_cause_cancel_id) {
connect(
stepped,
stepped.ty().Error(
Error
.UnexpectedFinishCauseCancelId(finish_cause_cancel_id)
.to_trace_as_string(),
),
);
}
} else {
connect(stepped_step.output_state, output_state_after_output_ready);
connect(
stepped_step.run_state,
stepped_step.ty().run_state.RunningMOp(
#[hdl]
RunMOpState::<_, _> {
mop_index: run_mop_state.mop_index,
unit_state: unit_state_after_output_ready,
config,
},
),
);
}
} else {
#[hdl]
if let MOp::TransformedMove(mop) = *unrenamed.mop {
#[hdl]
let MoveRegMOp::<_, _> { common: _ } = mop;
} else {
connect(
stepped,
stepped
.ty()
.Error(Error.InconsistentState().to_trace_as_string()),
);
}
let old_len = ArrayVec::len(retired_insns);
let len_ty = old_len.ty();
let old_len = old_len.cast_to(UInt[len_ty.bit_width()]);
connect(
ArrayVec::len(stepped_step.retired_insns),
(old_len + 1u8).cast_to(len_ty),
);
connect(
stepped_step.retired_insns[old_len],
#[hdl]
NextPcPredictorOp::<_> {
call_stack_op: CallStackOp.None(),
cond_br_taken: HdlNone(),
config,
},
);
for dest_reg in MOpDestReg::regs(MOpTrait::dest_reg(*unrenamed.mop)) {
#[hdl]
if MOpRegNum::const_zero().cmp_ne(dest_reg) {
connect(stepped_step.regs.regs[dest_reg.value], src_values[0]);
}
}
}
}
RunState::<_, _>::CancelingUnits(cancel_state) => {
#[hdl]
let CancelState::<_> {
canceling_units,
config: _,
} = cancel_state;
#[hdl]
let done_canceling_units = wire();
connect(done_canceling_units, true);
#[hdl]
let still_canceling_units = wire(canceling_units.ty());
for ((to_unit, canceling_unit), still_canceling_unit) in to_units_as_array
.into_iter()
.zip(canceling_units)
.zip(still_canceling_units)
{
connect(still_canceling_unit, false);
#[hdl]
if canceling_unit {
connect(to_unit.cancel_all.data, HdlSome(()));
#[hdl]
if !to_unit.cancel_all.ready {
connect(still_canceling_unit, true);
connect(done_canceling_units, false);
}
}
}
#[hdl]
if done_canceling_units {
connect(
stepped,
stepped.ty().Finished(
#[hdl]
DecodeAndRunSingleInsnOutput::<_, _> {
regs,
cancel_and_start_at,
retired_insns,
config,
},
),
);
} else {
connect(
stepped_step.run_state,
run_state.ty().CancelingUnits(
#[hdl]
CancelState::<_> {
canceling_units: still_canceling_units,
config,
},
),
);
}
}
RunState::<_, _>::Finished => connect(
stepped,
stepped.ty().Finished(
#[hdl]
DecodeAndRunSingleInsnOutput::<_, _> {
regs,
cancel_and_start_at,
retired_insns,
config,
},
),
),
RunState::<_, _>::Error(error) => connect(stepped, stepped.ty().Error(error)),
}
stepped
}
}
#[hdl_module]
pub fn decode_and_run_single_insn<C: Type + PhantomConstCpuConfig, D: Type + DecodeOneInsn>(
config: C,
decoder: Interned<Module<D>>,
) {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let input: ReadyValid<DecodeAndRunSingleInsnInput<C, DecodeOneInsnInput<D>>> = m.input(
ReadyValid[DecodeAndRunSingleInsnInput[config][DecodeOneInsnInput[decoder.io_ty()]]],
);
#[hdl]
let global_state: GlobalState = m.input();
#[hdl]
let output: ReadyValid<DecodeAndRunSingleInsnOutput<C, DecodeOneInsnMaxMOpCount<D>>> = m
.output(
ReadyValid
[DecodeAndRunSingleInsnOutput[config][DecodeOneInsnMaxMOpCount[decoder.io_ty()]]],
);
#[hdl]
let to_units: ExecuteToUnitInterfaces<C> = m.output(ExecuteToUnitInterfaces[config]);
#[hdl]
let error: Bool = m.output();
connect(error, false);
#[hdl]
let decoder = instance(decoder);
#[hdl]
let decoder_input = wire(decoder.ty().input_ty());
connect(decoder_input, decoder_input.ty().uninit());
#[hdl]
let decoder_output = wire(DecodeOneInsnOutput[decoder.ty().max_mop_count()]);
D::connect_io(decoder, decoder_input, decoder_output);
#[hdl]
let state_reg = reg_builder().clock_domain(cd).reset(
HdlOption[DecodeAndRunSingleInsnState[config][decoder.ty().max_mop_count()]].HdlNone(),
);
#[hdl]
if let HdlSome(state) = state_reg {
connect(input.ready, false);
let step = DecodeAndRunSingleInsnState::step(state, to_units, global_state);
#[hdl]
match step {
StepOutput::<_, _>::Finished(v) => {
connect(output.data, HdlSome(v));
#[hdl]
if output.ready {
connect(state_reg, state_reg.ty().HdlNone());
}
}
StepOutput::<_, _>::Step(state) => {
connect(state_reg, HdlSome(state));
connect(output.data, output.ty().data.HdlNone());
}
StepOutput::<_, _>::Error(_) => {
connect(output.data, output.ty().data.HdlNone());
connect(error, true);
}
}
} else {
for to_unit in ExecuteToUnitInterfaces::unit_fields(to_units) {
connect_to_unit_nop(to_unit, global_state);
}
connect(input.ready, true);
connect(output.data, output.ty().data.HdlNone());
#[hdl]
if let HdlSome(input) = input.data {
connect(decoder_input, input.decoder_input);
connect(
state_reg,
HdlSome(DecodeAndRunSingleInsnState::new(
input,
decoder_output,
config,
decoder.ty().max_mop_count(),
)),
);
}
}
}

View file

@ -226,10 +226,6 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
#[hdl] #[hdl]
let mapped_array_vec = wire(this.ty().mapped_ty(new_element_ty)); let mapped_array_vec = wire(this.ty().mapped_ty(new_element_ty));
connect(mapped_array_vec.len, this.len); connect(mapped_array_vec.len, this.len);
connect(
mapped_array_vec.elements,
mapped_array_vec.ty().elements.uninit(),
);
Self::for_each(this, |index, element| { Self::for_each(this, |index, element| {
connect(mapped_array_vec[index], f(index, element)); connect(mapped_array_vec[index], f(index, element));
}); });

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -149,7 +149,7 @@ fn test_decode_insn() {
#[derive(Debug)] #[derive(Debug)]
#[expect(dead_code, reason = "used only for Debug formatting")] #[expect(dead_code, reason = "used only for Debug formatting")]
struct FormattedOutput<'a> { struct FormattedOutput<'a> {
insns: &'a [SimValue<TraceAsString<MOp>>], insns: &'a [SimValue<MOp>],
second_input_used: bool, second_input_used: bool,
is_illegal: bool, is_illegal: bool,
} }

View file

@ -16,23 +16,14 @@ mod fixed_point_store;
mod move_to_from_system_register; mod move_to_from_system_register;
mod prefixed_no_operation; mod prefixed_no_operation;
#[hdl(get(|_| 3))]
pub type TestCaseOutputLen<C: PhantomConstGet<()>> = DynSize;
pub struct TestCase { pub struct TestCase {
pub mnemonic: &'static str, pub mnemonic: &'static str,
pub first_input: u32, pub first_input: u32,
pub second_input: Option<u32>, pub second_input: Option<u32>,
pub output: SimValue<ArrayVec<TraceAsString<MOp>, TestCaseOutputLen<PhantomConst<()>>>>, pub output: SimValue<ArrayVec<MOp, ConstUsize<3>>>,
pub loc: &'static std::panic::Location<'static>, pub loc: &'static std::panic::Location<'static>,
} }
impl TestCase {
pub fn output_ty() -> ArrayVec<TraceAsString<MOp>, TestCaseOutputLen<PhantomConst<()>>> {
ArrayVec[TraceAsString[MOp]][TestCaseOutputLen[PhantomConst::default()]]
}
}
impl fmt::Debug for TestCase { impl fmt::Debug for TestCase {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { let Self {
@ -58,91 +49,90 @@ impl fmt::Debug for TestCase {
} }
} }
#[inline(never)] // prevent stack overflow
#[track_caller] #[track_caller]
fn insn_empty(mnemonic: &'static str, first_input: u32, second_input: Option<u32>) -> TestCase { fn insn_empty(mnemonic: &'static str, first_input: u32, second_input: Option<u32>) -> TestCase {
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width()) let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
.zero() .zero()
.cast_bits_to(MOp) .cast_bits_to(MOp);
.into_trace_as_string();
TestCase { TestCase {
mnemonic, mnemonic,
first_input, first_input,
second_input, second_input,
output: TestCase::output_ty().new_sim(zero_mop), output: ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop),
loc: std::panic::Location::caller(), loc: std::panic::Location::caller(),
} }
} }
#[inline(never)] // prevent stack overflow
#[track_caller] #[track_caller]
fn insn_single<T: ToSimValue<Type = MOp>>( fn insn_single(
mnemonic: &'static str, mnemonic: &'static str,
first_input: u32, first_input: u32,
second_input: Option<u32>, second_input: Option<u32>,
// use a closure to avoid having too many variables in one function causing a stack overflow output: impl ToSimValue<Type = MOp>,
output: impl FnOnce() -> T,
) -> TestCase { ) -> TestCase {
let mut retval = insn_empty(mnemonic, first_input, second_input); let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
ArrayVec::try_push_sim( .zero()
&mut retval.output, .cast_bits_to(MOp);
output().into_sim_value().into_trace_as_string(), let mut single_storage = ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop);
) ArrayVec::try_push_sim(&mut single_storage, zero_mop).expect("known to have space");
.expect("known to have space"); ArrayVec::elements_sim_mut(&mut single_storage)[0] = output.to_sim_value();
retval TestCase {
mnemonic,
first_input,
second_input,
output: single_storage,
loc: std::panic::Location::caller(),
}
} }
#[inline(never)] // prevent stack overflow
#[track_caller] #[track_caller]
fn insn_double<T: ToSimValue<Type = MOp>>( fn insn_double(
mnemonic: &'static str, mnemonic: &'static str,
first_input: u32, first_input: u32,
second_input: Option<u32>, second_input: Option<u32>,
// use a closure to avoid having too many variables in one function causing a stack overflow insns: [impl ToSimValue<Type = MOp>; 2],
insns: impl FnOnce() -> [T; 2],
) -> TestCase { ) -> TestCase {
let mut retval = insn_empty(mnemonic, first_input, second_input); let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
let [insn0, insn1] = insns(); .zero()
ArrayVec::try_push_sim( .cast_bits_to(MOp);
&mut retval.output, let mut single_storage = ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop);
insn0.into_sim_value().into_trace_as_string(), ArrayVec::try_push_sim(&mut single_storage, &zero_mop).expect("known to have space");
) ArrayVec::try_push_sim(&mut single_storage, zero_mop).expect("known to have space");
.expect("known to have space"); ArrayVec::elements_sim_mut(&mut single_storage)[0] = insns[0].to_sim_value();
ArrayVec::try_push_sim( ArrayVec::elements_sim_mut(&mut single_storage)[1] = insns[1].to_sim_value();
&mut retval.output, TestCase {
insn1.into_sim_value().into_trace_as_string(), mnemonic,
) first_input,
.expect("known to have space"); second_input,
retval output: single_storage,
loc: std::panic::Location::caller(),
}
} }
#[inline(never)] // prevent stack overflow
#[track_caller] #[track_caller]
fn insn_triple<T: ToSimValue<Type = MOp>>( fn insn_triple(
mnemonic: &'static str, mnemonic: &'static str,
first_input: u32, first_input: u32,
second_input: Option<u32>, second_input: Option<u32>,
// use a closure to avoid having too many variables in one function causing a stack overflow insns: [impl ToSimValue<Type = MOp>; 3],
insns: impl FnOnce() -> [T; 3],
) -> TestCase { ) -> TestCase {
let mut retval = insn_empty(mnemonic, first_input, second_input); let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
let [insn0, insn1, insn2] = insns(); .zero()
ArrayVec::try_push_sim( .cast_bits_to(MOp);
&mut retval.output, let mut single_storage = ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop);
insn0.into_sim_value().into_trace_as_string(), ArrayVec::try_push_sim(&mut single_storage, &zero_mop).expect("known to have space");
) ArrayVec::try_push_sim(&mut single_storage, &zero_mop).expect("known to have space");
.expect("known to have space"); ArrayVec::try_push_sim(&mut single_storage, zero_mop).expect("known to have space");
ArrayVec::try_push_sim( ArrayVec::elements_sim_mut(&mut single_storage)[0] = insns[0].to_sim_value();
&mut retval.output, ArrayVec::elements_sim_mut(&mut single_storage)[1] = insns[1].to_sim_value();
insn1.into_sim_value().into_trace_as_string(), ArrayVec::elements_sim_mut(&mut single_storage)[2] = insns[2].to_sim_value();
) TestCase {
.expect("known to have space"); mnemonic,
ArrayVec::try_push_sim( first_input,
&mut retval.output, second_input,
insn2.into_sim_value().into_trace_as_string(), output: single_storage,
) loc: std::panic::Location::caller(),
.expect("known to have space"); }
retval
} }
pub fn test_cases() -> Vec<TestCase> { pub fn test_cases() -> Vec<TestCase> {

View file

@ -9,7 +9,10 @@ use fayalite::prelude::*;
/// covers instructions in PowerISA v3.1C Book I 2.4 Branch Instructions /// covers instructions in PowerISA v3.1C Book I 2.4 Branch Instructions
pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) { pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
retval.push(insn_single("b 0x345678", 0x48345678, None, || { retval.push(insn_single(
"b 0x345678",
0x48345678,
None,
BranchMOp::branch_i( BranchMOp::branch_i(
MOpDestReg::new_sim(&[], &[]), MOpDestReg::new_sim(&[], &[]),
[MOpRegNum::const_zero(); 2], [MOpRegNum::const_zero(); 2],
@ -17,9 +20,12 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
true, true,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("ba 0x345678", 0x4834567a, None, || { retval.push(insn_single(
"ba 0x345678",
0x4834567a,
None,
BranchMOp::branch_i( BranchMOp::branch_i(
MOpDestReg::new_sim(&[], &[]), MOpDestReg::new_sim(&[], &[]),
[MOpRegNum::const_zero(); 2], [MOpRegNum::const_zero(); 2],
@ -27,9 +33,12 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
false, false,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("bl 0x345678", 0x48345679, None, || { retval.push(insn_single(
"bl 0x345678",
0x48345679,
None,
BranchMOp::branch_i( BranchMOp::branch_i(
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]), MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
[MOpRegNum::const_zero(); 2], [MOpRegNum::const_zero(); 2],
@ -37,9 +46,12 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
true, true,
true, true,
false, false,
) ),
})); ));
retval.push(insn_single("bla 0x345678", 0x4834567b, None, || { retval.push(insn_single(
"bla 0x345678",
0x4834567b,
None,
BranchMOp::branch_i( BranchMOp::branch_i(
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]), MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
[MOpRegNum::const_zero(); 2], [MOpRegNum::const_zero(); 2],
@ -47,15 +59,18 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
false, false,
true, true,
false, false,
) ),
})); ));
fn insn_dec_ctr_and<T: ToSimValue<Type = MOp>>( fn insn_dec_ctr_and(
mnemonic: &'static str, mnemonic: &'static str,
first_input: u32, first_input: u32,
second_input: Option<u32>, second_input: Option<u32>,
second_insn: impl FnOnce() -> T, second_insn: impl ToSimValue<Type = MOp>,
) -> TestCase { ) -> TestCase {
insn_double(mnemonic, first_input, second_input, || { insn_double(
mnemonic,
first_input,
second_input,
[ [
AddSubMOp::add_sub_i::<MOp>( AddSubMOp::add_sub_i::<MOp>(
MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []), MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []),
@ -68,9 +83,9 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
false, false,
) )
.into_sim_value(), .into_sim_value(),
second_insn().into_sim_value(), second_insn.into_sim_value(),
] ],
}) )
} }
macro_rules! insn_branch_conds { macro_rules! insn_branch_conds {
( (
@ -122,146 +137,12 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " 0, 0, ", $asm_last_arg), concat!($mnemonic, " 0, 0, ", $asm_last_arg),
$encoding, $encoding,
None, None,
|| {
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.SLt(),
true,
$pc_relative,
$lk,
$is_ret,
)
},
));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 0, 1, ", $asm_last_arg),
$encoding | 0x010000,
None,
|| {
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.SGt(),
true,
$pc_relative,
$lk,
$is_ret,
)
},
));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 0, 2, ", $asm_last_arg),
$encoding | 0x020000,
None,
|| {
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.Eq(),
true,
$pc_relative,
$lk,
$is_ret,
)
},
));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 0, 3, ", $asm_last_arg),
$encoding | 0x030000,
None,
|| {
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.Overflow(),
true,
$pc_relative,
$lk,
$is_ret,
)
},
));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 0, 9, ", $asm_last_arg),
$encoding | 0x090000,
None,
|| {
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(2),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.SGt(),
true,
$pc_relative,
$lk,
$is_ret,
)
},
));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 2, 0, ", $asm_last_arg),
$encoding | (2 << 21),
None,
|| {
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.SLt(),
false,
$pc_relative,
$lk,
$is_ret,
)
},
));
}
retval.push(insn_single(
concat!($mnemonic, " 4, 0, ", $asm_last_arg),
$encoding | (4 << 21),
None,
|| {
BranchMOp::branch_cond_ctr( BranchMOp::branch_cond_ctr(
$dest, $dest,
[ [
MOpRegNum::power_isa_cr_reg_imm(0), MOpRegNum::power_isa_cr_reg_imm(0),
$src1, $src1,
MOpRegNum::const_zero(), MOpRegNum::power_isa_ctr_reg(),
], ],
$imm.cast_to_static::<SInt<_>>(), $imm.cast_to_static::<SInt<_>>(),
true, true,
@ -270,66 +151,140 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
$pc_relative, $pc_relative,
$lk, $lk,
$is_ret, $is_ret,
) ),
}, ));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 0, 1, ", $asm_last_arg),
$encoding | 0x010000,
None,
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.SGt(),
true,
$pc_relative,
$lk,
$is_ret,
),
));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 0, 2, ", $asm_last_arg),
$encoding | 0x020000,
None,
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.Eq(),
true,
$pc_relative,
$lk,
$is_ret,
),
));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 0, 3, ", $asm_last_arg),
$encoding | 0x030000,
None,
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.Overflow(),
true,
$pc_relative,
$lk,
$is_ret,
),
));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 0, 9, ", $asm_last_arg),
$encoding | 0x090000,
None,
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(2),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.SGt(),
true,
$pc_relative,
$lk,
$is_ret,
),
));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 2, 0, ", $asm_last_arg),
$encoding | (2 << 21),
None,
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.SLt(),
false,
$pc_relative,
$lk,
$is_ret,
),
));
}
retval.push(insn_single(
concat!($mnemonic, " 4, 0, ", $asm_last_arg),
$encoding | (4 << 21),
None,
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::const_zero(),
],
$imm.cast_to_static::<SInt<_>>(),
true,
ConditionMode.SLt(),
true,
$pc_relative,
$lk,
$is_ret,
),
)); ));
if !$mnemonic.starts_with("bcctr") { if !$mnemonic.starts_with("bcctr") {
retval.push(insn_dec_ctr_and( retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 8, 0, ", $asm_last_arg), concat!($mnemonic, " 8, 0, ", $asm_last_arg),
$encoding | (8 << 21), $encoding | (8 << 21),
None, None,
|| {
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
false,
ConditionMode.SLt(),
true,
$pc_relative,
$lk,
$is_ret,
)
},
));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 10, 0, ", $asm_last_arg),
$encoding | (10 << 21),
None,
|| {
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
false,
ConditionMode.SLt(),
false,
$pc_relative,
$lk,
$is_ret,
)
},
));
}
retval.push(insn_single(
concat!($mnemonic, " 12, 0, ", $asm_last_arg),
$encoding | (12 << 21),
None,
|| {
BranchMOp::branch_cond_ctr( BranchMOp::branch_cond_ctr(
$dest, $dest,
[ [
MOpRegNum::power_isa_cr_reg_imm(0), MOpRegNum::power_isa_cr_reg_imm(0),
$src1, $src1,
MOpRegNum::const_zero(), MOpRegNum::power_isa_ctr_reg(),
], ],
$imm.cast_to_static::<SInt<_>>(), $imm.cast_to_static::<SInt<_>>(),
false, false,
@ -338,65 +293,99 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
$pc_relative, $pc_relative,
$lk, $lk,
$is_ret, $is_ret,
) ),
}, ));
retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 10, 0, ", $asm_last_arg),
$encoding | (10 << 21),
None,
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::power_isa_ctr_reg(),
],
$imm.cast_to_static::<SInt<_>>(),
false,
ConditionMode.SLt(),
false,
$pc_relative,
$lk,
$is_ret,
),
));
}
retval.push(insn_single(
concat!($mnemonic, " 12, 0, ", $asm_last_arg),
$encoding | (12 << 21),
None,
BranchMOp::branch_cond_ctr(
$dest,
[
MOpRegNum::power_isa_cr_reg_imm(0),
$src1,
MOpRegNum::const_zero(),
],
$imm.cast_to_static::<SInt<_>>(),
false,
ConditionMode.SLt(),
true,
$pc_relative,
$lk,
$is_ret,
),
)); ));
if !$mnemonic.starts_with("bcctr") { if !$mnemonic.starts_with("bcctr") {
retval.push(insn_dec_ctr_and( retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 16, 0, ", $asm_last_arg), concat!($mnemonic, " 16, 0, ", $asm_last_arg),
$encoding | (16 << 21), $encoding | (16 << 21),
None, None,
|| { BranchMOp::branch_ctr(
BranchMOp::branch_ctr( $dest,
$dest, [
[ MOpRegNum::const_zero(),
MOpRegNum::const_zero(), $src1,
$src1, MOpRegNum::power_isa_ctr_reg(),
MOpRegNum::power_isa_ctr_reg(), ],
], $imm.cast_to_static::<SInt<_>>(),
$imm.cast_to_static::<SInt<_>>(), true,
true, $pc_relative,
$pc_relative, $lk,
$lk, $is_ret,
$is_ret, ),
)
},
)); ));
retval.push(insn_dec_ctr_and( retval.push(insn_dec_ctr_and(
concat!($mnemonic, " 18, 0, ", $asm_last_arg), concat!($mnemonic, " 18, 0, ", $asm_last_arg),
$encoding | (18 << 21), $encoding | (18 << 21),
None, None,
|| { BranchMOp::branch_ctr(
BranchMOp::branch_ctr( $dest,
$dest, [
[ MOpRegNum::const_zero(),
MOpRegNum::const_zero(), $src1,
$src1, MOpRegNum::power_isa_ctr_reg(),
MOpRegNum::power_isa_ctr_reg(), ],
], $imm.cast_to_static::<SInt<_>>(),
$imm.cast_to_static::<SInt<_>>(), false,
false, $pc_relative,
$pc_relative, $lk,
$lk, $is_ret,
$is_ret, ),
)
},
)); ));
} }
retval.push(insn_single( retval.push(insn_single(
concat!($mnemonic, " 20, 0, ", $asm_last_arg), concat!($mnemonic, " 20, 0, ", $asm_last_arg),
$encoding | (20 << 21), $encoding | (20 << 21),
None, None,
|| { BranchMOp::branch_i(
BranchMOp::branch_i( $dest,
$dest, [MOpRegNum::const_zero(), $src1],
[MOpRegNum::const_zero(), $src1], $imm.cast_to_static::<SInt<_>>(),
$imm.cast_to_static::<SInt<_>>(), $pc_relative,
$pc_relative, $lk,
$lk, $is_ret,
$is_ret, ),
)
},
)); ));
}; };
} }
@ -446,20 +435,18 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
".long 0x4e400461 # bctarl 18, 0, 0", ".long 0x4e400461 # bctarl 18, 0, 0",
0x4e400461, 0x4e400461,
None, None,
|| { BranchMOp::branch_ctr(
BranchMOp::branch_ctr( MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]), [
[ MOpRegNum::const_zero(),
MOpRegNum::const_zero(), MOpRegNum::power_isa_tar_reg(),
MOpRegNum::power_isa_tar_reg(), MOpRegNum::power_isa_ctr_reg(),
MOpRegNum::power_isa_ctr_reg(), ],
], 0.cast_to_static::<SInt<_>>(),
0.cast_to_static::<SInt<_>>(), false,
false, false,
false, true,
true, false,
false, ),
)
},
)); ));
} }

View file

@ -20,70 +20,58 @@ pub fn test_cases_book_i_2_5_condition_register(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " 4*cr3+so, 4*cr1+gt, 4*cr5+lt"), concat!($mnemonic, " 4*cr3+so, 4*cr1+gt, 4*cr5+lt"),
$encoding | 0x01e5a000, $encoding | 0x01e5a000,
None, None,
|| { LogicalFlagsMOp::logical_flags(
LogicalFlagsMOp::logical_flags( MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), [
[ MOpRegNum::power_isa_cr_reg_imm(1),
MOpRegNum::power_isa_cr_reg_imm(1), MOpRegNum::power_isa_cr_reg_imm(5),
MOpRegNum::power_isa_cr_reg_imm(5), MOpRegNum::power_isa_cr_reg_imm(3),
MOpRegNum::power_isa_cr_reg_imm(3), ],
], LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(|src0, src1, src2| {
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>( let mut dest = src2.map(|v| Some(v.into()));
|src0, src1, src2| { dest.so = Some((src0.cr_gt, src1.cr_lt).into());
let mut dest = src2.map(|v| Some(v.into())); dest
dest.so = Some((src0.cr_gt, src1.cr_lt).into()); }),
dest $lut,
}, ),
),
$lut,
)
},
)); ));
retval.push(insn_single( retval.push(insn_single(
concat!($mnemonic, " lt, gt, eq"), concat!($mnemonic, " lt, gt, eq"),
$encoding | 0x00011000, $encoding | 0x00011000,
None, None,
|| { LogicalFlagsMOp::logical_flags(
LogicalFlagsMOp::logical_flags( MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(0)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(0)], &[]), [
[ MOpRegNum::power_isa_cr_reg_imm(0),
MOpRegNum::power_isa_cr_reg_imm(0), MOpRegNum::power_isa_cr_reg_imm(0),
MOpRegNum::power_isa_cr_reg_imm(0), MOpRegNum::power_isa_cr_reg_imm(0),
MOpRegNum::power_isa_cr_reg_imm(0), ],
], LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(|src0, src1, src2| {
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>( let mut dest = src2.map(|v| Some(v.into()));
|src0, src1, src2| { dest.cr_lt = Some((src0.cr_gt, src1.cr_eq).into());
let mut dest = src2.map(|v| Some(v.into())); dest
dest.cr_lt = Some((src0.cr_gt, src1.cr_eq).into()); }),
dest $lut,
}, ),
),
$lut,
)
},
)); ));
retval.push(insn_single( retval.push(insn_single(
concat!($mnemonic, " gt, gt, eq"), concat!($mnemonic, " gt, gt, eq"),
$encoding | 0x00211000, $encoding | 0x00211000,
None, None,
|| { LogicalFlagsMOp::logical_flags(
LogicalFlagsMOp::logical_flags( MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(0)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(0)], &[]), [
[ MOpRegNum::power_isa_cr_reg_imm(0),
MOpRegNum::power_isa_cr_reg_imm(0), MOpRegNum::power_isa_cr_reg_imm(0),
MOpRegNum::power_isa_cr_reg_imm(0), MOpRegNum::power_isa_cr_reg_imm(0),
MOpRegNum::power_isa_cr_reg_imm(0), ],
], LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(|src0, src1, src2| {
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>( let mut dest = src2.map(|v| Some(v.into()));
|src0, src1, src2| { dest.cr_gt = Some((src0.cr_gt, src1.cr_eq).into());
let mut dest = src2.map(|v| Some(v.into())); dest
dest.cr_gt = Some((src0.cr_gt, src1.cr_eq).into()); }),
dest $lut,
}, ),
),
$lut,
)
},
)); ));
}}; }};
} }
@ -101,13 +89,11 @@ pub fn test_cases_book_i_2_5_condition_register(retval: &mut Vec<TestCase>) {
concat!("mcrf ", $dest, ", ", $src), concat!("mcrf ", $dest, ", ", $src),
$encoding, $encoding,
None, None,
|| { MoveRegMOp::move_reg(
MoveRegMOp::move_reg( MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num($dest)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num($dest)], &[]), [MOpRegNum::power_isa_cr_reg_imm($src)],
[MOpRegNum::power_isa_cr_reg_imm($src)], 0i8.cast_to_static::<SInt<_>>(),
0i8.cast_to_static::<SInt<_>>(), ),
)
},
)); ));
}; };
} }

View file

@ -7,7 +7,10 @@ use fayalite::prelude::*;
/// covers instructions in PowerISA v3.1C Book I 3.3.9 Fixed-Point Arithmetic Instructions /// covers instructions in PowerISA v3.1C Book I 3.3.9 Fixed-Point Arithmetic Instructions
pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>) { pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>) {
retval.push(insn_single("addi 3, 4, 0x1234", 0x38641234, None, || { retval.push(insn_single(
"addi 3, 4, 0x1234",
0x38641234,
None,
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[MOpRegNum::power_isa_gpr_reg_imm(4), MOpRegNum::const_zero()], [MOpRegNum::power_isa_gpr_reg_imm(4), MOpRegNum::const_zero()],
@ -17,43 +20,42 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
false, false,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single( retval.push(insn_single(
"paddi 3, 4, 0x123456789, 0", "paddi 3, 4, 0x123456789, 0",
0x06012345, 0x06012345,
Some(0x38646789), Some(0x38646789),
|| { AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), [MOpRegNum::power_isa_gpr_reg_imm(4), MOpRegNum::const_zero()],
[MOpRegNum::power_isa_gpr_reg_imm(4), MOpRegNum::const_zero()], 0x123456789i64.cast_to_static::<SInt<_>>(),
0x123456789i64.cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, false,
false, ),
)
},
)); ));
retval.push(insn_single( retval.push(insn_single(
"paddi 3, 0, 0x123456789, 1", "paddi 3, 0, 0x123456789, 1",
0x06112345, 0x06112345,
Some(0x38606789), Some(0x38606789),
|| { AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), [MOpRegNum::const_zero(), MOpRegNum::const_zero()],
[MOpRegNum::const_zero(), MOpRegNum::const_zero()], 0x123456789i64.cast_to_static::<SInt<_>>(),
0x123456789i64.cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, true,
true, ),
)
},
)); ));
retval.push(insn_single("addis 3, 4, 0x1234", 0x3C641234, None, || { retval.push(insn_single(
"addis 3, 4, 0x1234",
0x3C641234,
None,
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[MOpRegNum::power_isa_gpr_reg_imm(4), MOpRegNum::const_zero()], [MOpRegNum::power_isa_gpr_reg_imm(4), MOpRegNum::const_zero()],
@ -63,9 +65,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
false, false,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("addpcis 3, 0x1234", 0x4c7a1204, None, || { retval.push(insn_single(
"addpcis 3, 0x1234",
0x4c7a1204,
None,
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[MOpRegNum::const_zero(); _], [MOpRegNum::const_zero(); _],
@ -75,9 +80,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
false, false,
false, false,
true, true,
) ),
})); ));
retval.push(insn_single("add. 3, 4, 5", 0x7c642a15, None, || { retval.push(insn_single(
"add. 3, 4, 5",
0x7c642a15,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[MOpRegNum::power_isa_gpr_reg_num(3)], &[MOpRegNum::power_isa_gpr_reg_num(3)],
@ -94,9 +102,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
false, false,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("addic. 3, 4, 0x1234", 0x34641234, None, || { retval.push(insn_single(
"addic. 3, 4, 0x1234",
0x34641234,
None,
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[ &[
@ -112,9 +123,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
false, false,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("subf. 3, 4, 5", 0x7c642851, None, || { retval.push(insn_single(
"subf. 3, 4, 5",
0x7c642851,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[MOpRegNum::power_isa_gpr_reg_num(3)], &[MOpRegNum::power_isa_gpr_reg_num(3)],
@ -131,9 +145,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
false, false,
true, true,
false, false,
) ),
})); ));
retval.push(insn_single("subfic 3, 4, 0x1234", 0x20641234, None, || { retval.push(insn_single(
"subfic 3, 4, 0x1234",
0x20641234,
None,
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[ &[
@ -149,9 +166,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
false, false,
true, true,
false, false,
) ),
})); ));
retval.push(insn_single("addc. 3, 4, 5", 0x7c642815, None, || { retval.push(insn_single(
"addc. 3, 4, 5",
0x7c642815,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[ &[
@ -171,9 +191,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
false, false,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("subfc. 3, 4, 5", 0x7c642811, None, || { retval.push(insn_single(
"subfc. 3, 4, 5",
0x7c642811,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[ &[
@ -193,9 +216,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
false, false,
true, true,
false, false,
) ),
})); ));
retval.push(insn_single("adde. 3, 4, 5", 0x7c642915, None, || { retval.push(insn_single(
"adde. 3, 4, 5",
0x7c642915,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[ &[
@ -215,9 +241,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
true, true,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("subfe. 3, 4, 5", 0x7c642911, None, || { retval.push(insn_single(
"subfe. 3, 4, 5",
0x7c642911,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[ &[
@ -237,9 +266,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
true, true,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("addme. 3, 4", 0x7c6401d5, None, || { retval.push(insn_single(
"addme. 3, 4",
0x7c6401d5,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[ &[
@ -259,9 +291,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
true, true,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("subfme. 3, 4", 0x7c6401d1, None, || { retval.push(insn_single(
"subfme. 3, 4",
0x7c6401d1,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[ &[
@ -281,9 +316,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
true, true,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("addze. 3, 4", 0x7c640195, None, || { retval.push(insn_single(
"addze. 3, 4",
0x7c640195,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[ &[
@ -303,9 +341,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
true, true,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("subfze. 3, 4", 0x7c640191, None, || { retval.push(insn_single(
"subfze. 3, 4",
0x7c640191,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[ &[
@ -325,9 +366,12 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
true, true,
false, false,
false, false,
) ),
})); ));
retval.push(insn_single("neg. 3, 4", 0x7c6400d1, None, || { retval.push(insn_single(
"neg. 3, 4",
0x7c6400d1,
None,
AddSubMOp::add_sub( AddSubMOp::add_sub(
MOpDestReg::new_sim( MOpDestReg::new_sim(
&[MOpRegNum::power_isa_gpr_reg_num(3)], &[MOpRegNum::power_isa_gpr_reg_num(3)],
@ -344,6 +388,6 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
false, false,
true, true,
false, false,
) ),
})); ));
} }

View file

@ -11,29 +11,28 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
"cmpi 3, 0, 4, 0x1234", "cmpi 3, 0, 4, 0x1234",
0x2d841234, 0x2d841234,
None, None,
|| { CompareMOp::compare_i(
CompareMOp::compare_i( MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), [MOpRegNum::power_isa_gpr_reg_imm(4)],
[MOpRegNum::power_isa_gpr_reg_imm(4)], 0x1234.cast_to_static::<SInt<_>>(),
0x1234.cast_to_static::<SInt<_>>(), CompareMode.S32(),
CompareMode.S32(), ),
)
},
)); ));
retval.push(insn_single( retval.push(insn_single(
"cmpi 3, 1, 4, -0x7655", "cmpi 3, 1, 4, -0x7655",
0x2da489ab, 0x2da489ab,
None, None,
|| { CompareMOp::compare_i(
CompareMOp::compare_i( MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), [MOpRegNum::power_isa_gpr_reg_imm(4)],
[MOpRegNum::power_isa_gpr_reg_imm(4)], (0x89abu16 as i16).cast_to_static::<SInt<_>>(),
(0x89abu16 as i16).cast_to_static::<SInt<_>>(), CompareMode.S64(),
CompareMode.S64(), ),
)
},
)); ));
retval.push(insn_single("cmp 3, 0, 4, 5", 0x7d842800, None, || { retval.push(insn_single(
"cmp 3, 0, 4, 5",
0x7d842800,
None,
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[ [
@ -41,9 +40,12 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
MOpRegNum::power_isa_gpr_reg_imm(5), MOpRegNum::power_isa_gpr_reg_imm(5),
], ],
CompareMode.S32(), CompareMode.S32(),
) ),
})); ));
retval.push(insn_single("cmp 3, 1, 4, 5", 0x7da42800, None, || { retval.push(insn_single(
"cmp 3, 1, 4, 5",
0x7da42800,
None,
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[ [
@ -51,35 +53,34 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
MOpRegNum::power_isa_gpr_reg_imm(5), MOpRegNum::power_isa_gpr_reg_imm(5),
], ],
CompareMode.S64(), CompareMode.S64(),
) ),
})); ));
retval.push(insn_single( retval.push(insn_single(
"cmpli 3, 0, 4, 0x1234", "cmpli 3, 0, 4, 0x1234",
0x29841234, 0x29841234,
None, None,
|| { CompareMOp::compare_i(
CompareMOp::compare_i( MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), [MOpRegNum::power_isa_gpr_reg_imm(4)],
[MOpRegNum::power_isa_gpr_reg_imm(4)], 0x1234.cast_to_static::<SInt<_>>(),
0x1234.cast_to_static::<SInt<_>>(), CompareMode.U32(),
CompareMode.U32(), ),
)
},
)); ));
retval.push(insn_single( retval.push(insn_single(
"cmpli 3, 1, 4, 0x89ab", "cmpli 3, 1, 4, 0x89ab",
0x29a489ab, 0x29a489ab,
None, None,
|| { CompareMOp::compare_i(
CompareMOp::compare_i( MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), [MOpRegNum::power_isa_gpr_reg_imm(4)],
[MOpRegNum::power_isa_gpr_reg_imm(4)], 0x89ab.cast_to_static::<SInt<_>>(),
0x89ab.cast_to_static::<SInt<_>>(), CompareMode.U64(),
CompareMode.U64(), ),
)
},
)); ));
retval.push(insn_single("cmpl 3, 0, 4, 5", 0x7d842840, None, || { retval.push(insn_single(
"cmpl 3, 0, 4, 5",
0x7d842840,
None,
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[ [
@ -87,9 +88,12 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
MOpRegNum::power_isa_gpr_reg_imm(5), MOpRegNum::power_isa_gpr_reg_imm(5),
], ],
CompareMode.U32(), CompareMode.U32(),
) ),
})); ));
retval.push(insn_single("cmpl 3, 1, 4, 5", 0x7da42840, None, || { retval.push(insn_single(
"cmpl 3, 1, 4, 5",
0x7da42840,
None,
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[ [
@ -97,9 +101,12 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
MOpRegNum::power_isa_gpr_reg_imm(5), MOpRegNum::power_isa_gpr_reg_imm(5),
], ],
CompareMode.U64(), CompareMode.U64(),
) ),
})); ));
retval.push(insn_single("cmprb 3, 0, 4, 5", 0x7d842980, None, || { retval.push(insn_single(
"cmprb 3, 0, 4, 5",
0x7d842980,
None,
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[ [
@ -107,9 +114,12 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
MOpRegNum::power_isa_gpr_reg_imm(5), MOpRegNum::power_isa_gpr_reg_imm(5),
], ],
CompareMode.CmpRBOne(), CompareMode.CmpRBOne(),
) ),
})); ));
retval.push(insn_single("cmprb 3, 1, 4, 5", 0x7da42980, None, || { retval.push(insn_single(
"cmprb 3, 1, 4, 5",
0x7da42980,
None,
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[ [
@ -117,9 +127,12 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
MOpRegNum::power_isa_gpr_reg_imm(5), MOpRegNum::power_isa_gpr_reg_imm(5),
], ],
CompareMode.CmpRBTwo(), CompareMode.CmpRBTwo(),
) ),
})); ));
retval.push(insn_single("cmpeqb 3, 4, 5", 0x7d8429c0, None, || { retval.push(insn_single(
"cmpeqb 3, 4, 5",
0x7d8429c0,
None,
CompareMOp::compare( CompareMOp::compare(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[ [
@ -127,6 +140,6 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
MOpRegNum::power_isa_gpr_reg_imm(5), MOpRegNum::power_isa_gpr_reg_imm(5),
], ],
CompareMode.CmpEqB(), CompareMode.CmpEqB(),
) ),
})); ));
} }

View file

@ -21,33 +21,31 @@ pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, "), ", $r), concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, "), ", $r),
$prefix, $prefix,
Some($suffix), Some($suffix),
|| { [
[ AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]), [
[ if $r != 0 || $ra == 0 {
if $r != 0 || $ra == 0 { MOpRegNum::const_zero()
MOpRegNum::const_zero() } else {
} else { MOpRegNum::power_isa_gpr_reg_imm($ra)
MOpRegNum::power_isa_gpr_reg_imm($ra) },
}, MOpRegNum::const_zero(),
MOpRegNum::const_zero(), ],
], ($disp as i64).cast_to_static::<SInt<_>>(),
($disp as i64).cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, $r != 0,
$r != 0, ),
), LoadMOp::load(
LoadMOp::load( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]), [MOpRegNum::power_isa_temp_reg()],
[MOpRegNum::power_isa_temp_reg()], LoadStoreWidth.$width(),
LoadStoreWidth.$width(), LoadStoreConversion.$conversion(),
LoadStoreConversion.$conversion(), ),
), ],
]
},
)); ));
}; };
} }
@ -62,33 +60,31 @@ pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, ")"), concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, ")"),
$encoding, $encoding,
None, None,
|| { [
[ AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]), [
[ if $ra == 0 {
if $ra == 0 { MOpRegNum::const_zero()
MOpRegNum::const_zero() } else {
} else { MOpRegNum::power_isa_gpr_reg_imm($ra)
MOpRegNum::power_isa_gpr_reg_imm($ra) },
}, MOpRegNum::const_zero(),
MOpRegNum::const_zero(), ],
], ($disp as i64).cast_to_static::<SInt<_>>(),
($disp as i64).cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, false,
false, ),
), LoadMOp::load(
LoadMOp::load( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]), [MOpRegNum::power_isa_temp_reg()],
[MOpRegNum::power_isa_temp_reg()], LoadStoreWidth.$width(),
LoadStoreWidth.$width(), LoadStoreConversion.$conversion(),
LoadStoreConversion.$conversion(), ),
), ],
]
},
)); ));
}; };
} }
@ -103,29 +99,27 @@ pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, ")"), concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, ")"),
$encoding, $encoding,
None, None,
|| { [
[ AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]), [
[ MOpRegNum::power_isa_gpr_reg_imm($ra),
MOpRegNum::power_isa_gpr_reg_imm($ra), MOpRegNum::const_zero(),
MOpRegNum::const_zero(), ],
], ($disp as i64).cast_to_static::<SInt<_>>(),
($disp as i64).cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, false,
false, ),
), LoadMOp::load(
LoadMOp::load( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]), [MOpRegNum::power_isa_gpr_reg_imm($ra)],
[MOpRegNum::power_isa_gpr_reg_imm($ra)], LoadStoreWidth.$width(),
LoadStoreWidth.$width(), LoadStoreConversion.$conversion(),
LoadStoreConversion.$conversion(), ),
), ],
]
},
)); ));
}; };
} }
@ -140,33 +134,31 @@ pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " ", $dest, ", ", $ra, ", ", $rb), concat!($mnemonic, " ", $dest, ", ", $ra, ", ", $rb),
$encoding, $encoding,
None, None,
|| { [
[ AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]), [
[ if $ra == 0 {
if $ra == 0 { MOpRegNum::const_zero()
MOpRegNum::const_zero() } else {
} else { MOpRegNum::power_isa_gpr_reg_imm($ra)
MOpRegNum::power_isa_gpr_reg_imm($ra) },
}, MOpRegNum::power_isa_gpr_reg_imm($rb),
MOpRegNum::power_isa_gpr_reg_imm($rb), ],
], 0.cast_to_static::<SInt<_>>(),
0.cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, false,
false, ),
), LoadMOp::load(
LoadMOp::load( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]), [MOpRegNum::power_isa_temp_reg()],
[MOpRegNum::power_isa_temp_reg()], LoadStoreWidth.$width(),
LoadStoreWidth.$width(), LoadStoreConversion.$conversion(),
LoadStoreConversion.$conversion(), ),
), ],
]
},
)); ));
}; };
} }
@ -181,29 +173,27 @@ pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " ", $dest, ", ", $ra, ", ", $rb), concat!($mnemonic, " ", $dest, ", ", $ra, ", ", $rb),
$encoding, $encoding,
None, None,
|| { [
[ AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]), [
[ MOpRegNum::power_isa_gpr_reg_imm($ra),
MOpRegNum::power_isa_gpr_reg_imm($ra), MOpRegNum::power_isa_gpr_reg_imm($rb),
MOpRegNum::power_isa_gpr_reg_imm($rb), ],
], 0.cast_to_static::<SInt<_>>(),
0.cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, false,
false, ),
), LoadMOp::load(
LoadMOp::load( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]), [MOpRegNum::power_isa_gpr_reg_imm($ra)],
[MOpRegNum::power_isa_gpr_reg_imm($ra)], LoadStoreWidth.$width(),
LoadStoreWidth.$width(), LoadStoreConversion.$conversion(),
LoadStoreConversion.$conversion(), ),
), ],
]
},
)); ));
}; };
} }

View file

@ -25,23 +25,21 @@ pub fn test_cases_book_i_3_3_13_fixed_point_logical(retval: &mut Vec<TestCase>)
), ),
$encoding, $encoding,
None, None,
|| { LogicalMOp::logical_i(
LogicalMOp::logical_i( MOpDestReg::new_sim(
MOpDestReg::new_sim( &[MOpRegNum::power_isa_gpr_reg_num($dest)],
&[MOpRegNum::power_isa_gpr_reg_num($dest)], if $mnemonic.contains('.') {
if $mnemonic.contains('.') { &[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM] } else {
} else { &[]
&[] },
}, ),
), [MOpRegNum::power_isa_gpr_reg_imm($src)],
[MOpRegNum::power_isa_gpr_reg_imm($src)], (($imm as u32) << if $mnemonic.contains('s') { 16 } else { 0 })
(($imm as u32) << if $mnemonic.contains('s') { 16 } else { 0 }) .cast_to_static::<SInt<_>>(),
.cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), Lut4::from_fn(|$a, $b| $lut_fn),
Lut4::from_fn(|$a, $b| $lut_fn), ),
)
},
)); ));
}; };
} }
@ -100,25 +98,23 @@ pub fn test_cases_book_i_3_3_13_fixed_point_logical(retval: &mut Vec<TestCase>)
), ),
$encoding, $encoding,
None, None,
|| { LogicalMOp::logical(
LogicalMOp::logical( MOpDestReg::new_sim(
MOpDestReg::new_sim( &[MOpRegNum::power_isa_gpr_reg_num($dest)],
&[MOpRegNum::power_isa_gpr_reg_num($dest)], if $mnemonic.contains('.') {
if $mnemonic.contains('.') { &[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM] } else {
} else { &[]
&[] },
}, ),
), [
[ MOpRegNum::power_isa_gpr_reg_imm($src0),
MOpRegNum::power_isa_gpr_reg_imm($src0), MOpRegNum::power_isa_gpr_reg_imm($src1),
MOpRegNum::power_isa_gpr_reg_imm($src1), ],
], 0.cast_to_static::<SInt<_>>(),
0.cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), Lut4::from_fn(|$a, $b| $lut_fn),
Lut4::from_fn(|$a, $b| $lut_fn), ),
)
},
)); ));
}; };
} }
@ -161,13 +157,11 @@ pub fn test_cases_book_i_3_3_13_fixed_point_logical(retval: &mut Vec<TestCase>)
"or 3, 4, 4", // mr 3, 4 "or 3, 4, 4", // mr 3, 4
0x7c832378, 0x7c832378,
None, None,
|| { MoveRegMOp::move_reg(
MoveRegMOp::move_reg( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), [MOpRegNum::power_isa_gpr_reg_imm(4)],
[MOpRegNum::power_isa_gpr_reg_imm(4)], 0.cast_to_static::<SInt<_>>(),
0.cast_to_static::<SInt<_>>(), ),
)
},
)); ));
insn_logic! { insn_logic! {
"or." 3, 4, 5; "or." 3, 4, 5;
@ -229,22 +223,20 @@ pub fn test_cases_book_i_3_3_13_fixed_point_logical(retval: &mut Vec<TestCase>)
concat!($mnemonic, " ", stringify!($dest), ", ", stringify!($src)), concat!($mnemonic, " ", stringify!($dest), ", ", stringify!($src)),
$encoding, $encoding,
None, None,
|| { LogicalMOp::logical_i(
LogicalMOp::logical_i( MOpDestReg::new_sim(
MOpDestReg::new_sim( &[MOpRegNum::power_isa_gpr_reg_num($dest)],
&[MOpRegNum::power_isa_gpr_reg_num($dest)], if $mnemonic.contains('.') {
if $mnemonic.contains('.') { &[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM] } else {
} else { &[]
&[] },
}, ),
), [MOpRegNum::power_isa_gpr_reg_imm($src)],
[MOpRegNum::power_isa_gpr_reg_imm($src)], 0.cast_to_static::<SInt<_>>(),
0.cast_to_static::<SInt<_>>(), OutputIntegerMode.$OutputIntegerMode(),
OutputIntegerMode.$OutputIntegerMode(), Lut4::from_fn(|a, b| a | b),
Lut4::from_fn(|a, b| a | b), ),
)
},
)); ));
}; };
} }

View file

@ -105,7 +105,7 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding, $encoding,
None, None,
|| ShiftRotateMOp::shift_rotate( ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
[ [
MOpRegNum::power_isa_gpr_reg_imm($src), MOpRegNum::power_isa_gpr_reg_imm($src),
@ -131,7 +131,7 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding | 1, $encoding | 1,
None, None,
|| ShiftRotateMOp::shift_rotate( ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],), MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],),
[ [
MOpRegNum::power_isa_gpr_reg_imm($src), MOpRegNum::power_isa_gpr_reg_imm($src),
@ -168,7 +168,7 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding, $encoding,
None, None,
|| ShiftRotateMOp::shift_rotate( ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
[ [
MOpRegNum::power_isa_gpr_reg_imm($src), MOpRegNum::power_isa_gpr_reg_imm($src),
@ -199,7 +199,7 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding | 1, $encoding | 1,
None, None,
|| ShiftRotateMOp::shift_rotate( ShiftRotateMOp::shift_rotate(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],), MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],),
[ [
MOpRegNum::power_isa_gpr_reg_imm($src), MOpRegNum::power_isa_gpr_reg_imm($src),
@ -855,23 +855,21 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding, $encoding,
None, None,
|| { ShiftRotateMOp::shift_rotate(
ShiftRotateMOp::shift_rotate( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
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(),
MOpRegNum::const_zero(), MOpRegNum::power_isa_gpr_reg_imm($amount),
MOpRegNum::power_isa_gpr_reg_imm($amount), ],
], shift_imm(
shift_imm( None,
None, false,
false, ShiftAmountOverflowBehavior.$overflow_behavior(),
ShiftAmountOverflowBehavior.$overflow_behavior(), ),
), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), ShiftRotateMode.$shift_rotate_mode(),
ShiftRotateMode.$shift_rotate_mode(), ),
)
},
)); ));
retval.push(insn_single( retval.push(insn_single(
concat!( concat!(
@ -885,26 +883,24 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding | 1, $encoding | 1,
None, None,
|| { ShiftRotateMOp::shift_rotate(
ShiftRotateMOp::shift_rotate( MOpDestReg::new_sim(
MOpDestReg::new_sim( &[MOpRegNum::power_isa_gpr_reg_num($dest)],
&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM], ),
), [
[ MOpRegNum::power_isa_gpr_reg_imm($src),
MOpRegNum::power_isa_gpr_reg_imm($src), MOpRegNum::const_zero(),
MOpRegNum::const_zero(), MOpRegNum::power_isa_gpr_reg_imm($amount),
MOpRegNum::power_isa_gpr_reg_imm($amount), ],
], shift_imm(
shift_imm( None,
None, false,
false, ShiftAmountOverflowBehavior.$overflow_behavior(),
ShiftAmountOverflowBehavior.$overflow_behavior(), ),
), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), ShiftRotateMode.$shift_rotate_mode(),
ShiftRotateMode.$shift_rotate_mode(), ),
)
},
)); ));
}}; }};
} }
@ -927,19 +923,17 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding, $encoding,
None, None,
|| { ShiftRotateMOp::shift_rotate(
ShiftRotateMOp::shift_rotate( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]), [
[ MOpRegNum::const_zero(),
MOpRegNum::const_zero(), MOpRegNum::power_isa_gpr_reg_imm($src),
MOpRegNum::power_isa_gpr_reg_imm($src), MOpRegNum::power_isa_gpr_reg_imm($amount),
MOpRegNum::power_isa_gpr_reg_imm($amount), ],
], shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()),
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), ShiftRotateMode.$shift_rotate_mode(),
ShiftRotateMode.$shift_rotate_mode(), ),
)
},
)); ));
retval.push(insn_single( retval.push(insn_single(
concat!( concat!(
@ -953,22 +947,20 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding | 1, $encoding | 1,
None, None,
|| { ShiftRotateMOp::shift_rotate(
ShiftRotateMOp::shift_rotate( MOpDestReg::new_sim(
MOpDestReg::new_sim( &[MOpRegNum::power_isa_gpr_reg_num($dest)],
&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM], ),
), [
[ MOpRegNum::const_zero(),
MOpRegNum::const_zero(), MOpRegNum::power_isa_gpr_reg_imm($src),
MOpRegNum::power_isa_gpr_reg_imm($src), MOpRegNum::power_isa_gpr_reg_imm($amount),
MOpRegNum::power_isa_gpr_reg_imm($amount), ],
], shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()),
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), ShiftRotateMode.$shift_rotate_mode(),
ShiftRotateMode.$shift_rotate_mode(), ),
)
},
)); ));
}}; }};
} }
@ -991,25 +983,23 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding, $encoding,
None, None,
|| { ShiftRotateMOp::shift_rotate(
ShiftRotateMOp::shift_rotate( MOpDestReg::new_sim(
MOpDestReg::new_sim( &[
&[ MOpRegNum::power_isa_gpr_reg_num($dest),
MOpRegNum::power_isa_gpr_reg_num($dest), MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[],
),
[
MOpRegNum::power_isa_gpr_reg_imm($src),
MOpRegNum::const_zero(),
MOpRegNum::power_isa_gpr_reg_imm($amount),
], ],
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()), &[],
OutputIntegerMode.Full64(), ),
ShiftRotateMode.$shift_rotate_mode(), [
) MOpRegNum::power_isa_gpr_reg_imm($src),
}, MOpRegNum::const_zero(),
MOpRegNum::power_isa_gpr_reg_imm($amount),
],
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
)); ));
retval.push(insn_single( retval.push(insn_single(
concat!( concat!(
@ -1023,25 +1013,23 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding | 1, $encoding | 1,
None, None,
|| { ShiftRotateMOp::shift_rotate(
ShiftRotateMOp::shift_rotate( MOpDestReg::new_sim(
MOpDestReg::new_sim( &[
&[ MOpRegNum::power_isa_gpr_reg_num($dest),
MOpRegNum::power_isa_gpr_reg_num($dest), MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg_imm($src),
MOpRegNum::const_zero(),
MOpRegNum::power_isa_gpr_reg_imm($amount),
], ],
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()), &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
OutputIntegerMode.Full64(), ),
ShiftRotateMode.$shift_rotate_mode(), [
) MOpRegNum::power_isa_gpr_reg_imm($src),
}, MOpRegNum::const_zero(),
MOpRegNum::power_isa_gpr_reg_imm($amount),
],
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
)); ));
}}; }};
} }
@ -1063,29 +1051,27 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding, $encoding,
None, None,
|| { ShiftRotateMOp::shift_rotate(
ShiftRotateMOp::shift_rotate( MOpDestReg::new_sim(
MOpDestReg::new_sim( &[
&[ MOpRegNum::power_isa_gpr_reg_num($dest),
MOpRegNum::power_isa_gpr_reg_num($dest), MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[],
),
[
MOpRegNum::power_isa_gpr_reg_imm($src),
MOpRegNum::const_zero(),
MOpRegNum::const_zero(),
], ],
shift_imm( &[],
Some($amount), ),
true, [
ShiftAmountOverflowBehavior.WrapToUInt6(), MOpRegNum::power_isa_gpr_reg_imm($src),
), MOpRegNum::const_zero(),
OutputIntegerMode.Full64(), MOpRegNum::const_zero(),
ShiftRotateMode.$shift_rotate_mode(), ],
) shift_imm(
}, Some($amount),
true,
ShiftAmountOverflowBehavior.WrapToUInt6(),
),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
)); ));
retval.push(insn_single( retval.push(insn_single(
concat!( concat!(
@ -1099,29 +1085,27 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding | 1, $encoding | 1,
None, None,
|| { ShiftRotateMOp::shift_rotate(
ShiftRotateMOp::shift_rotate( MOpDestReg::new_sim(
MOpDestReg::new_sim( &[
&[ MOpRegNum::power_isa_gpr_reg_num($dest),
MOpRegNum::power_isa_gpr_reg_num($dest), MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
),
[
MOpRegNum::power_isa_gpr_reg_imm($src),
MOpRegNum::const_zero(),
MOpRegNum::const_zero(),
], ],
shift_imm( &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
Some($amount), ),
true, [
ShiftAmountOverflowBehavior.WrapToUInt6(), MOpRegNum::power_isa_gpr_reg_imm($src),
), MOpRegNum::const_zero(),
OutputIntegerMode.Full64(), MOpRegNum::const_zero(),
ShiftRotateMode.$shift_rotate_mode(), ],
) shift_imm(
}, Some($amount),
true,
ShiftAmountOverflowBehavior.WrapToUInt6(),
),
OutputIntegerMode.Full64(),
ShiftRotateMode.$shift_rotate_mode(),
),
)); ));
}}; }};
} }
@ -1228,23 +1212,21 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding, $encoding,
None, None,
|| { ShiftRotateMOp::shift_rotate(
ShiftRotateMOp::shift_rotate( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
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(),
MOpRegNum::const_zero(), MOpRegNum::const_zero(),
MOpRegNum::const_zero(), ],
], shift_imm(
shift_imm( Some($amount),
Some($amount), false,
false, ShiftAmountOverflowBehavior.WrapToUInt6(),
ShiftAmountOverflowBehavior.WrapToUInt6(), ),
), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), ShiftRotateMode.SignExt32To64BitThenShift(),
ShiftRotateMode.SignExt32To64BitThenShift(), ),
)
},
)); ));
retval.push(insn_single( retval.push(insn_single(
concat!( concat!(
@ -1258,26 +1240,24 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
), ),
$encoding | 1, $encoding | 1,
None, None,
|| { ShiftRotateMOp::shift_rotate(
ShiftRotateMOp::shift_rotate( MOpDestReg::new_sim(
MOpDestReg::new_sim( &[MOpRegNum::power_isa_gpr_reg_num($dest)],
&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM], ),
), [
[ MOpRegNum::power_isa_gpr_reg_imm($src),
MOpRegNum::power_isa_gpr_reg_imm($src), MOpRegNum::const_zero(),
MOpRegNum::const_zero(), MOpRegNum::const_zero(),
MOpRegNum::const_zero(), ],
], shift_imm(
shift_imm( Some($amount),
Some($amount), false,
false, ShiftAmountOverflowBehavior.WrapToUInt6(),
ShiftAmountOverflowBehavior.WrapToUInt6(), ),
), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), ShiftRotateMode.SignExt32To64BitThenShift(),
ShiftRotateMode.SignExt32To64BitThenShift(), ),
)
},
)); ));
}}; }};
} }

View file

@ -20,36 +20,34 @@ pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, "), ", $r), concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, "), ", $r),
$prefix, $prefix,
Some($suffix), Some($suffix),
|| { [
[ AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]), [
[ if $r != 0 || $ra == 0 {
if $r != 0 || $ra == 0 { MOpRegNum::const_zero()
MOpRegNum::const_zero() } else {
} else { MOpRegNum::power_isa_gpr_reg_imm($ra)
MOpRegNum::power_isa_gpr_reg_imm($ra) },
}, MOpRegNum::const_zero(),
MOpRegNum::const_zero(), ],
], ($disp as i64).cast_to_static::<SInt<_>>(),
($disp as i64).cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, $r != 0,
$r != 0, ),
), StoreMOp::store(
StoreMOp::store( MOpDestReg::new_sim(&[], &[]),
MOpDestReg::new_sim(&[], &[]), [
[ MOpRegNum::power_isa_temp_reg(),
MOpRegNum::power_isa_temp_reg(), MOpRegNum::power_isa_gpr_reg_imm($rs),
MOpRegNum::power_isa_gpr_reg_imm($rs), ],
], LoadStoreWidth.$width(),
LoadStoreWidth.$width(), LoadStoreConversion.ZeroExt(),
LoadStoreConversion.ZeroExt(), ),
), ],
]
},
)); ));
}; };
} }
@ -63,36 +61,34 @@ pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"), concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
$encoding, $encoding,
None, None,
|| { [
[ AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]), [
[ if $ra == 0 {
if $ra == 0 { MOpRegNum::const_zero()
MOpRegNum::const_zero() } else {
} else { MOpRegNum::power_isa_gpr_reg_imm($ra)
MOpRegNum::power_isa_gpr_reg_imm($ra) },
}, MOpRegNum::const_zero(),
MOpRegNum::const_zero(), ],
], ($disp as i64).cast_to_static::<SInt<_>>(),
($disp as i64).cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, false,
false, ),
), StoreMOp::store(
StoreMOp::store( MOpDestReg::new_sim(&[], &[]),
MOpDestReg::new_sim(&[], &[]), [
[ MOpRegNum::power_isa_temp_reg(),
MOpRegNum::power_isa_temp_reg(), MOpRegNum::power_isa_gpr_reg_imm($rs),
MOpRegNum::power_isa_gpr_reg_imm($rs), ],
], LoadStoreWidth.$width(),
LoadStoreWidth.$width(), LoadStoreConversion.ZeroExt(),
LoadStoreConversion.ZeroExt(), ),
), ],
]
},
)); ));
}; };
} }
@ -107,69 +103,65 @@ pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"), concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
$encoding, $encoding,
None, None,
|| { [
[ AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]), [
[ MOpRegNum::power_isa_gpr_reg_imm($ra),
MOpRegNum::power_isa_gpr_reg_imm($ra), MOpRegNum::const_zero(),
MOpRegNum::const_zero(), ],
], ($disp as i64).cast_to_static::<SInt<_>>(),
($disp as i64).cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, false,
false, ),
), StoreMOp::store(
StoreMOp::store( MOpDestReg::new_sim(&[], &[]),
MOpDestReg::new_sim(&[], &[]), [
[ MOpRegNum::power_isa_temp_reg(),
MOpRegNum::power_isa_temp_reg(), MOpRegNum::power_isa_gpr_reg_imm($rs),
MOpRegNum::power_isa_gpr_reg_imm($rs), ],
], LoadStoreWidth.$width(),
LoadStoreWidth.$width(), LoadStoreConversion.ZeroExt(),
LoadStoreConversion.ZeroExt(), ),
), MoveRegMOp::move_reg(
MoveRegMOp::move_reg( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]), [MOpRegNum::power_isa_temp_reg()],
[MOpRegNum::power_isa_temp_reg()], 0.cast_to_static::<SInt<_>>(),
0.cast_to_static::<SInt<_>>(), ),
), ],
]
},
)); ));
} else { } else {
retval.push(insn_double( retval.push(insn_double(
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"), concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
$encoding, $encoding,
None, None,
|| { [
[ AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]), [
[ MOpRegNum::power_isa_gpr_reg_imm($ra),
MOpRegNum::power_isa_gpr_reg_imm($ra), MOpRegNum::const_zero(),
MOpRegNum::const_zero(), ],
], ($disp as i64).cast_to_static::<SInt<_>>(),
($disp as i64).cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, false,
false, ),
), StoreMOp::store(
StoreMOp::store( MOpDestReg::new_sim(&[], &[]),
MOpDestReg::new_sim(&[], &[]), [
[ MOpRegNum::power_isa_gpr_reg_imm($ra),
MOpRegNum::power_isa_gpr_reg_imm($ra), MOpRegNum::power_isa_gpr_reg_imm($rs),
MOpRegNum::power_isa_gpr_reg_imm($rs), ],
], LoadStoreWidth.$width(),
LoadStoreWidth.$width(), LoadStoreConversion.ZeroExt(),
LoadStoreConversion.ZeroExt(), ),
), ],
]
},
)); ));
} }
}; };
@ -184,16 +176,53 @@ pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb), concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
$encoding, $encoding,
None, None,
|| { [
AddSubMOp::add_sub_i(
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
[
if $ra == 0 {
MOpRegNum::const_zero()
} else {
MOpRegNum::power_isa_gpr_reg_imm($ra)
},
MOpRegNum::power_isa_gpr_reg_imm($rb),
],
0.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($rs),
],
LoadStoreWidth.$width(),
LoadStoreConversion.ZeroExt(),
),
],
));
};
}
macro_rules! store_update_indexed {
(
$mnemonic:literal $rs:literal, $ra:literal, $rb:literal;
$encoding:literal;
$width:ident;
) => {
if $ra == $rs {
retval.push(insn_triple(
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
$encoding,
None,
[ [
AddSubMOp::add_sub_i( AddSubMOp::add_sub_i(
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]), MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
[ [
if $ra == 0 { MOpRegNum::power_isa_gpr_reg_imm($ra),
MOpRegNum::const_zero()
} else {
MOpRegNum::power_isa_gpr_reg_imm($ra)
},
MOpRegNum::power_isa_gpr_reg_imm($rb), MOpRegNum::power_isa_gpr_reg_imm($rb),
], ],
0.cast_to_static::<SInt<_>>(), 0.cast_to_static::<SInt<_>>(),
@ -212,89 +241,46 @@ pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
LoadStoreWidth.$width(), LoadStoreWidth.$width(),
LoadStoreConversion.ZeroExt(), LoadStoreConversion.ZeroExt(),
), ),
] MoveRegMOp::move_reg(
}, MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
)); [MOpRegNum::power_isa_temp_reg()],
}; 0.cast_to_static::<SInt<_>>(),
} ),
macro_rules! store_update_indexed { ],
(
$mnemonic:literal $rs:literal, $ra:literal, $rb:literal;
$encoding:literal;
$width:ident;
) => {
if $ra == $rs {
retval.push(insn_triple(
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
$encoding,
None,
|| {
[
AddSubMOp::add_sub_i(
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
[
MOpRegNum::power_isa_gpr_reg_imm($ra),
MOpRegNum::power_isa_gpr_reg_imm($rb),
],
0.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($rs),
],
LoadStoreWidth.$width(),
LoadStoreConversion.ZeroExt(),
),
MoveRegMOp::move_reg(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
[MOpRegNum::power_isa_temp_reg()],
0.cast_to_static::<SInt<_>>(),
),
]
},
)); ));
} else { } else {
retval.push(insn_double( retval.push(insn_double(
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb), concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
$encoding, $encoding,
None, None,
|| { [
[ AddSubMOp::add_sub_i(
AddSubMOp::add_sub_i( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]), [
[ if $ra == 0 {
if $ra == 0 { MOpRegNum::const_zero()
MOpRegNum::const_zero() } else {
} else { MOpRegNum::power_isa_gpr_reg_imm($ra)
MOpRegNum::power_isa_gpr_reg_imm($ra) },
}, MOpRegNum::power_isa_gpr_reg_imm($rb),
MOpRegNum::power_isa_gpr_reg_imm($rb), ],
], 0.cast_to_static::<SInt<_>>(),
0.cast_to_static::<SInt<_>>(), OutputIntegerMode.Full64(),
OutputIntegerMode.Full64(), false,
false, false,
false, false,
false, false,
false, ),
), StoreMOp::store(
StoreMOp::store( MOpDestReg::new_sim(&[], &[]),
MOpDestReg::new_sim(&[], &[]), [
[ MOpRegNum::power_isa_gpr_reg_imm($ra),
MOpRegNum::power_isa_gpr_reg_imm($ra), MOpRegNum::power_isa_gpr_reg_imm($rs),
MOpRegNum::power_isa_gpr_reg_imm($rs), ],
], LoadStoreWidth.$width(),
LoadStoreWidth.$width(), LoadStoreConversion.ZeroExt(),
LoadStoreConversion.ZeroExt(), ),
), ],
]
},
)); ));
} }
}; };

View file

@ -23,7 +23,10 @@ pub fn test_cases_book_i_3_3_19_move_to_from_system_register(retval: &mut Vec<Te
dest_count: 6usize.cast_to(LogicalFlagsMOpImm.dest_count), dest_count: 6usize.cast_to(LogicalFlagsMOpImm.dest_count),
} }
} }
retval.push(insn_single("mcrxrx 3", 0x7d800480, None, || { retval.push(insn_single(
"mcrxrx 3",
0x7d800480,
None,
LogicalFlagsMOp::logical_flags( LogicalFlagsMOp::logical_flags(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
[ [
@ -33,114 +36,114 @@ pub fn test_cases_book_i_3_3_19_move_to_from_system_register(retval: &mut Vec<Te
], ],
mcrxrx_imm(), mcrxrx_imm(),
Lut4::from_fn(|a, b| a | b), Lut4::from_fn(|a, b| a | b),
) ),
})); ));
} }
/// covers instructions in PowerISA v3.1C Book III 5.4.4 Move To/From System Register Instructions /// covers instructions in PowerISA v3.1C Book III 5.4.4 Move To/From System Register Instructions
pub fn test_cases_book_iii_5_4_4_move_to_from_system_register(retval: &mut Vec<TestCase>) { pub fn test_cases_book_iii_5_4_4_move_to_from_system_register(retval: &mut Vec<TestCase>) {
retval.push(insn_single("mflr 3", 0x7c6802a6, None, || { retval.push(insn_single(
"mflr 3",
0x7c6802a6,
None,
MoveRegMOp::move_reg( MoveRegMOp::move_reg(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[MOpRegNum::power_isa_lr_reg()], [MOpRegNum::power_isa_lr_reg()],
0.cast_to_static::<SInt<_>>(), 0.cast_to_static::<SInt<_>>(),
) ),
})); ));
retval.push(insn_single("mtlr 3", 0x7c6803a6, None, || { retval.push(insn_single(
"mtlr 3",
0x7c6803a6,
None,
MoveRegMOp::move_reg( MoveRegMOp::move_reg(
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]), MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
[MOpRegNum::power_isa_gpr_reg_imm(3)], [MOpRegNum::power_isa_gpr_reg_imm(3)],
0.cast_to_static::<SInt<_>>(), 0.cast_to_static::<SInt<_>>(),
) ),
})); ));
retval.push(insn_single("mfctr 3", 0x7c6902a6, None, || { retval.push(insn_single(
"mfctr 3",
0x7c6902a6,
None,
MoveRegMOp::move_reg( MoveRegMOp::move_reg(
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
[MOpRegNum::power_isa_ctr_reg()], [MOpRegNum::power_isa_ctr_reg()],
0.cast_to_static::<SInt<_>>(), 0.cast_to_static::<SInt<_>>(),
) ),
})); ));
retval.push(insn_single("mtctr 3", 0x7c6903a6, None, || { retval.push(insn_single(
"mtctr 3",
0x7c6903a6,
None,
MoveRegMOp::move_reg( MoveRegMOp::move_reg(
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_CTR_REG_NUM], &[]), MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_CTR_REG_NUM], &[]),
[MOpRegNum::power_isa_gpr_reg_imm(3)], [MOpRegNum::power_isa_gpr_reg_imm(3)],
0.cast_to_static::<SInt<_>>(), 0.cast_to_static::<SInt<_>>(),
) ),
})); ));
retval.push(insn_single( retval.push(insn_single(
"mfspr 3, 815 # mftar 3", "mfspr 3, 815 # mftar 3",
0x7c6fcaa6, 0x7c6fcaa6,
None, None,
|| { MoveRegMOp::move_reg(
MoveRegMOp::move_reg( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), [MOpRegNum::power_isa_tar_reg()],
[MOpRegNum::power_isa_tar_reg()], 0.cast_to_static::<SInt<_>>(),
0.cast_to_static::<SInt<_>>(), ),
)
},
)); ));
retval.push(insn_single( retval.push(insn_single(
"mtspr 815, 3 # mttar 3", "mtspr 815, 3 # mttar 3",
0x7c6fcba6, 0x7c6fcba6,
None, None,
|| { MoveRegMOp::move_reg(
MoveRegMOp::move_reg( MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TAR_REG_NUM], &[]),
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TAR_REG_NUM], &[]), [MOpRegNum::power_isa_gpr_reg_imm(3)],
[MOpRegNum::power_isa_gpr_reg_imm(3)], 0.cast_to_static::<SInt<_>>(),
0.cast_to_static::<SInt<_>>(), ),
)
},
)); ));
// make sure we generate mfspr and not the phased-out mftb // make sure we generate mfspr and not the phased-out mftb
retval.push(insn_single( retval.push(insn_single(
"mfspr 3, 268 # mftb 3", "mfspr 3, 268 # mftb 3",
0x7c6c42a6, 0x7c6c42a6,
None, None,
|| { ReadSpecialMOp::read_special(
ReadSpecialMOp::read_special( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), [MOpRegNum::const_zero(); 0],
[MOpRegNum::const_zero(); 0], ReadSpecialMOpImm.PowerIsaTimeBase(),
ReadSpecialMOpImm.PowerIsaTimeBase(), ),
)
},
)); ));
// make sure we generate mfspr and not the phased-out mftb // make sure we generate mfspr and not the phased-out mftb
retval.push(insn_single( retval.push(insn_single(
"mfspr 3, 269 # mftbu 3", "mfspr 3, 269 # mftbu 3",
0x7c6d42a6, 0x7c6d42a6,
None, None,
|| { ReadSpecialMOp::read_special(
ReadSpecialMOp::read_special( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), [MOpRegNum::const_zero(); 0],
[MOpRegNum::const_zero(); 0], ReadSpecialMOpImm.PowerIsaTimeBaseU(),
ReadSpecialMOpImm.PowerIsaTimeBaseU(), ),
)
},
)); ));
// phased-out mftb -- not actually generated by the assembler so we have to use .long // phased-out mftb -- not actually generated by the assembler so we have to use .long
retval.push(insn_single( retval.push(insn_single(
".long 0x7c6c42e6 # mftb 3, 268", ".long 0x7c6c42e6 # mftb 3, 268",
0x7c6c42e6, 0x7c6c42e6,
None, None,
|| { ReadSpecialMOp::read_special(
ReadSpecialMOp::read_special( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), [MOpRegNum::const_zero(); 0],
[MOpRegNum::const_zero(); 0], ReadSpecialMOpImm.PowerIsaTimeBase(),
ReadSpecialMOpImm.PowerIsaTimeBase(), ),
)
},
)); ));
// phased-out mftb -- not actually generated by the assembler so we have to use .long // phased-out mftb -- not actually generated by the assembler so we have to use .long
retval.push(insn_single( retval.push(insn_single(
".long 0x7c6d42e6 # mftb 3, 269", ".long 0x7c6d42e6 # mftb 3, 269",
0x7c6d42e6, 0x7c6d42e6,
None, None,
|| { ReadSpecialMOp::read_special(
ReadSpecialMOp::read_special( MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]), [MOpRegNum::const_zero(); 0],
[MOpRegNum::const_zero(); 0], ReadSpecialMOpImm.PowerIsaTimeBaseU(),
ReadSpecialMOpImm.PowerIsaTimeBaseU(), ),
)
},
)); ));
} }

View file

@ -1,291 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use cpu::{
config::{CpuConfig, UnitConfig},
decoder::simple_power_isa,
instruction::MOpRegNum,
next_pc::CallStackOp,
register::{FlagsMode, PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegValue},
rename_execute_retire::{
GlobalState, NextPcPredictorOp, to_unit_interfaces::ExecuteToUnitInterfaces,
},
test::decode_and_run_single_insn::{
DecodeAndRunSingleInsnInput, DecodeAndRunSingleInsnOutput, DecodeOneInsnInput,
DecodeOneInsnMaxMOpCount, decode_and_run_single_insn,
},
unit::{UnitKind, UnitTrait},
util::array_vec::ArrayVec,
};
use fayalite::{
firrtl::ExportOptions,
module::{instance_with_loc, transform::simplify_enums::SimplifyEnumsKind},
prelude::*,
ty::StaticType,
};
use std::num::NonZero;
#[hdl_module]
fn formal_harness(config: PhantomConst<CpuConfig>) {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let input: DecodeAndRunSingleInsnInput<
PhantomConst<CpuConfig>,
DecodeOneInsnInput<simple_power_isa::decode_one_insn>,
> = m.input(DecodeAndRunSingleInsnInput[config][StaticType::TYPE]);
#[hdl]
let output: HdlOption<
DecodeAndRunSingleInsnOutput<
PhantomConst<CpuConfig>,
DecodeOneInsnMaxMOpCount<simple_power_isa::decode_one_insn>,
>,
> = m.output(HdlOption[DecodeAndRunSingleInsnOutput[config][ConstUsize]]);
#[hdl]
let decode_and_run = instance(decode_and_run_single_insn(
config,
simple_power_isa::decode_one_insn(),
));
connect(decode_and_run.cd, cd);
#[hdl]
let need_to_send_input_reg = reg_builder().clock_domain(cd).reset(true);
#[hdl]
if need_to_send_input_reg {
connect(decode_and_run.input.data, HdlSome(input));
#[hdl]
if decode_and_run.input.ready {
connect(need_to_send_input_reg, false);
}
} else {
connect(
decode_and_run.input.data,
decode_and_run.ty().input.data.HdlNone(),
);
}
connect(
decode_and_run.global_state,
#[hdl]
GlobalState {
flags_mode: FlagsMode.PowerISA(
#[hdl]
PRegFlagsPowerISA {},
),
},
);
connect(decode_and_run.output.ready, true);
connect(output, decode_and_run.output.data);
for (unit_index, unit) in config.get().units.iter().enumerate() {
let dyn_unit = unit.kind.unit(config, unit_index);
let unit = instance_with_loc(
&decode_and_run.ty().to_units.unit_field_name(unit_index),
dyn_unit.module(),
SourceLocation::caller(),
);
connect(
dyn_unit.from_execute(unit),
ExecuteToUnitInterfaces::unit_fields(decode_and_run.to_units)[unit_index],
);
if let Some(unit_cd) = dyn_unit.cd(unit) {
connect(unit_cd, cd);
}
}
hdl_assert(cd.clk, !decode_and_run.error, "");
}
#[derive(Copy, Clone)]
struct R3R4AnyConst {
r3_any_const: Expr<UInt<64>>,
r4_any_const: Expr<UInt<64>>,
}
impl R3R4AnyConst {
#[track_caller]
fn new() -> Self {
Self {
r3_any_const: any_const(StaticType::TYPE),
r4_any_const: any_const(StaticType::TYPE),
}
}
}
#[hdl_module]
fn check_power_isa_add_formal(
config: PhantomConst<CpuConfig>,
r3_r4_any_const: Option<R3R4AnyConst>,
) {
#[hdl]
let cd = wire();
connect(
cd,
#[hdl]
ClockDomain {
clk: formal_global_clock(),
rst: formal_reset().to_reset(),
},
);
#[hdl]
let harness = instance(formal_harness(config));
connect(harness.cd, cd);
#[hdl]
let ran: Bool = m.output();
#[hdl]
let ran_reg = reg_builder().clock_domain(cd).reset(false);
connect(ran, ran_reg);
#[hdl]
let DecodeAndRunSingleInsnInput::<_, _> {
decoder_input,
fetch_block_id,
first_id,
pc,
predicted_next_pc,
regs: input_regs,
config: _,
} = harness.input;
// add r3, r3, r4
connect(decoder_input, (0x7c632214_u32, HdlNone()));
connect(fetch_block_id, 0u8);
connect(first_id, 0u16);
connect(pc, 0x1000_u64);
connect(predicted_next_pc, 0x1004_u64);
connect(
input_regs.regs,
repeat(
PRegValue::zeroed().to_trace_as_string(),
1 << MOpRegNum::WIDTH,
),
);
let R3R4AnyConst {
r3_any_const,
r4_any_const,
} = r3_r4_any_const.unwrap_or_else(|| R3R4AnyConst::new());
#[hdl]
let input_r3 = wire();
connect(input_r3, r3_any_const);
#[hdl]
let input_r4 = wire();
connect(input_r4, r4_any_const);
connect(
input_regs.regs[MOpRegNum::power_isa_gpr_reg_imm(3).value].int_fp,
input_r3,
);
connect(
input_regs.regs[MOpRegNum::power_isa_gpr_reg_imm(4).value].int_fp,
input_r4,
);
#[hdl]
if let HdlSome(output) = harness.output {
connect(ran_reg, true);
#[hdl]
let DecodeAndRunSingleInsnOutput::<_, _> {
regs,
cancel_and_start_at,
retired_insns,
config: _,
} = output;
hdl_assert(cd.clk, cancel_and_start_at.cmp_eq(HdlNone()), "");
hdl_assert(cd.clk, ArrayVec::len(retired_insns).cmp_eq(1u8), "");
#[hdl]
let NextPcPredictorOp::<_> {
call_stack_op,
cond_br_taken,
config: _,
} = retired_insns[0];
hdl_assert(cd.clk, call_stack_op.cmp_eq(CallStackOp.None()), "");
hdl_assert(cd.clk, cond_br_taken.cmp_eq(HdlNone()), "");
#[hdl]
let expected_regs = wire(regs.ty());
for (reg_index, expected) in expected_regs.regs.into_iter().enumerate() {
let reg_num = reg_index as u32;
if reg_num == MOpRegNum::power_isa_gpr_reg_num(3) {
connect(expected.int_fp, (input_r3 + input_r4).cast_to_static());
let PRegFlagsPowerISAView {
unused: _,
xer_ca,
xer_ca32,
xer_ov,
xer_ov32,
cr_lt,
cr_gt,
cr_eq,
so,
..
} = PRegFlags::view::<PRegFlagsPowerISA>(expected.flags);
let input_r3_s = input_r3.cast_to_static::<SInt<64>>();
let input_r4_s = input_r4.cast_to_static::<SInt<64>>();
let u64_sum = input_r3 + input_r4;
let s64_sum = input_r3_s + input_r4_s;
let u32_sum = input_r3.cast_to(UInt[32]) + input_r4.cast_to(UInt[32]);
let s32_sum = input_r3.cast_to(SInt[32]) + input_r4.cast_to(SInt[32]);
let sum_as_s64 = u64_sum.cast_to(SInt[64]);
connect(xer_ca, u64_sum[64]);
connect(xer_ca32, u32_sum[32]);
connect(xer_ov, s64_sum.cmp_lt(i64::MIN) | s64_sum.cmp_gt(i64::MAX));
connect(
xer_ov32,
s32_sum.cmp_lt(i32::MIN) | s32_sum.cmp_gt(i32::MAX),
);
connect(cr_gt, sum_as_s64.cmp_gt(0i64));
connect(cr_lt, sum_as_s64.cmp_lt(0i64));
connect(cr_eq, sum_as_s64.cmp_eq(0i64));
connect(so, xer_ov); // TODO: also propagate from input SO
} else {
connect(expected, input_regs.regs[reg_index]);
}
}
hdl_assert(cd.clk, expected_regs.cmp_eq(regs), "");
}
}
#[test]
fn test_power_isa_add_formal() {
let config = PhantomConst::new_sized(CpuConfig::new(
vec![UnitConfig::new(UnitKind::AluBranch)],
NonZero::new(20).unwrap(),
));
let m = check_power_isa_add_formal(config, None);
assert_formal(
"test_power_isa_add_formal",
m,
FormalMode::Prove,
10,
None,
ExportOptions {
simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts),
..Default::default()
},
);
}
#[hdl]
#[test]
fn test_power_isa_add_sim() {
let config = PhantomConst::new_sized(CpuConfig::new(
vec![UnitConfig::new(UnitKind::AluBranch)],
NonZero::new(20).unwrap(),
));
let r3_r4_any_const = R3R4AnyConst::new();
let m = check_power_isa_add_formal(config, Some(r3_r4_any_const));
let mut sim = Simulation::new(m);
let _checked_vcd_output = cpu::checked_vcd_output!(
&mut sim,
"tests/expected/units_formal_power_isa_add_sim.vcd",
);
sim.write(r3_r4_any_const.r3_any_const, 0x1234u64);
sim.write(r3_r4_any_const.r4_any_const, 0x2345u64);
let clk = formal_global_clock();
let rst = formal_reset();
sim.write_clock(clk, false);
sim.write_reset(rst, true);
for cycle in 0..10 {
sim.advance_time(SimDuration::from_nanos(500));
println!("clock tick: {cycle}");
sim.write_clock(clk, true);
sim.advance_time(SimDuration::from_nanos(500));
sim.write_clock(clk, false);
sim.write_reset(rst, false);
}
assert!(sim.read_bool(sim.io().ran));
}