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
|
// 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,
|
||||||
);
|
);
|
||||||
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||||
connect(
|
connect(
|
||||||
src_values,
|
src_ready_flags[src_index],
|
||||||
[HdlSome(PRegValue::zeroed()); COMMON_MOP_SRC_LEN],
|
config
|
||||||
);
|
|
||||||
MOp::for_each_src_reg(mop, &mut |src_reg, src_index| {
|
|
||||||
#[hdl]
|
|
||||||
if config
|
|
||||||
.p_reg_num()
|
.p_reg_num()
|
||||||
.const_zero()
|
.const_zero()
|
||||||
.cast_to_bits()
|
.cast_to_bits()
|
||||||
.cmp_ne(src_reg)
|
.cmp_eq(input_mop_src_regs[src_index]),
|
||||||
{
|
);
|
||||||
connect(src_values[src_index], HdlNone());
|
|
||||||
}
|
}
|
||||||
});
|
#[hdl]
|
||||||
|
if unit_to_reg_alloc.cancel_input.cmp_ne(HdlSome(
|
||||||
|
#[hdl]
|
||||||
|
UnitCancelInput::<_> {
|
||||||
|
which: MOp::dest_reg(mop),
|
||||||
|
},
|
||||||
|
)) {
|
||||||
connect(
|
connect(
|
||||||
input_in_flight_op,
|
input_in_flight_op,
|
||||||
HdlSome(
|
HdlSome(
|
||||||
#[hdl]
|
#[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 {
|
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::<_> {
|
||||||
#[hdl]
|
state,
|
||||||
let UnitCancelInput::<_> { which } = cancel_input;
|
mop,
|
||||||
#[hdl]
|
src_ready_flags,
|
||||||
if which.value.cmp_eq(MOp::dest_reg(in_flight_op.mop).value) {
|
} = in_flight_op;
|
||||||
// TODO: if it needs extra time to cancel (e.g. still in pipeline), handle that here
|
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(
|
connect(
|
||||||
in_flight_ops[in_flight_op_index],
|
src_regs,
|
||||||
HdlOption[InFlightOp[mop_ty]].HdlNone(),
|
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);
|
|
||||||
#[hdl]
|
|
||||||
if input_index.cmp_eq(in_flight_op_index) {
|
|
||||||
connect(in_flight_ops[in_flight_op_index], input_in_flight_op);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect(
|
||||||
|
in_flight_op_canceling[in_flight_op_index],
|
||||||
|
unit_to_reg_alloc.cancel_input.cmp_eq(HdlSome(
|
||||||
|
#[hdl]
|
||||||
|
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