forked from libre-chip/cpu
Compare commits
3 commits
c423dc4f15
...
10db8b3f90
| Author | SHA1 | Date | |
|---|---|---|---|
| 10db8b3f90 | |||
| f728964cb3 | |||
| 2c5b1b7f44 |
7 changed files with 155 additions and 7 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
|
@ -210,6 +210,7 @@ name = "cpu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fayalite",
|
"fayalite",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -303,7 +304,7 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite"
|
name = "fayalite"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c11a1743f97b5219725d123d876effe717b633f2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bitvec",
|
"bitvec",
|
||||||
|
|
@ -330,7 +331,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-proc-macros"
|
name = "fayalite-proc-macros"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c11a1743f97b5219725d123d876effe717b633f2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fayalite-proc-macros-impl",
|
"fayalite-proc-macros-impl",
|
||||||
]
|
]
|
||||||
|
|
@ -338,7 +339,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-proc-macros-impl"
|
name = "fayalite-proc-macros-impl"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c11a1743f97b5219725d123d876effe717b633f2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16ct",
|
"base16ct",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
|
|
@ -353,7 +354,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-visit-gen"
|
name = "fayalite-visit-gen"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c11a1743f97b5219725d123d876effe717b633f2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ rust-version = "1.89.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.3.0", branch = "master" }
|
fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.3.0", branch = "master" }
|
||||||
|
serde = { version = "1.0.202", features = ["derive"] }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
|
|
|
||||||
|
|
@ -16,3 +16,4 @@ version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fayalite.workspace = true
|
fayalite.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,10 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use fayalite::prelude::*;
|
use fayalite::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UnitConfig {
|
pub struct UnitConfig {
|
||||||
pub kind: UnitKind,
|
pub kind: UnitKind,
|
||||||
|
|
@ -27,12 +28,14 @@ impl UnitConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct CpuConfig {
|
pub struct CpuConfig {
|
||||||
pub units: Vec<UnitConfig>,
|
pub units: Vec<UnitConfig>,
|
||||||
pub out_reg_num_width: usize,
|
pub out_reg_num_width: usize,
|
||||||
pub fetch_width: NonZeroUsize,
|
pub fetch_width: NonZeroUsize,
|
||||||
|
pub max_branches_per_fetch: NonZeroUsize,
|
||||||
|
pub fetch_width_in_bytes: NonZeroUsize,
|
||||||
/// default value for [`UnitConfig::max_in_flight`]
|
/// default value for [`UnitConfig::max_in_flight`]
|
||||||
pub default_unit_max_in_flight: NonZeroUsize,
|
pub default_unit_max_in_flight: NonZeroUsize,
|
||||||
pub rob_size: NonZeroUsize,
|
pub rob_size: NonZeroUsize,
|
||||||
|
|
@ -46,6 +49,18 @@ impl CpuConfig {
|
||||||
};
|
};
|
||||||
v
|
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 = {
|
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
|
||||||
let Some(v) = NonZeroUsize::new(8) else {
|
let Some(v) = NonZeroUsize::new(8) else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
|
@ -57,6 +72,8 @@ impl CpuConfig {
|
||||||
units,
|
units,
|
||||||
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
|
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
|
||||||
fetch_width: Self::DEFAULT_FETCH_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,
|
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
||||||
rob_size,
|
rob_size,
|
||||||
}
|
}
|
||||||
|
|
@ -117,3 +134,12 @@ impl CpuConfig {
|
||||||
[self.non_const_unit_nums().len()]
|
[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
|
// See Notices.txt for copyright information
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
|
pub mod next_pc;
|
||||||
pub mod reg_alloc;
|
pub mod reg_alloc;
|
||||||
pub mod register;
|
pub mod register;
|
||||||
pub mod unit;
|
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!()
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,7 @@ use fayalite::{
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod alu_branch;
|
pub mod alu_branch;
|
||||||
pub mod unit_base;
|
pub mod unit_base;
|
||||||
|
|
@ -36,7 +37,7 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
$(#[$enum_meta])*
|
$(#[$enum_meta])*
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
|
||||||
$vis enum $UnitKind {
|
$vis enum $UnitKind {
|
||||||
$(
|
$(
|
||||||
$(#[$variant_meta])*
|
$(#[$variant_meta])*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue