forked from libre-chip/cpu
		
	WIP adding unit input/output values and insn tracking
This commit is contained in:
		
							parent
							
								
									d7818d889c
								
							
						
					
					
						commit
						2b7e7e4946
					
				
					 9 changed files with 11507 additions and 6399 deletions
				
			
		|  | @ -2,17 +2,36 @@ | |||
| // See Notices.txt for copyright information
 | ||||
| use crate::{ | ||||
|     instruction::{PRegNum, UnitNum, UnitOutRegNum, CONST_ZERO_UNIT_NUM}, | ||||
|     unit::{UnitKind, UnitMOp}, | ||||
|     unit::{unit_base::UnitForwardingInfo, UnitCancelInput, UnitKind, UnitMOp, UnitOutputWrite}, | ||||
| }; | ||||
| use fayalite::prelude::*; | ||||
| use std::num::NonZeroUsize; | ||||
| 
 | ||||
| #[derive(Clone, Eq, PartialEq, Hash, Debug)] | ||||
| #[non_exhaustive] | ||||
| pub struct UnitConfig { | ||||
|     pub kind: UnitKind, | ||||
|     /// max number of instructions that can be in-flight through this unit at any point in time.
 | ||||
|     pub max_in_flight: Option<NonZeroUsize>, | ||||
| } | ||||
| 
 | ||||
