forked from libre-chip/cpu
		
	start adding ROB
This commit is contained in:
		
							parent
							
								
									4ff75313e7
								
							
						
					
					
						commit
						6c91d1b0b0
					
				
					 4 changed files with 32643 additions and 30962 deletions
				
			
		|  | @ -35,6 +35,7 @@ pub struct CpuConfig { | |||
|     pub fetch_width: NonZeroUsize, | ||||
|     /// default value for [`UnitConfig::max_in_flight`]
 | ||||
|     pub default_unit_max_in_flight: NonZeroUsize, | ||||
|     pub rob_size: NonZeroUsize, | ||||
| } | ||||
| 
 | ||||
| impl CpuConfig { | ||||
|  | @ -51,12 +52,13 @@ impl CpuConfig { | |||
|         }; | ||||
|         v | ||||
|     }; | ||||
|     pub fn new(units: Vec<UnitConfig>) -> Self { | ||||
|     pub fn new(units: Vec<UnitConfig>, rob_size: NonZeroUsize) -> Self { | ||||
|         Self { | ||||
|             units, | ||||
|             out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH, | ||||
|             fetch_width: Self::DEFAULT_FETCH_WIDTH, | ||||
|             default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT, | ||||
|             rob_size, | ||||
|         } | ||||
|     } | ||||
|     pub fn non_const_unit_nums(&self) -> std::ops::Range<usize> { | ||||
|  |  | |||
|  | @ -7,8 +7,9 @@ use crate::{ | |||
|         COMMON_MOP_SRC_LEN, | ||||
|     }, | ||||
|     unit::{ | ||||
|         unit_base::UnitInput, GlobalState, TrapData, UnitOutput, UnitOutputWrite, UnitResult, | ||||
|         UnitResultCompleted, UnitTrait, | ||||
|         unit_base::{UnitForwardingInfo, UnitInput}, | ||||
|         GlobalState, TrapData, UnitOutput, UnitOutputWrite, UnitResult, UnitResultCompleted, | ||||
|         UnitTrait, | ||||
|     }, | ||||
|     util::tree_reduce::tree_reduce_with_state, | ||||
| }; | ||||
|  | @ -48,6 +49,145 @@ pub struct FetchDecodeInterface<FetchWidth: Size> { | |||
|     pub fetch_decode_special_op: ReadyValid<FetchDecodeSpecialOp>, | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| struct ROBRenamedInsn<UnitNumWidth: Size, OutRegNumWidth: Size> { | ||||
|     mop_dest: MOpDestReg, | ||||
|     p_dest: PRegNum<UnitNumWidth, OutRegNumWidth>, | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| struct ROBEntry<UnitNumWidth: Size, OutRegNumWidth: Size> { | ||||
|     renamed_insn: ROBRenamedInsn<UnitNumWidth, OutRegNumWidth>, | ||||
|     dest_written: Bool, | ||||
| } | ||||
| 
 | ||||
| #[hdl_module] | ||||
| fn rob(config: &CpuConfig) { | ||||
|     #[hdl] | ||||
|     let cd: ClockDomain = m.input(); | ||||
|     #[hdl] | ||||
|     let renamed_insns_in: Array<ReadyValid<ROBRenamedInsn<DynSize, DynSize>>> = m.input( | ||||
|         Array[ReadyValid[ROBRenamedInsn[config.unit_num_width()][config.out_reg_num_width]]] | ||||
|             [config.fetch_width.get()], | ||||
|     ); | ||||
|     #[hdl] | ||||
|     let unit_forwarding_info: UnitForwardingInfo<DynSize, DynSize, DynSize> = | ||||
|         m.input(config.unit_forwarding_info()); | ||||
| 
 | ||||
|     let rob_entry_ty = ROBEntry[config.unit_num_width()][config.out_reg_num_width]; | ||||
|     #[hdl] | ||||
|     let rob = reg_builder() | ||||
|         .clock_domain(cd) | ||||
|         .no_reset(Array[rob_entry_ty][config.rob_size.get()]); | ||||
|     #[hdl] | ||||
|     let rob_valid_start = reg_builder() | ||||
|         .clock_domain(cd) | ||||
|         .reset(UInt::range(0..config.rob_size.get()).zero()); | ||||
|     #[hdl] | ||||
|     let rob_valid_end = reg_builder() | ||||
|         .clock_domain(cd) | ||||
|         .reset(UInt::range(0..config.rob_size.get()).zero()); | ||||
|     #[hdl] | ||||
|     let free_space = wire(UInt::range_inclusive(0..=config.rob_size.get())); | ||||
|     #[hdl] | ||||
|     if rob_valid_end.cmp_lt(rob_valid_start) { | ||||
|         // rob_valid_end wrapped around but start didn't
 | ||||
|         connect_any( | ||||
|             free_space, | ||||
|             rob_valid_end + config.rob_size.get() - rob_valid_start, | ||||
|         ); | ||||
|     } else { | ||||
|         connect_any(free_space, rob_valid_end - rob_valid_start); | ||||
|     } | ||||
| 
 | ||||
|     struct IndexAndRange { | ||||
|         index: Expr<UInt>, | ||||
|         range: std::ops::Range<usize>, | ||||
|     } | ||||
| 
 | ||||
|     let mut next_write_index = IndexAndRange { | ||||
|         index: rob_valid_end, | ||||
|         range: 0..config.rob_size.get(), | ||||
|     }; | ||||
|     for fetch_index in 0..config.fetch_width.get() { | ||||
|         let write_index = next_write_index; | ||||
|         let next_write_index_range = write_index.range.start..write_index.range.end + 1; | ||||
|         next_write_index = IndexAndRange { | ||||
|             index: wire_with_loc( | ||||
|                 &format!("next_write_index_{fetch_index}"), | ||||
|                 SourceLocation::caller(), | ||||
|                 UInt::range(next_write_index_range.clone()), | ||||
|             ), | ||||
|             range: next_write_index_range, | ||||
|         }; | ||||
|         connect( | ||||
|             renamed_insns_in[fetch_index].ready, | ||||
|             fetch_index.cmp_lt(free_space), | ||||
|         ); | ||||
|         #[hdl] | ||||
|         if let HdlSome(renamed_insn) = ReadyValid::firing_data(renamed_insns_in[fetch_index]) { | ||||
|             for i in write_index.range.clone() { | ||||
|                 #[hdl] | ||||
|                 if write_index.index.cmp_eq(i) { | ||||
|                     connect( | ||||
|                         rob[i % config.rob_size.get()], | ||||
|                         #[hdl] | ||||
|                         ROBEntry { | ||||
|                             renamed_insn, | ||||
|                             dest_written: false, | ||||
|                         }, | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         // TODO: optimize write_index chain better
 | ||||
|         connect_any( | ||||
|             next_write_index.index, | ||||
|             write_index.index | ||||
|                 + ReadyValid::firing(renamed_insns_in[fetch_index]).cast_to_static::<UInt<1>>(), | ||||
|         ); | ||||
|     } | ||||
|     assert!( | ||||
|         config.rob_size >= config.fetch_width, | ||||
|         "rob_size ({}) is too small for fetch_width = {} -- next_write_index would overflow", | ||||
|         config.rob_size, | ||||
|         config.fetch_width, | ||||
|     ); | ||||
|     #[hdl] | ||||
|     if next_write_index.index.cmp_lt(config.rob_size.get()) { | ||||
|         connect_any(rob_valid_end, next_write_index.index); | ||||
|     } else { | ||||
|         connect_any( | ||||
|             rob_valid_end, | ||||
|             next_write_index.index - config.rob_size.get(), | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     // TODO: optimize better, O(rob_size * unit_count) is too big here
 | ||||
|     for rob_index in 0..config.rob_size.get() { | ||||
|         for unit_index in 0..config.non_const_unit_nums().len() { | ||||
|             #[hdl] | ||||
|             if let HdlSome(unit_output_write) = unit_forwarding_info.unit_output_writes[unit_index] | ||||
|             { | ||||
|                 #[hdl] | ||||
|                 let UnitOutputWrite::<_> { | ||||
|                     which: unit_out_reg, | ||||
|                     value: _, | ||||
|                 } = unit_output_write; | ||||
|                 let p_reg_num = #[hdl] | ||||
|                 PRegNum::<_, _> { | ||||
|                     unit_num: config.unit_num().from_index(unit_index), | ||||
|                     unit_out_reg, | ||||
|                 }; | ||||
|                 #[hdl] | ||||
|                 if rob[rob_index].renamed_insn.p_dest.cmp_eq(p_reg_num) { | ||||
|                     connect(rob[rob_index].dest_written, true); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[hdl_module] | ||||
| /// combination register allocator, register renaming, unit selection, and retire handling
 | ||||
| pub fn reg_alloc(config: &CpuConfig) { | ||||
|  | @ -65,6 +205,10 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|     ); | ||||
|     // TODO: finish
 | ||||
| 
 | ||||
|     #[hdl] | ||||
|     let rob = instance(rob(config)); | ||||
|     connect(rob.cd, cd); | ||||
| 
 | ||||
|     let mut rename_table_mems = BTreeMap::<RenameTableName, MemBuilder<_>>::new(); | ||||
| 
 | ||||
|     for reg_kind in MOpDestReg::REG_KINDS { | ||||
|  | @ -94,10 +238,25 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|     #[hdl] | ||||
|     let renamed_mops_out_reg = wire(Array[HdlOption[config.p_reg_num()]][config.fetch_width.get()]); | ||||
|     for fetch_index in 0..config.fetch_width.get() { | ||||
|         // TODO: finish
 | ||||
|         connect( | ||||
|             rob.renamed_insns_in[fetch_index].data, | ||||
|             Expr::ty(rob).renamed_insns_in.element().data.HdlNone(), | ||||
|         ); | ||||
|         // TODO: finish
 | ||||
|         connect( | ||||
|             fetch_decode_interface.decoded_insns[fetch_index].ready, | ||||
|             true, | ||||
|         ); | ||||
|         for prev_fetch_index in 0..fetch_index { | ||||
|             #[hdl] | ||||
|             if !fetch_decode_interface.decoded_insns[prev_fetch_index].ready { | ||||
|                 connect( | ||||
|                     fetch_decode_interface.decoded_insns[fetch_index].ready, | ||||
|                     false, | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|         connect( | ||||
|             available_units[fetch_index], | ||||
|             repeat(false, config.units.len()), | ||||
|  | @ -316,6 +475,7 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|     ); | ||||
|     #[hdl] | ||||
|     let unit_forwarding_info = wire(config.unit_forwarding_info()); | ||||
|     connect(rob.unit_forwarding_info, unit_forwarding_info); | ||||
|     for (unit_index, unit_config) in config.units.iter().enumerate() { | ||||
|         let dyn_unit = unit_config.kind.unit(config, unit_index); | ||||
|         let unit = instance_with_loc( | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -21,10 +21,13 @@ use std::num::NonZeroUsize; | |||
| #[test] | ||||
| fn test_reg_alloc() { | ||||
|     let _n = SourceLocation::normalize_files_for_tests(); | ||||
|     let mut config = CpuConfig::new(vec![ | ||||
|         UnitConfig::new(UnitKind::AluBranch), | ||||
|         UnitConfig::new(UnitKind::AluBranch), | ||||
|     ]); | ||||
|     let mut config = CpuConfig::new( | ||||
|         vec![ | ||||
|             UnitConfig::new(UnitKind::AluBranch), | ||||
|             UnitConfig::new(UnitKind::AluBranch), | ||||
|         ], | ||||
|         NonZeroUsize::new(20).unwrap(), | ||||
|     ); | ||||
|     config.fetch_width = NonZeroUsize::new(2).unwrap(); | ||||
|     let m = reg_alloc(&config); | ||||
|     let mut sim = Simulation::new(m); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue