forked from libre-chip/cpu
		
	WIP implementing reg_alloc
This commit is contained in:
		
							parent
							
								
									1a72425156
								
							
						
					
					
						commit
						b51109f4f6
					
				
					 4 changed files with 146 additions and 5 deletions
				
			
		|  | @ -5,12 +5,14 @@ use crate::{ | ||||||
|     unit::UnitKind, |     unit::UnitKind, | ||||||
| }; | }; | ||||||
| use fayalite::prelude::*; | use fayalite::prelude::*; | ||||||
|  | use std::num::NonZeroUsize; | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, Eq, PartialEq, Hash, Debug)] | #[derive(Clone, Eq, PartialEq, Hash, Debug)] | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| pub struct CpuConfig { | pub struct CpuConfig { | ||||||
|     pub unit_kinds: Vec<UnitKind>, |     pub unit_kinds: Vec<UnitKind>, | ||||||
|     pub out_reg_num_width: usize, |     pub out_reg_num_width: usize, | ||||||
|  |     pub fetch_width: NonZeroUsize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl CpuConfig { | impl CpuConfig { | ||||||
|  |  | ||||||
|  | @ -183,4 +183,5 @@ impl MOpRegNum { | ||||||
|     pub const CONST_ZERO_REG_NUM: u32 = 0; |     pub const CONST_ZERO_REG_NUM: u32 = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[hdl] | ||||||
| pub type MOp = UnitMOp<ConstUsize<{ MOpRegNum::WIDTH }>>; | pub type MOp = UnitMOp<ConstUsize<{ MOpRegNum::WIDTH }>>; | ||||||
|  |  | ||||||
|  | @ -1,11 +1,128 @@ | ||||||
| // SPDX-License-Identifier: LGPL-3.0-or-later
 | // SPDX-License-Identifier: LGPL-3.0-or-later
 | ||||||
| // See Notices.txt for copyright information
 | // See Notices.txt for copyright information
 | ||||||
| use crate::config::CpuConfig; | use crate::{ | ||||||
| use fayalite::prelude::*; |     config::CpuConfig, | ||||||
|  |     instruction::{MOp, UnitNum}, | ||||||
|  |     unit::{TrapData, UnitTrait}, | ||||||
|  |     util::tree_reduce::{tree_reduce, tree_reduce_with_state}, | ||||||
|  | }; | ||||||
|  | use fayalite::{module::instance_with_loc, prelude::*, util::ready_valid::ReadyValid}; | ||||||
|  | use std::num::NonZeroUsize; | ||||||
| 
 | 
 | ||||||
| pub mod unit_free_regs_tracker; | pub mod unit_free_regs_tracker; | ||||||
| 
 | 
 | ||||||
| #[hdl_module] | #[hdl] | ||||||
| pub fn reg_alloc(config: CpuConfig) { | pub struct FetchedDecodedMOp { | ||||||
|     todo!() |     pub uop: MOp, | ||||||
|  |     /// true if pc doesn't have to be related to the previous instruction.
 | ||||||
|  |     /// (enable to stop detecting when the current instruction isn't
 | ||||||
|  |     /// supposed to be run next, e.g. on branch mis-prediction)
 | ||||||
|  |     pub is_unrelated_pc: Bool, | ||||||
|  |     pub pc: UInt<64>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[hdl] | ||||||
|  | pub enum FetchDecodeSpecialOp { | ||||||
|  |     Trap(TrapData), | ||||||
|  |     ICacheFlush, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[hdl] | ||||||
|  | pub struct FetchDecodeInterface<FetchWidth: Size> { | ||||||
|  |     pub decoded_insns: ArrayType<ReadyValid<FetchedDecodedMOp>, FetchWidth>, | ||||||
|  |     #[hdl(flip)] | ||||||
|  |     pub fetch_decode_special_op: ReadyValid<FetchDecodeSpecialOp>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[hdl_module] | ||||||
|  | /// combination register allocator, register renaming, unit selection, and retire handling
 | ||||||
|  | pub fn reg_alloc(config: &CpuConfig) { | ||||||
|  |     #[hdl] | ||||||
|  |     let cd: ClockDomain = m.input(); | ||||||
|  |     #[hdl] | ||||||
|  |     let fetch_decode_interface: FetchDecodeInterface<DynSize> = | ||||||
|  |         m.input(FetchDecodeInterface[config.fetch_width.get()]); | ||||||
|  |     // TODO: propagate traps, branch mis-predictions, and special ops
 | ||||||
|  |     connect( | ||||||
|  |         fetch_decode_interface.fetch_decode_special_op.data, | ||||||
|  |         HdlNone(), | ||||||
|  |     ); | ||||||
|  |     // TODO: finish
 | ||||||
|  |     #[hdl] | ||||||
|  |     let available_units = | ||||||
|  |         wire(Array[Array[Bool][config.unit_kinds.len()]][config.fetch_width.get()]); | ||||||
|  |     #[hdl] | ||||||
|  |     let selected_unit_nums = wire(Array[HdlOption[config.unit_num()]][config.fetch_width.get()]); | ||||||
|  |     for fetch_index in 0..config.fetch_width.get() { | ||||||
|  |         connect( | ||||||
|  |             fetch_decode_interface.decoded_insns[fetch_index].ready, | ||||||
|  |             true, | ||||||
|  |         ); | ||||||
|  |         connect( | ||||||
|  |             available_units[fetch_index], | ||||||
|  |             repeat(false, config.unit_kinds.len()), | ||||||
|  |         ); | ||||||
|  |         #[hdl] | ||||||
|  |         if let HdlSome(decoded_insn) = fetch_decode_interface.decoded_insns[fetch_index].data { | ||||||
|  |             connect( | ||||||
|  |                 available_units[fetch_index], | ||||||
|  |                 config.available_units_for_kind(MOp::kind(decoded_insn.uop)), | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         connect( | ||||||
|  |             selected_unit_nums[fetch_index], | ||||||
|  |             tree_reduce_with_state( | ||||||
|  |                 0..config.unit_kinds.len(), | ||||||
|  |                 &mut (), | ||||||
|  |                 |_state, unit_index| { | ||||||
|  |                     #[hdl] | ||||||
|  |                     let selected_unit_leaf = wire(HdlOption[config.unit_num()]); | ||||||
|  |                     connect(selected_unit_leaf, HdlOption[config.unit_num()].HdlNone()); | ||||||
|  |                     #[hdl] | ||||||
|  |                     let unit_num = wire(config.unit_num()); | ||||||
|  |                     connect_any(unit_num.value, unit_index); | ||||||
|  |                     #[hdl] | ||||||
|  |                     if available_units[fetch_index][unit_index] { | ||||||
|  |                         connect(selected_unit_leaf, HdlSome(unit_num)) | ||||||
|  |                     } | ||||||
|  |                     selected_unit_leaf | ||||||
|  |                 }, | ||||||
|  |                 |_state, l, r| { | ||||||
|  |                     #[hdl] | ||||||
|  |                     let selected_unit_node = wire(Expr::ty(l)); | ||||||
|  |                     connect(selected_unit_node, l); | ||||||
|  |                     #[hdl] | ||||||
|  |                     if let HdlNone = l { | ||||||
|  |                         connect(selected_unit_node, r); | ||||||
|  |                     } | ||||||
|  |                     selected_unit_node | ||||||
|  |                 }, | ||||||
|  |             ) | ||||||
|  |             .expect("expected at least one unit"), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     for (unit_index, &unit_kind) in config.unit_kinds.iter().enumerate() { | ||||||
|  |         let dyn_unit = unit_kind.unit(config); | ||||||
|  |         let unit = instance_with_loc( | ||||||
|  |             &format!("unit_{unit_index}"), | ||||||
|  |             dyn_unit.make_module(), | ||||||
|  |             SourceLocation::caller(), | ||||||
|  |         ); | ||||||
|  |         connect(dyn_unit.cd(unit), cd); | ||||||
|  |         // TODO: handle assigning multiple instructions to a unit at a time
 | ||||||
|  |         let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap(); | ||||||
|  |         // TODO: handle retiring multiple instructions from a unit at a time
 | ||||||
|  |         let retire_from_unit_at_once = NonZeroUsize::new(1).unwrap(); | ||||||
|  |         let unit_free_regs_tracker = instance_with_loc( | ||||||
|  |             &format!("unit_{unit_index}_free_regs_tracker"), | ||||||
|  |             unit_free_regs_tracker::unit_free_regs_tracker( | ||||||
|  |                 retire_from_unit_at_once, | ||||||
|  |                 assign_to_unit_at_once, | ||||||
|  |                 config.out_reg_num_width, | ||||||
|  |             ), | ||||||
|  |             SourceLocation::caller(), | ||||||
|  |         ); | ||||||
|  |         connect(unit_free_regs_tracker.cd, cd); | ||||||
|  |         // TODO: finish
 | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ macro_rules! all_units { | ||||||
|         $(#[$enum_meta:meta])* |         $(#[$enum_meta:meta])* | ||||||
|         $vis:vis enum $UnitMOpEnum:ident<$RegWidth:ident: Size> { |         $vis:vis enum $UnitMOpEnum:ident<$RegWidth:ident: Size> { | ||||||
|             $( |             $( | ||||||
|  |                 #[create_dyn_unit_fn = $create_dyn_unit_fn:expr] | ||||||
|                 $(#[$variant_meta:meta])* |                 $(#[$variant_meta:meta])* | ||||||
|                 $Unit:ident($Op:ty), |                 $Unit:ident($Op:ty), | ||||||
|             )* |             )* | ||||||
|  | @ -35,6 +36,14 @@ macro_rules! all_units { | ||||||
|             )* |             )* | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         impl $UnitKind { | ||||||
|  |             pub fn unit(self, config: &CpuConfig) -> DynUnit { | ||||||
|  |                 match self { | ||||||
|  |                     $($UnitKind::$Unit => $create_dyn_unit_fn(config),)* | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         impl ToExpr for $UnitKind { |         impl ToExpr for $UnitKind { | ||||||
|             type Type = $HdlUnitKind; |             type Type = $HdlUnitKind; | ||||||
| 
 | 
 | ||||||
|  | @ -98,8 +107,11 @@ all_units! { | ||||||
|     #[unit_kind = UnitKind] |     #[unit_kind = UnitKind] | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     pub enum UnitMOp<RegWidth: Size> { |     pub enum UnitMOp<RegWidth: Size> { | ||||||
|  |         #[create_dyn_unit_fn = |config| todo!()] | ||||||
|         AluBranch(AluBranchMOp<RegWidth>), |         AluBranch(AluBranchMOp<RegWidth>), | ||||||
|  |         #[create_dyn_unit_fn = |config| todo!()] | ||||||
|         L2RegisterFile(L2RegisterFileMOp<RegWidth>), |         L2RegisterFile(L2RegisterFileMOp<RegWidth>), | ||||||
|  |         #[create_dyn_unit_fn = |config| todo!()] | ||||||
|         LoadStore(LoadStoreMOp<RegWidth>), |         LoadStore(LoadStoreMOp<RegWidth>), | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -156,6 +168,7 @@ pub trait UnitTrait: | ||||||
|         &self, |         &self, | ||||||
|         this: Expr<Self::Type>, |         this: Expr<Self::Type>, | ||||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>>; |     ) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>>; | ||||||
|  |     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>; | ||||||
| 
 | 
 | ||||||
|     fn to_dyn(&self) -> DynUnit; |     fn to_dyn(&self) -> DynUnit; | ||||||
| } | } | ||||||
|  | @ -217,6 +230,10 @@ impl UnitTrait for DynUnit { | ||||||
|         self.unit.output(this) |         self.unit.output(this) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> { | ||||||
|  |         self.unit.cd(this) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fn to_dyn(&self) -> DynUnit { |     fn to_dyn(&self) -> DynUnit { | ||||||
|         *self |         *self | ||||||
|     } |     } | ||||||
|  | @ -264,6 +281,10 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T | ||||||
|         Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this)))) |         Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this)))) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> { | ||||||
|  |         self.0.cd(Expr::from_bundle(this)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fn to_dyn(&self) -> DynUnit { |     fn to_dyn(&self) -> DynUnit { | ||||||
|         let unit = self.intern(); |         let unit = self.intern(); | ||||||
|         DynUnit { |         DynUnit { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue