forked from libre-chip/cpu
		
	WIP implementing unit_base
This commit is contained in:
		
							parent
							
								
									ece788dda3
								
							
						
					
					
						commit
						3f6e5cc600
					
				
					 10 changed files with 17918 additions and 8115 deletions
				
			
		|  | @ -1,8 +1,11 @@ | ||||||
| // 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::{ | use crate::{ | ||||||
|     instruction::{PRegNum, UnitNum, UnitOutRegNum, CONST_ZERO_UNIT_NUM}, |     instruction::{MOpTrait, PRegNum, UnitNum, UnitOutRegNum, CONST_ZERO_UNIT_NUM}, | ||||||
|     unit::{unit_base::UnitForwardingInfo, UnitCancelInput, UnitKind, UnitMOp, UnitOutputWrite}, |     unit::{ | ||||||
|  |         unit_base::{UnitForwardingInfo, UnitToRegAlloc}, | ||||||
|  |         UnitCancelInput, UnitKind, UnitMOp, UnitOutputWrite, | ||||||
|  |     }, | ||||||
| }; | }; | ||||||
| use fayalite::prelude::*; | use fayalite::prelude::*; | ||||||
| use std::num::NonZeroUsize; | use std::num::NonZeroUsize; | ||||||
|  | @ -95,4 +98,20 @@ impl CpuConfig { | ||||||
|             .max_in_flight |             .max_in_flight | ||||||
|             .unwrap_or(self.default_unit_max_in_flight) |             .unwrap_or(self.default_unit_max_in_flight) | ||||||
|     } |     } | ||||||
|  |     pub fn unit_to_reg_alloc< | ||||||
|  |         MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>, SrcRegWidth = DynSize>, | ||||||
|  |         ExtraOut: Type, | ||||||
|  |     >( | ||||||
|  |         &self, | ||||||
|  |         mop_ty: MOp, | ||||||
|  |         extra_out_ty: ExtraOut, | ||||||
|  |     ) -> UnitToRegAlloc<MOp, ExtraOut, DynSize, DynSize, DynSize> { | ||||||
|  |         assert_eq!( | ||||||
|  |             mop_ty.dest_reg_ty(), | ||||||
|  |             self.unit_out_reg_num(), | ||||||
|  |             "inconsistent types", | ||||||
|  |         ); | ||||||
|  |         UnitToRegAlloc[mop_ty][extra_out_ty][self.unit_num_width()][self.out_reg_num_width] | ||||||
|  |             [self.non_const_unit_nums().len()] | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,7 +1,11 @@ | ||||||
| // 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::{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, ExprPartialEq}, | ||||||
|  |     intern::Interned, | ||||||
|  |     prelude::*, | ||||||
|  | }; | ||||||
| use std::{fmt, marker::PhantomData, ops::Range}; | use std::{fmt, marker::PhantomData, ops::Range}; | ||||||
| 
 | 
 | ||||||
| pub mod power_isa; | pub mod power_isa; | ||||||
|  | @ -12,10 +16,26 @@ pub trait MOpTrait: Type { | ||||||
|     type SrcRegWidth: Size; |     type SrcRegWidth: Size; | ||||||
|     fn dest_reg_ty(self) -> Self::DestReg; |     fn dest_reg_ty(self) -> Self::DestReg; | ||||||
|     fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg>; |     fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg>; | ||||||
|  |     fn src_reg_width(self) -> <Self::SrcRegWidth as Size>::SizeType; | ||||||
|  |     fn src_reg_ty(self) -> UIntType<Self::SrcRegWidth> { | ||||||
|  |         UInt[self.src_reg_width()] | ||||||
|  |     } | ||||||
|  |     fn src_regs_ty(self) -> Array<UIntType<Self::SrcRegWidth>, { COMMON_MOP_SRC_LEN }> { | ||||||
|  |         Array[self.src_reg_ty()][ConstUsize::<{ COMMON_MOP_SRC_LEN }>] | ||||||
|  |     } | ||||||
|     fn for_each_src_reg( |     fn for_each_src_reg( | ||||||
|         input: impl ToExpr<Type = Self>, |         input: impl ToExpr<Type = Self>, | ||||||
|         f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize), |         f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize), | ||||||
|     ); |     ); | ||||||
|  |     fn connect_src_regs( | ||||||
|  |         input: impl ToExpr<Type = Self>, | ||||||
|  |         src_regs: impl ToExpr<Type = Array<UIntType<Self::SrcRegWidth>, { COMMON_MOP_SRC_LEN }>>, | ||||||
|  |     ) { | ||||||
|  |         let src_regs = src_regs.to_expr(); | ||||||
|  |         Self::for_each_src_reg(input.to_expr(), &mut |src_reg, index| { | ||||||
|  |             connect(src_regs[index], src_reg); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|     fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>( |     fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>( | ||||||
|         self, |         self, | ||||||
|         new_dest_reg: NewDestReg, |         new_dest_reg: NewDestReg, | ||||||
|  | @ -67,6 +87,9 @@ impl<T: CommonMOpTrait> MOpTrait for T { | ||||||
|     fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> { |     fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> { | ||||||
|         T::common_mop(input).dest |         T::common_mop(input).dest | ||||||
|     } |     } | ||||||
|  |     fn src_reg_width(self) -> <Self::SrcRegWidth as Size>::SizeType { | ||||||
|  |         self.common_mop_ty().src.element().width | ||||||
|  |     } | ||||||
|     fn for_each_src_reg( |     fn for_each_src_reg( | ||||||
|         input: impl ToExpr<Type = Self>, |         input: impl ToExpr<Type = Self>, | ||||||
|         f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize), |         f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize), | ||||||
|  | @ -129,13 +152,23 @@ pub enum OutputIntegerMode { | ||||||
|     SignExt8, |     SignExt8, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl ExprPartialEq<Self> for OutputIntegerMode { | ||||||
|  |     fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> { | ||||||
|  |         lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> { | ||||||
|  |         lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub const MOP_IMM_WIDTH: usize = 34; | pub const MOP_IMM_WIDTH: usize = 34; | ||||||
| pub const MOP_MIN_REG_WIDTH: usize = 8; | pub const MOP_MIN_REG_WIDTH: usize = 8; | ||||||
| pub const COMMON_MOP_SRC_LEN: usize = 3; | pub const COMMON_MOP_SRC_LEN: usize = 3; | ||||||
| pub const COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM: usize = 2; | pub const COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM: usize = 2; | ||||||
| pub const COMMON_MOP_IMM_LOW_WIDTH: usize = CommonMOpWithMaxSrcCount::IMM_WIDTH - 1; | pub const COMMON_MOP_IMM_LOW_WIDTH: usize = CommonMOpWithMaxSrcCount::IMM_WIDTH - 1; | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct CommonMOp<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> { | pub struct CommonMOp<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> { | ||||||
|     pub prefix_pad: UIntType<PrefixPad>, |     pub prefix_pad: UIntType<PrefixPad>, | ||||||
|     pub dest: DestReg, |     pub dest: DestReg, | ||||||
|  | @ -181,7 +214,7 @@ impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct CommonMOpImmParts<ImmInSrcCount: Size> { | pub struct CommonMOpImmParts<ImmInSrcCount: Size> { | ||||||
|     // fields must be in this exact order
 |     // fields must be in this exact order
 | ||||||
|     pub imm_low: UInt<{ COMMON_MOP_IMM_LOW_WIDTH }>, |     pub imm_low: UInt<{ COMMON_MOP_IMM_LOW_WIDTH }>, | ||||||
|  | @ -410,6 +443,9 @@ macro_rules! mop_enum { | ||||||
|                 } |                 } | ||||||
|                 dest_reg |                 dest_reg | ||||||
|             } |             } | ||||||
|  |             fn src_reg_width(self) -> <Self::SrcRegWidth as Size>::SizeType { | ||||||
|  |                 self.$FirstVariant.src_reg_width() | ||||||
|  |             } | ||||||
|             #[hdl] |             #[hdl] | ||||||
|             fn for_each_src_reg( |             fn for_each_src_reg( | ||||||
|                 input: impl ToExpr<Type = Self>, |                 input: impl ToExpr<Type = Self>, | ||||||
|  | @ -458,7 +494,7 @@ pub(crate) use mop_enum; | ||||||
| 
 | 
 | ||||||
| common_mop_struct! { | common_mop_struct! { | ||||||
|     #[mapped(<NewDestReg, NewSrcRegWidth> AluCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)] |     #[mapped(<NewDestReg, NewSrcRegWidth> AluCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)] | ||||||
|     #[hdl] |     #[hdl(cmp_eq)] | ||||||
|     pub struct AluCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> { |     pub struct AluCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> { | ||||||
|         #[common] |         #[common] | ||||||
|         pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount>, |         pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount>, | ||||||
|  | @ -468,7 +504,7 @@ common_mop_struct! { | ||||||
| 
 | 
 | ||||||
| common_mop_struct! { | common_mop_struct! { | ||||||
|     #[mapped(<NewDestReg, NewSrcRegWidth> AddSubMOp<NewDestReg, NewSrcRegWidth, SrcCount>)] |     #[mapped(<NewDestReg, NewSrcRegWidth> AddSubMOp<NewDestReg, NewSrcRegWidth, SrcCount>)] | ||||||
|     #[hdl] |     #[hdl(cmp_eq)] | ||||||
|     pub struct AddSubMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> { |     pub struct AddSubMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> { | ||||||
|         #[common] |         #[common] | ||||||
|         pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount>, |         pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount>, | ||||||
|  | @ -481,7 +517,7 @@ common_mop_struct! { | ||||||
| 
 | 
 | ||||||
| common_mop_struct! { | common_mop_struct! { | ||||||
|     #[mapped(<NewDestReg, NewSrcRegWidth> LogicalMOp<NewDestReg, NewSrcRegWidth>)] |     #[mapped(<NewDestReg, NewSrcRegWidth> LogicalMOp<NewDestReg, NewSrcRegWidth>)] | ||||||
|     #[hdl] |     #[hdl(cmp_eq)] | ||||||
|     pub struct LogicalMOp<DestReg: Type, SrcRegWidth: Size> { |     pub struct LogicalMOp<DestReg: Type, SrcRegWidth: Size> { | ||||||
|         #[common] |         #[common] | ||||||
|         pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>, |         pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>, | ||||||
|  | @ -491,7 +527,7 @@ common_mop_struct! { | ||||||
| 
 | 
 | ||||||
| common_mop_struct! { | common_mop_struct! { | ||||||
|     #[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth>)] |     #[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth>)] | ||||||
|     #[hdl] |     #[hdl(cmp_eq)] | ||||||
|     pub struct BranchMOp<DestReg: Type, SrcRegWidth: Size> { |     pub struct BranchMOp<DestReg: Type, SrcRegWidth: Size> { | ||||||
|         #[common] |         #[common] | ||||||
|         pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>, |         pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>, | ||||||
|  | @ -510,7 +546,7 @@ mop_enum! { | ||||||
| 
 | 
 | ||||||
| common_mop_struct! { | common_mop_struct! { | ||||||
|     #[mapped(<NewDestReg, NewSrcRegWidth> ReadL2RegMOp<NewDestReg, NewSrcRegWidth>)] |     #[mapped(<NewDestReg, NewSrcRegWidth> ReadL2RegMOp<NewDestReg, NewSrcRegWidth>)] | ||||||
|     #[hdl] |     #[hdl(cmp_eq)] | ||||||
|     pub struct ReadL2RegMOp<DestReg: Type, SrcRegWidth: Size> { |     pub struct ReadL2RegMOp<DestReg: Type, SrcRegWidth: Size> { | ||||||
|         #[common] |         #[common] | ||||||
|         pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<0>>, |         pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<0>>, | ||||||
|  | @ -519,7 +555,7 @@ common_mop_struct! { | ||||||
| 
 | 
 | ||||||
| common_mop_struct! { | common_mop_struct! { | ||||||
|     #[mapped(<NewDestReg, NewSrcRegWidth> WriteL2RegMOp<NewDestReg, NewSrcRegWidth>)] |     #[mapped(<NewDestReg, NewSrcRegWidth> WriteL2RegMOp<NewDestReg, NewSrcRegWidth>)] | ||||||
|     #[hdl] |     #[hdl(cmp_eq)] | ||||||
|     pub struct WriteL2RegMOp<DestReg: Type, SrcRegWidth: Size> { |     pub struct WriteL2RegMOp<DestReg: Type, SrcRegWidth: Size> { | ||||||
|         #[common] |         #[common] | ||||||
|         pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<1>>, |         pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<1>>, | ||||||
|  | @ -536,7 +572,7 @@ mop_enum! { | ||||||
| 
 | 
 | ||||||
| common_mop_struct! { | common_mop_struct! { | ||||||
|     #[mapped(<NewDestReg, NewSrcRegWidth> LoadStoreCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)] |     #[mapped(<NewDestReg, NewSrcRegWidth> LoadStoreCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)] | ||||||
|     #[hdl] |     #[hdl(cmp_eq)] | ||||||
|     pub struct LoadStoreCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> { |     pub struct LoadStoreCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> { | ||||||
|         #[common] |         #[common] | ||||||
|         pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, SrcCount>, |         pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, SrcCount>, | ||||||
|  | @ -545,7 +581,7 @@ common_mop_struct! { | ||||||
| 
 | 
 | ||||||
| common_mop_struct! { | common_mop_struct! { | ||||||
|     #[mapped(<NewDestReg, NewSrcRegWidth> LoadMOp<NewDestReg, NewSrcRegWidth>)] |     #[mapped(<NewDestReg, NewSrcRegWidth> LoadMOp<NewDestReg, NewSrcRegWidth>)] | ||||||
|     #[hdl] |     #[hdl(cmp_eq)] | ||||||
|     pub struct LoadMOp<DestReg: Type, SrcRegWidth: Size> { |     pub struct LoadMOp<DestReg: Type, SrcRegWidth: Size> { | ||||||
|         #[common] |         #[common] | ||||||
|         pub load_store_common: LoadStoreCommonMOp<DestReg, SrcRegWidth, ConstUsize<1>>, |         pub load_store_common: LoadStoreCommonMOp<DestReg, SrcRegWidth, ConstUsize<1>>, | ||||||
|  | @ -554,7 +590,7 @@ common_mop_struct! { | ||||||
| 
 | 
 | ||||||
| common_mop_struct! { | common_mop_struct! { | ||||||
|     #[mapped(<NewDestReg, NewSrcRegWidth> StoreMOp<NewDestReg, NewSrcRegWidth>)] |     #[mapped(<NewDestReg, NewSrcRegWidth> StoreMOp<NewDestReg, NewSrcRegWidth>)] | ||||||
|     #[hdl] |     #[hdl(cmp_eq)] | ||||||
|     pub struct StoreMOp<DestReg: Type, SrcRegWidth: Size> { |     pub struct StoreMOp<DestReg: Type, SrcRegWidth: Size> { | ||||||
|         #[common] |         #[common] | ||||||
|         pub load_store_common: LoadStoreCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>, |         pub load_store_common: LoadStoreCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>, | ||||||
|  | @ -569,7 +605,7 @@ mop_enum! { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| /// there may be more than one unit of a given kind, so UnitNum is not the same as UnitKind.
 | /// there may be more than one unit of a given kind, so UnitNum is not the same as UnitKind.
 | ||||||
| /// zero is used for built-in constants, such as the zero register
 | /// zero is used for built-in constants, such as the zero register
 | ||||||
| pub struct UnitNum<Width: Size> { | pub struct UnitNum<Width: Size> { | ||||||
|  | @ -617,12 +653,12 @@ impl<Width: Size> UnitNum<Width> { | ||||||
| 
 | 
 | ||||||
| pub const CONST_ZERO_UNIT_NUM: usize = 0; | pub const CONST_ZERO_UNIT_NUM: usize = 0; | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct UnitOutRegNum<Width: Size> { | pub struct UnitOutRegNum<Width: Size> { | ||||||
|     pub value: UIntType<Width>, |     pub value: UIntType<Width>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| /// Physical Register Number -- registers in the CPU's backend
 | /// Physical Register Number -- registers in the CPU's backend
 | ||||||
| pub struct PRegNum<UnitNumWidth: Size, OutRegNumWidth: Size> { | pub struct PRegNum<UnitNumWidth: Size, OutRegNumWidth: Size> { | ||||||
|     pub unit_num: UnitNum<UnitNumWidth>, |     pub unit_num: UnitNum<UnitNumWidth>, | ||||||
|  | @ -643,7 +679,7 @@ impl<UnitNumWidth: Size, OutRegNumWidth: Size> PRegNum<UnitNumWidth, OutRegNumWi | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| /// µOp Register Number -- register in a micro-operation before register renaming
 | /// µ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 = "UOpRegNum")] // help you find it in the docs if you mis-spell it
 | ||||||
| #[doc(alias = "\u{B5}OpRegNum")] // micro sign
 | #[doc(alias = "\u{B5}OpRegNum")] // micro sign
 | ||||||
|  | @ -681,7 +717,7 @@ impl MOpRegNum { | ||||||
|         Self::CONST_ZERO_REG_NUM + 1..Self::SPECIAL_REG_NUMS.start; |         Self::CONST_ZERO_REG_NUM + 1..Self::SPECIAL_REG_NUMS.start; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| /// all the registers this instruction will write to, they are all renamed to the same physical register.
 | /// all the registers this instruction will write to, they are all renamed to the same physical register.
 | ||||||
| pub struct MOpDestReg { | pub struct MOpDestReg { | ||||||
|     /// some instructions have multiple destination registers, e.g. x86 div
 |     /// some instructions have multiple destination registers, e.g. x86 div
 | ||||||
|  |  | ||||||
|  | @ -4,22 +4,22 @@ use crate::{instruction::MOpRegNum, util::range_u32_nth_or_panic}; | ||||||
| use fayalite::prelude::*; | use fayalite::prelude::*; | ||||||
| use std::ops::Range; | use std::ops::Range; | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct PowerIsaRegNum { | pub struct PowerIsaRegNum { | ||||||
|     pub value: UInt<5>, |     pub value: UInt<5>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct PowerIsaFRegNum { | pub struct PowerIsaFRegNum { | ||||||
|     pub value: UInt<5>, |     pub value: UInt<5>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct PowerIsaCrFieldNum { | pub struct PowerIsaCrFieldNum { | ||||||
|     pub value: UInt<3>, |     pub value: UInt<3>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct PowerIsaCrBitNum { | pub struct PowerIsaCrBitNum { | ||||||
|     pub cr_field: PowerIsaCrFieldNum, |     pub cr_field: PowerIsaCrFieldNum, | ||||||
|     pub bit_in_field: UInt<2>, |     pub bit_in_field: UInt<2>, | ||||||
|  |  | ||||||
|  | @ -311,7 +311,7 @@ pub fn reg_alloc(config: &CpuConfig) { | ||||||
|             SourceLocation::caller(), |             SourceLocation::caller(), | ||||||
|         ); |         ); | ||||||
|         connect(dyn_unit.cd(unit), cd); |         connect(dyn_unit.cd(unit), cd); | ||||||
|         let unit_input_insn = dyn_unit.input_insn(unit); |         let unit_to_reg_alloc = dyn_unit.unit_to_reg_alloc(unit); | ||||||
|         // TODO: handle assigning multiple instructions to a unit at a time
 |         // TODO: handle assigning multiple instructions to a unit at a time
 | ||||||
|         let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap(); |         let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap(); | ||||||
|         // TODO: handle retiring multiple instructions from a unit at a time
 |         // TODO: handle retiring multiple instructions from a unit at a time
 | ||||||
|  | @ -333,8 +333,8 @@ pub fn reg_alloc(config: &CpuConfig) { | ||||||
|         ); |         ); | ||||||
|         connect(unit_free_regs_tracker.alloc_out[0].ready, false); |         connect(unit_free_regs_tracker.alloc_out[0].ready, false); | ||||||
|         connect( |         connect( | ||||||
|             unit_input_insn.data, |             unit_to_reg_alloc.input_insn.data, | ||||||
|             Expr::ty(unit_input_insn).data.HdlNone(), |             Expr::ty(unit_to_reg_alloc.input_insn).data.HdlNone(), | ||||||
|         ); |         ); | ||||||
|         for fetch_index in 0..config.fetch_width.get() { |         for fetch_index in 0..config.fetch_width.get() { | ||||||
|             #[hdl] |             #[hdl] | ||||||
|  | @ -343,7 +343,7 @@ pub fn reg_alloc(config: &CpuConfig) { | ||||||
|                 connect(available_units[fetch_index][unit_index], false); |                 connect(available_units[fetch_index][unit_index], false); | ||||||
|             } |             } | ||||||
|             #[hdl] |             #[hdl] | ||||||
|             if !unit_input_insn.ready { |             if !unit_to_reg_alloc.input_insn.ready { | ||||||
|                 // must come after to override connects in loops above
 |                 // must come after to override connects in loops above
 | ||||||
|                 connect(available_units[fetch_index][unit_index], false); |                 connect(available_units[fetch_index][unit_index], false); | ||||||
|             } |             } | ||||||
|  | @ -356,11 +356,11 @@ pub fn reg_alloc(config: &CpuConfig) { | ||||||
|                     if let HdlSome(renamed_mop) = |                     if let HdlSome(renamed_mop) = | ||||||
|                         HdlOption::and_then(renamed_mops[fetch_index], |v| dyn_unit.extract_mop(v)) |                         HdlOption::and_then(renamed_mops[fetch_index], |v| dyn_unit.extract_mop(v)) | ||||||
|                     { |                     { | ||||||
|                         connect(unit_input_insn.data, HdlSome(renamed_mop)); |                         connect(unit_to_reg_alloc.input_insn.data, HdlSome(renamed_mop)); | ||||||
|                     } else { |                     } else { | ||||||
|                         connect( |                         connect( | ||||||
|                             unit_input_insn.data, |                             unit_to_reg_alloc.input_insn.data, | ||||||
|                             HdlSome(Expr::ty(unit_input_insn).data.HdlSome.uninit()), |                             HdlSome(Expr::ty(unit_to_reg_alloc.input_insn).data.HdlSome.uninit()), | ||||||
|                         ); |                         ); | ||||||
|                         // FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
 |                         // FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
 | ||||||
|                     } |                     } | ||||||
|  | @ -387,7 +387,7 @@ pub fn reg_alloc(config: &CpuConfig) { | ||||||
|         } |         } | ||||||
|         // TODO: connect outputs to other units
 |         // TODO: connect outputs to other units
 | ||||||
|         connect( |         connect( | ||||||
|             dyn_unit.unit_forwarding_info(unit), |             unit_to_reg_alloc.unit_forwarding_info, | ||||||
|             #[hdl] |             #[hdl] | ||||||
|             UnitForwardingInfo::<_, _, _> { |             UnitForwardingInfo::<_, _, _> { | ||||||
|                 unit_output_writes: repeat( |                 unit_output_writes: repeat( | ||||||
|  | @ -397,10 +397,9 @@ pub fn reg_alloc(config: &CpuConfig) { | ||||||
|                 _phantom: PhantomData, |                 _phantom: PhantomData, | ||||||
|             }, |             }, | ||||||
|         ); |         ); | ||||||
|         connect(dyn_unit.output(unit).ready, false); |  | ||||||
|         // TODO: handle cancellation
 |         // TODO: handle cancellation
 | ||||||
|         connect( |         connect( | ||||||
|             dyn_unit.cancel_input(unit).data, |             unit_to_reg_alloc.cancel_input, | ||||||
|             HdlOption[config.unit_cancel_input()].HdlNone(), |             HdlOption[config.unit_cancel_input()].HdlNone(), | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ pub enum FlagsMode { | ||||||
|     X86(PRegFlagsX86), |     X86(PRegFlagsX86), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct PRegFlagsPowerISA {} | pub struct PRegFlagsPowerISA {} | ||||||
| 
 | 
 | ||||||
| impl PRegFlagsPowerISA { | impl PRegFlagsPowerISA { | ||||||
|  | @ -56,7 +56,7 @@ impl PRegFlagsPowerISA { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct PRegFlagsX86 {} | pub struct PRegFlagsX86 {} | ||||||
| 
 | 
 | ||||||
| impl PRegFlagsX86 { | impl PRegFlagsX86 { | ||||||
|  | @ -100,7 +100,7 @@ impl PRegFlagsX86 { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| /// this is *not* the same as any particular ISA's flags register,
 | /// 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.
 | /// on PowerISA it is a combination of some bits from XER with a single 4-bit CR field.
 | ||||||
| ///
 | ///
 | ||||||
|  | @ -138,7 +138,7 @@ impl PRegFlags { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| /// Unit output register's value -- a combination of an integer/fp register
 | /// Unit output register's value -- a combination of an integer/fp register
 | ||||||
| /// and flags register and CR field.
 | /// and flags register and CR field.
 | ||||||
| ///
 | ///
 | ||||||
|  |  | ||||||
|  | @ -7,13 +7,12 @@ use crate::{ | ||||||
|         mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, UnitOutRegNum, |         mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, UnitOutRegNum, | ||||||
|     }, |     }, | ||||||
|     register::PRegValue, |     register::PRegValue, | ||||||
|     unit::unit_base::UnitForwardingInfo, |     unit::unit_base::UnitToRegAlloc, | ||||||
| }; | }; | ||||||
| use fayalite::{ | use fayalite::{ | ||||||
|     bundle::{Bundle, BundleType}, |     bundle::{Bundle, BundleType}, | ||||||
|     intern::{Intern, Interned}, |     intern::{Intern, Interned}, | ||||||
|     prelude::*, |     prelude::*, | ||||||
|     util::ready_valid::ReadyValid, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| pub mod alu_branch; | pub mod alu_branch; | ||||||
|  | @ -143,19 +142,19 @@ all_units! { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct UnitResultCompleted<ExtraOut> { | pub struct UnitResultCompleted<ExtraOut> { | ||||||
|     pub value: PRegValue, |     pub value: PRegValue, | ||||||
|     pub extra_out: ExtraOut, |     pub extra_out: ExtraOut, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct UnitOutputWrite<OutRegNumWidth: Size> { | pub struct UnitOutputWrite<OutRegNumWidth: Size> { | ||||||
|     pub which: UnitOutRegNum<OutRegNumWidth>, |     pub which: UnitOutRegNum<OutRegNumWidth>, | ||||||
|     pub value: PRegValue, |     pub value: PRegValue, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl(cmp_eq)] | ||||||
| pub struct TrapData { | pub struct TrapData { | ||||||
|     // TODO
 |     // TODO
 | ||||||
| } | } | ||||||
|  | @ -166,13 +165,25 @@ pub enum UnitResult<ExtraOut> { | ||||||
|     Trap(TrapData), |     Trap(TrapData), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl<ExtraOut: Type> UnitResult<ExtraOut> { | ||||||
|  |     pub fn extra_out_ty(self) -> ExtraOut { | ||||||
|  |         self.Completed.extra_out | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[hdl] | #[hdl] | ||||||
| pub struct UnitOutput<OutRegNumWidth: Size, ExtraOut> { | pub struct UnitOutput<OutRegNumWidth: Size, ExtraOut> { | ||||||
|     pub which: UnitOutRegNum<OutRegNumWidth>, |     pub which: UnitOutRegNum<OutRegNumWidth>, | ||||||
|     pub result: UnitResult<ExtraOut>, |     pub result: UnitResult<ExtraOut>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | impl<OutRegNumWidth: Size, ExtraOut: Type> UnitOutput<OutRegNumWidth, ExtraOut> { | ||||||
|  |     pub fn extra_out_ty(self) -> ExtraOut { | ||||||
|  |         self.result.extra_out_ty() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[hdl(cmp_eq)] | ||||||
| pub struct UnitCancelInput<OutRegNumWidth: Size> { | pub struct UnitCancelInput<OutRegNumWidth: Size> { | ||||||
|     pub which: UnitOutRegNum<OutRegNumWidth>, |     pub which: UnitOutRegNum<OutRegNumWidth>, | ||||||
| } | } | ||||||
|  | @ -197,19 +208,10 @@ pub trait UnitTrait: | ||||||
| 
 | 
 | ||||||
|     fn module(&self) -> Interned<Module<Self::Type>>; |     fn module(&self) -> Interned<Module<Self::Type>>; | ||||||
| 
 | 
 | ||||||
|     fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>>; |     fn unit_to_reg_alloc( | ||||||
| 
 |  | ||||||
|     fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>>; |  | ||||||
| 
 |  | ||||||
|     fn unit_forwarding_info( |  | ||||||
|         &self, |         &self, | ||||||
|         this: Expr<Self::Type>, |         this: Expr<Self::Type>, | ||||||
|     ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>>; |     ) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>>; | ||||||
| 
 |  | ||||||
|     fn output( |  | ||||||
|         &self, |  | ||||||
|         this: Expr<Self::Type>, |  | ||||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>>; |  | ||||||
| 
 | 
 | ||||||
|     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>; |     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>; | ||||||
| 
 | 
 | ||||||
|  | @ -266,26 +268,11 @@ impl UnitTrait for DynUnit { | ||||||
|         self.unit.module() |         self.unit.module() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { |     fn unit_to_reg_alloc( | ||||||
|         self.unit.input_insn(this) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>> { |  | ||||||
|         self.unit.cancel_input(this) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn unit_forwarding_info( |  | ||||||
|         &self, |         &self, | ||||||
|         this: Expr<Self::Type>, |         this: Expr<Self::Type>, | ||||||
|     ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> { |     ) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> { | ||||||
|         self.unit.unit_forwarding_info(this) |         self.unit.unit_to_reg_alloc(this) | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn output( |  | ||||||
|         &self, |  | ||||||
|         this: Expr<Self::Type>, |  | ||||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> { |  | ||||||
|         self.unit.output(this) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> { |     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> { | ||||||
|  | @ -332,26 +319,13 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T | ||||||
|         self.0.module().canonical().intern_sized() |         self.0.module().canonical().intern_sized() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { |     fn unit_to_reg_alloc( | ||||||
|         Expr::from_bundle(Expr::as_bundle(self.0.input_insn(Expr::from_bundle(this)))) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     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, |         &self, | ||||||
|         this: Expr<Self::Type>, |         this: Expr<Self::Type>, | ||||||
|     ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> { |     ) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> { | ||||||
|         self.0.unit_forwarding_info(Expr::from_bundle(this)) |         Expr::from_bundle(Expr::as_bundle( | ||||||
|     } |             self.0.unit_to_reg_alloc(Expr::from_bundle(this)), | ||||||
| 
 |         )) | ||||||
|     fn output( |  | ||||||
|         &self, |  | ||||||
|         this: Expr<Self::Type>, |  | ||||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> { |  | ||||||
|         Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this)))) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> { |     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> { | ||||||
|  |  | ||||||
|  | @ -5,14 +5,13 @@ use crate::{ | ||||||
|     config::CpuConfig, |     config::CpuConfig, | ||||||
|     instruction::{AluBranchMOp, UnitOutRegNum}, |     instruction::{AluBranchMOp, UnitOutRegNum}, | ||||||
|     unit::{ |     unit::{ | ||||||
|         unit_base::{unit_base, UnitForwardingInfo}, |         unit_base::{unit_base, UnitToRegAlloc}, | ||||||
|         DynUnit, DynUnitWrapper, UnitCancelInput, UnitKind, UnitMOp, UnitOutput, UnitTrait, |         DynUnit, DynUnitWrapper, UnitKind, UnitMOp, UnitTrait, | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
| use fayalite::{ | use fayalite::{ | ||||||
|     intern::{Intern, Interned}, |     intern::{Intern, Interned}, | ||||||
|     prelude::*, |     prelude::*, | ||||||
|     util::ready_valid::ReadyValid, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #[hdl_module] | #[hdl_module] | ||||||
|  | @ -20,30 +19,30 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) { | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let cd: ClockDomain = m.input(); |     let cd: ClockDomain = m.input(); | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let input_insn: ReadyValid<AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>> = |     let unit_to_reg_alloc: UnitToRegAlloc< | ||||||
|         m.input(ReadyValid[AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()]]); |         AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>, | ||||||
|     #[hdl] |         (), | ||||||
|     let unit_forwarding_info: UnitForwardingInfo<DynSize, DynSize, DynSize> = |         DynSize, | ||||||
|         m.input(config.unit_forwarding_info()); |         DynSize, | ||||||
|     #[hdl] |         DynSize, | ||||||
|     let cancel_input: ReadyValid<UnitCancelInput<DynSize>> = |     > = m.output(config.unit_to_reg_alloc( | ||||||
|         m.input(ReadyValid[config.unit_cancel_input()]); |         AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()], | ||||||
|     #[hdl] |         (), | ||||||
|     let output: ReadyValid<UnitOutput<DynSize, ()>> = |     )); | ||||||
|         m.output(ReadyValid[UnitOutput[config.out_reg_num_width][()]]); |  | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let unit_base = instance(unit_base( |     let unit_base = instance(unit_base( | ||||||
|         config, |         config, | ||||||
|         unit_index, |         unit_index, | ||||||
|         Expr::ty(input_insn).data.HdlSome, |         Expr::ty(unit_to_reg_alloc).input_insn.data.HdlSome, | ||||||
|  |         (), | ||||||
|     )); |     )); | ||||||
|     connect(unit_base.input_insn, input_insn); |     connect(unit_to_reg_alloc, unit_base.unit_to_reg_alloc); | ||||||
|     connect(unit_base.cd, cd); |     connect(unit_base.cd, cd); | ||||||
|     connect(unit_base.unit_forwarding_info, unit_forwarding_info); |     connect(unit_base.execute_start.ready, true); // TODO: finish
 | ||||||
|     connect(unit_base.cancel_input, cancel_input); |     connect( | ||||||
|     // TODO: finish
 |         unit_base.execute_end, | ||||||
|     connect(unit_base.ready_mop.ready, true); |         Expr::ty(unit_base.execute_end).HdlNone(), | ||||||
|     connect(output.data, Expr::ty(output.data).HdlNone()); |     ); // TODO: finish
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||||||
|  | @ -75,7 +74,7 @@ impl UnitTrait for AluBranch { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn mop_ty(&self) -> Self::MOp { |     fn mop_ty(&self) -> Self::MOp { | ||||||
|         self.module.io_ty().input_insn.data.HdlSome |         self.module.io_ty().unit_to_reg_alloc.mop_ty() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn unit_kind(&self) -> UnitKind { |     fn unit_kind(&self) -> UnitKind { | ||||||
|  | @ -93,26 +92,11 @@ impl UnitTrait for AluBranch { | ||||||
|         self.module |         self.module | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { |     fn unit_to_reg_alloc( | ||||||
|         this.input_insn |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>> { |  | ||||||
|         this.cancel_input |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn unit_forwarding_info( |  | ||||||
|         &self, |         &self, | ||||||
|         this: Expr<Self::Type>, |         this: Expr<Self::Type>, | ||||||
|     ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> { |     ) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> { | ||||||
|         this.unit_forwarding_info |         this.unit_to_reg_alloc | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn output( |  | ||||||
|         &self, |  | ||||||
|         this: Expr<Self::Type>, |  | ||||||
|     ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> { |  | ||||||
|         this.output |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> { |     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> { | ||||||
|  |  | ||||||
|  | @ -3,9 +3,9 @@ | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     config::CpuConfig, |     config::CpuConfig, | ||||||
|     instruction::{MOpTrait, UnitOutRegNum, COMMON_MOP_SRC_LEN}, |     instruction::{MOpTrait, PRegNum, UnitOutRegNum, COMMON_MOP_SRC_LEN}, | ||||||
|     register::PRegValue, |     register::PRegValue, | ||||||
|     unit::{UnitCancelInput, UnitOutputWrite}, |     unit::{UnitCancelInput, UnitOutput, UnitOutputWrite}, | ||||||
|     util::tree_reduce::tree_reduce, |     util::tree_reduce::tree_reduce, | ||||||
| }; | }; | ||||||
| use fayalite::{module::wire_with_loc, prelude::*, ty::StaticType, util::ready_valid::ReadyValid}; | use fayalite::{module::wire_with_loc, prelude::*, ty::StaticType, util::ready_valid::ReadyValid}; | ||||||
|  | @ -18,113 +18,439 @@ pub struct UnitForwardingInfo<UnitNumWidth: Size, OutRegNumWidth: Size, UnitCoun | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl] | ||||||
| pub struct ReadyMOp<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> { | pub struct UnitToRegAlloc< | ||||||
|  |     MOp: Type, | ||||||
|  |     ExtraOut: Type, | ||||||
|  |     UnitNumWidth: Size, | ||||||
|  |     OutRegNumWidth: Size, | ||||||
|  |     UnitCount: Size, | ||||||
|  | > { | ||||||
|  |     #[hdl(flip)] | ||||||
|  |     pub unit_forwarding_info: UnitForwardingInfo<UnitNumWidth, OutRegNumWidth, UnitCount>, | ||||||
|  |     #[hdl(flip)] | ||||||
|  |     pub input_insn: ReadyValid<MOp>, | ||||||
|  |     #[hdl(flip)] | ||||||
|  |     pub cancel_input: HdlOption<UnitCancelInput<OutRegNumWidth>>, | ||||||
|  |     pub output: HdlOption<UnitOutput<OutRegNumWidth, ExtraOut>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<MOp: Type, ExtraOut: Type, UnitNumWidth: Size, OutRegNumWidth: Size, UnitCount: Size> | ||||||
|  |     UnitToRegAlloc<MOp, ExtraOut, UnitNumWidth, OutRegNumWidth, UnitCount> | ||||||
|  | { | ||||||
|  |     pub fn mop_ty(self) -> MOp { | ||||||
|  |         self.input_insn.data.HdlSome | ||||||
|  |     } | ||||||
|  |     pub fn extra_out_ty(self) -> ExtraOut { | ||||||
|  |         self.output.HdlSome.extra_out_ty() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[hdl] | ||||||
|  | pub struct ExecuteStart<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> { | ||||||
|     pub mop: MOp, |     pub mop: MOp, | ||||||
|     pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>, |     pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl] | #[hdl] | ||||||
| struct InFlightOp<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> { | pub struct ExecuteEnd<OutRegNumWidth: Size, ExtraOut> { | ||||||
|     pub mop: MOp, |     pub unit_output: UnitOutput<OutRegNumWidth, ExtraOut>, | ||||||
|     pub src_values: Array<HdlOption<PRegValue>, { COMMON_MOP_SRC_LEN }>, | } | ||||||
|  | 
 | ||||||
|  | #[hdl] | ||||||
|  | enum InFlightOpState { | ||||||
|  |     Ready, | ||||||
|  |     Running, | ||||||
|  |     CanceledAndRunning, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl InFlightOpState { | ||||||
|  |     fn ready_next_state(canceling: bool, starting: bool, ending: bool) -> Expr<HdlOption<Self>> { | ||||||
|  |         match (canceling, starting, ending) { | ||||||
|  |             (false, false, _) => HdlSome(InFlightOpState.Ready()), | ||||||
|  |             (false, true, false) => HdlSome(InFlightOpState.Running()), | ||||||
|  |             (false, true, true) => HdlNone(), | ||||||
|  |             (true, false, _) => HdlNone(), | ||||||
|  |             (true, true, false) => HdlSome(InFlightOpState.CanceledAndRunning()), | ||||||
|  |             (true, true, true) => HdlNone(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn running_next_state(canceling: bool, _starting: bool, ending: bool) -> Expr<HdlOption<Self>> { | ||||||
|  |         match (canceling, ending) { | ||||||
|  |             (false, false) => HdlSome(InFlightOpState.Running()), | ||||||
|  |             (false, true) => HdlNone(), | ||||||
|  |             (true, false) => HdlSome(InFlightOpState.CanceledAndRunning()), | ||||||
|  |             (true, true) => HdlNone(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     fn canceled_and_running_next_state( | ||||||
|  |         _canceling: bool, | ||||||
|  |         _starting: bool, | ||||||
|  |         ending: bool, | ||||||
|  |     ) -> Expr<HdlOption<Self>> { | ||||||
|  |         if ending { | ||||||
|  |             HdlNone() | ||||||
|  |         } else { | ||||||
|  |             HdlSome(InFlightOpState.CanceledAndRunning()) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     /// FIXME: this is working around #[hdl] match not supporting matching values inside structs yet
 | ||||||
|  |     #[hdl] | ||||||
|  |     fn connect_next_state( | ||||||
|  |         canceling: Expr<Bool>, | ||||||
|  |         starting: Expr<Bool>, | ||||||
|  |         ending: Expr<Bool>, | ||||||
|  |         next_state_fn: fn(canceling: bool, starting: bool, ending: bool) -> Expr<HdlOption<Self>>, | ||||||
|  |         next_state: Expr<HdlOption<Self>>, | ||||||
|  |     ) { | ||||||
|  |         #[hdl] | ||||||
|  |         fn recurse<const N: usize>( | ||||||
|  |             exprs: &[Expr<Bool>; N], | ||||||
|  |             bools: &mut [bool; N], | ||||||
|  |             f: &mut impl FnMut(&[bool; N]), | ||||||
|  |             arg_index: usize, | ||||||
|  |         ) { | ||||||
|  |             if arg_index < N { | ||||||
|  |                 #[hdl] | ||||||
|  |                 if exprs[arg_index] { | ||||||
|  |                     bools[arg_index] = true; | ||||||
|  |                     recurse(exprs, bools, f, arg_index + 1); | ||||||
|  |                 } else { | ||||||
|  |                     bools[arg_index] = false; | ||||||
|  |                     recurse(exprs, bools, f, arg_index + 1); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 f(bools); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         recurse( | ||||||
|  |             &[canceling, starting, ending], | ||||||
|  |             &mut [false; 3], | ||||||
|  |             &mut |&[canceling, starting, ending]| { | ||||||
|  |                 connect(next_state, next_state_fn(canceling, starting, ending)) | ||||||
|  |             }, | ||||||
|  |             0, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[hdl] | ||||||
|  | struct InFlightOp<MOp: Type> { | ||||||
|  |     state: InFlightOpState, | ||||||
|  |     mop: MOp, | ||||||
|  |     src_ready_flags: Array<Bool, { COMMON_MOP_SRC_LEN }>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[hdl] | ||||||
|  | struct InFlightOpsSummary<OpIndexWidth: Size> { | ||||||
|  |     empty_op_index: HdlOption<UIntType<OpIndexWidth>>, | ||||||
|  |     ready_op_index: HdlOption<UIntType<OpIndexWidth>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<OpIndexWidth: Size> InFlightOpsSummary<OpIndexWidth> { | ||||||
|  |     #[hdl] | ||||||
|  |     fn new<MOp: Type>( | ||||||
|  |         op_index: usize, | ||||||
|  |         op_index_ty: UIntType<OpIndexWidth>, | ||||||
|  |         in_flight_op: impl ToExpr<Type = HdlOption<InFlightOp<MOp>>>, | ||||||
|  |     ) -> Expr<Self> { | ||||||
|  |         let empty_op_index = wire_with_loc( | ||||||
|  |             &format!("empty_op_index_{op_index}"), | ||||||
|  |             SourceLocation::caller(), | ||||||
|  |             HdlOption[op_index_ty], | ||||||
|  |         ); | ||||||
|  |         connect(empty_op_index, HdlOption[op_index_ty].HdlNone()); | ||||||
|  |         let ready_op_index = wire_with_loc( | ||||||
|  |             &format!("ready_op_index_{op_index}"), | ||||||
|  |             SourceLocation::caller(), | ||||||
|  |             HdlOption[op_index_ty], | ||||||
|  |         ); | ||||||
|  |         connect(ready_op_index, HdlOption[op_index_ty].HdlNone()); | ||||||
|  |         #[hdl] | ||||||
|  |         if let HdlSome(in_flight_op) = in_flight_op { | ||||||
|  |             #[hdl] | ||||||
|  |             let InFlightOp::<_> { | ||||||
|  |                 state, | ||||||
|  |                 mop: _, | ||||||
|  |                 src_ready_flags, | ||||||
|  |             } = in_flight_op; | ||||||
|  |             connect(ready_op_index, HdlOption[op_index_ty].HdlNone()); | ||||||
|  |             #[hdl] | ||||||
|  |             match state { | ||||||
|  |                 InFlightOpState::Ready => | ||||||
|  |                 { | ||||||
|  |                     #[hdl] | ||||||
|  |                     if src_ready_flags.cmp_eq([true; COMMON_MOP_SRC_LEN]) { | ||||||
|  |                         connect(ready_op_index, HdlSome(op_index.cast_to(op_index_ty))); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 InFlightOpState::CanceledAndRunning | InFlightOpState::Running => {} | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             connect(empty_op_index, HdlSome(op_index.cast_to(op_index_ty))); | ||||||
|  |         } | ||||||
|  |         #[hdl] | ||||||
|  |         InFlightOpsSummary::<_> { | ||||||
|  |             empty_op_index, | ||||||
|  |             ready_op_index, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     #[hdl] | ||||||
|  |     fn combine(l: impl ToExpr<Type = Self>, r: impl ToExpr<Type = Self>) -> Expr<Self> { | ||||||
|  |         let l = l.to_expr(); | ||||||
|  |         let r = r.to_expr(); | ||||||
|  |         #[hdl] | ||||||
|  |         InFlightOpsSummary::<_> { | ||||||
|  |             empty_op_index: HdlOption::or(l.empty_op_index, r.empty_op_index), | ||||||
|  |             ready_op_index: HdlOption::or(l.ready_op_index, r.ready_op_index), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl InFlightOpsSummary<DynSize> { | ||||||
|  |     fn summarize<MOp: Type, MaxInFlight: Size>( | ||||||
|  |         in_flight_ops: impl ToExpr<Type = ArrayType<HdlOption<InFlightOp<MOp>>, MaxInFlight>>, | ||||||
|  |     ) -> Expr<Self> { | ||||||
|  |         let in_flight_ops = in_flight_ops.to_expr(); | ||||||
|  |         let max_in_flight = Expr::ty(in_flight_ops).len(); | ||||||
|  |         let index_range = 0..max_in_flight; | ||||||
|  |         let index_ty = UInt::range(index_range.clone()); | ||||||
|  |         tree_reduce( | ||||||
|  |             index_range.map(|i| Self::new(i, index_ty, in_flight_ops[i])), | ||||||
|  |             Self::combine, | ||||||
|  |         ) | ||||||
|  |         .expect("in_flight_ops is known to have len > 0") | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[hdl_module] | #[hdl_module] | ||||||
| pub fn unit_base<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>>( | pub fn unit_base< | ||||||
|  |     MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>, SrcRegWidth = DynSize>, | ||||||
|  |     ExtraOut: Type, | ||||||
|  | >( | ||||||
|     config: &CpuConfig, |     config: &CpuConfig, | ||||||
|     unit_index: usize, |     unit_index: usize, | ||||||
|     mop_ty: MOp, |     mop_ty: MOp, | ||||||
|  |     extra_out_ty: ExtraOut, | ||||||
| ) { | ) { | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let cd: ClockDomain = m.input(); |     let cd: ClockDomain = m.input(); | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let unit_forwarding_info: UnitForwardingInfo<DynSize, DynSize, DynSize> = |     let unit_to_reg_alloc: UnitToRegAlloc<MOp, ExtraOut, DynSize, DynSize, DynSize> = | ||||||
|         m.input(config.unit_forwarding_info()); |         m.output(config.unit_to_reg_alloc(mop_ty, extra_out_ty)); | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let input_insn: ReadyValid<MOp> = m.input(ReadyValid[mop_ty]); |     let execute_start: ReadyValid<ExecuteStart<MOp>> = m.output(ReadyValid[ExecuteStart[mop_ty]]); | ||||||
|     connect(input_insn.ready, false); |  | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let cancel_input: ReadyValid<UnitCancelInput<DynSize>> = |     let execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> = | ||||||
|         m.input(ReadyValid[config.unit_cancel_input()]); |         m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]); | ||||||
|     connect(cancel_input.ready, true); | 
 | ||||||
|     #[hdl] |     connect(execute_start.data, Expr::ty(execute_start).data.HdlNone()); | ||||||
|     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(); |     let max_in_flight = config.unit_max_in_flight(unit_index).get(); | ||||||
|  |     let in_flight_op_ty = InFlightOp[mop_ty]; | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let in_flight_ops = reg_builder().clock_domain(cd).reset(repeat( |     let in_flight_ops = reg_builder() | ||||||
|         HdlOption[InFlightOp[mop_ty]].HdlNone(), |         .clock_domain(cd) | ||||||
|         max_in_flight, |         .reset(repeat(HdlOption[in_flight_op_ty].HdlNone(), max_in_flight)); | ||||||
|     )); | 
 | ||||||
|     let in_flight_op_index_ty = UInt::range(0..max_in_flight); |     let in_flight_ops_summary_value = InFlightOpsSummary::summarize(in_flight_ops); | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let input_index = wire(HdlOption[in_flight_op_index_ty]); |     let in_flight_ops_summary = wire(Expr::ty(in_flight_ops_summary_value)); | ||||||
|  |     connect(in_flight_ops_summary, in_flight_ops_summary_value); | ||||||
|  | 
 | ||||||
|     connect( |     connect( | ||||||
|         input_index, |         unit_to_reg_alloc.input_insn.ready, | ||||||
|         tree_reduce( |         HdlOption::is_some(in_flight_ops_summary.empty_op_index), | ||||||
|             (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"), |  | ||||||
|     ); |     ); | ||||||
|  |     // TODO: connect(execute_start.data, <read_regs>(in_flight_ops_summary.ready_op_index));
 | ||||||
|  | 
 | ||||||
|  |     connect( | ||||||
|  |         unit_to_reg_alloc.output, | ||||||
|  |         Expr::ty(unit_to_reg_alloc.output).HdlNone(), | ||||||
|  |     ); // TODO: finish
 | ||||||
|  | 
 | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     let input_in_flight_op = wire(HdlOption[InFlightOp[mop_ty]]); |     let input_in_flight_op = wire(HdlOption[in_flight_op_ty]); | ||||||
|     connect(input_in_flight_op, Expr::ty(input_in_flight_op).HdlNone()); |     connect(input_in_flight_op, HdlOption[in_flight_op_ty].HdlNone()); | ||||||
|     #[hdl] |     #[hdl] | ||||||
|     if let HdlSome(mop) = ReadyValid::firing_data(input_insn) { |     if let HdlSome(mop) = ReadyValid::firing_data(unit_to_reg_alloc.input_insn) { | ||||||
|         let src_values = wire_with_loc( |         #[hdl] | ||||||
|             "input_in_flight_op_src_values", |         let input_mop_src_regs = wire(mop_ty.src_regs_ty()); | ||||||
|  |         connect( | ||||||
|  |             input_mop_src_regs, | ||||||
|  |             repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize), | ||||||
|  |         ); | ||||||
|  |         MOp::connect_src_regs(mop, input_mop_src_regs); | ||||||
|  |         let src_ready_flags = wire_with_loc( | ||||||
|  |             "input_in_flight_op_src_ready_flags", | ||||||
|             SourceLocation::caller(), |             SourceLocation::caller(), | ||||||
|             StaticType::TYPE, |             StaticType::TYPE, | ||||||
|         ); |         ); | ||||||
|         connect( |         for src_index in 0..COMMON_MOP_SRC_LEN { | ||||||
|             src_values, |             connect( | ||||||
|             [HdlSome(PRegValue::zeroed()); COMMON_MOP_SRC_LEN], |                 src_ready_flags[src_index], | ||||||
|         ); |                 config | ||||||
|         MOp::for_each_src_reg(mop, &mut |src_reg, src_index| { |                     .p_reg_num() | ||||||
|  |                     .const_zero() | ||||||
|  |                     .cast_to_bits() | ||||||
|  |                     .cmp_eq(input_mop_src_regs[src_index]), | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         #[hdl] | ||||||
|  |         if unit_to_reg_alloc.cancel_input.cmp_ne(HdlSome( | ||||||
|             #[hdl] |             #[hdl] | ||||||
|             if config |             UnitCancelInput::<_> { | ||||||
|                 .p_reg_num() |                 which: MOp::dest_reg(mop), | ||||||
|                 .const_zero() |             }, | ||||||
|                 .cast_to_bits() |         )) { | ||||||
|                 .cmp_ne(src_reg) |             connect( | ||||||
|             { |                 input_in_flight_op, | ||||||
|                 connect(src_values[src_index], HdlNone()); |                 HdlSome( | ||||||
|             } |                     #[hdl] | ||||||
|         }); |                     InFlightOp::<_> { | ||||||
|         connect( |                         state: InFlightOpState.Ready(), | ||||||
|             input_in_flight_op, |                         mop, | ||||||
|             HdlSome( |                         src_ready_flags, | ||||||
|                 #[hdl] |                     }, | ||||||
|                 InFlightOp::<_> { mop, src_values }, |                 ), | ||||||
|             ), |             ); | ||||||
|         ); |         } | ||||||
|  |         #[hdl] | ||||||
|  |         if let HdlSome(empty_op_index) = in_flight_ops_summary.empty_op_index { | ||||||
|  |             connect(in_flight_ops[empty_op_index], input_in_flight_op); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     #[hdl] | ||||||
|  |     let in_flight_op_next_state = wire(Array[HdlOption[InFlightOpState]][max_in_flight]); | ||||||
|  |     #[hdl] | ||||||
|  |     let in_flight_op_next_src_ready_flags = | ||||||
|  |         wire(Array[in_flight_op_ty.src_ready_flags][max_in_flight]); | ||||||
|  |     #[hdl] | ||||||
|  |     let in_flight_op_canceling = wire(Array[Bool][max_in_flight]); | ||||||
|  |     #[hdl] | ||||||
|  |     let in_flight_op_execute_starting = wire(Array[Bool][max_in_flight]); | ||||||
|  |     #[hdl] | ||||||
|  |     let in_flight_op_execute_ending = wire(Array[Bool][max_in_flight]); | ||||||
|     for in_flight_op_index in 0..max_in_flight { |     for in_flight_op_index in 0..max_in_flight { | ||||||
|  |         connect( | ||||||
|  |             in_flight_op_next_src_ready_flags[in_flight_op_index], | ||||||
|  |             [false; COMMON_MOP_SRC_LEN], | ||||||
|  |         ); | ||||||
|  |         connect(in_flight_op_canceling[in_flight_op_index], false); | ||||||
|  |         connect(in_flight_op_execute_starting[in_flight_op_index], false); | ||||||
|  |         connect(in_flight_op_execute_ending[in_flight_op_index], false); | ||||||
|         #[hdl] |         #[hdl] | ||||||
|         if let HdlSome(in_flight_op) = in_flight_ops[in_flight_op_index] { |         if let HdlSome(in_flight_op) = in_flight_ops[in_flight_op_index] { | ||||||
|             #[hdl] |             #[hdl] | ||||||
|             if let HdlSome(cancel_input) = ReadyValid::firing_data(cancel_input) { |             let InFlightOp::<_> { | ||||||
|  |                 state, | ||||||
|  |                 mop, | ||||||
|  |                 src_ready_flags, | ||||||
|  |             } = in_flight_op; | ||||||
|  |             let which = MOp::dest_reg(mop); | ||||||
|  |             let src_regs = wire_with_loc( | ||||||
|  |                 &format!("in_flight_op_src_regs_{in_flight_op_index}"), | ||||||
|  |                 SourceLocation::caller(), | ||||||
|  |                 mop_ty.src_regs_ty(), | ||||||
|  |             ); | ||||||
|  |             connect( | ||||||
|  |                 src_regs, | ||||||
|  |                 repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize), | ||||||
|  |             ); | ||||||
|  |             MOp::connect_src_regs(mop, src_regs); | ||||||
|  | 
 | ||||||
|  |             connect( | ||||||
|  |                 in_flight_op_next_src_ready_flags[in_flight_op_index], | ||||||
|  |                 src_ready_flags, | ||||||
|  |             ); | ||||||
|  |             let unit_output_writes = unit_to_reg_alloc.unit_forwarding_info.unit_output_writes; | ||||||
|  |             for unit_index in 0..Expr::ty(unit_output_writes).len() { | ||||||
|                 #[hdl] |                 #[hdl] | ||||||
|                 let UnitCancelInput::<_> { which } = cancel_input; |                 if let HdlSome(unit_output_write) = unit_output_writes[unit_index] { | ||||||
|                 #[hdl] |                     #[hdl] | ||||||
|                 if which.value.cmp_eq(MOp::dest_reg(in_flight_op.mop).value) { |                     let UnitOutputWrite::<_> { | ||||||
|                     // TODO: if it needs extra time to cancel (e.g. still in pipeline), handle that here
 |                         which: unit_out_reg, | ||||||
|                     connect( |                         value: _, | ||||||
|                         in_flight_ops[in_flight_op_index], |                     } = unit_output_write; | ||||||
|                         HdlOption[InFlightOp[mop_ty]].HdlNone(), |                     let p_reg_num = #[hdl] | ||||||
|                     ); |                     PRegNum::<_, _> { | ||||||
|  |                         unit_num: config.unit_num().from_index(unit_index), | ||||||
|  |                         unit_out_reg, | ||||||
|  |                     }; | ||||||
|  |                     for src_index in 0..COMMON_MOP_SRC_LEN { | ||||||
|  |                         #[hdl] | ||||||
|  |                         if p_reg_num.cast_to_bits().cmp_eq(src_regs[src_index]) { | ||||||
|  |                             connect( | ||||||
|  |                                 in_flight_op_next_src_ready_flags[in_flight_op_index][src_index], | ||||||
|  |                                 true, | ||||||
|  |                             ); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             // TODO: finish
 | 
 | ||||||
|         } else if let HdlSome(input_index) = input_index { |             connect( | ||||||
|             connect(input_insn.ready, true); |                 in_flight_op_canceling[in_flight_op_index], | ||||||
|  |                 unit_to_reg_alloc.cancel_input.cmp_eq(HdlSome( | ||||||
|  |                     #[hdl] | ||||||
|  |                     UnitCancelInput::<_> { which }, | ||||||
|  |                 )), | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|             #[hdl] |             #[hdl] | ||||||
|             if input_index.cmp_eq(in_flight_op_index) { |             if let HdlSome(execute_end) = execute_end { | ||||||
|                 connect(in_flight_ops[in_flight_op_index], input_in_flight_op); |                 #[hdl] | ||||||
|  |                 let ExecuteEnd::<_, _> { unit_output } = execute_end; | ||||||
|  |                 #[hdl] | ||||||
|  |                 if which.cmp_eq(unit_output.which) { | ||||||
|  |                     connect(in_flight_op_execute_ending[in_flight_op_index], true); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |             #[hdl] | ||||||
|  |             if let HdlSome(execute_start) = ReadyValid::firing_data(execute_start) { | ||||||
|  |                 #[hdl] | ||||||
|  |                 if which.cmp_eq(MOp::dest_reg(execute_start.mop)) { | ||||||
|  |                     connect(in_flight_op_execute_starting[in_flight_op_index], true); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             let connect_next_state = |f| { | ||||||
|  |                 InFlightOpState::connect_next_state( | ||||||
|  |                     in_flight_op_canceling[in_flight_op_index], | ||||||
|  |                     in_flight_op_execute_starting[in_flight_op_index], | ||||||
|  |                     in_flight_op_execute_ending[in_flight_op_index], | ||||||
|  |                     f, | ||||||
|  |                     in_flight_op_next_state[in_flight_op_index], | ||||||
|  |                 ); | ||||||
|  |             }; | ||||||
|  |             #[hdl] | ||||||
|  |             match state { | ||||||
|  |                 InFlightOpState::Ready => connect_next_state(InFlightOpState::ready_next_state), | ||||||
|  |                 InFlightOpState::Running => connect_next_state(InFlightOpState::running_next_state), | ||||||
|  |                 InFlightOpState::CanceledAndRunning => { | ||||||
|  |                     connect_next_state(InFlightOpState::canceled_and_running_next_state); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             #[hdl] | ||||||
|  |             if let HdlSome(state) = in_flight_op_next_state[in_flight_op_index] { | ||||||
|  |                 connect( | ||||||
|  |                     in_flight_ops[in_flight_op_index], | ||||||
|  |                     HdlSome( | ||||||
|  |                         #[hdl] | ||||||
|  |                         InFlightOp::<_> { | ||||||
|  |                             state, | ||||||
|  |                             mop, | ||||||
|  |                             src_ready_flags, | ||||||
|  |                         }, | ||||||
|  |                     ), | ||||||
|  |                 ); | ||||||
|  |             } else { | ||||||
|  |                 connect( | ||||||
|  |                     in_flight_ops[in_flight_op_index], | ||||||
|  |                     HdlOption[in_flight_op_ty].HdlNone(), | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             connect(in_flight_op_next_state[in_flight_op_index], HdlNone()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
										
											
												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