add tests for and fix decoding branch instructions
All checks were successful
/ test (pull_request) Successful in 27m1s
All checks were successful
/ test (pull_request) Successful in 27m1s
This commit is contained in:
parent
2e05329c36
commit
85ada6e55a
4 changed files with 33637 additions and 5 deletions
|
|
@ -538,14 +538,26 @@ impl DecodeState {
|
|||
let branch_ctr_reg: MOpRegNum = wire();
|
||||
let dest = MOpDestReg::new([branch_lr_dest_reg], []);
|
||||
let src1 = addr_reg.unwrap_or_else(|| MOpRegNum::const_zero()).value;
|
||||
let imm = (bd.unwrap_or(0_hdl_i14) << 2).cast_to_static();
|
||||
let imm: Expr<SInt<_>> = (bd.unwrap_or(0_hdl_i14) << 2).cast_to_static();
|
||||
let invert_src2_eq_zero = !use_eq_for_ctr_compare;
|
||||
let pc_relative = match aa {
|
||||
Some(aa) => !aa,
|
||||
None => addr_reg.is_none().to_expr(),
|
||||
};
|
||||
#[hdl]
|
||||
if no_cr_bit {
|
||||
if no_ctr & no_cr_bit {
|
||||
connect(
|
||||
branch_mop,
|
||||
BranchMOp::branch_i(
|
||||
dest,
|
||||
src1,
|
||||
imm.cast_to_static::<SInt<_>>(),
|
||||
pc_relative,
|
||||
lk,
|
||||
is_ret,
|
||||
),
|
||||
);
|
||||
} else if no_cr_bit {
|
||||
connect(
|
||||
branch_mop,
|
||||
BranchMOp::branch_ctr(
|
||||
|
|
@ -586,7 +598,7 @@ impl DecodeState {
|
|||
} else {
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
1usize.cast_to_static::<Length<_>>(),
|
||||
2usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
|
|
|
|||
|
|
@ -121,6 +121,13 @@ impl MOpRegNum {
|
|||
power_isa_cr_reg
|
||||
}
|
||||
#[hdl]
|
||||
pub fn power_isa_cr_reg_imm(index: usize) -> Expr<Self> {
|
||||
#[hdl]
|
||||
Self {
|
||||
value: Self::power_isa_cr_reg_num(index).cast_to_static::<UInt<_>>(),
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
pub fn power_isa_cr_reg_sim(field_num: &SimValue<UInt<3>>) -> SimValue<Self> {
|
||||
#[hdl(sim)]
|
||||
Self {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,8 +4,8 @@
|
|||
use cpu::{
|
||||
decoder::simple_power_isa::decode_one_insn,
|
||||
instruction::{
|
||||
AddSubMOp, CompareMOp, CompareMode, LogicalMOp, MOp, MOpDestReg, MOpRegNum, MoveRegMOp,
|
||||
OutputIntegerMode,
|
||||
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LogicalMOp, MOp, MOpDestReg,
|
||||
MOpRegNum, MoveRegMOp, OutputIntegerMode,
|
||||
},
|
||||
util::array_vec::ArrayVec,
|
||||
};
|
||||
|
|
@ -85,6 +85,29 @@ fn test_cases() -> Vec<TestCase> {
|
|||
loc: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
#[track_caller]
|
||||
fn insn_double(
|
||||
mnemonic: &'static str,
|
||||
first_input: u32,
|
||||
second_input: Option<u32>,
|
||||
insns: [impl ToSimValue<Type = MOp>; 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(),
|
||||
}
|
||||
}
|
||||
retval.push(insn_single(
|
||||
"addi 3, 4, 0x1234",
|
||||
0x38641234,
|
||||
|
|
@ -907,6 +930,440 @@ fn test_cases() -> Vec<TestCase> {
|
|||
0x07000000,
|
||||
Some(0),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"b 0x345678",
|
||||
0x48345678,
|
||||
None,
|
||||
BranchMOp::branch_i(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
MOpRegNum::const_zero().value,
|
||||
0x345678.cast_to_static::<SInt<_>>(),
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"ba 0x345678",
|
||||
0x4834567a,
|
||||
None,
|
||||
BranchMOp::branch_i(
|
||||
MOpDestReg::new_sim(&[], &[]),
|
||||
MOpRegNum::const_zero().value,
|
||||
0x345678.cast_to_static::<SInt<_>>(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"bl 0x345678",
|
||||
0x48345679,
|
||||
None,
|
||||
BranchMOp::branch_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||
MOpRegNum::const_zero().value,
|
||||
0x345678.cast_to_static::<SInt<_>>(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"bla 0x345678",
|
||||
0x4834567b,
|
||||
None,
|
||||
BranchMOp::branch_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||
MOpRegNum::const_zero().value,
|
||||
0x345678.cast_to_static::<SInt<_>>(),
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
fn insn_dec_ctr_and(
|
||||
mnemonic: &'static str,
|
||||
first_input: u32,
|
||||
second_input: Option<u32>,
|
||||
second_insn: impl ToSimValue<Type = MOp>,
|
||||
) -> TestCase {
|
||||
insn_double(
|
||||
mnemonic,
|
||||
first_input,
|
||||
second_input,
|
||||
[
|
||||
AddSubMOp::add_sub_i::<MOp>(
|
||||
MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []),
|
||||
[
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
(-1).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.into_sim_value(),
|
||||
second_insn.into_sim_value(),
|
||||
],
|
||||
)
|
||||
}
|
||||
macro_rules! insn_branch_conds {
|
||||
(
|
||||
mnemonic = $mnemonic:literal;
|
||||
mnemonic_l = $mnemonic_l:literal;
|
||||
asm_last_arg = $asm_last_arg:literal;
|
||||
imm = $imm:literal;
|
||||
encoding = $encoding:literal;
|
||||
src1 = $src1:expr;
|
||||
pc_relative = $pc_relative:expr;
|
||||
is_ret = $is_ret:expr;
|
||||
) => {
|
||||
insn_branch_conds! {
|
||||
mnemonic = $mnemonic;
|
||||
asm_last_arg = $asm_last_arg;
|
||||
imm = $imm;
|
||||
encoding = $encoding;
|
||||
dest = MOpDestReg::new_sim(&[], &[]);
|
||||
src1 = $src1;
|
||||
pc_relative = $pc_relative;
|
||||
lk = false;
|
||||
is_ret = $is_ret;
|
||||
}
|
||||
insn_branch_conds! {
|
||||
mnemonic = $mnemonic_l;
|
||||
asm_last_arg = $asm_last_arg;
|
||||
imm = $imm;
|
||||
encoding = $encoding | 1;
|
||||
dest = MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]);
|
||||
src1 = $src1;
|
||||
pc_relative = $pc_relative;
|
||||
lk = true;
|
||||
is_ret = $is_ret;
|
||||
}
|
||||
};
|
||||
(
|
||||
mnemonic = $mnemonic:literal;
|
||||
asm_last_arg = $asm_last_arg:literal;
|
||||
imm = $imm:literal;
|
||||
encoding = $encoding:expr;
|
||||
dest = $dest:expr;
|
||||
src1 = $src1:expr;
|
||||
pc_relative = $pc_relative:expr;
|
||||
lk = $lk:expr;
|
||||
is_ret = $is_ret:expr;
|
||||
) => {
|
||||
if !$mnemonic.starts_with("bcctr") {
|
||||
retval.push(insn_dec_ctr_and(
|
||||
concat!($mnemonic, " 0, 0, ", $asm_last_arg),
|
||||
$encoding,
|
||||
None,
|
||||
BranchMOp::branch_cond_ctr(
|
||||
$dest,
|
||||
[
|
||||
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
],
|
||||
$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).value,
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
],
|
||||
$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).value,
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
],
|
||||
$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).value,
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
],
|
||||
$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).value,
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
],
|
||||
$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).value,
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
],
|
||||
$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).value,
|
||||
$src1,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
$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).value,
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
],
|
||||
$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).value,
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
],
|
||||
$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).value,
|
||||
$src1,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
$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,
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
$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,
|
||||
$src1,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
$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,
|
||||
$src1,
|
||||
$imm.cast_to_static::<SInt<_>>(),
|
||||
$pc_relative,
|
||||
$lk,
|
||||
$is_ret,
|
||||
),
|
||||
));
|
||||
};
|
||||
}
|
||||
insn_branch_conds! {
|
||||
mnemonic = "bc";
|
||||
mnemonic_l = "bcl";
|
||||
asm_last_arg = "0x1234";
|
||||
imm = 0x1234;
|
||||
encoding = 0x40001234;
|
||||
src1 = MOpRegNum::const_zero().value;
|
||||
pc_relative = true;
|
||||
is_ret = false;
|
||||
}
|
||||
insn_branch_conds! {
|
||||
mnemonic = "bca";
|
||||
mnemonic_l = "bcla";
|
||||
asm_last_arg = "0x1234";
|
||||
imm = 0x1234;
|
||||
encoding = 0x40001236;
|
||||
src1 = MOpRegNum::const_zero().value;
|
||||
pc_relative = false;
|
||||
is_ret = false;
|
||||
}
|
||||
insn_branch_conds! {
|
||||
mnemonic = "bclr";
|
||||
mnemonic_l = "bclrl";
|
||||
asm_last_arg = "0";
|
||||
imm = 0;
|
||||
encoding = 0x4c000020;
|
||||
src1 = MOpRegNum::power_isa_lr_reg().value;
|
||||
pc_relative = false;
|
||||
is_ret = true;
|
||||
}
|
||||
insn_branch_conds! {
|
||||
mnemonic = "bcctr";
|
||||
mnemonic_l = "bcctrl";
|
||||
asm_last_arg = "0";
|
||||
imm = 0;
|
||||
encoding = 0x4c000420;
|
||||
src1 = MOpRegNum::power_isa_ctr_reg().value;
|
||||
pc_relative = false;
|
||||
is_ret = false;
|
||||
}
|
||||
retval.push(insn_dec_ctr_and(
|
||||
// LLVM doesn't support the bctar[l] instructions:
|
||||
// https://github.com/llvm/llvm-project/issues/176864
|
||||
".long 0x4e400461 # bctarl 18, 0, 0",
|
||||
0x4e400461,
|
||||
None,
|
||||
BranchMOp::branch_ctr(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||
MOpRegNum::power_isa_tar_reg().value,
|
||||
MOpRegNum::power_isa_ctr_reg().value,
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue