WIP: add cpu::test::decode_and_run_single_insn and some formal tests of running PowerISA instructions #15
23 changed files with 5756 additions and 89702 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
|
@ -388,7 +388,7 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
|||
[[package]]
|
||||
name = "fayalite"
|
||||
version = "0.3.0"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cf3e6cfc6bc33eebf2d2862c7a1948b9cf40ecac"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#31353862ceba3d255fd6712813a457688b269358"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bitvec",
|
||||
|
|
@ -417,7 +417,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "fayalite-proc-macros"
|
||||
version = "0.3.0"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cf3e6cfc6bc33eebf2d2862c7a1948b9cf40ecac"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#31353862ceba3d255fd6712813a457688b269358"
|
||||
dependencies = [
|
||||
"fayalite-proc-macros-impl",
|
||||
]
|
||||
|
|
@ -425,7 +425,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "fayalite-proc-macros-impl"
|
||||
version = "0.3.0"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cf3e6cfc6bc33eebf2d2862c7a1948b9cf40ecac"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#31353862ceba3d255fd6712813a457688b269358"
|
||||
dependencies = [
|
||||
"base16ct 0.2.0",
|
||||
"num-bigint",
|
||||
|
|
@ -440,7 +440,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "fayalite-visit-gen"
|
||||
version = "0.3.0"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cf3e6cfc6bc33eebf2d2862c7a1948b9cf40ecac"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#31353862ceba3d255fd6712813a457688b269358"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"prettyplease",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use crate::{
|
|||
register::{
|
||||
PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, ViewUnused,
|
||||
},
|
||||
test::decode_and_run_single_insn::{DecodeOneInsn, DecodeOneInsnOutput},
|
||||
util::{
|
||||
Rotate,
|
||||
array_vec::{ArrayVec, Length},
|
||||
|
|
@ -138,10 +139,11 @@ struct DecodeState<'a> {
|
|||
conditions: Option<&'static str>,
|
||||
header: &'static crate::powerisa_instructions_xml::InstructionHeader,
|
||||
insn: &'static crate::powerisa_instructions_xml::Instruction,
|
||||
output: Expr<ArrayVec<MOp, ConstUsize<3>>>,
|
||||
output: Expr<ArrayVec<TraceAsString<MOp>, ConstUsize<3>>>,
|
||||
is_illegal: Expr<Bool>,
|
||||
first_input: Expr<UInt<32>>,
|
||||
second_input: Expr<HdlOption<UInt<32>>>,
|
||||
has_second_input: Expr<Bool>,
|
||||
second_input_value: Expr<UInt<32>>,
|
||||
second_input_used: Expr<Bool>,
|
||||
field_wires: &'a mut HashMap<String, HashMap<Expr<UInt>, Expr<UInt>>>,
|
||||
}
|
||||
|
|
@ -428,10 +430,9 @@ impl DecodeState<'_> {
|
|||
Entry::Occupied(entry) => *entry.get(),
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
fn decode_word(
|
||||
&mut self,
|
||||
matches: &mut Expr<Bool>,
|
||||
matches: &mut Option<Expr<Bool>>,
|
||||
fields: &mut BTreeMap<&'static str, Expr<UInt>>,
|
||||
word: Expr<UInt<32>>,
|
||||
fields_inner: &'static InstructionBitFieldsInner,
|
||||
|
|
@ -524,7 +525,10 @@ impl DecodeState<'_> {
|
|||
}
|
||||
} else {
|
||||
let value: u32 = name.parse().expect("bit field name must have at least one letter, be all `/`, or be a valid decimal number");
|
||||
*matches = *matches & field.cmp_eq(value);
|
||||
*matches = match *matches {
|
||||
Some(matches) => Some(matches & field.cmp_eq(value)),
|
||||
None => Some(field.cmp_eq(value)),
|
||||
};
|
||||
if orig_name.contains(char::is_alphabetic) {
|
||||
if fields
|
||||
.insert(orig_name, value.cast_to(field.ty()).to_expr())
|
||||
|
|
@ -536,20 +540,19 @@ impl DecodeState<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
#[track_caller]
|
||||
fn decode_scope<FS: FieldSet, F: FnOnce(&mut Self, FS)>(&mut self, f: F) {
|
||||
let mut fields = BTreeMap::new();
|
||||
let mut matches = true.to_expr();
|
||||
let mut f = Some(f);
|
||||
#[hdl]
|
||||
#[track_caller]
|
||||
fn run<'a, FS: FieldSet, F: FnOnce(&mut DecodeState<'a>, FS)>(
|
||||
this: &mut DecodeState<'a>,
|
||||
matches: Expr<Bool>,
|
||||
matches: Option<Expr<Bool>>,
|
||||
fields: &mut BTreeMap<&str, Expr<UInt>>,
|
||||
f: &mut Option<F>,
|
||||
) {
|
||||
let matches = matches.expect("matches is known to be Some");
|
||||
#[hdl]
|
||||
if matches {
|
||||
connect(
|
||||
|
|
@ -561,23 +564,22 @@ impl DecodeState<'_> {
|
|||
}
|
||||
}
|
||||
if let Some(prefix) = self.header.bit_fields().prefix() {
|
||||
#[hdl]
|
||||
if let HdlSome(suffix_word) = self.second_input {
|
||||
self.decode_word(
|
||||
&mut matches,
|
||||
&mut fields,
|
||||
self.first_input,
|
||||
prefix.fields_inner(),
|
||||
);
|
||||
self.decode_word(
|
||||
&mut matches,
|
||||
&mut fields,
|
||||
suffix_word,
|
||||
self.header.bit_fields().fields_inner(),
|
||||
);
|
||||
run(self, matches, &mut fields, &mut f);
|
||||
}
|
||||
let mut matches = Some(self.has_second_input);
|
||||
self.decode_word(
|
||||
&mut matches,
|
||||
&mut fields,
|
||||
self.first_input,
|
||||
prefix.fields_inner(),
|
||||
);
|
||||
self.decode_word(
|
||||
&mut matches,
|
||||
&mut fields,
|
||||
self.second_input_value,
|
||||
self.header.bit_fields().fields_inner(),
|
||||
);
|
||||
run(self, matches, &mut fields, &mut f);
|
||||
} else {
|
||||
let mut matches = None;
|
||||
self.decode_word(
|
||||
&mut matches,
|
||||
&mut fields,
|
||||
|
|
@ -594,7 +596,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
BranchMOp::branch_i(
|
||||
MOpDestReg::new(
|
||||
[if this.mnemonic.contains('l') {
|
||||
|
|
@ -635,7 +637,7 @@ impl DecodeState<'_> {
|
|||
let no_cr_bit = bo[4]; // BO_0 in specification
|
||||
let (cr_field, condition_mode) = cr_bit_cond(bi);
|
||||
#[hdl]
|
||||
let branch_mop = wire();
|
||||
let branch_mop: TraceAsString<MOp> = wire();
|
||||
#[hdl]
|
||||
let branch_lr_dest_reg = wire();
|
||||
connect(branch_lr_dest_reg, MOpRegNum::const_zero());
|
||||
|
|
@ -656,7 +658,7 @@ impl DecodeState<'_> {
|
|||
#[hdl]
|
||||
if no_ctr & no_cr_bit {
|
||||
connect(
|
||||
branch_mop,
|
||||
*branch_mop,
|
||||
BranchMOp::branch_i(
|
||||
dest,
|
||||
[MOpRegNum::const_zero(), src1],
|
||||
|
|
@ -668,7 +670,7 @@ impl DecodeState<'_> {
|
|||
);
|
||||
} else if no_cr_bit {
|
||||
connect(
|
||||
branch_mop,
|
||||
*branch_mop,
|
||||
BranchMOp::branch_ctr(
|
||||
dest,
|
||||
[MOpRegNum::const_zero(), src1, branch_ctr_reg],
|
||||
|
|
@ -681,7 +683,7 @@ impl DecodeState<'_> {
|
|||
);
|
||||
} else {
|
||||
connect(
|
||||
branch_mop,
|
||||
*branch_mop,
|
||||
BranchMOp::branch_cond_ctr(
|
||||
dest,
|
||||
[cr_field, src1, branch_ctr_reg],
|
||||
|
|
@ -709,7 +711,7 @@ impl DecodeState<'_> {
|
|||
2usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []),
|
||||
[MOpRegNum::power_isa_ctr_reg(), MOpRegNum::const_zero()],
|
||||
|
|
@ -782,7 +784,7 @@ impl DecodeState<'_> {
|
|||
- bt_flag_index.cast_to(uint_ty))
|
||||
% PRegFlags::FLAG_COUNT;
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
MOpDestReg::new([bt_reg], []),
|
||||
[ba_reg, bb_reg, bt_reg],
|
||||
|
|
@ -808,7 +810,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new([crf(bf)], []),
|
||||
[crf(bfa)],
|
||||
|
|
@ -885,7 +887,7 @@ impl DecodeState<'_> {
|
|||
#[hdl]
|
||||
if r {
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([ea_reg], []),
|
||||
[MOpRegNum::const_zero(); 2],
|
||||
|
|
@ -899,7 +901,7 @@ impl DecodeState<'_> {
|
|||
);
|
||||
} else {
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([ea_reg], []),
|
||||
[gpr_or_zero(ra), MOpRegNum::const_zero()],
|
||||
|
|
@ -913,7 +915,7 @@ impl DecodeState<'_> {
|
|||
);
|
||||
}
|
||||
connect(
|
||||
this.output[1],
|
||||
*this.output[1],
|
||||
LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion),
|
||||
);
|
||||
},
|
||||
|
|
@ -927,7 +929,7 @@ impl DecodeState<'_> {
|
|||
);
|
||||
let ea_reg = ea_reg(ra);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([ea_reg], []),
|
||||
[gpr_or_zero(ra), gpr(rb)],
|
||||
|
|
@ -940,7 +942,7 @@ impl DecodeState<'_> {
|
|||
),
|
||||
);
|
||||
connect(
|
||||
this.output[1],
|
||||
*this.output[1],
|
||||
LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion),
|
||||
);
|
||||
});
|
||||
|
|
@ -952,7 +954,7 @@ impl DecodeState<'_> {
|
|||
);
|
||||
let ea_reg = ea_reg(ra);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([ea_reg], []),
|
||||
[gpr_or_zero(ra), MOpRegNum::const_zero()],
|
||||
|
|
@ -965,7 +967,7 @@ impl DecodeState<'_> {
|
|||
),
|
||||
);
|
||||
connect(
|
||||
this.output[1],
|
||||
*this.output[1],
|
||||
LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion),
|
||||
);
|
||||
});
|
||||
|
|
@ -983,7 +985,7 @@ impl DecodeState<'_> {
|
|||
);
|
||||
let ea_reg = ea_reg(ra);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([ea_reg], []),
|
||||
[gpr_or_zero(ra), MOpRegNum::const_zero()],
|
||||
|
|
@ -996,7 +998,7 @@ impl DecodeState<'_> {
|
|||
),
|
||||
);
|
||||
connect(
|
||||
this.output[1],
|
||||
*this.output[1],
|
||||
LoadMOp::load(MOpDestReg::new([gpr(rt)], []), [ea_reg], width, conversion),
|
||||
);
|
||||
});
|
||||
|
|
@ -1063,9 +1065,9 @@ impl DecodeState<'_> {
|
|||
} else {
|
||||
(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(
|
||||
this.output[1],
|
||||
*this.output[1],
|
||||
StoreMOp::store(
|
||||
MOpDestReg::new([], []),
|
||||
[ea_reg, gpr(rs)],
|
||||
|
|
@ -1080,7 +1082,7 @@ impl DecodeState<'_> {
|
|||
3usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[2],
|
||||
*this.output[2],
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new([gpr(ra)], []),
|
||||
[ea_reg],
|
||||
|
|
@ -1202,7 +1204,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([gpr(rt)], []),
|
||||
#[hdl]
|
||||
|
|
@ -1225,7 +1227,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([gpr(rt)], []),
|
||||
#[hdl]
|
||||
|
|
@ -1252,7 +1254,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([gpr(rt)], []),
|
||||
#[hdl]
|
||||
|
|
@ -1279,7 +1281,7 @@ impl DecodeState<'_> {
|
|||
+ (d1 << 1).cast_to_static::<SInt<16>>()
|
||||
+ d2.cast_to_static::<SInt<16>>();
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([gpr(rt)], []),
|
||||
#[hdl]
|
||||
|
|
@ -1306,7 +1308,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new(
|
||||
[gpr(rt)],
|
||||
|
|
@ -1337,7 +1339,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new(
|
||||
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
|
||||
|
|
@ -1369,7 +1371,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new(
|
||||
[
|
||||
|
|
@ -1406,7 +1408,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new(
|
||||
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
|
||||
|
|
@ -1438,7 +1440,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new(
|
||||
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
|
||||
|
|
@ -1471,7 +1473,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new(
|
||||
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
|
||||
|
|
@ -1504,7 +1506,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new(
|
||||
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
|
||||
|
|
@ -1537,7 +1539,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new(
|
||||
[gpr(rt), MOpRegNum::power_isa_xer_ca_ca32_reg()],
|
||||
|
|
@ -1575,7 +1577,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new(
|
||||
[gpr(rt)],
|
||||
|
|
@ -1615,7 +1617,7 @@ impl DecodeState<'_> {
|
|||
connect(compare_mode, CompareMode.S32());
|
||||
}
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
CompareMOp::compare_i(
|
||||
MOpDestReg::new([crf(bf)], []),
|
||||
[gpr(ra)],
|
||||
|
|
@ -1643,7 +1645,7 @@ impl DecodeState<'_> {
|
|||
connect(compare_mode, CompareMode.S32());
|
||||
}
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new([crf(bf)], []),
|
||||
[gpr(ra), gpr(rb)],
|
||||
|
|
@ -1670,7 +1672,7 @@ impl DecodeState<'_> {
|
|||
connect(compare_mode, CompareMode.U32());
|
||||
}
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
CompareMOp::compare_i(
|
||||
MOpDestReg::new([crf(bf)], []),
|
||||
[gpr(ra)],
|
||||
|
|
@ -1698,7 +1700,7 @@ impl DecodeState<'_> {
|
|||
connect(compare_mode, CompareMode.U32());
|
||||
}
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new([crf(bf)], []),
|
||||
[gpr(ra), gpr(rb)],
|
||||
|
|
@ -1725,7 +1727,7 @@ impl DecodeState<'_> {
|
|||
connect(compare_mode, CompareMode.CmpRBOne());
|
||||
}
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new([crf(bf)], []),
|
||||
[gpr(ra), gpr(rb)],
|
||||
|
|
@ -1744,7 +1746,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new([crf(bf)], []),
|
||||
[gpr(ra), gpr(rb)],
|
||||
|
|
@ -1770,7 +1772,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
LogicalMOp::logical_i(
|
||||
MOpDestReg::new(
|
||||
[gpr(ra)],
|
||||
|
|
@ -1824,7 +1826,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
LogicalMOp::logical(
|
||||
MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]),
|
||||
[gpr(rs), gpr(rb)],
|
||||
|
|
@ -1838,7 +1840,7 @@ impl DecodeState<'_> {
|
|||
if rs.reg_num.cmp_eq(rb.reg_num) & !rc {
|
||||
// found `mr`
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new([gpr(ra)], []),
|
||||
[gpr(rs)],
|
||||
|
|
@ -1867,7 +1869,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
LogicalMOp::logical_i(
|
||||
MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]),
|
||||
[gpr(rs)],
|
||||
|
|
@ -1945,7 +1947,7 @@ impl DecodeState<'_> {
|
|||
);
|
||||
let dest_logic_op = self.rotate_dest_logic_op(msb0_mask_begin, msb0_mask_end, false);
|
||||
connect(
|
||||
self.output[0],
|
||||
*self.output[0],
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new([gpr(ra.0)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc.0)]),
|
||||
[gpr(rs.0), gpr(rs.0), gpr(rb.0)],
|
||||
|
|
@ -2004,7 +2006,7 @@ impl DecodeState<'_> {
|
|||
}
|
||||
}
|
||||
connect(
|
||||
self.output[0],
|
||||
*self.output[0],
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new([gpr(ra.0)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc.0)]),
|
||||
[gpr(rs.0), gpr(rs.0), rotate_imm_src2],
|
||||
|
|
@ -2156,7 +2158,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new(
|
||||
[gpr(ra), MOpRegNum::power_isa_xer_ca_ca32_reg()],
|
||||
|
|
@ -2186,7 +2188,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new(
|
||||
[gpr(ra), MOpRegNum::power_isa_xer_ca_ca32_reg()],
|
||||
|
|
@ -2218,7 +2220,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new(
|
||||
[
|
||||
|
|
@ -2280,7 +2282,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new([gpr(ra)], [(MOpRegNum::POWER_ISA_CR_0_REG_NUM, rc)]),
|
||||
[gpr(rs), MOpRegNum::const_zero(), MOpRegNum::const_zero()],
|
||||
|
|
@ -2312,7 +2314,7 @@ impl DecodeState<'_> {
|
|||
);
|
||||
if is_write_to_spr {
|
||||
connect(
|
||||
self.output[0],
|
||||
*self.output[0],
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new([spr], []),
|
||||
[gpr(reg)],
|
||||
|
|
@ -2321,7 +2323,7 @@ impl DecodeState<'_> {
|
|||
);
|
||||
} else {
|
||||
connect(
|
||||
self.output[0],
|
||||
*self.output[0],
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new([gpr(reg)], []),
|
||||
[spr],
|
||||
|
|
@ -2337,7 +2339,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
self.output[0],
|
||||
*self.output[0],
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new([gpr(reg)], []),
|
||||
[MOpRegNum::const_zero(); 0],
|
||||
|
|
@ -2412,7 +2414,7 @@ impl DecodeState<'_> {
|
|||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
*this.output[0],
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
MOpDestReg::new([crf(bf)], []),
|
||||
[
|
||||
|
|
@ -2741,10 +2743,12 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
|||
),
|
||||
];
|
||||
|
||||
const MAX_MOPS_PER_INSN: usize = 3;
|
||||
|
||||
#[hdl_module]
|
||||
pub fn decode_one_insn() {
|
||||
#[hdl]
|
||||
let output: ArrayVec<MOp, ConstUsize<3>> = m.output();
|
||||
let output: ArrayVec<TraceAsString<MOp>, ConstUsize<{ MAX_MOPS_PER_INSN }>> = m.output();
|
||||
#[hdl]
|
||||
let is_illegal: Bool = m.output();
|
||||
#[hdl]
|
||||
|
|
@ -2758,6 +2762,20 @@ pub fn decode_one_insn() {
|
|||
connect(second_input_used, false);
|
||||
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();
|
||||
for &(mnemonics, decode_fn) in DECODE_FNS {
|
||||
for &mnemonic in mnemonics {
|
||||
|
|
@ -2807,7 +2825,8 @@ pub fn decode_one_insn() {
|
|||
output,
|
||||
is_illegal,
|
||||
first_input,
|
||||
second_input,
|
||||
has_second_input,
|
||||
second_input_value,
|
||||
second_input_used,
|
||||
field_wires: &mut field_wires,
|
||||
});
|
||||
|
|
@ -2816,6 +2835,49 @@ 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]
|
||||
pub fn simple_power_isa_decoder(config: PhantomConst<CpuConfig>) {
|
||||
todo!()
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ pub trait MOpTrait: Type {
|
|||
input: &mut SimValue<Self>,
|
||||
f: &mut impl FnMut(&mut SimValue<Self::SrcReg>, usize),
|
||||
);
|
||||
fn connect_src_regs(
|
||||
fn connect_to_src_regs(
|
||||
input: impl ToExpr<Type = Self>,
|
||||
src_regs: impl ToExpr<Type = Array<Self::SrcReg, { COMMON_MOP_SRC_LEN }>>,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -11,5 +11,6 @@ pub mod powerisa_instructions_xml;
|
|||
pub mod reg_alloc;
|
||||
pub mod register;
|
||||
pub mod rename_execute_retire;
|
||||
pub mod test;
|
||||
pub mod unit;
|
||||
pub mod util;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ pub struct WipDecodedInsn {
|
|||
pub kind: WipDecodedInsnKind,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub enum CallStackOp {
|
||||
None,
|
||||
Push(UInt<64>),
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use crate::{
|
|||
COMMON_MOP_SRC_LEN, L2RegNum, MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, ReadL2RegMOp,
|
||||
UnitNum, UnitOutRegNum, WriteL2RegMOp,
|
||||
},
|
||||
next_pc::{CallStackOp, SimValueDefault},
|
||||
next_pc::{CallStackOp, FETCH_BLOCK_ID_WIDTH, SimValueDefault},
|
||||
register::{FlagsMode, PRegFlagsPowerISA, PRegValue},
|
||||
rename_execute_retire::{
|
||||
rename_table::{RenameTable, RenameTableDebugState, RenameTableEntry, RenameTableUpdate},
|
||||
|
|
@ -42,7 +42,7 @@ pub type MOpId = UInt<{ MOP_ID_WIDTH }>;
|
|||
#[hdl(custom_debug(sim))]
|
||||
/// A µOp along with the state needed for this instance of the µOp.
|
||||
pub struct MOpInstance<MOp> {
|
||||
pub fetch_block_id: UInt<8>,
|
||||
pub fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
|
||||
pub id: MOpId,
|
||||
pub pc: UInt<64>,
|
||||
/// initialized to 0 by decoder, overwritten by `next_pc()`
|
||||
|
|
@ -217,6 +217,7 @@ pub struct UnitMOpCantCauseCancel<C: PhantomConstGet<CpuConfig>> {
|
|||
pub struct ExecuteToUnitInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
pub global_state: GlobalState,
|
||||
/// 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>>,
|
||||
/// if [`Self::unit_outputs_ready`] is `false`, then this is always [`HdlNone`]
|
||||
pub inputs_ready: HdlOption<UnitInputsReady<C>>,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{config::CpuConfig, rename_execute_retire::ExecuteToUnitInterface};
|
||||
use crate::{
|
||||
config::{CpuConfig, CpuConfigUnitCount},
|
||||
rename_execute_retire::ExecuteToUnitInterface,
|
||||
};
|
||||
use fayalite::{
|
||||
bundle::{BundleField, BundleType, NoBuilder},
|
||||
expr::ops::FieldAccess,
|
||||
intern::{Intern, Interned, Memoize},
|
||||
module::{connect_with_loc, wire_with_loc},
|
||||
prelude::*,
|
||||
ty::{
|
||||
OpaqueSimValue, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
|
||||
|
|
@ -102,6 +106,42 @@ impl<C: Type + PhantomConstGet<CpuConfig>> ExecuteToUnitInterfaces<C> {
|
|||
}
|
||||
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)]
|
||||
|
|
|
|||
4
crates/cpu/src/test.rs
Normal file
4
crates/cpu/src/test.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
pub mod decode_and_run_single_insn;
|
||||
951
crates/cpu/src/test/decode_and_run_single_insn.rs
Normal file
951
crates/cpu/src/test/decode_and_run_single_insn.rs
Normal file
|
|
@ -0,0 +1,951 @@
|
|||
// 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(
|
||||
state_reg,
|
||||
HdlSome(DecodeAndRunSingleInsnState::new(
|
||||
input,
|
||||
decoder_output,
|
||||
config,
|
||||
decoder.ty().max_mop_count(),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -226,6 +226,10 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
|||
#[hdl]
|
||||
let mapped_array_vec = wire(this.ty().mapped_ty(new_element_ty));
|
||||
connect(mapped_array_vec.len, this.len);
|
||||
connect(
|
||||
mapped_array_vec.elements,
|
||||
mapped_array_vec.ty().elements.uninit(),
|
||||
);
|
||||
Self::for_each(this, |index, element| {
|
||||
connect(mapped_array_vec[index], f(index, element));
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -149,7 +149,7 @@ fn test_decode_insn() {
|
|||
#[derive(Debug)]
|
||||
#[expect(dead_code, reason = "used only for Debug formatting")]
|
||||
struct FormattedOutput<'a> {
|
||||
insns: &'a [SimValue<MOp>],
|
||||
insns: &'a [SimValue<TraceAsString<MOp>>],
|
||||
second_input_used: bool,
|
||||
is_illegal: bool,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,14 +16,23 @@ mod fixed_point_store;
|
|||
mod move_to_from_system_register;
|
||||
mod prefixed_no_operation;
|
||||
|
||||
#[hdl(get(|_| 3))]
|
||||
pub type TestCaseOutputLen<C: PhantomConstGet<()>> = DynSize;
|
||||
|
||||
pub struct TestCase {
|
||||
pub mnemonic: &'static str,
|
||||
pub first_input: u32,
|
||||
pub second_input: Option<u32>,
|
||||
pub output: SimValue<ArrayVec<MOp, ConstUsize<3>>>,
|
||||
pub output: SimValue<ArrayVec<TraceAsString<MOp>, TestCaseOutputLen<PhantomConst<()>>>>,
|
||||
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 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
|
|
@ -49,90 +58,91 @@ impl fmt::Debug for TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline(never)] // prevent stack overflow
|
||||
#[track_caller]
|
||||
fn insn_empty(mnemonic: &'static str, first_input: u32, second_input: Option<u32>) -> TestCase {
|
||||
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||
.zero()
|
||||
.cast_bits_to(MOp);
|
||||
.cast_bits_to(MOp)
|
||||
.into_trace_as_string();
|
||||
TestCase {
|
||||
mnemonic,
|
||||
first_input,
|
||||
second_input,
|
||||
output: ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop),
|
||||
output: TestCase::output_ty().new_sim(zero_mop),
|
||||
loc: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)] // prevent stack overflow
|
||||
#[track_caller]
|
||||
fn insn_single(
|
||||
fn insn_single<T: ToSimValue<Type = MOp>>(
|
||||
mnemonic: &'static str,
|
||||
first_input: u32,
|
||||
second_input: Option<u32>,
|
||||
output: impl ToSimValue<Type = MOp>,
|
||||
// use a closure to avoid having too many variables in one function causing a stack overflow
|
||||
output: impl FnOnce() -> T,
|
||||
) -> TestCase {
|
||||
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||
.zero()
|
||||
.cast_bits_to(MOp);
|
||||
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");
|
||||
ArrayVec::elements_sim_mut(&mut single_storage)[0] = output.to_sim_value();
|
||||
TestCase {
|
||||
mnemonic,
|
||||
first_input,
|
||||
second_input,
|
||||
output: single_storage,
|
||||
loc: std::panic::Location::caller(),
|
||||
}
|
||||
let mut retval = insn_empty(mnemonic, first_input, second_input);
|
||||
ArrayVec::try_push_sim(
|
||||
&mut retval.output,
|
||||
output().into_sim_value().into_trace_as_string(),
|
||||
)
|
||||
.expect("known to have space");
|
||||
retval
|
||||
}
|
||||
|
||||
#[inline(never)] // prevent stack overflow
|
||||
#[track_caller]
|
||||
fn insn_double(
|
||||
fn insn_double<T: ToSimValue<Type = MOp>>(
|
||||
mnemonic: &'static str,
|
||||
first_input: u32,
|
||||
second_input: Option<u32>,
|
||||
insns: [impl ToSimValue<Type = MOp>; 2],
|
||||
// use a closure to avoid having too many variables in one function causing a stack overflow
|
||||
insns: impl FnOnce() -> [T; 2],
|
||||
) -> TestCase {
|
||||
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||
.zero()
|
||||
.cast_bits_to(MOp);
|
||||
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");
|
||||
ArrayVec::try_push_sim(&mut single_storage, zero_mop).expect("known to have space");
|
||||
ArrayVec::elements_sim_mut(&mut single_storage)[0] = insns[0].to_sim_value();
|
||||
ArrayVec::elements_sim_mut(&mut single_storage)[1] = insns[1].to_sim_value();
|
||||
TestCase {
|
||||
mnemonic,
|
||||
first_input,
|
||||
second_input,
|
||||
output: single_storage,
|
||||
loc: std::panic::Location::caller(),
|
||||
}
|
||||
let mut retval = insn_empty(mnemonic, first_input, second_input);
|
||||
let [insn0, insn1] = insns();
|
||||
ArrayVec::try_push_sim(
|
||||
&mut retval.output,
|
||||
insn0.into_sim_value().into_trace_as_string(),
|
||||
)
|
||||
.expect("known to have space");
|
||||
ArrayVec::try_push_sim(
|
||||
&mut retval.output,
|
||||
insn1.into_sim_value().into_trace_as_string(),
|
||||
)
|
||||
.expect("known to have space");
|
||||
retval
|
||||
}
|
||||
|
||||
#[inline(never)] // prevent stack overflow
|
||||
#[track_caller]
|
||||
fn insn_triple(
|
||||
fn insn_triple<T: ToSimValue<Type = MOp>>(
|
||||
mnemonic: &'static str,
|
||||
first_input: u32,
|
||||
second_input: Option<u32>,
|
||||
insns: [impl ToSimValue<Type = MOp>; 3],
|
||||
// use a closure to avoid having too many variables in one function causing a stack overflow
|
||||
insns: impl FnOnce() -> [T; 3],
|
||||
) -> TestCase {
|
||||
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||
.zero()
|
||||
.cast_bits_to(MOp);
|
||||
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");
|
||||
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");
|
||||
ArrayVec::elements_sim_mut(&mut single_storage)[0] = insns[0].to_sim_value();
|
||||
ArrayVec::elements_sim_mut(&mut single_storage)[1] = insns[1].to_sim_value();
|
||||
ArrayVec::elements_sim_mut(&mut single_storage)[2] = insns[2].to_sim_value();
|
||||
TestCase {
|
||||
mnemonic,
|
||||
first_input,
|
||||
second_input,
|
||||
output: single_storage,
|
||||
loc: std::panic::Location::caller(),
|
||||
}
|
||||
let mut retval = insn_empty(mnemonic, first_input, second_input);
|
||||
let [insn0, insn1, insn2] = insns();
|
||||
ArrayVec::try_push_sim(
|
||||
&mut retval.output,
|
||||
insn0.into_sim_value().into_trace_as_string(),
|
||||
)
|
||||
.expect("known to have space");
|
||||
ArrayVec::try_push_sim(
|
||||
&mut retval.output,
|
||||
insn1.into_sim_value().into_trace_as_string(),
|
||||
)
|
||||
.expect("known to have space");
|
||||
ArrayVec::try_push_sim(
|
||||
&mut retval.output,
|
||||
insn2.into_sim_value().into_trace_as_string(),
|
||||
)
|
||||
.expect("known to have space");
|
||||
retval
|
||||
}
|
||||
|
||||
pub fn test_cases() -> Vec<TestCase> {
|
||||
|
|
|
|||
|
|
@ -9,10 +9,7 @@ use fayalite::prelude::*;
|
|||
|
||||
/// 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>) {
|
||||
retval.push(insn_single(
|
||||
"b 0x345678",
|
||||
0x48345678,
|
||||
None,
|
||||
retval.push(insn_single("b 0x345678", 0x48345678, None, || {
|
||||
BranchMOp::branch_i(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[MOpRegNum::const_zero(); 2],
|
||||
|
|
@ -20,12 +17,9 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
|
|||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"ba 0x345678",
|
||||
0x4834567a,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("ba 0x345678", 0x4834567a, None, || {
|
||||
BranchMOp::branch_i(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[MOpRegNum::const_zero(); 2],
|
||||
|
|
@ -33,12 +27,9 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"bl 0x345678",
|
||||
0x48345679,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("bl 0x345678", 0x48345679, None, || {
|
||||
BranchMOp::branch_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||
[MOpRegNum::const_zero(); 2],
|
||||
|
|
@ -46,12 +37,9 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"bla 0x345678",
|
||||
0x4834567b,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("bla 0x345678", 0x4834567b, None, || {
|
||||
BranchMOp::branch_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||
[MOpRegNum::const_zero(); 2],
|
||||
|
|
@ -59,18 +47,15 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
|
|||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
fn insn_dec_ctr_and(
|
||||
)
|
||||
}));
|
||||
fn insn_dec_ctr_and<T: ToSimValue<Type = MOp>>(
|
||||
mnemonic: &'static str,
|
||||
first_input: u32,
|
||||
second_input: Option<u32>,
|
||||
second_insn: impl ToSimValue<Type = MOp>,
|
||||
second_insn: impl FnOnce() -> T,
|
||||
) -> TestCase {
|
||||
insn_double(
|
||||
mnemonic,
|
||||
first_input,
|
||||
second_input,
|
||||
insn_double(mnemonic, first_input, second_input, || {
|
||||
[
|
||||
AddSubMOp::add_sub_i::<MOp>(
|
||||
MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []),
|
||||
|
|
@ -83,9 +68,9 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
|
|||
false,
|
||||
)
|
||||
.into_sim_value(),
|
||||
second_insn.into_sim_value(),
|
||||
],
|
||||
)
|
||||
second_insn().into_sim_value(),
|
||||
]
|
||||
})
|
||||
}
|
||||
macro_rules! insn_branch_conds {
|
||||
(
|
||||
|
|
@ -137,255 +122,281 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
|
|||
concat!($mnemonic, " 0, 0, ", $asm_last_arg),
|
||||
$encoding,
|
||||
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,
|
||||
),
|
||||
|| {
|
||||
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,
|
||||
),
|
||||
|| {
|
||||
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,
|
||||
),
|
||||
|| {
|
||||
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,
|
||||
),
|
||||
|| {
|
||||
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,
|
||||
),
|
||||
|| {
|
||||
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,
|
||||
),
|
||||
|| {
|
||||
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,
|
||||
),
|
||||
|| {
|
||||
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") {
|
||||
retval.push(insn_dec_ctr_and(
|
||||
concat!($mnemonic, " 8, 0, ", $asm_last_arg),
|
||||
$encoding | (8 << 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(),
|
||||
true,
|
||||
$pc_relative,
|
||||
$lk,
|
||||
$is_ret,
|
||||
),
|
||||
|| {
|
||||
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,
|
||||
),
|
||||
|| {
|
||||
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,
|
||||
),
|
||||
|| {
|
||||
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") {
|
||||
retval.push(insn_dec_ctr_and(
|
||||
concat!($mnemonic, " 16, 0, ", $asm_last_arg),
|
||||
$encoding | (16 << 21),
|
||||
None,
|
||||
BranchMOp::branch_ctr(
|
||||
$dest,
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg(),
|
||||
],
|
||||
$imm.cast_to_static::<SInt<_>>(),
|
||||
true,
|
||||
$pc_relative,
|
||||
$lk,
|
||||
$is_ret,
|
||||
),
|
||||
|| {
|
||||
BranchMOp::branch_ctr(
|
||||
$dest,
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg(),
|
||||
],
|
||||
$imm.cast_to_static::<SInt<_>>(),
|
||||
true,
|
||||
$pc_relative,
|
||||
$lk,
|
||||
$is_ret,
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_dec_ctr_and(
|
||||
concat!($mnemonic, " 18, 0, ", $asm_last_arg),
|
||||
$encoding | (18 << 21),
|
||||
None,
|
||||
BranchMOp::branch_ctr(
|
||||
$dest,
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg(),
|
||||
],
|
||||
$imm.cast_to_static::<SInt<_>>(),
|
||||
false,
|
||||
$pc_relative,
|
||||
$lk,
|
||||
$is_ret,
|
||||
),
|
||||
|| {
|
||||
BranchMOp::branch_ctr(
|
||||
$dest,
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg(),
|
||||
],
|
||||
$imm.cast_to_static::<SInt<_>>(),
|
||||
false,
|
||||
$pc_relative,
|
||||
$lk,
|
||||
$is_ret,
|
||||
)
|
||||
},
|
||||
));
|
||||
}
|
||||
retval.push(insn_single(
|
||||
concat!($mnemonic, " 20, 0, ", $asm_last_arg),
|
||||
$encoding | (20 << 21),
|
||||
None,
|
||||
BranchMOp::branch_i(
|
||||
$dest,
|
||||
[MOpRegNum::const_zero(), $src1],
|
||||
$imm.cast_to_static::<SInt<_>>(),
|
||||
$pc_relative,
|
||||
$lk,
|
||||
$is_ret,
|
||||
),
|
||||
|| {
|
||||
BranchMOp::branch_i(
|
||||
$dest,
|
||||
[MOpRegNum::const_zero(), $src1],
|
||||
$imm.cast_to_static::<SInt<_>>(),
|
||||
$pc_relative,
|
||||
$lk,
|
||||
$is_ret,
|
||||
)
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
@ -435,18 +446,20 @@ pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
|
|||
".long 0x4e400461 # bctarl 18, 0, 0",
|
||||
0x4e400461,
|
||||
None,
|
||||
BranchMOp::branch_ctr(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::power_isa_tar_reg(),
|
||||
MOpRegNum::power_isa_ctr_reg(),
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
|| {
|
||||
BranchMOp::branch_ctr(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::power_isa_tar_reg(),
|
||||
MOpRegNum::power_isa_ctr_reg(),
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
},
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,58 +20,70 @@ 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"),
|
||||
$encoding | 0x01e5a000,
|
||||
None,
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_cr_reg_imm(1),
|
||||
MOpRegNum::power_isa_cr_reg_imm(5),
|
||||
MOpRegNum::power_isa_cr_reg_imm(3),
|
||||
],
|
||||
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(|src0, src1, src2| {
|
||||
let mut dest = src2.map(|v| Some(v.into()));
|
||||
dest.so = Some((src0.cr_gt, src1.cr_lt).into());
|
||||
dest
|
||||
}),
|
||||
$lut,
|
||||
),
|
||||
|| {
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_cr_reg_imm(1),
|
||||
MOpRegNum::power_isa_cr_reg_imm(5),
|
||||
MOpRegNum::power_isa_cr_reg_imm(3),
|
||||
],
|
||||
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(
|
||||
|src0, src1, src2| {
|
||||
let mut dest = src2.map(|v| Some(v.into()));
|
||||
dest.so = Some((src0.cr_gt, src1.cr_lt).into());
|
||||
dest
|
||||
},
|
||||
),
|
||||
$lut,
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
concat!($mnemonic, " lt, gt, eq"),
|
||||
$encoding | 0x00011000,
|
||||
None,
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
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),
|
||||
],
|
||||
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(|src0, src1, src2| {
|
||||
let mut dest = src2.map(|v| Some(v.into()));
|
||||
dest.cr_lt = Some((src0.cr_gt, src1.cr_eq).into());
|
||||
dest
|
||||
}),
|
||||
$lut,
|
||||
),
|
||||
|| {
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
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),
|
||||
],
|
||||
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(
|
||||
|src0, src1, src2| {
|
||||
let mut dest = src2.map(|v| Some(v.into()));
|
||||
dest.cr_lt = Some((src0.cr_gt, src1.cr_eq).into());
|
||||
dest
|
||||
},
|
||||
),
|
||||
$lut,
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
concat!($mnemonic, " gt, gt, eq"),
|
||||
$encoding | 0x00211000,
|
||||
None,
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
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),
|
||||
],
|
||||
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(|src0, src1, src2| {
|
||||
let mut dest = src2.map(|v| Some(v.into()));
|
||||
dest.cr_gt = Some((src0.cr_gt, src1.cr_eq).into());
|
||||
dest
|
||||
}),
|
||||
$lut,
|
||||
),
|
||||
|| {
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
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),
|
||||
],
|
||||
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(
|
||||
|src0, src1, src2| {
|
||||
let mut dest = src2.map(|v| Some(v.into()));
|
||||
dest.cr_gt = Some((src0.cr_gt, src1.cr_eq).into());
|
||||
dest
|
||||
},
|
||||
),
|
||||
$lut,
|
||||
)
|
||||
},
|
||||
));
|
||||
}};
|
||||
}
|
||||
|
|
@ -89,11 +101,13 @@ pub fn test_cases_book_i_2_5_condition_register(retval: &mut Vec<TestCase>) {
|
|||
concat!("mcrf ", $dest, ", ", $src),
|
||||
$encoding,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_cr_reg_imm($src)],
|
||||
0i8.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
|| {
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_cr_reg_imm($src)],
|
||||
0i8.cast_to_static::<SInt<_>>(),
|
||||
)
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@ use fayalite::prelude::*;
|
|||
|
||||
/// 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>) {
|
||||
retval.push(insn_single(
|
||||
"addi 3, 4, 0x1234",
|
||||
0x38641234,
|
||||
None,
|
||||
retval.push(insn_single("addi 3, 4, 0x1234", 0x38641234, None, || {
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4), MOpRegNum::const_zero()],
|
||||
|
|
@ -20,42 +17,43 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single(
|
||||
"paddi 3, 4, 0x123456789, 0",
|
||||
0x06012345,
|
||||
Some(0x38646789),
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4), MOpRegNum::const_zero()],
|
||||
0x123456789i64.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
|| {
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4), MOpRegNum::const_zero()],
|
||||
0x123456789i64.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"paddi 3, 0, 0x123456789, 1",
|
||||
0x06112345,
|
||||
Some(0x38606789),
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(), MOpRegNum::const_zero()],
|
||||
0x123456789i64.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
|| {
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(), MOpRegNum::const_zero()],
|
||||
0x123456789i64.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
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(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4), MOpRegNum::const_zero()],
|
||||
|
|
@ -65,12 +63,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
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(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(); _],
|
||||
|
|
@ -80,12 +75,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
false,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"add. 3, 4, 5",
|
||||
0x7c642a15,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("add. 3, 4, 5", 0x7c642a15, None, || {
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num(3)],
|
||||
|
|
@ -102,12 +94,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
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(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
|
|
@ -123,12 +112,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
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(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num(3)],
|
||||
|
|
@ -145,12 +131,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
false,
|
||||
true,
|
||||
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(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
|
|
@ -166,12 +149,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"addc. 3, 4, 5",
|
||||
0x7c642815,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("addc. 3, 4, 5", 0x7c642815, None, || {
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
|
|
@ -191,12 +171,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
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(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
|
|
@ -216,12 +193,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"adde. 3, 4, 5",
|
||||
0x7c642915,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("adde. 3, 4, 5", 0x7c642915, None, || {
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
|
|
@ -241,12 +215,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
true,
|
||||
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(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
|
|
@ -266,12 +237,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"addme. 3, 4",
|
||||
0x7c6401d5,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("addme. 3, 4", 0x7c6401d5, None, || {
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
|
|
@ -291,12 +259,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"subfme. 3, 4",
|
||||
0x7c6401d1,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("subfme. 3, 4", 0x7c6401d1, None, || {
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
|
|
@ -316,12 +281,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"addze. 3, 4",
|
||||
0x7c640195,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("addze. 3, 4", 0x7c640195, None, || {
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
|
|
@ -341,12 +303,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"subfze. 3, 4",
|
||||
0x7c640191,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("subfze. 3, 4", 0x7c640191, None, || {
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
|
|
@ -366,12 +325,9 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"neg. 3, 4",
|
||||
0x7c6400d1,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("neg. 3, 4", 0x7c6400d1, None, || {
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num(3)],
|
||||
|
|
@ -388,6 +344,6 @@ pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>
|
|||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,28 +11,29 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
|
|||
"cmpi 3, 0, 4, 0x1234",
|
||||
0x2d841234,
|
||||
None,
|
||||
CompareMOp::compare_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4)],
|
||||
0x1234.cast_to_static::<SInt<_>>(),
|
||||
CompareMode.S32(),
|
||||
),
|
||||
|| {
|
||||
CompareMOp::compare_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4)],
|
||||
0x1234.cast_to_static::<SInt<_>>(),
|
||||
CompareMode.S32(),
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"cmpi 3, 1, 4, -0x7655",
|
||||
0x2da489ab,
|
||||
None,
|
||||
CompareMOp::compare_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4)],
|
||||
(0x89abu16 as i16).cast_to_static::<SInt<_>>(),
|
||||
CompareMode.S64(),
|
||||
),
|
||||
|| {
|
||||
CompareMOp::compare_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4)],
|
||||
(0x89abu16 as i16).cast_to_static::<SInt<_>>(),
|
||||
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(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
|
|
@ -40,12 +41,9 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
|
|||
MOpRegNum::power_isa_gpr_reg_imm(5),
|
||||
],
|
||||
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(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
|
|
@ -53,34 +51,35 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
|
|||
MOpRegNum::power_isa_gpr_reg_imm(5),
|
||||
],
|
||||
CompareMode.S64(),
|
||||
),
|
||||
));
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single(
|
||||
"cmpli 3, 0, 4, 0x1234",
|
||||
0x29841234,
|
||||
None,
|
||||
CompareMOp::compare_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4)],
|
||||
0x1234.cast_to_static::<SInt<_>>(),
|
||||
CompareMode.U32(),
|
||||
),
|
||||
|| {
|
||||
CompareMOp::compare_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4)],
|
||||
0x1234.cast_to_static::<SInt<_>>(),
|
||||
CompareMode.U32(),
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"cmpli 3, 1, 4, 0x89ab",
|
||||
0x29a489ab,
|
||||
None,
|
||||
CompareMOp::compare_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4)],
|
||||
0x89ab.cast_to_static::<SInt<_>>(),
|
||||
CompareMode.U64(),
|
||||
),
|
||||
|| {
|
||||
CompareMOp::compare_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4)],
|
||||
0x89ab.cast_to_static::<SInt<_>>(),
|
||||
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(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
|
|
@ -88,12 +87,9 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
|
|||
MOpRegNum::power_isa_gpr_reg_imm(5),
|
||||
],
|
||||
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(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
|
|
@ -101,12 +97,9 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
|
|||
MOpRegNum::power_isa_gpr_reg_imm(5),
|
||||
],
|
||||
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(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
|
|
@ -114,12 +107,9 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
|
|||
MOpRegNum::power_isa_gpr_reg_imm(5),
|
||||
],
|
||||
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(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
|
|
@ -127,12 +117,9 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
|
|||
MOpRegNum::power_isa_gpr_reg_imm(5),
|
||||
],
|
||||
CompareMode.CmpRBTwo(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"cmpeqb 3, 4, 5",
|
||||
0x7d8429c0,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("cmpeqb 3, 4, 5", 0x7d8429c0, None, || {
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
|
|
@ -140,6 +127,6 @@ pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>)
|
|||
MOpRegNum::power_isa_gpr_reg_imm(5),
|
||||
],
|
||||
CompareMode.CmpEqB(),
|
||||
),
|
||||
));
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,31 +21,33 @@ pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
|
|||
concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, "), ", $r),
|
||||
$prefix,
|
||||
Some($suffix),
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||
[
|
||||
if $r != 0 || $ra == 0 {
|
||||
MOpRegNum::const_zero()
|
||||
} else {
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra)
|
||||
},
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
$r != 0,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_temp_reg()],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
],
|
||||
|| {
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||
[
|
||||
if $r != 0 || $ra == 0 {
|
||||
MOpRegNum::const_zero()
|
||||
} else {
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra)
|
||||
},
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
$r != 0,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_temp_reg()],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
]
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
@ -60,31 +62,33 @@ pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
|
|||
concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, ")"),
|
||||
$encoding,
|
||||
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::const_zero(),
|
||||
],
|
||||
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_temp_reg()],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
],
|
||||
|| {
|
||||
[
|
||||
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::const_zero(),
|
||||
],
|
||||
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_temp_reg()],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
]
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
@ -99,27 +103,29 @@ pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
|
|||
concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, ")"),
|
||||
$encoding,
|
||||
None,
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm($ra)],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
],
|
||||
|| {
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm($ra)],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
]
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
@ -134,31 +140,33 @@ pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
|
|||
concat!($mnemonic, " ", $dest, ", ", $ra, ", ", $rb),
|
||||
$encoding,
|
||||
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,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_temp_reg()],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
],
|
||||
|| {
|
||||
[
|
||||
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,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_temp_reg()],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
]
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
@ -173,27 +181,29 @@ pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
|
|||
concat!($mnemonic, " ", $dest, ", ", $ra, ", ", $rb),
|
||||
$encoding,
|
||||
None,
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||
[
|
||||
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,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm($ra)],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
],
|
||||
|| {
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||
[
|
||||
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,
|
||||
),
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm($ra)],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
]
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,21 +25,23 @@ pub fn test_cases_book_i_3_3_13_fixed_point_logical(retval: &mut Vec<TestCase>)
|
|||
),
|
||||
$encoding,
|
||||
None,
|
||||
LogicalMOp::logical_i(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||
if $mnemonic.contains('.') {
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm($src)],
|
||||
(($imm as u32) << if $mnemonic.contains('s') { 16 } else { 0 })
|
||||
.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
Lut4::from_fn(|$a, $b| $lut_fn),
|
||||
),
|
||||
|| {
|
||||
LogicalMOp::logical_i(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||
if $mnemonic.contains('.') {
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm($src)],
|
||||
(($imm as u32) << if $mnemonic.contains('s') { 16 } else { 0 })
|
||||
.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
Lut4::from_fn(|$a, $b| $lut_fn),
|
||||
)
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
@ -98,23 +100,25 @@ pub fn test_cases_book_i_3_3_13_fixed_point_logical(retval: &mut Vec<TestCase>)
|
|||
),
|
||||
$encoding,
|
||||
None,
|
||||
LogicalMOp::logical(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||
if $mnemonic.contains('.') {
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src0),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src1),
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
Lut4::from_fn(|$a, $b| $lut_fn),
|
||||
),
|
||||
|| {
|
||||
LogicalMOp::logical(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||
if $mnemonic.contains('.') {
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src0),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src1),
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
Lut4::from_fn(|$a, $b| $lut_fn),
|
||||
)
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
@ -157,11 +161,13 @@ pub fn test_cases_book_i_3_3_13_fixed_point_logical(retval: &mut Vec<TestCase>)
|
|||
"or 3, 4, 4", // mr 3, 4
|
||||
0x7c832378,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4)],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
|| {
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(4)],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
)
|
||||
},
|
||||
));
|
||||
insn_logic! {
|
||||
"or." 3, 4, 5;
|
||||
|
|
@ -223,20 +229,22 @@ pub fn test_cases_book_i_3_3_13_fixed_point_logical(retval: &mut Vec<TestCase>)
|
|||
concat!($mnemonic, " ", stringify!($dest), ", ", stringify!($src)),
|
||||
$encoding,
|
||||
None,
|
||||
LogicalMOp::logical_i(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||
if $mnemonic.contains('.') {
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm($src)],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.$OutputIntegerMode(),
|
||||
Lut4::from_fn(|a, b| a | b),
|
||||
),
|
||||
|| {
|
||||
LogicalMOp::logical_i(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||
if $mnemonic.contains('.') {
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm($src)],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.$OutputIntegerMode(),
|
||||
Lut4::from_fn(|a, b| a | b),
|
||||
)
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
|| ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[
|
||||
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,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
|| ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],),
|
||||
[
|
||||
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,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
|| ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[
|
||||
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,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
|| ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[MOpRegNum::POWER_ISA_CR_0_REG_NUM],),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
|
|
@ -855,21 +855,23 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($amount),
|
||||
],
|
||||
shift_imm(
|
||||
None,
|
||||
false,
|
||||
ShiftAmountOverflowBehavior.$overflow_behavior(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
),
|
||||
|| {
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($amount),
|
||||
],
|
||||
shift_imm(
|
||||
None,
|
||||
false,
|
||||
ShiftAmountOverflowBehavior.$overflow_behavior(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
concat!(
|
||||
|
|
@ -883,24 +885,26 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding | 1,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
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::const_zero(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($amount),
|
||||
],
|
||||
shift_imm(
|
||||
None,
|
||||
false,
|
||||
ShiftAmountOverflowBehavior.$overflow_behavior(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
),
|
||||
|| {
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
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::const_zero(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($amount),
|
||||
],
|
||||
shift_imm(
|
||||
None,
|
||||
false,
|
||||
ShiftAmountOverflowBehavior.$overflow_behavior(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
)
|
||||
},
|
||||
));
|
||||
}};
|
||||
}
|
||||
|
|
@ -923,17 +927,19 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($amount),
|
||||
],
|
||||
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
),
|
||||
|| {
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($amount),
|
||||
],
|
||||
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
concat!(
|
||||
|
|
@ -947,20 +953,22 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding | 1,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($amount),
|
||||
],
|
||||
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
),
|
||||
|| {
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($amount),
|
||||
],
|
||||
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
)
|
||||
},
|
||||
));
|
||||
}};
|
||||
}
|
||||
|
|
@ -983,23 +991,25 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
|| {
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||
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),
|
||||
],
|
||||
&[],
|
||||
),
|
||||
[
|
||||
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(),
|
||||
),
|
||||
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
concat!(
|
||||
|
|
@ -1013,23 +1023,25 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding | 1,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
|| {
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||
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),
|
||||
],
|
||||
&[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()),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
),
|
||||
shift_imm(None, true, ShiftAmountOverflowBehavior.$overflow_behavior()),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
)
|
||||
},
|
||||
));
|
||||
}};
|
||||
}
|
||||
|
|
@ -1051,27 +1063,29 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
|| {
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
&[],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
shift_imm(
|
||||
Some($amount),
|
||||
true,
|
||||
ShiftAmountOverflowBehavior.WrapToUInt6(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
),
|
||||
shift_imm(
|
||||
Some($amount),
|
||||
true,
|
||||
ShiftAmountOverflowBehavior.WrapToUInt6(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
concat!(
|
||||
|
|
@ -1085,27 +1099,29 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding | 1,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
|| {
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num($dest),
|
||||
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(),
|
||||
],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
shift_imm(
|
||||
Some($amount),
|
||||
true,
|
||||
ShiftAmountOverflowBehavior.WrapToUInt6(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
),
|
||||
shift_imm(
|
||||
Some($amount),
|
||||
true,
|
||||
ShiftAmountOverflowBehavior.WrapToUInt6(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.$shift_rotate_mode(),
|
||||
)
|
||||
},
|
||||
));
|
||||
}};
|
||||
}
|
||||
|
|
@ -1212,21 +1228,23 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
shift_imm(
|
||||
Some($amount),
|
||||
false,
|
||||
ShiftAmountOverflowBehavior.WrapToUInt6(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.SignExt32To64BitThenShift(),
|
||||
),
|
||||
|| {
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src),
|
||||
MOpRegNum::const_zero(),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
shift_imm(
|
||||
Some($amount),
|
||||
false,
|
||||
ShiftAmountOverflowBehavior.WrapToUInt6(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.SignExt32To64BitThenShift(),
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
concat!(
|
||||
|
|
@ -1240,24 +1258,26 @@ pub fn test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(retval: &mut Vec<Te
|
|||
),
|
||||
$encoding | 1,
|
||||
None,
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
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::const_zero(),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
shift_imm(
|
||||
Some($amount),
|
||||
false,
|
||||
ShiftAmountOverflowBehavior.WrapToUInt6(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.SignExt32To64BitThenShift(),
|
||||
),
|
||||
|| {
|
||||
ShiftRotateMOp::shift_rotate(
|
||||
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::const_zero(),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
shift_imm(
|
||||
Some($amount),
|
||||
false,
|
||||
ShiftAmountOverflowBehavior.WrapToUInt6(),
|
||||
),
|
||||
OutputIntegerMode.Full64(),
|
||||
ShiftRotateMode.SignExt32To64BitThenShift(),
|
||||
)
|
||||
},
|
||||
));
|
||||
}};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,34 +20,36 @@ pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
|
|||
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, "), ", $r),
|
||||
$prefix,
|
||||
Some($suffix),
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||
[
|
||||
if $r != 0 || $ra == 0 {
|
||||
MOpRegNum::const_zero()
|
||||
} else {
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra)
|
||||
},
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
$r != 0,
|
||||
),
|
||||
StoreMOp::store(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_temp_reg(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($rs),
|
||||
],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.ZeroExt(),
|
||||
),
|
||||
],
|
||||
|| {
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||
[
|
||||
if $r != 0 || $ra == 0 {
|
||||
MOpRegNum::const_zero()
|
||||
} else {
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra)
|
||||
},
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
$r != 0,
|
||||
),
|
||||
StoreMOp::store(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_temp_reg(),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($rs),
|
||||
],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.ZeroExt(),
|
||||
),
|
||||
]
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
@ -61,34 +63,36 @@ pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
|
|||
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
|
||||
$encoding,
|
||||
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::const_zero(),
|
||||
],
|
||||
($disp as i64).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(),
|
||||
),
|
||||
],
|
||||
|| {
|
||||
[
|
||||
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::const_zero(),
|
||||
],
|
||||
($disp as i64).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(),
|
||||
),
|
||||
]
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
|
|
@ -103,65 +107,69 @@ pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
|
|||
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
|
||||
$encoding,
|
||||
None,
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
($disp as i64).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<_>>(),
|
||||
),
|
||||
],
|
||||
|| {
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
($disp as i64).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 {
|
||||
retval.push(insn_double(
|
||||
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
|
||||
$encoding,
|
||||
None,
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
StoreMOp::store(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($rs),
|
||||
],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.ZeroExt(),
|
||||
),
|
||||
],
|
||||
|| {
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra),
|
||||
MOpRegNum::const_zero(),
|
||||
],
|
||||
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
StoreMOp::store(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($rs),
|
||||
],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.ZeroExt(),
|
||||
),
|
||||
]
|
||||
},
|
||||
));
|
||||
}
|
||||
};
|
||||
|
|
@ -176,86 +184,10 @@ pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
|
|||
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
|
||||
$encoding,
|
||||
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(
|
||||
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 {
|
||||
retval.push(insn_double(
|
||||
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
|
||||
$encoding,
|
||||
None,
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||
[
|
||||
if $ra == 0 {
|
||||
MOpRegNum::const_zero()
|
||||
|
|
@ -274,13 +206,95 @@ pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
|
|||
StoreMOp::store(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra),
|
||||
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(
|
||||
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 {
|
||||
retval.push(insn_double(
|
||||
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
|
||||
$encoding,
|
||||
None,
|
||||
|| {
|
||||
[
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||
[
|
||||
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_gpr_reg_imm($ra),
|
||||
MOpRegNum::power_isa_gpr_reg_imm($rs),
|
||||
],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.ZeroExt(),
|
||||
),
|
||||
]
|
||||
},
|
||||
));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,10 +23,7 @@ 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),
|
||||
}
|
||||
}
|
||||
retval.push(insn_single(
|
||||
"mcrxrx 3",
|
||||
0x7d800480,
|
||||
None,
|
||||
retval.push(insn_single("mcrxrx 3", 0x7d800480, None, || {
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
|
|
@ -36,114 +33,114 @@ pub fn test_cases_book_i_3_3_19_move_to_from_system_register(retval: &mut Vec<Te
|
|||
],
|
||||
mcrxrx_imm(),
|
||||
Lut4::from_fn(|a, b| a | b),
|
||||
),
|
||||
));
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
/// 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>) {
|
||||
retval.push(insn_single(
|
||||
"mflr 3",
|
||||
0x7c6802a6,
|
||||
None,
|
||||
retval.push(insn_single("mflr 3", 0x7c6802a6, None, || {
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_lr_reg()],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"mtlr 3",
|
||||
0x7c6803a6,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("mtlr 3", 0x7c6803a6, None, || {
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(3)],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"mfctr 3",
|
||||
0x7c6902a6,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("mfctr 3", 0x7c6902a6, None, || {
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_ctr_reg()],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"mtctr 3",
|
||||
0x7c6903a6,
|
||||
None,
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single("mtctr 3", 0x7c6903a6, None, || {
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_CTR_REG_NUM], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(3)],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
)
|
||||
}));
|
||||
retval.push(insn_single(
|
||||
"mfspr 3, 815 # mftar 3",
|
||||
0x7c6fcaa6,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_tar_reg()],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
|| {
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_tar_reg()],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
)
|
||||
},
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"mtspr 815, 3 # mttar 3",
|
||||
0x7c6fcba6,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TAR_REG_NUM], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(3)],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
|| {
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TAR_REG_NUM], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(3)],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
)
|
||||
},
|
||||
));
|
||||
// make sure we generate mfspr and not the phased-out mftb
|
||||
retval.push(insn_single(
|
||||
"mfspr 3, 268 # mftb 3",
|
||||
0x7c6c42a6,
|
||||
None,
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(); 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBase(),
|
||||
),
|
||||
|| {
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(); 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBase(),
|
||||
)
|
||||
},
|
||||
));
|
||||
// make sure we generate mfspr and not the phased-out mftb
|
||||
retval.push(insn_single(
|
||||
"mfspr 3, 269 # mftbu 3",
|
||||
0x7c6d42a6,
|
||||
None,
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(); 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBaseU(),
|
||||
),
|
||||
|| {
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(); 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBaseU(),
|
||||
)
|
||||
},
|
||||
));
|
||||
// phased-out mftb -- not actually generated by the assembler so we have to use .long
|
||||
retval.push(insn_single(
|
||||
".long 0x7c6c42e6 # mftb 3, 268",
|
||||
0x7c6c42e6,
|
||||
None,
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(); 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBase(),
|
||||
),
|
||||
|| {
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(); 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBase(),
|
||||
)
|
||||
},
|
||||
));
|
||||
// phased-out mftb -- not actually generated by the assembler so we have to use .long
|
||||
retval.push(insn_single(
|
||||
".long 0x7c6d42e6 # mftb 3, 269",
|
||||
0x7c6d42e6,
|
||||
None,
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(); 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBaseU(),
|
||||
),
|
||||
|| {
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero(); 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBaseU(),
|
||||
)
|
||||
},
|
||||
));
|
||||
}
|
||||
|
|
|
|||
234
crates/cpu/tests/units_formal.rs
Normal file
234
crates/cpu/tests/units_formal.rs
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
// 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, "");
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
fn check_power_isa_add_formal(config: PhantomConst<CpuConfig>) {
|
||||
#[hdl]
|
||||
let clk: Clock = m.input();
|
||||
#[hdl]
|
||||
let cd = wire();
|
||||
connect(
|
||||
cd,
|
||||
#[hdl]
|
||||
ClockDomain {
|
||||
clk,
|
||||
rst: formal_reset().to_reset(),
|
||||
},
|
||||
);
|
||||
#[hdl]
|
||||
let harness = instance(formal_harness(config));
|
||||
connect(harness.cd, cd);
|
||||
#[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,
|
||||
),
|
||||
);
|
||||
#[hdl]
|
||||
let input_r3 = wire();
|
||||
connect(input_r3, any_const(StaticType::TYPE));
|
||||
#[hdl]
|
||||
let input_r4 = wire();
|
||||
connect(input_r4, any_const(StaticType::TYPE));
|
||||
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 {
|
||||
#[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);
|
||||
println!("starting assert formal");
|
||||
assert_formal(
|
||||
"test_power_isa_add_formal",
|
||||
m,
|
||||
FormalMode::Prove,
|
||||
10,
|
||||
None,
|
||||
ExportOptions {
|
||||
simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue