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::*; | 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue