forked from libre-chip/cpu
Compare commits
5 commits
e6f876f9af
...
29757a568c
| Author | SHA1 | Date | |
|---|---|---|---|
| 29757a568c | |||
| 33529a2296 | |||
| 5e9d0957f6 | |||
| fc8a6cd959 | |||
| 87112c681a |
12 changed files with 42994 additions and 22890 deletions
|
|
@ -11,10 +11,12 @@ use crate::{
|
|||
powerisa_instructions_xml::{
|
||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||
},
|
||||
register::{PRegFlagsPowerISA, PRegFlagsPowerISAView},
|
||||
register::{
|
||||
PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, ViewUnused,
|
||||
},
|
||||
util::array_vec::{ArrayVec, Length},
|
||||
};
|
||||
use fayalite::{module::wire_with_loc, prelude::*, ty::StaticType};
|
||||
use fayalite::{int::UIntInRange, module::wire_with_loc, prelude::*, ty::StaticType};
|
||||
use std::{collections::BTreeMap, ops::RangeInclusive};
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
|
@ -181,8 +183,16 @@ macro_rules! impl_fields {
|
|||
impl_fields! {
|
||||
#[name = "BF"]
|
||||
struct FieldBF(FieldCrf);
|
||||
#[name = "BFA"]
|
||||
struct FieldBFA(FieldCrf);
|
||||
#[name = "BA"]
|
||||
struct FieldBA(FieldCrBit);
|
||||
#[name = "BB"]
|
||||
struct FieldBB(FieldCrBit);
|
||||
#[name = "BI"]
|
||||
struct FieldBI(FieldCrBit);
|
||||
#[name = "BT"]
|
||||
struct FieldBT(FieldCrBit);
|
||||
#[name = "RA"]
|
||||
struct FieldRA(FieldGpr);
|
||||
#[name = "RB"]
|
||||
|
|
@ -258,7 +268,7 @@ fn crf(this: impl ToExpr<Type = FieldCrf>) -> Expr<MOpRegNum> {
|
|||
}
|
||||
|
||||
#[hdl]
|
||||
fn cr_bit(cr_bit: impl ToExpr<Type = FieldCrBit>) -> (Expr<MOpRegNum>, Expr<ConditionMode>) {
|
||||
fn cr_bit_cond(cr_bit: impl ToExpr<Type = FieldCrBit>) -> (Expr<MOpRegNum>, Expr<ConditionMode>) {
|
||||
let cr_bit = cr_bit.to_expr();
|
||||
let field_bit = cr_bit.bit_num.cast_to_static::<UInt<2>>();
|
||||
let field_num = (cr_bit.bit_num >> 2).cast_to_static::<UInt<3>>();
|
||||
|
|
@ -269,19 +279,21 @@ fn cr_bit(cr_bit: impl ToExpr<Type = FieldCrBit>) -> (Expr<MOpRegNum>, Expr<Cond
|
|||
}
|
||||
|
||||
#[hdl]
|
||||
fn cr_bit_sim(
|
||||
cr_bit: impl ToSimValue<Type = FieldCrBit>,
|
||||
) -> (SimValue<MOpRegNum>, SimValue<ConditionMode>) {
|
||||
let cr_bit = cr_bit.into_sim_value();
|
||||
let field_bit = *cr_bit
|
||||
.bit_num
|
||||
.cast_to_static::<UInt<2>>()
|
||||
.cast_to_static::<fayalite::int::UIntInRange<0, 4>>();
|
||||
let field_num = (&cr_bit.bit_num >> 2).cast_to_static::<UInt<3>>();
|
||||
(
|
||||
MOpRegNum::power_isa_cr_reg_sim(&field_num),
|
||||
PRegFlagsPowerISA::cr_condition_modes_msb0_sim()[field_bit].clone(),
|
||||
)
|
||||
fn cr_bit_flag_index(
|
||||
cr_bit: impl ToExpr<Type = FieldCrBit>,
|
||||
) -> (
|
||||
Expr<MOpRegNum>,
|
||||
Expr<UIntInRange<0, { PRegFlags::FLAG_COUNT }>>,
|
||||
) {
|
||||
let cr_bit = cr_bit.to_expr();
|
||||
let field_bit = cr_bit.bit_num.cast_to_static::<UInt<2>>();
|
||||
let field_num = (cr_bit.bit_num >> 2).cast_to_static::<UInt<3>>();
|
||||
let flag_indexes = ViewUnused::from_fn(|i| i);
|
||||
let flag_index = PRegFlagsPowerISA::view_unused_into_view(flag_indexes)
|
||||
.into_cr_bits_msb0()
|
||||
.map(|i| i.cast_to_static::<UIntInRange<_, _>>())
|
||||
.to_expr()[field_bit];
|
||||
(MOpRegNum::power_isa_cr_reg(field_num), flag_index)
|
||||
}
|
||||
|
||||
impl DecodeState {
|
||||
|
|
@ -533,7 +545,7 @@ impl DecodeState {
|
|||
let no_ctr = bo[2]; // BO_2 in specification
|
||||
let expected_cr_bit_value = bo[3]; // BO_1 in specification
|
||||
let no_cr_bit = bo[4]; // BO_0 in specification
|
||||
let (cr_field, condition_mode) = cr_bit(bi);
|
||||
let (cr_field, condition_mode) = cr_bit_cond(bi);
|
||||
#[hdl]
|
||||
let branch_mop = wire();
|
||||
#[hdl]
|
||||
|
|
@ -655,6 +667,72 @@ impl DecodeState {
|
|||
);
|
||||
}
|
||||
}
|
||||
// for crand, crnand, cror, crxor, crnor, creqv, crandc, crorc
|
||||
#[hdl]
|
||||
fn decode_crand_crnand_cror_crxor_crnor_creqv_crandc_crorc(&mut self) {
|
||||
assert_eq!(self.arguments, Some("BT,BA,BB"));
|
||||
let lut = match self.mnemonic {
|
||||
"crand" => Lut4::from_fn(|a, b| a & b),
|
||||
"crnand" => Lut4::from_fn(|a, b| !(a & b)),
|
||||
"cror" => Lut4::from_fn(|a, b| a | b),
|
||||
"crxor" => Lut4::from_fn(|a, b| a ^ b),
|
||||
"crnor" => Lut4::from_fn(|a, b| !(a | b)),
|
||||
"creqv" => Lut4::from_fn(|a, b| a == b),
|
||||
"crandc" => Lut4::from_fn(|a, b| a & !b),
|
||||
"crorc" => Lut4::from_fn(|a, b| a | !b),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.decode_scope(|this, (FieldBT(bt), FieldBA(ba), FieldBB(bb))| {
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
let (bt_reg, bt_flag_index) = cr_bit_flag_index(bt);
|
||||
let (ba_reg, ba_flag_index) = cr_bit_flag_index(ba);
|
||||
let (bb_reg, bb_flag_index) = cr_bit_flag_index(bb);
|
||||
let uint_ty = UInt[ba_flag_index.ty().bit_width()];
|
||||
let src0_start = (ba_flag_index.cast_to(uint_ty) + PRegFlags::FLAG_COUNT
|
||||
- bt_flag_index.cast_to(uint_ty))
|
||||
% PRegFlags::FLAG_COUNT;
|
||||
let src1_start = (bb_flag_index.cast_to(uint_ty) + PRegFlags::FLAG_COUNT
|
||||
- bt_flag_index.cast_to(uint_ty))
|
||||
% PRegFlags::FLAG_COUNT;
|
||||
connect(
|
||||
this.output[0],
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
MOpDestReg::new([bt_reg], []),
|
||||
[ba_reg.value, bb_reg.value, bt_reg.value],
|
||||
#[hdl]
|
||||
LogicalFlagsMOpImm {
|
||||
src0_start: src0_start.cast_to(LogicalFlagsMOpImm.src0_start),
|
||||
src1_start: src1_start.cast_to(LogicalFlagsMOpImm.src1_start),
|
||||
src2_start: 0usize.cast_to(LogicalFlagsMOpImm.src2_start),
|
||||
dest_start: bt_flag_index,
|
||||
dest_count: 1usize.cast_to(LogicalFlagsMOpImm.dest_count),
|
||||
},
|
||||
lut,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
// for mcrf
|
||||
#[hdl]
|
||||
fn decode_mcrf(&mut self) {
|
||||
self.decode_scope(|this, (FieldBF(bf), FieldBFA(bfa))| {
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
this.output[0],
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new([crf(bf)], []),
|
||||
[crf(bfa).value],
|
||||
0i8.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
#[hdl]
|
||||
fn decode_addi_paddi(&mut self) {
|
||||
match self.mnemonic {
|
||||
|
|
@ -1423,13 +1501,9 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
|||
&[
|
||||
"crand", "crnand", "cror", "crxor", "crnor", "creqv", "crandc", "crorc",
|
||||
],
|
||||
|_state| {
|
||||
// TODO
|
||||
},
|
||||
DecodeState::decode_crand_crnand_cror_crxor_crnor_creqv_crandc_crorc,
|
||||
),
|
||||
(&["mcrf"], |_state| {
|
||||
// TODO
|
||||
}),
|
||||
(&["mcrf"], DecodeState::decode_mcrf),
|
||||
(&["sc", "scv"], |_state| {
|
||||
// TODO
|
||||
}),
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
193
crates/cpu/tests/simple_power_isa_decoder/main.rs
Normal file
193
crates/cpu/tests/simple_power_isa_decoder/main.rs
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::test_cases::TestCase;
|
||||
use cpu::{
|
||||
decoder::simple_power_isa::decode_one_insn, instruction::MOp, util::array_vec::ArrayVec,
|
||||
};
|
||||
use fayalite::{prelude::*, sim::vcd::VcdWriterDecls, util::RcWriter};
|
||||
use std::{fmt::Write as _, io::Write, process::Command};
|
||||
|
||||
mod test_cases;
|
||||
|
||||
#[test]
|
||||
fn test_test_cases_assembly() -> std::io::Result<()> {
|
||||
let llvm_mc_regex = regex::Regex::new(r"llvm-mc(-\d+)?$").expect("known to be a valid regex");
|
||||
let llvm_mc = which::which_re(llvm_mc_regex)
|
||||
.expect("can't find llvm-mc or llvm-mc-<num> in path")
|
||||
.next()
|
||||
.expect("can't find llvm-mc or llvm-mc-<num> in path");
|
||||
let test_cases = test_cases::test_cases();
|
||||
let mut assembly = String::new();
|
||||
for TestCase {
|
||||
mnemonic,
|
||||
first_input: _,
|
||||
second_input: _,
|
||||
output: _,
|
||||
loc: _,
|
||||
} in &test_cases
|
||||
{
|
||||
writeln!(assembly, "{mnemonic}").unwrap();
|
||||
}
|
||||
let (reader, mut writer) = std::io::pipe()?;
|
||||
let thread = std::thread::spawn(move || writer.write_all(assembly.as_bytes()));
|
||||
let std::process::Output {
|
||||
status,
|
||||
stdout,
|
||||
stderr,
|
||||
} = Command::new(&llvm_mc)
|
||||
.arg("--triple=powerpc64le-linux-gnu")
|
||||
.arg("--assemble")
|
||||
.arg("--filetype=asm")
|
||||
.arg("--show-encoding")
|
||||
.arg("-")
|
||||
.stdin(reader)
|
||||
.output()?;
|
||||
let _ = thread.join();
|
||||
let stderr = String::from_utf8_lossy(&stderr);
|
||||
eprint!("{stderr}");
|
||||
if !status.success() {
|
||||
panic!("{} failed: {status}", llvm_mc.display());
|
||||
}
|
||||
let stdout = String::from_utf8_lossy(&stdout);
|
||||
print!("{stdout}");
|
||||
let mut lines = stdout.lines();
|
||||
let text_line = lines.next();
|
||||
assert_eq!(text_line, Some("\t.text"));
|
||||
for test_case @ TestCase {
|
||||
mnemonic: _,
|
||||
first_input,
|
||||
second_input,
|
||||
output: _,
|
||||
loc: _,
|
||||
} in test_cases
|
||||
{
|
||||
let Some(line) = lines.next() else {
|
||||
panic!("output missing line for: {test_case:?}");
|
||||
};
|
||||
if line.starts_with("\t.long") {
|
||||
assert_eq!(
|
||||
line,
|
||||
format!("\t.long\t{first_input}"),
|
||||
"test_case={test_case:?}\nline:\n{line}"
|
||||
);
|
||||
if let Some(second_input) = second_input {
|
||||
let Some(line) = lines.next() else {
|
||||
panic!("output missing line for: {test_case:?}");
|
||||
};
|
||||
assert_eq!(
|
||||
line,
|
||||
format!("\t.long\t{second_input}"),
|
||||
"test_case={test_case:?}\nline:\n{line}"
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let Some((_, comment)) = line.split_once('#') else {
|
||||
panic!("output line missing comment. test_case={test_case:?}\nline:\n{line}");
|
||||
};
|
||||
let [b0, b1, b2, b3] = first_input.to_le_bytes();
|
||||
let expected_comment = if let Some(second_input) = second_input {
|
||||
let [b4, b5, b6, b7] = second_input.to_le_bytes();
|
||||
format!(
|
||||
" encoding: [0x{b0:02x},0x{b1:02x},0x{b2:02x},0x{b3:02x},0x{b4:02x},0x{b5:02x},0x{b6:02x},0x{b7:02x}]"
|
||||
)
|
||||
} else {
|
||||
format!(" encoding: [0x{b0:02x},0x{b1:02x},0x{b2:02x},0x{b3:02x}]")
|
||||
};
|
||||
assert_eq!(
|
||||
comment, expected_comment,
|
||||
"test_case={test_case:?}\nline:\n{line}"
|
||||
);
|
||||
}
|
||||
for line in lines {
|
||||
assert!(line.trim().is_empty(), "bad trailing output line: {line:?}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[test]
|
||||
fn test_decode_insn() {
|
||||
let _n = SourceLocation::normalize_files_for_tests();
|
||||
let m = decode_one_insn();
|
||||
let mut sim = Simulation::new(m);
|
||||
let writer = RcWriter::default();
|
||||
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
||||
struct DumpVcdOnDrop {
|
||||
writer: Option<RcWriter>,
|
||||
}
|
||||
impl Drop for DumpVcdOnDrop {
|
||||
fn drop(&mut self) {
|
||||
if let Some(mut writer) = self.writer.take() {
|
||||
let vcd = String::from_utf8(writer.take()).unwrap();
|
||||
println!("####### VCD:\n{vcd}\n#######");
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut writer = DumpVcdOnDrop {
|
||||
writer: Some(writer),
|
||||
};
|
||||
for test_case @ TestCase {
|
||||
mnemonic: _,
|
||||
first_input,
|
||||
second_input,
|
||||
output: _,
|
||||
loc: _,
|
||||
} in test_cases::test_cases()
|
||||
{
|
||||
sim.write(sim.io().first_input, first_input);
|
||||
sim.write(
|
||||
sim.io().second_input,
|
||||
if let Some(v) = second_input {
|
||||
#[hdl(sim)]
|
||||
HdlSome(v)
|
||||
} else {
|
||||
#[hdl(sim)]
|
||||
HdlNone()
|
||||
},
|
||||
);
|
||||
sim.advance_time(SimDuration::from_micros(1));
|
||||
let second_input_used = sim.read_bool(sim.io().second_input_used);
|
||||
let is_illegal = sim.read_bool(sim.io().is_illegal);
|
||||
let output = sim.read(sim.io().output);
|
||||
#[derive(Debug)]
|
||||
#[expect(dead_code, reason = "used only for Debug formatting")]
|
||||
struct FormattedOutput<'a> {
|
||||
insns: &'a [SimValue<MOp>],
|
||||
second_input_used: bool,
|
||||
is_illegal: bool,
|
||||
}
|
||||
let expected = format!(
|
||||
"{:#?}",
|
||||
FormattedOutput {
|
||||
insns: ArrayVec::elements_sim_ref(&test_case.output),
|
||||
second_input_used: second_input.is_some(),
|
||||
is_illegal: false,
|
||||
},
|
||||
);
|
||||
let output = format!(
|
||||
"{:#?}",
|
||||
FormattedOutput {
|
||||
insns: ArrayVec::elements_sim_ref(&output),
|
||||
second_input_used,
|
||||
is_illegal,
|
||||
},
|
||||
);
|
||||
assert!(
|
||||
expected == output,
|
||||
"test_case={test_case:#?}\noutput={output}\nexpected={expected}"
|
||||
);
|
||||
}
|
||||
let vcd = String::from_utf8(writer.writer.take().unwrap().take()).unwrap();
|
||||
println!("####### VCD:\n{vcd}\n#######");
|
||||
if vcd != include_str!("expected/decode_one_insn.vcd") {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[test]
|
||||
fn test_simple_power_isa_decoder() {
|
||||
// TODO
|
||||
}
|
||||
121
crates/cpu/tests/simple_power_isa_decoder/test_cases.rs
Normal file
121
crates/cpu/tests/simple_power_isa_decoder/test_cases.rs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use cpu::{instruction::MOp, util::array_vec::ArrayVec};
|
||||
use fayalite::prelude::*;
|
||||
use std::fmt;
|
||||
|
||||
mod branch;
|
||||
mod condition_register;
|
||||
mod fixed_point_arithmetic;
|
||||
mod fixed_point_compare;
|
||||
mod fixed_point_logical;
|
||||
mod move_to_from_system_register;
|
||||
mod prefixed_no_operation;
|
||||
|
||||
pub struct TestCase {
|
||||
pub mnemonic: &'static str,
|
||||
pub first_input: u32,
|
||||
pub second_input: Option<u32>,
|
||||
pub output: SimValue<ArrayVec<MOp, ConstUsize<2>>>,
|
||||
pub loc: &'static std::panic::Location<'static>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for TestCase {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
mnemonic,
|
||||
first_input,
|
||||
second_input,
|
||||
output,
|
||||
loc,
|
||||
} = self;
|
||||
let mut debug_struct = f.debug_struct("TestCase");
|
||||
debug_struct
|
||||
.field("mnemonic", mnemonic)
|
||||
.field("first_input", &format_args!("0x{first_input:08x}"));
|
||||
if let Some(second_input) = second_input {
|
||||
debug_struct.field("second_input", &format_args!("0x{second_input:08x}"));
|
||||
} else {
|
||||
debug_struct.field("second_input", &format_args!("None"));
|
||||
}
|
||||
debug_struct
|
||||
.field("output", &ArrayVec::elements_sim_ref(output))
|
||||
.field("loc", &format_args!("{loc}"))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[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);
|
||||
TestCase {
|
||||
mnemonic,
|
||||
first_input,
|
||||
second_input,
|
||||
output: ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop),
|
||||
loc: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn insn_single(
|
||||
mnemonic: &'static str,
|
||||
first_input: u32,
|
||||
second_input: Option<u32>,
|
||||
output: impl ToSimValue<Type = MOp>,
|
||||
) -> 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(),
|
||||
}
|
||||
}
|
||||
|
||||
#[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(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_cases() -> Vec<TestCase> {
|
||||
let mut retval = Vec::new();
|
||||
branch::test_cases_book_i_2_4_branch(&mut retval);
|
||||
condition_register::test_cases_book_i_2_5_condition_register(&mut retval);
|
||||
fixed_point_arithmetic::test_cases_book_i_3_3_9_fixed_point_arithmetic(&mut retval);
|
||||
fixed_point_compare::test_cases_book_i_3_3_10_fixed_point_compare(&mut retval);
|
||||
fixed_point_logical::test_cases_book_i_3_3_13_fixed_point_logical(&mut retval);
|
||||
move_to_from_system_register::test_cases_book_i_3_3_19_move_to_from_system_register(
|
||||
&mut retval,
|
||||
);
|
||||
prefixed_no_operation::test_cases_book_i_3_3_20_prefixed_no_operation(&mut retval);
|
||||
retval
|
||||
}
|
||||
446
crates/cpu/tests/simple_power_isa_decoder/test_cases/branch.rs
Normal file
446
crates/cpu/tests/simple_power_isa_decoder/test_cases/branch.rs
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::test_cases::{TestCase, insn_double, insn_single};
|
||||
use cpu::instruction::{
|
||||
AddSubMOp, BranchMOp, ConditionMode, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode,
|
||||
};
|
||||
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,
|
||||
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,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::test_cases::{TestCase, insn_single};
|
||||
use cpu::{
|
||||
instruction::{LogicalFlagsMOp, LogicalFlagsMOpImm, Lut4, MOpDestReg, MOpRegNum, MoveRegMOp},
|
||||
register::PRegFlagsPowerISA,
|
||||
};
|
||||
use fayalite::prelude::*;
|
||||
|
||||
/// covers instructions in PowerISA v3.1C Book I 2.5 Condition Register Instructions
|
||||
pub fn test_cases_book_i_2_5_condition_register(retval: &mut Vec<TestCase>) {
|
||||
macro_rules! cr_bit_logical_op {
|
||||
(
|
||||
$mnemonic:literal,
|
||||
$encoding:literal,
|
||||
$lut:expr
|
||||
) => {{
|
||||
retval.push(insn_single(
|
||||
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).value,
|
||||
MOpRegNum::power_isa_cr_reg_imm(5).value,
|
||||
MOpRegNum::power_isa_cr_reg_imm(3).value,
|
||||
],
|
||||
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).value,
|
||||
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||
],
|
||||
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).value,
|
||||
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||
],
|
||||
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,
|
||||
),
|
||||
));
|
||||
}};
|
||||
}
|
||||
cr_bit_logical_op!("crand", 0x4c000202, Lut4::from_fn(|a, b| a & b));
|
||||
cr_bit_logical_op!("crnand", 0x4c0001c2, Lut4::from_fn(|a, b| !(a & b)));
|
||||
cr_bit_logical_op!("cror", 0x4c000382, Lut4::from_fn(|a, b| a | b));
|
||||
cr_bit_logical_op!("crxor", 0x4c000182, Lut4::from_fn(|a, b| a ^ b));
|
||||
cr_bit_logical_op!("crnor", 0x4c000042, Lut4::from_fn(|a, b| !(a | b)));
|
||||
cr_bit_logical_op!("creqv", 0x4c000242, Lut4::from_fn(|a, b| a == b));
|
||||
cr_bit_logical_op!("crandc", 0x4c000102, Lut4::from_fn(|a, b| a & !b));
|
||||
cr_bit_logical_op!("crorc", 0x4c000342, Lut4::from_fn(|a, b| a | !b));
|
||||
macro_rules! mcrf {
|
||||
($dest:literal, $src:literal; $encoding:literal) => {
|
||||
retval.push(insn_single(
|
||||
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).value],
|
||||
0i8.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
};
|
||||
}
|
||||
mcrf!(0, 0; 0x4c000000);
|
||||
mcrf!(5, 7; 0x4e9c0000);
|
||||
mcrf!(5, 0; 0x4e800000);
|
||||
}
|
||||
|
|
@ -0,0 +1,408 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::test_cases::{TestCase, insn_single};
|
||||
use cpu::instruction::{AddSubMOp, MOpDestReg, MOpRegNum, OutputIntegerMode};
|
||||
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,
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0x1234.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
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).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
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().value, MOpRegNum::const_zero().value],
|
||||
0x123456789i64.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
));
|
||||
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).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0x12340000.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
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().value; _],
|
||||
0x12340004.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"add. 3, 4, 5",
|
||||
0x7c642a15,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num(3)],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"addic. 3, 4, 0x1234",
|
||||
0x34641234,
|
||||
None,
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0x1234.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"subf. 3, 4, 5",
|
||||
0x7c642851,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num(3)],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"subfic 3, 4, 0x1234",
|
||||
0x20641234,
|
||||
None,
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0x1234.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"addc. 3, 4, 5",
|
||||
0x7c642815,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"subfc. 3, 4, 5",
|
||||
0x7c642811,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"adde. 3, 4, 5",
|
||||
0x7c642915,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"subfe. 3, 4, 5",
|
||||
0x7c642911,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"addme. 3, 4",
|
||||
0x7c6401d5,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
(-1i8).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"subfme. 3, 4",
|
||||
0x7c6401d1,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
(-1i8).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"addze. 3, 4",
|
||||
0x7c640195,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"subfze. 3, 4",
|
||||
0x7c640191,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[
|
||||
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||
],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"neg. 3, 4",
|
||||
0x7c6400d1,
|
||||
None,
|
||||
AddSubMOp::add_sub(
|
||||
MOpDestReg::new_sim(
|
||||
&[MOpRegNum::power_isa_gpr_reg_num(3)],
|
||||
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||
),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::test_cases::{TestCase, insn_single};
|
||||
use cpu::instruction::{CompareMOp, CompareMode, MOpDestReg, MOpRegNum, OutputIntegerMode};
|
||||
use fayalite::prelude::*;
|
||||
|
||||
/// covers instructions in PowerISA v3.1C Book I 3.3.10 Fixed-Point Compare Instructions
|
||||
pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>) {
|
||||
retval.push(insn_single(
|
||||
"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).value],
|
||||
0x1234.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
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).value],
|
||||
(0x89abu16 as i16).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
CompareMode.S64(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"cmp 3, 0, 4, 5",
|
||||
0x7d842800,
|
||||
None,
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
CompareMode.S32(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"cmp 3, 1, 4, 5",
|
||||
0x7da42800,
|
||||
None,
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
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).value],
|
||||
0x1234.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
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).value],
|
||||
0x89ab.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
CompareMode.U64(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"cmpl 3, 0, 4, 5",
|
||||
0x7d842840,
|
||||
None,
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
CompareMode.U32(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"cmpl 3, 1, 4, 5",
|
||||
0x7da42840,
|
||||
None,
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
CompareMode.U64(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"cmprb 3, 0, 4, 5",
|
||||
0x7d842980,
|
||||
None,
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
CompareMode.CmpRBOne(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"cmprb 3, 1, 4, 5",
|
||||
0x7da42980,
|
||||
None,
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
CompareMode.CmpRBTwo(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"cmpeqb 3, 4, 5",
|
||||
0x7d8429c0,
|
||||
None,
|
||||
CompareMOp::compare(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
CompareMode.CmpEqB(),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::test_cases::{TestCase, insn_empty, insn_single};
|
||||
use cpu::instruction::{LogicalMOp, Lut4, MOpDestReg, MOpRegNum, MoveRegMOp, OutputIntegerMode};
|
||||
use fayalite::prelude::*;
|
||||
|
||||
/// covers instructions in PowerISA v3.1C Book I 3.3.13 Fixed-Point Logical Instructions
|
||||
pub fn test_cases_book_i_3_3_13_fixed_point_logical(retval: &mut Vec<TestCase>) {
|
||||
macro_rules! insn_logic_i {
|
||||
(
|
||||
$mnemonic:literal $dest:literal, $src:literal, $imm:literal;
|
||||
$encoding:literal;
|
||||
|$a:ident, $b:ident| $lut_fn:expr;
|
||||
) => {
|
||||
retval.push(insn_single(
|
||||
concat!(
|
||||
$mnemonic,
|
||||
" ",
|
||||
stringify!($dest),
|
||||
", ",
|
||||
stringify!($src),
|
||||
", ",
|
||||
stringify!($imm)
|
||||
),
|
||||
$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).value],
|
||||
(($imm as u32) << if $mnemonic.contains('s') { 16 } else { 0 })
|
||||
.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
Lut4::from_fn(|$a, $b| $lut_fn),
|
||||
),
|
||||
));
|
||||
};
|
||||
}
|
||||
insn_logic_i! {
|
||||
"andi." 3, 4, 0x89ab;
|
||||
0x708389ab;
|
||||
|a, b| a & b;
|
||||
}
|
||||
insn_logic_i! {
|
||||
"andis." 3, 4, 0x89ab;
|
||||
0x748389ab;
|
||||
|a, b| a & b;
|
||||
}
|
||||
insn_logic_i! {
|
||||
"ori" 3, 4, 0x89ab;
|
||||
0x608389ab;
|
||||
|a, b| a | b;
|
||||
}
|
||||
// ensure nop decodes to zero instructions
|
||||
retval.push(insn_empty("ori 0, 0, 0", 0x60000000, None));
|
||||
insn_logic_i! {
|
||||
"oris" 3, 4, 0x89ab;
|
||||
0x648389ab;
|
||||
|a, b| a | b;
|
||||
}
|
||||
insn_logic_i! {
|
||||
"xori" 3, 4, 0x89ab;
|
||||
0x688389ab;
|
||||
|a, b| a ^ b;
|
||||
}
|
||||
insn_logic_i! {
|
||||
"xori" 0, 0, 0; // ensure xnop actually decodes to a normal ALU instruction
|
||||
0x68000000;
|
||||
|a, b| a ^ b;
|
||||
}
|
||||
insn_logic_i! {
|
||||
"xoris" 3, 4, 0x89ab;
|
||||
0x6c8389ab;
|
||||
|a, b| a ^ b;
|
||||
}
|
||||
macro_rules! insn_logic {
|
||||
(
|
||||
$mnemonic:literal $dest:literal, $src0:literal, $src1:literal;
|
||||
$encoding:literal;
|
||||
|$a:ident, $b:ident| $lut_fn:expr;
|
||||
) => {
|
||||
retval.push(insn_single(
|
||||
concat!(
|
||||
$mnemonic,
|
||||
" ",
|
||||
stringify!($dest),
|
||||
", ",
|
||||
stringify!($src0),
|
||||
", ",
|
||||
stringify!($src1)
|
||||
),
|
||||
$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).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm($src1).value,
|
||||
],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
Lut4::from_fn(|$a, $b| $lut_fn),
|
||||
),
|
||||
));
|
||||
};
|
||||
}
|
||||
insn_logic! {
|
||||
"and" 3, 4, 5;
|
||||
0x7c832838;
|
||||
|a, b| a & b;
|
||||
}
|
||||
insn_logic! {
|
||||
"and." 3, 4, 5;
|
||||
0x7c832839;
|
||||
|a, b| a & b;
|
||||
}
|
||||
insn_logic! {
|
||||
"xor" 3, 4, 5;
|
||||
0x7c832a78;
|
||||
|a, b| a ^ b;
|
||||
}
|
||||
insn_logic! {
|
||||
"xor." 3, 4, 5;
|
||||
0x7c832a79;
|
||||
|a, b| a ^ b;
|
||||
}
|
||||
insn_logic! {
|
||||
"nand" 3, 4, 5;
|
||||
0x7c832bb8;
|
||||
|a, b| !(a & b);
|
||||
}
|
||||
insn_logic! {
|
||||
"nand." 3, 4, 5;
|
||||
0x7c832bb9;
|
||||
|a, b| !(a & b);
|
||||
}
|
||||
insn_logic! {
|
||||
"or" 3, 4, 5;
|
||||
0x7c832b78;
|
||||
|a, b| a | b;
|
||||
}
|
||||
retval.push(insn_single(
|
||||
"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).value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
insn_logic! {
|
||||
"or." 3, 4, 5;
|
||||
0x7c832b79;
|
||||
|a, b| a | b;
|
||||
}
|
||||
insn_logic! {
|
||||
"or." 3, 4, 4; // mr. 3, 4
|
||||
0x7c832379;
|
||||
|a, b| a | b;
|
||||
}
|
||||
insn_logic! {
|
||||
"orc" 3, 4, 5;
|
||||
0x7c832b38;
|
||||
|a, b| a | !b;
|
||||
}
|
||||
insn_logic! {
|
||||
"orc." 3, 4, 5;
|
||||
0x7c832b39;
|
||||
|a, b| a | !b;
|
||||
}
|
||||
insn_logic! {
|
||||
"nor" 3, 4, 5;
|
||||
0x7c8328f8;
|
||||
|a, b| !(a | b);
|
||||
}
|
||||
insn_logic! {
|
||||
"nor." 3, 4, 5;
|
||||
0x7c8328f9;
|
||||
|a, b| !(a | b);
|
||||
}
|
||||
insn_logic! {
|
||||
"eqv" 3, 4, 5;
|
||||
0x7c832a38;
|
||||
|a, b| a == b;
|
||||
}
|
||||
insn_logic! {
|
||||
"eqv." 3, 4, 5;
|
||||
0x7c832a39;
|
||||
|a, b| a == b;
|
||||
}
|
||||
insn_logic! {
|
||||
"andc" 3, 4, 5;
|
||||
0x7c832878;
|
||||
|a, b| a & !b;
|
||||
}
|
||||
insn_logic! {
|
||||
"andc." 3, 4, 5;
|
||||
0x7c832879;
|
||||
|a, b| a & !b;
|
||||
}
|
||||
macro_rules! insn_exts {
|
||||
(
|
||||
$mnemonic:literal $dest:literal, $src:literal;
|
||||
$encoding:literal;
|
||||
$OutputIntegerMode:ident;
|
||||
) => {
|
||||
retval.push(insn_single(
|
||||
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).value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.$OutputIntegerMode(),
|
||||
Lut4::from_fn(|a, b| a | b),
|
||||
),
|
||||
));
|
||||
};
|
||||
}
|
||||
insn_exts! {
|
||||
"extsb" 3, 4;
|
||||
0x7c830774;
|
||||
SignExt8;
|
||||
}
|
||||
insn_exts! {
|
||||
"extsb." 3, 4;
|
||||
0x7c830775;
|
||||
SignExt8;
|
||||
}
|
||||
insn_exts! {
|
||||
"extsh" 3, 4;
|
||||
0x7c830734;
|
||||
SignExt16;
|
||||
}
|
||||
insn_exts! {
|
||||
"extsh." 3, 4;
|
||||
0x7c830735;
|
||||
SignExt16;
|
||||
}
|
||||
insn_exts! {
|
||||
"extsw" 3, 4;
|
||||
0x7c8307b4;
|
||||
SignExt32;
|
||||
}
|
||||
insn_exts! {
|
||||
"extsw." 3, 4;
|
||||
0x7c8307b5;
|
||||
SignExt32;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::test_cases::{TestCase, insn_single};
|
||||
use cpu::instruction::{LogicalFlagsMOp, LogicalFlagsMOpImm, Lut4, MOpDestReg, MOpRegNum};
|
||||
use fayalite::prelude::*;
|
||||
|
||||
/// covers instructions in PowerISA v3.1C Book I 3.3.19 Move To/From System Register Instructions
|
||||
pub fn test_cases_book_i_3_3_19_move_to_from_system_register(retval: &mut Vec<TestCase>) {
|
||||
#[hdl]
|
||||
fn mcrxrx_imm() -> SimValue<LogicalFlagsMOpImm> {
|
||||
#[hdl(sim)]
|
||||
LogicalFlagsMOpImm {
|
||||
// if the order of flags in PRegFlags changes, this will need to be updated
|
||||
src0_start: 4usize.cast_to(LogicalFlagsMOpImm.src0_start),
|
||||
src1_start: 4usize.cast_to(LogicalFlagsMOpImm.src1_start),
|
||||
src2_start: 4usize.cast_to(LogicalFlagsMOpImm.src2_start),
|
||||
dest_start: 0usize.cast_to(LogicalFlagsMOpImm.dest_start),
|
||||
dest_count: 6usize.cast_to(LogicalFlagsMOpImm.dest_count),
|
||||
}
|
||||
}
|
||||
retval.push(insn_single(
|
||||
"mcrxrx 3",
|
||||
0x7d800480,
|
||||
None,
|
||||
LogicalFlagsMOp::logical_flags(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||
[
|
||||
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||
MOpRegNum::const_zero().value,
|
||||
MOpRegNum::power_isa_xer_so_ov_ov32_reg().value,
|
||||
],
|
||||
mcrxrx_imm(),
|
||||
Lut4::from_fn(|a, b| a | b),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::test_cases::{TestCase, insn_empty};
|
||||
|
||||
/// covers instructions in PowerISA v3.1C Book I 3.3.20 Prefixed No-Operation Instruction
|
||||
pub fn test_cases_book_i_3_3_20_prefixed_no_operation(retval: &mut Vec<TestCase>) {
|
||||
// ensure pnop decodes to zero instructions
|
||||
retval.push(insn_empty(
|
||||
// LLVM doesn't support the pnop instruction:
|
||||
// https://github.com/llvm/llvm-project/issues/176831
|
||||
".long 0x07000000, 0 # pnop",
|
||||
0x07000000,
|
||||
Some(0),
|
||||
));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue