add PowerISA decoder #7
7 changed files with 146914 additions and 114528 deletions
|
|
@ -4,9 +4,9 @@
|
|||
use crate::{
|
||||
config::CpuConfig,
|
||||
instruction::{
|
||||
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LogicalFlagsMOp,
|
||||
LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg, MOpRegNum, MoveRegMOp,
|
||||
OutputIntegerMode,
|
||||
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
|
||||
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
|
||||
MOpRegNum, MoveRegMOp, OutputIntegerMode,
|
||||
},
|
||||
powerisa_instructions_xml::{
|
||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||
|
|
@ -16,7 +16,12 @@ use crate::{
|
|||
},
|
||||
util::array_vec::{ArrayVec, Length},
|
||||
};
|
||||
use fayalite::{int::UIntInRange, module::wire_with_loc, prelude::*, ty::StaticType};
|
||||
use fayalite::{
|
||||
int::{BoolOrIntType, UIntInRange},
|
||||
module::wire_with_loc,
|
||||
prelude::*,
|
||||
ty::StaticType,
|
||||
};
|
||||
use std::{collections::BTreeMap, ops::RangeInclusive};
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
|
@ -203,6 +208,14 @@ impl_fields! {
|
|||
struct FieldRT(FieldGpr);
|
||||
#[name = "BD"]
|
||||
struct FieldBD(SInt<14>);
|
||||
#[name = "D"]
|
||||
struct FieldD(SInt<16>);
|
||||
#[name = "d0"]
|
||||
struct FieldD0(SInt<18>);
|
||||
#[name = "d1"]
|
||||
struct FieldD1(UInt<16>);
|
||||
#[name = "DS"]
|
||||
struct FieldDS(SInt<14>);
|
||||
#[name = "LI"]
|
||||
struct FieldLI(SInt<24>);
|
||||
#[name = "SI"]
|
||||
|
|
@ -336,14 +349,17 @@ impl DecodeState {
|
|||
}
|
||||
panic!("can't extract bit field name text: {bit_field_name:#?}")
|
||||
}
|
||||
fn msb0_bit_range(word: Expr<UInt<32>>, bit_range: RangeInclusive<usize>) -> Expr<UInt> {
|
||||
fn msb0_bit_range(&self, word: Expr<UInt<32>>, bit_range: RangeInclusive<usize>) -> Expr<UInt> {
|
||||
let (msb0_start, msb0_end) = bit_range.into_inner();
|
||||
let max_index = word.ty().width() - 1;
|
||||
let (Some(lsb0_start), Some(lsb0_end)) = (
|
||||
max_index.checked_sub(msb0_end),
|
||||
max_index.checked_sub(msb0_start),
|
||||
) else {
|
||||
panic!("invalid msb0 bit range {msb0_start}..={msb0_end}");
|
||||
panic!(
|
||||
"invalid msb0 bit range {msb0_start}..={msb0_end}\nmnemonic={:?}",
|
||||
self.mnemonic,
|
||||
);
|
||||
};
|
||||
word[lsb0_start..=lsb0_end]
|
||||
}
|
||||
|
|
@ -382,7 +398,11 @@ impl DecodeState {
|
|||
) {
|
||||
let mut last_start = word.ty().width();
|
||||
for bit_field in fields_inner.fields().iter().rev() {
|
||||
let mut bit_number_split = bit_field.bit_number().text().split_whitespace();
|
||||
let bit_number_text = match bit_field.bit_number().text() {
|
||||
"3031" => "30 31",
|
||||
v => v,
|
||||
};
|
||||
let mut bit_number_split = bit_number_text.split_whitespace();
|
||||
let Some(first_bit_number) = bit_number_split.next() else {
|
||||
panic!(
|
||||
"missing first bit number: {fields_inner:#?}\nheader: {:#?}",
|
||||
|
|
@ -410,7 +430,7 @@ impl DecodeState {
|
|||
panic!("no space for bit field, next bit field starts at bit 0\n{fields_inner:#?}");
|
||||
};
|
||||
last_start = *msb0_bit_range.start();
|
||||
let field = Self::msb0_bit_range(word, msb0_bit_range);
|
||||
let field = self.msb0_bit_range(word, msb0_bit_range);
|
||||
let mut name = Self::bit_field_name(bit_field.name());
|
||||
let orig_name = name;
|
||||
if name.contains(char::is_alphabetic) {
|
||||
|
|
@ -734,6 +754,211 @@ impl DecodeState {
|
|||
});
|
||||
}
|
||||
#[hdl]
|
||||
fn decode_load_8_16_32_64_bit(&mut self) {
|
||||
let (is_prefixed, is_update, is_indexed, width, is_signed) = match self.mnemonic {
|
||||
"lbz" => (false, false, false, 8, false),
|
||||
"plbz" => (true, false, false, 8, false),
|
||||
"lbzx" => (false, false, true, 8, false),
|
||||
"lbzu" => (false, true, false, 8, false),
|
||||
"lbzux" => (false, true, true, 8, false),
|
||||
"lhz" => (false, false, false, 16, false),
|
||||
"plhz" => (true, false, false, 16, false),
|
||||
"lhzx" => (false, false, true, 16, false),
|
||||
"lhzu" => (false, true, false, 16, false),
|
||||
"lhzux" => (false, true, true, 16, false),
|
||||
"lha" => (false, false, false, 16, true),
|
||||
"plha" => (true, false, false, 16, true),
|
||||
"lhax" => (false, false, true, 16, true),
|
||||
"lhau" => (false, true, false, 16, true),
|
||||
"lhaux" => (false, true, true, 16, true),
|
||||
"lwz" => (false, false, false, 32, false),
|
||||
"plwz" => (true, false, false, 32, false),
|
||||
"lwzx" => (false, false, true, 32, false),
|
||||
"lwzu" => (false, true, false, 32, false),
|
||||
"lwzux" => (false, true, true, 32, false),
|
||||
"lwa" => (false, false, false, 32, true),
|
||||
"plwa" => (true, false, false, 32, true),
|
||||
"lwax" => (false, false, true, 32, true),
|
||||
// there is no `lwau`
|
||||
"lwaux" => (false, true, true, 32, true),
|
||||
"ld" => (false, false, false, 64, false),
|
||||
"pld" => (true, false, false, 64, false),
|
||||
"ldx" => (false, false, true, 64, false),
|
||||
"ldu" => (false, true, false, 64, false),
|
||||
"ldux" => (false, true, true, 64, false),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let conversion = if is_signed {
|
||||
LoadStoreConversion.SignExt()
|
||||
} else {
|
||||
LoadStoreConversion.ZeroExt()
|
||||
};
|
||||
let width = match width {
|
||||
8 => LoadStoreWidth.Width8Bit(),
|
||||
16 => LoadStoreWidth.Width16Bit(),
|
||||
32 => LoadStoreWidth.Width32Bit(),
|
||||
64 => LoadStoreWidth.Width64Bit(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let ea_reg = |ra: Expr<FieldGpr>| {
|
||||
if is_update {
|
||||
gpr(ra)
|
||||
} else {
|
||||
MOpRegNum::power_isa_temp_reg()
|
||||
}
|
||||
};
|
||||
if is_prefixed {
|
||||
assert_eq!(self.arguments, Some("RT,D(RA),R"));
|
||||
assert!(!is_indexed);
|
||||
self.decode_scope(
|
||||
|this, (FieldRT(rt), FieldD0(d0), FieldD1(d1), FieldRA(ra), FieldR(r))| {
|
||||
let d = ((d0 << 16) + d1.cast_to(SInt[32])).cast_to_static::<SInt<_>>();
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
2usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
let ea_reg = ea_reg(ra);
|
||||
#[hdl]
|
||||
if r {
|
||||
connect(
|
||||
this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([ea_reg], []),
|
||||
[MOpRegNum::const_zero().value; 2],
|
||||
d,
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
connect(
|
||||
this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([ea_reg], []),
|
||||
[gpr_or_zero(ra).value, MOpRegNum::const_zero().value],
|
||||
d,
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
);
|
||||
}
|
||||
connect(
|
||||
this.output[1],
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new([gpr(rt)], []),
|
||||
[ea_reg.value],
|
||||
width,
|
||||
conversion,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else if is_indexed {
|
||||
assert_eq!(self.arguments, Some("RT,RA,RB"));
|
||||
self.decode_scope(|this, (FieldRT(rt), FieldRA(ra), FieldRB(rb))| {
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
2usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
let ea_reg = ea_reg(ra);
|
||||
connect(
|
||||
this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([ea_reg], []),
|
||||
[gpr_or_zero(ra).value, gpr(rb).value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
);
|
||||
connect(
|
||||
this.output[1],
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new([gpr(rt)], []),
|
||||
[ea_reg.value],
|
||||
width,
|
||||
conversion,
|
||||
),
|
||||
);
|
||||
});
|
||||
} else if self.arguments == Some("RT,disp(RA)") {
|
||||
self.decode_scope(|this, (FieldRT(rt), FieldRA(ra), FieldDS(ds))| {
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
2usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
let ea_reg = ea_reg(ra);
|
||||
connect(
|
||||
this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([ea_reg], []),
|
||||
[gpr_or_zero(ra).value, MOpRegNum::const_zero().value],
|
||||
(ds << 2).cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
);
|
||||
connect(
|
||||
this.output[1],
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new([gpr(rt)], []),
|
||||
[ea_reg.value],
|
||||
width,
|
||||
conversion,
|
||||
),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
assert_eq!(
|
||||
self.arguments,
|
||||
Some("RT,D(RA)"),
|
||||
"mnemonic={:?}",
|
||||
self.mnemonic,
|
||||
);
|
||||
self.decode_scope(|this, (FieldRT(rt), FieldRA(ra), FieldD(d))| {
|
||||
connect(
|
||||
ArrayVec::len(this.output),
|
||||
2usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
let ea_reg = ea_reg(ra);
|
||||
connect(
|
||||
this.output[0],
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new([ea_reg], []),
|
||||
[gpr_or_zero(ra).value, MOpRegNum::const_zero().value],
|
||||
d.cast_to_static::<SInt<_>>(),
|
||||
OutputIntegerMode.Full64(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
);
|
||||
connect(
|
||||
this.output[1],
|
||||
LoadMOp::load(
|
||||
MOpDestReg::new([gpr(rt)], []),
|
||||
[ea_reg.value],
|
||||
width,
|
||||
conversion,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
fn decode_addi_paddi(&mut self) {
|
||||
match self.mnemonic {
|
||||
"addi" => {
|
||||
|
|
@ -1513,9 +1738,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
|||
"plha", "lhax", "lhau", "lhaux", "lwz", "plwz", "lwzx", "lwzu", "lwzux", "lwa", "plwa",
|
||||
"lwax", "lwaux", "ld", "pld", "ldx", "ldu", "ldux",
|
||||
],
|
||||
|_state| {
|
||||
// TODO
|
||||
},
|
||||
DecodeState::decode_load_8_16_32_64_bit,
|
||||
),
|
||||
(
|
||||
&[
|
||||
|
|
|
|||
|
|
@ -1951,12 +1951,98 @@ mop_enum! {
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub enum LoadStoreWidth {
|
||||
Width8Bit,
|
||||
Width16Bit,
|
||||
Width32Bit,
|
||||
Width64Bit,
|
||||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> for LoadStoreWidth {
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: Self,
|
||||
rhs_value: Cow<'_, Self::SimValue>,
|
||||
) -> bool {
|
||||
SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned()))
|
||||
== SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned()))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_eq(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub enum LoadStoreConversion {
|
||||
ZeroExt,
|
||||
SignExt,
|
||||
// TODO(FP): add Power ISA's f32 in f64 format and RISC-V's ones-extension of floating-point
|
||||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> for LoadStoreConversion {
|
||||
#[track_caller]
|
||||
fn cmp_value_eq(
|
||||
lhs: Self,
|
||||
lhs_value: Cow<'_, Self::SimValue>,
|
||||
rhs: Self,
|
||||
rhs_value: Cow<'_, Self::SimValue>,
|
||||
) -> bool {
|
||||
SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned()))
|
||||
== SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned()))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_eq(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_sim_value_ne(
|
||||
lhs: Cow<'_, SimValue<Self>>,
|
||||
rhs: Cow<'_, SimValue<Self>>,
|
||||
) -> SimValue<Bool> {
|
||||
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||
}
|
||||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> LoadStoreCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[hdl(cmp_eq)]
|
||||
/// `src0` is always the address to load from or store to.
|
||||
pub struct LoadStoreCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, SrcCount>,
|
||||
pub width: LoadStoreWidth,
|
||||
pub conversion: LoadStoreConversion,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1969,15 +2055,76 @@ common_mop_struct! {
|
|||
}
|
||||
}
|
||||
|
||||
impl<DestReg: Type, SrcRegWidth: Size> LoadMOp<DestReg, SrcRegWidth> {
|
||||
#[hdl]
|
||||
pub fn load<Target: MOpTrait>(
|
||||
dest: impl ToExpr<Type = DestReg>,
|
||||
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 1>>,
|
||||
width: impl ToExpr<Type = LoadStoreWidth>,
|
||||
conversion: impl ToExpr<Type = LoadStoreConversion>,
|
||||
) -> Expr<Target>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
MOpInto::mop_into(
|
||||
#[hdl]
|
||||
LoadMOp {
|
||||
load_store_common: #[hdl]
|
||||
LoadStoreCommonMOp {
|
||||
common: CommonMOp::new(
|
||||
0.cast_to_static::<UInt<_>>(),
|
||||
dest,
|
||||
src,
|
||||
SInt[COMMON_MOP_1_IMM_WIDTH].zero(),
|
||||
),
|
||||
width,
|
||||
conversion,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> StoreMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl(cmp_eq)]
|
||||
/// does `*src0 = convert(src1)`
|
||||
pub struct StoreMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub load_store_common: LoadStoreCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<DestReg: Type, SrcRegWidth: Size> StoreMOp<DestReg, SrcRegWidth> {
|
||||
#[hdl]
|
||||
pub fn store<Target: MOpTrait>(
|
||||
dest: impl ToExpr<Type = DestReg>,
|
||||
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 2>>,
|
||||
width: impl ToExpr<Type = LoadStoreWidth>,
|
||||
conversion: impl ToExpr<Type = LoadStoreConversion>,
|
||||
) -> Expr<Target>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
MOpInto::mop_into(
|
||||
#[hdl]
|
||||
StoreMOp {
|
||||
load_store_common: #[hdl]
|
||||
LoadStoreCommonMOp {
|
||||
common: CommonMOp::new(
|
||||
0.cast_to_static::<UInt<_>>(),
|
||||
dest,
|
||||
src,
|
||||
SInt[COMMON_MOP_2_IMM_WIDTH].zero(),
|
||||
),
|
||||
width,
|
||||
conversion,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
mop_enum! {
|
||||
#[impl_mop_into = true]
|
||||
#[hdl]
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@ impl MOpRegNum {
|
|||
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||
pub const POWER_ISA_XER_OTHER_REG_NUM: u32 = 5;
|
||||
|
||||
/// used as a temporary for things like computing the effective address before loading/storing memory
|
||||
pub const POWER_ISA_TEMP_REG_NUM: u32 = 8;
|
||||
#[hdl]
|
||||
pub fn power_isa_temp_reg() -> Expr<Self> {
|
||||
#[hdl]
|
||||
Self {
|
||||
value: Self::POWER_ISA_TEMP_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||
}
|
||||
}
|
||||
|
||||
/// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`]
|
||||
///
|
||||
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||
|
|
|
|||
105188
crates/cpu/tests/expected/reg_alloc.vcd
generated
105188
crates/cpu/tests/expected/reg_alloc.vcd
generated
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -9,6 +9,7 @@ mod branch;
|
|||
mod condition_register;
|
||||
mod fixed_point_arithmetic;
|
||||
mod fixed_point_compare;
|
||||
mod fixed_point_load;
|
||||
mod fixed_point_logical;
|
||||
mod move_to_from_system_register;
|
||||
mod prefixed_no_operation;
|
||||
|
|
@ -110,6 +111,7 @@ 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_load::test_cases_book_i_3_3_2_fixed_point_load(&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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,525 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::test_cases::{TestCase, insn_double};
|
||||
use cpu::instruction::{
|
||||
AddSubMOp, LoadMOp, LoadStoreConversion, LoadStoreWidth, MOpDestReg, MOpRegNum,
|
||||
OutputIntegerMode,
|
||||
};
|
||||
use fayalite::prelude::*;
|
||||
|
||||
/// covers instructions in PowerISA v3.1C Book I 3.3.2 Fixed-Point Load Instructions
|
||||
pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
|
||||
macro_rules! load_prefixed {
|
||||
(
|
||||
$mnemonic:literal $dest:literal, $disp:literal($ra:literal), $r:literal;
|
||||
$prefix:literal, $suffix:literal;
|
||||
$width:ident;
|
||||
$conversion:ident;
|
||||
) => {
|
||||
retval.push(insn_double(
|
||||
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().value
|
||||
} else {
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra).value
|
||||
},
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
($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().value],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
],
|
||||
));
|
||||
};
|
||||
}
|
||||
macro_rules! load {
|
||||
(
|
||||
$mnemonic:literal $dest:literal, $disp:literal($ra:literal);
|
||||
$encoding:literal;
|
||||
$width:ident;
|
||||
$conversion:ident;
|
||||
) => {
|
||||
retval.push(insn_double(
|
||||
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().value
|
||||
} else {
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra).value
|
||||
},
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
($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().value],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
],
|
||||
));
|
||||
};
|
||||
}
|
||||
macro_rules! load_update {
|
||||
(
|
||||
$mnemonic:literal $dest:literal, $disp:literal($ra:literal);
|
||||
$encoding:literal;
|
||||
$width:ident;
|
||||
$conversion:ident;
|
||||
) => {
|
||||
retval.push(insn_double(
|
||||
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).value,
|
||||
MOpRegNum::const_zero().value,
|
||||
],
|
||||
($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).value],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
],
|
||||
));
|
||||
};
|
||||
}
|
||||
macro_rules! load_indexed {
|
||||
(
|
||||
$mnemonic:literal $dest:literal, $ra:literal, $rb:literal;
|
||||
$encoding:literal;
|
||||
$width:ident;
|
||||
$conversion:ident;
|
||||
) => {
|
||||
retval.push(insn_double(
|
||||
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().value
|
||||
} else {
|
||||
MOpRegNum::power_isa_gpr_reg_imm($ra).value
|
||||
},
|
||||
MOpRegNum::power_isa_gpr_reg_imm($rb).value,
|
||||
],
|
||||
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().value],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
],
|
||||
));
|
||||
};
|
||||
}
|
||||
macro_rules! load_update_indexed {
|
||||
(
|
||||
$mnemonic:literal $dest:literal, $ra:literal, $rb:literal;
|
||||
$encoding:literal;
|
||||
$width:ident;
|
||||
$conversion:ident;
|
||||
) => {
|
||||
retval.push(insn_double(
|
||||
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).value,
|
||||
MOpRegNum::power_isa_gpr_reg_imm($rb).value,
|
||||
],
|
||||
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).value],
|
||||
LoadStoreWidth.$width(),
|
||||
LoadStoreConversion.$conversion(),
|
||||
),
|
||||
],
|
||||
));
|
||||
};
|
||||
}
|
||||
|
||||
load! {
|
||||
"lbz" 3, 0x1234(4);
|
||||
0x88641234;
|
||||
Width8Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load! {
|
||||
"lbz" 3, 0x1234(0);
|
||||
0x88601234;
|
||||
Width8Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plbz" 3, 0x123456789(4), 0;
|
||||
0x06012345, 0x88646789;
|
||||
Width8Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plbz" 3, 0x123456789(0), 0;
|
||||
0x06012345, 0x88606789;
|
||||
Width8Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plbz" 3, 0x123456789(0), 1;
|
||||
0x06112345, 0x88606789;
|
||||
Width8Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"lbzx" 3, 4, 5;
|
||||
0x7c6428ae;
|
||||
Width8Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"lbzx" 3, 0, 5;
|
||||
0x7c6028ae;
|
||||
Width8Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_update! {
|
||||
"lbzu" 3, 0x1234(4);
|
||||
0x8c641234;
|
||||
Width8Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_update_indexed! {
|
||||
"lbzux" 3, 4, 5;
|
||||
0x7c6428ee;
|
||||
Width8Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
|
||||
load! {
|
||||
"lhz" 3, 0x1234(4);
|
||||
0xa0641234;
|
||||
Width16Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load! {
|
||||
"lhz" 3, 0x1234(0);
|
||||
0xa0601234;
|
||||
Width16Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plhz" 3, 0x123456789(4), 0;
|
||||
0x06012345, 0xa0646789;
|
||||
Width16Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plhz" 3, 0x123456789(0), 0;
|
||||
0x06012345, 0xa0606789;
|
||||
Width16Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plhz" 3, 0x123456789(0), 1;
|
||||
0x06112345, 0xa0606789;
|
||||
Width16Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"lhzx" 3, 4, 5;
|
||||
0x7c642a2e;
|
||||
Width16Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"lhzx" 3, 0, 5;
|
||||
0x7c602a2e;
|
||||
Width16Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_update! {
|
||||
"lhzu" 3, 0x1234(4);
|
||||
0xa4641234;
|
||||
Width16Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_update_indexed! {
|
||||
"lhzux" 3, 4, 5;
|
||||
0x7c642a6e;
|
||||
Width16Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
|
||||
load! {
|
||||
"lha" 3, 0x1234(4);
|
||||
0xa8641234;
|
||||
Width16Bit;
|
||||
SignExt;
|
||||
}
|
||||
load! {
|
||||
"lha" 3, 0x1234(0);
|
||||
0xa8601234;
|
||||
Width16Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plha" 3, 0x123456789(4), 0;
|
||||
0x06012345, 0xa8646789;
|
||||
Width16Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plha" 3, 0x123456789(0), 0;
|
||||
0x06012345, 0xa8606789;
|
||||
Width16Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plha" 3, 0x123456789(0), 1;
|
||||
0x06112345, 0xa8606789;
|
||||
Width16Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"lhax" 3, 4, 5;
|
||||
0x7c642aae;
|
||||
Width16Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"lhax" 3, 0, 5;
|
||||
0x7c602aae;
|
||||
Width16Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_update! {
|
||||
"lhau" 3, 0x1234(4);
|
||||
0xac641234;
|
||||
Width16Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_update_indexed! {
|
||||
"lhaux" 3, 4, 5;
|
||||
0x7c642aee;
|
||||
Width16Bit;
|
||||
SignExt;
|
||||
}
|
||||
|
||||
load! {
|
||||
"lwz" 3, 0x1234(4);
|
||||
0x80641234;
|
||||
Width32Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load! {
|
||||
"lwz" 3, 0x1234(0);
|
||||
0x80601234;
|
||||
Width32Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plwz" 3, 0x123456789(4), 0;
|
||||
0x06012345, 0x80646789;
|
||||
Width32Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plwz" 3, 0x123456789(0), 0;
|
||||
0x06012345, 0x80606789;
|
||||
Width32Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plwz" 3, 0x123456789(0), 1;
|
||||
0x06112345, 0x80606789;
|
||||
Width32Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"lwzx" 3, 4, 5;
|
||||
0x7c64282e;
|
||||
Width32Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"lwzx" 3, 0, 5;
|
||||
0x7c60282e;
|
||||
Width32Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_update! {
|
||||
"lwzu" 3, 0x1234(4);
|
||||
0x84641234;
|
||||
Width32Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_update_indexed! {
|
||||
"lwzux" 3, 4, 5;
|
||||
0x7c64286e;
|
||||
Width32Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
|
||||
load! {
|
||||
"lwa" 3, 0x1234(4);
|
||||
0xe8641236;
|
||||
Width32Bit;
|
||||
SignExt;
|
||||
}
|
||||
load! {
|
||||
"lwa" 3, 0x1234(0);
|
||||
0xe8601236;
|
||||
Width32Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plwa" 3, 0x123456789(4), 0;
|
||||
0x04012345, 0xa4646789;
|
||||
Width32Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plwa" 3, 0x123456789(0), 0;
|
||||
0x04012345, 0xa4606789;
|
||||
Width32Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"plwa" 3, 0x123456789(0), 1;
|
||||
0x04112345, 0xa4606789;
|
||||
Width32Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"lwax" 3, 4, 5;
|
||||
0x7c642aaa;
|
||||
Width32Bit;
|
||||
SignExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"lwax" 3, 0, 5;
|
||||
0x7c602aaa;
|
||||
Width32Bit;
|
||||
SignExt;
|
||||
}
|
||||
// there is no `lwau`
|
||||
load_update_indexed! {
|
||||
"lwaux" 3, 4, 5;
|
||||
0x7c642aea;
|
||||
Width32Bit;
|
||||
SignExt;
|
||||
}
|
||||
|
||||
load! {
|
||||
"ld" 3, 0x1234(4);
|
||||
0xe8641234;
|
||||
Width64Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load! {
|
||||
"ld" 3, 0x1234(0);
|
||||
0xe8601234;
|
||||
Width64Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"pld" 3, 0x123456789(4), 0;
|
||||
0x04012345, 0xe4646789;
|
||||
Width64Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"pld" 3, 0x123456789(0), 0;
|
||||
0x04012345, 0xe4606789;
|
||||
Width64Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_prefixed! {
|
||||
"pld" 3, 0x123456789(0), 1;
|
||||
0x04112345, 0xe4606789;
|
||||
Width64Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"ldx" 3, 4, 5;
|
||||
0x7c64282a;
|
||||
Width64Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_indexed! {
|
||||
"ldx" 3, 0, 5;
|
||||
0x7c60282a;
|
||||
Width64Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_update! {
|
||||
"ldu" 3, 0x1234(4);
|
||||
0xe8641235;
|
||||
Width64Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
load_update_indexed! {
|
||||
"ldux" 3, 4, 5;
|
||||
0x7c64286a;
|
||||
Width64Bit;
|
||||
ZeroExt;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue