add more register stuff
This commit is contained in:
parent
1a44fcc609
commit
f65fc1d616
|
@ -1,14 +1,21 @@
|
||||||
use crate::instruction::{UnitKind, UnitNum};
|
use crate::instruction::{PRegNum, UnitKind, UnitNum};
|
||||||
use fayalite::prelude::*;
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct CpuConfig {
|
pub struct CpuConfig {
|
||||||
pub units: Vec<UnitKind>,
|
pub units: Vec<UnitKind>,
|
||||||
|
pub out_reg_num_width: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CpuConfig {
|
impl CpuConfig {
|
||||||
|
pub fn unit_num_width(&self) -> usize {
|
||||||
|
UInt::range(0..self.units.len()).width()
|
||||||
|
}
|
||||||
pub fn unit_num(&self) -> UnitNum<DynSize> {
|
pub fn unit_num(&self) -> UnitNum<DynSize> {
|
||||||
UnitNum[UInt::range(0..self.units.len()).width()]
|
UnitNum[self.unit_num_width()]
|
||||||
|
}
|
||||||
|
pub fn p_reg_num(&self) -> PRegNum<DynSize, DynSize> {
|
||||||
|
PRegNum[self.unit_num_width()][self.out_reg_num_width]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,11 +255,18 @@ pub struct PRegNum<UnitNumWidth: Size, OutRegNumWidth: Size> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
/// µOp Register Number -- register in a micro-operation
|
/// µOp Register Number -- register in a micro-operation before register renaming
|
||||||
#[doc(alias = "UOpRegNum")] // help you find it in the docs if you mis-spell it
|
#[doc(alias = "UOpRegNum")] // help you find it in the docs if you mis-spell it
|
||||||
#[doc(alias = "\u{B5}OpRegNum")] // micro sign
|
#[doc(alias = "\u{B5}OpRegNum")] // micro sign
|
||||||
#[doc(alias = "\u{39C}OpRegNum")] // greek capital letter mu
|
#[doc(alias = "\u{39C}OpRegNum")] // greek capital letter mu
|
||||||
#[doc(alias = "\u{3BC}OpRegNum")] // greek small letter mu
|
#[doc(alias = "\u{3BC}OpRegNum")] // greek small letter mu
|
||||||
pub struct MOpRegNum {
|
pub struct MOpRegNum {
|
||||||
pub value: UInt<8>,
|
pub value: UInt<{ MOpRegNum::WIDTH }>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MOpRegNum {
|
||||||
|
pub const WIDTH: usize = 8;
|
||||||
|
pub const CONST_ZERO_REG_NUM: u32 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type MOp = UnitMOp<ConstUsize<{ MOpRegNum::WIDTH }>>;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
use crate::{instruction::MOpRegNum, util::range_u32_nth_or_panic};
|
||||||
use fayalite::prelude::*;
|
use fayalite::prelude::*;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub struct PowerIsaRegNum {
|
pub struct PowerIsaRegNum {
|
||||||
|
@ -20,3 +22,29 @@ pub struct PowerIsaCrBitNum {
|
||||||
pub cr_field: PowerIsaCrFieldNum,
|
pub cr_field: PowerIsaCrFieldNum,
|
||||||
pub bit_in_field: UInt<2>,
|
pub bit_in_field: UInt<2>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MOpRegNum {
|
||||||
|
pub const POWER_ISA_LR_REG_NUM: u32 = 1;
|
||||||
|
pub const POWER_ISA_CTR_REG_NUM: u32 = 2;
|
||||||
|
pub const POWER_ISA_TAR_REG_NUM: u32 = 3;
|
||||||
|
/// XER bits are stored in [`PRegValue.flags`], bits that don't exist in [`PRegValue.flags`] are stored in [`PRegValue.int_fp`]
|
||||||
|
///
|
||||||
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||||
|
/// [`PRegValue.int_fp`]: struct@crate::register::PRegValue
|
||||||
|
pub const POWER_ISA_XER_REG_NUM: u32 = 4;
|
||||||
|
|
||||||
|
pub const POWER_ISA_CR_REG_NUMS: Range<u32> = 8..16;
|
||||||
|
pub const fn power_isa_cr_reg_num(index: usize) -> u32 {
|
||||||
|
range_u32_nth_or_panic(&Self::POWER_ISA_CR_REG_NUMS, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
|
pub mod register;
|
||||||
|
pub mod util;
|
||||||
|
|
148
crates/cpu/src/register.rs
Normal file
148
crates/cpu/src/register.rs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub enum FlagsMode {
|
||||||
|
PowerISA(PRegFlagsPowerISA),
|
||||||
|
X86(PRegFlagsX86),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub struct PRegFlagsPowerISA {}
|
||||||
|
|
||||||
|
impl PRegFlagsPowerISA {
|
||||||
|
pub fn xer_ca(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_ca_x86_cf
|
||||||
|
}
|
||||||
|
pub fn xer_ca32(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_ca32_x86_af
|
||||||
|
}
|
||||||
|
pub fn xer_ov(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_ov_x86_of
|
||||||
|
}
|
||||||
|
pub fn xer_ov32(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_ov32_x86_df
|
||||||
|
}
|
||||||
|
/// both `CR<N>.SO` and `XER.SO` since instructions that write to both always write the same value
|
||||||
|
pub fn so(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_so
|
||||||
|
}
|
||||||
|
pub fn cr_lt(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_cr_lt_x86_sf
|
||||||
|
}
|
||||||
|
pub fn cr_gt(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_cr_gt_x86_pf
|
||||||
|
}
|
||||||
|
pub fn cr_eq(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_cr_eq_x86_zf
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn clear_unused(flags: impl ToExpr<Type = PRegFlags>) {
|
||||||
|
#[hdl]
|
||||||
|
match flags {
|
||||||
|
// list all flags explicitly so we don't miss handling any new flags
|
||||||
|
PRegFlags {
|
||||||
|
pwr_ca_x86_cf: _,
|
||||||
|
pwr_ca32_x86_af: _,
|
||||||
|
pwr_ov_x86_of: _,
|
||||||
|
pwr_ov32_x86_df: _,
|
||||||
|
pwr_cr_lt_x86_sf: _,
|
||||||
|
pwr_cr_gt_x86_pf: _,
|
||||||
|
pwr_cr_eq_x86_zf: _,
|
||||||
|
pwr_so: _,
|
||||||
|
} => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub struct PRegFlagsX86 {}
|
||||||
|
|
||||||
|
impl PRegFlagsX86 {
|
||||||
|
pub fn cf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_ca_x86_cf
|
||||||
|
}
|
||||||
|
pub fn zf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_cr_eq_x86_zf
|
||||||
|
}
|
||||||
|
pub fn sf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_cr_lt_x86_sf
|
||||||
|
}
|
||||||
|
pub fn of(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_ov_x86_of
|
||||||
|
}
|
||||||
|
pub fn af(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_ca32_x86_af
|
||||||
|
}
|
||||||
|
pub fn pf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_cr_gt_x86_pf
|
||||||
|
}
|
||||||
|
pub fn df(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
flags.to_expr().pwr_ov32_x86_df
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn clear_unused(flags: impl ToExpr<Type = PRegFlags>) {
|
||||||
|
#[hdl]
|
||||||
|
match flags {
|
||||||
|
// list all flags explicitly so we don't miss handling any new flags
|
||||||
|
PRegFlags {
|
||||||
|
pwr_ca_x86_cf: _,
|
||||||
|
pwr_ca32_x86_af: _,
|
||||||
|
pwr_ov_x86_of: _,
|
||||||
|
pwr_ov32_x86_df: _,
|
||||||
|
pwr_cr_lt_x86_sf: _,
|
||||||
|
pwr_cr_gt_x86_pf: _,
|
||||||
|
pwr_cr_eq_x86_zf: _,
|
||||||
|
pwr_so: unused1,
|
||||||
|
} => connect(unused1, false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
/// this is *not* the same as any particular ISA's flags register,
|
||||||
|
/// on PowerISA it is a combination of some bits from XER with a single 4-bit CR field.
|
||||||
|
///
|
||||||
|
/// Accessor functions depend on the ISA:
|
||||||
|
///
|
||||||
|
/// * PowerISA: [`struct@PRegFlagsPowerISA`]
|
||||||
|
/// * x86: [`struct@PRegFlagsX86`]
|
||||||
|
pub struct PRegFlags {
|
||||||
|
pwr_ca_x86_cf: Bool,
|
||||||
|
pwr_ca32_x86_af: Bool,
|
||||||
|
pwr_ov_x86_of: Bool,
|
||||||
|
pwr_ov32_x86_df: Bool,
|
||||||
|
pwr_cr_lt_x86_sf: Bool,
|
||||||
|
pwr_cr_gt_x86_pf: Bool,
|
||||||
|
pwr_cr_eq_x86_zf: Bool,
|
||||||
|
pwr_so: Bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PRegFlags {
|
||||||
|
/// if trying to set all fields individually, prefer using the individual accessor
|
||||||
|
/// functions and [`PRegFlagsPowerISA::clear_unused()`]/[`PRegFlagsX86::clear_unused()`]/etc.
|
||||||
|
#[hdl]
|
||||||
|
pub fn zeroed() -> Expr<PRegFlags> {
|
||||||
|
#[hdl]
|
||||||
|
PRegFlags {
|
||||||
|
pwr_ca_x86_cf: false,
|
||||||
|
pwr_ca32_x86_af: false,
|
||||||
|
pwr_ov_x86_of: false,
|
||||||
|
pwr_ov32_x86_df: false,
|
||||||
|
pwr_cr_lt_x86_sf: false,
|
||||||
|
pwr_cr_gt_x86_pf: false,
|
||||||
|
pwr_cr_eq_x86_zf: false,
|
||||||
|
pwr_so: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
/// Unit output register's value -- a combination of an integer/fp register
|
||||||
|
/// and flags register and CR field.
|
||||||
|
///
|
||||||
|
/// Register Renaming will independently rename the ISA-level integer/fp
|
||||||
|
/// register, flags, and CR field portions.
|
||||||
|
pub struct PRegValue {
|
||||||
|
pub int_fp: UInt<64>,
|
||||||
|
pub flags: PRegFlags,
|
||||||
|
}
|
21
crates/cpu/src/util.rs
Normal file
21
crates/cpu/src/util.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
pub(crate) const fn range_u32_len(range: &std::ops::Range<u32>) -> usize {
|
||||||
|
let retval = range.end.saturating_sub(range.start);
|
||||||
|
assert!(retval as usize as u32 != retval, "len overflowed");
|
||||||
|
retval as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const fn range_u32_nth(range: &std::ops::Range<u32>, index: usize) -> Option<u32> {
|
||||||
|
if index < range_u32_len(range) {
|
||||||
|
Some(range.start + index as u32)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const fn range_u32_nth_or_panic(range: &std::ops::Range<u32>, index: usize) -> u32 {
|
||||||
|
if let Some(retval) = range_u32_nth(range, index) {
|
||||||
|
retval
|
||||||
|
} else {
|
||||||
|
panic!("index out of range")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue