implement decoding 8/16/32/64-bit load instructions -- all of Power ISA v3.1C Book I 3.3.2
All checks were successful
/ test (pull_request) Successful in 28m7s

This commit is contained in:
Jacob Lifshay 2026-01-23 16:06:16 -08:00
parent d361a2b578
commit 706d54ae0d
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
7 changed files with 146914 additions and 114528 deletions

View file

@ -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,
),
(
&[

View file

@ -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]

View file

@ -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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -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;
}
}