implement decoding mtspr/mfspr/mftb
This commit is contained in:
parent
a42b76b468
commit
f88346ea37
8 changed files with 175160 additions and 165913 deletions
|
|
@ -6,8 +6,9 @@ use crate::{
|
|||
instruction::{
|
||||
AddSubMOp, BranchMOp, CompareMOp, CompareMode, ConditionMode, LoadMOp, LoadStoreConversion,
|
||||
LoadStoreWidth, LogicalFlagsMOp, LogicalFlagsMOpImm, LogicalMOp, Lut4, MOp, MOpDestReg,
|
||||
MOpRegNum, MoveRegMOp, OutputIntegerMode, ShiftRotateDestLogicOp, ShiftRotateMOp,
|
||||
ShiftRotateMOpImm, ShiftRotateMode, StoreMOp,
|
||||
MOpRegNum, MoveRegMOp, OutputIntegerMode, ReadSpecialMOp, ReadSpecialMOpImm,
|
||||
ShiftRotateDestLogicOp, ShiftRotateMOp, ShiftRotateMOpImm, ShiftRotateMode, StoreMOp,
|
||||
power_isa::PowerIsaSprEnum,
|
||||
},
|
||||
powerisa_instructions_xml::{
|
||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||
|
|
@ -239,6 +240,10 @@ impl_fields! {
|
|||
struct FieldSi0(SInt<18>);
|
||||
#[name = "si1"]
|
||||
struct FieldSi1(UInt<16>);
|
||||
#[name = "spr"]
|
||||
struct FieldSpr(UInt<10>);
|
||||
#[name = "tbr"]
|
||||
struct FieldTbr(UInt<10>);
|
||||
#[name = "UI"]
|
||||
struct FieldUI(UInt<16>);
|
||||
#[name = "d0"]
|
||||
|
|
@ -2319,6 +2324,110 @@ impl DecodeState<'_> {
|
|||
},
|
||||
);
|
||||
}
|
||||
fn read_write_spr(
|
||||
&mut self,
|
||||
spr: PowerIsaSprEnum,
|
||||
reg: Expr<FieldGpr>,
|
||||
is_write_to_spr: bool,
|
||||
) -> Result<(), ()> {
|
||||
let normal_move = |spr: Expr<MOpRegNum>| {
|
||||
connect(
|
||||
ArrayVec::len(self.output),
|
||||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
if is_write_to_spr {
|
||||
connect(
|
||||
self.output[0],
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new([spr], []),
|
||||
[gpr(reg).value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
connect(
|
||||
self.output[0],
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new([gpr(reg)], []),
|
||||
[spr.value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
let read_special = |imm: Expr<ReadSpecialMOpImm>| {
|
||||
connect(
|
||||
ArrayVec::len(self.output),
|
||||
1usize.cast_to_static::<Length<_>>(),
|
||||
);
|
||||
connect(
|
||||
self.output[0],
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new([gpr(reg)], []),
|
||||
[MOpRegNum::const_zero().value; 0],
|
||||
imm,
|
||||
),
|
||||
);
|
||||
Ok(())
|
||||
};
|
||||
match spr {
|
||||
// PowerIsaSprEnum::Xer => todo!(),
|
||||
PowerIsaSprEnum::Lr => normal_move(MOpRegNum::power_isa_lr_reg()),
|
||||
PowerIsaSprEnum::Ctr => normal_move(MOpRegNum::power_isa_ctr_reg()),
|
||||
PowerIsaSprEnum::Tar => normal_move(MOpRegNum::power_isa_tar_reg()),
|
||||
PowerIsaSprEnum::Tb if !is_write_to_spr => {
|
||||
read_special(ReadSpecialMOpImm.PowerIsaTimeBase())
|
||||
}
|
||||
PowerIsaSprEnum::Tbu if !is_write_to_spr => {
|
||||
read_special(ReadSpecialMOpImm.PowerIsaTimeBaseU())
|
||||
}
|
||||
_ => {
|
||||
Err(()) // allow emulation
|
||||
}
|
||||
}
|
||||
}
|
||||
/// for `mtspr/mfspr/mftb`
|
||||
fn decode_mtspr_mfspr_mftb(&mut self) {
|
||||
#[hdl]
|
||||
fn do_read_write_spr(
|
||||
this: &mut DecodeState<'_>,
|
||||
spr_field: Expr<UInt<10>>,
|
||||
reg: Expr<FieldGpr>,
|
||||
is_write_to_spr: bool,
|
||||
) {
|
||||
#[hdl]
|
||||
let spr_num = wire();
|
||||
connect(spr_num, spr_field.rotate_left(5));
|
||||
connect(this.is_illegal, true); // trap and/or allow emulation
|
||||
for &spr in PowerIsaSprEnum::VARIANTS {
|
||||
let num = spr.to_expr().num;
|
||||
#[hdl]
|
||||
if spr_num.cmp_eq(num) {
|
||||
match this.read_write_spr(spr, reg, is_write_to_spr) {
|
||||
Ok(()) => {
|
||||
connect(this.is_illegal, false);
|
||||
}
|
||||
Err(()) => {
|
||||
// self.is_illegal is already set to true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
match self.mnemonic {
|
||||
"mtspr" => self.decode_scope(|this, (FieldSpr(spr), FieldRS(rs))| {
|
||||
do_read_write_spr(this, spr, rs, true)
|
||||
}),
|
||||
"mfspr" => self.decode_scope(|this, (FieldRT(rt), FieldSpr(spr))| {
|
||||
do_read_write_spr(this, spr, rt, false)
|
||||
}),
|
||||
"mftb" => self.decode_scope(|this, (FieldRT(rt), FieldTbr(tbr))| {
|
||||
do_read_write_spr(this, tbr, rt, false)
|
||||
}),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
/// for `mcrxrx`
|
||||
#[hdl]
|
||||
fn decode_mcrxrx(&mut self) {
|
||||
|
|
@ -2572,12 +2681,12 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
|||
// TODO(FP) -- mostly intentionally not implemented
|
||||
},
|
||||
),
|
||||
(
|
||||
&["mtspr", "mfspr", "mftb", "mtmsr", "mtmsrd", "mfmsr"],
|
||||
|_state| {
|
||||
// TODO
|
||||
},
|
||||
),
|
||||
(&["mtspr", "mfspr", "mftb"], |state| {
|
||||
DecodeState::decode_mtspr_mfspr_mftb(state)
|
||||
}),
|
||||
(&["mtmsr", "mtmsrd", "mfmsr"], |_state| {
|
||||
// TODO
|
||||
}),
|
||||
(&["mcrxrx"], |state| DecodeState::decode_mcrxrx(state)),
|
||||
(
|
||||
&[
|
||||
|
|
|
|||
|
|
@ -2239,6 +2239,80 @@ impl<DestReg: Type, SrcRegWidth: Size> BranchMOp<DestReg, SrcRegWidth, ConstUsiz
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub enum ReadSpecialMOpImm {
|
||||
PowerIsaTimeBase,
|
||||
PowerIsaTimeBaseU,
|
||||
}
|
||||
|
||||
impl HdlPartialEqImpl<Self> for ReadSpecialMOpImm {
|
||||
#[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> ReadSpecialMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct ReadSpecialMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, ConstUsize<0>, ReadSpecialMOpImm>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<DestReg: Type, SrcRegWidth: Size> ReadSpecialMOp<DestReg, SrcRegWidth> {
|
||||
#[hdl]
|
||||
pub fn read_special<Target: MOpTrait>(
|
||||
dest: impl ToExpr<Type = DestReg>,
|
||||
src: impl ToExpr<Type = Array<UIntType<SrcRegWidth>, 0>>,
|
||||
imm: impl ToExpr<Type = ReadSpecialMOpImm>,
|
||||
) -> Expr<Target>
|
||||
where
|
||||
Self: MOpInto<Target>,
|
||||
{
|
||||
MOpInto::mop_into(
|
||||
#[hdl]
|
||||
ReadSpecialMOp {
|
||||
common: #[hdl]
|
||||
CommonMOp {
|
||||
prefix_pad: 0_hdl_u0,
|
||||
dest,
|
||||
src,
|
||||
imm,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
mop_enum! {
|
||||
#[impl_mop_into = true]
|
||||
#[hdl]
|
||||
|
|
@ -2253,6 +2327,7 @@ mop_enum! {
|
|||
CompareI(CompareMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||
Branch(BranchMOp<DestReg, SrcRegWidth, ConstUsize<3>>),
|
||||
BranchI(BranchMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
||||
ReadSpecial(ReadSpecialMOp<DestReg, SrcRegWidth>),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -221,3 +221,238 @@ impl MOpRegNum {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct PowerIsaSpr {
|
||||
pub num: UInt<10>,
|
||||
}
|
||||
|
||||
macro_rules! make_spr_enum {
|
||||
(
|
||||
$(#[$enum_meta:meta])*
|
||||
$enum_vis:vis enum $PowerIsaSprEnum:ident {
|
||||
$($enum_body:tt)*
|
||||
}
|
||||
) => {
|
||||
$(#[$enum_meta])*
|
||||
$enum_vis enum $PowerIsaSprEnum {
|
||||
$($enum_body)*
|
||||
Unknown(u16),
|
||||
}
|
||||
|
||||
make_spr_enum! {
|
||||
@impl
|
||||
$enum_vis enum $PowerIsaSprEnum {
|
||||
$($enum_body)*
|
||||
}
|
||||
}
|
||||
};
|
||||
(
|
||||
@impl
|
||||
$enum_vis:vis enum $PowerIsaSprEnum:ident {
|
||||
$(
|
||||
$(#[$variant_meta:meta])*
|
||||
$Variant:ident = $value:literal,
|
||||
)+
|
||||
}
|
||||
) => {
|
||||
impl $PowerIsaSprEnum {
|
||||
pub const VARIANTS: &[Self; 1 << 10] = &{
|
||||
let mut retval = [Self::Unknown(0); 1 << 10];
|
||||
let mut i = 0;
|
||||
while i < retval.len() {
|
||||
retval[i] = Self::Unknown(i as u16);
|
||||
i += 1;
|
||||
}
|
||||
let mut last_value = None;
|
||||
#[track_caller]
|
||||
const fn add_variant(
|
||||
values: &mut [$PowerIsaSprEnum; 1 << 10],
|
||||
last_value: &mut Option<u16>,
|
||||
variant: $PowerIsaSprEnum,
|
||||
value: u16,
|
||||
) {
|
||||
assert!(value < 1 << 10, "variant value out of range");
|
||||
if let Some(last_value) = *last_value {
|
||||
assert!(last_value < value, "variants must be in ascending order with no duplicates");
|
||||
}
|
||||
*last_value = Some(value);
|
||||
values[value as usize] = variant;
|
||||
}
|
||||
$(add_variant(&mut retval, &mut last_value, Self::$Variant, $value);)+
|
||||
retval
|
||||
};
|
||||
pub const fn value(self) -> u16 {
|
||||
match self {
|
||||
$(Self::$Variant => $value,)+
|
||||
Self::Unknown(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_spr_enum! {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[repr(u16)]
|
||||
pub enum PowerIsaSprEnum {
|
||||
Xer = 1,
|
||||
UserDscr = 3,
|
||||
Lr = 8,
|
||||
Ctr = 9,
|
||||
UserAmr = 13,
|
||||
Dscr = 17,
|
||||
Dsisr = 18,
|
||||
Dar = 19,
|
||||
Dec = 22,
|
||||
Srr0 = 26,
|
||||
Srr1 = 27,
|
||||
Cfar = 28,
|
||||
Amr = 29,
|
||||
Pidr = 48,
|
||||
Iamr = 61,
|
||||
ReadCtrl = 136,
|
||||
WriteCtrl = 152,
|
||||
Fscr = 153,
|
||||
Uamor = 157,
|
||||
Pspb = 159,
|
||||
Dpdes = 176,
|
||||
Dawr0 = 180,
|
||||
Dawr1 = 181,
|
||||
Rpr = 186,
|
||||
Ciabr = 187,
|
||||
Dawrx0 = 188,
|
||||
Dawrx1 = 189,
|
||||
Hfscr = 190,
|
||||
Vrsave = 256,
|
||||
UserSprg3 = 259,
|
||||
Tb = 268,
|
||||
Tbu = 269,
|
||||
Sprg0 = 272,
|
||||
Sprg1 = 273,
|
||||
Sprg2 = 274,
|
||||
Sprg3 = 275,
|
||||
Tbl = 284,
|
||||
WriteTbu = 285,
|
||||
Tbu40 = 286,
|
||||
Pvr = 287,
|
||||
Hsprg0 = 304,
|
||||
Hsprg1 = 305,
|
||||
Hdsisr = 306,
|
||||
Hdar = 307,
|
||||
Spurr = 308,
|
||||
Purr = 309,
|
||||
Hdec = 310,
|
||||
Hrmor = 313,
|
||||
Hsrr0 = 314,
|
||||
Hsrr1 = 315,
|
||||
Lpcr = 318,
|
||||
Lpidr = 319,
|
||||
Hmer = 336,
|
||||
Hmeer = 337,
|
||||
Pcr = 338,
|
||||
Heir = 339,
|
||||
Amor = 349,
|
||||
Tir = 446,
|
||||
UserHdexcr = 455,
|
||||
Ptcr = 464,
|
||||
Hashkeyr = 468,
|
||||
Hashpkeyr = 469,
|
||||
Hdexcr = 471,
|
||||
Usprg0 = 496,
|
||||
Usprg1 = 497,
|
||||
Urmor = 505,
|
||||
Usrr0 = 506,
|
||||
Usrr1 = 507,
|
||||
Smfctrl = 511,
|
||||
UserSier2 = 736,
|
||||
UserSier3 = 737,
|
||||
UserMmcr3 = 738,
|
||||
Sier2 = 752,
|
||||
Sier3 = 753,
|
||||
Mmcr3 = 754,
|
||||
UserSier = 768,
|
||||
Mmcr2 = 769,
|
||||
Mmcra = 770,
|
||||
Pmc1 = 771,
|
||||
Pmc2 = 772,
|
||||
Pmc3 = 773,
|
||||
Pmc4 = 774,
|
||||
Pmc5 = 775,
|
||||
Pmc6 = 776,
|
||||
Mmcr0 = 779,
|
||||
Siar = 780,
|
||||
Sdar = 781,
|
||||
Mmcr1 = 782,
|
||||
Sier = 784,
|
||||
PrivMmcr2 = 785,
|
||||
PrivMmcra = 786,
|
||||
PrivPmc1 = 787,
|
||||
PrivPmc2 = 788,
|
||||
PrivPmc3 = 789,
|
||||
PrivPmc4 = 790,
|
||||
PrivPmc5 = 791,
|
||||
PrivPmc6 = 792,
|
||||
PrivMmcr0 = 795,
|
||||
PrivSiar = 796,
|
||||
PrivSdar = 797,
|
||||
PrivMmcr1 = 798,
|
||||
Bescrs15 = 800,
|
||||
Bescrsu16 = 801,
|
||||
Bescrr15 = 802,
|
||||
Bescrru16 = 803,
|
||||
Ebbhr = 804,
|
||||
Ebbrr = 805,
|
||||
Bescr = 806,
|
||||
Reserved808 = 808,
|
||||
Reserved809 = 809,
|
||||
Reserved810 = 810,
|
||||
Reserved811 = 811,
|
||||
UserDexcr = 812,
|
||||
Tar = 815,
|
||||
Asdr = 816,
|
||||
Psscr = 823,
|
||||
Dexcr = 828,
|
||||
Ic = 848,
|
||||
Vtb = 849,
|
||||
HyperPsscr = 855,
|
||||
Ppr = 896,
|
||||
Ppr32 = 898,
|
||||
Pir = 1023,
|
||||
}
|
||||
}
|
||||
|
||||
impl ValueType for PowerIsaSprEnum {
|
||||
type Type = PowerIsaSpr;
|
||||
type ValueCategory = fayalite::expr::value_category::ValueCategoryValue;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
PowerIsaSpr
|
||||
}
|
||||
}
|
||||
|
||||
impl ToExpr for PowerIsaSprEnum {
|
||||
#[hdl]
|
||||
fn to_expr(&self) -> Expr<Self::Type> {
|
||||
#[hdl]
|
||||
PowerIsaSpr {
|
||||
num: self.value().cast_to_static::<UInt<_>>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSimValueWithType<PowerIsaSpr> for PowerIsaSprEnum {
|
||||
fn to_sim_value_with_type(&self, _ty: PowerIsaSpr) -> SimValue<PowerIsaSpr> {
|
||||
self.to_sim_value()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSimValue for PowerIsaSprEnum {
|
||||
#[hdl]
|
||||
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||
#[hdl(sim)]
|
||||
PowerIsaSpr {
|
||||
num: self.value().cast_to_static::<UInt<_>>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ use crate::{
|
|||
config::CpuConfig,
|
||||
instruction::{
|
||||
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOpDefaultImm,
|
||||
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp,
|
||||
ShiftRotateMOp, UnitOutRegNum,
|
||||
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, ReadSpecialMOp,
|
||||
RenamedMOp, ShiftRotateMOp, UnitOutRegNum,
|
||||
},
|
||||
register::{
|
||||
FlagsMode, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, PRegFlagsX86,
|
||||
|
|
@ -328,6 +328,21 @@ fn branch<SrcCount: KnownSize>(
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn read_special(
|
||||
mop: Expr<ReadSpecialMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
||||
pc: Expr<UInt<64>>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
// TODO: finish
|
||||
#[hdl]
|
||||
UnitResultCompleted::<_> {
|
||||
value: PRegValue::zeroed(),
|
||||
extra_out: (),
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||
#[hdl]
|
||||
|
|
@ -541,6 +556,24 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
|||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::ReadSpecial(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(read_special(
|
||||
mop,
|
||||
pc,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
123289
crates/cpu/tests/expected/reg_alloc.vcd
generated
123289
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
|
|
@ -151,5 +151,8 @@ pub fn test_cases() -> Vec<TestCase> {
|
|||
&mut retval,
|
||||
);
|
||||
prefixed_no_operation::test_cases_book_i_3_3_20_prefixed_no_operation(&mut retval);
|
||||
move_to_from_system_register::test_cases_book_iii_5_4_4_move_to_from_system_register(
|
||||
&mut retval,
|
||||
);
|
||||
retval
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::test_cases::{TestCase, insn_single};
|
||||
use cpu::instruction::{LogicalFlagsMOp, LogicalFlagsMOpImm, Lut4, MOpDestReg, MOpRegNum};
|
||||
use cpu::instruction::{
|
||||
LogicalFlagsMOp, LogicalFlagsMOpImm, Lut4, MOpDestReg, MOpRegNum, MoveRegMOp, ReadSpecialMOp,
|
||||
ReadSpecialMOpImm,
|
||||
};
|
||||
use fayalite::prelude::*;
|
||||
|
||||
/// covers instructions in PowerISA v3.1C Book I 3.3.19 Move To/From System Register Instructions
|
||||
pub fn test_cases_book_i_3_3_19_move_to_from_system_register(retval: &mut Vec<TestCase>) {
|
||||
// mfspr/mtspr are covered by test_cases_book_iii_5_4_4_move_to_from_system_register
|
||||
#[hdl]
|
||||
fn mcrxrx_imm() -> SimValue<LogicalFlagsMOpImm> {
|
||||
#[hdl(sim)]
|
||||
|
|
@ -35,3 +39,111 @@ pub fn test_cases_book_i_3_3_19_move_to_from_system_register(retval: &mut Vec<Te
|
|||
),
|
||||
));
|
||||
}
|
||||
|
||||
/// covers instructions in PowerISA v3.1C Book III 5.4.4 Move To/From System Register Instructions
|
||||
pub fn test_cases_book_iii_5_4_4_move_to_from_system_register(retval: &mut Vec<TestCase>) {
|
||||
retval.push(insn_single(
|
||||
"mflr 3",
|
||||
0x7c6802a6,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_lr_reg().value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"mtlr 3",
|
||||
0x7c6803a6,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(3).value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"mfctr 3",
|
||||
0x7c6902a6,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_ctr_reg().value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"mtctr 3",
|
||||
0x7c6903a6,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_CTR_REG_NUM], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(3).value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"mfspr 3, 815 # mftar 3",
|
||||
0x7c6fcaa6,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::power_isa_tar_reg().value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
retval.push(insn_single(
|
||||
"mtspr 815, 3 # mttar 3",
|
||||
0x7c6fcba6,
|
||||
None,
|
||||
MoveRegMOp::move_reg(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TAR_REG_NUM], &[]),
|
||||
[MOpRegNum::power_isa_gpr_reg_imm(3).value],
|
||||
0.cast_to_static::<SInt<_>>(),
|
||||
),
|
||||
));
|
||||
// make sure we generate mfspr and not the phased-out mftb
|
||||
retval.push(insn_single(
|
||||
"mfspr 3, 268 # mftb 3",
|
||||
0x7c6c42a6,
|
||||
None,
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero().value; 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBase(),
|
||||
),
|
||||
));
|
||||
// make sure we generate mfspr and not the phased-out mftb
|
||||
retval.push(insn_single(
|
||||
"mfspr 3, 269 # mftbu 3",
|
||||
0x7c6d42a6,
|
||||
None,
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero().value; 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBaseU(),
|
||||
),
|
||||
));
|
||||
// phased-out mftb -- not actually generated by the assembler so we have to use .long
|
||||
retval.push(insn_single(
|
||||
".long 0x7c6c42e6 # mftb 3, 268",
|
||||
0x7c6c42e6,
|
||||
None,
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero().value; 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBase(),
|
||||
),
|
||||
));
|
||||
// phased-out mftb -- not actually generated by the assembler so we have to use .long
|
||||
retval.push(insn_single(
|
||||
".long 0x7c6d42e6 # mftb 3, 269",
|
||||
0x7c6d42e6,
|
||||
None,
|
||||
ReadSpecialMOp::read_special(
|
||||
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||
[MOpRegNum::const_zero().value; 0],
|
||||
ReadSpecialMOpImm.PowerIsaTimeBaseU(),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue