Compare commits

...

2 commits

4 changed files with 271 additions and 38 deletions

View file

@ -8,6 +8,7 @@ use crate::{
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, mop_enum,
},
rename_execute_retire::ExecuteToUnitInterface,
unit::load_store::LoadStoreToDCacheInterface,
};
use fayalite::{
bundle::{Bundle, BundleType},
@ -18,6 +19,7 @@ use serde::{Deserialize, Serialize};
use std::ops::ControlFlow;
pub mod alu_branch;
pub mod load_store;
macro_rules! all_units {
(
@ -333,7 +335,7 @@ all_units! {
#[create_dyn_unit_fn = |config, unit_index, filter| todo!()]
#[extract(transformed_move_mop, transformed_move_mop_sim, transformed_move_mop_sim_ref, transformed_move_mop_sim_mut)]
TransformedMove(TransformedMoveOp),
#[create_dyn_unit_fn = |config, unit_index, filter| todo!()]
#[create_dyn_unit_fn = |config, unit_index, filter| load_store::LoadStore::new(config, unit_index, filter).to_dyn()]
#[extract(load_store_mop, load_store_mop_sim, load_store_mop_sim_ref, load_store_mop_sim_mut)]
LoadStore(LoadStoreMOp<DestReg, SrcReg>),
}
@ -387,6 +389,13 @@ impl RenamedMOpFilter for () {
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct UnitIO {
pub cd: Option<Expr<ClockDomain>>,
pub from_execute: Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>>,
pub to_d_cache: Option<Expr<LoadStoreToDCacheInterface<PhantomConst<CpuConfig>>>>,
}
pub trait UnitTrait:
'static + Send + Sync + std::fmt::Debug + fayalite::intern::SupportsPtrEqWithTypeId
{
@ -395,11 +404,7 @@ pub trait UnitTrait:
fn ty(&self) -> Self::Type;
fn unit_kind(&self) -> UnitKind;
fn module(&self) -> Interned<Module<Self::Type>>;
fn cd(&self, this: Expr<Self::Type>) -> Option<Expr<ClockDomain>>;
fn from_execute(
&self,
this: Expr<Self::Type>,
) -> Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>>;
fn io(&self, this: Expr<Self::Type>) -> UnitIO;
fn to_dyn(&self) -> DynUnit;
}
@ -434,15 +439,8 @@ impl UnitTrait for DynUnit {
self.unit.module()
}
fn cd(&self, this: Expr<Self::Type>) -> Option<Expr<ClockDomain>> {
self.unit.cd(this)
}
fn from_execute(
&self,
this: Expr<Self::Type>,
) -> Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>> {
self.unit.from_execute(this)
fn io(&self, this: Expr<Self::Type>) -> UnitIO {
self.unit.io(this)
}
fn to_dyn(&self) -> DynUnit {
@ -468,15 +466,8 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
self.0.module().canonical().intern_sized()
}
fn cd(&self, this: Expr<Self::Type>) -> Option<Expr<ClockDomain>> {
self.0.cd(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 io(&self, this: Expr<Self::Type>) -> UnitIO {
self.0.io(Expr::from_bundle(this))
}
fn to_dyn(&self) -> DynUnit {

View file

@ -18,7 +18,7 @@ use crate::{
ExecuteToUnitInterface, GlobalState, NextPcPredictorOp, RenamedMOp, UnitCausedCancel,
UnitFinishCauseCancel, UnitInputsReady, UnitOutputReady,
},
unit::{DynUnit, DynUnitWrapper, RenamedMOpFilter, UnitKind, UnitTrait},
unit::{DynUnit, DynUnitWrapper, RenamedMOpFilter, UnitIO, UnitKind, UnitTrait},
};
use fayalite::{
expr::CastToImpl,
@ -1613,15 +1613,12 @@ impl UnitTrait for AluBranch {
self.module
}
fn cd(&self, _this: Expr<Self::Type>) -> Option<Expr<ClockDomain>> {
None
}
fn from_execute(
&self,
this: Expr<Self::Type>,
) -> Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>> {
this.from_execute
fn io(&self, this: Expr<Self::Type>) -> UnitIO {
UnitIO {
cd: None,
from_execute: this.from_execute,
to_d_cache: None,
}
}
fn to_dyn(&self) -> DynUnit {

View file

@ -0,0 +1,237 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
config::CpuConfig,
instruction::LoadStoreMOp,
main_memory_and_io::MemoryOperationErrorKind,
next_pc::CallStackOp,
register::PRegValue,
rename_execute_retire::{
ExecuteToUnitInterface, NextPcPredictorOp, RenamedMOp, UnitCausedCancel,
UnitFinishCauseCancel, UnitInputsReady, UnitOutputReady,
},
unit::{DynUnit, DynUnitWrapper, RenamedMOpFilter, UnitIO, UnitKind, UnitTrait},
};
use fayalite::{intern::Interned, prelude::*, util::ready_valid::ReadyValid};
use serde::{Deserialize, Serialize};
#[hdl]
pub struct DCacheOpKindLoad {
/// if this is `false`, then if the address refers to a valid cache line, that cache line must have any dirty data
/// written back to memory and then be set to invalid before performing the load.
pub is_cacheable: Bool,
/// if this is `true`, then the load must only look in the cache (must not propagate to the L2/L3 cache or to
/// memory), must not cause any earlier operations' timing to change because this load exists, and must not change
/// any cache state that remains after all operations finish, including LRU state, random number generators,
/// predictive prefetching state, etc.
/// Speculative loads that miss the cache must return [`DCacheFinishStatus::NotFound`].
pub is_speculative: Bool,
}
#[hdl]
pub struct DCacheOpKindStore {
/// if this is `false`, then if the address refers to a valid cache line, that cache line must have any dirty data
/// written back to memory and then be set to invalid before performing the store.
pub is_cacheable: Bool,
}
#[hdl]
pub enum DCacheOpKind {
Load(DCacheOpKindLoad),
Store(DCacheOpKindStore),
}
#[hdl]
pub struct DCacheStart<C: PhantomConstGet<CpuConfig>> {
pub kind: DCacheOpKind,
/// unaligned addresses may cause a load/store to cross a cache-line boundary
pub address: UInt<64>,
pub data_and_mask: Array<HdlOption<UInt<8>>, 8>,
pub config: C,
}
#[hdl]
pub enum DCacheFinishStatus {
/// The operation finished successfully
Success,
/// A speculative load missed the cache, so data was not returned.
NotFound,
MemoryError(MemoryOperationErrorKind),
}
#[hdl]
pub struct DCacheFinish<C: PhantomConstGet<CpuConfig>> {
pub status: DCacheFinishStatus,
pub data: Array<UInt<8>, 8>,
pub config: C,
}
#[hdl]
pub struct LoadStoreToDCacheInterface<C: PhantomConstGet<CpuConfig>> {
pub start: ReadyValid<DCacheStart<C>>,
#[hdl(flip)]
pub finish: ReadyValid<DCacheFinish<C>>,
pub config: C,
}
#[hdl]
async fn load_store_impl(
config: PhantomConst<CpuConfig>,
unit_index: usize,
filter: LoadStoreFilter,
cd: Expr<ClockDomain>,
from_execute: Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>>,
to_d_cache: Expr<LoadStoreToDCacheInterface<PhantomConst<CpuConfig>>>,
mut sim: ExternModuleSimulationState,
) {
todo!()
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
struct LoadStoreFilter {
load: bool,
store: bool,
}
impl LoadStoreFilter {
fn new(
from_execute: ExecuteToUnitInterface<PhantomConst<CpuConfig>>,
filter: &mut impl RenamedMOpFilter,
) -> Self {
let LoadStoreMOp { Load, Store } = from_execute
.inputs_ready
.HdlSome
.mop
.mop
.inner_ty()
.LoadStore;
Self {
load: filter.should_include_ty(Load),
store: filter.should_include_ty(Store),
}
}
}
#[hdl_module(extern)]
pub fn load_store(
config: PhantomConst<CpuConfig>,
unit_index: usize,
filter: &mut impl RenamedMOpFilter,
) {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let from_execute: ExecuteToUnitInterface<PhantomConst<CpuConfig>> =
m.input(ExecuteToUnitInterface[config]);
#[hdl]
let to_d_cache: LoadStoreToDCacheInterface<PhantomConst<CpuConfig>> =
m.output(LoadStoreToDCacheInterface[config]);
let filter = LoadStoreFilter::new(from_execute.ty(), filter);
assert_eq!(config.get().units[unit_index].kind, UnitKind::LoadStore);
m.register_clock_for_past(cd.clk);
m.extern_module_simulation_fn(
(config, unit_index, filter, cd, from_execute, to_d_cache),
async |(config, unit_index, filter, cd, from_execute, to_d_cache), mut sim| {
sim.resettable(
cd,
async |mut sim| {
#[hdl]
let ExecuteToUnitInterface::<_> {
global_state: _,
enqueue,
inputs_ready: _,
is_no_longer_speculative: _,
cant_cause_cancel,
output_ready,
finish_cause_cancel,
unit_outputs_ready: _,
cancel_all,
config: _,
} = from_execute;
sim.write(enqueue.ready, false).await;
sim.write(cant_cause_cancel, cant_cause_cancel.ty().HdlNone())
.await;
sim.write(output_ready, output_ready.ty().HdlNone()).await;
sim.write(finish_cause_cancel, finish_cause_cancel.ty().HdlNone())
.await;
sim.write(cancel_all.ready, false).await;
#[hdl]
let LoadStoreToDCacheInterface::<_> {
start,
finish,
config: _,
} = to_d_cache;
sim.write(start.data, start.ty().data.HdlNone()).await;
sim.write(finish.ready, false).await;
},
async |sim, ()| {
load_store_impl(
config,
unit_index,
filter,
cd,
from_execute,
to_d_cache,
sim,
)
.await
},
)
.await
},
);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct LoadStore {
config: PhantomConst<CpuConfig>,
module: Interned<Module<load_store>>,
}
impl LoadStore {
pub fn new(
config: PhantomConst<CpuConfig>,
unit_index: usize,
filter: &mut impl RenamedMOpFilter,
) -> Self {
Self {
config,
module: load_store(config, unit_index, filter),
}
}
}
impl UnitTrait for LoadStore {
type Type = load_store;
fn ty(&self) -> Self::Type {
self.module.io_ty()
}
fn unit_kind(&self) -> UnitKind {
UnitKind::LoadStore
}
fn module(&self) -> Interned<Module<Self::Type>> {
self.module
}
fn io(&self, this: Expr<Self::Type>) -> UnitIO {
UnitIO {
cd: Some(this.cd),
from_execute: this.from_execute,
to_d_cache: Some(this.to_d_cache),
}
}
fn to_dyn(&self) -> DynUnit {
DynUnitWrapper(*self).to_dyn()
}
}

View file

@ -14,7 +14,7 @@ use cpu::{
DecodeAndRunSingleInsnInput, DecodeAndRunSingleInsnOutput, DecodeOneInsnInput,
DecodeOneInsnMaxMOpCount, decode_and_run_single_insn,
},
unit::{RenamedMOpFilter, UnitKind, UnitMOp, UnitTrait},
unit::{RenamedMOpFilter, UnitIO, UnitKind, UnitMOp, UnitTrait},
util::array_vec::ArrayVec,
};
use fayalite::{
@ -91,12 +91,20 @@ fn formal_harness(
dyn_unit.module(),
SourceLocation::caller(),
);
let UnitIO {
cd: unit_cd,
from_execute: unit_from_execute,
to_d_cache,
} = dyn_unit.io(unit);
if let Some(unit_cd) = unit_cd {
connect(unit_cd, cd);
}
connect(
dyn_unit.from_execute(unit),
unit_from_execute,
ExecuteToUnitInterfaces::unit_fields(decode_and_run.to_units)[unit_index],
);
if let Some(unit_cd) = dyn_unit.cd(unit) {
connect(unit_cd, cd);
if let Some(to_d_cache) = to_d_cache {
unimplemented!("to_d_cache for {unit:?}: {to_d_cache:?}");
}
}
hdl_assert(cd.clk, !decode_and_run.error, "");