WIP implementing unit_base
This commit is contained in:
parent
ece788dda3
commit
3f6e5cc600
|
@ -1,8 +1,11 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
instruction::{PRegNum, UnitNum, UnitOutRegNum, CONST_ZERO_UNIT_NUM},
|
||||
unit::{unit_base::UnitForwardingInfo, UnitCancelInput, UnitKind, UnitMOp, UnitOutputWrite},
|
||||
instruction::{MOpTrait, PRegNum, UnitNum, UnitOutRegNum, CONST_ZERO_UNIT_NUM},
|
||||
unit::{
|
||||
unit_base::{UnitForwardingInfo, UnitToRegAlloc},
|
||||
UnitCancelInput, UnitKind, UnitMOp, UnitOutputWrite,
|
||||
},
|
||||
};
|
||||
use fayalite::prelude::*;
|
||||
use std::num::NonZeroUsize;
|
||||
|
@ -95,4 +98,20 @@ impl CpuConfig {
|
|||
.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
|
||||
// See Notices.txt for copyright information
|
||||
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};
|
||||
|
||||
pub mod power_isa;
|
||||
|
@ -12,10 +16,26 @@ 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 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(
|
||||
input: impl ToExpr<Type = Self>,
|
||||
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>(
|
||||
self,
|
||||
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> {
|
||||
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(
|
||||
input: impl ToExpr<Type = Self>,
|
||||
f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize),
|
||||
|
@ -129,13 +152,23 @@ pub enum OutputIntegerMode {
|
|||
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_MIN_REG_WIDTH: usize = 8;
|
||||
pub const COMMON_MOP_SRC_LEN: usize = 3;
|
||||
pub const COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM: usize = 2;
|
||||
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 prefix_pad: UIntType<PrefixPad>,
|
||||
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> {
|
||||
// fields must be in this exact order
|
||||
pub imm_low: UInt<{ COMMON_MOP_IMM_LOW_WIDTH }>,
|
||||
|
@ -410,6 +443,9 @@ macro_rules! mop_enum {
|
|||
}
|
||||
dest_reg
|
||||
}
|
||||
fn src_reg_width(self) -> <Self::SrcRegWidth as Size>::SizeType {
|
||||
self.$FirstVariant.src_reg_width()
|
||||
}
|
||||
#[hdl]
|
||||
fn for_each_src_reg(
|
||||
input: impl ToExpr<Type = Self>,
|
||||
|
@ -458,7 +494,7 @@ pub(crate) use mop_enum;
|
|||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> AluCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct AluCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount>,
|
||||
|
@ -468,7 +504,7 @@ common_mop_struct! {
|
|||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> AddSubMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct AddSubMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
||||
#[common]
|
||||
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount>,
|
||||
|
@ -481,7 +517,7 @@ common_mop_struct! {
|
|||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> LogicalMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct LogicalMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
|
||||
|
@ -491,7 +527,7 @@ common_mop_struct! {
|
|||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct BranchMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
|
||||
|
@ -510,7 +546,7 @@ mop_enum! {
|
|||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> ReadL2RegMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct ReadL2RegMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<0>>,
|
||||
|
@ -519,7 +555,7 @@ common_mop_struct! {
|
|||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> WriteL2RegMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct WriteL2RegMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<1>>,
|
||||
|
@ -536,7 +572,7 @@ mop_enum! {
|
|||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> LoadStoreCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct LoadStoreCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
|
||||
#[common]
|
||||
pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, SrcCount>,
|
||||
|
@ -545,7 +581,7 @@ common_mop_struct! {
|
|||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> LoadMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct LoadMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
pub load_store_common: LoadStoreCommonMOp<DestReg, SrcRegWidth, ConstUsize<1>>,
|
||||
|
@ -554,7 +590,7 @@ common_mop_struct! {
|
|||
|
||||
common_mop_struct! {
|
||||
#[mapped(<NewDestReg, NewSrcRegWidth> StoreMOp<NewDestReg, NewSrcRegWidth>)]
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct StoreMOp<DestReg: Type, SrcRegWidth: Size> {
|
||||
#[common]
|
||||
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.
|
||||
/// zero is used for built-in constants, such as the zero register
|
||||
pub struct UnitNum<Width: Size> {
|
||||
|
@ -617,12 +653,12 @@ impl<Width: Size> UnitNum<Width> {
|
|||
|
||||
pub const CONST_ZERO_UNIT_NUM: usize = 0;
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct UnitOutRegNum<Width: Size> {
|
||||
pub value: UIntType<Width>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
/// Physical Register Number -- registers in the CPU's backend
|
||||
pub struct PRegNum<UnitNumWidth: Size, OutRegNumWidth: Size> {
|
||||
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
|
||||
#[doc(alias = "UOpRegNum")] // help you find it in the docs if you mis-spell it
|
||||
#[doc(alias = "\u{B5}OpRegNum")] // micro sign
|
||||
|
@ -681,7 +717,7 @@ impl MOpRegNum {
|
|||
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.
|
||||
pub struct MOpDestReg {
|
||||
/// 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 std::ops::Range;
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct PowerIsaRegNum {
|
||||
pub value: UInt<5>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct PowerIsaFRegNum {
|
||||
pub value: UInt<5>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct PowerIsaCrFieldNum {
|
||||
pub value: UInt<3>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct PowerIsaCrBitNum {
|
||||
pub cr_field: PowerIsaCrFieldNum,
|
||||
pub bit_in_field: UInt<2>,
|
||||
|
|
|
@ -311,7 +311,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
SourceLocation::caller(),
|
||||
);
|
||||
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
|
||||
let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap();
|
||||
// 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_input_insn.data,
|
||||
Expr::ty(unit_input_insn).data.HdlNone(),
|
||||
unit_to_reg_alloc.input_insn.data,
|
||||
Expr::ty(unit_to_reg_alloc.input_insn).data.HdlNone(),
|
||||
);
|
||||
for fetch_index in 0..config.fetch_width.get() {
|
||||
#[hdl]
|
||||
|
@ -343,7 +343,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
connect(available_units[fetch_index][unit_index], false);
|
||||
}
|
||||
#[hdl]
|
||||
if !unit_input_insn.ready {
|
||||
if !unit_to_reg_alloc.input_insn.ready {
|
||||
// must come after to override connects in loops above
|
||||
connect(available_units[fetch_index][unit_index], false);
|
||||
}
|
||||
|
@ -356,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_insn.data, HdlSome(renamed_mop));
|
||||
connect(unit_to_reg_alloc.input_insn.data, HdlSome(renamed_mop));
|
||||
} else {
|
||||
connect(
|
||||
unit_input_insn.data,
|
||||
HdlSome(Expr::ty(unit_input_insn).data.HdlSome.uninit()),
|
||||
unit_to_reg_alloc.input_insn.data,
|
||||
HdlSome(Expr::ty(unit_to_reg_alloc.input_insn).data.HdlSome.uninit()),
|
||||
);
|
||||
// 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
|
||||
connect(
|
||||
dyn_unit.unit_forwarding_info(unit),
|
||||
unit_to_reg_alloc.unit_forwarding_info,
|
||||
#[hdl]
|
||||
UnitForwardingInfo::<_, _, _> {
|
||||
unit_output_writes: repeat(
|
||||
|
@ -397,10 +397,9 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
_phantom: PhantomData,
|
||||
},
|
||||
);
|
||||
connect(dyn_unit.output(unit).ready, false);
|
||||
// TODO: handle cancellation
|
||||
connect(
|
||||
dyn_unit.cancel_input(unit).data,
|
||||
unit_to_reg_alloc.cancel_input,
|
||||
HdlOption[config.unit_cancel_input()].HdlNone(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ pub enum FlagsMode {
|
|||
X86(PRegFlagsX86),
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct PRegFlagsPowerISA {}
|
||||
|
||||
impl PRegFlagsPowerISA {
|
||||
|
@ -56,7 +56,7 @@ impl PRegFlagsPowerISA {
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct 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,
|
||||
/// 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
|
||||
/// and flags register and CR field.
|
||||
///
|
||||
|
|
|
@ -7,13 +7,12 @@ use crate::{
|
|||
mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, UnitOutRegNum,
|
||||
},
|
||||
register::PRegValue,
|
||||
unit::unit_base::UnitForwardingInfo,
|
||||
unit::unit_base::UnitToRegAlloc,
|
||||
};
|
||||
use fayalite::{
|
||||
bundle::{Bundle, BundleType},
|
||||
intern::{Intern, Interned},
|
||||
prelude::*,
|
||||
util::ready_valid::ReadyValid,
|
||||
};
|
||||
|
||||
pub mod alu_branch;
|
||||
|
@ -143,19 +142,19 @@ all_units! {
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct UnitResultCompleted<ExtraOut> {
|
||||
pub value: PRegValue,
|
||||
pub extra_out: ExtraOut,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct UnitOutputWrite<OutRegNumWidth: Size> {
|
||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
||||
pub value: PRegValue,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct TrapData {
|
||||
// TODO
|
||||
}
|
||||
|
@ -166,13 +165,25 @@ pub enum UnitResult<ExtraOut> {
|
|||
Trap(TrapData),
|
||||
}
|
||||
|
||||
impl<ExtraOut: Type> UnitResult<ExtraOut> {
|
||||
pub fn extra_out_ty(self) -> ExtraOut {
|
||||
self.Completed.extra_out
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct UnitOutput<OutRegNumWidth: Size, ExtraOut> {
|
||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
||||
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 which: UnitOutRegNum<OutRegNumWidth>,
|
||||
}
|
||||
|
@ -197,19 +208,10 @@ pub trait UnitTrait:
|
|||
|
||||
fn module(&self) -> Interned<Module<Self::Type>>;
|
||||
|
||||
fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>>;
|
||||
|
||||
fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>>;
|
||||
|
||||
fn unit_forwarding_info(
|
||||
fn unit_to_reg_alloc(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>>;
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>>;
|
||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>>;
|
||||
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
|
||||
|
||||
|
@ -266,26 +268,11 @@ impl UnitTrait for DynUnit {
|
|||
self.unit.module()
|
||||
}
|
||||
|
||||
fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
|
||||
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(
|
||||
fn unit_to_reg_alloc(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> {
|
||||
self.unit.unit_forwarding_info(this)
|
||||
}
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> {
|
||||
self.unit.output(this)
|
||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
|
||||
self.unit.unit_to_reg_alloc(this)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
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(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>> {
|
||||
self.0.cancel_input(Expr::from_bundle(this))
|
||||
}
|
||||
|
||||
fn unit_forwarding_info(
|
||||
fn unit_to_reg_alloc(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> 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, Self::ExtraOut>>> {
|
||||
Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this))))
|
||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
|
||||
Expr::from_bundle(Expr::as_bundle(
|
||||
self.0.unit_to_reg_alloc(Expr::from_bundle(this)),
|
||||
))
|
||||
}
|
||||
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
|
||||
|
|
|
@ -5,14 +5,13 @@ use crate::{
|
|||
config::CpuConfig,
|
||||
instruction::{AluBranchMOp, UnitOutRegNum},
|
||||
unit::{
|
||||
unit_base::{unit_base, UnitForwardingInfo},
|
||||
DynUnit, DynUnitWrapper, UnitCancelInput, UnitKind, UnitMOp, UnitOutput, UnitTrait,
|
||||
unit_base::{unit_base, UnitToRegAlloc},
|
||||
DynUnit, DynUnitWrapper, UnitKind, UnitMOp, UnitTrait,
|
||||
},
|
||||
};
|
||||
use fayalite::{
|
||||
intern::{Intern, Interned},
|
||||
prelude::*,
|
||||
util::ready_valid::ReadyValid,
|
||||
};
|
||||
|
||||
#[hdl_module]
|
||||
|
@ -20,30 +19,30 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
|||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[hdl]
|
||||
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][()]]);
|
||||
let unit_to_reg_alloc: UnitToRegAlloc<
|
||||
AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>,
|
||||
(),
|
||||
DynSize,
|
||||
DynSize,
|
||||
DynSize,
|
||||
> = m.output(config.unit_to_reg_alloc(
|
||||
AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()],
|
||||
(),
|
||||
));
|
||||
#[hdl]
|
||||
let unit_base = instance(unit_base(
|
||||
config,
|
||||
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.unit_forwarding_info, unit_forwarding_info);
|
||||
connect(unit_base.cancel_input, cancel_input);
|
||||
// TODO: finish
|
||||
connect(unit_base.ready_mop.ready, true);
|
||||
connect(output.data, Expr::ty(output.data).HdlNone());
|
||||
connect(unit_base.execute_start.ready, true); // TODO: finish
|
||||
connect(
|
||||
unit_base.execute_end,
|
||||
Expr::ty(unit_base.execute_end).HdlNone(),
|
||||
); // TODO: finish
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -75,7 +74,7 @@ impl UnitTrait for AluBranch {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -93,26 +92,11 @@ impl UnitTrait for AluBranch {
|
|||
self.module
|
||||
}
|
||||
|
||||
fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
|
||||
this.input_insn
|
||||
}
|
||||
|
||||
fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>> {
|
||||
this.cancel_input
|
||||
}
|
||||
|
||||
fn unit_forwarding_info(
|
||||
fn unit_to_reg_alloc(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> {
|
||||
this.unit_forwarding_info
|
||||
}
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> {
|
||||
this.output
|
||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
|
||||
this.unit_to_reg_alloc
|
||||
}
|
||||
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
use crate::{
|
||||
config::CpuConfig,
|
||||
instruction::{MOpTrait, UnitOutRegNum, COMMON_MOP_SRC_LEN},
|
||||
instruction::{MOpTrait, PRegNum, UnitOutRegNum, COMMON_MOP_SRC_LEN},
|
||||
register::PRegValue,
|
||||
unit::{UnitCancelInput, UnitOutputWrite},
|
||||
unit::{UnitCancelInput, UnitOutput, UnitOutputWrite},
|
||||
util::tree_reduce::tree_reduce,
|
||||
};
|
||||
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]
|
||||
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 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 }>,
|
||||
pub struct ExecuteEnd<OutRegNumWidth: Size, ExtraOut> {
|
||||
pub unit_output: UnitOutput<OutRegNumWidth, ExtraOut>,
|
||||
}
|
||||
|
||||
#[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]
|
||||
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,
|
||||
unit_index: usize,
|
||||
mop_ty: MOp,
|
||||
extra_out_ty: ExtraOut,
|
||||
) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[hdl]
|
||||
let unit_forwarding_info: UnitForwardingInfo<DynSize, DynSize, DynSize> =
|
||||
m.input(config.unit_forwarding_info());
|
||||
let unit_to_reg_alloc: UnitToRegAlloc<MOp, ExtraOut, DynSize, DynSize, DynSize> =
|
||||
m.output(config.unit_to_reg_alloc(mop_ty, extra_out_ty));
|
||||
#[hdl]
|
||||
let input_insn: ReadyValid<MOp> = m.input(ReadyValid[mop_ty]);
|
||||
connect(input_insn.ready, false);
|
||||
let execute_start: ReadyValid<ExecuteStart<MOp>> = m.output(ReadyValid[ExecuteStart[mop_ty]]);
|
||||
#[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 execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> =
|
||||
m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]);
|
||||
|
||||
connect(execute_start.data, Expr::ty(execute_start).data.HdlNone());
|
||||
|
||||
let max_in_flight = config.unit_max_in_flight(unit_index).get();
|
||||
let in_flight_op_ty = InFlightOp[mop_ty];
|
||||
#[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);
|
||||
let in_flight_ops = reg_builder()
|
||||
.clock_domain(cd)
|
||||
.reset(repeat(HdlOption[in_flight_op_ty].HdlNone(), max_in_flight));
|
||||
|
||||
let in_flight_ops_summary_value = InFlightOpsSummary::summarize(in_flight_ops);
|
||||
#[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(
|
||||
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"),
|
||||
unit_to_reg_alloc.input_insn.ready,
|
||||
HdlOption::is_some(in_flight_ops_summary.empty_op_index),
|
||||
);
|
||||
// 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]
|
||||
let input_in_flight_op = wire(HdlOption[InFlightOp[mop_ty]]);
|
||||
connect(input_in_flight_op, Expr::ty(input_in_flight_op).HdlNone());
|
||||
let input_in_flight_op = wire(HdlOption[in_flight_op_ty]);
|
||||
connect(input_in_flight_op, HdlOption[in_flight_op_ty].HdlNone());
|
||||
#[hdl]
|
||||
if let HdlSome(mop) = ReadyValid::firing_data(input_insn) {
|
||||
let src_values = wire_with_loc(
|
||||
"input_in_flight_op_src_values",
|
||||
if let HdlSome(mop) = ReadyValid::firing_data(unit_to_reg_alloc.input_insn) {
|
||||
#[hdl]
|
||||
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(),
|
||||
StaticType::TYPE,
|
||||
);
|
||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||
connect(
|
||||
src_values,
|
||||
[HdlSome(PRegValue::zeroed()); COMMON_MOP_SRC_LEN],
|
||||
);
|
||||
MOp::for_each_src_reg(mop, &mut |src_reg, src_index| {
|
||||
#[hdl]
|
||||
if config
|
||||
src_ready_flags[src_index],
|
||||
config
|
||||
.p_reg_num()
|
||||
.const_zero()
|
||||
.cast_to_bits()
|
||||
.cmp_ne(src_reg)
|
||||
{
|
||||
connect(src_values[src_index], HdlNone());
|
||||
.cmp_eq(input_mop_src_regs[src_index]),
|
||||
);
|
||||
}
|
||||
});
|
||||
#[hdl]
|
||||
if unit_to_reg_alloc.cancel_input.cmp_ne(HdlSome(
|
||||
#[hdl]
|
||||
UnitCancelInput::<_> {
|
||||
which: MOp::dest_reg(mop),
|
||||
},
|
||||
)) {
|
||||
connect(
|
||||
input_in_flight_op,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
InFlightOp::<_> { mop, src_values },
|
||||
InFlightOp::<_> {
|
||||
state: InFlightOpState.Ready(),
|
||||
mop,
|
||||
src_ready_flags,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
#[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 {
|
||||
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]
|
||||
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
|
||||
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(
|
||||
in_flight_ops[in_flight_op_index],
|
||||
HdlOption[InFlightOp[mop_ty]].HdlNone(),
|
||||
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]
|
||||
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
||||
#[hdl]
|
||||
let UnitOutputWrite::<_> {
|
||||
which: unit_out_reg,
|
||||
value: _,
|
||||
} = unit_output_write;
|
||||
let p_reg_num = #[hdl]
|
||||
PRegNum::<_, _> {
|
||||
unit_num: config.unit_num().from_index(unit_index),
|
||||
unit_out_reg,
|
||||
};
|
||||
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(input_insn.ready, true);
|
||||
}
|
||||
}
|
||||
|
||||
connect(
|
||||
in_flight_op_canceling[in_flight_op_index],
|
||||
unit_to_reg_alloc.cancel_input.cmp_eq(HdlSome(
|
||||
#[hdl]
|
||||
if input_index.cmp_eq(in_flight_op_index) {
|
||||
connect(in_flight_ops[in_flight_op_index], input_in_flight_op);
|
||||
}
|
||||
UnitCancelInput::<_> { which },
|
||||
)),
|
||||
);
|
||||
|
||||
#[hdl]
|
||||
if let HdlSome(execute_end) = execute_end {
|
||||
#[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…
Reference in a new issue