| impl UnitConfig { | ||||
|     pub fn new(kind: UnitKind) -> Self { | ||||
|         Self { | ||||
|             kind, | ||||
|             max_in_flight: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Eq, PartialEq, Hash, Debug)] | ||||
| #[non_exhaustive] | ||||
| pub struct CpuConfig { | ||||
|     pub unit_kinds: Vec<UnitKind>, | ||||
|     pub units: Vec<UnitConfig>, | ||||
|     pub out_reg_num_width: usize, | ||||
|     pub fetch_width: NonZeroUsize, | ||||
|     /// default value for [`UnitConfig::max_in_flight`]
 | ||||
|     pub default_unit_max_in_flight: NonZeroUsize, | ||||
| } | ||||
| 
 | ||||
| impl CpuConfig { | ||||
|  | @ -23,15 +42,22 @@ impl CpuConfig { | |||
|         }; | ||||
|         v | ||||
|     }; | ||||
|     pub fn new(unit_kinds: Vec<UnitKind>) -> Self { | ||||
|     pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = { | ||||
|         let Some(v) = NonZeroUsize::new(8) else { | ||||
|             unreachable!(); | ||||
|         }; | ||||
|         v | ||||
|     }; | ||||
|     pub fn new(units: Vec<UnitConfig>) -> Self { | ||||
|         Self { | ||||
|             unit_kinds, | ||||
|             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, | ||||
|         } | ||||
|     } | ||||
|     pub fn non_const_unit_nums(&self) -> std::ops::Range<usize> { | ||||
|         (CONST_ZERO_UNIT_NUM + 1)..(self.unit_kinds.len() + 1) | ||||
|         (CONST_ZERO_UNIT_NUM + 1)..(self.units.len() + 1) | ||||
|     } | ||||
|     pub fn unit_num_width(&self) -> usize { | ||||
|         UInt::range(CONST_ZERO_UNIT_NUM..self.non_const_unit_nums().end).width() | ||||
|  | @ -51,4 +77,22 @@ impl CpuConfig { | |||
|     pub fn unit_mop_in_unit(&self) -> UnitMOp<UnitOutRegNum<DynSize>, DynSize> { | ||||
|         UnitMOp[self.unit_out_reg_num()][self.p_reg_num_width()] | ||||
|     } | ||||
|     pub fn unit_output_write(&self) -> UnitOutputWrite<DynSize> { | ||||
|         UnitOutputWrite[self.out_reg_num_width] | ||||
|     } | ||||
|     pub fn unit_output_writes(&self) -> Array<HdlOption<UnitOutputWrite<DynSize>>> { | ||||
|         Array[HdlOption[self.unit_output_write()]][self.non_const_unit_nums().len()] | ||||
|     } | ||||
|     pub fn unit_cancel_input(&self) -> UnitCancelInput<DynSize> { | ||||
|         UnitCancelInput[self.out_reg_num_width] | ||||
|     } | ||||
|     pub fn unit_forwarding_info(&self) -> UnitForwardingInfo<DynSize, DynSize, DynSize> { | ||||
|         UnitForwardingInfo[self.unit_num_width()][self.out_reg_num_width] | ||||
|             [self.non_const_unit_nums().len()] | ||||
|     } | ||||
|     pub fn unit_max_in_flight(&self, unit_index: usize) -> NonZeroUsize { | ||||
|         self.units[unit_index] | ||||
|             .max_in_flight | ||||
|             .unwrap_or(self.default_unit_max_in_flight) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -12,6 +12,10 @@ pub trait MOpTrait: Type { | |||
|     type SrcRegWidth: Size; | ||||
|     fn dest_reg_ty(self) -> Self::DestReg; | ||||
|     fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg>; | ||||
|     fn for_each_src_reg( | ||||
|         input: impl ToExpr<Type = Self>, | ||||
|         f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize), | ||||
|     ); | ||||
|     fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>( | ||||
|         self, | ||||
|         new_dest_reg: NewDestReg, | ||||
|  | @ -63,6 +67,16 @@ impl<T: CommonMOpTrait> MOpTrait for T { | |||
|     fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> { | ||||
|         T::common_mop(input).dest | ||||
|     } | ||||
|     fn for_each_src_reg( | ||||
|         input: impl ToExpr<Type = Self>, | ||||
|         f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize), | ||||
|     ) { | ||||
|         let input = input.to_expr(); | ||||
|         let common = T::common_mop(input); | ||||
|         for index in 0..T::SrcCount::VALUE { | ||||
|             f(common.src[index], index); | ||||
|         } | ||||
|     } | ||||
|     fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>( | ||||
|         self, | ||||
|         new_dest_reg: NewDestReg, | ||||
|  | @ -396,6 +410,17 @@ macro_rules! mop_enum { | |||
|                 } | ||||
|                 dest_reg | ||||
|             } | ||||
|             #[hdl] | ||||
|             fn for_each_src_reg( | ||||
|                 input: impl ToExpr<Type = Self>, | ||||
|                 f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize), | ||||
|             ) { | ||||
|                 #[hdl] | ||||
|                 match input { | ||||
|                     $MOp::<_, _>::$FirstVariant(v) => MOpTrait::for_each_src_reg(v, f), | ||||
|                     $($MOp::<_, _>::$Variant(v) => MOpTrait::for_each_src_reg(v, f),)* | ||||
|                 } | ||||
|             } | ||||
|             fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>( | ||||
|                 self, | ||||
|                 new_dest_reg: NewDestReg, | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ use crate::{ | |||
|         MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, RenameTableName, UnitOutRegNum, | ||||
|         COMMON_MOP_SRC_LEN, | ||||
|     }, | ||||
|     unit::{TrapData, UnitTrait}, | ||||
|     unit::{unit_base::UnitForwardingInfo, TrapData, UnitTrait}, | ||||
|     util::tree_reduce::tree_reduce_with_state, | ||||
| }; | ||||
| use fayalite::{ | ||||
|  | @ -17,6 +17,7 @@ use fayalite::{ | |||
| }; | ||||
| use std::{ | ||||
|     collections::{BTreeMap, VecDeque}, | ||||
|     marker::PhantomData, | ||||
|     num::NonZeroUsize, | ||||
| }; | ||||
| 
 | ||||
|  | @ -79,8 +80,7 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|     } | ||||
| 
 | ||||
|     #[hdl] | ||||
|     let available_units = | ||||
|         wire(Array[Array[Bool][config.unit_kinds.len()]][config.fetch_width.get()]); | ||||
|     let available_units = wire(Array[Array[Bool][config.units.len()]][config.fetch_width.get()]); | ||||
|     #[hdl] | ||||
|     let selected_unit_indexes = | ||||
|         wire(Array[HdlOption[UInt[config.unit_num_width()]]][config.fetch_width.get()]); | ||||
|  | @ -95,7 +95,7 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|         ); | ||||
|         connect( | ||||
|             available_units[fetch_index], | ||||
|             repeat(false, config.unit_kinds.len()), | ||||
|             repeat(false, config.units.len()), | ||||
|         ); | ||||
|         connect( | ||||
|             renamed_mops[fetch_index], | ||||
|  | @ -116,7 +116,6 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|             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(); | ||||
|                 connect(read_port.clk, cd.clk); | ||||
|                 connect_any(read_port.addr, 0u8); | ||||
|  | @ -242,7 +241,7 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|         connect( | ||||
|             selected_unit_indexes[fetch_index], | ||||
|             tree_reduce_with_state( | ||||
|                 0..config.unit_kinds.len(), | ||||
|                 0..config.units.len(), | ||||
|                 &mut 0usize, | ||||
|                 |_state, unit_index| { | ||||
|                     let selected_unit_index_leaf = wire_with_loc( | ||||
|  | @ -304,15 +303,15 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|             config.fetch_width.get(), | ||||
|         ), | ||||
|     ); | ||||
|     for (unit_index, &unit_kind) in config.unit_kinds.iter().enumerate() { | ||||
|         let dyn_unit = unit_kind.unit(config); | ||||
|     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( | ||||
|             &format!("unit_{unit_index}"), | ||||
|             dyn_unit.make_module(), | ||||
|             dyn_unit.module(), | ||||
|             SourceLocation::caller(), | ||||
|         ); | ||||
|         connect(dyn_unit.cd(unit), cd); | ||||
|         let unit_input = dyn_unit.input(unit); | ||||
|         let unit_input_insn = dyn_unit.input_insn(unit); | ||||
|         // 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
 | ||||
|  | @ -333,7 +332,10 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|             HdlOption[UInt[config.out_reg_num_width]].uninit(), // FIXME: just for debugging
 | ||||
|         ); | ||||
|         connect(unit_free_regs_tracker.alloc_out[0].ready, false); | ||||
|         connect(unit_input.data, Expr::ty(unit_input).data.HdlNone()); | ||||
|         connect( | ||||
|             unit_input_insn.data, | ||||
|             Expr::ty(unit_input_insn).data.HdlNone(), | ||||
|         ); | ||||
|         for fetch_index in 0..config.fetch_width.get() { | ||||
|             #[hdl] | ||||
|             if let HdlNone = unit_free_regs_tracker.alloc_out[0].data { | ||||
|  | @ -341,7 +343,7 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|                 connect(available_units[fetch_index][unit_index], false); | ||||
|             } | ||||
|             #[hdl] | ||||
|             if !unit_input.ready { | ||||
|             if !unit_input_insn.ready { | ||||
|                 // must come after to override connects in loops above
 | ||||
|                 connect(available_units[fetch_index][unit_index], false); | ||||
|             } | ||||
|  | @ -354,11 +356,11 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|                     if let HdlSome(renamed_mop) = | ||||
|                         HdlOption::and_then(renamed_mops[fetch_index], |v| dyn_unit.extract_mop(v)) | ||||
|                     { | ||||
|                         connect(unit_input.data, HdlSome(renamed_mop)); | ||||
|                         connect(unit_input_insn.data, HdlSome(renamed_mop)); | ||||
|                     } else { | ||||
|                         connect( | ||||
|                             unit_input.data, | ||||
|                             HdlSome(Expr::ty(unit_input).data.HdlSome.uninit()), | ||||
|                             unit_input_insn.data, | ||||
|                             HdlSome(Expr::ty(unit_input_insn).data.HdlSome.uninit()), | ||||
|                         ); | ||||
|                         // FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
 | ||||
|                     } | ||||
|  | @ -383,5 +385,23 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|                 } | ||||
|             } | ||||
|         } | ||||
|         // TODO: connect outputs to other units
 | ||||
|         connect( | ||||
|             dyn_unit.unit_forwarding_info(unit), | ||||
|             #[hdl] | ||||
|             UnitForwardingInfo::<_, _, _> { | ||||
|                 unit_output_writes: repeat( | ||||
|                     HdlOption[config.unit_output_write()].HdlNone(), | ||||
|                     config.units.len(), | ||||
|                 ), | ||||
|                 _phantom: PhantomData, | ||||
|             }, | ||||
|         ); | ||||
|         connect(dyn_unit.output(unit).ready, false); | ||||
|         // TODO: handle cancellation
 | ||||
|         connect( | ||||
|             dyn_unit.cancel_input(unit).data, | ||||
|             HdlOption[config.unit_cancel_input()].HdlNone(), | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -148,3 +148,14 @@ pub struct PRegValue { | |||
|     pub int_fp: UInt<64>, | ||||
|     pub flags: PRegFlags, | ||||
| } | ||||
| 
 | ||||
| impl PRegValue { | ||||
|     #[hdl] | ||||
|     pub fn zeroed() -> Expr<Self> { | ||||
|         #[hdl] | ||||
|         PRegValue { | ||||
|             int_fp: 0u64, | ||||
|             flags: PRegFlags::zeroed(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -4,9 +4,10 @@ | |||
| use crate::{ | ||||
|     config::CpuConfig, | ||||
|     instruction::{ | ||||
|         mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, PRegNum, UnitOutRegNum, | ||||
|         mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, UnitOutRegNum, | ||||
|     }, | ||||
|     register::PRegValue, | ||||
|     unit::unit_base::UnitForwardingInfo, | ||||
| }; | ||||
| use fayalite::{ | ||||
|     bundle::{Bundle, BundleType}, | ||||
|  | @ -16,6 +17,7 @@ use fayalite::{ | |||
| }; | ||||
| 
 | ||||
| pub mod alu_branch; | ||||
| pub mod unit_base; | ||||
| 
 | ||||
| macro_rules! all_units { | ||||
|     ( | ||||
|  | @ -42,9 +44,9 @@ macro_rules! all_units { | |||
|         } | ||||
| 
 | ||||
|         impl $UnitKind { | ||||
|             pub fn unit(self, config: &CpuConfig) -> DynUnit { | ||||
|             pub fn unit(self, config: &CpuConfig, unit_index: usize) -> DynUnit { | ||||
|                 match self { | ||||
|                     $($UnitKind::$Unit => $create_dyn_unit_fn(config),)* | ||||
|                     $($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index),)* | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | @ -111,11 +113,11 @@ macro_rules! all_units { | |||
|             #[hdl] | ||||
|             pub fn available_units_for_kind(&self, unit_kind: impl ToExpr<Type = $HdlUnitKind>) -> Expr<Array<Bool>> { | ||||
|                 #[hdl] | ||||
|                 let available_units_for_kind = wire(Array[Bool][self.unit_kinds.len()]); | ||||
|                 let available_units_for_kind = wire(Array[Bool][self.units.len()]); | ||||
|                 #[hdl] | ||||
|                 match unit_kind { | ||||
|                     $($HdlUnitKind::$Unit => for (index, &unit_kind) in self.unit_kinds.iter().enumerate() { | ||||
|                         connect(available_units_for_kind[index], unit_kind == $UnitKind::$Unit); | ||||
|                     $($HdlUnitKind::$Unit => for (index, unit) in self.units.iter().enumerate() { | ||||
|                         connect(available_units_for_kind[index], unit.kind == $UnitKind::$Unit); | ||||
|                     })* | ||||
|                 } | ||||
|                 available_units_for_kind | ||||
|  | @ -129,13 +131,13 @@ all_units! { | |||
|     #[unit_kind = UnitKind] | ||||
|     #[hdl] | ||||
|     pub enum UnitMOp<DestReg: Type, SrcRegWidth: Size> { | ||||
|         #[create_dyn_unit_fn = |config| alu_branch::AluBranch::new(config).to_dyn()] | ||||
|         #[create_dyn_unit_fn = |config, unit_index| alu_branch::AluBranch::new(config, unit_index).to_dyn()] | ||||
|         #[extract = alu_branch_mop] | ||||
|         AluBranch(AluBranchMOp<DestReg, SrcRegWidth>), | ||||
|         #[create_dyn_unit_fn = |config| todo!()] | ||||
|         #[create_dyn_unit_fn = |config, unit_index| todo!()] | ||||
|         #[extract = l2_register_file_mop] | ||||
|         L2RegisterFile(L2RegisterFileMOp<DestReg, SrcRegWidth>), | ||||
|         #[create_dyn_unit_fn = |config| todo!()] | ||||
|         #[create_dyn_unit_fn = |config, unit_index| todo!()] | ||||
|         #[extract = load_store_mop] | ||||
|         LoadStore(LoadStoreMOp<DestReg, SrcRegWidth>), | ||||
|     } | ||||
|  | @ -147,6 +149,12 @@ pub struct UnitResultCompleted<ExtraOut> { | |||
|     pub extra_out: ExtraOut, | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| pub struct UnitOutputWrite<OutRegNumWidth: Size> { | ||||
|     pub which: UnitOutRegNum<OutRegNumWidth>, | ||||
|     pub value: PRegValue, | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| pub struct TrapData { | ||||
|     // TODO
 | ||||
|  | @ -159,14 +167,14 @@ pub enum UnitResult<ExtraOut> { | |||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| pub struct UnitOutput<UnitNumWidth: Size, OutRegNumWidth: Size, ExtraOut> { | ||||
|     pub which: PRegNum<UnitNumWidth, OutRegNumWidth>, | ||||
| pub struct UnitOutput<OutRegNumWidth: Size, ExtraOut> { | ||||
|     pub which: UnitOutRegNum<OutRegNumWidth>, | ||||
|     pub result: UnitResult<ExtraOut>, | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| pub struct UnitCancelInput<UnitNumWidth: Size, OutRegNumWidth: Size> { | ||||
|     pub which: PRegNum<UnitNumWidth, OutRegNumWidth>, | ||||
| pub struct UnitCancelInput<OutRegNumWidth: Size> { | ||||
|     pub which: UnitOutRegNum<OutRegNumWidth>, | ||||
| } | ||||
| 
 | ||||
| pub trait UnitTrait: | ||||
|  | @ -187,18 +195,22 @@ pub trait UnitTrait: | |||
|         mop: Expr<UnitMOp<UnitOutRegNum<DynSize>, DynSize>>, | ||||
|     ) -> Expr<HdlOption<Self::MOp>>; | ||||
| 
 | ||||
|     fn make_module(&self) -> Interned<Module<Self::Type>>; | ||||
|     fn module(&self) -> Interned<Module<Self::Type>>; | ||||
| 
 | ||||
|     fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>>; | ||||
|     fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>>; | ||||
| 
 | ||||
|     fn cancel_input( | ||||
|     fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>>; | ||||
| 
 | ||||
|     fn unit_forwarding_info( | ||||
|         &self, | ||||
|         this: Expr<Self::Type>, | ||||
|     ) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>>; | ||||
|     ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>>; | ||||
| 
 | ||||
|     fn output( | ||||
|         &self, | ||||
|         this: Expr<Self::Type>, | ||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>>; | ||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>>; | ||||
| 
 | ||||
|     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>; | ||||
| 
 | ||||
|     fn to_dyn(&self) -> DynUnit; | ||||
|  | @ -250,25 +262,29 @@ impl UnitTrait for DynUnit { | |||
|         self.unit.extract_mop(mop) | ||||
|     } | ||||
| 
 | ||||
|     fn make_module(&self) -> Interned<Module<Self::Type>> { | ||||
|         self.unit.make_module() | ||||
|     fn module(&self) -> Interned<Module<Self::Type>> { | ||||
|         self.unit.module() | ||||
|     } | ||||
| 
 | ||||
|     fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { | ||||
|         self.unit.input(this) | ||||
|     fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { | ||||
|         self.unit.input_insn(this) | ||||
|     } | ||||
| 
 | ||||
|     fn cancel_input( | ||||
|     fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>> { | ||||
|         self.unit.cancel_input(this) | ||||
|     } | ||||
| 
 | ||||
|     fn unit_forwarding_info( | ||||
|         &self, | ||||
|         this: Expr<Self::Type>, | ||||
|     ) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> { | ||||
|         self.unit.cancel_input(this) | ||||
|     ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> { | ||||
|         self.unit.unit_forwarding_info(this) | ||||
|     } | ||||
| 
 | ||||
|     fn output( | ||||
|         &self, | ||||
|         this: Expr<Self::Type>, | ||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>> { | ||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> { | ||||
|         self.unit.output(this) | ||||
|     } | ||||
| 
 | ||||
|  | @ -312,25 +328,29 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T | |||
|         Expr::from_enum(Expr::as_enum(self.0.extract_mop(mop))) | ||||
|     } | ||||
| 
 | ||||
|     fn make_module(&self) -> Interned<Module<Self::Type>> { | ||||
|         self.0.make_module().canonical().intern_sized() | ||||
|     fn module(&self) -> Interned<Module<Self::Type>> { | ||||
|         self.0.module().canonical().intern_sized() | ||||
|     } | ||||
| 
 | ||||
|     fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { | ||||
|         Expr::from_bundle(Expr::as_bundle(self.0.input(Expr::from_bundle(this)))) | ||||
|     fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { | ||||
|         Expr::from_bundle(Expr::as_bundle(self.0.input_insn(Expr::from_bundle(this)))) | ||||
|     } | ||||
| 
 | ||||
|     fn cancel_input( | ||||
|     fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>> { | ||||
|         self.0.cancel_input(Expr::from_bundle(this)) | ||||
|     } | ||||
| 
 | ||||
|     fn unit_forwarding_info( | ||||
|         &self, | ||||
|         this: Expr<Self::Type>, | ||||
|     ) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> { | ||||
|         self.0.cancel_input(Expr::from_bundle(this)) | ||||
|     ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> { | ||||
|         self.0.unit_forwarding_info(Expr::from_bundle(this)) | ||||
|     } | ||||
| 
 | ||||
|     fn output( | ||||
|         &self, | ||||
|         this: Expr<Self::Type>, | ||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>> { | ||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> { | ||||
|         Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this)))) | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,7 +4,10 @@ | |||
| use crate::{ | ||||
|     config::CpuConfig, | ||||
|     instruction::{AluBranchMOp, UnitOutRegNum}, | ||||
|     unit::{DynUnit, DynUnitWrapper, UnitCancelInput, UnitKind, UnitMOp, UnitOutput, UnitTrait}, | ||||
|     unit::{ | ||||
|         unit_base::{unit_base, UnitForwardingInfo}, | ||||
|         DynUnit, DynUnitWrapper, UnitCancelInput, UnitKind, UnitMOp, UnitOutput, UnitTrait, | ||||
|     }, | ||||
| }; | ||||
| use fayalite::{ | ||||
|     intern::{Intern, Interned}, | ||||
|  | @ -13,14 +16,34 @@ use fayalite::{ | |||
| }; | ||||
| 
 | ||||
| #[hdl_module] | ||||
| pub fn alu_branch(config: &CpuConfig) { | ||||
| pub fn alu_branch(config: &CpuConfig, unit_index: usize) { | ||||
|     #[hdl] | ||||
|     let cd: ClockDomain = m.input(); | ||||
|     #[hdl] | ||||
|     let input: ReadyValid<AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>> = | ||||
|     let input_insn: ReadyValid<AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>> = | ||||
|         m.input(ReadyValid[AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()]]); | ||||
|     #[hdl] | ||||
|     let unit_forwarding_info: UnitForwardingInfo<DynSize, DynSize, DynSize> = | ||||
|         m.input(config.unit_forwarding_info()); | ||||
|     #[hdl] | ||||
|     let cancel_input: ReadyValid<UnitCancelInput<DynSize>> = | ||||
|         m.input(ReadyValid[config.unit_cancel_input()]); | ||||
|     #[hdl] | ||||
|     let output: ReadyValid<UnitOutput<DynSize, ()>> = | ||||
|         m.output(ReadyValid[UnitOutput[config.out_reg_num_width][()]]); | ||||
|     #[hdl] | ||||
|     let unit_base = instance(unit_base( | ||||
|         config, | ||||
|         unit_index, | ||||
|         Expr::ty(input_insn).data.HdlSome, | ||||
|     )); | ||||
|     connect(unit_base.input_insn, input_insn); | ||||
|     connect(unit_base.cd, cd); | ||||
|     connect(unit_base.unit_forwarding_info, unit_forwarding_info); | ||||
|     connect(unit_base.cancel_input, cancel_input); | ||||
|     // TODO: finish
 | ||||
|     connect(input.ready, true); | ||||
|     connect(unit_base.ready_mop.ready, true); | ||||
|     connect(output.data, Expr::ty(output.data).HdlNone()); | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||||
|  | @ -30,10 +53,10 @@ pub struct AluBranch { | |||
| } | ||||
| 
 | ||||
| impl AluBranch { | ||||
|     pub fn new(config: &CpuConfig) -> Self { | ||||
|     pub fn new(config: &CpuConfig, unit_index: usize) -> Self { | ||||
|         Self { | ||||
|             config: config.intern(), | ||||
|             module: alu_branch(config), | ||||
|             module: alu_branch(config, unit_index), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -52,7 +75,7 @@ impl UnitTrait for AluBranch { | |||
|     } | ||||
| 
 | ||||
|     fn mop_ty(&self) -> Self::MOp { | ||||
|         self.module.io_ty().input.data.HdlSome | ||||
|         self.module.io_ty().input_insn.data.HdlSome | ||||
|     } | ||||
| 
 | ||||
|     fn unit_kind(&self) -> UnitKind { | ||||
|  | @ -66,26 +89,30 @@ impl UnitTrait for AluBranch { | |||
|         UnitMOp::alu_branch_mop(mop) | ||||
|     } | ||||
| 
 | ||||
|     fn make_module(&self) -> Interned<Module<Self::Type>> { | ||||
|     fn module(&self) -> Interned<Module<Self::Type>> { | ||||
|         self.module | ||||
|     } | ||||
| 
 | ||||
|     fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { | ||||
|         this.input | ||||
|     fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { | ||||
|         this.input_insn | ||||
|     } | ||||
| 
 | ||||
|     fn cancel_input( | ||||
|     fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>> { | ||||
|         this.cancel_input | ||||
|     } | ||||
| 
 | ||||
|     fn unit_forwarding_info( | ||||
|         &self, | ||||
|         this: Expr<Self::Type>, | ||||
|     ) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> { | ||||
|         todo!() | ||||
|     ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> { | ||||
|         this.unit_forwarding_info | ||||
|     } | ||||
| 
 | ||||
|     fn output( | ||||
|         &self, | ||||
|         this: Expr<Self::Type>, | ||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>> { | ||||
|         todo!() | ||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> { | ||||
|         this.output | ||||
|     } | ||||
| 
 | ||||
|     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> { | ||||
|  |  | |||
							
								
								
									
										130
									
								
								crates/cpu/src/unit/unit_base.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								crates/cpu/src/unit/unit_base.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,130 @@ | |||
| // SPDX-License-Identifier: LGPL-3.0-or-later
 | ||||
| // See Notices.txt for copyright information
 | ||||
| 
 | ||||
| use crate::{ | ||||
|     config::CpuConfig, | ||||
|     instruction::{MOpTrait, UnitOutRegNum, COMMON_MOP_SRC_LEN}, | ||||
|     register::PRegValue, | ||||
|     unit::{UnitCancelInput, UnitOutputWrite}, | ||||
|     util::tree_reduce::tree_reduce, | ||||
| }; | ||||
| use fayalite::{module::wire_with_loc, prelude::*, ty::StaticType, util::ready_valid::ReadyValid}; | ||||
| use std::marker::PhantomData; | ||||
| 
 | ||||
| #[hdl] | ||||
| pub struct UnitForwardingInfo<UnitNumWidth: Size, OutRegNumWidth: Size, UnitCount: Size> { | ||||
|     pub unit_output_writes: ArrayType<HdlOption<UnitOutputWrite<OutRegNumWidth>>, UnitCount>, | ||||
|     pub _phantom: PhantomData<UnitNumWidth>, | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| pub struct ReadyMOp<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> { | ||||
|     pub mop: MOp, | ||||
|     pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>, | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| struct InFlightOp<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> { | ||||
|     pub mop: MOp, | ||||
|     pub src_values: Array<HdlOption<PRegValue>, { COMMON_MOP_SRC_LEN }>, | ||||
| } | ||||
| 
 | ||||
| #[hdl_module] | ||||
| pub fn unit_base<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>>( | ||||
|     config: &CpuConfig, | ||||
|     unit_index: usize, | ||||
|     mop_ty: MOp, | ||||
| ) { | ||||
|     #[hdl] | ||||
|     let cd: ClockDomain = m.input(); | ||||
|     #[hdl] | ||||
|     let unit_forwarding_info: UnitForwardingInfo<DynSize, DynSize, DynSize> = | ||||
|         m.input(config.unit_forwarding_info()); | ||||
|     #[hdl] | ||||
|     let input_insn: ReadyValid<MOp> = m.input(ReadyValid[mop_ty]); | ||||
|     connect(input_insn.ready, false); | ||||
|     #[hdl] | ||||
|     let cancel_input: ReadyValid<UnitCancelInput<DynSize>> = | ||||
|         m.input(ReadyValid[config.unit_cancel_input()]); | ||||
|     connect(cancel_input.ready, true); | ||||
|     #[hdl] | ||||
|     let ready_mop: ReadyValid<ReadyMOp<MOp>> = m.output(ReadyValid[ReadyMOp[mop_ty]]); | ||||
|     connect(ready_mop.data, Expr::ty(ready_mop.data).HdlNone()); | ||||
|     let max_in_flight = config.unit_max_in_flight(unit_index).get(); | ||||
|     #[hdl] | ||||
|     let in_flight_ops = reg_builder().clock_domain(cd).reset(repeat( | ||||
|         HdlOption[InFlightOp[mop_ty]].HdlNone(), | ||||
|         max_in_flight, | ||||
|     )); | ||||
|     let in_flight_op_index_ty = UInt::range(0..max_in_flight); | ||||
|     #[hdl] | ||||
|     let input_index = wire(HdlOption[in_flight_op_index_ty]); | ||||
|     connect( | ||||
|         input_index, | ||||
|         tree_reduce( | ||||
|             (0..max_in_flight).map(|i| -> Expr<HdlOption<UInt>> { | ||||
|                 HdlOption::map(in_flight_ops[i], |_| i.cast_to(in_flight_op_index_ty)) | ||||
|             }), | ||||
|             HdlOption::or, | ||||
|         ) | ||||
|         .expect("max_in_flight is known to be non-zero"), | ||||
|     ); | ||||
|     #[hdl] | ||||
|     let input_in_flight_op = wire(HdlOption[InFlightOp[mop_ty]]); | ||||
|     connect(input_in_flight_op, Expr::ty(input_in_flight_op).HdlNone()); | ||||
|     #[hdl] | ||||
|     if let HdlSome(mop) = ReadyValid::firing_data(input_insn) { | ||||
|         let src_values = wire_with_loc( | ||||
|             "input_in_flight_op_src_values", | ||||
|             SourceLocation::caller(), | ||||
|             StaticType::TYPE, | ||||
|         ); | ||||
|         connect( | ||||
|             src_values, | ||||
|             [HdlSome(PRegValue::zeroed()); COMMON_MOP_SRC_LEN], | ||||
|         ); | ||||
|         MOp::for_each_src_reg(mop, &mut |src_reg, src_index| { | ||||
|             #[hdl] | ||||
|             if config | ||||
|                 .p_reg_num() | ||||
|                 .const_zero() | ||||
|                 .cast_to_bits() | ||||
|                 .cmp_ne(src_reg) | ||||
|             { | ||||
|                 connect(src_values[src_index], HdlNone()); | ||||
|             } | ||||
|         }); | ||||
|         connect( | ||||
|             input_in_flight_op, | ||||
|             HdlSome( | ||||
|                 #[hdl] | ||||
|                 InFlightOp::<_> { mop, src_values }, | ||||
|             ), | ||||
|         ); | ||||
|     } | ||||
|     for in_flight_op_index in 0..max_in_flight { | ||||
|         #[hdl] | ||||
|         if let HdlSome(in_flight_op) = in_flight_ops[in_flight_op_index] { | ||||
|             #[hdl] | ||||
|             if let HdlSome(cancel_input) = ReadyValid::firing_data(cancel_input) { | ||||
|                 #[hdl] | ||||
|                 let UnitCancelInput::<_> { which } = cancel_input; | ||||
|                 #[hdl] | ||||
|                 if which.value.cmp_eq(MOp::dest_reg(in_flight_op.mop).value) { | ||||
|                     // TODO: if it needs extra time to cancel (e.g. still in pipeline), handle that here
 | ||||
|                     connect( | ||||
|                         in_flight_ops[in_flight_op_index], | ||||
|                         HdlOption[InFlightOp[mop_ty]].HdlNone(), | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|             // TODO: finish
 | ||||
|         } else if let HdlSome(input_index) = input_index { | ||||
|             connect(input_insn.ready, true); | ||||
|             #[hdl] | ||||
|             if input_index.cmp_eq(in_flight_op_index) { | ||||
|                 connect(in_flight_ops[in_flight_op_index], input_in_flight_op); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
										
											
												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