forked from libre-chip/cpu
implement decoding 8/16/32/64-bit store instructions -- all of Power ISA v3.1c Book I 3.3.3
This commit is contained in:
parent
706d54ae0d
commit
0824b63d31
4 changed files with 122563 additions and 87706 deletions
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
|
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
|
||||||
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
|
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
|
||||||
MOpRegNum, MoveRegMOp, OutputIntegerMode,
|
MOpRegNum, MoveRegMOp, OutputIntegerMode, StoreMOp,
|
||||||
},
|
},
|
||||||
powerisa_instructions_xml::{
|
powerisa_instructions_xml::{
|
||||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||||
|
|
@ -135,7 +135,7 @@ struct DecodeState {
|
||||||
conditions: Option<&'static str>,
|
conditions: Option<&'static str>,
|
||||||
header: &'static crate::powerisa_instructions_xml::InstructionHeader,
|
header: &'static crate::powerisa_instructions_xml::InstructionHeader,
|
||||||
insn: &'static crate::powerisa_instructions_xml::Instruction,
|
insn: &'static crate::powerisa_instructions_xml::Instruction,
|
||||||
output: Expr<ArrayVec<MOp, ConstUsize<2>>>,
|
output: Expr<ArrayVec<MOp, ConstUsize<3>>>,
|
||||||
is_illegal: Expr<Bool>,
|
is_illegal: Expr<Bool>,
|
||||||
first_input: Expr<UInt<32>>,
|
first_input: Expr<UInt<32>>,
|
||||||
second_input: Expr<HdlOption<UInt<32>>>,
|
second_input: Expr<HdlOption<UInt<32>>>,
|
||||||
|
|
@ -959,6 +959,196 @@ impl DecodeState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
fn decode_store_8_16_32_64_bit(&mut self) {
|
||||||
|
let (is_prefixed, is_update, is_indexed, width) = match self.mnemonic {
|
||||||
|
"stb" => (false, false, false, 8),
|
||||||
|
"pstb" => (true, false, false, 8),
|
||||||
|
"stbx" => (false, false, true, 8),
|
||||||
|
"stbu" => (false, true, false, 8),
|
||||||
|
"stbux" => (false, true, true, 8),
|
||||||
|
"sth" => (false, false, false, 16),
|
||||||
|
"psth" => (true, false, false, 16),
|
||||||
|
"sthx" => (false, false, true, 16),
|
||||||
|
"sthu" => (false, true, false, 16),
|
||||||
|
"sthux" => (false, true, true, 16),
|
||||||
|
"stw" => (false, false, false, 32),
|
||||||
|
"pstw" => (true, false, false, 32),
|
||||||
|
"stwx" => (false, false, true, 32),
|
||||||
|
"stwu" => (false, true, false, 32),
|
||||||
|
"stwux" => (false, true, true, 32),
|
||||||
|
"std" => (false, false, false, 64),
|
||||||
|
"pstd" => (true, false, false, 64),
|
||||||
|
"stdx" => (false, false, true, 64),
|
||||||
|
"stdu" => (false, true, false, 64),
|
||||||
|
"stdux" => (false, true, true, 64),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let width = match width {
|
||||||
|
8 => LoadStoreWidth.Width8Bit(),
|
||||||
|
16 => LoadStoreWidth.Width16Bit(),
|
||||||
|
32 => LoadStoreWidth.Width32Bit(),
|
||||||
|
64 => LoadStoreWidth.Width64Bit(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
#[hdl]
|
||||||
|
fn do_store(
|
||||||
|
this: &mut DecodeState,
|
||||||
|
rs: Expr<FieldGpr>,
|
||||||
|
ra: Expr<FieldGpr>,
|
||||||
|
is_update: bool,
|
||||||
|
width: Expr<LoadStoreWidth>,
|
||||||
|
write_compute_ea_insn: impl FnOnce(Expr<MOp>, Expr<MOpRegNum>),
|
||||||
|
) {
|
||||||
|
connect(
|
||||||
|
ArrayVec::len(this.output),
|
||||||
|
2usize.cast_to_static::<Length<_>>(),
|
||||||
|
);
|
||||||
|
let (ea_reg, ea_reg_conflict) = if is_update {
|
||||||
|
let ea_reg = wire_with_loc(
|
||||||
|
&format!("{}_ea_reg", this.mnemonic),
|
||||||
|
SourceLocation::caller(),
|
||||||
|
MOpRegNum,
|
||||||
|
);
|
||||||
|
connect(ea_reg, gpr(ra));
|
||||||
|
let ea_reg_conflict = ra.reg_num.cmp_eq(rs.reg_num);
|
||||||
|
#[hdl]
|
||||||
|
if ea_reg_conflict {
|
||||||
|
connect(ea_reg, MOpRegNum::power_isa_temp_reg());
|
||||||
|
}
|
||||||
|
(ea_reg, ea_reg_conflict)
|
||||||
|
} else {
|
||||||
|
(MOpRegNum::power_isa_temp_reg(), false.to_expr())
|
||||||
|
};
|
||||||
|
write_compute_ea_insn(this.output[0], ea_reg);
|
||||||
|
connect(
|
||||||
|
this.output[1],
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new([], []),
|
||||||
|
[ea_reg.value, gpr(rs).value],
|
||||||
|
width,
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
#[hdl]
|
||||||
|
if ea_reg_conflict {
|
||||||
|
connect(
|
||||||
|
ArrayVec::len(this.output),
|
||||||
|
3usize.cast_to_static::<Length<_>>(),
|
||||||
|
);
|
||||||
|
connect(
|
||||||
|
this.output[2],
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new([gpr(ra)], []),
|
||||||
|
[ea_reg.value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if is_prefixed {
|
||||||
|
assert_eq!(self.arguments, Some("RS,D(RA),R"));
|
||||||
|
assert!(!is_indexed);
|
||||||
|
self.decode_scope(
|
||||||
|
|this, (FieldRS(rs), FieldD0(d0), FieldD1(d1), FieldRA(ra), FieldR(r))| {
|
||||||
|
let d = ((d0 << 16) + d1.cast_to(SInt[32])).cast_to_static::<SInt<_>>();
|
||||||
|
do_store(this, rs, ra, is_update, width, |insn, ea_reg| {
|
||||||
|
#[hdl]
|
||||||
|
if r {
|
||||||
|
connect(
|
||||||
|
insn,
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new([ea_reg], []),
|
||||||
|
[MOpRegNum::const_zero().value; 2],
|
||||||
|
d,
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
connect(
|
||||||
|
insn,
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new([ea_reg], []),
|
||||||
|
[gpr_or_zero(ra).value, MOpRegNum::const_zero().value],
|
||||||
|
d,
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if is_indexed {
|
||||||
|
assert_eq!(self.arguments, Some("RS,RA,RB"));
|
||||||
|
self.decode_scope(|this, (FieldRS(rs), FieldRA(ra), FieldRB(rb))| {
|
||||||
|
do_store(this, rs, ra, is_update, width, |insn, ea_reg| {
|
||||||
|
connect(
|
||||||
|
insn,
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if self.arguments == Some("RS,disp(RA)") {
|
||||||
|
self.decode_scope(|this, (FieldRS(rs), FieldRA(ra), FieldDS(ds))| {
|
||||||
|
do_store(this, rs, ra, is_update, width, |insn, ea_reg| {
|
||||||
|
connect(
|
||||||
|
insn,
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
self.arguments,
|
||||||
|
Some("RS,D(RA)"),
|
||||||
|
"mnemonic={:?}",
|
||||||
|
self.mnemonic,
|
||||||
|
);
|
||||||
|
self.decode_scope(|this, (FieldRS(rs), FieldRA(ra), FieldD(d))| {
|
||||||
|
do_store(this, rs, ra, is_update, width, |insn, ea_reg| {
|
||||||
|
connect(
|
||||||
|
insn,
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
fn decode_addi_paddi(&mut self) {
|
fn decode_addi_paddi(&mut self) {
|
||||||
match self.mnemonic {
|
match self.mnemonic {
|
||||||
"addi" => {
|
"addi" => {
|
||||||
|
|
@ -1745,9 +1935,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
||||||
"stb", "pstb", "stbx", "stbu", "stbux", "sth", "psth", "sthx", "sthu", "sthux", "stw",
|
"stb", "pstb", "stbx", "stbu", "stbux", "sth", "psth", "sthx", "sthu", "sthux", "stw",
|
||||||
"pstw", "stwx", "stwu", "stwux", "std", "pstd", "stdx", "stdu", "stdux",
|
"pstw", "stwx", "stwu", "stwux", "std", "pstd", "stdx", "stdu", "stdux",
|
||||||
],
|
],
|
||||||
|_state| {
|
DecodeState::decode_store_8_16_32_64_bit,
|
||||||
// TODO
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
(&["lq", "plq", "stq", "pstq"], |_state| {
|
(&["lq", "plq", "stq", "pstq"], |_state| {
|
||||||
// TODO
|
// TODO
|
||||||
|
|
@ -2008,7 +2196,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
pub fn decode_one_insn() {
|
pub fn decode_one_insn() {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let output: ArrayVec<MOp, ConstUsize<2>> = m.output();
|
let output: ArrayVec<MOp, ConstUsize<3>> = m.output();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let is_illegal: Bool = m.output();
|
let is_illegal: Bool = m.output();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -11,6 +11,7 @@ mod fixed_point_arithmetic;
|
||||||
mod fixed_point_compare;
|
mod fixed_point_compare;
|
||||||
mod fixed_point_load;
|
mod fixed_point_load;
|
||||||
mod fixed_point_logical;
|
mod fixed_point_logical;
|
||||||
|
mod fixed_point_store;
|
||||||
mod move_to_from_system_register;
|
mod move_to_from_system_register;
|
||||||
mod prefixed_no_operation;
|
mod prefixed_no_operation;
|
||||||
|
|
||||||
|
|
@ -18,7 +19,7 @@ pub struct TestCase {
|
||||||
pub mnemonic: &'static str,
|
pub mnemonic: &'static str,
|
||||||
pub first_input: u32,
|
pub first_input: u32,
|
||||||
pub second_input: Option<u32>,
|
pub second_input: Option<u32>,
|
||||||
pub output: SimValue<ArrayVec<MOp, ConstUsize<2>>>,
|
pub output: SimValue<ArrayVec<MOp, ConstUsize<3>>>,
|
||||||
pub loc: &'static std::panic::Location<'static>,
|
pub loc: &'static std::panic::Location<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,11 +108,38 @@ fn insn_double(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn insn_triple(
|
||||||
|
mnemonic: &'static str,
|
||||||
|
first_input: u32,
|
||||||
|
second_input: Option<u32>,
|
||||||
|
insns: [impl ToSimValue<Type = MOp>; 3],
|
||||||
|
) -> TestCase {
|
||||||
|
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||||
|
.zero()
|
||||||
|
.cast_bits_to(MOp);
|
||||||
|
let mut single_storage = ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop);
|
||||||
|
ArrayVec::try_push_sim(&mut single_storage, &zero_mop).expect("known to have space");
|
||||||
|
ArrayVec::try_push_sim(&mut single_storage, &zero_mop).expect("known to have space");
|
||||||
|
ArrayVec::try_push_sim(&mut single_storage, zero_mop).expect("known to have space");
|
||||||
|
ArrayVec::elements_sim_mut(&mut single_storage)[0] = insns[0].to_sim_value();
|
||||||
|
ArrayVec::elements_sim_mut(&mut single_storage)[1] = insns[1].to_sim_value();
|
||||||
|
ArrayVec::elements_sim_mut(&mut single_storage)[2] = insns[2].to_sim_value();
|
||||||
|
TestCase {
|
||||||
|
mnemonic,
|
||||||
|
first_input,
|
||||||
|
second_input,
|
||||||
|
output: single_storage,
|
||||||
|
loc: std::panic::Location::caller(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn test_cases() -> Vec<TestCase> {
|
pub fn test_cases() -> Vec<TestCase> {
|
||||||
let mut retval = Vec::new();
|
let mut retval = Vec::new();
|
||||||
branch::test_cases_book_i_2_4_branch(&mut retval);
|
branch::test_cases_book_i_2_4_branch(&mut retval);
|
||||||
condition_register::test_cases_book_i_2_5_condition_register(&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_load::test_cases_book_i_3_3_2_fixed_point_load(&mut retval);
|
||||||
|
fixed_point_store::test_cases_book_i_3_3_3_fixed_point_store(&mut retval);
|
||||||
fixed_point_arithmetic::test_cases_book_i_3_3_9_fixed_point_arithmetic(&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_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);
|
fixed_point_logical::test_cases_book_i_3_3_13_fixed_point_logical(&mut retval);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,512 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_double, insn_triple};
|
||||||
|
use cpu::instruction::{
|
||||||
|
AddSubMOp, LoadStoreConversion, LoadStoreWidth, MOpDestReg, MOpRegNum, MoveRegMOp,
|
||||||
|
OutputIntegerMode, StoreMOp,
|
||||||
|
};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 3.3.3 Fixed-Point Store Instructions
|
||||||
|
pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
|
||||||
|
macro_rules! store_prefixed {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $rs:literal, $disp:literal($ra:literal), $r:literal;
|
||||||
|
$prefix:literal, $suffix:literal;
|
||||||
|
$width:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, "), ", $r),
|
||||||
|
$prefix,
|
||||||
|
Some($suffix),
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
if $r != 0 || $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().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,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_temp_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! store {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $rs:literal, $disp:literal($ra:literal);
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
if $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().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,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_temp_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! store_update {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $rs:literal, $disp:literal($ra:literal);
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
) => {
|
||||||
|
if $ra == $rs {
|
||||||
|
retval.push(insn_triple(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_temp_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||||
|
[MOpRegNum::power_isa_temp_reg().value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! store_indexed {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $rs:literal, $ra:literal, $rb:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
if $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().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,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_temp_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! store_update_indexed {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $rs:literal, $ra:literal, $rb:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
) => {
|
||||||
|
if $ra == $rs {
|
||||||
|
retval.push(insn_triple(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rb).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_temp_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||||
|
[MOpRegNum::power_isa_temp_reg().value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||||
|
[
|
||||||
|
if $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().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,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
store! {
|
||||||
|
"stb" 3, 0x1234(4);
|
||||||
|
0x98641234;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store! {
|
||||||
|
"stb" 3, 0x1234(0);
|
||||||
|
0x98601234;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstb" 3, 0x123456789(4), 0;
|
||||||
|
0x06012345, 0x98646789;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstb" 3, 0x123456789(0), 0;
|
||||||
|
0x06012345, 0x98606789;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstb" 3, 0x123456789(0), 1;
|
||||||
|
0x06112345, 0x98606789;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stbx" 3, 4, 5;
|
||||||
|
0x7c6429ae;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stbx" 3, 0, 5;
|
||||||
|
0x7c6029ae;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stbu" 3, 0x1234(4);
|
||||||
|
0x9c641234;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stbu" 3, 0x1234(3);
|
||||||
|
0x9c631234;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stbux" 3, 4, 5;
|
||||||
|
0x7c6429ee;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stbux" 3, 3, 5;
|
||||||
|
0x7c6329ee;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
store! {
|
||||||
|
"sth" 3, 0x1234(4);
|
||||||
|
0xb0641234;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store! {
|
||||||
|
"sth" 3, 0x1234(0);
|
||||||
|
0xb0601234;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"psth" 3, 0x123456789(4), 0;
|
||||||
|
0x06012345, 0xb0646789;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"psth" 3, 0x123456789(0), 0;
|
||||||
|
0x06012345, 0xb0606789;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"psth" 3, 0x123456789(0), 1;
|
||||||
|
0x06112345, 0xb0606789;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"sthx" 3, 4, 5;
|
||||||
|
0x7c642b2e;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"sthx" 3, 0, 5;
|
||||||
|
0x7c602b2e;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"sthu" 3, 0x1234(4);
|
||||||
|
0xb4641234;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"sthu" 3, 0x1234(3);
|
||||||
|
0xb4631234;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"sthux" 3, 4, 5;
|
||||||
|
0x7c642b6e;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"sthux" 3, 3, 5;
|
||||||
|
0x7c632b6e;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
store! {
|
||||||
|
"stw" 3, 0x1234(4);
|
||||||
|
0x90641234;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store! {
|
||||||
|
"stw" 3, 0x1234(0);
|
||||||
|
0x90601234;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstw" 3, 0x123456789(4), 0;
|
||||||
|
0x06012345, 0x90646789;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstw" 3, 0x123456789(0), 0;
|
||||||
|
0x06012345, 0x90606789;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstw" 3, 0x123456789(0), 1;
|
||||||
|
0x06112345, 0x90606789;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stwx" 3, 4, 5;
|
||||||
|
0x7c64292e;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stwx" 3, 0, 5;
|
||||||
|
0x7c60292e;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stwu" 3, 0x1234(4);
|
||||||
|
0x94641234;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stwu" 3, 0x1234(3);
|
||||||
|
0x94631234;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stwux" 3, 4, 5;
|
||||||
|
0x7c64296e;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stwux" 3, 3, 5;
|
||||||
|
0x7c63296e;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
store! {
|
||||||
|
"std" 3, 0x1234(4);
|
||||||
|
0xf8641234;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store! {
|
||||||
|
"std" 3, 0x1234(0);
|
||||||
|
0xf8601234;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstd" 3, 0x123456789(4), 0;
|
||||||
|
0x04012345, 0xf4646789;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstd" 3, 0x123456789(0), 0;
|
||||||
|
0x04012345, 0xf4606789;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstd" 3, 0x123456789(0), 1;
|
||||||
|
0x04112345, 0xf4606789;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stdx" 3, 4, 5;
|
||||||
|
0x7c64292a;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stdx" 3, 0, 5;
|
||||||
|
0x7c60292a;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stdu" 3, 0x1234(4);
|
||||||
|
0xf8641235;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stdu" 3, 0x1234(3);
|
||||||
|
0xf8631235;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stdux" 3, 4, 5;
|
||||||
|
0x7c64296a;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stdux" 3, 3, 5;
|
||||||
|
0x7c63296a;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue