forked from libre-chip/cpu
458 lines
12 KiB
Rust
458 lines
12 KiB
Rust
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
// See Notices.txt for copyright information
|
|
use crate::{instruction::MOpRegNum, util::range_u32_nth_or_panic};
|
|
use fayalite::prelude::*;
|
|
use std::ops::Range;
|
|
|
|
#[hdl(cmp_eq)]
|
|
pub struct PowerIsaRegNum {
|
|
pub value: UInt<5>,
|
|
}
|
|
|
|
#[hdl(cmp_eq)]
|
|
pub struct PowerIsaFRegNum {
|
|
pub value: UInt<5>,
|
|
}
|
|
|
|
#[hdl(cmp_eq)]
|
|
pub struct PowerIsaCrFieldNum {
|
|
pub value: UInt<3>,
|
|
}
|
|
|
|
#[hdl(cmp_eq)]
|
|
pub struct PowerIsaCrBitNum {
|
|
pub cr_field: PowerIsaCrFieldNum,
|
|
pub bit_in_field: UInt<2>,
|
|
}
|
|
|
|
impl MOpRegNum {
|
|
pub const POWER_ISA_LR_REG_NUM: u32 = 1;
|
|
#[hdl]
|
|
pub fn power_isa_lr_reg() -> Expr<Self> {
|
|
#[hdl]
|
|
Self {
|
|
value: Self::POWER_ISA_LR_REG_NUM.cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
pub const POWER_ISA_CTR_REG_NUM: u32 = 2;
|
|
#[hdl]
|
|
pub fn power_isa_ctr_reg() -> Expr<Self> {
|
|
#[hdl]
|
|
Self {
|
|
value: Self::POWER_ISA_CTR_REG_NUM.cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
pub const POWER_ISA_TAR_REG_NUM: u32 = 3;
|
|
#[hdl]
|
|
pub fn power_isa_tar_reg() -> Expr<Self> {
|
|
#[hdl]
|
|
Self {
|
|
value: Self::POWER_ISA_TAR_REG_NUM.cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
|
|
/// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`]
|
|
///
|
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
|
pub const POWER_ISA_XER_SO_OV_OV32_REG_NUM: u32 =
|
|
range_u32_nth_or_panic(&Self::FLAG_REG_NUMS, 0);
|
|
/// CA and CA32 XER bits -- in [`PRegValue.flags`]
|
|
///
|
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
|
pub const POWER_ISA_XER_CA_CA32_REG_NUM: u32 = 4;
|
|
/// only the XER bits that don't exist in [`PRegValue.flags`]
|
|
///
|
|
/// [`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
|
|
#[hdl]
|
|
pub fn power_isa_xer_so_ov_ov32_reg() -> Expr<Self> {
|
|
#[hdl]
|
|
Self {
|
|
value: Self::POWER_ISA_XER_SO_OV_OV32_REG_NUM.cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
/// CA and CA32 XER bits -- in [`PRegValue.flags`]
|
|
///
|
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
|
#[hdl]
|
|
pub fn power_isa_xer_ca_ca32_reg() -> Expr<Self> {
|
|
#[hdl]
|
|
Self {
|
|
value: Self::POWER_ISA_XER_CA_CA32_REG_NUM.cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
/// only the XER bits that don't exist in [`PRegValue.flags`]
|
|
///
|
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
|
#[hdl]
|
|
pub fn power_isa_xer_other_reg() -> Expr<Self> {
|
|
#[hdl]
|
|
Self {
|
|
value: Self::POWER_ISA_XER_OTHER_REG_NUM.cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
|
|
pub const POWER_ISA_CR_0_REG_NUM: u32 = range_u32_nth_or_panic(&Self::FLAG_REG_NUMS, 1);
|
|
pub const POWER_ISA_CR_1_THRU_7_REG_NUMS: Range<u32> = 9..16;
|
|
pub const fn power_isa_cr_reg_num(index: usize) -> u32 {
|
|
if index == 0 {
|
|
Self::POWER_ISA_CR_0_REG_NUM
|
|
} else {
|
|
range_u32_nth_or_panic(&Self::POWER_ISA_CR_1_THRU_7_REG_NUMS, index - 1)
|
|
}
|
|
}
|
|
#[hdl]
|
|
pub fn power_isa_cr_reg(field_num: Expr<UInt<3>>) -> Expr<Self> {
|
|
#[hdl]
|
|
let power_isa_cr_reg: Self = wire();
|
|
#[hdl]
|
|
if field_num.cmp_eq(0u8) {
|
|
connect_any(power_isa_cr_reg.value, Self::POWER_ISA_CR_0_REG_NUM);
|
|
} else {
|
|
connect_any(
|
|
power_isa_cr_reg.value,
|
|
Self::POWER_ISA_CR_1_THRU_7_REG_NUMS.start - 1 + field_num,
|
|
);
|
|
}
|
|
power_isa_cr_reg
|
|
}
|
|
#[hdl]
|
|
pub fn power_isa_cr_reg_imm(index: usize) -> Expr<Self> {
|
|
#[hdl]
|
|
Self {
|
|
value: Self::power_isa_cr_reg_num(index).cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
#[hdl]
|
|
pub fn power_isa_cr_reg_sim(field_num: &SimValue<UInt<3>>) -> SimValue<Self> {
|
|
#[hdl(sim)]
|
|
Self {
|
|
value: Self::power_isa_cr_reg_num(
|
|
field_num.cast_to_static::<UInt<8>>().as_int() as usize
|
|
)
|
|
.cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
|
|
pub const POWER_ISA_GPR_REG_NUMS: Range<u32> = 32..64;
|
|
pub const fn power_isa_gpr_reg_num(index: usize) -> u32 {
|
|
range_u32_nth_or_panic(&Self::POWER_ISA_GPR_REG_NUMS, index)
|
|
}
|
|
#[hdl]
|
|
pub fn power_isa_gpr_reg(reg_num: Expr<UInt<5>>) -> Expr<Self> {
|
|
#[hdl]
|
|
Self {
|
|
value: (Self::POWER_ISA_GPR_REG_NUMS.start + reg_num).cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
#[hdl]
|
|
pub fn power_isa_gpr_reg_imm(index: usize) -> Expr<Self> {
|
|
#[hdl]
|
|
Self {
|
|
value: Self::power_isa_gpr_reg_num(index).cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
#[hdl]
|
|
pub fn power_isa_gpr_reg_sim(reg_num: &SimValue<UInt<5>>) -> SimValue<Self> {
|
|
#[hdl(sim)]
|
|
Self {
|
|
value: (Self::POWER_ISA_GPR_REG_NUMS.start + reg_num).cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
pub const fn power_isa_gpr_or_zero_reg_num(index: usize) -> u32 {
|
|
if index == 0 {
|
|
Self::CONST_ZERO_REG_NUM
|
|
} else {
|
|
Self::power_isa_gpr_reg_num(index)
|
|
}
|
|
}
|
|
#[hdl]
|
|
pub fn power_isa_gpr_or_zero_reg(reg_num: Expr<UInt<5>>) -> Expr<Self> {
|
|
#[hdl]
|
|
let power_isa_gpr_or_zero_reg: Self = wire();
|
|
connect(power_isa_gpr_or_zero_reg, Self::power_isa_gpr_reg(reg_num));
|
|
#[hdl]
|
|
if reg_num.cmp_eq(0u8) {
|
|
connect(power_isa_gpr_or_zero_reg, Self::const_zero());
|
|
}
|
|
power_isa_gpr_or_zero_reg
|
|
}
|
|
#[hdl]
|
|
pub fn power_isa_gpr_or_zero_reg_sim(reg_num: &SimValue<UInt<5>>) -> SimValue<Self> {
|
|
#[hdl(sim)]
|
|
Self {
|
|
value: Self::power_isa_gpr_or_zero_reg_num(
|
|
reg_num.cast_to_static::<UInt<8>>().as_int() as usize,
|
|
)
|
|
.cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
|
|
pub const POWER_ISA_FPR_REG_NUMS: Range<u32> = 64..96;
|
|
pub const fn power_isa_fpr_reg_num(index: usize) -> u32 {
|
|
range_u32_nth_or_panic(&Self::POWER_ISA_FPR_REG_NUMS, index)
|
|
}
|
|
#[hdl]
|
|
pub fn power_isa_fpr_reg(reg_num: Expr<UInt<5>>) -> Expr<Self> {
|
|
#[hdl]
|
|
Self {
|
|
value: (Self::POWER_ISA_FPR_REG_NUMS.start + reg_num).cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
#[hdl]
|
|
pub fn power_isa_fpr_reg_sim(reg_num: &SimValue<UInt<5>>) -> SimValue<Self> {
|
|
#[hdl(sim)]
|
|
Self {
|
|
value: (Self::POWER_ISA_FPR_REG_NUMS.start + reg_num).cast_to_static::<UInt<_>>(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[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<_>>(),
|
|
}
|
|
}
|
|
}
|