Refactor src/unit* to work with the rename_execute_retire unit API #13
5 changed files with 195199 additions and 1160 deletions
|
|
@ -2,14 +2,12 @@
|
|||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{
|
||||
config::{CpuConfig, PhantomConstCpuConfig},
|
||||
config::CpuConfig,
|
||||
instruction::{
|
||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait,
|
||||
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, PRegNum, RenamedMOp,
|
||||
UnitOutRegNum, mop_enum,
|
||||
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, mop_enum,
|
||||
},
|
||||
register::{FlagsMode, PRegValue},
|
||||
unit::unit_base::UnitToRegAlloc,
|
||||
rename_execute_retire::ExecuteToUnitInterface,
|
||||
};
|
||||
use fayalite::{
|
||||
bundle::{Bundle, BundleType},
|
||||
|
|
@ -20,7 +18,6 @@ use serde::{Deserialize, Serialize};
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
pub mod alu_branch;
|
||||
pub mod unit_base;
|
||||
|
||||
macro_rules! all_units {
|
||||
(
|
||||
|
|
@ -342,92 +339,23 @@ all_units! {
|
|||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct GlobalState {
|
||||
pub flags_mode: FlagsMode,
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct UnitResultCompleted<ExtraOut> {
|
||||
pub value: PRegValue,
|
||||
pub extra_out: ExtraOut,
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq, no_static)]
|
||||
pub struct UnitOutputWrite<C: PhantomConstGet<CpuConfig>> {
|
||||
pub which: UnitOutRegNum<C>,
|
||||
pub value: PRegValue,
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq)]
|
||||
pub struct TrapData {
|
||||
// TODO
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub enum UnitResult<ExtraOut> {
|
||||
Completed(UnitResultCompleted<ExtraOut>),
|
||||
Trap(TrapData),
|
||||
}
|
||||
|
||||
impl<ExtraOut: Type> UnitResult<ExtraOut> {
|
||||
pub fn extra_out_ty(self) -> ExtraOut {
|
||||
self.Completed.extra_out
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct UnitOutput<C: PhantomConstGet<CpuConfig>, ExtraOut> {
|
||||
pub which: UnitOutRegNum<C>,
|
||||
pub result: UnitResult<ExtraOut>,
|
||||
}
|
||||
|
||||
impl<C: PhantomConstCpuConfig, ExtraOut: Type> UnitOutput<C, ExtraOut> {
|
||||
pub fn extra_out_ty(self) -> ExtraOut {
|
||||
self.result.extra_out_ty()
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(cmp_eq, no_static)]
|
||||
pub struct UnitCancelInput<C: PhantomConstGet<CpuConfig>> {
|
||||
pub which: UnitOutRegNum<C>,
|
||||
}
|
||||
|
||||
pub trait UnitTrait:
|
||||
'static + Send + Sync + std::fmt::Debug + fayalite::intern::SupportsPtrEqWithTypeId
|
||||
{
|
||||
type Type: BundleType;
|
||||
type ExtraOut: Type;
|
||||
type MOp: Type;
|
||||
|
||||
fn ty(&self) -> Self::Type;
|
||||
fn extra_out_ty(&self) -> Self::ExtraOut;
|
||||
fn mop_ty(&self) -> Self::MOp;
|
||||
|
||||
fn unit_kind(&self) -> UnitKind;
|
||||
|
||||
fn extract_mop(
|
||||
&self,
|
||||
mop: Expr<
|
||||
RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, PRegNum<PhantomConst<CpuConfig>>>,
|
||||
>,
|
||||
) -> Expr<HdlOption<Self::MOp>>;
|
||||
|
||||
fn module(&self) -> Interned<Module<Self::Type>>;
|
||||
|
||||
fn unit_to_reg_alloc(
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Option<Expr<ClockDomain>>;
|
||||
fn from_execute(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>>;
|
||||
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
|
||||
|
||||
fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState>;
|
||||
|
||||
) -> Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>>;
|
||||
fn to_dyn(&self) -> DynUnit;
|
||||
}
|
||||
|
||||
type DynUnitTrait = dyn UnitTrait<Type = Bundle, ExtraOut = CanonicalType, MOp = CanonicalType>;
|
||||
type DynUnitTrait = dyn UnitTrait<Type = Bundle>;
|
||||
|
||||
impl fayalite::intern::InternedCompare for DynUnitTrait {
|
||||
type InternedCompareKey = fayalite::intern::PtrEqWithTypeId;
|
||||
|
|
@ -439,59 +367,34 @@ impl fayalite::intern::InternedCompare for DynUnitTrait {
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct DynUnit {
|
||||
ty: Bundle,
|
||||
extra_out_ty: CanonicalType,
|
||||
mop_ty: CanonicalType,
|
||||
unit_kind: UnitKind,
|
||||
unit: Interned<DynUnitTrait>,
|
||||
}
|
||||
|
||||
impl UnitTrait for DynUnit {
|
||||
type Type = Bundle;
|
||||
type ExtraOut = CanonicalType;
|
||||
type MOp = CanonicalType;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
self.ty
|
||||
}
|
||||
|
||||
fn extra_out_ty(&self) -> Self::ExtraOut {
|
||||
self.extra_out_ty
|
||||
}
|
||||
|
||||
fn mop_ty(&self) -> Self::MOp {
|
||||
self.mop_ty
|
||||
}
|
||||
|
||||
fn unit_kind(&self) -> UnitKind {
|
||||
self.unit_kind
|
||||
}
|
||||
|
||||
fn extract_mop(
|
||||
&self,
|
||||
mop: Expr<
|
||||
RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, PRegNum<PhantomConst<CpuConfig>>>,
|
||||
>,
|
||||
) -> Expr<HdlOption<Self::MOp>> {
|
||||
self.unit.extract_mop(mop)
|
||||
}
|
||||
|
||||
fn module(&self) -> Interned<Module<Self::Type>> {
|
||||
self.unit.module()
|
||||
}
|
||||
|
||||
fn unit_to_reg_alloc(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
|
||||
self.unit.unit_to_reg_alloc(this)
|
||||
}
|
||||
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Option<Expr<ClockDomain>> {
|
||||
self.unit.cd(this)
|
||||
}
|
||||
|
||||
fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState> {
|
||||
self.unit.global_state(this)
|
||||
fn from_execute(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>> {
|
||||
self.unit.from_execute(this)
|
||||
}
|
||||
|
||||
fn to_dyn(&self) -> DynUnit {
|
||||
|
|
@ -504,61 +407,34 @@ pub struct DynUnitWrapper<T>(pub T);
|
|||
|
||||
impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T> {
|
||||
type Type = Bundle;
|
||||
type ExtraOut = CanonicalType;
|
||||
type MOp = CanonicalType;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
Bundle::from_canonical(self.0.ty().canonical())
|
||||
}
|
||||
|
||||
fn extra_out_ty(&self) -> Self::ExtraOut {
|
||||
self.0.extra_out_ty().canonical()
|
||||
}
|
||||
|
||||
fn mop_ty(&self) -> Self::MOp {
|
||||
self.0.mop_ty().canonical()
|
||||
}
|
||||
|
||||
fn unit_kind(&self) -> UnitKind {
|
||||
self.0.unit_kind()
|
||||
}
|
||||
|
||||
fn extract_mop(
|
||||
&self,
|
||||
mop: Expr<
|
||||
RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, PRegNum<PhantomConst<CpuConfig>>>,
|
||||
>,
|
||||
) -> Expr<HdlOption<Self::MOp>> {
|
||||
Expr::from_enum(Expr::as_enum(self.0.extract_mop(mop)))
|
||||
}
|
||||
|
||||
fn module(&self) -> Interned<Module<Self::Type>> {
|
||||
self.0.module().canonical().intern_sized()
|
||||
}
|
||||
|
||||
fn unit_to_reg_alloc(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
|
||||
Expr::from_bundle(Expr::as_bundle(
|
||||
self.0.unit_to_reg_alloc(Expr::from_bundle(this)),
|
||||
))
|
||||
}
|
||||
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Option<Expr<ClockDomain>> {
|
||||
self.0.cd(Expr::from_bundle(this))
|
||||
}
|
||||
|
||||
fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState> {
|
||||
self.0.global_state(Expr::from_bundle(this))
|
||||
fn from_execute(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>> {
|
||||
self.0.from_execute(Expr::from_bundle(this))
|
||||
}
|
||||
|
||||
fn to_dyn(&self) -> DynUnit {
|
||||
let unit = self.intern();
|
||||
DynUnit {
|
||||
ty: unit.ty(),
|
||||
extra_out_ty: unit.extra_out_ty(),
|
||||
mop_ty: unit.mop_ty(),
|
||||
unit_kind: unit.unit_kind(),
|
||||
unit: Interned::cast_unchecked(unit, |v: &Self| -> &DynUnitTrait { v }),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,40 +2,35 @@
|
|||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{
|
||||
config::CpuConfig,
|
||||
config::{CpuConfig, PhantomConstCpuConfig},
|
||||
instruction::{
|
||||
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOpDefaultImm,
|
||||
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, PRegNum,
|
||||
ReadSpecialMOp, RenamedMOp, ShiftRotateMOp, UnitOutRegNum,
|
||||
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOp,
|
||||
CommonMOpDefaultImm, CompareMOp, ConditionMode, LogicalFlagsMOp, LogicalMOp,
|
||||
OutputIntegerMode, PRegNum, ReadSpecialMOp, ShiftRotateMOp,
|
||||
},
|
||||
next_pc::CallStackOp,
|
||||
register::{
|
||||
FlagsMode, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, PRegFlagsX86,
|
||||
PRegFlagsX86View, PRegValue, ViewUnused,
|
||||
FlagsMode, PRegFlags, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait,
|
||||
PRegFlagsX86, PRegFlagsX86View, PRegValue, ViewUnused,
|
||||
},
|
||||
unit::{
|
||||
DynUnit, DynUnitWrapper, GlobalState, UnitKind, UnitMOp, UnitOutput, UnitResult,
|
||||
UnitResultCompleted, UnitTrait,
|
||||
unit_base::{ExecuteEnd, ExecuteStart, UnitToRegAlloc, unit_base},
|
||||
rename_execute_retire::{
|
||||
ExecuteToUnitInterface, GlobalState, NextPcPredictorOp, RenamedMOp, UnitCausedCancel,
|
||||
UnitFinishCauseCancel, UnitInputsReady, UnitOutputReady,
|
||||
},
|
||||
unit::{DynUnit, DynUnitWrapper, UnitKind, UnitTrait},
|
||||
};
|
||||
use fayalite::{
|
||||
intern::Interned, module::wire_with_loc, prelude::*, util::ready_valid::ReadyValid,
|
||||
};
|
||||
use fayalite::{intern::Interned, module::wire_with_loc, prelude::*};
|
||||
use std::{collections::HashMap, ops::RangeTo};
|
||||
|
||||
#[hdl]
|
||||
fn add_sub<SrcCount: KnownSize>(
|
||||
mop: Expr<
|
||||
AddSubMOp<
|
||||
UnitOutRegNum<PhantomConst<CpuConfig>>,
|
||||
PRegNum<PhantomConst<CpuConfig>>,
|
||||
SrcCount,
|
||||
>,
|
||||
>,
|
||||
fn add_sub<C: PhantomConstCpuConfig, SrcCount: KnownSize>(
|
||||
global_state: Expr<GlobalState>,
|
||||
pc: Expr<UInt<64>>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
mop: Expr<AddSubMOp<PRegNum<C>, PRegNum<C>, SrcCount>>,
|
||||
src_values: Expr<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<TraceAsString<PRegValue>> {
|
||||
#[hdl]
|
||||
let GlobalState { flags_mode } = global_state;
|
||||
#[hdl]
|
||||
let AddSubMOp::<_, _, _> {
|
||||
alu_common,
|
||||
|
|
@ -238,373 +233,450 @@ fn add_sub<SrcCount: KnownSize>(
|
|||
);
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
UnitResultCompleted::<_> {
|
||||
value: #[hdl]
|
||||
PRegValue { int_fp, flags },
|
||||
extra_out: (),
|
||||
}
|
||||
let retval = #[hdl]
|
||||
PRegValue { int_fp, flags };
|
||||
retval.to_trace_as_string()
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn logical_flags(
|
||||
mop: Expr<
|
||||
LogicalFlagsMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, PRegNum<PhantomConst<CpuConfig>>>,
|
||||
>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
// TODO: finish
|
||||
#[hdl]
|
||||
UnitResultCompleted::<_> {
|
||||
value: PRegValue::zeroed(),
|
||||
extra_out: (),
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn logical(
|
||||
mop: Expr<
|
||||
LogicalMOp<
|
||||
UnitOutRegNum<PhantomConst<CpuConfig>>,
|
||||
PRegNum<PhantomConst<CpuConfig>>,
|
||||
ConstUsize<2>,
|
||||
>,
|
||||
>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
// TODO: finish
|
||||
#[hdl]
|
||||
UnitResultCompleted::<_> {
|
||||
value: PRegValue::zeroed(),
|
||||
extra_out: (),
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn logical_i(
|
||||
mop: Expr<
|
||||
LogicalMOp<
|
||||
UnitOutRegNum<PhantomConst<CpuConfig>>,
|
||||
PRegNum<PhantomConst<CpuConfig>>,
|
||||
ConstUsize<1>,
|
||||
>,
|
||||
>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
// TODO: finish
|
||||
#[hdl]
|
||||
UnitResultCompleted::<_> {
|
||||
value: PRegValue::zeroed(),
|
||||
extra_out: (),
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn shift_rotate(
|
||||
mop: Expr<
|
||||
ShiftRotateMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, PRegNum<PhantomConst<CpuConfig>>>,
|
||||
>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
// TODO: finish
|
||||
#[hdl]
|
||||
UnitResultCompleted::<_> {
|
||||
value: PRegValue::zeroed(),
|
||||
extra_out: (),
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn compare<SrcCount: KnownSize>(
|
||||
mop: Expr<
|
||||
CompareMOp<
|
||||
UnitOutRegNum<PhantomConst<CpuConfig>>,
|
||||
PRegNum<PhantomConst<CpuConfig>>,
|
||||
SrcCount,
|
||||
>,
|
||||
>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
// TODO: finish
|
||||
#[hdl]
|
||||
UnitResultCompleted::<_> {
|
||||
value: PRegValue::zeroed(),
|
||||
extra_out: (),
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn branch<SrcCount: KnownSize>(
|
||||
mop: Expr<
|
||||
BranchMOp<
|
||||
UnitOutRegNum<PhantomConst<CpuConfig>>,
|
||||
PRegNum<PhantomConst<CpuConfig>>,
|
||||
SrcCount,
|
||||
>,
|
||||
>,
|
||||
fn logical_flags<C: PhantomConstCpuConfig>(
|
||||
global_state: Expr<GlobalState>,
|
||||
pc: Expr<UInt<64>>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
// TODO: finish
|
||||
mop: Expr<LogicalFlagsMOp<PRegNum<C>, PRegNum<C>>>,
|
||||
src_values: Expr<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<TraceAsString<PRegValue>> {
|
||||
#[hdl]
|
||||
UnitResultCompleted::<_> {
|
||||
value: PRegValue::zeroed(),
|
||||
extra_out: (),
|
||||
}
|
||||
let GlobalState { flags_mode } = global_state;
|
||||
// TODO: finish
|
||||
PRegValue::zeroed().to_trace_as_string()
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn read_special(
|
||||
mop: Expr<
|
||||
ReadSpecialMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, PRegNum<PhantomConst<CpuConfig>>>,
|
||||
>,
|
||||
fn logical<C: PhantomConstCpuConfig>(
|
||||
global_state: Expr<GlobalState>,
|
||||
pc: Expr<UInt<64>>,
|
||||
flags_mode: Expr<FlagsMode>,
|
||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<UnitResultCompleted<()>> {
|
||||
// TODO: finish
|
||||
mop: Expr<LogicalMOp<PRegNum<C>, PRegNum<C>, ConstUsize<2>>>,
|
||||
src_values: Expr<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<TraceAsString<PRegValue>> {
|
||||
#[hdl]
|
||||
UnitResultCompleted::<_> {
|
||||
value: PRegValue::zeroed(),
|
||||
extra_out: (),
|
||||
let GlobalState { flags_mode } = global_state;
|
||||
// TODO: finish
|
||||
PRegValue::zeroed().to_trace_as_string()
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn logical_i<C: PhantomConstCpuConfig>(
|
||||
global_state: Expr<GlobalState>,
|
||||
pc: Expr<UInt<64>>,
|
||||
mop: Expr<LogicalMOp<PRegNum<C>, PRegNum<C>, ConstUsize<1>>>,
|
||||
src_values: Expr<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<TraceAsString<PRegValue>> {
|
||||
#[hdl]
|
||||
let GlobalState { flags_mode } = global_state;
|
||||
// TODO: finish
|
||||
PRegValue::zeroed().to_trace_as_string()
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn shift_rotate<C: PhantomConstCpuConfig>(
|
||||
global_state: Expr<GlobalState>,
|
||||
pc: Expr<UInt<64>>,
|
||||
mop: Expr<ShiftRotateMOp<PRegNum<C>, PRegNum<C>>>,
|
||||
src_values: Expr<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<TraceAsString<PRegValue>> {
|
||||
#[hdl]
|
||||
let GlobalState { flags_mode } = global_state;
|
||||
// TODO: finish
|
||||
PRegValue::zeroed().to_trace_as_string()
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn compare<C: PhantomConstCpuConfig, SrcCount: KnownSize>(
|
||||
global_state: Expr<GlobalState>,
|
||||
pc: Expr<UInt<64>>,
|
||||
mop: Expr<CompareMOp<PRegNum<C>, PRegNum<C>, SrcCount>>,
|
||||
src_values: Expr<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<TraceAsString<PRegValue>> {
|
||||
#[hdl]
|
||||
let GlobalState { flags_mode } = global_state;
|
||||
// TODO: finish
|
||||
PRegValue::zeroed().to_trace_as_string()
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn branch<C: PhantomConstCpuConfig, SrcCount: KnownSize>(
|
||||
global_state: Expr<GlobalState>,
|
||||
pc: Expr<UInt<64>>,
|
||||
fallthrough_pc: Expr<UInt<64>>,
|
||||
predicted_next_pc: Expr<UInt<64>>,
|
||||
mop: Expr<BranchMOp<PRegNum<C>, PRegNum<C>, SrcCount>>,
|
||||
src_values: Expr<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
|
||||
config: C,
|
||||
) -> (
|
||||
Expr<TraceAsString<PRegValue>>,
|
||||
Expr<NextPcPredictorOp<C>>,
|
||||
Expr<HdlOption<UnitCausedCancel<C>>>,
|
||||
) {
|
||||
#[hdl]
|
||||
let GlobalState { flags_mode } = global_state;
|
||||
#[hdl]
|
||||
let BranchMOp::<_, _, _> {
|
||||
common,
|
||||
invert_src0_cond,
|
||||
src0_cond_mode,
|
||||
invert_src2_eq_zero,
|
||||
pc_relative,
|
||||
is_call,
|
||||
is_ret,
|
||||
} = mop;
|
||||
#[hdl]
|
||||
let CommonMOp::<_, _, _, _, _> {
|
||||
prefix_pad: _,
|
||||
dest: _,
|
||||
src,
|
||||
imm,
|
||||
} = common;
|
||||
let [src0, src1, src2] = *src_values;
|
||||
#[hdl]
|
||||
let has_src0 = wire();
|
||||
if let Some(src0) = src.as_ref().get(0) {
|
||||
connect(has_src0, src0.cmp_ne(src0.ty().const_zero()));
|
||||
} else {
|
||||
connect(has_src0, false);
|
||||
}
|
||||
#[hdl]
|
||||
let has_src2 = wire();
|
||||
if let Some(src2) = src.as_ref().get(2) {
|
||||
connect(has_src2, src2.cmp_ne(src2.ty().const_zero()));
|
||||
} else {
|
||||
connect(has_src2, false);
|
||||
}
|
||||
#[hdl]
|
||||
let src2_cond = wire();
|
||||
#[hdl]
|
||||
if has_src2 {
|
||||
#[hdl]
|
||||
if invert_src2_eq_zero {
|
||||
connect(src2_cond, src2.int_fp.cmp_ne(0u64));
|
||||
} else {
|
||||
connect(src2_cond, src2.int_fp.cmp_eq(0u64));
|
||||
}
|
||||
} else {
|
||||
connect(src2_cond, true);
|
||||
}
|
||||
#[hdl]
|
||||
let src0_cond = wire();
|
||||
#[hdl]
|
||||
match flags_mode {
|
||||
FlagsMode::PowerISA(_) => {
|
||||
let src0_flags = PRegFlags::view::<PRegFlagsPowerISA>(src0.flags);
|
||||
#[hdl]
|
||||
match src0_cond_mode {
|
||||
ConditionMode::Eq => connect(src0_cond, src0_flags.cr_eq),
|
||||
ConditionMode::ULt => connect(src0_cond, src0_flags.cr_lt),
|
||||
ConditionMode::UGt => connect(src0_cond, src0_flags.cr_gt),
|
||||
ConditionMode::SLt => connect(src0_cond, src0_flags.cr_lt),
|
||||
ConditionMode::SGt => connect(src0_cond, src0_flags.cr_gt),
|
||||
ConditionMode::Sign => connect(src0_cond, false),
|
||||
ConditionMode::Overflow => connect(src0_cond, src0_flags.so),
|
||||
ConditionMode::Parity => connect(src0_cond, false),
|
||||
};
|
||||
}
|
||||
FlagsMode::X86(_) => {
|
||||
let src0_flags = PRegFlags::view::<PRegFlagsX86>(src0.flags);
|
||||
#[hdl]
|
||||
match src0_cond_mode {
|
||||
ConditionMode::Eq => connect(src0_cond, src0_flags.zf),
|
||||
ConditionMode::ULt => connect(src0_cond, src0_flags.cf),
|
||||
ConditionMode::UGt => connect(src0_cond, !src0_flags.zf & !src0_flags.cf),
|
||||
ConditionMode::SLt => connect(src0_cond, src0_flags.sf.cmp_ne(src0_flags.of)),
|
||||
ConditionMode::SGt => connect(
|
||||
src0_cond,
|
||||
!src0_flags.zf & src0_flags.sf.cmp_eq(src0_flags.of),
|
||||
),
|
||||
ConditionMode::Sign => connect(src0_cond, src0_flags.sf),
|
||||
ConditionMode::Overflow => connect(src0_cond, src0_flags.of),
|
||||
ConditionMode::Parity => connect(src0_cond, src0_flags.pf),
|
||||
};
|
||||
}
|
||||
}
|
||||
let src0_cond = src0_cond ^ invert_src0_cond;
|
||||
#[hdl]
|
||||
let pc_or_zero = wire();
|
||||
#[hdl]
|
||||
if pc_relative {
|
||||
connect(pc_or_zero, pc);
|
||||
} else {
|
||||
connect(pc_or_zero, 0u64);
|
||||
}
|
||||
#[hdl]
|
||||
let target_pc: UInt<64> = wire();
|
||||
connect_any(
|
||||
target_pc,
|
||||
src1.int_fp
|
||||
+ CommonMOpDefaultImm::as_sint_dyn(imm).cast_to_static::<UInt<64>>()
|
||||
+ pc_or_zero,
|
||||
);
|
||||
#[hdl]
|
||||
let cond_br_taken = wire();
|
||||
connect(cond_br_taken, src0_cond & src2_cond);
|
||||
#[hdl]
|
||||
let is_cond = wire();
|
||||
connect(is_cond, !cond_br_taken | has_src0 | has_src2);
|
||||
#[hdl]
|
||||
let next_pc = wire();
|
||||
#[hdl]
|
||||
if cond_br_taken {
|
||||
connect(next_pc, target_pc);
|
||||
} else {
|
||||
connect(next_pc, fallthrough_pc);
|
||||
};
|
||||
#[hdl]
|
||||
let cancel = wire(HdlOption[UnitCausedCancel[config]]);
|
||||
#[hdl]
|
||||
if next_pc.cmp_ne(predicted_next_pc) {
|
||||
connect(
|
||||
cancel,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
UnitCausedCancel::<C> {
|
||||
start_at_pc: next_pc,
|
||||
cancel_after_retire: true,
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
connect(cancel, cancel.ty().HdlNone());
|
||||
};
|
||||
let fallthrough_pc_value = #[hdl]
|
||||
PRegValue {
|
||||
int_fp: fallthrough_pc,
|
||||
flags: PRegFlags::zeroed_sim(),
|
||||
};
|
||||
#[hdl]
|
||||
let call_stack_op = wire();
|
||||
#[hdl]
|
||||
if is_ret {
|
||||
connect(call_stack_op, CallStackOp.Pop());
|
||||
} else if is_call {
|
||||
connect(call_stack_op, CallStackOp.Push(fallthrough_pc));
|
||||
} else {
|
||||
connect(call_stack_op, CallStackOp.None());
|
||||
}
|
||||
#[hdl]
|
||||
let cond_br_taken_opt = wire();
|
||||
#[hdl]
|
||||
if is_cond {
|
||||
connect(cond_br_taken_opt, HdlSome(cond_br_taken));
|
||||
} else {
|
||||
connect(cond_br_taken_opt, HdlNone());
|
||||
}
|
||||
(
|
||||
fallthrough_pc_value.into_trace_as_string(),
|
||||
#[hdl]
|
||||
NextPcPredictorOp::<_> {
|
||||
call_stack_op,
|
||||
cond_br_taken: cond_br_taken_opt,
|
||||
config,
|
||||
},
|
||||
cancel,
|
||||
)
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn read_special<C: PhantomConstCpuConfig>(
|
||||
global_state: Expr<GlobalState>,
|
||||
pc: Expr<UInt<64>>,
|
||||
mop: Expr<ReadSpecialMOp<PRegNum<C>, PRegNum<C>>>,
|
||||
src_values: Expr<Array<TraceAsString<PRegValue>, { COMMON_MOP_SRC_LEN }>>,
|
||||
) -> Expr<TraceAsString<PRegValue>> {
|
||||
#[hdl]
|
||||
let GlobalState { flags_mode } = global_state;
|
||||
// TODO: finish
|
||||
PRegValue::zeroed().to_trace_as_string()
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn alu_branch(config: PhantomConst<CpuConfig>, unit_index: usize) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[hdl]
|
||||
let unit_to_reg_alloc: UnitToRegAlloc<
|
||||
PhantomConst<CpuConfig>,
|
||||
AluBranchMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, PRegNum<PhantomConst<CpuConfig>>>,
|
||||
(),
|
||||
> = m.output(UnitToRegAlloc[config][AluBranchMOp[UnitOutRegNum[config]][PRegNum[config]]][()]);
|
||||
#[hdl]
|
||||
let global_state: GlobalState = m.input();
|
||||
let from_execute: ExecuteToUnitInterface<PhantomConst<CpuConfig>> =
|
||||
m.input(ExecuteToUnitInterface[config]);
|
||||
|
||||
assert_eq!(config.get().units[unit_index].kind, UnitKind::AluBranch);
|
||||
|
||||
#[hdl]
|
||||
let unit_base = instance(unit_base(
|
||||
config,
|
||||
unit_index,
|
||||
unit_to_reg_alloc.ty().input.data.HdlSome.mop,
|
||||
(),
|
||||
));
|
||||
connect(unit_to_reg_alloc, unit_base.unit_to_reg_alloc);
|
||||
connect(unit_base.cd, cd);
|
||||
connect(unit_base.execute_start.ready, true);
|
||||
connect(unit_base.execute_end, unit_base.execute_end.ty().HdlNone());
|
||||
let ExecuteToUnitInterface::<_> {
|
||||
global_state,
|
||||
enqueue,
|
||||
inputs_ready,
|
||||
is_no_longer_speculative: _, // we don't care about being speculative for these instructions
|
||||
cant_cause_cancel,
|
||||
output_ready,
|
||||
finish_cause_cancel,
|
||||
unit_outputs_ready: _,
|
||||
cancel_all,
|
||||
config: _,
|
||||
} = from_execute;
|
||||
// we ignore enqueues since we don't need to track order for these instructions
|
||||
connect(enqueue.ready, true);
|
||||
#[hdl]
|
||||
if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) {
|
||||
if let HdlSome(inputs_ready) = inputs_ready {
|
||||
#[hdl]
|
||||
let ExecuteStart::<_, _> {
|
||||
mop,
|
||||
pc,
|
||||
let UnitInputsReady::<_> {
|
||||
mop: mop_instance,
|
||||
src_values,
|
||||
config: _,
|
||||
} = execute_start;
|
||||
} = inputs_ready;
|
||||
#[hdl]
|
||||
match mop {
|
||||
AluBranchMOp::<_, _>::AddSub(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
let fallthrough_pc: UInt<64> = wire();
|
||||
connect_any(fallthrough_pc, mop_instance.pc + mop_instance.size_in_bytes);
|
||||
|
||||
#[hdl]
|
||||
match *mop_instance.mop {
|
||||
RenamedMOp::<_>::AluBranch(mop) => {
|
||||
#[hdl]
|
||||
let dest_value = wire();
|
||||
|
||||
#[hdl]
|
||||
let predictor_op = wire(NextPcPredictorOp[config]);
|
||||
connect(
|
||||
predictor_op,
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(add_sub(
|
||||
mop,
|
||||
pc,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
NextPcPredictorOp::<_> {
|
||||
call_stack_op: CallStackOp.None(),
|
||||
cond_br_taken: HdlNone(),
|
||||
config,
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::AddSubI(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(add_sub(
|
||||
mop,
|
||||
pc,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
);
|
||||
|
||||
#[hdl]
|
||||
let caused_cancel = wire(HdlOption[UnitCausedCancel[config]]);
|
||||
connect(caused_cancel, caused_cancel.ty().HdlNone());
|
||||
|
||||
#[hdl]
|
||||
match mop {
|
||||
AluBranchMOp::<_, _>::AddSub(mop) => {
|
||||
connect(
|
||||
dest_value,
|
||||
add_sub(global_state, mop_instance.pc, mop, src_values),
|
||||
);
|
||||
}
|
||||
AluBranchMOp::<_, _>::AddSubI(mop) => {
|
||||
connect(
|
||||
dest_value,
|
||||
add_sub(global_state, mop_instance.pc, mop, src_values),
|
||||
);
|
||||
}
|
||||
AluBranchMOp::<_, _>::LogicalFlags(mop) => {
|
||||
connect(
|
||||
dest_value,
|
||||
logical_flags(global_state, mop_instance.pc, mop, src_values),
|
||||
);
|
||||
}
|
||||
AluBranchMOp::<_, _>::Logical(mop) => {
|
||||
connect(
|
||||
dest_value,
|
||||
logical(global_state, mop_instance.pc, mop, src_values),
|
||||
);
|
||||
}
|
||||
AluBranchMOp::<_, _>::LogicalI(mop) => {
|
||||
connect(
|
||||
dest_value,
|
||||
logical_i(global_state, mop_instance.pc, mop, src_values),
|
||||
);
|
||||
}
|
||||
AluBranchMOp::<_, _>::ShiftRotate(mop) => {
|
||||
connect(
|
||||
dest_value,
|
||||
shift_rotate(global_state, mop_instance.pc, mop, src_values),
|
||||
);
|
||||
}
|
||||
AluBranchMOp::<_, _>::Compare(mop) => {
|
||||
connect(
|
||||
dest_value,
|
||||
compare(global_state, mop_instance.pc, mop, src_values),
|
||||
);
|
||||
}
|
||||
AluBranchMOp::<_, _>::CompareI(mop) => {
|
||||
connect(
|
||||
dest_value,
|
||||
compare(global_state, mop_instance.pc, mop, src_values),
|
||||
);
|
||||
}
|
||||
AluBranchMOp::<_, _>::Branch(mop) => {
|
||||
let (dest_value_, predictor_op_, caused_cancel_) = branch(
|
||||
global_state,
|
||||
mop_instance.pc,
|
||||
fallthrough_pc,
|
||||
mop_instance.predicted_next_pc,
|
||||
mop,
|
||||
src_values,
|
||||
config,
|
||||
);
|
||||
connect(dest_value, dest_value_);
|
||||
connect(predictor_op, predictor_op_);
|
||||
connect(caused_cancel, caused_cancel_);
|
||||
}
|
||||
AluBranchMOp::<_, _>::BranchI(mop) => {
|
||||
let (dest_value_, predictor_op_, caused_cancel_) = branch(
|
||||
global_state,
|
||||
mop_instance.pc,
|
||||
fallthrough_pc,
|
||||
mop_instance.predicted_next_pc,
|
||||
mop,
|
||||
src_values,
|
||||
config,
|
||||
);
|
||||
connect(dest_value, dest_value_);
|
||||
connect(predictor_op, predictor_op_);
|
||||
connect(caused_cancel, caused_cancel_);
|
||||
}
|
||||
AluBranchMOp::<_, _>::ReadSpecial(mop) => {
|
||||
connect(
|
||||
dest_value,
|
||||
read_special(global_state, mop_instance.pc, mop, src_values),
|
||||
);
|
||||
}
|
||||
}
|
||||
connect(
|
||||
output_ready,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
UnitOutputReady::<_> {
|
||||
id: mop_instance.id,
|
||||
dest_value,
|
||||
predictor_op,
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::LogicalFlags(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(logical_flags(
|
||||
mop,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
),
|
||||
);
|
||||
connect(
|
||||
finish_cause_cancel,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
UnitFinishCauseCancel::<_> {
|
||||
id: mop_instance.id,
|
||||
caused_cancel,
|
||||
config,
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::Logical(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(logical(
|
||||
mop,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::LogicalI(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(logical_i(
|
||||
mop,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::ShiftRotate(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(shift_rotate(
|
||||
mop,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::Compare(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(compare(
|
||||
mop,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::CompareI(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(compare(
|
||||
mop,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::Branch(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(branch(
|
||||
mop,
|
||||
pc,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::BranchI(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(branch(
|
||||
mop,
|
||||
pc,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
AluBranchMOp::<_, _>::ReadSpecial(mop) => connect(
|
||||
unit_base.execute_end,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteEnd::<_, _> {
|
||||
unit_output: #[hdl]
|
||||
UnitOutput::<_, _> {
|
||||
which: MOpTrait::dest_reg(mop),
|
||||
result: UnitResult[()].Completed(read_special(
|
||||
mop,
|
||||
pc,
|
||||
global_state.flags_mode,
|
||||
src_values,
|
||||
)),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
// error
|
||||
connect(output_ready, output_ready.ty().HdlNone());
|
||||
connect(finish_cause_cancel, finish_cause_cancel.ty().HdlNone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
connect(output_ready, output_ready.ty().HdlNone());
|
||||
connect(finish_cause_cancel, finish_cause_cancel.ty().HdlNone());
|
||||
}
|
||||
|
||||
// all outputs are immediately ready, so reporting that instructions can't cause cancels is superfluous
|
||||
connect(cant_cause_cancel, cant_cause_cancel.ty().HdlNone());
|
||||
// this unit is purely combinational so canceling does nothing
|
||||
connect(cancel_all.ready, true);
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
@ -624,52 +696,28 @@ impl AluBranch {
|
|||
|
||||
impl UnitTrait for AluBranch {
|
||||
type Type = alu_branch;
|
||||
type ExtraOut = ();
|
||||
type MOp =
|
||||
AluBranchMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, PRegNum<PhantomConst<CpuConfig>>>;
|
||||
|
||||
fn ty(&self) -> Self::Type {
|
||||
self.module.io_ty()
|
||||
}
|
||||
|
||||
fn extra_out_ty(&self) -> Self::ExtraOut {
|
||||
()
|
||||
}
|
||||
|
||||
fn mop_ty(&self) -> Self::MOp {
|
||||
self.module.io_ty().unit_to_reg_alloc.mop_ty()
|
||||
}
|
||||
|
||||
fn unit_kind(&self) -> UnitKind {
|
||||
UnitKind::AluBranch
|
||||
}
|
||||
|
||||
fn extract_mop(
|
||||
&self,
|
||||
mop: Expr<
|
||||
RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, PRegNum<PhantomConst<CpuConfig>>>,
|
||||
>,
|
||||
) -> Expr<HdlOption<Self::MOp>> {
|
||||
UnitMOp::alu_branch_mop(mop)
|
||||
}
|
||||
|
||||
fn module(&self) -> Interned<Module<Self::Type>> {
|
||||
self.module
|
||||
}
|
||||
|
||||
fn unit_to_reg_alloc(
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Option<Expr<ClockDomain>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn from_execute(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
|
||||
this.unit_to_reg_alloc
|
||||
}
|
||||
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
|
||||
this.cd
|
||||
}
|
||||
|
||||
fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState> {
|
||||
this.global_state
|
||||
) -> Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>> {
|
||||
this.from_execute
|
||||
}
|
||||
|
||||
fn to_dyn(&self) -> DynUnit {
|
||||
|
|
|
|||
|
|
@ -1,611 +0,0 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{
|
||||
config::{CpuConfig, CpuConfigUnitCount, PhantomConstCpuConfig},
|
||||
instruction::{COMMON_MOP_SRC_LEN, MOpTrait, PRegNum, UnitNum, UnitOutRegNum},
|
||||
register::PRegValue,
|
||||
unit::{UnitCancelInput, UnitOutput, UnitOutputWrite},
|
||||
util::tree_reduce::tree_reduce,
|
||||
};
|
||||
use fayalite::{
|
||||
memory::splat_mask,
|
||||
module::{memory_with_loc, wire_with_loc},
|
||||
prelude::*,
|
||||
ty::StaticType,
|
||||
util::ready_valid::ReadyValid,
|
||||
};
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct UnitForwardingInfo<C: PhantomConstGet<CpuConfig>> {
|
||||
pub unit_output_writes: ArrayType<HdlOption<UnitOutputWrite<C>>, CpuConfigUnitCount<C>>,
|
||||
pub unit_reg_frees: ArrayType<HdlOption<UnitOutRegNum<C>>, CpuConfigUnitCount<C>>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct UnitInput<MOp: Type> {
|
||||
pub mop: MOp,
|
||||
pub pc: UInt<64>,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct UnitToRegAlloc<C: PhantomConstGet<CpuConfig>, MOp: Type, ExtraOut: Type> {
|
||||
#[hdl(flip)]
|
||||
pub unit_forwarding_info: UnitForwardingInfo<C>,
|
||||
#[hdl(flip)]
|
||||
pub input: ReadyValid<UnitInput<MOp>>,
|
||||
#[hdl(flip)]
|
||||
pub cancel_input: HdlOption<UnitCancelInput<C>>,
|
||||
pub output: HdlOption<UnitOutput<C, ExtraOut>>,
|
||||
}
|
||||
|
||||
impl<C: PhantomConstCpuConfig, MOp: Type, ExtraOut: Type> UnitToRegAlloc<C, MOp, ExtraOut> {
|
||||
pub fn mop_ty(self) -> MOp {
|
||||
self.input.data.HdlSome.mop
|
||||
}
|
||||
pub fn extra_out_ty(self) -> ExtraOut {
|
||||
self.output.HdlSome.extra_out_ty()
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct ExecuteStart<
|
||||
C: PhantomConstGet<CpuConfig>,
|
||||
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<C>>,
|
||||
> {
|
||||
pub mop: MOp,
|
||||
pub pc: UInt<64>,
|
||||
pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct ExecuteEnd<C: PhantomConstGet<CpuConfig>, ExtraOut> {
|
||||
pub unit_output: UnitOutput<C, ExtraOut>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
enum InFlightOpState {
|
||||
Ready,
|
||||
Running,
|
||||
CanceledAndRunning,
|
||||
}
|
||||
|
||||
impl InFlightOpState {
|
||||
fn ready_next_state(canceling: bool, starting: bool, ending: bool) -> Expr<HdlOption<Self>> {
|
||||
match (canceling, starting, ending) {
|
||||
(false, false, _) => HdlSome(InFlightOpState.Ready()),
|
||||
(false, true, false) => HdlSome(InFlightOpState.Running()),
|
||||
(false, true, true) => HdlNone(),
|
||||
(true, false, _) => HdlNone(),
|
||||
(true, true, false) => HdlSome(InFlightOpState.CanceledAndRunning()),
|
||||
(true, true, true) => HdlNone(),
|
||||
}
|
||||
}
|
||||
fn running_next_state(canceling: bool, _starting: bool, ending: bool) -> Expr<HdlOption<Self>> {
|
||||
match (canceling, ending) {
|
||||
(false, false) => HdlSome(InFlightOpState.Running()),
|
||||
(false, true) => HdlNone(),
|
||||
(true, false) => HdlSome(InFlightOpState.CanceledAndRunning()),
|
||||
(true, true) => HdlNone(),
|
||||
}
|
||||
}
|
||||
fn canceled_and_running_next_state(
|
||||
_canceling: bool,
|
||||
_starting: bool,
|
||||
ending: bool,
|
||||
) -> Expr<HdlOption<Self>> {
|
||||
if ending {
|
||||
HdlNone()
|
||||
} else {
|
||||
HdlSome(InFlightOpState.CanceledAndRunning())
|
||||
}
|
||||
}
|
||||
/// FIXME: this is working around #[hdl] match not supporting matching values inside structs yet
|
||||
#[hdl]
|
||||
fn connect_next_state(
|
||||
canceling: Expr<Bool>,
|
||||
starting: Expr<Bool>,
|
||||
ending: Expr<Bool>,
|
||||
next_state_fn: fn(canceling: bool, starting: bool, ending: bool) -> Expr<HdlOption<Self>>,
|
||||
next_state: Expr<HdlOption<Self>>,
|
||||
) {
|
||||
#[hdl]
|
||||
fn recurse<const N: usize>(
|
||||
exprs: &[Expr<Bool>; N],
|
||||
bools: &mut [bool; N],
|
||||
f: &mut impl FnMut(&[bool; N]),
|
||||
arg_index: usize,
|
||||
) {
|
||||
if arg_index < N {
|
||||
#[hdl]
|
||||
if exprs[arg_index] {
|
||||
bools[arg_index] = true;
|
||||
recurse(exprs, bools, f, arg_index + 1);
|
||||
} else {
|
||||
bools[arg_index] = false;
|
||||
recurse(exprs, bools, f, arg_index + 1);
|
||||
}
|
||||
} else {
|
||||
f(bools);
|
||||
}
|
||||
}
|
||||
recurse(
|
||||
&[canceling, starting, ending],
|
||||
&mut [false; 3],
|
||||
&mut |&[canceling, starting, ending]| {
|
||||
connect(next_state, next_state_fn(canceling, starting, ending))
|
||||
},
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
struct InFlightOp<MOp: Type> {
|
||||
state: InFlightOpState,
|
||||
mop: MOp,
|
||||
pc: UInt<64>,
|
||||
src_ready_flags: Array<Bool, { COMMON_MOP_SRC_LEN }>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
struct InFlightOpsSummary<OpIndexWidth: Size> {
|
||||
empty_op_index: HdlOption<UIntType<OpIndexWidth>>,
|
||||
ready_op_index: HdlOption<UIntType<OpIndexWidth>>,
|
||||
}
|
||||
|
||||
impl<OpIndexWidth: Size> InFlightOpsSummary<OpIndexWidth> {
|
||||
#[hdl]
|
||||
fn new<MOp: Type>(
|
||||
op_index: usize,
|
||||
op_index_ty: UIntType<OpIndexWidth>,
|
||||
in_flight_op: impl ToExpr<Type = HdlOption<InFlightOp<MOp>>>,
|
||||
) -> Expr<Self> {
|
||||
let empty_op_index = wire_with_loc(
|
||||
&format!("empty_op_index_{op_index}"),
|
||||
SourceLocation::caller(),
|
||||
HdlOption[op_index_ty],
|
||||
);
|
||||
connect(empty_op_index, HdlOption[op_index_ty].HdlNone());
|
||||
let ready_op_index = wire_with_loc(
|
||||
&format!("ready_op_index_{op_index}"),
|
||||
SourceLocation::caller(),
|
||||
HdlOption[op_index_ty],
|
||||
);
|
||||
connect(ready_op_index, HdlOption[op_index_ty].HdlNone());
|
||||
#[hdl]
|
||||
if let HdlSome(in_flight_op) = in_flight_op {
|
||||
#[hdl]
|
||||
let InFlightOp::<_> {
|
||||
state,
|
||||
mop: _,
|
||||
pc: _,
|
||||
src_ready_flags,
|
||||
} = in_flight_op;
|
||||
connect(ready_op_index, HdlOption[op_index_ty].HdlNone());
|
||||
#[hdl]
|
||||
match state {
|
||||
InFlightOpState::Ready =>
|
||||
{
|
||||
#[hdl]
|
||||
if src_ready_flags.cmp_eq([true; COMMON_MOP_SRC_LEN]) {
|
||||
connect(ready_op_index, HdlSome(op_index.cast_to(op_index_ty)));
|
||||
}
|
||||
}
|
||||
InFlightOpState::CanceledAndRunning | InFlightOpState::Running => {}
|
||||
}
|
||||
} else {
|
||||
connect(empty_op_index, HdlSome(op_index.cast_to(op_index_ty)));
|
||||
}
|
||||
#[hdl]
|
||||
InFlightOpsSummary::<_> {
|
||||
empty_op_index,
|
||||
ready_op_index,
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
fn combine(l: impl ToExpr<Type = Self>, r: impl ToExpr<Type = Self>) -> Expr<Self> {
|
||||
let l = l.to_expr();
|
||||
let r = r.to_expr();
|
||||
#[hdl]
|
||||
InFlightOpsSummary::<_> {
|
||||
empty_op_index: HdlOption::or(l.empty_op_index, r.empty_op_index),
|
||||
ready_op_index: HdlOption::or(l.ready_op_index, r.ready_op_index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InFlightOpsSummary<DynSize> {
|
||||
fn summarize<MOp: Type, MaxInFlight: Size>(
|
||||
in_flight_ops: impl ToExpr<Type = ArrayType<HdlOption<InFlightOp<MOp>>, MaxInFlight>>,
|
||||
) -> Expr<Self> {
|
||||
let in_flight_ops = in_flight_ops.to_expr();
|
||||
let max_in_flight = in_flight_ops.ty().len();
|
||||
let index_range = 0..max_in_flight;
|
||||
let index_ty = UInt::range(index_range.clone());
|
||||
tree_reduce(
|
||||
index_range.map(|i| Self::new(i, index_ty, in_flight_ops[i])),
|
||||
Self::combine,
|
||||
)
|
||||
.expect("in_flight_ops is known to have len > 0")
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn unit_base<
|
||||
MOp: Type
|
||||
+ MOpTrait<
|
||||
DestReg = UnitOutRegNum<PhantomConst<CpuConfig>>,
|
||||
SrcReg = PRegNum<PhantomConst<CpuConfig>>,
|
||||
>,
|
||||
ExtraOut: Type,
|
||||
>(
|
||||
config: PhantomConst<CpuConfig>,
|
||||
unit_index: usize,
|
||||
mop_ty: MOp,
|
||||
extra_out_ty: ExtraOut,
|
||||
) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[hdl]
|
||||
let unit_to_reg_alloc: UnitToRegAlloc<PhantomConst<CpuConfig>, MOp, ExtraOut> =
|
||||
m.output(UnitToRegAlloc[config][mop_ty][extra_out_ty]);
|
||||
#[hdl]
|
||||
let execute_start: ReadyValid<ExecuteStart<PhantomConst<CpuConfig>, MOp>> =
|
||||
m.output(ReadyValid[ExecuteStart[config][mop_ty]]);
|
||||
#[hdl]
|
||||
let execute_end: HdlOption<ExecuteEnd<PhantomConst<CpuConfig>, ExtraOut>> =
|
||||
m.input(HdlOption[ExecuteEnd[config][extra_out_ty]]);
|
||||
|
||||
connect(execute_start.data, execute_start.ty().data.HdlNone());
|
||||
|
||||
let max_in_flight = config.get().unit_max_in_flight(unit_index).get();
|
||||
let in_flight_op_ty = InFlightOp[mop_ty];
|
||||
#[hdl]
|
||||
let in_flight_ops = reg_builder()
|
||||
.clock_domain(cd)
|
||||
.reset(repeat(HdlOption[in_flight_op_ty].HdlNone(), max_in_flight));
|
||||
|
||||
let in_flight_ops_summary_value = InFlightOpsSummary::summarize(in_flight_ops);
|
||||
#[hdl]
|
||||
let in_flight_ops_summary = wire(in_flight_ops_summary_value.ty());
|
||||
connect(in_flight_ops_summary, in_flight_ops_summary_value);
|
||||
|
||||
connect(
|
||||
unit_to_reg_alloc.input.ready,
|
||||
HdlOption::is_some(in_flight_ops_summary.empty_op_index),
|
||||
);
|
||||
|
||||
#[hdl]
|
||||
let UnitForwardingInfo::<_> {
|
||||
unit_output_writes,
|
||||
unit_reg_frees,
|
||||
} = unit_to_reg_alloc.unit_forwarding_info;
|
||||
#[hdl]
|
||||
let read_src_regs = wire(mop_ty.src_regs_ty());
|
||||
connect(
|
||||
read_src_regs,
|
||||
repeat(PRegNum[config].const_zero(), ConstUsize),
|
||||
);
|
||||
#[hdl]
|
||||
let read_src_values = wire();
|
||||
connect(read_src_values, [PRegValue::zeroed(); COMMON_MOP_SRC_LEN]);
|
||||
#[hdl]
|
||||
let input_src_regs = wire(mop_ty.src_regs_ty());
|
||||
connect(
|
||||
input_src_regs,
|
||||
repeat(PRegNum[config].const_zero(), ConstUsize),
|
||||
);
|
||||
#[hdl]
|
||||
let input_src_regs_valid = wire();
|
||||
connect(input_src_regs_valid, [true; COMMON_MOP_SRC_LEN]);
|
||||
let mut unit_output_regs_valid: Vec<MemBuilder<Bool>> = (0..unit_output_writes.ty().len())
|
||||
.map(|unit_index| {
|
||||
let mut mem = memory_with_loc(
|
||||
&format!("unit_{unit_index}_output_regs_valid"),
|
||||
Bool,
|
||||
SourceLocation::caller(),
|
||||
);
|
||||
mem.depth(1 << config.get().out_reg_num_width);
|
||||
mem
|
||||
})
|
||||
.collect();
|
||||
for unit_index in 0..unit_output_writes.ty().len() {
|
||||
let mut unit_output_regs = memory_with_loc(
|
||||
&format!("unit_{unit_index}_output_regs"),
|
||||
PRegValue,
|
||||
SourceLocation::caller(),
|
||||
);
|
||||
unit_output_regs.depth(1 << config.get().out_reg_num_width);
|
||||
|
||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||
let read_port = unit_output_regs.new_read_port();
|
||||
let p_reg_num = read_src_regs[src_index];
|
||||
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
|
||||
connect(read_port.en, false);
|
||||
connect(read_port.clk, cd.clk);
|
||||
#[hdl]
|
||||
if UnitNum::is_index(p_reg_num.unit_num, unit_index) {
|
||||
connect(read_port.en, true);
|
||||
connect(read_src_values[src_index], read_port.data);
|
||||
}
|
||||
}
|
||||
|
||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||
let read_port = unit_output_regs_valid[unit_index].new_read_port();
|
||||
let p_reg_num = input_src_regs[src_index];
|
||||
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
|
||||
connect(read_port.en, false);
|
||||
connect(read_port.clk, cd.clk);
|
||||
#[hdl]
|
||||
if UnitNum::is_index(p_reg_num.unit_num, unit_index) {
|
||||
connect(read_port.en, true);
|
||||
connect(input_src_regs_valid[src_index], read_port.data);
|
||||
}
|
||||
}
|
||||
|
||||
let write_port = unit_output_regs.new_write_port();
|
||||
connect_any(write_port.addr, 0u8);
|
||||
connect(write_port.en, false);
|
||||
connect(write_port.clk, cd.clk);
|
||||
connect(write_port.data, PRegValue::zeroed());
|
||||
connect(write_port.mask, splat_mask(PRegValue, true.to_expr()));
|
||||
let ready_write_port = unit_output_regs_valid[unit_index].new_write_port();
|
||||
connect_any(ready_write_port.addr, 0u8);
|
||||
connect(ready_write_port.en, false);
|
||||
connect(ready_write_port.clk, cd.clk);
|
||||
connect(ready_write_port.data, true);
|
||||
connect(ready_write_port.mask, true);
|
||||
#[hdl]
|
||||
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
||||
connect_any(write_port.addr, unit_output_write.which.value);
|
||||
connect(write_port.data, unit_output_write.value);
|
||||
connect(write_port.en, true);
|
||||
connect_any(ready_write_port.addr, unit_output_write.which.value);
|
||||
connect(ready_write_port.en, true);
|
||||
let p_reg_num = #[hdl]
|
||||
PRegNum::<_> {
|
||||
unit_num: UnitNum[config].from_index(unit_index),
|
||||
unit_out_reg: unit_output_write.which,
|
||||
};
|
||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||
#[hdl]
|
||||
if input_src_regs[src_index].cmp_eq(p_reg_num) {
|
||||
connect(input_src_regs_valid[src_index], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
let free_write_port = unit_output_regs_valid[unit_index].new_write_port();
|
||||
connect_any(free_write_port.addr, 0u8);
|
||||
connect(free_write_port.en, false);
|
||||
connect(free_write_port.clk, cd.clk);
|
||||
connect(free_write_port.data, false);
|
||||
connect(free_write_port.mask, true);
|
||||
#[hdl]
|
||||
if let HdlSome(unit_reg_free) = unit_reg_frees[unit_index] {
|
||||
connect_any(free_write_port.addr, unit_reg_free.value);
|
||||
connect(free_write_port.en, true);
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
if let HdlSome(ready_op_index) = in_flight_ops_summary.ready_op_index {
|
||||
#[hdl]
|
||||
if let HdlSome(in_flight_op) = in_flight_ops[ready_op_index] {
|
||||
connect(
|
||||
execute_start.data,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
ExecuteStart::<_, _> {
|
||||
mop: in_flight_op.mop,
|
||||
pc: in_flight_op.pc,
|
||||
src_values: read_src_values,
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
connect(
|
||||
unit_to_reg_alloc.output,
|
||||
unit_to_reg_alloc.output.ty().HdlNone(),
|
||||
);
|
||||
|
||||
#[hdl]
|
||||
let input_in_flight_op = wire(HdlOption[in_flight_op_ty]);
|
||||
connect(input_in_flight_op, HdlOption[in_flight_op_ty].HdlNone());
|
||||
#[hdl]
|
||||
if let HdlSome(input) = ReadyValid::firing_data(unit_to_reg_alloc.input) {
|
||||
#[hdl]
|
||||
let UnitInput::<_> { mop, pc } = input;
|
||||
#[hdl]
|
||||
let input_mop_src_regs = wire(mop_ty.src_regs_ty());
|
||||
connect(
|
||||
input_mop_src_regs,
|
||||
repeat(PRegNum[config].const_zero(), ConstUsize),
|
||||
);
|
||||
MOp::connect_src_regs(mop, input_mop_src_regs);
|
||||
let src_ready_flags = wire_with_loc(
|
||||
"input_in_flight_op_src_ready_flags",
|
||||
SourceLocation::caller(),
|
||||
StaticType::TYPE,
|
||||
);
|
||||
connect(src_ready_flags, input_src_regs_valid);
|
||||
connect(input_src_regs, input_mop_src_regs);
|
||||
#[hdl]
|
||||
if unit_to_reg_alloc.cancel_input.cmp_ne(HdlSome(
|
||||
#[hdl]
|
||||
UnitCancelInput::<_> {
|
||||
which: MOp::dest_reg(mop),
|
||||
},
|
||||
)) {
|
||||
connect(
|
||||
input_in_flight_op,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
InFlightOp::<_> {
|
||||
state: InFlightOpState.Ready(),
|
||||
mop,
|
||||
pc,
|
||||
src_ready_flags,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
#[hdl]
|
||||
if let HdlSome(empty_op_index) = in_flight_ops_summary.empty_op_index {
|
||||
connect(in_flight_ops[empty_op_index], input_in_flight_op);
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
let in_flight_op_next_state = wire(Array[HdlOption[InFlightOpState]][max_in_flight]);
|
||||
#[hdl]
|
||||
let in_flight_op_next_src_ready_flags =
|
||||
wire(Array[in_flight_op_ty.src_ready_flags][max_in_flight]);
|
||||
#[hdl]
|
||||
let in_flight_op_canceling = wire(Array[Bool][max_in_flight]);
|
||||
#[hdl]
|
||||
let in_flight_op_execute_starting = wire(Array[Bool][max_in_flight]);
|
||||
#[hdl]
|
||||
let in_flight_op_execute_ending = wire(Array[Bool][max_in_flight]);
|
||||
for in_flight_op_index in 0..max_in_flight {
|
||||
connect(
|
||||
in_flight_op_next_src_ready_flags[in_flight_op_index],
|
||||
[false; COMMON_MOP_SRC_LEN],
|
||||
);
|
||||
connect(in_flight_op_canceling[in_flight_op_index], false);
|
||||
connect(in_flight_op_execute_starting[in_flight_op_index], false);
|
||||
connect(in_flight_op_execute_ending[in_flight_op_index], false);
|
||||
#[hdl]
|
||||
if let HdlSome(in_flight_op) = in_flight_ops[in_flight_op_index] {
|
||||
#[hdl]
|
||||
let InFlightOp::<_> {
|
||||
state,
|
||||
mop,
|
||||
pc,
|
||||
src_ready_flags,
|
||||
} = in_flight_op;
|
||||
let which = MOp::dest_reg(mop);
|
||||
let src_regs = wire_with_loc(
|
||||
&format!("in_flight_op_src_regs_{in_flight_op_index}"),
|
||||
SourceLocation::caller(),
|
||||
mop_ty.src_regs_ty(),
|
||||
);
|
||||
connect(src_regs, repeat(PRegNum[config].const_zero(), ConstUsize));
|
||||
MOp::connect_src_regs(mop, src_regs);
|
||||
|
||||
#[hdl]
|
||||
if in_flight_ops_summary.ready_op_index.cmp_eq(HdlSome(
|
||||
in_flight_op_index.cast_to(in_flight_ops_summary.ty().ready_op_index.HdlSome),
|
||||
)) {
|
||||
connect(read_src_regs, src_regs);
|
||||
}
|
||||
|
||||
connect(
|
||||
in_flight_op_next_src_ready_flags[in_flight_op_index],
|
||||
src_ready_flags,
|
||||
);
|
||||
for unit_index in 0..unit_output_writes.ty().len() {
|
||||
#[hdl]
|
||||
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
||||
#[hdl]
|
||||
let UnitOutputWrite::<_> {
|
||||
which: unit_out_reg,
|
||||
value: _,
|
||||
} = unit_output_write;
|
||||
let p_reg_num = #[hdl]
|
||||
PRegNum::<_> {
|
||||
unit_num: UnitNum[config].from_index(unit_index),
|
||||
unit_out_reg,
|
||||
};
|
||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||
#[hdl]
|
||||
if p_reg_num.cmp_eq(src_regs[src_index]) {
|
||||
connect(
|
||||
in_flight_op_next_src_ready_flags[in_flight_op_index][src_index],
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
connect(
|
||||
in_flight_op_canceling[in_flight_op_index],
|
||||
unit_to_reg_alloc.cancel_input.cmp_eq(HdlSome(
|
||||
#[hdl]
|
||||
UnitCancelInput::<_> { which },
|
||||
)),
|
||||
);
|
||||
|
||||
#[hdl]
|
||||
if let HdlSome(execute_end) = execute_end {
|
||||
#[hdl]
|
||||
let ExecuteEnd::<_, _> { unit_output } = execute_end;
|
||||
#[hdl]
|
||||
if which.cmp_eq(unit_output.which) {
|
||||
connect(in_flight_op_execute_ending[in_flight_op_index], true);
|
||||
#[hdl]
|
||||
if !in_flight_op_canceling[in_flight_op_index] {
|
||||
#[hdl]
|
||||
match state {
|
||||
InFlightOpState::Running | InFlightOpState::Ready => {
|
||||
connect(unit_to_reg_alloc.output, HdlSome(unit_output))
|
||||
}
|
||||
InFlightOpState::CanceledAndRunning => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
if let HdlSome(execute_start) = ReadyValid::firing_data(execute_start) {
|
||||
#[hdl]
|
||||
if which.cmp_eq(MOp::dest_reg(execute_start.mop)) {
|
||||
connect(in_flight_op_execute_starting[in_flight_op_index], true);
|
||||
}
|
||||
}
|
||||
let connect_next_state = |f| {
|
||||
InFlightOpState::connect_next_state(
|
||||
in_flight_op_canceling[in_flight_op_index],
|
||||
in_flight_op_execute_starting[in_flight_op_index],
|
||||
in_flight_op_execute_ending[in_flight_op_index],
|
||||
f,
|
||||
in_flight_op_next_state[in_flight_op_index],
|
||||
);
|
||||
};
|
||||
#[hdl]
|
||||
match state {
|
||||
InFlightOpState::Ready => connect_next_state(InFlightOpState::ready_next_state),
|
||||
InFlightOpState::Running => connect_next_state(InFlightOpState::running_next_state),
|
||||
InFlightOpState::CanceledAndRunning => {
|
||||
connect_next_state(InFlightOpState::canceled_and_running_next_state);
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
if let HdlSome(state) = in_flight_op_next_state[in_flight_op_index] {
|
||||
connect(
|
||||
in_flight_ops[in_flight_op_index],
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
InFlightOp::<_> {
|
||||
state,
|
||||
mop,
|
||||
pc,
|
||||
src_ready_flags: in_flight_op_next_src_ready_flags[in_flight_op_index],
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
connect(
|
||||
in_flight_ops[in_flight_op_index],
|
||||
HdlOption[in_flight_op_ty].HdlNone(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
connect(in_flight_op_next_state[in_flight_op_index], HdlNone());
|
||||
}
|
||||
}
|
||||
}
|
||||
194669
crates/cpu/tests/expected/rename_execute_retire_real_alu_branch.vcd
generated
Normal file
194669
crates/cpu/tests/expected/rename_execute_retire_real_alu_branch.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -4057,10 +4057,16 @@ fn mock_load_store_unit<#[hdl(skip)] MI: MakeInsns>(
|
|||
}
|
||||
}
|
||||
|
||||
enum AluBranchKind {
|
||||
MockUnit,
|
||||
MockCombinationalUnit,
|
||||
Real,
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
fn rename_execute_retire_test_harness<#[hdl(skip)] MI: MakeInsns>(
|
||||
config: PhantomConst<CpuConfig>,
|
||||
alu_branch_is_combinatorial: bool,
|
||||
alu_branch_kind: AluBranchKind,
|
||||
) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
|
|
@ -4106,15 +4112,16 @@ fn rename_execute_retire_test_harness<#[hdl(skip)] MI: MakeInsns>(
|
|||
connect(mock_unit.from_execute, to_unit);
|
||||
connect(started_any_l2_reg_file_ops, mock_unit.started_any);
|
||||
}
|
||||
UnitKind::AluBranch => {
|
||||
if alu_branch_is_combinatorial {
|
||||
UnitKind::AluBranch => match alu_branch_kind {
|
||||
AluBranchKind::MockCombinationalUnit => {
|
||||
let mock_unit = instance_with_loc(
|
||||
&dut.ty().to_units.unit_field_name(unit_index),
|
||||
mock_combinational_unit::<()>(config, unit_index),
|
||||
SourceLocation::caller(),
|
||||
);
|
||||
connect(mock_unit.from_execute, to_unit);
|
||||
} else {
|
||||
}
|
||||
AluBranchKind::MockUnit => {
|
||||
let mock_unit = instance_with_loc(
|
||||
&dut.ty().to_units.unit_field_name(unit_index),
|
||||
mock_unit::<()>(config, unit_index),
|
||||
|
|
@ -4123,7 +4130,15 @@ fn rename_execute_retire_test_harness<#[hdl(skip)] MI: MakeInsns>(
|
|||
connect(mock_unit.cd, cd);
|
||||
connect(mock_unit.from_execute, to_unit);
|
||||
}
|
||||
}
|
||||
AluBranchKind::Real => {
|
||||
let unit = instance_with_loc(
|
||||
&dut.ty().to_units.unit_field_name(unit_index),
|
||||
cpu::unit::alu_branch::alu_branch(config, unit_index),
|
||||
SourceLocation::caller(),
|
||||
);
|
||||
connect(unit.from_execute, to_unit);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4198,7 +4213,7 @@ fn test_rename_execute_retire_fibonacci_non_combinatorial() {
|
|||
config.fetch_width = NonZeroUsize::new(3).unwrap();
|
||||
let m = rename_execute_retire_test_harness::<FibonacciInsns>(
|
||||
PhantomConst::new_sized(config),
|
||||
false,
|
||||
AluBranchKind::MockUnit,
|
||||
);
|
||||
let mut sim = Simulation::new(m);
|
||||
let _checked_vcd_output = checked_vcd_output!(
|
||||
|
|
@ -4233,8 +4248,10 @@ fn test_rename_execute_retire_fibonacci_combinatorial() {
|
|||
NonZeroUsize::new(20).unwrap(),
|
||||
);
|
||||
config.fetch_width = NonZeroUsize::new(3).unwrap();
|
||||
let m =
|
||||
rename_execute_retire_test_harness::<FibonacciInsns>(PhantomConst::new_sized(config), true);
|
||||
let m = rename_execute_retire_test_harness::<FibonacciInsns>(
|
||||
PhantomConst::new_sized(config),
|
||||
AluBranchKind::MockCombinationalUnit,
|
||||
);
|
||||
let mut sim = Simulation::new(m);
|
||||
let _checked_vcd_output = checked_vcd_output!(
|
||||
&mut sim,
|
||||
|
|
@ -4348,8 +4365,10 @@ fn test_rename_execute_retire_slow_loop() {
|
|||
NonZeroUsize::new(20).unwrap(),
|
||||
);
|
||||
config.fetch_width = NonZeroUsize::new(4).unwrap();
|
||||
let m =
|
||||
rename_execute_retire_test_harness::<SlowLoopInsns>(PhantomConst::new_sized(config), true);
|
||||
let m = rename_execute_retire_test_harness::<SlowLoopInsns>(
|
||||
PhantomConst::new_sized(config),
|
||||
AluBranchKind::MockCombinationalUnit,
|
||||
);
|
||||
let mut sim = Simulation::new(m);
|
||||
let _checked_vcd_output = checked_vcd_output!(
|
||||
&mut sim,
|
||||
|
|
@ -4469,8 +4488,10 @@ fn test_rename_execute_retire_head_n1() {
|
|||
NonZeroUsize::new(20).unwrap(),
|
||||
);
|
||||
config.fetch_width = NonZeroUsize::new(2).unwrap();
|
||||
let m =
|
||||
rename_execute_retire_test_harness::<HeadN1Insns>(PhantomConst::new_sized(config), true);
|
||||
let m = rename_execute_retire_test_harness::<HeadN1Insns>(
|
||||
PhantomConst::new_sized(config),
|
||||
AluBranchKind::MockCombinationalUnit,
|
||||
);
|
||||
let mut sim = Simulation::new(m);
|
||||
let _checked_vcd_output =
|
||||
checked_vcd_output!(&mut sim, "tests/expected/rename_execute_retire_head_n1.vcd");
|
||||
|
|
@ -4566,7 +4587,7 @@ fn test_rename_execute_retire_save_restore_gprs() {
|
|||
config.fetch_width = NonZeroUsize::new(2).unwrap();
|
||||
let m = rename_execute_retire_test_harness::<SaveRestoreGprsInsns>(
|
||||
PhantomConst::new_sized(config),
|
||||
true,
|
||||
AluBranchKind::MockCombinationalUnit,
|
||||
);
|
||||
let mut sim = Simulation::new(m);
|
||||
let _checked_vcd_output = checked_vcd_output!(
|
||||
|
|
@ -4585,3 +4606,39 @@ fn test_rename_execute_retire_save_restore_gprs() {
|
|||
}
|
||||
assert!(sim.read_bool(sim.io().all_outputs_written));
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
#[test]
|
||||
fn test_rename_execute_retire_real_alu_branch() {
|
||||
let _n = SourceLocation::normalize_files_for_tests();
|
||||
let mut config = CpuConfig::new(
|
||||
vec![
|
||||
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(2).unwrap();
|
||||
let m = rename_execute_retire_test_harness::<SaveRestoreGprsInsns>(
|
||||
PhantomConst::new_sized(config),
|
||||
AluBranchKind::Real,
|
||||
);
|
||||
let mut sim = Simulation::new(m);
|
||||
let _checked_vcd_output = checked_vcd_output!(
|
||||
&mut sim,
|
||||
"tests/expected/rename_execute_retire_real_alu_branch.vcd",
|
||||
);
|
||||
sim.write_clock(sim.io().cd.clk, false);
|
||||
sim.write_reset(sim.io().cd.rst, true);
|
||||
for cycle in 0..700 {
|
||||
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);
|
||||
}
|
||||
assert!(sim.read_bool(sim.io().all_outputs_written));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue