reg_alloc: add writes to rename table
This commit is contained in:
		
							parent
							
								
									64566f718f
								
							
						
					
					
						commit
						1084278f34
					
				
					 4 changed files with 10856 additions and 8375 deletions
				
			
		|  | @ -2,7 +2,7 @@ | ||||||
| // See Notices.txt for copyright information
 | // See Notices.txt for copyright information
 | ||||||
| use crate::{unit::UnitMOp, util::range_u32_len}; | use crate::{unit::UnitMOp, util::range_u32_len}; | ||||||
| use fayalite::{expr::ops::ArrayLiteral, intern::Interned, prelude::*}; | use fayalite::{expr::ops::ArrayLiteral, intern::Interned, prelude::*}; | ||||||
| use std::{marker::PhantomData, ops::Range}; | use std::{fmt, marker::PhantomData, ops::Range}; | ||||||
| 
 | 
 | ||||||
| pub mod power_isa; | pub mod power_isa; | ||||||
| 
 | 
 | ||||||
|  | @ -668,6 +668,29 @@ pub struct MOpDestReg { | ||||||
|     pub flag_regs: Array<HdlOption<()>, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>, |     pub flag_regs: Array<HdlOption<()>, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] | ||||||
|  | pub enum RenameTableName { | ||||||
|  |     /// the large rename table for normal registers (has less read/write ports)
 | ||||||
|  |     Normal, | ||||||
|  |     /// a special small rename table (for flags and stuff, since it has more read/write ports)
 | ||||||
|  |     Special, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl RenameTableName { | ||||||
|  |     pub const fn reg_range(self) -> std::ops::Range<u32> { | ||||||
|  |         match self { | ||||||
|  |             Self::Normal => MOpRegNum::NORMAL_REG_NUMS, | ||||||
|  |             Self::Special => MOpRegNum::SPECIAL_REG_NUMS, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub const fn as_str(self) -> &'static str { | ||||||
|  |         match self { | ||||||
|  |             Self::Normal => "rename_table_normal", | ||||||
|  |             Self::Special => "rename_table_special", | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] | ||||||
| pub enum MOpDestRegKind { | pub enum MOpDestRegKind { | ||||||
|     NormalReg { |     NormalReg { | ||||||
|  | @ -682,6 +705,69 @@ pub enum MOpDestRegKind { | ||||||
|     }, |     }, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Copy, Clone, Debug)] | ||||||
|  | pub struct MOpDestRegName { | ||||||
|  |     base_name: &'static str, | ||||||
|  |     index: usize, | ||||||
|  |     reg_num: Option<u32>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl fmt::Display for MOpDestRegName { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|  |         let Self { | ||||||
|  |             base_name, | ||||||
|  |             index, | ||||||
|  |             reg_num, | ||||||
|  |         } = self; | ||||||
|  |         write!(f, "{base_name}{index}")?; | ||||||
|  |         if let Some(reg_num) = reg_num { | ||||||
|  |             write!(f, "_r{reg_num:02X}")?; | ||||||
|  |         } | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl MOpDestRegKind { | ||||||
|  |     pub const fn reg_range(self) -> std::ops::Range<u32> { | ||||||
|  |         match self { | ||||||
|  |             Self::NormalReg { .. } => MOpRegNum::NORMAL_REG_NUMS, | ||||||
|  |             Self::FlagReg { .. } => MOpRegNum::FLAG_REG_NUMS, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub const fn rename_table_names(self) -> &'static [RenameTableName] { | ||||||
|  |         match self { | ||||||
|  |             Self::NormalReg { .. } => &[RenameTableName::Normal, RenameTableName::Special], | ||||||
|  |             Self::FlagReg { .. } => &[RenameTableName::Special], | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn fixed_reg_num(self) -> Option<u32> { | ||||||
|  |         match self { | ||||||
|  |             Self::NormalReg { dest_reg_index: _ } => None, | ||||||
|  |             Self::FlagReg { | ||||||
|  |                 flag_reg_index: _, | ||||||
|  |                 reg_num, | ||||||
|  |             } => Some(reg_num), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     pub fn reg_name(self) -> MOpDestRegName { | ||||||
|  |         match self { | ||||||
|  |             Self::NormalReg { dest_reg_index } => MOpDestRegName { | ||||||
|  |                 base_name: "dest", | ||||||
|  |                 index: dest_reg_index, | ||||||
|  |                 reg_num: None, | ||||||
|  |             }, | ||||||
|  |             Self::FlagReg { | ||||||
|  |                 flag_reg_index, | ||||||
|  |                 reg_num, | ||||||
|  |             } => MOpDestRegName { | ||||||
|  |                 base_name: "flag", | ||||||
|  |                 index: flag_reg_index, | ||||||
|  |                 reg_num: Some(reg_num), | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl MOpDestReg { | impl MOpDestReg { | ||||||
|     pub const NORMAL_REG_COUNT: usize = 2; |     pub const NORMAL_REG_COUNT: usize = 2; | ||||||
|     pub const REG_COUNT: usize = Self::NORMAL_REG_COUNT + range_u32_len(&MOpRegNum::FLAG_REG_NUMS); |     pub const REG_COUNT: usize = Self::NORMAL_REG_COUNT + range_u32_len(&MOpRegNum::FLAG_REG_NUMS); | ||||||
|  |  | ||||||
|  | @ -3,17 +3,22 @@ | ||||||
| use crate::{ | use crate::{ | ||||||
|     config::CpuConfig, |     config::CpuConfig, | ||||||
|     instruction::{ |     instruction::{ | ||||||
|         MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, UnitOutRegNum, COMMON_MOP_SRC_LEN, |         MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, RenameTableName, UnitOutRegNum, | ||||||
|  |         COMMON_MOP_SRC_LEN, | ||||||
|     }, |     }, | ||||||
|     unit::{TrapData, UnitTrait}, |     unit::{TrapData, UnitTrait}, | ||||||
|     util::tree_reduce::tree_reduce_with_state, |     util::tree_reduce::tree_reduce_with_state, | ||||||
| }; | }; | ||||||
| use fayalite::{ | use fayalite::{ | ||||||
|     module::{instance_with_loc, wire_with_loc}, |     memory::{splat_mask, WriteStruct}, | ||||||
|  |     module::{instance_with_loc, memory_with_loc, wire_with_loc}, | ||||||
|     prelude::*, |     prelude::*, | ||||||
|     util::ready_valid::ReadyValid, |     util::ready_valid::ReadyValid, | ||||||
| }; | }; | ||||||
| use std::num::NonZeroUsize; | use std::{ | ||||||
|  |     collections::{BTreeMap, VecDeque}, | ||||||
|  |     num::NonZeroUsize, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| pub mod unit_free_regs_tracker; | pub mod unit_free_regs_tracker; | ||||||
| 
 | 
 | ||||||
|  | @ -55,15 +60,23 @@ pub fn reg_alloc(config: &CpuConfig) { | ||||||
|     ); |     ); | ||||||
|     // TODO: finish
 |     // TODO: finish
 | ||||||
| 
 | 
 | ||||||
|     // the large rename table for normal registers (has less read/write ports)
 |     let mut rename_table_mems = BTreeMap::<RenameTableName, MemBuilder<_>>::new(); | ||||||
|     #[hdl] |  | ||||||
|     let mut rename_table_normal_mem = memory(config.p_reg_num()); |  | ||||||
|     rename_table_normal_mem.depth(MOpRegNum::NORMAL_REG_NUMS.len()); |  | ||||||
| 
 | 
 | ||||||
|     // a special small rename table (for flags and stuff, since it has more read/write ports)
 |     for reg_kind in MOpDestReg::REG_KINDS { | ||||||
|     #[hdl] |         for &rename_table_name in reg_kind.rename_table_names() { | ||||||
|     let mut rename_table_special_mem = memory(config.p_reg_num()); |             rename_table_mems | ||||||
|     rename_table_special_mem.depth(MOpRegNum::SPECIAL_REG_NUMS.len()); |                 .entry(rename_table_name) | ||||||
|  |                 .or_insert_with(|| { | ||||||
|  |                     let mut mem = memory_with_loc( | ||||||
|  |                         &format!("{}_mem", rename_table_name.as_str()), | ||||||
|  |                         config.p_reg_num(), | ||||||
|  |                         SourceLocation::caller(), | ||||||
|  |                     ); | ||||||
|  |                     mem.depth(rename_table_name.reg_range().len()); | ||||||
|  |                     mem | ||||||
|  |                 }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let available_units = |     let available_units = | ||||||
|  | @ -92,29 +105,28 @@ pub fn reg_alloc(config: &CpuConfig) { | ||||||
|         struct RenameTableReadPort<T> { |         struct RenameTableReadPort<T> { | ||||||
|             addr: MOpRegNum, |             addr: MOpRegNum, | ||||||
|             #[hdl(flip)] |             #[hdl(flip)] | ||||||
|             data: HdlOption<T>, |             data: T, | ||||||
|         } |         } | ||||||
|         let make_rename_table_read_port = |         let rename_table_read_ports: [_; COMMON_MOP_SRC_LEN] = std::array::from_fn(|src_index| { | ||||||
|             |mem: &mut MemBuilder<_>, |             let wire = wire_with_loc( | ||||||
|              reg_range: std::ops::Range<u32>, |                 &format!("rename_{fetch_index}_src_{src_index}"), | ||||||
|              src_index: usize, |                 SourceLocation::caller(), | ||||||
|              table_name: &str| { |                 RenameTableReadPort[config.p_reg_num()], | ||||||
|  |             ); | ||||||
|  |             connect(wire.addr, MOpRegNum::const_zero()); | ||||||
|  |             connect(wire.data, config.p_reg_num().const_zero()); | ||||||
|  |             for (&rename_table_name, mem) in &mut rename_table_mems { | ||||||
|  |                 let table_name = rename_table_name.as_str(); | ||||||
|                 let read_port = mem.new_read_port(); |                 let read_port = mem.new_read_port(); | ||||||
|                 connect(read_port.clk, cd.clk); |                 connect(read_port.clk, cd.clk); | ||||||
|                 connect_any(read_port.addr, 0u8); |                 connect_any(read_port.addr, 0u8); | ||||||
|                 connect(read_port.en, false); |                 connect(read_port.en, false); | ||||||
|                 let wire = wire_with_loc( |                 let reg_range = rename_table_name.reg_range(); | ||||||
|                     &format!("{table_name}_{fetch_index}_src_{src_index}"), |  | ||||||
|                     SourceLocation::caller(), |  | ||||||
|                     RenameTableReadPort[config.p_reg_num()], |  | ||||||
|                 ); |  | ||||||
|                 connect(wire.addr, MOpRegNum::const_zero()); |  | ||||||
|                 connect(wire.data, Expr::ty(wire.data).HdlNone()); |  | ||||||
|                 #[hdl] |                 #[hdl] | ||||||
|                 if wire.addr.value.cmp_ge(reg_range.start) & wire.addr.value.cmp_lt(reg_range.end) { |                 if wire.addr.value.cmp_ge(reg_range.start) & wire.addr.value.cmp_lt(reg_range.end) { | ||||||
|                     connect_any(read_port.addr, wire.addr.value - reg_range.start); |                     connect_any(read_port.addr, wire.addr.value - reg_range.start); | ||||||
|                     connect(read_port.en, true); |                     connect(read_port.en, true); | ||||||
|                     connect(wire.data, HdlSome(read_port.data)); |                     connect(wire.data, read_port.data); | ||||||
|                     for prev_fetch_index in 0..fetch_index { |                     for prev_fetch_index in 0..fetch_index { | ||||||
|                         #[hdl] |                         #[hdl] | ||||||
|                         if let HdlSome(decoded_insn) = |                         if let HdlSome(decoded_insn) = | ||||||
|  | @ -125,36 +137,55 @@ pub fn reg_alloc(config: &CpuConfig) { | ||||||
|                                 renamed_mops_out_reg[prev_fetch_index] |                                 renamed_mops_out_reg[prev_fetch_index] | ||||||
|                             { |                             { | ||||||
|                                 let dest_reg = MOpTrait::dest_reg(decoded_insn.mop); |                                 let dest_reg = MOpTrait::dest_reg(decoded_insn.mop); | ||||||
|                                 for dest_reg in MOpDestReg::regs(dest_reg) { |                                 for (dest_reg, reg_kind) in MOpDestReg::regs(dest_reg) | ||||||
|                                     #[hdl] |                                     .into_iter() | ||||||
|                                     if dest_reg.value.cmp_eq(wire.addr.value) { |                                     .zip(MOpDestReg::REG_KINDS) | ||||||
|                                         connect(wire.data, HdlSome(renamed_mop_out_reg)); |                                 { | ||||||
|  |                                     if reg_kind.rename_table_names().contains(&rename_table_name) { | ||||||
|  |                                         #[hdl] | ||||||
|  |                                         if dest_reg.value.cmp_eq(wire.addr.value) { | ||||||
|  |                                             connect(wire.data, renamed_mop_out_reg); | ||||||
|  |                                         } | ||||||
|                                     } |                                     } | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 wire |             } | ||||||
|             }; |             wire | ||||||
|         let rename_table_normal_read_ports: [_; COMMON_MOP_SRC_LEN] = |         }); | ||||||
|             std::array::from_fn(|src_index| { |         let mut rename_table_write_ports = BTreeMap::<RenameTableName, VecDeque<_>>::new(); | ||||||
|                 make_rename_table_read_port( |         for reg_kind in MOpDestReg::REG_KINDS { | ||||||
|                     &mut rename_table_normal_mem, |             for &rename_table_name in reg_kind.rename_table_names() { | ||||||
|                     MOpRegNum::NORMAL_REG_NUMS, |                 let mem = rename_table_mems | ||||||
|                     src_index, |                     .get_mut(&rename_table_name) | ||||||
|                     "rename_table_normal", |                     .expect("already added all RenameTableName values"); | ||||||
|                 ) |                 let write_ports = rename_table_write_ports | ||||||
|             }); |                     .entry(rename_table_name) | ||||||
|         let rename_table_special_read_ports: [_; COMMON_MOP_SRC_LEN] = |                     .or_default(); | ||||||
|             std::array::from_fn(|src_index| { |                 let write_port_ = mem.new_write_port(); | ||||||
|                 make_rename_table_read_port( |                 let table_name = rename_table_name.as_str(); | ||||||
|                     &mut rename_table_special_mem, |                 let write_port = wire_with_loc( | ||||||
|                     MOpRegNum::FLAG_REG_NUMS, |                     &format!("{table_name}_{fetch_index}_{}", reg_kind.reg_name()), | ||||||
|                     src_index, |                     SourceLocation::caller(), | ||||||
|                     "rename_table_special", |                     Expr::ty(write_port_), | ||||||
|                 ) |                 ); | ||||||
|             }); |                 connect(write_port_, write_port); | ||||||
|  |                 write_ports.push_back(write_port); | ||||||
|  |                 connect_any( | ||||||
|  |                     write_port, | ||||||
|  |                     #[hdl] | ||||||
|  |                     WriteStruct::<_, _> { | ||||||
|  |                         addr: 0_hdl_u0, | ||||||
|  |                         en: false, | ||||||
|  |                         clk: cd.clk, | ||||||
|  |                         data: Expr::ty(write_port.data).uninit(), | ||||||
|  |                         mask: splat_mask(config.p_reg_num(), true.to_expr()), | ||||||
|  |                     }, | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         #[hdl] |         #[hdl] | ||||||
|         if let HdlSome(decoded_insn) = fetch_decode_interface.decoded_insns[fetch_index].data { |         if let HdlSome(decoded_insn) = fetch_decode_interface.decoded_insns[fetch_index].data { | ||||||
|             connect( |             connect( | ||||||
|  | @ -171,31 +202,41 @@ pub fn reg_alloc(config: &CpuConfig) { | ||||||
|                         renamed_mop_out_reg.unit_out_reg, |                         renamed_mop_out_reg.unit_out_reg, | ||||||
|                         config.p_reg_num_width(), |                         config.p_reg_num_width(), | ||||||
|                         &mut |src_reg, src_index| { |                         &mut |src_reg, src_index| { | ||||||
|                             let src_reg = #[hdl] |                             connect( | ||||||
|                             MOpRegNum { value: src_reg }; |                                 rename_table_read_ports[src_index].addr, | ||||||
|                             let renamed_src_reg = wire_with_loc( |                                 #[hdl] | ||||||
|                                 &format!("renamed_src_reg_{fetch_index}_{src_index}"), |                                 MOpRegNum { value: src_reg }, | ||||||
|                                 SourceLocation::caller(), |  | ||||||
|                                 config.p_reg_num(), |  | ||||||
|                             ); |                             ); | ||||||
|                             connect(rename_table_normal_read_ports[src_index].addr, src_reg); |                             rename_table_read_ports[src_index].data.cast_to_bits() | ||||||
|                             connect(rename_table_special_read_ports[src_index].addr, src_reg); |  | ||||||
|                             #[hdl] |  | ||||||
|                             if let HdlSome(v) = rename_table_normal_read_ports[src_index].data { |  | ||||||
|                                 connect(renamed_src_reg, v); |  | ||||||
|                             } else if let HdlSome(v) = |  | ||||||
|                                 rename_table_special_read_ports[src_index].data |  | ||||||
|                             { |  | ||||||
|                                 connect(renamed_src_reg, v); |  | ||||||
|                             } else { |  | ||||||
|                                 connect(renamed_src_reg, config.p_reg_num().const_zero()); |  | ||||||
|                             } |  | ||||||
|                             renamed_src_reg.cast_to_bits() |  | ||||||
|                         }, |                         }, | ||||||
|                     )), |                     )), | ||||||
|                 ); |                 ); | ||||||
|                 // TODO: write dest_reg to rename table
 |                 for (reg, reg_kind) in MOpDestReg::regs(dest_reg) | ||||||
|                 // rename_table_mem.new_write_port()
 |                     .into_iter() | ||||||
|  |                     .zip(MOpDestReg::REG_KINDS) | ||||||
|  |                 { | ||||||
|  |                     for &rename_table_name in reg_kind.rename_table_names() { | ||||||
|  |                         let Some(write_ports) = | ||||||
|  |                             rename_table_write_ports.get_mut(&rename_table_name) | ||||||
|  |                         else { | ||||||
|  |                             unreachable!(); | ||||||
|  |                         }; | ||||||
|  |                         let Some(write_port) = write_ports.pop_front() else { | ||||||
|  |                             unreachable!(); | ||||||
|  |                         }; | ||||||
|  |                         let reg_range = rename_table_name.reg_range(); | ||||||
|  |                         #[hdl] | ||||||
|  |                         if reg.value.cmp_ge(reg_range.start) & reg.value.cmp_lt(reg_range.end) { | ||||||
|  |                             connect(write_port.data, renamed_mop_out_reg); | ||||||
|  |                             if let Some(fixed_reg_num) = reg_kind.fixed_reg_num() { | ||||||
|  |                                 connect_any(write_port.addr, fixed_reg_num - reg_range.start); | ||||||
|  |                             } else { | ||||||
|  |                                 connect_any(write_port.addr, reg.value - reg_range.start); | ||||||
|  |                             } | ||||||
|  |                             connect(write_port.en, true); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         connect( |         connect( | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue