forked from libre-chip/cpu
		
	add more register stuff
This commit is contained in:
		
							parent
							
								
									1a44fcc609
								
							
						
					
					
						commit
						f65fc1d616
					
				
					 6 changed files with 217 additions and 4 deletions
				
			
		| 
						 | 
				
			
			@ -1,14 +1,21 @@
 | 
			
		|||
use crate::instruction::{UnitKind, UnitNum};
 | 
			
		||||
use crate::instruction::{PRegNum, UnitKind, UnitNum};
 | 
			
		||||
use fayalite::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
 | 
			
		||||
#[non_exhaustive]
 | 
			
		||||
pub struct CpuConfig {
 | 
			
		||||
    pub units: Vec<UnitKind>,
 | 
			
		||||
    pub out_reg_num_width: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CpuConfig {
 | 
			
		||||
    pub fn unit_num_width(&self) -> usize {
 | 
			
		||||
        UInt::range(0..self.units.len()).width()
 | 
			
		||||
    }
 | 
			
		||||
    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]
 | 
			
		||||
/// µ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 = "\u{B5}OpRegNum")] // micro sign
 | 
			
		||||
#[doc(alias = "\u{39C}OpRegNum")] // greek capital letter mu
 | 
			
		||||
#[doc(alias = "\u{3BC}OpRegNum")] // greek small letter mu
 | 
			
		||||
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 std::ops::Range;
 | 
			
		||||
 | 
			
		||||
#[hdl]
 | 
			
		||||
pub struct PowerIsaRegNum {
 | 
			
		||||
| 
						 | 
				
			
			@ -20,3 +22,29 @@ pub struct PowerIsaCrBitNum {
 | 
			
		|||
    pub cr_field: PowerIsaCrFieldNum,
 | 
			
		||||
    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 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue