forked from libre-chip/cpu
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::{
|
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, ShiftRotateDestLogicOp, ShiftRotateMOp,
|
MOpRegNum, MoveRegMOp, OutputIntegerMode, ReadSpecialMOp, ReadSpecialMOpImm,
|
||||||
ShiftRotateMOpImm, ShiftRotateMode, StoreMOp,
|
ShiftRotateDestLogicOp, ShiftRotateMOp, ShiftRotateMOpImm, ShiftRotateMode, StoreMOp,
|
||||||
|
power_isa::PowerIsaSprEnum,
|
||||||
},
|
},
|
||||||
powerisa_instructions_xml::{
|
powerisa_instructions_xml::{
|
||||||
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
InstructionBitFieldName, InstructionBitFieldsInner, Instructions, TextLineItem,
|
||||||
|
|
@ -239,6 +240,10 @@ impl_fields! {
|
||||||
struct FieldSi0(SInt<18>);
|
struct FieldSi0(SInt<18>);
|
||||||
#[name = "si1"]
|
#[name = "si1"]
|
||||||
struct FieldSi1(UInt<16>);
|
struct FieldSi1(UInt<16>);
|
||||||
|
#[name = "spr"]
|
||||||
|
struct FieldSpr(UInt<10>);
|
||||||
|
#[name = "tbr"]
|
||||||
|
struct FieldTbr(UInt<10>);
|
||||||
#[name = "UI"]
|
#[name = "UI"]
|
||||||
struct FieldUI(UInt<16>);
|
struct FieldUI(UInt<16>);
|
||||||
#[name = "d0"]
|
#[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`
|
/// for `mcrxrx`
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn decode_mcrxrx(&mut self) {
|
fn decode_mcrxrx(&mut self) {
|
||||||
|
|
@ -2572,12 +2681,12 @@ const DECODE_FNS: &[(&[&str], DecodeFn)] = &[
|
||||||
// TODO(FP) -- mostly intentionally not implemented
|
// TODO(FP) -- mostly intentionally not implemented
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(&["mtspr", "mfspr", "mftb"], |state| {
|
||||||
&["mtspr", "mfspr", "mftb", "mtmsr", "mtmsrd", "mfmsr"],
|
DecodeState::decode_mtspr_mfspr_mftb(state)
|
||||||
|_state| {
|
}),
|
||||||
// TODO
|
(&["mtmsr", "mtmsrd", "mfmsr"], |_state| {
|
||||||
},
|
// TODO
|
||||||
),
|
}),
|
||||||
(&["mcrxrx"], |state| DecodeState::decode_mcrxrx(state)),
|
(&["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! {
|
mop_enum! {
|
||||||
#[impl_mop_into = true]
|
#[impl_mop_into = true]
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -2253,6 +2327,7 @@ mop_enum! {
|
||||||
CompareI(CompareMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
CompareI(CompareMOp<DestReg, SrcRegWidth, ConstUsize<1>>),
|
||||||
Branch(BranchMOp<DestReg, SrcRegWidth, ConstUsize<3>>),
|
Branch(BranchMOp<DestReg, SrcRegWidth, ConstUsize<3>>),
|
||||||
BranchI(BranchMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
|
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,
|
config::CpuConfig,
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOpDefaultImm,
|
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOpDefaultImm,
|
||||||
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, RenamedMOp,
|
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, ReadSpecialMOp,
|
||||||
ShiftRotateMOp, UnitOutRegNum,
|
RenamedMOp, ShiftRotateMOp, UnitOutRegNum,
|
||||||
},
|
},
|
||||||
register::{
|
register::{
|
||||||
FlagsMode, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, PRegFlagsX86,
|
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]
|
#[hdl_module]
|
||||||
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
#[hdl]
|
#[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,
|
&mut retval,
|
||||||
);
|
);
|
||||||
prefixed_no_operation::test_cases_book_i_3_3_20_prefixed_no_operation(&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
|
retval
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,15 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::test_cases::{TestCase, insn_single};
|
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::*;
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
/// covers instructions in PowerISA v3.1C Book I 3.3.19 Move To/From System Register Instructions
|
/// 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>) {
|
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]
|
#[hdl]
|
||||||
fn mcrxrx_imm() -> SimValue<LogicalFlagsMOpImm> {
|
fn mcrxrx_imm() -> SimValue<LogicalFlagsMOpImm> {
|
||||||
#[hdl(sim)]
|
#[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