forked from libre-chip/cpu
add tests for and fix decoding branch instructions
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 branch_ctr_reg: MOpRegNum = wire();
|
||||||
let dest = MOpDestReg::new([branch_lr_dest_reg], []);
|
let dest = MOpDestReg::new([branch_lr_dest_reg], []);
|
||||||
let src1 = addr_reg.unwrap_or_else(|| MOpRegNum::const_zero()).value;
|
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 invert_src2_eq_zero = !use_eq_for_ctr_compare;
|
||||||
let pc_relative = match aa {
|
let pc_relative = match aa {
|
||||||
Some(aa) => !aa,
|
Some(aa) => !aa,
|
||||||
None => addr_reg.is_none().to_expr(),
|
None => addr_reg.is_none().to_expr(),
|
||||||
};
|
};
|
||||||
#[hdl]
|
#[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(
|
connect(
|
||||||
branch_mop,
|
branch_mop,
|
||||||
BranchMOp::branch_ctr(
|
BranchMOp::branch_ctr(
|
||||||
|
|
@ -586,7 +598,7 @@ impl DecodeState {
|
||||||
} else {
|
} else {
|
||||||
connect(
|
connect(
|
||||||
ArrayVec::len(this.output),
|
ArrayVec::len(this.output),
|
||||||
1usize.cast_to_static::<Length<_>>(),
|
2usize.cast_to_static::<Length<_>>(),
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
this.output[0],
|
this.output[0],
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,13 @@ impl MOpRegNum {
|
||||||
power_isa_cr_reg
|
power_isa_cr_reg
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[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> {
|
pub fn power_isa_cr_reg_sim(field_num: &SimValue<UInt<3>>) -> SimValue<Self> {
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
Self {
|
Self {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -4,8 +4,8 @@
|
||||||
use cpu::{
|
use cpu::{
|
||||||
decoder::simple_power_isa::decode_one_insn,
|
decoder::simple_power_isa::decode_one_insn,
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, CompareMOp, CompareMode, LogicalMOp, MOp, MOpDestReg, MOpRegNum, MoveRegMOp,
|
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LogicalMOp, MOp, MOpDestReg,
|
||||||
OutputIntegerMode,
|
MOpRegNum, MoveRegMOp, OutputIntegerMode,
|
||||||
},
|
},
|
||||||
util::array_vec::ArrayVec,
|
util::array_vec::ArrayVec,
|
||||||
};
|
};
|
||||||
|
|
@ -85,6 +85,29 @@ fn test_cases() -> Vec<TestCase> {
|
||||||
loc: std::panic::Location::caller(),
|
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(
|
retval.push(insn_single(
|
||||||
"addi 3, 4, 0x1234",
|
"addi 3, 4, 0x1234",
|
||||||
0x38641234,
|
0x38641234,
|
||||||
|
|
@ -907,6 +930,440 @@ fn test_cases() -> Vec<TestCase> {
|
||||||
0x07000000,
|
0x07000000,
|
||||||
Some(0),
|
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
|
retval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue