add cpu::test::decode_and_run_single_insn and some formal tests of running PowerISA instructions #15
39 changed files with 855063 additions and 110566 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#bb34aeb7f1881ad03a320f9f792994a88afe5fe2"
|
||||
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#bb34aeb7f1881ad03a320f9f792994a88afe5fe2"
|
||||
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#bb34aeb7f1881ad03a320f9f792994a88afe5fe2"
|
||||
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#bb34aeb7f1881ad03a320f9f792994a88afe5fe2"
|
||||
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,39 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
|||
),
|
||||
];
|
||||
|
||||
const MAX_MOPS_PER_INSN: usize = 3;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DecodeFilterArgs<'a> {
|
||||
mnemonic: &'a str,
|
||||
}
|
||||
|
||||
impl DecodeFilterArgs<'_> {
|
||||
pub fn mnemonic(&self) -> &str {
|
||||
self.mnemonic
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DecodeFilter {
|
||||
fn should_include(&mut self, args: &DecodeFilterArgs<'_>) -> bool;
|
||||
}
|
||||
|
||||
impl<T: ?Sized + FnMut(&DecodeFilterArgs<'_>) -> bool> DecodeFilter for T {
|
||||
fn should_include(&mut self, args: &DecodeFilterArgs<'_>) -> bool {
|
||||
self(args)
|
||||
}
|
||||
}
|
||||
|
||||
impl DecodeFilter for () {
|
||||
fn should_include(&mut self, _args: &DecodeFilterArgs<'_>) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn decode_one_insn() {
|
||||
pub fn decode_one_insn(mut filter: impl DecodeFilter) {
|
||||
#[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 +2789,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 {
|
||||
|
|
@ -2798,24 +2843,70 @@ pub fn decode_one_insn() {
|
|||
let Some(decode_fn) = decode_fns.get(mnemonic) else {
|
||||
panic!("unhandled mnemonic: {mnemonic:?}");
|
||||
};
|
||||
decode_fn(&mut DecodeState {
|
||||
mnemonic,
|
||||
arguments,
|
||||
conditions,
|
||||
header,
|
||||
insn,
|
||||
output,
|
||||
is_illegal,
|
||||
first_input,
|
||||
second_input,
|
||||
second_input_used,
|
||||
field_wires: &mut field_wires,
|
||||
});
|
||||
if filter.should_include(&DecodeFilterArgs { mnemonic }) {
|
||||
decode_fn(&mut DecodeState {
|
||||
mnemonic,
|
||||
arguments,
|
||||
conditions,
|
||||
header,
|
||||
insn,
|
||||
output,
|
||||
is_illegal,
|
||||
first_input,
|
||||
has_second_input,
|
||||
second_input_value,
|
||||
second_input_used,
|
||||
field_wires: &mut field_wires,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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!()
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ impl<T: MOpTrait> MOpInto<T> for T {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait MOpLeaf<Target: MOpTrait>: MOpInto<Target> {}
|
||||
|
||||
pub trait MOpVariantVisitOps {
|
||||
type MOp: MOpTrait<
|
||||
DestReg = <Self::Target as MOpTrait>::DestReg,
|
||||
|
|
@ -115,7 +117,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 }>>,
|
||||
) {
|
||||
|
|
@ -533,6 +535,8 @@ impl<SrcCount: KnownSize> StaticType for CommonMOpDefaultImm<SrcCount> {
|
|||
}
|
||||
|
||||
impl<SrcCount: KnownSize> HdlPartialEqImpl<Self> for CommonMOpDefaultImm<SrcCount> {
|
||||
const TRY_STRUCTURAL_EQ: bool = true;
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
_lhs: Self,
|
||||
|
|
@ -714,6 +718,35 @@ pub const COMMON_MOP_2_IMM_WIDTH: usize = common_mop_max_imm_size(2);
|
|||
pub const COMMON_MOP_3_IMM_WIDTH: usize = common_mop_max_imm_size(3);
|
||||
|
||||
macro_rules! common_mop_struct {
|
||||
(
|
||||
#[leaf]
|
||||
$(#[debug($($debug:tt)*)])?
|
||||
#[mapped(<$NewDestReg:ident, $NewSrcReg:ident> $mapped_ty:ty)]
|
||||
$(#[$struct_meta:meta])*
|
||||
$vis:vis struct $MOp:ident<$DestReg:ident: $DestRegBound:ident, $SrcReg:ident: $SrcRegBound:ident $(, $Generic:ident: $GenericBound:ident)* $(,)?> {
|
||||
$($body:tt)*
|
||||
}
|
||||
) => {
|
||||
common_mop_struct! {
|
||||
$(#[debug($($debug)*)])?
|
||||
#[mapped(<$NewDestReg, $NewSrcReg> $mapped_ty)]
|
||||
$(#[$struct_meta])*
|
||||
$vis struct $MOp<$DestReg: $DestRegBound, $SrcReg: $SrcRegBound $(, $Generic: $GenericBound)*> {
|
||||
$($body)*
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
$DestReg: $DestRegBound,
|
||||
$SrcReg: $SrcRegBound,
|
||||
$($Generic: $GenericBound,)*
|
||||
Target: MOpTrait,
|
||||
> MOpLeaf<Target> for $MOp<$DestReg, $SrcReg, $($Generic),*>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
}
|
||||
};
|
||||
(
|
||||
#[debug($(#[$debug_hdl:ident])? |$debug_value:ident, $debug_f:ident| $debug_block:block $(where $($debug_where:tt)*)?)]
|
||||
#[mapped(<$NewDestReg:ident, $SrcReg:ident> $mapped_ty:ty)]
|
||||
|
|
@ -1322,6 +1355,7 @@ macro_rules! maybe_write_comma_flag {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let AddSubMOp::<_, _, _> {
|
||||
|
|
@ -1909,6 +1943,7 @@ impl LogicalFlagsMOpImm {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let LogicalFlagsMOp::<_, _> {
|
||||
|
|
@ -2073,6 +2108,7 @@ impl<DestReg: Type, SrcReg: Type> LogicalFlagsMOp<DestReg, SrcReg> {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let LogicalMOp::<_, _, _> {
|
||||
|
|
@ -2350,6 +2386,7 @@ impl SimValueDebug for ShiftRotateMOpImm {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let ShiftRotateMOp::<_, _> {
|
||||
|
|
@ -2465,6 +2502,7 @@ impl CompareMode {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let CompareMOp::<_, _, _> {
|
||||
|
|
@ -2569,6 +2607,7 @@ impl ConditionMode {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let BranchMOp::<_, _, _> {
|
||||
|
|
@ -2736,6 +2775,7 @@ pub enum ReadSpecialMOpImm {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let ReadSpecialMOp::<_, _> {
|
||||
|
|
@ -2826,6 +2866,7 @@ impl SimValueDebug for L2RegNum {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let ReadL2RegMOp::<_, _> {
|
||||
|
|
@ -2868,6 +2909,7 @@ impl<DestReg: Type, SrcReg: Type> ReadL2RegMOp<DestReg, SrcReg> {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let WriteL2RegMOp::<_, _> {
|
||||
|
|
@ -3014,6 +3056,7 @@ impl<DestReg: Type, SrcReg: Type, SrcCount: KnownSize>
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let LoadMOp::<_, _> {
|
||||
|
|
@ -3062,6 +3105,7 @@ impl<DestReg: Type, SrcReg: Type> LoadMOp<DestReg, SrcReg> {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let StoreMOp::<_, _> {
|
||||
|
|
@ -3120,6 +3164,7 @@ mop_enum! {
|
|||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[leaf]
|
||||
#[debug(#[hdl] |this, f| {
|
||||
#[hdl(sim)]
|
||||
let MoveRegMOp::<_, _> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
952
crates/cpu/src/test/decode_and_run_single_insn.rs
Normal file
952
crates/cpu/src/test/decode_and_run_single_insn.rs
Normal file
|
|
@ -0,0 +1,952 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{
|
||||
config::{CpuConfig, CpuConfigUnitCount, PhantomConstCpuConfig},
|
||||
instruction::{
|
||||
COMMON_MOP_SRC_LEN, MOp, MOpDestReg, MOpRegNum, MOpTrait, MoveRegMOp, PRegNum, UnitNum,
|
||||
UnitOutRegNum,
|
||||
},
|
||||
next_pc::{CallStackOp, FETCH_BLOCK_ID_WIDTH},
|
||||
register::PRegValue,
|
||||
rename_execute_retire::{
|
||||
ExecuteToUnitInterface, GlobalState, MOpId, MOpInstance, NextPcPredictorOp, RenamedMOp,
|
||||
UnitCausedCancel, UnitEnqueue, UnitFinishCauseCancel, UnitInputsReady,
|
||||
UnitMOpIsNoLongerSpeculative, UnitOutputReady, to_unit_interfaces::ExecuteToUnitInterfaces,
|
||||
},
|
||||
unit::{HdlUnitKind, UnitMOp},
|
||||
util::array_vec::ArrayVec,
|
||||
};
|
||||
use fayalite::{
|
||||
bundle::BundleType,
|
||||
int::UIntInRangeType,
|
||||
intern::{Intern, Interned},
|
||||
module::wire_with_loc,
|
||||
prelude::*,
|
||||
util::{prefix_sum::reduce, ready_valid::ReadyValid},
|
||||
};
|
||||
|
||||
/// make arrays dynamically-sized to avoid putting large types on the stack
|
||||
#[hdl(get(|c| 1 << MOpRegNum::WIDTH))]
|
||||
type MOpRegCount<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(cmp_eq, no_static)]
|
||||
pub struct Registers<C: PhantomConstGet<CpuConfig>> {
|
||||
pub regs: ArrayType<TraceAsString<PRegValue>, MOpRegCount<C>>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
impl<C: PhantomConstCpuConfig> Registers<C> {
|
||||
#[hdl]
|
||||
pub fn zeroed(self) -> Expr<Self> {
|
||||
#[hdl]
|
||||
Self {
|
||||
regs: repeat(PRegValue::zeroed().into_trace_as_string(), self.regs.len()),
|
||||
config: self.config,
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
pub fn zeroed_sim(self) -> SimValue<Self> {
|
||||
#[hdl(sim)]
|
||||
Self {
|
||||
regs: vec![PRegValue::zeroed_sim().into_trace_as_string(); self.regs.len()],
|
||||
config: self.config,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct DecodeOneInsnOutput<MaxMOpCount: Size> {
|
||||
pub mops: ArrayVec<TraceAsString<MOp>, MaxMOpCount>,
|
||||
pub size_in_bytes: UInt<4>,
|
||||
pub is_illegal: Bool,
|
||||
}
|
||||
|
||||
pub trait DecodeOneInsn: BundleType {
|
||||
type Input: Type;
|
||||
fn input_ty(self) -> Self::Input;
|
||||
type MaxMOpCount: Size;
|
||||
fn max_mop_count(self) -> <Self::MaxMOpCount as Size>::SizeType;
|
||||
fn connect_io(
|
||||
this: Expr<Self>,
|
||||
input: Expr<Self::Input>,
|
||||
output: Expr<DecodeOneInsnOutput<Self::MaxMOpCount>>,
|
||||
);
|
||||
}
|
||||
|
||||
pub type DecodeOneInsnInput<T> = <T as DecodeOneInsn>::Input;
|
||||
#[doc(hidden)]
|
||||
#[expect(non_upper_case_globals)]
|
||||
pub const DecodeOneInsnInput: DecodeOneInsnInputWithoutGenerics =
|
||||
DecodeOneInsnInputWithoutGenerics {};
|
||||
#[doc(hidden)]
|
||||
pub struct DecodeOneInsnInputWithoutGenerics {}
|
||||
|
||||
impl<T: DecodeOneInsn> std::ops::Index<T> for DecodeOneInsnInputWithoutGenerics {
|
||||
type Output = DecodeOneInsnInput<T>;
|
||||
|
||||
fn index(&self, index: T) -> &Self::Output {
|
||||
Interned::into_inner(index.input_ty().intern_sized())
|
||||
}
|
||||
}
|
||||
|
||||
pub type DecodeOneInsnMaxMOpCount<T> = <T as DecodeOneInsn>::MaxMOpCount;
|
||||
#[doc(hidden)]
|
||||
#[expect(non_upper_case_globals)]
|
||||
pub const DecodeOneInsnMaxMOpCount: DecodeOneInsnMaxMOpCountWithoutGenerics =
|
||||
DecodeOneInsnMaxMOpCountWithoutGenerics {};
|
||||
#[doc(hidden)]
|
||||
pub struct DecodeOneInsnMaxMOpCountWithoutGenerics {}
|
||||
|
||||
impl<T: DecodeOneInsn> std::ops::Index<T> for DecodeOneInsnMaxMOpCountWithoutGenerics {
|
||||
type Output = <T::MaxMOpCount as Size>::SizeType;
|
||||
|
||||
fn index(&self, index: T) -> &Self::Output {
|
||||
Interned::into_inner(index.max_mop_count().intern_sized())
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct DecodeAndRunSingleInsnInput<C: PhantomConstGet<CpuConfig>, I> {
|
||||
pub decoder_input: I,
|
||||
pub fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
|
||||
pub first_id: MOpId,
|
||||
pub pc: UInt<64>,
|
||||
pub predicted_next_pc: UInt<64>,
|
||||
pub regs: Registers<C>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct DecodeAndRunSingleInsnOutput<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
pub regs: Registers<C>,
|
||||
pub cancel_and_start_at: HdlOption<UInt<64>>,
|
||||
pub retired_insns: ArrayVec<NextPcPredictorOp<C>, MaxMOpCount>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct UnrenamedMOpState<C: PhantomConstGet<CpuConfig>> {
|
||||
unrenamed: MOpInstance<MOp>,
|
||||
renamed: HdlOption<TraceAsString<RenamedMOp<C>>>,
|
||||
unit_num: TraceAsString<UnitNum<C>>,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
enum Error {
|
||||
NoUnitsOfKind(HdlUnitKind),
|
||||
UnexpectedOutputReadyId(MOpId),
|
||||
UnexpectedFinishCauseCancelId(MOpId),
|
||||
InconsistentState,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct CancelState<C: PhantomConstGet<CpuConfig>> {
|
||||
canceling_units: ArrayType<Bool, CpuConfigUnitCount<C>>,
|
||||
config: C,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
enum UnitState {
|
||||
NotYetEnqueued,
|
||||
SentInputsReady,
|
||||
OutputReady,
|
||||
FinishedAndOrCausedCancel,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct RunMOpState<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
mop_index: UIntInRangeType<ConstUsize<0>, MaxMOpCount>,
|
||||
unit_state: UnitState,
|
||||
config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
enum RunState<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
RunningMOp(RunMOpState<C, MaxMOpCount>),
|
||||
CancelingUnits(CancelState<C>),
|
||||
Finished,
|
||||
Error(TraceAsString<Error>),
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct OutputState<C: PhantomConstGet<CpuConfig>> {
|
||||
dest_value: TraceAsString<PRegValue>,
|
||||
predictor_op: NextPcPredictorOp<C>,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct DecodeAndRunSingleInsnState<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
mops: ArrayVec<UnrenamedMOpState<C>, MaxMOpCount>,
|
||||
regs: Registers<C>,
|
||||
run_state: RunState<C, MaxMOpCount>,
|
||||
output_state: HdlOption<OutputState<C>>,
|
||||
cancel_and_start_at: HdlOption<UInt<64>>,
|
||||
retired_insns: ArrayVec<NextPcPredictorOp<C>, MaxMOpCount>,
|
||||
config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
enum StepOutput<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
Finished(DecodeAndRunSingleInsnOutput<C, MaxMOpCount>),
|
||||
Step(DecodeAndRunSingleInsnState<C, MaxMOpCount>),
|
||||
Error(TraceAsString<Error>),
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn connect_to_unit_nop<C: Type + PhantomConstGet<CpuConfig>>(
|
||||
to_unit: Expr<ExecuteToUnitInterface<C>>,
|
||||
global_state: impl ToExpr<Type = GlobalState>,
|
||||
) {
|
||||
#[hdl]
|
||||
let ExecuteToUnitInterface::<_> {
|
||||
global_state: to_unit_global_state,
|
||||
enqueue,
|
||||
inputs_ready,
|
||||
is_no_longer_speculative,
|
||||
cant_cause_cancel: _,
|
||||
output_ready: _,
|
||||
finish_cause_cancel: _,
|
||||
unit_outputs_ready,
|
||||
cancel_all,
|
||||
config: _,
|
||||
} = to_unit;
|
||||
connect(to_unit_global_state, global_state);
|
||||
connect(enqueue.data, enqueue.ty().data.HdlNone());
|
||||
connect(inputs_ready, inputs_ready.ty().HdlNone());
|
||||
connect(
|
||||
is_no_longer_speculative,
|
||||
is_no_longer_speculative.ty().HdlNone(),
|
||||
);
|
||||
connect(unit_outputs_ready, false);
|
||||
connect(cancel_all.data, HdlNone());
|
||||
}
|
||||
|
||||
impl<C: PhantomConstCpuConfig, MaxMOpCount: Size> DecodeAndRunSingleInsnState<C, MaxMOpCount> {
|
||||
#[hdl]
|
||||
fn new(
|
||||
input: Expr<DecodeAndRunSingleInsnInput<C, impl Type>>,
|
||||
decoder_output: Expr<DecodeOneInsnOutput<MaxMOpCount>>,
|
||||
config: C,
|
||||
max_mop_count: MaxMOpCount::SizeType,
|
||||
) -> Expr<Self> {
|
||||
#[hdl]
|
||||
let new_state = wire(DecodeAndRunSingleInsnState[config][max_mop_count]);
|
||||
#[hdl]
|
||||
let Self {
|
||||
mops,
|
||||
regs,
|
||||
run_state,
|
||||
output_state,
|
||||
cancel_and_start_at,
|
||||
retired_insns,
|
||||
config: _,
|
||||
} = new_state;
|
||||
connect(run_state, run_state.ty().Finished());
|
||||
connect(output_state, output_state.ty().HdlNone());
|
||||
connect(cancel_and_start_at, HdlNone());
|
||||
connect(retired_insns, retired_insns.ty().new());
|
||||
connect(
|
||||
mops,
|
||||
ArrayVec::map(
|
||||
decoder_output.mops,
|
||||
mops.ty().element(),
|
||||
|index, decoded_mop| {
|
||||
if index == 0 {
|
||||
connect(
|
||||
run_state,
|
||||
run_state.ty().RunningMOp(
|
||||
#[hdl]
|
||||
RunMOpState::<_, _> {
|
||||
mop_index: 0usize.cast_to(run_state.ty().RunningMOp.mop_index),
|
||||
unit_state: UnitState.NotYetEnqueued(),
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
let retval = wire_with_loc(
|
||||
&format!("mops_{index}"),
|
||||
SourceLocation::caller(),
|
||||
UnrenamedMOpState[config],
|
||||
);
|
||||
#[hdl]
|
||||
let UnrenamedMOpState::<_> {
|
||||
unrenamed,
|
||||
renamed,
|
||||
unit_num,
|
||||
} = retval;
|
||||
#[hdl]
|
||||
let MOpInstance::<_> {
|
||||
fetch_block_id,
|
||||
id,
|
||||
pc,
|
||||
predicted_next_pc,
|
||||
size_in_bytes,
|
||||
is_first_mop_in_insn,
|
||||
is_last_mop_in_insn,
|
||||
mop,
|
||||
} = unrenamed;
|
||||
connect(fetch_block_id, input.fetch_block_id);
|
||||
connect(id, (input.first_id + index).cast_to_static::<MOpId>());
|
||||
connect(pc, input.pc);
|
||||
connect(predicted_next_pc, input.predicted_next_pc);
|
||||
connect(size_in_bytes, decoder_output.size_in_bytes);
|
||||
connect(is_first_mop_in_insn, index == 0);
|
||||
connect(
|
||||
is_last_mop_in_insn,
|
||||
ArrayVec::len(decoder_output.mops).cmp_eq(index + 1),
|
||||
);
|
||||
connect(mop, decoded_mop);
|
||||
#[hdl]
|
||||
let renamed_untransformed_move = wire(
|
||||
HdlOption[TraceAsString[UnitMOp[PRegNum[config]][PRegNum[config]]
|
||||
[MoveRegMOp[PRegNum[config]][PRegNum[config]]]]],
|
||||
);
|
||||
#[hdl]
|
||||
if let MOp::TransformedMove(_) = *mop {
|
||||
connect(
|
||||
renamed_untransformed_move,
|
||||
renamed_untransformed_move.ty().HdlNone(),
|
||||
);
|
||||
} else {
|
||||
let unit_kind = MOp::kind(*mop);
|
||||
let available_units = config.get().available_units_for_kind(unit_kind);
|
||||
let chosen_unit = reduce(
|
||||
available_units.into_iter().enumerate().map(
|
||||
|(unit_index, available_unit)| {
|
||||
#[hdl]
|
||||
let chosen_unit = wire(UnitNum[config]);
|
||||
connect(chosen_unit, chosen_unit.ty().const_zero());
|
||||
#[hdl]
|
||||
if available_unit {
|
||||
connect(
|
||||
chosen_unit,
|
||||
chosen_unit.ty().from_index(unit_index),
|
||||
);
|
||||
}
|
||||
chosen_unit
|
||||
},
|
||||
),
|
||||
|a, b| {
|
||||
#[hdl]
|
||||
let chosen_unit = wire(UnitNum[config]);
|
||||
connect(chosen_unit, a);
|
||||
#[hdl]
|
||||
if a.cmp_eq(chosen_unit.ty().const_zero()) {
|
||||
connect(chosen_unit, b);
|
||||
}
|
||||
chosen_unit
|
||||
},
|
||||
)
|
||||
.unwrap_or(UnitNum[config].const_zero());
|
||||
#[hdl]
|
||||
if chosen_unit.cmp_eq(chosen_unit.ty().const_zero()) {
|
||||
connect(
|
||||
run_state,
|
||||
run_state
|
||||
.ty()
|
||||
.Error(Error.NoUnitsOfKind(unit_kind).to_trace_as_string()),
|
||||
);
|
||||
}
|
||||
let unit_out_reg_num_ty = UnitOutRegNum[config];
|
||||
connect(
|
||||
renamed_untransformed_move,
|
||||
HdlSome(
|
||||
MOpTrait::map_regs(
|
||||
*mop,
|
||||
#[hdl]
|
||||
PRegNum::<_> {
|
||||
unit_num: chosen_unit,
|
||||
unit_out_reg: #[hdl]
|
||||
UnitOutRegNum::<_> {
|
||||
value: !unit_out_reg_num_ty.value.zero(),
|
||||
config,
|
||||
},
|
||||
},
|
||||
PRegNum[config],
|
||||
&mut |src_reg, index| {
|
||||
#[hdl]
|
||||
let renamed_src_reg = wire(PRegNum[config]);
|
||||
#[hdl]
|
||||
if src_reg.cmp_eq(MOpRegNum::const_zero()) {
|
||||
connect(
|
||||
renamed_src_reg,
|
||||
renamed_src_reg.ty().const_zero(),
|
||||
);
|
||||
} else {
|
||||
connect(
|
||||
renamed_src_reg,
|
||||
#[hdl]
|
||||
PRegNum::<_> {
|
||||
unit_num: chosen_unit,
|
||||
unit_out_reg: unit_out_reg_num_ty
|
||||
.new_sim(index),
|
||||
},
|
||||
);
|
||||
}
|
||||
renamed_src_reg
|
||||
},
|
||||
)
|
||||
.to_trace_as_string(),
|
||||
),
|
||||
);
|
||||
}
|
||||
connect(renamed, renamed.ty().HdlNone());
|
||||
connect(*unit_num, unit_num.ty().inner_ty().const_zero());
|
||||
#[hdl]
|
||||
if let HdlSome(renamed_untransformed_move) = renamed_untransformed_move {
|
||||
let v = UnitMOp::try_with_transformed_move_op(
|
||||
*renamed_untransformed_move,
|
||||
renamed.ty().HdlSome.inner_ty().TransformedMove,
|
||||
|dest, _src| {
|
||||
connect(dest, dest.ty().HdlNone());
|
||||
},
|
||||
);
|
||||
#[hdl]
|
||||
if let HdlSome(v) = v {
|
||||
connect(renamed, HdlSome(v.to_trace_as_string()));
|
||||
connect(*unit_num, MOpTrait::dest_reg(v).unit_num);
|
||||
}
|
||||
}
|
||||
retval
|
||||
},
|
||||
),
|
||||
);
|
||||
connect(regs, input.regs);
|
||||
#[hdl]
|
||||
if PRegValue::zeroed().cmp_ne(*regs.regs[MOpRegNum::CONST_ZERO_REG_NUM as usize]) {
|
||||
connect(
|
||||
run_state,
|
||||
run_state
|
||||
.ty()
|
||||
.Error(Error.InconsistentState().to_trace_as_string()),
|
||||
);
|
||||
}
|
||||
new_state
|
||||
}
|
||||
#[hdl]
|
||||
fn step(
|
||||
this: Expr<Self>,
|
||||
to_units: Expr<ExecuteToUnitInterfaces<C>>,
|
||||
global_state: Expr<GlobalState>,
|
||||
) -> Expr<StepOutput<C, MaxMOpCount>> {
|
||||
#[hdl]
|
||||
let Self {
|
||||
mops,
|
||||
regs,
|
||||
run_state,
|
||||
output_state,
|
||||
cancel_and_start_at,
|
||||
retired_insns,
|
||||
config,
|
||||
} = this;
|
||||
let config = config.ty();
|
||||
let max_mop_count = MaxMOpCount::from_usize(mops.ty().capacity());
|
||||
#[hdl]
|
||||
let stepped = wire(StepOutput[config][max_mop_count]);
|
||||
let to_units_as_array = ExecuteToUnitInterfaces::unit_fields_as_array_wire(
|
||||
to_units,
|
||||
"to_units_as_array",
|
||||
false,
|
||||
);
|
||||
for to_unit in to_units_as_array {
|
||||
connect_to_unit_nop(to_unit, global_state);
|
||||
}
|
||||
#[hdl]
|
||||
let stepped_step = wire(stepped.ty().Step);
|
||||
connect(stepped_step, this);
|
||||
connect(stepped, stepped.ty().Step(stepped_step));
|
||||
#[hdl]
|
||||
match run_state {
|
||||
RunState::<_, _>::RunningMOp(run_mop_state) => {
|
||||
#[hdl]
|
||||
let RunMOpState::<_, _> {
|
||||
mop_index,
|
||||
unit_state,
|
||||
config: _,
|
||||
} = run_mop_state;
|
||||
let mop_index = mop_index.cast_to(UInt[mop_index.ty().bit_width()]);
|
||||
#[hdl]
|
||||
let mop = wire(mops.ty().element());
|
||||
connect(mop, mops[mop_index]);
|
||||
#[hdl]
|
||||
let UnrenamedMOpState::<_> {
|
||||
unrenamed,
|
||||
renamed,
|
||||
unit_num,
|
||||
} = mop;
|
||||
#[hdl]
|
||||
let unrenamed_src_regs = wire();
|
||||
connect(
|
||||
unrenamed_src_regs,
|
||||
repeat(
|
||||
MOpRegNum::const_zero(),
|
||||
ConstUsize::<{ COMMON_MOP_SRC_LEN }>,
|
||||
),
|
||||
);
|
||||
MOpTrait::connect_to_src_regs(*unrenamed.mop, unrenamed_src_regs);
|
||||
#[hdl]
|
||||
let src_values: Array<
|
||||
TraceAsString<PRegValue>,
|
||||
{ COMMON_MOP_SRC_LEN },
|
||||
> = wire();
|
||||
for (src_value, src_reg) in src_values.into_iter().zip(unrenamed_src_regs) {
|
||||
connect(src_value, regs.regs[src_reg.value]);
|
||||
}
|
||||
#[hdl]
|
||||
if let HdlSome(unit_index) = UnitNum::as_index(*unit_num) {
|
||||
#[hdl]
|
||||
let to_unit = wire(to_units_as_array.ty().element());
|
||||
connect(to_units_as_array[unit_index], to_unit);
|
||||
connect_to_unit_nop(to_unit, global_state);
|
||||
#[hdl]
|
||||
let ExecuteToUnitInterface::<_> {
|
||||
global_state: _,
|
||||
enqueue,
|
||||
inputs_ready,
|
||||
is_no_longer_speculative,
|
||||
cant_cause_cancel: _, // we don't track if it can cause a cancel
|
||||
output_ready,
|
||||
finish_cause_cancel,
|
||||
unit_outputs_ready,
|
||||
cancel_all,
|
||||
config: _,
|
||||
} = to_unit;
|
||||
connect(unit_outputs_ready, true);
|
||||
connect(cancel_all.data, HdlNone());
|
||||
#[hdl]
|
||||
let unit_state_after_start = wire();
|
||||
connect(unit_state_after_start, unit_state);
|
||||
#[hdl]
|
||||
if let UnitState::NotYetEnqueued = unit_state {
|
||||
#[hdl]
|
||||
if let HdlSome(renamed) = renamed {
|
||||
let mop = #[hdl]
|
||||
MOpInstance::<_> {
|
||||
fetch_block_id: unrenamed.fetch_block_id,
|
||||
id: unrenamed.id,
|
||||
pc: unrenamed.pc,
|
||||
predicted_next_pc: unrenamed.predicted_next_pc,
|
||||
size_in_bytes: unrenamed.size_in_bytes,
|
||||
is_first_mop_in_insn: unrenamed.is_first_mop_in_insn,
|
||||
is_last_mop_in_insn: unrenamed.is_last_mop_in_insn,
|
||||
mop: renamed,
|
||||
};
|
||||
connect(
|
||||
enqueue.data,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
UnitEnqueue::<_> { mop, config },
|
||||
),
|
||||
);
|
||||
#[hdl]
|
||||
if enqueue.ready {
|
||||
connect(
|
||||
inputs_ready,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
UnitInputsReady::<_> {
|
||||
mop,
|
||||
src_values,
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
connect(
|
||||
is_no_longer_speculative,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
UnitMOpIsNoLongerSpeculative::<_> {
|
||||
id: unrenamed.id,
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
connect(unit_state_after_start, UnitState.SentInputsReady());
|
||||
}
|
||||
} else {
|
||||
connect(
|
||||
stepped,
|
||||
stepped
|
||||
.ty()
|
||||
.Error(Error.InconsistentState().to_trace_as_string()),
|
||||
);
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
let unit_state_after_output_ready = wire();
|
||||
connect(unit_state_after_output_ready, unit_state_after_start);
|
||||
#[hdl]
|
||||
let output_state_after_output_ready = wire(output_state.ty());
|
||||
connect(output_state_after_output_ready, output_state);
|
||||
#[hdl]
|
||||
if let HdlSome(output_ready) = output_ready {
|
||||
#[hdl]
|
||||
let UnitOutputReady::<_> {
|
||||
id: output_ready_id,
|
||||
dest_value,
|
||||
predictor_op,
|
||||
} = output_ready;
|
||||
#[hdl]
|
||||
match unit_state_after_start {
|
||||
UnitState::SentInputsReady => {
|
||||
connect(
|
||||
output_state_after_output_ready,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
OutputState::<_> {
|
||||
dest_value,
|
||||
predictor_op,
|
||||
},
|
||||
),
|
||||
);
|
||||
connect(unit_state_after_output_ready, UnitState.OutputReady());
|
||||
}
|
||||
UnitState::NotYetEnqueued
|
||||
| UnitState::OutputReady
|
||||
| UnitState::FinishedAndOrCausedCancel => connect(
|
||||
stepped,
|
||||
stepped
|
||||
.ty()
|
||||
.Error(Error.InconsistentState().to_trace_as_string()),
|
||||
),
|
||||
}
|
||||
#[hdl]
|
||||
if unrenamed.id.cmp_ne(output_ready_id) {
|
||||
connect(
|
||||
stepped,
|
||||
stepped.ty().Error(
|
||||
Error
|
||||
.UnexpectedOutputReadyId(output_ready_id)
|
||||
.to_trace_as_string(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
if let HdlSome(finish_cause_cancel) = finish_cause_cancel {
|
||||
#[hdl]
|
||||
let UnitFinishCauseCancel::<_> {
|
||||
id: finish_cause_cancel_id,
|
||||
caused_cancel,
|
||||
config: _,
|
||||
} = finish_cause_cancel;
|
||||
connect(stepped_step.output_state, output_state.ty().HdlNone());
|
||||
#[hdl]
|
||||
match unit_state_after_output_ready {
|
||||
UnitState::OutputReady => {}
|
||||
UnitState::NotYetEnqueued
|
||||
| UnitState::SentInputsReady
|
||||
| UnitState::FinishedAndOrCausedCancel => connect(
|
||||
stepped,
|
||||
stepped
|
||||
.ty()
|
||||
.Error(Error.InconsistentState().to_trace_as_string()),
|
||||
),
|
||||
}
|
||||
#[hdl]
|
||||
let do_retire = wire();
|
||||
#[hdl]
|
||||
if do_retire {
|
||||
#[hdl]
|
||||
if let HdlSome(output_state) = output_state_after_output_ready {
|
||||
#[hdl]
|
||||
let OutputState::<_> {
|
||||
dest_value,
|
||||
predictor_op,
|
||||
} = output_state;
|
||||
let old_len = ArrayVec::len(retired_insns);
|
||||
let len_ty = old_len.ty();
|
||||
let old_len = old_len.cast_to(UInt[len_ty.bit_width()]);
|
||||
connect(
|
||||
ArrayVec::len(stepped_step.retired_insns),
|
||||
(old_len + 1u8).cast_to(len_ty),
|
||||
);
|
||||
connect(stepped_step.retired_insns[old_len], predictor_op);
|
||||
for dest_reg in MOpDestReg::regs(MOpTrait::dest_reg(*unrenamed.mop))
|
||||
{
|
||||
#[hdl]
|
||||
if MOpRegNum::const_zero().cmp_ne(dest_reg) {
|
||||
connect(stepped_step.regs.regs[dest_reg.value], dest_value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
connect(
|
||||
stepped,
|
||||
stepped
|
||||
.ty()
|
||||
.Error(Error.InconsistentState().to_trace_as_string()),
|
||||
);
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
if let HdlSome(caused_cancel) = caused_cancel {
|
||||
#[hdl]
|
||||
let UnitCausedCancel::<_> {
|
||||
start_at_pc,
|
||||
cancel_after_retire,
|
||||
config: _,
|
||||
} = caused_cancel;
|
||||
connect(stepped_step.cancel_and_start_at, HdlSome(start_at_pc));
|
||||
connect(do_retire, cancel_after_retire);
|
||||
connect(
|
||||
stepped_step.run_state,
|
||||
stepped_step.ty().run_state.CancelingUnits(
|
||||
#[hdl]
|
||||
CancelState::<_> {
|
||||
canceling_units: repeat(
|
||||
true,
|
||||
CancelState[config].canceling_units.len(),
|
||||
),
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
connect(do_retire, true);
|
||||
#[hdl]
|
||||
let next_mop_index = wire(mops.ty().len_ty());
|
||||
connect(
|
||||
next_mop_index,
|
||||
(mop_index + 1u8).cast_to(next_mop_index.ty()),
|
||||
);
|
||||
#[hdl]
|
||||
if next_mop_index.cmp_lt(ArrayVec::len(mops)) {
|
||||
connect(
|
||||
stepped_step.run_state,
|
||||
stepped_step.ty().run_state.RunningMOp(
|
||||
#[hdl]
|
||||
RunMOpState::<_, _> {
|
||||
mop_index: next_mop_index
|
||||
.cast_to(mop_index.ty())
|
||||
.cast_to(run_mop_state.ty().mop_index),
|
||||
unit_state: UnitState.NotYetEnqueued(),
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
connect(
|
||||
stepped_step.run_state,
|
||||
stepped_step.ty().run_state.Finished(),
|
||||
);
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
if unrenamed.id.cmp_ne(finish_cause_cancel_id) {
|
||||
connect(
|
||||
stepped,
|
||||
stepped.ty().Error(
|
||||
Error
|
||||
.UnexpectedFinishCauseCancelId(finish_cause_cancel_id)
|
||||
.to_trace_as_string(),
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
connect(stepped_step.output_state, output_state_after_output_ready);
|
||||
connect(
|
||||
stepped_step.run_state,
|
||||
stepped_step.ty().run_state.RunningMOp(
|
||||
#[hdl]
|
||||
RunMOpState::<_, _> {
|
||||
mop_index: run_mop_state.mop_index,
|
||||
unit_state: unit_state_after_output_ready,
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
#[hdl]
|
||||
if let MOp::TransformedMove(mop) = *unrenamed.mop {
|
||||
#[hdl]
|
||||
let MoveRegMOp::<_, _> { common: _ } = mop;
|
||||
} else {
|
||||
connect(
|
||||
stepped,
|
||||
stepped
|
||||
.ty()
|
||||
.Error(Error.InconsistentState().to_trace_as_string()),
|
||||
);
|
||||
}
|
||||
let old_len = ArrayVec::len(retired_insns);
|
||||
let len_ty = old_len.ty();
|
||||
let old_len = old_len.cast_to(UInt[len_ty.bit_width()]);
|
||||
connect(
|
||||
ArrayVec::len(stepped_step.retired_insns),
|
||||
(old_len + 1u8).cast_to(len_ty),
|
||||
);
|
||||
connect(
|
||||
stepped_step.retired_insns[old_len],
|
||||
#[hdl]
|
||||
NextPcPredictorOp::<_> {
|
||||
call_stack_op: CallStackOp.None(),
|
||||
cond_br_taken: HdlNone(),
|
||||
config,
|
||||
},
|
||||
);
|
||||
for dest_reg in MOpDestReg::regs(MOpTrait::dest_reg(*unrenamed.mop)) {
|
||||
#[hdl]
|
||||
if MOpRegNum::const_zero().cmp_ne(dest_reg) {
|
||||
connect(stepped_step.regs.regs[dest_reg.value], src_values[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RunState::<_, _>::CancelingUnits(cancel_state) => {
|
||||
#[hdl]
|
||||
let CancelState::<_> {
|
||||
canceling_units,
|
||||
config: _,
|
||||
} = cancel_state;
|
||||
#[hdl]
|
||||
let done_canceling_units = wire();
|
||||
connect(done_canceling_units, true);
|
||||
#[hdl]
|
||||
let still_canceling_units = wire(canceling_units.ty());
|
||||
for ((to_unit, canceling_unit), still_canceling_unit) in to_units_as_array
|
||||
.into_iter()
|
||||
.zip(canceling_units)
|
||||
.zip(still_canceling_units)
|
||||
{
|
||||
connect(still_canceling_unit, false);
|
||||
#[hdl]
|
||||
if canceling_unit {
|
||||
connect(to_unit.cancel_all.data, HdlSome(()));
|
||||
#[hdl]
|
||||
if !to_unit.cancel_all.ready {
|
||||
connect(still_canceling_unit, true);
|
||||
connect(done_canceling_units, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
if done_canceling_units {
|
||||
connect(
|
||||
stepped,
|
||||
stepped.ty().Finished(
|
||||
#[hdl]
|
||||
DecodeAndRunSingleInsnOutput::<_, _> {
|
||||
regs,
|
||||
cancel_and_start_at,
|
||||
retired_insns,
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
connect(
|
||||
stepped_step.run_state,
|
||||
run_state.ty().CancelingUnits(
|
||||
#[hdl]
|
||||
CancelState::<_> {
|
||||
canceling_units: still_canceling_units,
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
RunState::<_, _>::Finished => connect(
|
||||
stepped,
|
||||
stepped.ty().Finished(
|
||||
#[hdl]
|
||||
DecodeAndRunSingleInsnOutput::<_, _> {
|
||||
regs,
|
||||
cancel_and_start_at,
|
||||
retired_insns,
|
||||
config,
|
||||
},
|
||||
),
|
||||
),
|
||||
RunState::<_, _>::Error(error) => connect(stepped, stepped.ty().Error(error)),
|
||||
}
|
||||
stepped
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn decode_and_run_single_insn<C: Type + PhantomConstCpuConfig, D: Type + DecodeOneInsn>(
|
||||
config: C,
|
||||
decoder: Interned<Module<D>>,
|
||||
) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[hdl]
|
||||
let input: ReadyValid<DecodeAndRunSingleInsnInput<C, DecodeOneInsnInput<D>>> = m.input(
|
||||
ReadyValid[DecodeAndRunSingleInsnInput[config][DecodeOneInsnInput[decoder.io_ty()]]],
|
||||
);
|
||||
#[hdl]
|
||||
let global_state: GlobalState = m.input();
|
||||
#[hdl]
|
||||
let output: ReadyValid<DecodeAndRunSingleInsnOutput<C, DecodeOneInsnMaxMOpCount<D>>> = m
|
||||
.output(
|
||||
ReadyValid
|
||||
[DecodeAndRunSingleInsnOutput[config][DecodeOneInsnMaxMOpCount[decoder.io_ty()]]],
|
||||
);
|
||||
#[hdl]
|
||||
let to_units: ExecuteToUnitInterfaces<C> = m.output(ExecuteToUnitInterfaces[config]);
|
||||
#[hdl]
|
||||
let error: Bool = m.output();
|
||||
|
||||
connect(error, false);
|
||||
|
||||
#[hdl]
|
||||
let decoder = instance(decoder);
|
||||
#[hdl]
|
||||
let decoder_input = wire(decoder.ty().input_ty());
|
||||
connect(decoder_input, decoder_input.ty().uninit());
|
||||
#[hdl]
|
||||
let decoder_output = wire(DecodeOneInsnOutput[decoder.ty().max_mop_count()]);
|
||||
D::connect_io(decoder, decoder_input, decoder_output);
|
||||
|
||||
#[hdl]
|
||||
let state_reg = reg_builder().clock_domain(cd).reset(
|
||||
HdlOption[DecodeAndRunSingleInsnState[config][decoder.ty().max_mop_count()]].HdlNone(),
|
||||
);
|
||||
|
||||
#[hdl]
|
||||
if let HdlSome(state) = state_reg {
|
||||
connect(input.ready, false);
|
||||
let step = DecodeAndRunSingleInsnState::step(state, to_units, global_state);
|
||||
#[hdl]
|
||||
match step {
|
||||
StepOutput::<_, _>::Finished(v) => {
|
||||
connect(output.data, HdlSome(v));
|
||||
#[hdl]
|
||||
if output.ready {
|
||||
connect(state_reg, state_reg.ty().HdlNone());
|
||||
}
|
||||
}
|
||||
StepOutput::<_, _>::Step(state) => {
|
||||
connect(state_reg, HdlSome(state));
|
||||
connect(output.data, output.ty().data.HdlNone());
|
||||
}
|
||||
StepOutput::<_, _>::Error(_) => {
|
||||
connect(output.data, output.ty().data.HdlNone());
|
||||
connect(error, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for to_unit in ExecuteToUnitInterfaces::unit_fields(to_units) {
|
||||
connect_to_unit_nop(to_unit, global_state);
|
||||
}
|
||||
connect(input.ready, true);
|
||||
connect(output.data, output.ty().data.HdlNone());
|
||||
#[hdl]
|
||||
if let HdlSome(input) = input.data {
|
||||
connect(decoder_input, input.decoder_input);
|
||||
connect(
|
||||
state_reg,
|
||||
HdlSome(DecodeAndRunSingleInsnState::new(
|
||||
input,
|
||||
decoder_output,
|
||||
config,
|
||||
decoder.ty().max_mop_count(),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
use crate::{
|
||||
config::CpuConfig,
|
||||
instruction::{
|
||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait,
|
||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpLeaf, MOpRegNum, MOpTrait,
|
||||
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, mop_enum,
|
||||
},
|
||||
rename_execute_retire::ExecuteToUnitInterface,
|
||||
|
|
@ -45,9 +45,9 @@ macro_rules! all_units {
|
|||
}
|
||||
|
||||
impl $UnitKind {
|
||||
pub fn unit(self, config: PhantomConst<CpuConfig>, unit_index: usize) -> DynUnit {
|
||||
pub fn unit(self, config: PhantomConst<CpuConfig>, unit_index: usize, filter: &mut impl RenamedMOpFilter) -> DynUnit {
|
||||
match self {
|
||||
$($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index),)*
|
||||
$($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index, filter),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -326,19 +326,67 @@ all_units! {
|
|||
this.TransformedMove.mapped_ty(new_dest_reg, new_src_reg)
|
||||
})] TransformedMoveOp: Type
|
||||
> {
|
||||
#[create_dyn_unit_fn = |config, unit_index| alu_branch::AluBranch::new(config, unit_index).to_dyn()]
|
||||
#[create_dyn_unit_fn = |config, unit_index, filter| alu_branch::AluBranch::new(config, unit_index, filter).to_dyn()]
|
||||
#[extract(alu_branch_mop, alu_branch_mop_sim, alu_branch_mop_sim_ref, alu_branch_mop_sim_mut)]
|
||||
AluBranch(AluBranchMOp<DestReg, SrcReg>),
|
||||
#[transformed_move]
|
||||
#[create_dyn_unit_fn = |config, unit_index| todo!()]
|
||||
#[create_dyn_unit_fn = |config, unit_index, filter| todo!()]
|
||||
#[extract(transformed_move_mop, transformed_move_mop_sim, transformed_move_mop_sim_ref, transformed_move_mop_sim_mut)]
|
||||
TransformedMove(TransformedMoveOp),
|
||||
#[create_dyn_unit_fn = |config, unit_index| todo!()]
|
||||
#[create_dyn_unit_fn = |config, unit_index, filter| todo!()]
|
||||
#[extract(load_store_mop, load_store_mop_sim, load_store_mop_sim_ref, load_store_mop_sim_mut)]
|
||||
LoadStore(LoadStoreMOp<DestReg, SrcReg>),
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RenamedMOpFilter {
|
||||
fn should_include(
|
||||
&mut self,
|
||||
mop: &SimValue<crate::rename_execute_retire::RenamedMOp<PhantomConst<CpuConfig>>>,
|
||||
) -> bool;
|
||||
fn should_include_ty<
|
||||
T: MOpLeaf<crate::rename_execute_retire::RenamedMOp<PhantomConst<CpuConfig>>>,
|
||||
>(
|
||||
&mut self,
|
||||
ty: T,
|
||||
) -> bool
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.should_include(
|
||||
&T::mop_into(
|
||||
UInt::new_dyn(ty.canonical().bit_width())
|
||||
.zero()
|
||||
.to_expr()
|
||||
.cast_bits_to(ty),
|
||||
)
|
||||
.to_sim_value(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
T: ?Sized
|
||||
+ FnMut(&SimValue<crate::rename_execute_retire::RenamedMOp<PhantomConst<CpuConfig>>>) -> bool,
|
||||
> RenamedMOpFilter for T
|
||||
{
|
||||
fn should_include(
|
||||
&mut self,
|
||||
mop: &SimValue<crate::rename_execute_retire::RenamedMOp<PhantomConst<CpuConfig>>>,
|
||||
) -> bool {
|
||||
self(mop)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenamedMOpFilter for () {
|
||||
fn should_include(
|
||||
&mut self,
|
||||
_mop: &SimValue<crate::rename_execute_retire::RenamedMOp<PhantomConst<CpuConfig>>>,
|
||||
) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub trait UnitTrait:
|
||||
'static + Send + Sync + std::fmt::Debug + fayalite::intern::SupportsPtrEqWithTypeId
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use crate::{
|
|||
ExecuteToUnitInterface, GlobalState, NextPcPredictorOp, RenamedMOp, UnitCausedCancel,
|
||||
UnitFinishCauseCancel, UnitInputsReady, UnitOutputReady,
|
||||
},
|
||||
unit::{DynUnit, DynUnitWrapper, UnitKind, UnitTrait},
|
||||
unit::{DynUnit, DynUnitWrapper, RenamedMOpFilter, UnitKind, UnitTrait},
|
||||
};
|
||||
use fayalite::{
|
||||
expr::CastToImpl,
|
||||
|
|
@ -87,8 +87,11 @@ fn add_sub<C: Type + PhantomConstCpuConfig, SrcCount: KnownSize>(config: C) {
|
|||
connect(src1, src_values[1].int_fp);
|
||||
}
|
||||
#[hdl]
|
||||
let carry_in = wire();
|
||||
connect(carry_in, carry_in_before_inversion ^ invert_carry_in);
|
||||
let carry_in: UInt<1> = wire();
|
||||
connect(
|
||||
carry_in,
|
||||
(carry_in_before_inversion ^ invert_carry_in).cast_to_static::<UInt<1>>(),
|
||||
);
|
||||
#[hdl]
|
||||
let src0 = wire();
|
||||
connect(src0, src_values[0].int_fp);
|
||||
|
|
@ -104,7 +107,12 @@ fn add_sub<C: Type + PhantomConstCpuConfig, SrcCount: KnownSize>(config: C) {
|
|||
connect(pc_or_zero, pc);
|
||||
}
|
||||
let sum_of_sliced = |slice: RangeTo<usize>| {
|
||||
src0[slice] + src1[slice] + src_values[2].int_fp[slice] + pc_or_zero[slice] + imm[slice]
|
||||
src0[slice]
|
||||
+ src1[slice]
|
||||
+ src_values[2].int_fp[slice]
|
||||
+ pc_or_zero[slice]
|
||||
+ imm[slice]
|
||||
+ carry_in
|
||||
};
|
||||
#[hdl]
|
||||
let sum: UInt<64> = wire();
|
||||
|
|
@ -1235,7 +1243,11 @@ fn read_special<C: Type + PhantomConstCpuConfig>(config: C) {
|
|||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn alu_branch(config: PhantomConst<CpuConfig>, unit_index: usize) {
|
||||
pub fn alu_branch(
|
||||
config: PhantomConst<CpuConfig>,
|
||||
unit_index: usize,
|
||||
filter: &mut impl RenamedMOpFilter,
|
||||
) {
|
||||
#[hdl]
|
||||
let from_execute: ExecuteToUnitInterface<PhantomConst<CpuConfig>> =
|
||||
m.input(ExecuteToUnitInterface[config]);
|
||||
|
|
@ -1294,193 +1306,237 @@ pub fn alu_branch(config: PhantomConst<CpuConfig>, unit_index: usize) {
|
|||
#[hdl]
|
||||
match mop {
|
||||
AluBranchMOp::<_, _>::AddSub(mop) => {
|
||||
#[hdl]
|
||||
let add_sub = instance(add_sub(config));
|
||||
#[hdl]
|
||||
let add_sub::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = add_sub;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc, mop_instance.pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let add_sub = instance(add_sub(config));
|
||||
#[hdl]
|
||||
let add_sub::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = add_sub;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc, mop_instance.pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::AddSubI(mop) => {
|
||||
#[hdl]
|
||||
let add_sub_i = instance(add_sub(config));
|
||||
#[hdl]
|
||||
let add_sub::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = add_sub_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc, mop_instance.pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let add_sub_i = instance(add_sub(config));
|
||||
#[hdl]
|
||||
let add_sub::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = add_sub_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc, mop_instance.pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::LogicalFlags(mop) => {
|
||||
#[hdl]
|
||||
let logical_flags = instance(logical_flags(config));
|
||||
#[hdl]
|
||||
let logical_flags::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical_flags;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let logical_flags = instance(logical_flags(config));
|
||||
#[hdl]
|
||||
let logical_flags::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical_flags;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::Logical(mop) => {
|
||||
#[hdl]
|
||||
let logical = instance(logical(config));
|
||||
#[hdl]
|
||||
let logical::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let logical = instance(logical(config));
|
||||
#[hdl]
|
||||
let logical::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::LogicalI(mop) => {
|
||||
#[hdl]
|
||||
let logical_i = instance(logical(config));
|
||||
#[hdl]
|
||||
let logical::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let logical_i = instance(logical(config));
|
||||
#[hdl]
|
||||
let logical::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = logical_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::ShiftRotate(mop) => {
|
||||
#[hdl]
|
||||
let shift_rotate = instance(shift_rotate(config));
|
||||
#[hdl]
|
||||
let shift_rotate::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = shift_rotate;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let shift_rotate = instance(shift_rotate(config));
|
||||
#[hdl]
|
||||
let shift_rotate::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = shift_rotate;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::Compare(mop) => {
|
||||
#[hdl]
|
||||
let compare = instance(compare(config));
|
||||
#[hdl]
|
||||
let compare::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = compare;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let compare = instance(compare(config));
|
||||
#[hdl]
|
||||
let compare::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = compare;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::CompareI(mop) => {
|
||||
#[hdl]
|
||||
let compare_i = instance(compare(config));
|
||||
#[hdl]
|
||||
let compare::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = compare_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let compare_i = instance(compare(config));
|
||||
#[hdl]
|
||||
let compare::<_, _> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = compare_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::Branch(mop) => {
|
||||
#[hdl]
|
||||
let branch = instance(branch(config));
|
||||
#[hdl]
|
||||
let branch::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc: pc_,
|
||||
fallthrough_pc: fallthrough_pc_,
|
||||
predicted_next_pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
predictor_op: predictor_op_,
|
||||
caused_cancel: caused_cancel_,
|
||||
} = branch;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc_, mop_instance.pc);
|
||||
connect(fallthrough_pc_, fallthrough_pc);
|
||||
connect(predicted_next_pc, mop_instance.predicted_next_pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
connect(predictor_op, predictor_op_);
|
||||
connect(caused_cancel, caused_cancel_);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let branch = instance(branch(config));
|
||||
#[hdl]
|
||||
let branch::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc: pc_,
|
||||
fallthrough_pc: fallthrough_pc_,
|
||||
predicted_next_pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
predictor_op: predictor_op_,
|
||||
caused_cancel: caused_cancel_,
|
||||
} = branch;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc_, mop_instance.pc);
|
||||
connect(fallthrough_pc_, fallthrough_pc);
|
||||
connect(predicted_next_pc, mop_instance.predicted_next_pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
connect(predictor_op, predictor_op_);
|
||||
connect(caused_cancel, caused_cancel_);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::BranchI(mop) => {
|
||||
#[hdl]
|
||||
let branch_i = instance(branch(config));
|
||||
#[hdl]
|
||||
let branch::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc: pc_,
|
||||
fallthrough_pc: fallthrough_pc_,
|
||||
predicted_next_pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
predictor_op: predictor_op_,
|
||||
caused_cancel: caused_cancel_,
|
||||
} = branch_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc_, mop_instance.pc);
|
||||
connect(fallthrough_pc_, fallthrough_pc);
|
||||
connect(predicted_next_pc, mop_instance.predicted_next_pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
connect(predictor_op, predictor_op_);
|
||||
connect(caused_cancel, caused_cancel_);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let branch_i = instance(branch(config));
|
||||
#[hdl]
|
||||
let branch::<_, _> {
|
||||
global_state: global_state_,
|
||||
pc: pc_,
|
||||
fallthrough_pc: fallthrough_pc_,
|
||||
predicted_next_pc,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
predictor_op: predictor_op_,
|
||||
caused_cancel: caused_cancel_,
|
||||
} = branch_i;
|
||||
connect(global_state_, global_state);
|
||||
connect(pc_, mop_instance.pc);
|
||||
connect(fallthrough_pc_, fallthrough_pc);
|
||||
connect(predicted_next_pc, mop_instance.predicted_next_pc);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
connect(predictor_op, predictor_op_);
|
||||
connect(caused_cancel, caused_cancel_);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
AluBranchMOp::<_, _>::ReadSpecial(mop) => {
|
||||
#[hdl]
|
||||
let read_special = instance(read_special(config));
|
||||
#[hdl]
|
||||
let read_special::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = read_special;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
if filter.should_include_ty(mop.ty()) {
|
||||
#[hdl]
|
||||
let read_special = instance(read_special(config));
|
||||
#[hdl]
|
||||
let read_special::<_> {
|
||||
global_state: global_state_,
|
||||
mop: mop_,
|
||||
src_values: src_values_,
|
||||
output,
|
||||
} = read_special;
|
||||
connect(global_state_, global_state);
|
||||
connect(*mop_, mop);
|
||||
connect(src_values_, src_values);
|
||||
connect(dest_value, output);
|
||||
} else {
|
||||
connect(*dest_value, PRegValue::zeroed());
|
||||
}
|
||||
}
|
||||
}
|
||||
connect(
|
||||
|
|
@ -1530,10 +1586,14 @@ pub struct AluBranch {
|
|||
}
|
||||
|
||||
impl AluBranch {
|
||||
pub fn new(config: PhantomConst<CpuConfig>, unit_index: usize) -> Self {
|
||||
pub fn new(
|
||||
config: PhantomConst<CpuConfig>,
|
||||
unit_index: usize,
|
||||
filter: &mut impl RenamedMOpFilter,
|
||||
) -> Self {
|
||||
Self {
|
||||
config,
|
||||
module: alu_branch(config, unit_index),
|
||||
module: alu_branch(config, unit_index, filter),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,152 +317,3 @@ impl LFSR31 {
|
|||
state
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CheckedVcdOutput {
|
||||
writer: Option<RcWriter>,
|
||||
expected_path: PathBuf,
|
||||
expected_contents: Result<String, (Option<PathBuf>, std::io::Error)>,
|
||||
location: &'static Location<'static>,
|
||||
}
|
||||
|
||||
impl CheckedVcdOutput {
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
pub fn new<T: BundleType>(sim: &mut Simulation<T>, expected_path: PathBuf) -> Self {
|
||||
let writer = RcWriter::default();
|
||||
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
||||
Self {
|
||||
writer: Some(writer),
|
||||
expected_contents: std::fs::read_to_string(&expected_path).map_err(|e| {
|
||||
eprintln!(
|
||||
"error: failed to read expected VCD from: {}",
|
||||
expected_path.display(),
|
||||
);
|
||||
(std::env::current_dir().ok(), e)
|
||||
}),
|
||||
expected_path,
|
||||
location: Location::caller(),
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
#[track_caller]
|
||||
#[doc(hidden)]
|
||||
pub fn __checked_vcd_output_macro_helper<T: BundleType>(
|
||||
sim: &mut Simulation<T>,
|
||||
cargo_manifest_dir: &'static str,
|
||||
path: &'static str,
|
||||
) -> Self {
|
||||
Self::new(sim, Path::new(cargo_manifest_dir).join(path))
|
||||
}
|
||||
pub fn with_vcd_output<R>(&self, f: impl FnOnce(&str) -> R) -> R {
|
||||
let Some(writer) = &self.writer else {
|
||||
unreachable!();
|
||||
};
|
||||
writer.clone().borrow(|output| {
|
||||
let Ok(output) = str::from_utf8(output) else {
|
||||
unreachable!("VcdWriter writes valid UTF-8");
|
||||
};
|
||||
f(output)
|
||||
})
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn finish(mut self) {
|
||||
let Ok(()) = self.finish_impl(|msg| panic!("{msg}"));
|
||||
}
|
||||
fn finish_impl<E>(
|
||||
&mut self,
|
||||
error: impl FnOnce(std::fmt::Arguments<'_>) -> E,
|
||||
) -> Result<(), E> {
|
||||
let Self {
|
||||
writer: Some(writer),
|
||||
expected_path,
|
||||
expected_contents,
|
||||
location,
|
||||
} = self
|
||||
else {
|
||||
// already finished
|
||||
return Ok(());
|
||||
};
|
||||
let Ok(vcd) = String::from_utf8(writer.take()) else {
|
||||
unreachable!("VcdWriter writes valid UTF-8");
|
||||
};
|
||||
let expected_path_d = expected_path.display();
|
||||
if expected_contents
|
||||
.as_ref()
|
||||
.is_ok_and(|expected_contents| *expected_contents == vcd)
|
||||
{
|
||||
// avoid written output from being split from threads interleaving writes to stdout
|
||||
let _stdout = std::io::stderr().lock();
|
||||
// use println to get output captured by tests
|
||||
println!("\n{location}: generated VCD matches the expected VCD in {expected_path_d}");
|
||||
return Ok(());
|
||||
}
|
||||
// avoid written output from being split from threads interleaving writes to stderr
|
||||
let _stderr = std::io::stderr().lock();
|
||||
let error = |msg: std::fmt::Arguments<'_>| {
|
||||
// print msg at both beginning and end so it's easier to find when the vcd is huge
|
||||
Err(error(format_args!(
|
||||
"\n{msg}####### VCD:\n{vcd}\n#######\n{msg}"
|
||||
)))
|
||||
};
|
||||
let error = |msg: std::fmt::Arguments<'_>| match &*expected_contents {
|
||||
Ok(_) => error(format_args!(
|
||||
"{location}: generated VCD doesn't match the expected VCD in {expected_path_d}\n\
|
||||
{msg}",
|
||||
)),
|
||||
Err((Some(current_dir), e)) => error(format_args!(
|
||||
"{location}: generated VCD doesn't match the expected VCD in {expected_path_d}\n\
|
||||
error: failed to read: {e}\n\
|
||||
current dir: {current_dir}\n\
|
||||
{msg}",
|
||||
current_dir = current_dir.display(),
|
||||
)),
|
||||
Err((None, e)) => error(format_args!(
|
||||
"{location}: generated VCD doesn't match the expected VCD in {expected_path_d}\n\
|
||||
error: failed to read: {e}\n\
|
||||
{msg}",
|
||||
)),
|
||||
};
|
||||
const OVERWRITE_VAR_NAME: &str = "OVERWRITE_EXPECTED_VCD";
|
||||
const OVERWRITE_VAR_VALUE: &str = "overwrite";
|
||||
match std::env::var_os(OVERWRITE_VAR_NAME) {
|
||||
Some(v) if v == OVERWRITE_VAR_VALUE => match std::fs::write(&expected_path, &vcd) {
|
||||
Ok(()) => error(format_args!(
|
||||
"warning: since `{OVERWRITE_VAR_NAME}={OVERWRITE_VAR_VALUE}` is set -- writing the generated VCD to {expected_path_d}\n"
|
||||
)),
|
||||
Err(e) => error(format_args!(
|
||||
"error: since `{OVERWRITE_VAR_NAME}={OVERWRITE_VAR_VALUE}` is set -- tried to write the generated VCD to {expected_path_d}\n\
|
||||
error: failed to write: {e}"
|
||||
)),
|
||||
},
|
||||
_ => error(format_args!(
|
||||
"note: rerun the test with the environment variable `{OVERWRITE_VAR_NAME}={OVERWRITE_VAR_VALUE}`\n\
|
||||
to update the expected output to match the generated output.\n"
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CheckedVcdOutput {
|
||||
#[track_caller]
|
||||
fn drop(&mut self) {
|
||||
let _ = self.finish_impl(|msg| {
|
||||
if std::thread::panicking() {
|
||||
eprintln!("{msg}"); // use eprintln to get output captured by tests
|
||||
} else {
|
||||
panic!("{msg}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! checked_vcd_output {
|
||||
($sim:expr, $path_relative_to_manifest_dir:expr $(,)?) => {
|
||||
$crate::util::CheckedVcdOutput::__checked_vcd_output_macro_helper(
|
||||
$sim,
|
||||
::std::env!("CARGO_MANIFEST_DIR"),
|
||||
::std::concat!($path_relative_to_manifest_dir),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
25372
crates/cpu/tests/expected/units_formal_power_isa_add_sim.vcd
generated
Normal file
25372
crates/cpu/tests/expected/units_formal_power_isa_add_sim.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
126030
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_0.vcd
generated
Normal file
126030
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_0.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
171484
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_1.vcd
generated
Normal file
171484
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_1.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
135028
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_2.vcd
generated
Normal file
135028
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_2.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
178767
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_3.vcd
generated
Normal file
178767
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_3.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
96323
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_4.vcd
generated
Normal file
96323
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_4.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
72104
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_5.vcd
generated
Normal file
72104
crates/cpu/tests/expected/units_formal_power_isa_add_sub_sim_5.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
25238
crates/cpu/tests/expected/units_formal_power_isa_paddi_sim.vcd
generated
Normal file
25238
crates/cpu/tests/expected/units_formal_power_isa_paddi_sim.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,6 @@
|
|||
// See Notices.txt for copyright information
|
||||
|
||||
use cpu::{
|
||||
checked_vcd_output,
|
||||
config::{
|
||||
CpuConfig, CpuConfigFetchWidth, CpuConfigMaxUnitMaxInFlight, PhantomConstCpuConfig,
|
||||
UnitConfig,
|
||||
|
|
@ -29,6 +28,7 @@ use cpu::{
|
|||
};
|
||||
use fayalite::{
|
||||
bundle::BundleType,
|
||||
checked_vcd_output,
|
||||
module::instance_with_loc,
|
||||
prelude::*,
|
||||
ty::{OpaqueSimValue, StaticType},
|
||||
|
|
@ -4079,7 +4079,7 @@ fn rename_execute_retire_test_harness<#[hdl(skip)] MI: MakeInsns>(
|
|||
AluBranchKind::Real => {
|
||||
let unit = instance_with_loc(
|
||||
&dut.ty().to_units.unit_field_name(unit_index),
|
||||
cpu::unit::alu_branch::alu_branch(config, unit_index),
|
||||
cpu::unit::alu_branch::alu_branch(config, unit_index, &mut ()),
|
||||
SourceLocation::caller(),
|
||||
);
|
||||
connect(unit.from_execute, to_unit);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3,10 +3,9 @@
|
|||
|
||||
use crate::test_cases::TestCase;
|
||||
use cpu::{
|
||||
checked_vcd_output, decoder::simple_power_isa::decode_one_insn, instruction::MOp,
|
||||
util::array_vec::ArrayVec,
|
||||
decoder::simple_power_isa::decode_one_insn, instruction::MOp, util::array_vec::ArrayVec,
|
||||
};
|
||||
use fayalite::prelude::*;
|
||||
use fayalite::{checked_vcd_output, prelude::*};
|
||||
use std::{fmt::Write as _, io::Write, process::Command};
|
||||
|
||||
mod test_cases;
|
||||
|
|
@ -126,7 +125,7 @@ fn test_test_cases_assembly() -> std::io::Result<()> {
|
|||
#[test]
|
||||
fn test_decode_insn() {
|
||||
let _n = SourceLocation::normalize_files_for_tests();
|
||||
let m = decode_one_insn();
|
||||
let m = decode_one_insn(());
|
||||
let mut sim = Simulation::new(m);
|
||||
let _checked_vcd_output = checked_vcd_output!(
|
||||
&mut sim,
|
||||
|
|
@ -149,7 +148,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(),
|
||||
)
|
||||
},
|
||||
));
|
||||
}
|
||||
|
|
|
|||
1439
crates/cpu/tests/units_formal.rs
Normal file
1439
crates/cpu/tests/units_formal.rs
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue