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