forked from libre-chip/cpu
implement decoding 8/16/32/64-bit load instructions -- all of Power ISA v3.1C Book I 3.3.2
This commit is contained in:
parent
d361a2b578
commit
706d54ae0d
7 changed files with 146914 additions and 114528 deletions
|
|
@ -4,9 +4,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::CpuConfig,
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LogicalFlagsMOp,
|
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
|
||||||
LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg, MOpRegNum, MoveRegMOp,
|
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
|
||||||
OutputIntegerMode,
|
MOpRegNum, MoveRegMOp, OutputIntegerMode,
|
||||||
},
|
},
|
||||||
powerisa_instructions_xml::{
|
powerisa_instructions_xml::{
|
||||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||||
|
|
@ -16,7 +16,12 @@ use crate::{
|
||||||
},
|
},
|
||||||
util::array_vec::{ArrayVec, Length},
|
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};
|
use std::{collections::BTreeMap, ops::RangeInclusive};
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
|
|
@ -203,6 +208,14 @@ impl_fields! {
|
||||||
struct FieldRT(FieldGpr);
|
struct FieldRT(FieldGpr);
|
||||||
#[name = "BD"]
|
#[name = "BD"]
|
||||||
struct FieldBD(SInt<14>);
|
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"]
|
#[name = "LI"]
|
||||||
struct FieldLI(SInt<24>);
|
struct FieldLI(SInt<24>);
|
||||||
#[name = "SI"]
|
#[name = "SI"]
|
||||||
|
|
@ -336,14 +349,17 @@ impl DecodeState {
|
||||||
}
|
}
|
||||||
panic!("can't extract bit field name text: {bit_field_name:#?}")
|
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 (msb0_start, msb0_end) = bit_range.into_inner();
|
||||||
let max_index = word.ty().width() - 1;
|
let max_index = word.ty().width() - 1;
|
||||||
let (Some(lsb0_start), Some(lsb0_end)) = (
|
let (Some(lsb0_start), Some(lsb0_end)) = (
|
||||||
max_index.checked_sub(msb0_end),
|
max_index.checked_sub(msb0_end),
|
||||||
max_index.checked_sub(msb0_start),
|
max_index.checked_sub(msb0_start),
|
||||||
) else {
|
) 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]
|
word[lsb0_start..=lsb0_end]
|
||||||
}
|
}
|
||||||
|
|
@ -382,7 +398,11 @@ impl DecodeState {
|
||||||
) {
|
) {
|
||||||
let mut last_start = word.ty().width();
|
let mut last_start = word.ty().width();
|
||||||
for bit_field in fields_inner.fields().iter().rev() {
|
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 {
|
let Some(first_bit_number) = bit_number_split.next() else {
|
||||||
panic!(
|
panic!(
|
||||||
"missing first bit number: {fields_inner:#?}\nheader: {:#?}",
|
"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:#?}");
|
panic!("no space for bit field, next bit field starts at bit 0\n{fields_inner:#?}");
|
||||||
};
|
};
|
||||||
last_start = *msb0_bit_range.start();
|
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 mut name = Self::bit_field_name(bit_field.name());
|
||||||
let orig_name = name;
|
let orig_name = name;
|
||||||
if name.contains(char::is_alphabetic) {
|
if name.contains(char::is_alphabetic) {
|
||||||
|
|
@ -734,6 +754,211 @@ impl DecodeState {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[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) {
|
fn decode_addi_paddi(&mut self) {
|
||||||
match self.mnemonic {
|
match self.mnemonic {
|
||||||
"addi" => {
|
"addi" => {
|
||||||
|
|
@ -1513,9 +1738,7 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
||||||
"plha", "lhax", "lhau", "lhaux", "lwz", "plwz", "lwzx", "lwzu", "lwzux", "lwa", "plwa",
|
"plha", "lhax", "lhau", "lhaux", "lwz", "plwz", "lwzx", "lwzu", "lwzux", "lwa", "plwa",
|
||||||
"lwax", "lwaux", "ld", "pld", "ldx", "ldu", "ldux",
|
"lwax", "lwaux", "ld", "pld", "ldx", "ldu", "ldux",
|
||||||
],
|
],
|
||||||
|_state| {
|
DecodeState::decode_load_8_16_32_64_bit,
|
||||||
// TODO
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
&[
|
&[
|
||||||
|
|
|
||||||
|
|
@ -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! {
|
common_mop_struct! {
|
||||||
#[mapped(<NewDestReg, NewSrcRegWidth> LoadStoreCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
#[mapped(<NewDestReg, NewSrcRegWidth> LoadStoreCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq)]
|
||||||
|
/// `src0` is always the address to load from or store to.
|
||||||
pub struct LoadStoreCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
pub struct LoadStoreCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
||||||
#[common]
|
#[common]
|
||||||
pub common: CommonMOp<ConstUsize<3>, DestReg, SrcRegWidth, SrcCount>,
|
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! {
|
common_mop_struct! {
|
||||||
#[mapped(<NewDestReg, NewSrcRegWidth> StoreMOp<NewDestReg, NewSrcRegWidth>)]
|
#[mapped(<NewDestReg, NewSrcRegWidth> StoreMOp<NewDestReg, NewSrcRegWidth>)]
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq)]
|
||||||
|
/// does `*src0 = convert(src1)`
|
||||||
pub struct StoreMOp<DestReg: Type, SrcRegWidth: Size> {
|
pub struct StoreMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||||
#[common]
|
#[common]
|
||||||
pub load_store_common: LoadStoreCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
|
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! {
|
mop_enum! {
|
||||||
#[impl_mop_into = true]
|
#[impl_mop_into = true]
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,16 @@ impl MOpRegNum {
|
||||||
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||||
pub const POWER_ISA_XER_OTHER_REG_NUM: u32 = 5;
|
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`]
|
/// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`]
|
||||||
///
|
///
|
||||||
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
/// [`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 condition_register;
|
||||||
mod fixed_point_arithmetic;
|
mod fixed_point_arithmetic;
|
||||||
mod fixed_point_compare;
|
mod fixed_point_compare;
|
||||||
|
mod fixed_point_load;
|
||||||
mod fixed_point_logical;
|
mod fixed_point_logical;
|
||||||
mod move_to_from_system_register;
|
mod move_to_from_system_register;
|
||||||
mod prefixed_no_operation;
|
mod prefixed_no_operation;
|
||||||
|
|
@ -110,6 +111,7 @@ 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_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,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