forked from libre-chip/cpu
WIP adding next_pc
This commit is contained in:
parent
6b703b012a
commit
c423dc4f15
3 changed files with 143 additions and 0 deletions
|
|
@ -34,6 +34,8 @@ pub struct CpuConfig {
|
|||
pub units: Vec<UnitConfig>,
|
||||
pub out_reg_num_width: usize,
|
||||
pub fetch_width: NonZeroUsize,
|
||||
pub max_branches_per_fetch: NonZeroUsize,
|
||||
pub fetch_width_in_bytes: NonZeroUsize,
|
||||
/// default value for [`UnitConfig::max_in_flight`]
|
||||
pub default_unit_max_in_flight: NonZeroUsize,
|
||||
pub rob_size: NonZeroUsize,
|
||||
|
|
@ -47,6 +49,18 @@ impl CpuConfig {
|
|||
};
|
||||
v
|
||||
};
|
||||
pub const DEFAULT_MAX_BRANCHES_PER_FETCH: NonZeroUsize = {
|
||||
let Some(v) = NonZeroUsize::new(1) else {
|
||||
unreachable!();
|
||||
};
|
||||
v
|
||||
};
|
||||
pub const DEFAULT_FETCH_WIDTH_IN_BYTES: NonZeroUsize = {
|
||||
let Some(v) = NonZeroUsize::new(4) else {
|
||||
unreachable!();
|
||||
};
|
||||
v
|
||||
};
|
||||
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
|
||||
let Some(v) = NonZeroUsize::new(8) else {
|
||||
unreachable!();
|
||||
|
|
@ -58,6 +72,8 @@ impl CpuConfig {
|
|||
units,
|
||||
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
|
||||
fetch_width: Self::DEFAULT_FETCH_WIDTH,
|
||||
max_branches_per_fetch: Self::DEFAULT_MAX_BRANCHES_PER_FETCH,
|
||||
fetch_width_in_bytes: Self::DEFAULT_FETCH_WIDTH_IN_BYTES,
|
||||
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
||||
rob_size,
|
||||
}
|
||||
|
|
@ -118,3 +134,12 @@ impl CpuConfig {
|
|||
[self.non_const_unit_nums().len()]
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(get(|c| c.fetch_width.get()))]
|
||||
pub type CpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(get(|c| c.max_branches_per_fetch.get()))]
|
||||
pub type CpuConfigMaxBranchesPerFetch<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(get(|c| c.fetch_width_in_bytes.get()))]
|
||||
pub type CpuConfigFetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// See Notices.txt for copyright information
|
||||
pub mod config;
|
||||
pub mod instruction;
|
||||
pub mod next_pc;
|
||||
pub mod reg_alloc;
|
||||
pub mod register;
|
||||
pub mod unit;
|
||||
|
|
|
|||
117
crates/cpu/src/next_pc.rs
Normal file
117
crates/cpu/src/next_pc.rs
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
//! [Next-Instruction Logic](https://git.libre-chip.org/libre-chip/grant-tracking/issues/10)
|
||||
//!
|
||||
//! The basic idea here is that there's a `next_pc` stage that sends predicted fetch PCs to the `fetch` stage,
|
||||
//! the `fetch` stage's outputs eventually end up in the `decode` stage,
|
||||
//! after the `decode` stage there's a `post_decode` stage (that may run in the same clock cycle as `decode`)
|
||||
//! that checks that the fetched instructions' kinds match the predicted instruction kinds and that feeds
|
||||
//! information back to the `fetch` stage to cancel fetches that need to be predicted differently.
|
||||
|
||||
use crate::{config::CpuConfig, util::array_vec::ArrayVec};
|
||||
use fayalite::prelude::*;
|
||||
use fayalite::util::ready_valid::ReadyValid;
|
||||
|
||||
#[hdl]
|
||||
pub enum PredictedCond {
|
||||
Taken,
|
||||
Fallthrough,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct PredictedFallthrough {}
|
||||
|
||||
#[hdl]
|
||||
pub enum BranchPredictionKind<CondKind> {
|
||||
Branch(HdlOption<CondKind>),
|
||||
IndirectBranch(HdlOption<CondKind>),
|
||||
Call(HdlOption<CondKind>),
|
||||
IndirectCall(HdlOption<CondKind>),
|
||||
Ret(HdlOption<CondKind>),
|
||||
}
|
||||
|
||||
#[hdl(get(|c| c.max_branches_per_fetch.get() - 1))]
|
||||
pub type NextPcPredictionMaxBranchesBeforeLast<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct NextPcPrediction<C: PhantomConstGet<CpuConfig>> {
|
||||
pub fetch_pc: UInt<64>,
|
||||
pub async_interrupt: Bool,
|
||||
pub branches_before_last: ArrayVec<
|
||||
BranchPredictionKind<PredictedFallthrough>,
|
||||
NextPcPredictionMaxBranchesBeforeLast<C>,
|
||||
>,
|
||||
pub last_branch: HdlOption<BranchPredictionKind<PredictedCond>>,
|
||||
pub last_branch_target_pc: UInt<64>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct NextPcToFetchInterfaceInner {
|
||||
pub next_fetch_pc: UInt<64>,
|
||||
pub in_progress_fetches_to_cancel: UInt<8>,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct NextPcToFetchInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
pub inner: ReadyValid<NextPcToFetchInterfaceInner>,
|
||||
pub config: 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 NextPcToRetireInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
// TODO: add needed fields
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct NextPcToPostDecodeInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
// TODO: add needed fields
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct FetchToPostDecodeInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
// TODO: add needed fields
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct PostDecodeOutputInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
// TODO: add needed fields
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn next_pc(config: PhantomConst<CpuConfig>) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[hdl]
|
||||
let to_fetch_interface: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
||||
m.output(NextPcToFetchInterface[config]);
|
||||
#[hdl]
|
||||
let to_post_decode_interface: NextPcToPostDecodeInterface<PhantomConst<CpuConfig>> =
|
||||
m.output(NextPcToPostDecodeInterface[config]);
|
||||
#[hdl]
|
||||
let to_retire_interface: NextPcToRetireInterface<PhantomConst<CpuConfig>> =
|
||||
m.output(NextPcToRetireInterface[config]);
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn post_decode(config: PhantomConst<CpuConfig>) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[hdl]
|
||||
let from_next_pc_interface: NextPcToPostDecodeInterface<PhantomConst<CpuConfig>> =
|
||||
m.input(NextPcToPostDecodeInterface[config]);
|
||||
#[hdl]
|
||||
let from_fetch_interface: FetchToPostDecodeInterface<PhantomConst<CpuConfig>> =
|
||||
m.output(FetchToPostDecodeInterface[config]);
|
||||
#[hdl]
|
||||
let output: PostDecodeOutputInterface<PhantomConst<CpuConfig>> =
|
||||
m.output(PostDecodeOutputInterface[config]);
|
||||
todo!()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue