forked from libre-chip/cpu
WIP adding rename_execute_retire
This commit is contained in:
parent
6ed04c809e
commit
13efae0ad9
11 changed files with 93793 additions and 166 deletions
|
|
@ -33,3 +33,6 @@ hex-literal.workspace = true
|
||||||
regex = "1.12.2"
|
regex = "1.12.2"
|
||||||
sha2.workspace = true
|
sha2.workspace = true
|
||||||
which.workspace = true
|
which.workspace = true
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(todo)'] }
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,6 @@
|
||||||
// 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::CONST_ZERO_UNIT_NUM, unit::UnitKind};
|
||||||
instruction::{CONST_ZERO_UNIT_NUM, MOpTrait, PRegNum, RenamedMOp, UnitNum, UnitOutRegNum},
|
|
||||||
unit::{
|
|
||||||
UnitCancelInput, UnitKind, UnitOutputWrite,
|
|
||||||
unit_base::{UnitForwardingInfo, UnitToRegAlloc},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use fayalite::prelude::*;
|
use fayalite::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
@ -101,54 +95,20 @@ impl CpuConfig {
|
||||||
pub fn unit_num_width(&self) -> usize {
|
pub fn unit_num_width(&self) -> usize {
|
||||||
UInt::range(CONST_ZERO_UNIT_NUM..self.non_const_unit_nums().end).width()
|
UInt::range(CONST_ZERO_UNIT_NUM..self.non_const_unit_nums().end).width()
|
||||||
}
|
}
|
||||||
pub fn unit_num(&self) -> UnitNum<DynSize> {
|
|
||||||
UnitNum[self.unit_num_width()]
|
|
||||||
}
|
|
||||||
pub fn unit_out_reg_num(&self) -> UnitOutRegNum<DynSize> {
|
|
||||||
UnitOutRegNum[self.out_reg_num_width]
|
|
||||||
}
|
|
||||||
pub fn p_reg_num(&self) -> PRegNum<DynSize, DynSize> {
|
|
||||||
PRegNum[self.unit_num_width()][self.out_reg_num_width]
|
|
||||||
}
|
|
||||||
pub fn p_reg_num_width(&self) -> usize {
|
pub fn p_reg_num_width(&self) -> usize {
|
||||||
self.unit_num_width() + self.out_reg_num_width
|
self.unit_num_width() + self.out_reg_num_width
|
||||||
}
|
}
|
||||||
pub fn renamed_mop_in_unit(&self) -> RenamedMOp<UnitOutRegNum<DynSize>, DynSize> {
|
|
||||||
RenamedMOp[self.unit_out_reg_num()][self.p_reg_num_width()]
|
|
||||||
}
|
|
||||||
pub fn unit_output_write(&self) -> UnitOutputWrite<DynSize> {
|
|
||||||
UnitOutputWrite[self.out_reg_num_width]
|
|
||||||
}
|
|
||||||
pub fn unit_output_writes(&self) -> Array<HdlOption<UnitOutputWrite<DynSize>>> {
|
|
||||||
Array[HdlOption[self.unit_output_write()]][self.non_const_unit_nums().len()]
|
|
||||||
}
|
|
||||||
pub fn unit_cancel_input(&self) -> UnitCancelInput<DynSize> {
|
|
||||||
UnitCancelInput[self.out_reg_num_width]
|
|
||||||
}
|
|
||||||
pub fn unit_forwarding_info(&self) -> UnitForwardingInfo<DynSize, DynSize, DynSize> {
|
|
||||||
UnitForwardingInfo[self.unit_num_width()][self.out_reg_num_width]
|
|
||||||
[self.non_const_unit_nums().len()]
|
|
||||||
}
|
|
||||||
pub fn unit_max_in_flight(&self, unit_index: usize) -> NonZeroUsize {
|
pub fn unit_max_in_flight(&self, unit_index: usize) -> NonZeroUsize {
|
||||||
self.units[unit_index]
|
self.units[unit_index]
|
||||||
.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<
|
/// the maximum of all [`unit_max_in_flight()`][Self::unit_max_in_flight()]
|
||||||
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>, SrcRegWidth = DynSize>,
|
pub fn max_unit_max_in_flight(&self) -> NonZeroUsize {
|
||||||
ExtraOut: Type,
|
(0..self.units.len())
|
||||||
>(
|
.map(|unit_index| self.unit_max_in_flight(unit_index))
|
||||||
&self,
|
.max()
|
||||||
mop_ty: MOp,
|
.unwrap_or(self.default_unit_max_in_flight)
|
||||||
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()]
|
|
||||||
}
|
}
|
||||||
pub fn fetch_width_in_bytes(&self) -> usize {
|
pub fn fetch_width_in_bytes(&self) -> usize {
|
||||||
1usize
|
1usize
|
||||||
|
|
@ -188,6 +148,21 @@ impl CpuConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.out_reg_num_width))]
|
||||||
|
pub type CpuConfigOutRegNumWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.unit_num_width()))]
|
||||||
|
pub type CpuConfigUnitNumWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.p_reg_num_width()))]
|
||||||
|
pub type CpuConfigPRegNumWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| 1 << c.out_reg_num_width))]
|
||||||
|
pub type CpuConfig2PowOutRegNumWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.units.len()))]
|
||||||
|
pub type CpuConfigUnitCount<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
#[hdl(get(|c| c.fetch_width.get()))]
|
#[hdl(get(|c| c.fetch_width.get()))]
|
||||||
pub type CpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
pub type CpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
|
@ -236,6 +211,10 @@ pub type CpuConfigL1ICacheMaxMissesInFlight<C: PhantomConstGet<CpuConfig>> = Dyn
|
||||||
#[hdl(get(|c| c.rob_size.get()))]
|
#[hdl(get(|c| c.rob_size.get()))]
|
||||||
pub type CpuConfigRobSize<C: PhantomConstGet<CpuConfig>> = DynSize;
|
pub type CpuConfigRobSize<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
/// the maximum of all [`unit_max_in_flight()`][CpuConfig::unit_max_in_flight()]
|
||||||
|
#[hdl(get(|c| c.max_unit_max_in_flight().get()))]
|
||||||
|
pub type CpuConfigMaxUnitMaxInFlight<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
pub trait PhantomConstCpuConfig:
|
pub trait PhantomConstCpuConfig:
|
||||||
PhantomConstGet<CpuConfig>
|
PhantomConstGet<CpuConfig>
|
||||||
+ Into<PhantomConst<CpuConfig>>
|
+ Into<PhantomConst<CpuConfig>>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// 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::{
|
||||||
|
config::{CpuConfig, CpuConfigOutRegNumWidth, CpuConfigUnitNumWidth, PhantomConstCpuConfig},
|
||||||
register::{PRegFlags, PRegFlagsViewTrait, PRegValue, ViewUnused},
|
register::{PRegFlags, PRegFlagsViewTrait, PRegValue, ViewUnused},
|
||||||
unit::UnitMOp,
|
unit::UnitMOp,
|
||||||
util::{Rotate, range_u32_len},
|
util::{Rotate, range_u32_len},
|
||||||
|
|
@ -91,6 +92,9 @@ 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 dest_reg_sim(input: impl ToSimValue<Type = Self>) -> SimValue<Self::DestReg>;
|
||||||
|
fn dest_reg_sim_ref(input: &SimValue<Self>) -> &SimValue<Self::DestReg>;
|
||||||
|
fn dest_reg_sim_mut(input: &mut SimValue<Self>) -> &mut SimValue<Self::DestReg>;
|
||||||
fn src_reg_width(self) -> <Self::SrcRegWidth as Size>::SizeType;
|
fn src_reg_width(self) -> <Self::SrcRegWidth as Size>::SizeType;
|
||||||
fn src_reg_ty(self) -> UIntType<Self::SrcRegWidth> {
|
fn src_reg_ty(self) -> UIntType<Self::SrcRegWidth> {
|
||||||
UInt[self.src_reg_width()]
|
UInt[self.src_reg_width()]
|
||||||
|
|
@ -102,6 +106,18 @@ pub trait MOpTrait: Type {
|
||||||
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 for_each_src_reg_sim(
|
||||||
|
input: SimValue<Self>,
|
||||||
|
f: &mut impl FnMut(SimValue<UIntType<Self::SrcRegWidth>>, usize),
|
||||||
|
);
|
||||||
|
fn for_each_src_reg_sim_ref(
|
||||||
|
input: &SimValue<Self>,
|
||||||
|
f: &mut impl FnMut(&SimValue<UIntType<Self::SrcRegWidth>>, usize),
|
||||||
|
);
|
||||||
|
fn for_each_src_reg_sim_mut(
|
||||||
|
input: &mut SimValue<Self>,
|
||||||
|
f: &mut impl FnMut(&mut SimValue<UIntType<Self::SrcRegWidth>>, usize),
|
||||||
|
);
|
||||||
fn connect_src_regs(
|
fn connect_src_regs(
|
||||||
input: impl ToExpr<Type = Self>,
|
input: impl ToExpr<Type = Self>,
|
||||||
src_regs: impl ToExpr<Type = Array<UIntType<Self::SrcRegWidth>, { COMMON_MOP_SRC_LEN }>>,
|
src_regs: impl ToExpr<Type = Array<UIntType<Self::SrcRegWidth>, { COMMON_MOP_SRC_LEN }>>,
|
||||||
|
|
@ -125,6 +141,15 @@ pub trait MOpTrait: Type {
|
||||||
usize,
|
usize,
|
||||||
) -> Expr<UIntType<NewSrcRegWidth>>,
|
) -> Expr<UIntType<NewSrcRegWidth>>,
|
||||||
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>>;
|
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>>;
|
||||||
|
fn map_regs_sim<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
|
input: impl ToSimValue<Type = Self>,
|
||||||
|
new_dest: impl ToSimValue<Type = NewDestReg>,
|
||||||
|
new_src_reg_width: NewSrcRegWidth::SizeType,
|
||||||
|
map_src: &mut impl FnMut(
|
||||||
|
SimValue<UIntType<Self::SrcRegWidth>>,
|
||||||
|
usize,
|
||||||
|
) -> SimValue<UIntType<NewSrcRegWidth>>,
|
||||||
|
) -> SimValue<Self::Mapped<NewDestReg, NewSrcRegWidth>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CommonMOpTrait: MOpTrait {
|
pub trait CommonMOpTrait: MOpTrait {
|
||||||
|
|
@ -146,6 +171,21 @@ pub trait CommonMOpTrait: MOpTrait {
|
||||||
fn common_mop(
|
fn common_mop(
|
||||||
input: impl ToExpr<Type = Self>,
|
input: impl ToExpr<Type = Self>,
|
||||||
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>>;
|
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>>;
|
||||||
|
fn common_mop_sim(
|
||||||
|
input: impl ToSimValue<Type = Self>,
|
||||||
|
) -> SimValue<
|
||||||
|
CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>,
|
||||||
|
>;
|
||||||
|
fn common_mop_sim_ref(
|
||||||
|
input: &SimValue<Self>,
|
||||||
|
) -> &SimValue<
|
||||||
|
CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>,
|
||||||
|
>;
|
||||||
|
fn common_mop_sim_mut(
|
||||||
|
input: &mut SimValue<Self>,
|
||||||
|
) -> &mut SimValue<
|
||||||
|
CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>,
|
||||||
|
>;
|
||||||
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
|
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
self,
|
self,
|
||||||
new_common_mop_ty: CommonMOp<
|
new_common_mop_ty: CommonMOp<
|
||||||
|
|
@ -168,6 +208,18 @@ pub trait CommonMOpTrait: MOpTrait {
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>>;
|
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>>;
|
||||||
|
fn with_common_mop_sim<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
|
input: impl ToSimValue<Type = Self>,
|
||||||
|
new_common_mop: impl ToSimValue<
|
||||||
|
Type = CommonMOp<
|
||||||
|
Self::PrefixPad,
|
||||||
|
NewDestReg,
|
||||||
|
NewSrcRegWidth,
|
||||||
|
Self::SrcCount,
|
||||||
|
Self::Imm,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
) -> SimValue<Self::Mapped<NewDestReg, NewSrcRegWidth>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type CommonMOpFor<T> = CommonMOp<
|
pub type CommonMOpFor<T> = CommonMOp<
|
||||||
|
|
@ -189,6 +241,15 @@ 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 dest_reg_sim(input: impl ToSimValue<Type = Self>) -> SimValue<Self::DestReg> {
|
||||||
|
SimValue::into_value(T::common_mop_sim(input)).dest
|
||||||
|
}
|
||||||
|
fn dest_reg_sim_ref(input: &SimValue<Self>) -> &SimValue<Self::DestReg> {
|
||||||
|
&T::common_mop_sim_ref(input).dest
|
||||||
|
}
|
||||||
|
fn dest_reg_sim_mut(input: &mut SimValue<Self>) -> &mut SimValue<Self::DestReg> {
|
||||||
|
&mut T::common_mop_sim_mut(input).dest
|
||||||
|
}
|
||||||
fn src_reg_width(self) -> <Self::SrcRegWidth as Size>::SizeType {
|
fn src_reg_width(self) -> <Self::SrcRegWidth as Size>::SizeType {
|
||||||
self.common_mop_ty().src.element().width
|
self.common_mop_ty().src.element().width
|
||||||
}
|
}
|
||||||
|
|
@ -202,6 +263,37 @@ impl<T: CommonMOpTrait> MOpTrait for T {
|
||||||
f(common.src[index], index);
|
f(common.src[index], index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn for_each_src_reg_sim(
|
||||||
|
input: SimValue<Self>,
|
||||||
|
f: &mut impl FnMut(SimValue<UIntType<Self::SrcRegWidth>>, usize),
|
||||||
|
) {
|
||||||
|
let common = SimValue::into_value(T::common_mop_sim(input));
|
||||||
|
for (index, src) in SimValue::into_value(common.src)
|
||||||
|
.into_iter()
|
||||||
|
.take(T::SrcCount::VALUE)
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
f(src, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn for_each_src_reg_sim_ref(
|
||||||
|
input: &SimValue<Self>,
|
||||||
|
f: &mut impl FnMut(&SimValue<UIntType<Self::SrcRegWidth>>, usize),
|
||||||
|
) {
|
||||||
|
let common = T::common_mop_sim_ref(input);
|
||||||
|
for index in 0..T::SrcCount::VALUE {
|
||||||
|
f(&common.src[index], index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn for_each_src_reg_sim_mut(
|
||||||
|
input: &mut SimValue<Self>,
|
||||||
|
f: &mut impl FnMut(&mut SimValue<UIntType<Self::SrcRegWidth>>, usize),
|
||||||
|
) {
|
||||||
|
let common = T::common_mop_sim_mut(input);
|
||||||
|
for index in 0..T::SrcCount::VALUE {
|
||||||
|
f(&mut common.src[index], index);
|
||||||
|
}
|
||||||
|
}
|
||||||
fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
|
fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
self,
|
self,
|
||||||
new_dest_reg: NewDestReg,
|
new_dest_reg: NewDestReg,
|
||||||
|
|
@ -244,6 +336,30 @@ impl<T: CommonMOpTrait> MOpTrait for T {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn map_regs_sim<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
|
input: impl ToSimValue<Type = Self>,
|
||||||
|
new_dest: impl ToSimValue<Type = NewDestReg>,
|
||||||
|
new_src_reg_width: NewSrcRegWidth::SizeType,
|
||||||
|
map_src: &mut impl FnMut(
|
||||||
|
SimValue<UIntType<Self::SrcRegWidth>>,
|
||||||
|
usize,
|
||||||
|
) -> SimValue<UIntType<NewSrcRegWidth>>,
|
||||||
|
) -> SimValue<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
|
||||||
|
let input = input.into_sim_value();
|
||||||
|
let common = T::common_mop_sim_ref(&input);
|
||||||
|
let common = #[hdl(sim)]
|
||||||
|
CommonMOp::<_, _, _, _, _> {
|
||||||
|
prefix_pad: &common.prefix_pad,
|
||||||
|
dest: new_dest,
|
||||||
|
src: SimValue::from_array_elements(
|
||||||
|
ArrayType[UIntType[new_src_reg_width]][T::SrcCount::SIZE],
|
||||||
|
(0..T::SrcCount::VALUE).map(|index| map_src(common.src[index].clone(), index)),
|
||||||
|
),
|
||||||
|
imm: common.imm,
|
||||||
|
};
|
||||||
|
T::with_common_mop_sim(input, common)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: CommonMOpTrait> MOpVisitVariants for T {
|
impl<T: CommonMOpTrait> MOpVisitVariants for T {
|
||||||
|
|
@ -532,6 +648,27 @@ impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize
|
||||||
input.ty().validate();
|
input.ty().validate();
|
||||||
input
|
input
|
||||||
}
|
}
|
||||||
|
fn common_mop_sim(
|
||||||
|
input: impl ToSimValue<Type = Self>,
|
||||||
|
) -> SimValue<
|
||||||
|
CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>,
|
||||||
|
> {
|
||||||
|
input.into_sim_value()
|
||||||
|
}
|
||||||
|
fn common_mop_sim_ref(
|
||||||
|
input: &SimValue<Self>,
|
||||||
|
) -> &SimValue<
|
||||||
|
CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>,
|
||||||
|
> {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
fn common_mop_sim_mut(
|
||||||
|
input: &mut SimValue<Self>,
|
||||||
|
) -> &mut SimValue<
|
||||||
|
CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>,
|
||||||
|
> {
|
||||||
|
input
|
||||||
|
}
|
||||||
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
|
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
self,
|
self,
|
||||||
new_common_mop_ty: CommonMOp<
|
new_common_mop_ty: CommonMOp<
|
||||||
|
|
@ -564,6 +701,24 @@ impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize
|
||||||
new_common_mop.ty().validate();
|
new_common_mop.ty().validate();
|
||||||
new_common_mop
|
new_common_mop
|
||||||
}
|
}
|
||||||
|
fn with_common_mop_sim<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
|
input: impl ToSimValue<Type = Self>,
|
||||||
|
new_common_mop: impl ToSimValue<
|
||||||
|
Type = CommonMOp<
|
||||||
|
Self::PrefixPad,
|
||||||
|
NewDestReg,
|
||||||
|
NewSrcRegWidth,
|
||||||
|
Self::SrcCount,
|
||||||
|
Self::Imm,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
) -> SimValue<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
|
||||||
|
let input = input.into_sim_value();
|
||||||
|
let new_common_mop = new_common_mop.into_sim_value();
|
||||||
|
input.ty().validate();
|
||||||
|
new_common_mop.ty().validate();
|
||||||
|
new_common_mop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const COMMON_MOP_0_IMM_WIDTH: usize = common_mop_max_imm_size(0);
|
pub const COMMON_MOP_0_IMM_WIDTH: usize = common_mop_max_imm_size(0);
|
||||||
|
|
@ -613,6 +768,27 @@ macro_rules! common_mop_struct {
|
||||||
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>> {
|
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>> {
|
||||||
CommonMOpTrait::common_mop(input.to_expr().$common)
|
CommonMOpTrait::common_mop(input.to_expr().$common)
|
||||||
}
|
}
|
||||||
|
fn common_mop_sim(
|
||||||
|
input: impl ToSimValue<Type = Self>,
|
||||||
|
) -> SimValue<
|
||||||
|
CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>,
|
||||||
|
> {
|
||||||
|
CommonMOpTrait::common_mop_sim(SimValue::into_value(input.into_sim_value()).$common)
|
||||||
|
}
|
||||||
|
fn common_mop_sim_ref(
|
||||||
|
input: &SimValue<Self>,
|
||||||
|
) -> &SimValue<
|
||||||
|
CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>,
|
||||||
|
> {
|
||||||
|
CommonMOpTrait::common_mop_sim_ref(&input.$common)
|
||||||
|
}
|
||||||
|
fn common_mop_sim_mut(
|
||||||
|
input: &mut SimValue<Self>,
|
||||||
|
) -> &mut SimValue<
|
||||||
|
CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount, Self::Imm>,
|
||||||
|
> {
|
||||||
|
CommonMOpTrait::common_mop_sim_mut(&mut input.$common)
|
||||||
|
}
|
||||||
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
|
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
self,
|
self,
|
||||||
new_common_mop_ty: CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount, Self::Imm>,
|
new_common_mop_ty: CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount, Self::Imm>,
|
||||||
|
|
@ -636,6 +812,26 @@ macro_rules! common_mop_struct {
|
||||||
$($field: input.$field,)*
|
$($field: input.$field,)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn with_common_mop_sim<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
|
input: impl ToSimValue<Type = Self>,
|
||||||
|
new_common_mop: impl ToSimValue<
|
||||||
|
Type = CommonMOp<
|
||||||
|
Self::PrefixPad,
|
||||||
|
NewDestReg,
|
||||||
|
NewSrcRegWidth,
|
||||||
|
Self::SrcCount,
|
||||||
|
Self::Imm,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
) -> SimValue<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
|
||||||
|
let input = SimValue::into_value(input.into_sim_value());
|
||||||
|
#[hdl(sim)]
|
||||||
|
Self::Mapped::<NewDestReg, NewSrcRegWidth> {
|
||||||
|
$common: CommonMOpTrait::with_common_mop_sim(input.$common, new_common_mop),
|
||||||
|
$($field: input.$field,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -741,6 +937,37 @@ macro_rules! mop_enum {
|
||||||
}
|
}
|
||||||
dest_reg
|
dest_reg
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn dest_reg_sim(input: impl ToSimValue<Type = Self>) -> SimValue<Self::DestReg> {
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
let input = input.into_sim_value();
|
||||||
|
#[hdl(sim)]
|
||||||
|
match input {
|
||||||
|
Self::$FirstVariant(v) => <$first_ty as MOpTrait>::dest_reg_sim(v),
|
||||||
|
$(Self::$Variant(v) => <$ty as MOpTrait>::dest_reg_sim(v),)*
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn dest_reg_sim_ref(input: &SimValue<Self>) -> &SimValue<Self::DestReg> {
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
#[hdl(sim)]
|
||||||
|
match input {
|
||||||
|
Self::$FirstVariant(v) => <$first_ty as MOpTrait>::dest_reg_sim_ref(v),
|
||||||
|
$(Self::$Variant(v) => <$ty as MOpTrait>::dest_reg_sim_ref(v),)*
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn dest_reg_sim_mut(input: &mut SimValue<Self>) -> &mut SimValue<Self::DestReg> {
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
#[hdl(sim)]
|
||||||
|
match input {
|
||||||
|
Self::$FirstVariant(v) => <$first_ty as MOpTrait>::dest_reg_sim_mut(v),
|
||||||
|
$(Self::$Variant(v) => <$ty as MOpTrait>::dest_reg_sim_mut(v),)*
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
fn src_reg_width(self) -> <Self::SrcRegWidth as Size>::SizeType {
|
fn src_reg_width(self) -> <Self::SrcRegWidth as Size>::SizeType {
|
||||||
self.$FirstVariant.src_reg_width()
|
self.$FirstVariant.src_reg_width()
|
||||||
}
|
}
|
||||||
|
|
@ -755,6 +982,45 @@ macro_rules! mop_enum {
|
||||||
$(Self::$Variant(v) => MOpTrait::for_each_src_reg(v, f),)*
|
$(Self::$Variant(v) => MOpTrait::for_each_src_reg(v, f),)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn for_each_src_reg_sim(
|
||||||
|
input: SimValue<Self>,
|
||||||
|
f: &mut impl FnMut(SimValue<UIntType<Self::SrcRegWidth>>, usize),
|
||||||
|
) {
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
#[hdl(sim)]
|
||||||
|
match input {
|
||||||
|
Self::$FirstVariant(v) => MOpTrait::for_each_src_reg_sim(v, f),
|
||||||
|
$(Self::$Variant(v) => MOpTrait::for_each_src_reg_sim(v, f),)*
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn for_each_src_reg_sim_ref(
|
||||||
|
input: &SimValue<Self>,
|
||||||
|
f: &mut impl FnMut(&SimValue<UIntType<Self::SrcRegWidth>>, usize),
|
||||||
|
) {
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
#[hdl(sim)]
|
||||||
|
match input {
|
||||||
|
Self::$FirstVariant(v) => MOpTrait::for_each_src_reg_sim_ref(v, f),
|
||||||
|
$(Self::$Variant(v) => MOpTrait::for_each_src_reg_sim_ref(v, f),)*
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn for_each_src_reg_sim_mut(
|
||||||
|
input: &mut SimValue<Self>,
|
||||||
|
f: &mut impl FnMut(&mut SimValue<UIntType<Self::SrcRegWidth>>, usize),
|
||||||
|
) {
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
#[hdl(sim)]
|
||||||
|
match input {
|
||||||
|
Self::$FirstVariant(v) => MOpTrait::for_each_src_reg_sim_mut(v, f),
|
||||||
|
$(Self::$Variant(v) => MOpTrait::for_each_src_reg_sim_mut(v, f),)*
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
|
fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
self,
|
self,
|
||||||
new_dest_reg: NewDestReg,
|
new_dest_reg: NewDestReg,
|
||||||
|
|
@ -784,6 +1050,33 @@ macro_rules! mop_enum {
|
||||||
}
|
}
|
||||||
mapped_regs
|
mapped_regs
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn map_regs_sim<NewDestReg: Type, NewSrcRegWidth: Size>(
|
||||||
|
input: impl ToSimValue<Type = Self>,
|
||||||
|
new_dest: impl ToSimValue<Type = NewDestReg>,
|
||||||
|
new_src_reg_width: NewSrcRegWidth::SizeType,
|
||||||
|
map_src: &mut impl FnMut(
|
||||||
|
SimValue<UIntType<Self::SrcRegWidth>>,
|
||||||
|
usize,
|
||||||
|
) -> SimValue<UIntType<NewSrcRegWidth>>,
|
||||||
|
) -> SimValue<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
let input = input.into_sim_value();
|
||||||
|
let new_dest = new_dest.into_sim_value();
|
||||||
|
let mapped_ty = input.ty().mapped_ty(new_dest.ty(), new_src_reg_width);
|
||||||
|
#[hdl(sim)]
|
||||||
|
match input {
|
||||||
|
Self::$FirstVariant(v) => {
|
||||||
|
#[hdl(sim)]
|
||||||
|
mapped_ty.$FirstVariant(MOpTrait::map_regs_sim(v, new_dest, new_src_reg_width, map_src))
|
||||||
|
}
|
||||||
|
$(Self::$Variant(v) => {
|
||||||
|
#[hdl(sim)]
|
||||||
|
mapped_ty.$Variant(MOpTrait::map_regs_sim(v, new_dest, new_src_reg_width, map_src))
|
||||||
|
})*
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
|
|
@ -2595,34 +2888,53 @@ impl<DestReg: Type, SrcRegWidth: Size> MoveRegMOp<DestReg, SrcRegWidth> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq, no_static)]
|
||||||
/// 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<C: PhantomConstGet<CpuConfig>> {
|
||||||
pub adj_value: UIntType<Width>,
|
pub adj_value: UIntType<CpuConfigUnitNumWidth<C>>,
|
||||||
|
pub config: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Width: Size> UnitNum<Width> {
|
impl<C: PhantomConstCpuConfig> UnitNum<C> {
|
||||||
#[hdl]
|
|
||||||
pub fn const_zero(self) -> Expr<Self> {
|
pub fn const_zero(self) -> Expr<Self> {
|
||||||
#[hdl]
|
self.const_zero_sim().to_expr()
|
||||||
UnitNum {
|
|
||||||
adj_value: CONST_ZERO_UNIT_NUM.cast_to(self.adj_value),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
pub fn const_zero_sim(self) -> SimValue<Self> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
UnitNum::<_> {
|
||||||
|
adj_value: CONST_ZERO_UNIT_NUM.cast_to(self.adj_value),
|
||||||
|
config: self.config,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn from_index(self, index: usize) -> Expr<Self> {
|
pub fn from_index(self, index: usize) -> Expr<Self> {
|
||||||
#[hdl]
|
self.from_index_sim(index).to_expr()
|
||||||
UnitNum {
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn from_index_sim(self, index: usize) -> SimValue<Self> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
UnitNum::<_> {
|
||||||
adj_value: (index + 1).cast_to(self.adj_value),
|
adj_value: (index + 1).cast_to(self.adj_value),
|
||||||
|
config: self.config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_index(expr: impl ToExpr<Type = Self>, index: usize) -> Expr<Bool> {
|
pub fn is_index(expr: impl ToExpr<Type = Self>, index: usize) -> Expr<Bool> {
|
||||||
let expr = expr.to_expr();
|
let expr = expr.to_expr();
|
||||||
expr.ty().from_index(index).adj_value.cmp_eq(expr.adj_value)
|
expr.ty().from_index(index).adj_value.cmp_eq(expr.adj_value)
|
||||||
}
|
}
|
||||||
|
pub fn index_sim(expr: &SimValue<Self>) -> Option<usize> {
|
||||||
|
let adj_value = expr.adj_value.cast_to_static::<UInt<32>>().as_int();
|
||||||
|
if adj_value == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(adj_value as usize - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub fn as_index(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<UIntType<Width>>> {
|
pub fn as_index(
|
||||||
|
expr: impl ToExpr<Type = Self>,
|
||||||
|
) -> Expr<HdlOption<UIntType<CpuConfigUnitNumWidth<C>>>> {
|
||||||
let expr = expr.to_expr();
|
let expr = expr.to_expr();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let unit_index = wire(HdlOption[expr.ty().adj_value]);
|
let unit_index = wire(HdlOption[expr.ty().adj_value]);
|
||||||
|
|
@ -2640,19 +2952,20 @@ impl<Width: Size> UnitNum<Width> {
|
||||||
|
|
||||||
pub const CONST_ZERO_UNIT_NUM: usize = 0;
|
pub const CONST_ZERO_UNIT_NUM: usize = 0;
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq, no_static)]
|
||||||
pub struct UnitOutRegNum<Width: Size> {
|
pub struct UnitOutRegNum<C: PhantomConstGet<CpuConfig>> {
|
||||||
pub value: UIntType<Width>,
|
pub value: UIntType<CpuConfigOutRegNumWidth<C>>,
|
||||||
|
pub config: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq, no_static)]
|
||||||
/// 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<C: PhantomConstGet<CpuConfig>> {
|
||||||
pub unit_num: UnitNum<UnitNumWidth>,
|
pub unit_num: UnitNum<C>,
|
||||||
pub unit_out_reg: UnitOutRegNum<OutRegNumWidth>,
|
pub unit_out_reg: UnitOutRegNum<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<UnitNumWidth: Size, OutRegNumWidth: Size> PRegNum<UnitNumWidth, OutRegNumWidth> {
|
impl<C: PhantomConstCpuConfig> PRegNum<C> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub fn const_zero(self) -> Expr<Self> {
|
pub fn const_zero(self) -> Expr<Self> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -2661,6 +2974,7 @@ impl<UnitNumWidth: Size, OutRegNumWidth: Size> PRegNum<UnitNumWidth, OutRegNumWi
|
||||||
unit_out_reg: #[hdl]
|
unit_out_reg: #[hdl]
|
||||||
UnitOutRegNum {
|
UnitOutRegNum {
|
||||||
value: 0u8.cast_to(self.unit_out_reg.value),
|
value: 0u8.cast_to(self.unit_out_reg.value),
|
||||||
|
config: self.unit_out_reg.config,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@ pub mod instruction;
|
||||||
pub mod main_memory_and_io;
|
pub mod main_memory_and_io;
|
||||||
pub mod next_pc;
|
pub mod next_pc;
|
||||||
pub mod powerisa_instructions_xml;
|
pub mod powerisa_instructions_xml;
|
||||||
|
#[cfg(todo)]
|
||||||
pub mod reg_alloc;
|
pub mod reg_alloc;
|
||||||
pub mod register;
|
pub mod register;
|
||||||
|
pub mod rename_execute_retire;
|
||||||
pub mod unit;
|
pub mod unit;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
|
||||||
766
crates/cpu/src/rename_execute_retire.rs
Normal file
766
crates/cpu/src/rename_execute_retire.rs
Normal file
|
|
@ -0,0 +1,766 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::{
|
||||||
|
CpuConfig, CpuConfig2PowOutRegNumWidth, CpuConfigFetchWidth, CpuConfigMaxUnitMaxInFlight,
|
||||||
|
CpuConfigPRegNumWidth, CpuConfigRobSize, CpuConfigUnitCount, PhantomConstCpuConfig,
|
||||||
|
TwiceCpuConfigFetchWidth,
|
||||||
|
},
|
||||||
|
instruction::{MOp, MOpRegNum, MOpTrait, PRegNum, RenamedMOp, UnitNum},
|
||||||
|
next_pc::{CallStackOp, SimValueDefault},
|
||||||
|
unit::{UnitKind, UnitMOp},
|
||||||
|
util::array_vec::ArrayVec,
|
||||||
|
};
|
||||||
|
use fayalite::{
|
||||||
|
int::UIntInRangeInclusiveType,
|
||||||
|
prelude::*,
|
||||||
|
ty::{OpaqueSimValue, StaticType},
|
||||||
|
util::ready_valid::ReadyValid,
|
||||||
|
};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
pub const MOP_ID_WIDTH: usize = 16;
|
||||||
|
#[hdl]
|
||||||
|
pub type MOpId = UInt<{ MOP_ID_WIDTH }>;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
/// A µOp along with the state needed for this instance of the µOp.
|
||||||
|
pub struct MOpInstance<MOp> {
|
||||||
|
pub fetch_block_id: UInt<8>,
|
||||||
|
pub id: MOpId,
|
||||||
|
pub pc: UInt<64>,
|
||||||
|
/// initialized to 0 by decoder, overwritten by `next_pc()`
|
||||||
|
pub predicted_next_pc: UInt<64>,
|
||||||
|
pub size_in_bytes: UInt<4>,
|
||||||
|
/// `true` if this µOp is the first µOp in the ISA-level instruction.
|
||||||
|
/// In general, a single µOp can't be cancelled by itself,
|
||||||
|
/// it needs to be cancelled along with all other µOps that
|
||||||
|
/// come from the same ISA-level instruction.
|
||||||
|
pub is_first_mop_in_insn: Bool,
|
||||||
|
pub mop: MOp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
/// TODO: merge with [`crate::next_pc::PostDecodeOutputInterface`]
|
||||||
|
pub struct PostDecodeOutputInterface<C: PhantomConstGet<CpuConfig>> {
|
||||||
|
pub insns: ArrayVec<MOpInstance<MOp>, CpuConfigFetchWidth<C>>,
|
||||||
|
#[hdl(flip)]
|
||||||
|
pub ready: UIntInRangeInclusiveType<ConstUsize<0>, CpuConfigFetchWidth<C>>,
|
||||||
|
/// tells the rename/execute/retire circuit to cancel all non-retired instructions
|
||||||
|
pub cancel: ReadyValid<()>,
|
||||||
|
pub config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct NextPcPredictorOp<C: PhantomConstGet<CpuConfig>> {
|
||||||
|
pub call_stack_op: CallStackOp,
|
||||||
|
/// should be `HdlSome(taken)` for any conditional control-flow instruction
|
||||||
|
/// with an immediate target that can be predicted as taken/not-taken (branch/call/return).
|
||||||
|
pub cond_br_taken: HdlOption<Bool>,
|
||||||
|
pub config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
/// TODO: merge with [`crate::next_pc::RetireToNextPcInterfaceInner`]
|
||||||
|
pub enum RetireToNextPcInterfaceInner<C: PhantomConstGet<CpuConfig>> {
|
||||||
|
CancelAndStartAt(UInt<64>),
|
||||||
|
RetiredInstructions(ArrayVec<NextPcPredictorOp<C>, CpuConfigFetchWidth<C>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
/// handles updating speculative branch predictor state (e.g. branch histories)
|
||||||
|
/// when instructions retire, as well as updating state when a
|
||||||
|
/// branch instruction is mis-speculated.
|
||||||
|
pub struct RetireToNextPcInterface<C: PhantomConstGet<CpuConfig>> {
|
||||||
|
pub inner: ReadyValid<RetireToNextPcInterfaceInner<C>>,
|
||||||
|
/// only for debugging
|
||||||
|
pub next_insns: HdlOption<ArrayVec<MOpInstance<MOp>, CpuConfigRobSize<C>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zeroed<T: Type>(ty: T) -> SimValue<T> {
|
||||||
|
SimValue::from_opaque(
|
||||||
|
ty,
|
||||||
|
OpaqueSimValue::from_bits(UInt::new(ty.canonical().bit_width()).zero()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: PhantomConstCpuConfig> SimValueDefault for RenameExecuteRetireDebugState<C> {
|
||||||
|
fn sim_value_default(self) -> SimValue<Self> {
|
||||||
|
zeroed(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
enum RenameTableEntry<C: PhantomConstGet<CpuConfig>> {
|
||||||
|
L1(PRegNum<C>),
|
||||||
|
L2(MOpRegNum),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: PhantomConstCpuConfig> RenameTableEntry<C> {
|
||||||
|
#[hdl]
|
||||||
|
fn const_zero(self) -> SimValue<Self> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
self.L1(self.L1.const_zero())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// make arrays dynamically-sized to avoid putting large types on the stack
|
||||||
|
#[hdl(get(|c| 1 << MOpRegNum::WIDTH))]
|
||||||
|
type MOpRegCount<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
struct RenameTableDebugState<C: PhantomConstGet<CpuConfig>> {
|
||||||
|
entries: ArrayType<RenameTableEntry<C>, MOpRegCount<C>>,
|
||||||
|
prev_entries: ArrayType<RenameTableEntry<C>, MOpRegCount<C>>,
|
||||||
|
free_regs: ArrayType<ArrayType<Bool, CpuConfig2PowOutRegNumWidth<C>>, CpuConfigUnitCount<C>>,
|
||||||
|
free_l2_regs: ArrayType<Bool, MOpRegCount<C>>,
|
||||||
|
config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct RenameTable<C: PhantomConstCpuConfig> {
|
||||||
|
entries: Box<[SimValue<RenameTableEntry<C>>; 1 << MOpRegNum::WIDTH]>,
|
||||||
|
prev_entries: Box<[SimValue<RenameTableEntry<C>>; 1 << MOpRegNum::WIDTH]>,
|
||||||
|
free_regs: Box<[Box<[bool]>]>,
|
||||||
|
free_l2_regs: Box<[bool; 1 << MOpRegNum::WIDTH]>,
|
||||||
|
config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: PhantomConstCpuConfig> Clone for RenameTable<C> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
entries: self.entries.clone(),
|
||||||
|
prev_entries: self.prev_entries.clone(),
|
||||||
|
free_regs: self.free_regs.clone(),
|
||||||
|
free_l2_regs: self.free_l2_regs.clone(),
|
||||||
|
config: self.config.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn clone_from(&mut self, source: &Self) {
|
||||||
|
let Self {
|
||||||
|
entries,
|
||||||
|
prev_entries,
|
||||||
|
free_regs,
|
||||||
|
free_l2_regs,
|
||||||
|
config,
|
||||||
|
} = self;
|
||||||
|
entries.clone_from(&source.entries);
|
||||||
|
prev_entries.clone_from(&source.prev_entries);
|
||||||
|
free_regs.clone_from(&source.free_regs);
|
||||||
|
free_l2_regs.clone_from(&source.free_l2_regs);
|
||||||
|
*config = source.config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: PhantomConstCpuConfig> RenameTable<C> {
|
||||||
|
fn new(config: C) -> Self {
|
||||||
|
let entries: Box<[SimValue<RenameTableEntry<C>>; 1 << MOpRegNum::WIDTH]> =
|
||||||
|
vec![RenameTableEntry[config].const_zero(); 1 << MOpRegNum::WIDTH]
|
||||||
|
.try_into()
|
||||||
|
.expect("size is known to match");
|
||||||
|
let free_regs_for_unit = vec![true; CpuConfig2PowOutRegNumWidth[config]].into_boxed_slice();
|
||||||
|
let free_regs = vec![free_regs_for_unit; CpuConfigUnitCount[config]].into_boxed_slice();
|
||||||
|
Self {
|
||||||
|
entries: entries.clone(),
|
||||||
|
prev_entries: entries,
|
||||||
|
free_regs,
|
||||||
|
free_l2_regs: vec![true; 1 << MOpRegNum::WIDTH]
|
||||||
|
.try_into()
|
||||||
|
.expect("size is known to match"),
|
||||||
|
config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn to_debug_state(&self) -> SimValue<RenameTableDebugState<C>> {
|
||||||
|
let Self {
|
||||||
|
entries,
|
||||||
|
prev_entries,
|
||||||
|
free_regs,
|
||||||
|
free_l2_regs,
|
||||||
|
config,
|
||||||
|
} = self;
|
||||||
|
let ty = RenameTableDebugState[*config];
|
||||||
|
#[hdl(sim)]
|
||||||
|
RenameTableDebugState::<_> {
|
||||||
|
entries: entries.to_sim_value_with_type(ty.entries),
|
||||||
|
prev_entries: prev_entries.to_sim_value_with_type(ty.prev_entries),
|
||||||
|
free_regs: free_regs.to_sim_value_with_type(ty.free_regs),
|
||||||
|
free_l2_regs: free_l2_regs.to_sim_value_with_type(ty.free_l2_regs),
|
||||||
|
config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
struct RobEntryDebugState<C: PhantomConstGet<CpuConfig>> {
|
||||||
|
mop: MOpInstance<RenamedMOp<PRegNum<C>, CpuConfigPRegNumWidth<C>>>,
|
||||||
|
unit_num: UnitNum<C>,
|
||||||
|
config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: PhantomConstCpuConfig> SimValueDefault for RobEntryDebugState<C> {
|
||||||
|
fn sim_value_default(self) -> SimValue<Self> {
|
||||||
|
zeroed(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct RobEntry<C: PhantomConstCpuConfig> {
|
||||||
|
mop: SimValue<MOpInstance<RenamedMOp<PRegNum<C>, CpuConfigPRegNumWidth<C>>>>,
|
||||||
|
unit_index: usize,
|
||||||
|
config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
struct OrigMOpQueueEntryDebugState {
|
||||||
|
mop: MOpInstance<MOp>,
|
||||||
|
/// number of renamed µOps that this non-renamed µOp corresponds to
|
||||||
|
renamed_mop_count: UInt<8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct OrigMOpQueueEntry {
|
||||||
|
mop: SimValue<MOpInstance<MOp>>,
|
||||||
|
/// number of renamed µOps that this non-renamed µOp corresponds to
|
||||||
|
renamed_mop_count: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
struct UnitDebugState<C: PhantomConstGet<CpuConfig>> {
|
||||||
|
assigned_rob_entries: ArrayVec<MOpId, CpuConfigMaxUnitMaxInFlight<C>>,
|
||||||
|
/// see [`UnitState::started_l2_store`]
|
||||||
|
started_l2_store: Bool,
|
||||||
|
config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct UnitState<C: PhantomConstCpuConfig> {
|
||||||
|
assigned_rob_entries: VecDeque<SimValue<MOpId>>,
|
||||||
|
/// `true` if a L2 register file write was started for this unit after the last µOp was
|
||||||
|
/// assigned to this unit.
|
||||||
|
/// So, if this unit runs out of registers and a L2 register file write is started, this gets
|
||||||
|
/// set to `true`, and if a new µOp is assigned to this unit, this gets set to `false`.
|
||||||
|
started_l2_store: bool,
|
||||||
|
config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: PhantomConstCpuConfig> UnitState<C> {
|
||||||
|
fn finish_cancel(&mut self) {
|
||||||
|
let Self {
|
||||||
|
assigned_rob_entries,
|
||||||
|
started_l2_store,
|
||||||
|
config: _,
|
||||||
|
} = self;
|
||||||
|
assigned_rob_entries.clear();
|
||||||
|
*started_l2_store = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
enum CancelingDebugState {
|
||||||
|
NeedSendCancel(UInt<64>),
|
||||||
|
NeedReceiveCancel,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
enum CancelingState {
|
||||||
|
NeedSendCancel(u64),
|
||||||
|
NeedReceiveCancel,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct RenameExecuteRetireDebugState<C: PhantomConstGet<CpuConfig>> {
|
||||||
|
next_mop_id: MOpId,
|
||||||
|
rename_delayed: ArrayVec<MOpInstance<MOp>, TwiceCpuConfigFetchWidth<C>>,
|
||||||
|
next_renamed_mop_count: UInt<8>,
|
||||||
|
rename_table: RenameTableDebugState<C>,
|
||||||
|
retire_rename_table: RenameTableDebugState<C>,
|
||||||
|
rob: ArrayVec<RobEntryDebugState<C>, CpuConfigRobSize<C>>,
|
||||||
|
orig_mop_queue: ArrayVec<OrigMOpQueueEntryDebugState, CpuConfigRobSize<C>>,
|
||||||
|
units: ArrayType<UnitDebugState<C>, CpuConfigUnitCount<C>>,
|
||||||
|
canceling: HdlOption<CancelingDebugState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct RenameExecuteRetireState<C: PhantomConstCpuConfig> {
|
||||||
|
next_mop_id: SimValue<MOpId>,
|
||||||
|
rename_delayed: VecDeque<SimValue<MOpInstance<MOp>>>,
|
||||||
|
/// count of renamed µOps that have been started that correspond to the next un-renamed µOp in `rename_delayed`
|
||||||
|
next_renamed_mop_count: u8,
|
||||||
|
rename_table: RenameTable<C>,
|
||||||
|
retire_rename_table: RenameTable<C>,
|
||||||
|
rob: VecDeque<RobEntry<C>>,
|
||||||
|
orig_mop_queue: VecDeque<OrigMOpQueueEntry>,
|
||||||
|
units: Box<[UnitState<C>]>,
|
||||||
|
canceling: Option<CancelingState>,
|
||||||
|
l2_reg_file_unit_index: usize,
|
||||||
|
config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
|
||||||
|
fn new(config: C) -> Self {
|
||||||
|
let rename_table = RenameTable::new(config);
|
||||||
|
Self {
|
||||||
|
next_mop_id: MOpId.zero().into_sim_value(),
|
||||||
|
rename_delayed: VecDeque::with_capacity(TwiceCpuConfigFetchWidth[config]),
|
||||||
|
next_renamed_mop_count: 0,
|
||||||
|
rename_table: rename_table.clone(),
|
||||||
|
retire_rename_table: rename_table,
|
||||||
|
rob: VecDeque::with_capacity(CpuConfigRobSize[config]),
|
||||||
|
orig_mop_queue: VecDeque::with_capacity(CpuConfigRobSize[config]),
|
||||||
|
units: Box::from_iter((0..config.get().units.len()).map(|unit_index| UnitState {
|
||||||
|
assigned_rob_entries: VecDeque::with_capacity(
|
||||||
|
config.get().unit_max_in_flight(unit_index).get(),
|
||||||
|
),
|
||||||
|
started_l2_store: false,
|
||||||
|
config,
|
||||||
|
})),
|
||||||
|
canceling: None,
|
||||||
|
l2_reg_file_unit_index: config
|
||||||
|
.get()
|
||||||
|
.units
|
||||||
|
.iter()
|
||||||
|
.position(|unit| unit.kind == UnitKind::TransformedMove)
|
||||||
|
.expect("Unit for L2 register file is missing"),
|
||||||
|
config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
async fn write_for_debug(
|
||||||
|
&self,
|
||||||
|
sim: &mut ExternModuleSimulationState,
|
||||||
|
state_for_debug: Expr<RenameExecuteRetireDebugState<C>>,
|
||||||
|
) {
|
||||||
|
let Self {
|
||||||
|
ref next_mop_id,
|
||||||
|
ref rename_delayed,
|
||||||
|
next_renamed_mop_count,
|
||||||
|
ref rename_table,
|
||||||
|
ref retire_rename_table,
|
||||||
|
ref rob,
|
||||||
|
ref orig_mop_queue,
|
||||||
|
ref units,
|
||||||
|
ref canceling,
|
||||||
|
l2_reg_file_unit_index: _,
|
||||||
|
config,
|
||||||
|
} = *self;
|
||||||
|
sim.write(
|
||||||
|
state_for_debug,
|
||||||
|
#[hdl(sim)]
|
||||||
|
RenameExecuteRetireDebugState::<_> {
|
||||||
|
next_mop_id,
|
||||||
|
rename_delayed: state_for_debug
|
||||||
|
.ty()
|
||||||
|
.rename_delayed
|
||||||
|
.from_iter_sim(zeroed(StaticType::TYPE), rename_delayed)
|
||||||
|
.expect("known to fit"),
|
||||||
|
next_renamed_mop_count,
|
||||||
|
rename_table: rename_table.to_debug_state(),
|
||||||
|
retire_rename_table: retire_rename_table.to_debug_state(),
|
||||||
|
rob: state_for_debug
|
||||||
|
.ty()
|
||||||
|
.rob
|
||||||
|
.from_iter_sim(
|
||||||
|
zeroed(RobEntryDebugState[config]),
|
||||||
|
rob.iter().map(|entry| {
|
||||||
|
let RobEntry {
|
||||||
|
mop,
|
||||||
|
unit_index,
|
||||||
|
config: _,
|
||||||
|
} = entry;
|
||||||
|
#[hdl(sim)]
|
||||||
|
RobEntryDebugState::<_> {
|
||||||
|
mop,
|
||||||
|
unit_num: UnitNum[config].from_index_sim(*unit_index),
|
||||||
|
config,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.expect("known to fit"),
|
||||||
|
orig_mop_queue: state_for_debug
|
||||||
|
.ty()
|
||||||
|
.orig_mop_queue
|
||||||
|
.from_iter_sim(
|
||||||
|
zeroed(OrigMOpQueueEntryDebugState),
|
||||||
|
orig_mop_queue.iter().map(|entry| {
|
||||||
|
let OrigMOpQueueEntry {
|
||||||
|
mop,
|
||||||
|
renamed_mop_count,
|
||||||
|
} = entry;
|
||||||
|
#[hdl(sim)]
|
||||||
|
OrigMOpQueueEntryDebugState {
|
||||||
|
mop,
|
||||||
|
renamed_mop_count,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.expect("known to fit"),
|
||||||
|
units: SimValue::from_array_elements(
|
||||||
|
state_for_debug.ty().units,
|
||||||
|
units.iter().map(|unit| {
|
||||||
|
let UnitState {
|
||||||
|
assigned_rob_entries,
|
||||||
|
started_l2_store,
|
||||||
|
config: _,
|
||||||
|
} = unit;
|
||||||
|
let ty = UnitDebugState[config];
|
||||||
|
#[hdl(sim)]
|
||||||
|
UnitDebugState::<_> {
|
||||||
|
assigned_rob_entries: ty
|
||||||
|
.assigned_rob_entries
|
||||||
|
.from_iter_sim(zeroed(UInt::new_static()), assigned_rob_entries)
|
||||||
|
.expect("known to fit"),
|
||||||
|
started_l2_store,
|
||||||
|
config,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
canceling: match canceling {
|
||||||
|
Some(canceling) =>
|
||||||
|
{
|
||||||
|
#[hdl(sim)]
|
||||||
|
HdlSome(match canceling {
|
||||||
|
CancelingState::NeedSendCancel(v) =>
|
||||||
|
{
|
||||||
|
#[hdl(sim)]
|
||||||
|
CancelingDebugState.NeedSendCancel(v)
|
||||||
|
}
|
||||||
|
CancelingState::NeedReceiveCancel =>
|
||||||
|
{
|
||||||
|
#[hdl(sim)]
|
||||||
|
CancelingDebugState.NeedReceiveCancel()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None =>
|
||||||
|
{
|
||||||
|
#[hdl(sim)]
|
||||||
|
HdlNone()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
async fn write_to_next_pc_next_insns(
|
||||||
|
&self,
|
||||||
|
sim: &mut ExternModuleSimulationState,
|
||||||
|
next_insns: Expr<HdlOption<ArrayVec<MOpInstance<MOp>, CpuConfigRobSize<C>>>>,
|
||||||
|
) {
|
||||||
|
sim.write(
|
||||||
|
next_insns,
|
||||||
|
if self.canceling.is_some() {
|
||||||
|
#[hdl(sim)]
|
||||||
|
(next_insns.ty()).HdlNone()
|
||||||
|
} else {
|
||||||
|
#[hdl(sim)]
|
||||||
|
(next_insns.ty()).HdlSome(
|
||||||
|
next_insns
|
||||||
|
.ty()
|
||||||
|
.HdlSome
|
||||||
|
.from_iter_sim(
|
||||||
|
zeroed(MOpInstance[MOp]),
|
||||||
|
self.rename_delayed
|
||||||
|
.iter()
|
||||||
|
.chain(self.orig_mop_queue.iter().map(|entry| &entry.mop)),
|
||||||
|
)
|
||||||
|
.expect("known to fit"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
fn space_available_for_unit(&self, unit_index: usize) -> usize {
|
||||||
|
self.config
|
||||||
|
.get()
|
||||||
|
.unit_max_in_flight(unit_index)
|
||||||
|
.get()
|
||||||
|
.saturating_sub(self.units[unit_index].assigned_rob_entries.len())
|
||||||
|
}
|
||||||
|
//#[hdl]
|
||||||
|
fn try_rename(
|
||||||
|
&mut self,
|
||||||
|
insn: SimValue<MOpInstance<MOp>>,
|
||||||
|
) -> Result<(), SimValue<MOpInstance<MOp>>> {
|
||||||
|
let unit_kind = UnitMOp::kind_sim(&insn.mop);
|
||||||
|
if let UnitKind::TransformedMove = unit_kind {
|
||||||
|
todo!("handle reg-reg moves in rename stage");
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct ChosenUnit {
|
||||||
|
unit_index: usize,
|
||||||
|
out_reg_num: Option<usize>,
|
||||||
|
space_available: usize,
|
||||||
|
}
|
||||||
|
impl ChosenUnit {
|
||||||
|
fn is_better_than(self, other: Self) -> bool {
|
||||||
|
let Self {
|
||||||
|
unit_index: _,
|
||||||
|
out_reg_num,
|
||||||
|
space_available,
|
||||||
|
} = self;
|
||||||
|
if out_reg_num.is_some() != other.out_reg_num.is_some() {
|
||||||
|
out_reg_num.is_some()
|
||||||
|
} else {
|
||||||
|
space_available > other.space_available
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut chosen_unit = None;
|
||||||
|
for (unit_index, unit_state) in self.units.iter().enumerate() {
|
||||||
|
if self.config.get().units[unit_index].kind != unit_kind {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let cur_unit = ChosenUnit {
|
||||||
|
unit_index,
|
||||||
|
out_reg_num: self.rename_table.free_regs[unit_index]
|
||||||
|
.iter()
|
||||||
|
.position(|v| *v),
|
||||||
|
space_available: self.space_available_for_unit(unit_index),
|
||||||
|
};
|
||||||
|
let chosen_unit = chosen_unit.get_or_insert(cur_unit);
|
||||||
|
if cur_unit.is_better_than(*chosen_unit) {
|
||||||
|
*chosen_unit = cur_unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let Some(ChosenUnit {
|
||||||
|
unit_index,
|
||||||
|
out_reg_num,
|
||||||
|
space_available,
|
||||||
|
}) = chosen_unit
|
||||||
|
else {
|
||||||
|
panic!(
|
||||||
|
"there are no units of kind: {unit_kind:?}:\n{:?}",
|
||||||
|
self.config,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if space_available == 0 {
|
||||||
|
return Err(insn);
|
||||||
|
}
|
||||||
|
let Some(out_reg_num) = out_reg_num else {
|
||||||
|
if self.units[unit_index].started_l2_store {
|
||||||
|
if self.space_available_for_unit(self.l2_reg_file_unit_index) > 0 {
|
||||||
|
todo!("start a L2 register file store");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(insn);
|
||||||
|
};
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn get_from_post_decode_ready(&self) -> usize {
|
||||||
|
if self.canceling.is_some() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
TwiceCpuConfigFetchWidth[self.config]
|
||||||
|
.saturating_sub(self.rename_delayed.len())
|
||||||
|
.min(CpuConfigFetchWidth[self.config])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn handle_from_post_decode(&mut self, insns: &[SimValue<MOpInstance<MOp>>]) {
|
||||||
|
if insns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert!(self.canceling.is_none());
|
||||||
|
for insn in insns {
|
||||||
|
self.rename_delayed.push_back(insn.clone());
|
||||||
|
}
|
||||||
|
for _ in 0..CpuConfigFetchWidth[self.config] {
|
||||||
|
let Some(insn) = self.rename_delayed.pop_front() else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
match self.try_rename(insn) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(insn) => {
|
||||||
|
self.rename_delayed.push_front(insn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn finish_receive_cancel(&mut self) {
|
||||||
|
let Self {
|
||||||
|
next_mop_id: _,
|
||||||
|
rename_delayed,
|
||||||
|
next_renamed_mop_count,
|
||||||
|
rename_table,
|
||||||
|
retire_rename_table,
|
||||||
|
rob,
|
||||||
|
orig_mop_queue,
|
||||||
|
units,
|
||||||
|
canceling,
|
||||||
|
l2_reg_file_unit_index: _,
|
||||||
|
config: _,
|
||||||
|
} = self;
|
||||||
|
assert_eq!(*canceling, Some(CancelingState::NeedReceiveCancel));
|
||||||
|
rename_delayed.clear();
|
||||||
|
*next_renamed_mop_count = 0;
|
||||||
|
rename_table.clone_from(retire_rename_table);
|
||||||
|
rob.clear();
|
||||||
|
orig_mop_queue.clear();
|
||||||
|
for unit in units {
|
||||||
|
unit.finish_cancel();
|
||||||
|
}
|
||||||
|
*canceling = None;
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn finish_send_cancel(&mut self) {
|
||||||
|
assert!(matches!(
|
||||||
|
self.canceling,
|
||||||
|
Some(CancelingState::NeedSendCancel(_))
|
||||||
|
));
|
||||||
|
self.canceling = Some(CancelingState::NeedReceiveCancel);
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
fn retire_peek(&self) -> SimValue<HdlOption<RetireToNextPcInterfaceInner<C>>> {
|
||||||
|
let ty = RetireToNextPcInterfaceInner[self.config];
|
||||||
|
let next_pc_predictor_op = NextPcPredictorOp[self.config];
|
||||||
|
match self.canceling {
|
||||||
|
Some(CancelingState::NeedSendCancel(v)) =>
|
||||||
|
{
|
||||||
|
#[hdl(sim)]
|
||||||
|
(HdlOption[ty]).HdlSome(
|
||||||
|
#[hdl(sim)]
|
||||||
|
ty.CancelAndStartAt(v),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Some(CancelingState::NeedReceiveCancel) =>
|
||||||
|
{
|
||||||
|
#[hdl(sim)]
|
||||||
|
(HdlOption[ty]).HdlNone()
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let mut retired_insns = Vec::<SimValue<NextPcPredictorOp<_>>>::new();
|
||||||
|
// TODO: implement
|
||||||
|
#[hdl(sim)]
|
||||||
|
(HdlOption[ty]).HdlSome(
|
||||||
|
#[hdl(sim)]
|
||||||
|
ty.RetiredInstructions(
|
||||||
|
ty.RetiredInstructions
|
||||||
|
.from_iter_sim(zeroed(next_pc_predictor_op), retired_insns)
|
||||||
|
.expect("known to fit"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn retire_one(&mut self, retire: &SimValue<NextPcPredictorOp<C>>) {
|
||||||
|
assert!(self.canceling.is_none());
|
||||||
|
todo!("{retire:#?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
async fn rename_execute_retire_run(
|
||||||
|
mut sim: ExternModuleSimulationState,
|
||||||
|
cd: Expr<ClockDomain>,
|
||||||
|
from_post_decode: Expr<PostDecodeOutputInterface<PhantomConst<CpuConfig>>>,
|
||||||
|
to_next_pc: Expr<RetireToNextPcInterface<PhantomConst<CpuConfig>>>,
|
||||||
|
state_for_debug: Expr<RenameExecuteRetireDebugState<PhantomConst<CpuConfig>>>,
|
||||||
|
config: PhantomConst<CpuConfig>,
|
||||||
|
) {
|
||||||
|
let mut state = RenameExecuteRetireState::new(config);
|
||||||
|
loop {
|
||||||
|
state
|
||||||
|
.write_to_next_pc_next_insns(&mut sim, to_next_pc.next_insns)
|
||||||
|
.await;
|
||||||
|
state.write_for_debug(&mut sim, state_for_debug).await;
|
||||||
|
let from_post_decode_ready = state.get_from_post_decode_ready();
|
||||||
|
assert!(from_post_decode_ready <= from_post_decode.ty().ready.end());
|
||||||
|
sim.write(from_post_decode.ready, from_post_decode_ready)
|
||||||
|
.await;
|
||||||
|
sim.write(
|
||||||
|
from_post_decode.cancel.ready,
|
||||||
|
state.canceling == Some(CancelingState::NeedReceiveCancel),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let retire_peek = state.retire_peek();
|
||||||
|
sim.write(to_next_pc.inner.data, &retire_peek).await;
|
||||||
|
sim.wait_for_clock_edge(cd.clk).await;
|
||||||
|
let from_post_decode_insns = sim.read_past(from_post_decode.insns, cd.clk).await;
|
||||||
|
let from_post_decode_insns = ArrayVec::elements_sim_ref(&from_post_decode_insns);
|
||||||
|
state.handle_from_post_decode(
|
||||||
|
from_post_decode_insns
|
||||||
|
.get(..from_post_decode_ready)
|
||||||
|
.unwrap_or(from_post_decode_insns),
|
||||||
|
);
|
||||||
|
match state.canceling {
|
||||||
|
Some(CancelingState::NeedReceiveCancel) => {
|
||||||
|
#[hdl(sim)]
|
||||||
|
if let HdlSome(_) = sim.read_past(from_post_decode.cancel.data, cd.clk).await {
|
||||||
|
state.finish_receive_cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(CancelingState::NeedSendCancel(_)) => {
|
||||||
|
if sim.read_past_bool(to_next_pc.inner.ready, cd.clk).await {
|
||||||
|
state.finish_send_cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if sim.read_past_bool(to_next_pc.inner.ready, cd.clk).await {
|
||||||
|
let ops = #[hdl(sim)]
|
||||||
|
if let HdlSome(v) = retire_peek {
|
||||||
|
#[hdl(sim)]
|
||||||
|
if let RetireToNextPcInterfaceInner::<_>::RetiredInstructions(ops) = v {
|
||||||
|
ops
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
for op in ArrayVec::elements_sim_ref(&ops) {
|
||||||
|
state.retire_one(op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module(extern)]
|
||||||
|
pub fn rename_execute_retire(config: PhantomConst<CpuConfig>) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let from_post_decode: PostDecodeOutputInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.input(PostDecodeOutputInterface[config]);
|
||||||
|
#[hdl]
|
||||||
|
let to_next_pc: RetireToNextPcInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.output(RetireToNextPcInterface[config]);
|
||||||
|
#[hdl]
|
||||||
|
let state_for_debug: RenameExecuteRetireDebugState<PhantomConst<CpuConfig>> =
|
||||||
|
m.output(RenameExecuteRetireDebugState[config]);
|
||||||
|
m.register_clock_for_past(cd.clk);
|
||||||
|
m.extern_module_simulation_fn(
|
||||||
|
(cd, from_post_decode, to_next_pc, state_for_debug, config),
|
||||||
|
|(cd, from_post_decode, to_next_pc, state_for_debug, config), mut sim| async move {
|
||||||
|
sim.write(state_for_debug, state_for_debug.ty().sim_value_default())
|
||||||
|
.await;
|
||||||
|
sim.resettable(
|
||||||
|
cd,
|
||||||
|
|mut sim: ExternModuleSimulationState| async move {
|
||||||
|
sim.write(from_post_decode.ready, 0usize).await;
|
||||||
|
sim.write(from_post_decode.cancel.ready, false).await;
|
||||||
|
sim.write(to_next_pc.inner.data, to_next_pc.ty().inner.data.HdlNone())
|
||||||
|
.await;
|
||||||
|
sim.write(to_next_pc.next_insns, to_next_pc.ty().next_insns.HdlNone())
|
||||||
|
.await;
|
||||||
|
},
|
||||||
|
|sim, ()| {
|
||||||
|
rename_execute_retire_run(
|
||||||
|
sim,
|
||||||
|
cd,
|
||||||
|
from_post_decode,
|
||||||
|
to_next_pc,
|
||||||
|
state_for_debug,
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::{CpuConfig, PhantomConstCpuConfig},
|
||||||
instruction::{
|
instruction::{
|
||||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait,
|
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait,
|
||||||
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, UnitOutRegNum,
|
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, UnitOutRegNum,
|
||||||
|
|
@ -32,7 +32,7 @@ macro_rules! all_units {
|
||||||
$(
|
$(
|
||||||
$(#[transformed_move $($transformed_move:tt)*])?
|
$(#[transformed_move $($transformed_move:tt)*])?
|
||||||
#[create_dyn_unit_fn = $create_dyn_unit_fn:expr]
|
#[create_dyn_unit_fn = $create_dyn_unit_fn:expr]
|
||||||
#[extract = $extract:ident]
|
#[extract($extract:ident, $extract_sim:ident, $extract_sim_ref:ident, $extract_sim_mut:ident)]
|
||||||
$(#[$variant_meta:meta])*
|
$(#[$variant_meta:meta])*
|
||||||
$Unit:ident($Op:ty),
|
$Unit:ident($Op:ty),
|
||||||
)*
|
)*
|
||||||
|
|
@ -48,7 +48,7 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $UnitKind {
|
impl $UnitKind {
|
||||||
pub fn unit(self, config: &CpuConfig, unit_index: usize) -> DynUnit {
|
pub fn unit(self, config: PhantomConst<CpuConfig>, unit_index: usize) -> DynUnit {
|
||||||
match self {
|
match self {
|
||||||
$($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index),)*
|
$($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index),)*
|
||||||
}
|
}
|
||||||
|
|
@ -112,6 +112,15 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
unit_kind
|
unit_kind
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
$vis fn kind_sim(expr: &SimValue<Self>) -> UnitKind {
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
#[hdl(sim)]
|
||||||
|
match expr {
|
||||||
|
$(Self::$Unit(_) => $UnitKind::$Unit,)*
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
$(
|
$(
|
||||||
#[hdl]
|
#[hdl]
|
||||||
$vis fn $extract(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<$Op>> {
|
$vis fn $extract(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<$Op>> {
|
||||||
|
|
@ -126,6 +135,34 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
$extract
|
$extract
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
$vis fn $extract_sim(expr: impl ToSimValue<Type = Self>) -> Option<SimValue<$Op>> {
|
||||||
|
let expr = expr.into_sim_value();
|
||||||
|
#[hdl(sim)]
|
||||||
|
if let Self::$Unit(v) = expr {
|
||||||
|
Some(v)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
$vis fn $extract_sim_ref(expr: &SimValue<Self>) -> Option<&SimValue<$Op>> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
if let Self::$Unit(v) = expr {
|
||||||
|
Some(v)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
$vis fn $extract_sim_mut(expr: &mut SimValue<Self>) -> Option<&mut SimValue<$Op>> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
if let Self::$Unit(v) = expr {
|
||||||
|
Some(v)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
)*
|
)*
|
||||||
$vis fn with_transformed_move_op_ty<T>(self, new_transformed_move_op_ty: T) -> $UnitMOpEnum<$DestReg, $SrcRegWidth, T>
|
$vis fn with_transformed_move_op_ty<T>(self, new_transformed_move_op_ty: T) -> $UnitMOpEnum<$DestReg, $SrcRegWidth, T>
|
||||||
where
|
where
|
||||||
|
|
@ -254,14 +291,14 @@ all_units! {
|
||||||
})] TransformedMoveOp: Type
|
})] TransformedMoveOp: Type
|
||||||
> {
|
> {
|
||||||
#[create_dyn_unit_fn = |config, unit_index| alu_branch::AluBranch::new(config, unit_index).to_dyn()]
|
#[create_dyn_unit_fn = |config, unit_index| alu_branch::AluBranch::new(config, unit_index).to_dyn()]
|
||||||
#[extract = alu_branch_mop]
|
#[extract(alu_branch_mop, alu_branch_mop_sim, alu_branch_mop_sim_ref, alu_branch_mop_sim_mut)]
|
||||||
AluBranch(AluBranchMOp<DestReg, SrcRegWidth>),
|
AluBranch(AluBranchMOp<DestReg, SrcRegWidth>),
|
||||||
#[transformed_move]
|
#[transformed_move]
|
||||||
#[create_dyn_unit_fn = |config, unit_index| todo!()]
|
#[create_dyn_unit_fn = |config, unit_index| todo!()]
|
||||||
#[extract = transformed_move_mop]
|
#[extract(transformed_move_mop, transformed_move_mop_sim, transformed_move_mop_sim_ref, transformed_move_mop_sim_mut)]
|
||||||
TransformedMove(TransformedMoveOp),
|
TransformedMove(TransformedMoveOp),
|
||||||
#[create_dyn_unit_fn = |config, unit_index| todo!()]
|
#[create_dyn_unit_fn = |config, unit_index| todo!()]
|
||||||
#[extract = load_store_mop]
|
#[extract(load_store_mop, load_store_mop_sim, load_store_mop_sim_ref, load_store_mop_sim_mut)]
|
||||||
LoadStore(LoadStoreMOp<DestReg, SrcRegWidth>),
|
LoadStore(LoadStoreMOp<DestReg, SrcRegWidth>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -277,9 +314,9 @@ pub struct UnitResultCompleted<ExtraOut> {
|
||||||
pub extra_out: ExtraOut,
|
pub extra_out: ExtraOut,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq, no_static)]
|
||||||
pub struct UnitOutputWrite<OutRegNumWidth: Size> {
|
pub struct UnitOutputWrite<C: PhantomConstGet<CpuConfig>> {
|
||||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
pub which: UnitOutRegNum<C>,
|
||||||
pub value: PRegValue,
|
pub value: PRegValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,21 +337,21 @@ impl<ExtraOut: Type> UnitResult<ExtraOut> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl(no_static)]
|
||||||
pub struct UnitOutput<OutRegNumWidth: Size, ExtraOut> {
|
pub struct UnitOutput<C: PhantomConstGet<CpuConfig>, ExtraOut> {
|
||||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
pub which: UnitOutRegNum<C>,
|
||||||
pub result: UnitResult<ExtraOut>,
|
pub result: UnitResult<ExtraOut>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<OutRegNumWidth: Size, ExtraOut: Type> UnitOutput<OutRegNumWidth, ExtraOut> {
|
impl<C: PhantomConstCpuConfig, ExtraOut: Type> UnitOutput<C, ExtraOut> {
|
||||||
pub fn extra_out_ty(self) -> ExtraOut {
|
pub fn extra_out_ty(self) -> ExtraOut {
|
||||||
self.result.extra_out_ty()
|
self.result.extra_out_ty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq, no_static)]
|
||||||
pub struct UnitCancelInput<OutRegNumWidth: Size> {
|
pub struct UnitCancelInput<C: PhantomConstGet<CpuConfig>> {
|
||||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
pub which: UnitOutRegNum<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UnitTrait:
|
pub trait UnitTrait:
|
||||||
|
|
@ -332,7 +369,7 @@ pub trait UnitTrait:
|
||||||
|
|
||||||
fn extract_mop(
|
fn extract_mop(
|
||||||
&self,
|
&self,
|
||||||
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
mop: Expr<RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
|
||||||
) -> Expr<HdlOption<Self::MOp>>;
|
) -> Expr<HdlOption<Self::MOp>>;
|
||||||
|
|
||||||
fn module(&self) -> Interned<Module<Self::Type>>;
|
fn module(&self) -> Interned<Module<Self::Type>>;
|
||||||
|
|
@ -340,7 +377,7 @@ pub trait UnitTrait:
|
||||||
fn unit_to_reg_alloc(
|
fn unit_to_reg_alloc(
|
||||||
&self,
|
&self,
|
||||||
this: Expr<Self::Type>,
|
this: Expr<Self::Type>,
|
||||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>>;
|
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>>;
|
||||||
|
|
||||||
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
|
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
|
||||||
|
|
||||||
|
|
@ -390,7 +427,7 @@ impl UnitTrait for DynUnit {
|
||||||
|
|
||||||
fn extract_mop(
|
fn extract_mop(
|
||||||
&self,
|
&self,
|
||||||
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
mop: Expr<RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
|
||||||
) -> Expr<HdlOption<Self::MOp>> {
|
) -> Expr<HdlOption<Self::MOp>> {
|
||||||
self.unit.extract_mop(mop)
|
self.unit.extract_mop(mop)
|
||||||
}
|
}
|
||||||
|
|
@ -402,7 +439,7 @@ impl UnitTrait for DynUnit {
|
||||||
fn unit_to_reg_alloc(
|
fn unit_to_reg_alloc(
|
||||||
&self,
|
&self,
|
||||||
this: Expr<Self::Type>,
|
this: Expr<Self::Type>,
|
||||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
|
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
|
||||||
self.unit.unit_to_reg_alloc(this)
|
self.unit.unit_to_reg_alloc(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -445,7 +482,7 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
|
||||||
|
|
||||||
fn extract_mop(
|
fn extract_mop(
|
||||||
&self,
|
&self,
|
||||||
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
mop: Expr<RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
|
||||||
) -> Expr<HdlOption<Self::MOp>> {
|
) -> Expr<HdlOption<Self::MOp>> {
|
||||||
Expr::from_enum(Expr::as_enum(self.0.extract_mop(mop)))
|
Expr::from_enum(Expr::as_enum(self.0.extract_mop(mop)))
|
||||||
}
|
}
|
||||||
|
|
@ -457,7 +494,7 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
|
||||||
fn unit_to_reg_alloc(
|
fn unit_to_reg_alloc(
|
||||||
&self,
|
&self,
|
||||||
this: Expr<Self::Type>,
|
this: Expr<Self::Type>,
|
||||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
|
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
|
||||||
Expr::from_bundle(Expr::as_bundle(
|
Expr::from_bundle(Expr::as_bundle(
|
||||||
self.0.unit_to_reg_alloc(Expr::from_bundle(this)),
|
self.0.unit_to_reg_alloc(Expr::from_bundle(this)),
|
||||||
))
|
))
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,13 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
intern::{Intern, Interned},
|
intern::Interned, module::wire_with_loc, prelude::*, util::ready_valid::ReadyValid,
|
||||||
module::wire_with_loc,
|
|
||||||
prelude::*,
|
|
||||||
util::ready_valid::ReadyValid,
|
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, ops::RangeTo};
|
use std::{collections::HashMap, ops::RangeTo};
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn add_sub<SrcCount: KnownSize>(
|
fn add_sub<SrcCount: KnownSize>(
|
||||||
mop: Expr<AddSubMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
|
mop: Expr<AddSubMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize, SrcCount>>,
|
||||||
pc: Expr<UInt<64>>,
|
pc: Expr<UInt<64>>,
|
||||||
flags_mode: Expr<FlagsMode>,
|
flags_mode: Expr<FlagsMode>,
|
||||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
|
|
@ -245,7 +242,7 @@ fn add_sub<SrcCount: KnownSize>(
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn logical_flags(
|
fn logical_flags(
|
||||||
mop: Expr<LogicalFlagsMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
mop: Expr<LogicalFlagsMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
|
||||||
flags_mode: Expr<FlagsMode>,
|
flags_mode: Expr<FlagsMode>,
|
||||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
) -> Expr<UnitResultCompleted<()>> {
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
|
@ -259,7 +256,7 @@ fn logical_flags(
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn logical(
|
fn logical(
|
||||||
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize, ConstUsize<2>>>,
|
mop: Expr<LogicalMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize, ConstUsize<2>>>,
|
||||||
flags_mode: Expr<FlagsMode>,
|
flags_mode: Expr<FlagsMode>,
|
||||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
) -> Expr<UnitResultCompleted<()>> {
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
|
@ -273,7 +270,7 @@ fn logical(
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn logical_i(
|
fn logical_i(
|
||||||
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize, ConstUsize<1>>>,
|
mop: Expr<LogicalMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize, ConstUsize<1>>>,
|
||||||
flags_mode: Expr<FlagsMode>,
|
flags_mode: Expr<FlagsMode>,
|
||||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
) -> Expr<UnitResultCompleted<()>> {
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
|
@ -287,7 +284,7 @@ fn logical_i(
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn shift_rotate(
|
fn shift_rotate(
|
||||||
mop: Expr<ShiftRotateMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
mop: Expr<ShiftRotateMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
|
||||||
flags_mode: Expr<FlagsMode>,
|
flags_mode: Expr<FlagsMode>,
|
||||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
) -> Expr<UnitResultCompleted<()>> {
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
|
@ -301,7 +298,7 @@ fn shift_rotate(
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn compare<SrcCount: KnownSize>(
|
fn compare<SrcCount: KnownSize>(
|
||||||
mop: Expr<CompareMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
|
mop: Expr<CompareMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize, SrcCount>>,
|
||||||
flags_mode: Expr<FlagsMode>,
|
flags_mode: Expr<FlagsMode>,
|
||||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
) -> Expr<UnitResultCompleted<()>> {
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
|
@ -315,7 +312,7 @@ fn compare<SrcCount: KnownSize>(
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn branch<SrcCount: KnownSize>(
|
fn branch<SrcCount: KnownSize>(
|
||||||
mop: Expr<BranchMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
|
mop: Expr<BranchMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize, SrcCount>>,
|
||||||
pc: Expr<UInt<64>>,
|
pc: Expr<UInt<64>>,
|
||||||
flags_mode: Expr<FlagsMode>,
|
flags_mode: Expr<FlagsMode>,
|
||||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
|
|
@ -330,7 +327,7 @@ fn branch<SrcCount: KnownSize>(
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn read_special(
|
fn read_special(
|
||||||
mop: Expr<ReadSpecialMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
mop: Expr<ReadSpecialMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
|
||||||
pc: Expr<UInt<64>>,
|
pc: Expr<UInt<64>>,
|
||||||
flags_mode: Expr<FlagsMode>,
|
flags_mode: Expr<FlagsMode>,
|
||||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
|
|
@ -344,20 +341,18 @@ fn read_special(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
pub fn alu_branch(config: PhantomConst<CpuConfig>, unit_index: usize) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let unit_to_reg_alloc: UnitToRegAlloc<
|
let unit_to_reg_alloc: UnitToRegAlloc<
|
||||||
AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>,
|
PhantomConst<CpuConfig>,
|
||||||
|
AluBranchMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>,
|
||||||
(),
|
(),
|
||||||
DynSize,
|
> = m.output(
|
||||||
DynSize,
|
UnitToRegAlloc[config][AluBranchMOp[UnitOutRegNum[config]][config.get().p_reg_num_width()]]
|
||||||
DynSize,
|
[()],
|
||||||
> = m.output(config.unit_to_reg_alloc(
|
);
|
||||||
AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()],
|
|
||||||
(),
|
|
||||||
));
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let global_state: GlobalState = m.input();
|
let global_state: GlobalState = m.input();
|
||||||
|
|
||||||
|
|
@ -375,10 +370,11 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) {
|
if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let ExecuteStart::<_> {
|
let ExecuteStart::<_, _> {
|
||||||
mop,
|
mop,
|
||||||
pc,
|
pc,
|
||||||
src_values,
|
src_values,
|
||||||
|
config: _,
|
||||||
} = execute_start;
|
} = execute_start;
|
||||||
#[hdl]
|
#[hdl]
|
||||||
match mop {
|
match mop {
|
||||||
|
|
@ -580,14 +576,14 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct AluBranch {
|
pub struct AluBranch {
|
||||||
config: Interned<CpuConfig>,
|
config: PhantomConst<CpuConfig>,
|
||||||
module: Interned<Module<alu_branch>>,
|
module: Interned<Module<alu_branch>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AluBranch {
|
impl AluBranch {
|
||||||
pub fn new(config: &CpuConfig, unit_index: usize) -> Self {
|
pub fn new(config: PhantomConst<CpuConfig>, unit_index: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
config: config.intern(),
|
config,
|
||||||
module: alu_branch(config, unit_index),
|
module: alu_branch(config, unit_index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -596,7 +592,7 @@ impl AluBranch {
|
||||||
impl UnitTrait for AluBranch {
|
impl UnitTrait for AluBranch {
|
||||||
type Type = alu_branch;
|
type Type = alu_branch;
|
||||||
type ExtraOut = ();
|
type ExtraOut = ();
|
||||||
type MOp = AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>;
|
type MOp = AluBranchMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>;
|
||||||
|
|
||||||
fn ty(&self) -> Self::Type {
|
fn ty(&self) -> Self::Type {
|
||||||
self.module.io_ty()
|
self.module.io_ty()
|
||||||
|
|
@ -616,7 +612,7 @@ impl UnitTrait for AluBranch {
|
||||||
|
|
||||||
fn extract_mop(
|
fn extract_mop(
|
||||||
&self,
|
&self,
|
||||||
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
mop: Expr<RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
|
||||||
) -> Expr<HdlOption<Self::MOp>> {
|
) -> Expr<HdlOption<Self::MOp>> {
|
||||||
UnitMOp::alu_branch_mop(mop)
|
UnitMOp::alu_branch_mop(mop)
|
||||||
}
|
}
|
||||||
|
|
@ -628,7 +624,7 @@ impl UnitTrait for AluBranch {
|
||||||
fn unit_to_reg_alloc(
|
fn unit_to_reg_alloc(
|
||||||
&self,
|
&self,
|
||||||
this: Expr<Self::Type>,
|
this: Expr<Self::Type>,
|
||||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
|
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
|
||||||
this.unit_to_reg_alloc
|
this.unit_to_reg_alloc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::{CpuConfig, CpuConfigUnitCount, PhantomConstCpuConfig},
|
||||||
instruction::{COMMON_MOP_SRC_LEN, MOpTrait, PRegNum, UnitNum, UnitOutRegNum},
|
instruction::{COMMON_MOP_SRC_LEN, MOpTrait, PRegNum, UnitNum, UnitOutRegNum},
|
||||||
register::PRegValue,
|
register::PRegValue,
|
||||||
unit::{UnitCancelInput, UnitOutput, UnitOutputWrite},
|
unit::{UnitCancelInput, UnitOutput, UnitOutputWrite},
|
||||||
|
|
@ -15,13 +15,11 @@ use fayalite::{
|
||||||
ty::StaticType,
|
ty::StaticType,
|
||||||
util::ready_valid::ReadyValid,
|
util::ready_valid::ReadyValid,
|
||||||
};
|
};
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
#[hdl]
|
#[hdl(no_static)]
|
||||||
pub struct UnitForwardingInfo<UnitNumWidth: Size, OutRegNumWidth: Size, UnitCount: Size> {
|
pub struct UnitForwardingInfo<C: PhantomConstGet<CpuConfig>> {
|
||||||
pub unit_output_writes: ArrayType<HdlOption<UnitOutputWrite<OutRegNumWidth>>, UnitCount>,
|
pub unit_output_writes: ArrayType<HdlOption<UnitOutputWrite<C>>, CpuConfigUnitCount<C>>,
|
||||||
pub unit_reg_frees: ArrayType<HdlOption<UnitOutRegNum<OutRegNumWidth>>, UnitCount>,
|
pub unit_reg_frees: ArrayType<HdlOption<UnitOutRegNum<C>>, CpuConfigUnitCount<C>>,
|
||||||
pub _phantom: PhantomData<UnitNumWidth>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -30,26 +28,18 @@ pub struct UnitInput<MOp: Type> {
|
||||||
pub pc: UInt<64>,
|
pub pc: UInt<64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl(no_static)]
|
||||||
pub struct UnitToRegAlloc<
|
pub struct UnitToRegAlloc<C: PhantomConstGet<CpuConfig>, MOp: Type, ExtraOut: Type> {
|
||||||
MOp: Type,
|
|
||||||
ExtraOut: Type,
|
|
||||||
UnitNumWidth: Size,
|
|
||||||
OutRegNumWidth: Size,
|
|
||||||
UnitCount: Size,
|
|
||||||
> {
|
|
||||||
#[hdl(flip)]
|
#[hdl(flip)]
|
||||||
pub unit_forwarding_info: UnitForwardingInfo<UnitNumWidth, OutRegNumWidth, UnitCount>,
|
pub unit_forwarding_info: UnitForwardingInfo<C>,
|
||||||
#[hdl(flip)]
|
#[hdl(flip)]
|
||||||
pub input: ReadyValid<UnitInput<MOp>>,
|
pub input: ReadyValid<UnitInput<MOp>>,
|
||||||
#[hdl(flip)]
|
#[hdl(flip)]
|
||||||
pub cancel_input: HdlOption<UnitCancelInput<OutRegNumWidth>>,
|
pub cancel_input: HdlOption<UnitCancelInput<C>>,
|
||||||
pub output: HdlOption<UnitOutput<OutRegNumWidth, ExtraOut>>,
|
pub output: HdlOption<UnitOutput<C, ExtraOut>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<MOp: Type, ExtraOut: Type, UnitNumWidth: Size, OutRegNumWidth: Size, UnitCount: Size>
|
impl<C: PhantomConstCpuConfig, MOp: Type, ExtraOut: Type> UnitToRegAlloc<C, MOp, ExtraOut> {
|
||||||
UnitToRegAlloc<MOp, ExtraOut, UnitNumWidth, OutRegNumWidth, UnitCount>
|
|
||||||
{
|
|
||||||
pub fn mop_ty(self) -> MOp {
|
pub fn mop_ty(self) -> MOp {
|
||||||
self.input.data.HdlSome.mop
|
self.input.data.HdlSome.mop
|
||||||
}
|
}
|
||||||
|
|
@ -58,16 +48,20 @@ impl<MOp: Type, ExtraOut: Type, UnitNumWidth: Size, OutRegNumWidth: Size, UnitCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl(no_static)]
|
||||||
pub struct ExecuteStart<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> {
|
pub struct ExecuteStart<
|
||||||
|
C: PhantomConstGet<CpuConfig>,
|
||||||
|
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<C>>,
|
||||||
|
> {
|
||||||
pub mop: MOp,
|
pub mop: MOp,
|
||||||
pub pc: UInt<64>,
|
pub pc: UInt<64>,
|
||||||
pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>,
|
pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>,
|
||||||
|
pub config: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl(no_static)]
|
||||||
pub struct ExecuteEnd<OutRegNumWidth: Size, ExtraOut> {
|
pub struct ExecuteEnd<C: PhantomConstGet<CpuConfig>, ExtraOut> {
|
||||||
pub unit_output: UnitOutput<OutRegNumWidth, ExtraOut>,
|
pub unit_output: UnitOutput<C, ExtraOut>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -240,10 +234,10 @@ impl InFlightOpsSummary<DynSize> {
|
||||||
|
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
pub fn unit_base<
|
pub fn unit_base<
|
||||||
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>, SrcRegWidth = DynSize>,
|
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<PhantomConst<CpuConfig>>, SrcRegWidth = DynSize>,
|
||||||
ExtraOut: Type,
|
ExtraOut: Type,
|
||||||
>(
|
>(
|
||||||
config: &CpuConfig,
|
config: PhantomConst<CpuConfig>,
|
||||||
unit_index: usize,
|
unit_index: usize,
|
||||||
mop_ty: MOp,
|
mop_ty: MOp,
|
||||||
extra_out_ty: ExtraOut,
|
extra_out_ty: ExtraOut,
|
||||||
|
|
@ -251,17 +245,18 @@ pub fn unit_base<
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let unit_to_reg_alloc: UnitToRegAlloc<MOp, ExtraOut, DynSize, DynSize, DynSize> =
|
let unit_to_reg_alloc: UnitToRegAlloc<PhantomConst<CpuConfig>, MOp, ExtraOut> =
|
||||||
m.output(config.unit_to_reg_alloc(mop_ty, extra_out_ty));
|
m.output(UnitToRegAlloc[config][mop_ty][extra_out_ty]);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let execute_start: ReadyValid<ExecuteStart<MOp>> = m.output(ReadyValid[ExecuteStart[mop_ty]]);
|
let execute_start: ReadyValid<ExecuteStart<PhantomConst<CpuConfig>, MOp>> =
|
||||||
|
m.output(ReadyValid[ExecuteStart[config][mop_ty]]);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> =
|
let execute_end: HdlOption<ExecuteEnd<PhantomConst<CpuConfig>, ExtraOut>> =
|
||||||
m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]);
|
m.input(HdlOption[ExecuteEnd[config][extra_out_ty]]);
|
||||||
|
|
||||||
connect(execute_start.data, execute_start.ty().data.HdlNone());
|
connect(execute_start.data, execute_start.ty().data.HdlNone());
|
||||||
|
|
||||||
let max_in_flight = config.unit_max_in_flight(unit_index).get();
|
let max_in_flight = config.get().unit_max_in_flight(unit_index).get();
|
||||||
let in_flight_op_ty = InFlightOp[mop_ty];
|
let in_flight_op_ty = InFlightOp[mop_ty];
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let in_flight_ops = reg_builder()
|
let in_flight_ops = reg_builder()
|
||||||
|
|
@ -279,16 +274,15 @@ pub fn unit_base<
|
||||||
);
|
);
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let UnitForwardingInfo::<_, _, _> {
|
let UnitForwardingInfo::<_> {
|
||||||
unit_output_writes,
|
unit_output_writes,
|
||||||
unit_reg_frees,
|
unit_reg_frees,
|
||||||
_phantom: _,
|
|
||||||
} = unit_to_reg_alloc.unit_forwarding_info;
|
} = unit_to_reg_alloc.unit_forwarding_info;
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let read_src_regs = wire(mop_ty.src_regs_ty());
|
let read_src_regs = wire(mop_ty.src_regs_ty());
|
||||||
connect(
|
connect(
|
||||||
read_src_regs,
|
read_src_regs,
|
||||||
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let read_src_values = wire();
|
let read_src_values = wire();
|
||||||
|
|
@ -297,7 +291,7 @@ pub fn unit_base<
|
||||||
let input_src_regs = wire(mop_ty.src_regs_ty());
|
let input_src_regs = wire(mop_ty.src_regs_ty());
|
||||||
connect(
|
connect(
|
||||||
input_src_regs,
|
input_src_regs,
|
||||||
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let input_src_regs_valid = wire();
|
let input_src_regs_valid = wire();
|
||||||
|
|
@ -309,7 +303,7 @@ pub fn unit_base<
|
||||||
Bool,
|
Bool,
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
);
|
);
|
||||||
mem.depth(1 << config.out_reg_num_width);
|
mem.depth(1 << config.get().out_reg_num_width);
|
||||||
mem
|
mem
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
@ -319,11 +313,11 @@ pub fn unit_base<
|
||||||
PRegValue,
|
PRegValue,
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
);
|
);
|
||||||
unit_output_regs.depth(1 << config.out_reg_num_width);
|
unit_output_regs.depth(1 << config.get().out_reg_num_width);
|
||||||
|
|
||||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||||
let read_port = unit_output_regs.new_read_port();
|
let read_port = unit_output_regs.new_read_port();
|
||||||
let p_reg_num = read_src_regs[src_index].cast_bits_to(config.p_reg_num());
|
let p_reg_num = read_src_regs[src_index].cast_bits_to(PRegNum[config]);
|
||||||
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
|
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
|
||||||
connect(read_port.en, false);
|
connect(read_port.en, false);
|
||||||
connect(read_port.clk, cd.clk);
|
connect(read_port.clk, cd.clk);
|
||||||
|
|
@ -336,7 +330,7 @@ pub fn unit_base<
|
||||||
|
|
||||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||||
let read_port = unit_output_regs_valid[unit_index].new_read_port();
|
let read_port = unit_output_regs_valid[unit_index].new_read_port();
|
||||||
let p_reg_num = input_src_regs[src_index].cast_bits_to(config.p_reg_num());
|
let p_reg_num = input_src_regs[src_index].cast_bits_to(PRegNum[config]);
|
||||||
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
|
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
|
||||||
connect(read_port.en, false);
|
connect(read_port.en, false);
|
||||||
connect(read_port.clk, cd.clk);
|
connect(read_port.clk, cd.clk);
|
||||||
|
|
@ -367,8 +361,8 @@ pub fn unit_base<
|
||||||
connect_any(ready_write_port.addr, unit_output_write.which.value);
|
connect_any(ready_write_port.addr, unit_output_write.which.value);
|
||||||
connect(ready_write_port.en, true);
|
connect(ready_write_port.en, true);
|
||||||
let p_reg_num = #[hdl]
|
let p_reg_num = #[hdl]
|
||||||
PRegNum::<_, _> {
|
PRegNum::<_> {
|
||||||
unit_num: config.unit_num().from_index(unit_index),
|
unit_num: UnitNum[config].from_index(unit_index),
|
||||||
unit_out_reg: unit_output_write.which,
|
unit_out_reg: unit_output_write.which,
|
||||||
};
|
};
|
||||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||||
|
|
@ -399,10 +393,11 @@ pub fn unit_base<
|
||||||
execute_start.data,
|
execute_start.data,
|
||||||
HdlSome(
|
HdlSome(
|
||||||
#[hdl]
|
#[hdl]
|
||||||
ExecuteStart::<_> {
|
ExecuteStart::<_, _> {
|
||||||
mop: in_flight_op.mop,
|
mop: in_flight_op.mop,
|
||||||
pc: in_flight_op.pc,
|
pc: in_flight_op.pc,
|
||||||
src_values: read_src_values,
|
src_values: read_src_values,
|
||||||
|
config,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -425,7 +420,7 @@ pub fn unit_base<
|
||||||
let input_mop_src_regs = wire(mop_ty.src_regs_ty());
|
let input_mop_src_regs = wire(mop_ty.src_regs_ty());
|
||||||
connect(
|
connect(
|
||||||
input_mop_src_regs,
|
input_mop_src_regs,
|
||||||
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
||||||
);
|
);
|
||||||
MOp::connect_src_regs(mop, input_mop_src_regs);
|
MOp::connect_src_regs(mop, input_mop_src_regs);
|
||||||
let src_ready_flags = wire_with_loc(
|
let src_ready_flags = wire_with_loc(
|
||||||
|
|
@ -497,7 +492,7 @@ pub fn unit_base<
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
src_regs,
|
src_regs,
|
||||||
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
||||||
);
|
);
|
||||||
MOp::connect_src_regs(mop, src_regs);
|
MOp::connect_src_regs(mop, src_regs);
|
||||||
|
|
||||||
|
|
@ -521,8 +516,8 @@ pub fn unit_base<
|
||||||
value: _,
|
value: _,
|
||||||
} = unit_output_write;
|
} = unit_output_write;
|
||||||
let p_reg_num = #[hdl]
|
let p_reg_num = #[hdl]
|
||||||
PRegNum::<_, _> {
|
PRegNum::<_> {
|
||||||
unit_num: config.unit_num().from_index(unit_index),
|
unit_num: UnitNum[config].from_index(unit_index),
|
||||||
unit_out_reg,
|
unit_out_reg,
|
||||||
};
|
};
|
||||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||||
|
|
|
||||||
92318
crates/cpu/tests/expected/rename_execute_retire.vcd
generated
Normal file
92318
crates/cpu/tests/expected/rename_execute_retire.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,6 @@
|
||||||
// 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
|
||||||
|
#![cfg(todo)]
|
||||||
|
|
||||||
use cpu::{
|
use cpu::{
|
||||||
config::{CpuConfig, UnitConfig},
|
config::{CpuConfig, UnitConfig},
|
||||||
|
|
|
||||||
216
crates/cpu/tests/rename_execute_retire.rs
Normal file
216
crates/cpu/tests/rename_execute_retire.rs
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use cpu::{
|
||||||
|
config::{CpuConfig, UnitConfig},
|
||||||
|
next_pc::{CallStackOp, FETCH_BLOCK_ID_WIDTH},
|
||||||
|
rename_execute_retire::{
|
||||||
|
PostDecodeOutputInterface, RetireToNextPcInterface, rename_execute_retire,
|
||||||
|
},
|
||||||
|
unit::UnitKind,
|
||||||
|
util::array_vec::ArrayVec,
|
||||||
|
};
|
||||||
|
use fayalite::{
|
||||||
|
intern::{Intern, Interned},
|
||||||
|
prelude::*,
|
||||||
|
sim::vcd::VcdWriterDecls,
|
||||||
|
ty::{OpaqueSimValue, StaticType},
|
||||||
|
util::{DebugAsDisplay, RcWriter},
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
cell::Cell,
|
||||||
|
collections::{BTreeMap, BTreeSet, VecDeque},
|
||||||
|
fmt,
|
||||||
|
num::NonZeroUsize,
|
||||||
|
ops::Range,
|
||||||
|
u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn zeroed<T: Type>(ty: T) -> SimValue<T> {
|
||||||
|
SimValue::from_opaque(
|
||||||
|
ty,
|
||||||
|
OpaqueSimValue::from_bits(UInt::new(ty.canonical().bit_width()).zero()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RandomState {
|
||||||
|
state: Cell<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RandomState {
|
||||||
|
fn random_u64(&self, key: u32) -> u64 {
|
||||||
|
let state = self.state.replace(self.state.get().wrapping_add(1));
|
||||||
|
// make a pseudo-random number deterministically based on state and key
|
||||||
|
let mut random = state
|
||||||
|
.wrapping_add(1)
|
||||||
|
.wrapping_mul(0x39FF446D8BFB75BB) // random prime
|
||||||
|
.rotate_left(32)
|
||||||
|
.wrapping_mul(0x73161B54984B1C21) // random prime
|
||||||
|
.rotate_right(60);
|
||||||
|
random ^= key as u64;
|
||||||
|
random
|
||||||
|
.wrapping_mul(0x39FF446D8BFB75BB) // random prime
|
||||||
|
.rotate_left(32)
|
||||||
|
.wrapping_mul(0x73161B54984B1C21) // random prime
|
||||||
|
.rotate_right(60)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
struct MockNextPcDebugState {}
|
||||||
|
|
||||||
|
#[hdl_module(extern)]
|
||||||
|
fn mock_next_pc(config: PhantomConst<CpuConfig>) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let post_decode_output: PostDecodeOutputInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.output(PostDecodeOutputInterface[config]);
|
||||||
|
#[hdl]
|
||||||
|
let from_retire: RetireToNextPcInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.input(RetireToNextPcInterface[config]);
|
||||||
|
#[hdl]
|
||||||
|
let debug_state: MockNextPcDebugState = m.output();
|
||||||
|
m.register_clock_for_past(cd.clk);
|
||||||
|
m.extern_module_simulation_fn(
|
||||||
|
(cd, post_decode_output, from_retire, debug_state),
|
||||||
|
|args, mut sim| async move {
|
||||||
|
let (cd, post_decode_output, from_retire, debug_state) = args;
|
||||||
|
// intentionally have a different sequence each time we're reset
|
||||||
|
let random_state = RandomState {
|
||||||
|
state: Cell::new(0),
|
||||||
|
};
|
||||||
|
sim.resettable(
|
||||||
|
cd,
|
||||||
|
async |mut sim| {
|
||||||
|
sim.write(
|
||||||
|
post_decode_output.insns,
|
||||||
|
post_decode_output
|
||||||
|
.ty()
|
||||||
|
.insns
|
||||||
|
.new_sim(zeroed(StaticType::TYPE)),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
sim.write(
|
||||||
|
post_decode_output.cancel.data,
|
||||||
|
#[hdl(sim)]
|
||||||
|
HdlNone(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
sim.write(from_retire.inner.ready, false).await;
|
||||||
|
},
|
||||||
|
|sim, ()| {
|
||||||
|
run_fn(
|
||||||
|
cd,
|
||||||
|
post_decode_output,
|
||||||
|
from_retire,
|
||||||
|
debug_state,
|
||||||
|
&random_state,
|
||||||
|
sim,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
#[hdl]
|
||||||
|
async fn run_fn(
|
||||||
|
cd: Expr<ClockDomain>,
|
||||||
|
post_decode_output: Expr<PostDecodeOutputInterface<PhantomConst<CpuConfig>>>,
|
||||||
|
from_retire: Expr<RetireToNextPcInterface<PhantomConst<CpuConfig>>>,
|
||||||
|
debug_state: Expr<MockNextPcDebugState>,
|
||||||
|
random_state: &RandomState,
|
||||||
|
mut sim: ExternModuleSimulationState,
|
||||||
|
) {
|
||||||
|
let config = post_decode_output.ty().config;
|
||||||
|
loop {
|
||||||
|
sim.write(
|
||||||
|
post_decode_output.insns,
|
||||||
|
post_decode_output
|
||||||
|
.ty()
|
||||||
|
.insns
|
||||||
|
.new_sim(zeroed(StaticType::TYPE)),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
sim.write(
|
||||||
|
post_decode_output.cancel.data,
|
||||||
|
#[hdl(sim)]
|
||||||
|
HdlNone(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
sim.write(from_retire.inner.ready, false).await;
|
||||||
|
sim.write(
|
||||||
|
debug_state,
|
||||||
|
#[hdl(sim)]
|
||||||
|
MockNextPcDebugState {},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
sim.wait_for_clock_edge(cd.clk).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module]
|
||||||
|
fn rename_execute_retire_test_harness(config: PhantomConst<CpuConfig>) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let next_pc = instance(mock_next_pc(config));
|
||||||
|
connect(next_pc.cd, cd);
|
||||||
|
#[hdl]
|
||||||
|
let dut = instance(rename_execute_retire(config));
|
||||||
|
connect(dut.cd, cd);
|
||||||
|
connect(dut.from_post_decode, next_pc.post_decode_output);
|
||||||
|
connect(next_pc.from_retire, dut.to_next_pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
#[test]
|
||||||
|
fn test_rename_execute_retire() {
|
||||||
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
let mut config = CpuConfig::new(
|
||||||
|
vec![
|
||||||
|
UnitConfig::new(UnitKind::AluBranch),
|
||||||
|
UnitConfig::new(UnitKind::AluBranch),
|
||||||
|
UnitConfig::new(UnitKind::AluBranch),
|
||||||
|
UnitConfig::new(UnitKind::LoadStore),
|
||||||
|
UnitConfig::new(UnitKind::TransformedMove),
|
||||||
|
],
|
||||||
|
NonZeroUsize::new(20).unwrap(),
|
||||||
|
);
|
||||||
|
config.fetch_width = NonZeroUsize::new(3).unwrap();
|
||||||
|
let m = rename_execute_retire_test_harness(PhantomConst::new_sized(config));
|
||||||
|
let mut sim = Simulation::new(m);
|
||||||
|
let writer = RcWriter::default();
|
||||||
|
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
||||||
|
struct DumpVcdOnDrop {
|
||||||
|
writer: Option<RcWriter>,
|
||||||
|
}
|
||||||
|
impl Drop for DumpVcdOnDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(mut writer) = self.writer.take() {
|
||||||
|
let vcd = String::from_utf8(writer.take()).unwrap();
|
||||||
|
println!("####### VCD:\n{vcd}\n#######");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut writer = DumpVcdOnDrop {
|
||||||
|
writer: Some(writer),
|
||||||
|
};
|
||||||
|
sim.write_clock(sim.io().cd.clk, false);
|
||||||
|
sim.write_reset(sim.io().cd.rst, true);
|
||||||
|
for cycle in 0..50 {
|
||||||
|
sim.advance_time(SimDuration::from_nanos(500));
|
||||||
|
println!("clock tick: {cycle}");
|
||||||
|
sim.write_clock(sim.io().cd.clk, true);
|
||||||
|
sim.advance_time(SimDuration::from_nanos(500));
|
||||||
|
sim.write_clock(sim.io().cd.clk, false);
|
||||||
|
sim.write_reset(sim.io().cd.rst, false);
|
||||||
|
}
|
||||||
|
// FIXME: vcd is just whatever rename_execute_retire does now, which isn't known to be correct
|
||||||
|
let vcd = String::from_utf8(writer.writer.take().unwrap().take()).unwrap();
|
||||||
|
println!("####### VCD:\n{vcd}\n#######");
|
||||||
|
if vcd != include_str!("expected/rename_execute_retire.vcd") {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue