forked from libre-chip/cpu
WIP linking next_pc stages together
This commit is contained in:
parent
e3ebbe6b40
commit
1d8adba04c
3 changed files with 584 additions and 69 deletions
|
|
@ -35,6 +35,7 @@ pub struct CpuConfig {
|
|||
pub out_reg_num_width: usize,
|
||||
pub fetch_width: NonZeroUsize,
|
||||
pub max_branches_per_fetch: NonZeroUsize,
|
||||
pub max_fetches_in_flight: NonZeroUsize,
|
||||
pub log2_fetch_width_in_bytes: u8,
|
||||
/// default value for [`UnitConfig::max_in_flight`]
|
||||
pub default_unit_max_in_flight: NonZeroUsize,
|
||||
|
|
@ -55,6 +56,12 @@ impl CpuConfig {
|
|||
};
|
||||
v
|
||||
};
|
||||
pub const DEFAULT_MAX_FETCHES_IN_FLIGHT: NonZeroUsize = {
|
||||
let Some(v) = NonZeroUsize::new(16) else {
|
||||
unreachable!();
|
||||
};
|
||||
v
|
||||
};
|
||||
pub const DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES: u8 = 3;
|
||||
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
|
||||
let Some(v) = NonZeroUsize::new(8) else {
|
||||
|
|
@ -68,6 +75,7 @@ impl CpuConfig {
|
|||
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,
|
||||
max_fetches_in_flight: Self::DEFAULT_MAX_FETCHES_IN_FLIGHT,
|
||||
log2_fetch_width_in_bytes: Self::DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES,
|
||||
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
||||
rob_size,
|
||||
|
|
@ -138,9 +146,15 @@ impl CpuConfig {
|
|||
#[hdl(get(|c| c.fetch_width.get()))]
|
||||
pub type CpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(get(|c| c.fetch_width.get() * 2))]
|
||||
pub type TwiceCpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(get(|c| c.max_branches_per_fetch.get()))]
|
||||
pub type CpuConfigMaxBranchesPerFetch<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(get(|c| c.max_fetches_in_flight.get()))]
|
||||
pub type CpuConfigMaxFetchesInFlight<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(get(|c| c.log2_fetch_width_in_bytes.into()))]
|
||||
pub type CpuConfigLog2FetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,14 +12,15 @@
|
|||
#![doc = simple_mermaid::mermaid!("next_pc/next_pc.mermaid")]
|
||||
|
||||
use crate::{
|
||||
config::{CpuConfig, CpuConfigFetchWidth},
|
||||
config::{CpuConfig, CpuConfigFetchWidth, CpuConfigMaxFetchesInFlight},
|
||||
util::array_vec::ArrayVec,
|
||||
};
|
||||
use fayalite::{
|
||||
expr::HdlPartialEqImpl,
|
||||
int::{UIntInRange, UIntInRangeInclusive, UIntInRangeType},
|
||||
int::{UIntInRange, UIntInRangeInclusive, UIntInRangeInclusiveType, UIntInRangeType},
|
||||
prelude::*,
|
||||
sim::value::SimOnlyValueTrait,
|
||||
ty::StaticType,
|
||||
util::ready_valid::ReadyValid,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
|
@ -29,14 +30,14 @@ type FetchBlockIdInt = u8;
|
|||
|
||||
#[hdl]
|
||||
pub struct NextPcToFetchInterfaceInner {
|
||||
pub next_fetch_pc: UInt<64>,
|
||||
pub start_pc: UInt<64>,
|
||||
pub fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
|
||||
pub in_progress_fetches_to_cancel: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct NextPcToFetchInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
pub inner: ReadyValid<NextPcToFetchInterfaceInner>,
|
||||
pub fetch: ReadyValid<NextPcToFetchInterfaceInner>,
|
||||
pub cancel: ReadyValid<UIntInRangeInclusiveType<ConstUsize<1>, CpuConfigMaxFetchesInFlight<C>>>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
|
|
@ -111,6 +112,29 @@ pub struct RetireToNextPcInterfacePerInsn<C: PhantomConstGet<CpuConfig>> {
|
|||
pub config: C,
|
||||
}
|
||||
|
||||
impl SimValueDefault for RetireToNextPcInterfacePerInsn<PhantomConst<CpuConfig>> {
|
||||
#[hdl]
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
let Self {
|
||||
id,
|
||||
next_pc: _,
|
||||
call_stack_op: _,
|
||||
cond_br_taken: _,
|
||||
config,
|
||||
} = self;
|
||||
#[hdl(sim)]
|
||||
Self {
|
||||
id: id.zero(),
|
||||
next_pc: 0u64,
|
||||
call_stack_op: #[hdl(sim)]
|
||||
CallStackOp::None(),
|
||||
cond_br_taken: #[hdl(sim)]
|
||||
HdlNone(),
|
||||
config,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct RetireToNextPcInterfaceInner<C: PhantomConstGet<CpuConfig>> {
|
||||
pub insns: ArrayVec<RetireToNextPcInterfacePerInsn<C>, CpuConfigFetchWidth<C>>,
|
||||
|
|
@ -151,7 +175,9 @@ pub struct DecodeToPostDecodeInterface<C: PhantomConstGet<CpuConfig>> {
|
|||
|
||||
#[hdl(no_static)]
|
||||
pub struct PostDecodeOutputInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
// TODO: add needed fields
|
||||
pub insns: ArrayVec<WipDecodedInsn, CpuConfigFetchWidth<C>>,
|
||||
#[hdl(flip)]
|
||||
pub ready: UIntInRangeInclusiveType<ConstUsize<0>, CpuConfigFetchWidth<C>>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
|
|
@ -171,12 +197,13 @@ struct Cancel<C: PhantomConstGet<CpuConfig>> {
|
|||
config: C,
|
||||
}
|
||||
|
||||
/// the output of `Stage::run`.
|
||||
/// the output of [`Stage::run`].
|
||||
/// when cancelling operations, the returned [`StageOutput.cancel`] should be the state after
|
||||
/// running all operations returned in [`StageOutput.output`]
|
||||
/// running all operations returned in [`StageOutput.output`].
|
||||
#[hdl(no_static)]
|
||||
struct StageOutput<Output, MaxOutputCount: Size, C: PhantomConstGet<CpuConfig>> {
|
||||
outputs: ArrayVec<Output, MaxOutputCount>,
|
||||
/// when set to [`HdlSome`], [`Stage::cancel`] is called on all previous stages
|
||||
cancel: HdlOption<Cancel<C>>,
|
||||
}
|
||||
|
||||
|
|
@ -194,6 +221,7 @@ trait Stage: Type + SimValueDefault + ResetSteps {
|
|||
) -> StageOutput<Self::Output, Self::MaxOutputCount, PhantomConst<CpuConfig>> {
|
||||
StageOutput[Self::output_ty(config)][Self::max_output_count(config)][config]
|
||||
}
|
||||
/// see [`StageOutput`] for docs on output
|
||||
fn run(
|
||||
state: &mut SimValue<Self>,
|
||||
inputs: &SimValue<Self::Inputs>,
|
||||
|
|
@ -780,6 +808,23 @@ struct PostDecodeStageState<C: PhantomConstGet<CpuConfig>> {
|
|||
config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct PostDecodeStageInput<C: PhantomConstGet<CpuConfig>> {
|
||||
fetch_decode_stage_output: FetchDecodeStageOutput<C>,
|
||||
br_pred_stage_output: BrPredStageOutput<C>,
|
||||
}
|
||||
|
||||
impl SimValueDefault for PostDecodeStageInput<PhantomConst<CpuConfig>> {
|
||||
#[hdl]
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
#[hdl(sim)]
|
||||
Self {
|
||||
fetch_decode_stage_output: self.fetch_decode_stage_output.sim_value_default(),
|
||||
br_pred_stage_output: self.br_pred_stage_output.sim_value_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct PostDecodeStageOutput<C: PhantomConstGet<CpuConfig>> {
|
||||
insn: WipDecodedInsn,
|
||||
|
|
@ -829,10 +874,7 @@ impl ResetSteps for PostDecodeStageState<PhantomConst<CpuConfig>> {
|
|||
}
|
||||
|
||||
impl Stage for PostDecodeStageState<PhantomConst<CpuConfig>> {
|
||||
type Inputs = (
|
||||
FetchDecodeStageOutput<PhantomConst<CpuConfig>>,
|
||||
BrPredStageOutput<PhantomConst<CpuConfig>>,
|
||||
);
|
||||
type Inputs = PostDecodeStageInput<PhantomConst<CpuConfig>>;
|
||||
type Output = PostDecodeStageOutput<PhantomConst<CpuConfig>>;
|
||||
type MaxOutputCount = CpuConfigFetchWidth<PhantomConst<CpuConfig>>;
|
||||
|
||||
|
|
@ -855,7 +897,10 @@ impl Stage for PostDecodeStageState<PhantomConst<CpuConfig>> {
|
|||
let Self { config } = state;
|
||||
let config = config.ty();
|
||||
#[hdl(sim)]
|
||||
let (fetch_decode_stage_output, br_pred_stage_output) = inputs;
|
||||
let PostDecodeStageInput::<_> {
|
||||
fetch_decode_stage_output,
|
||||
br_pred_stage_output,
|
||||
} = inputs;
|
||||
#[hdl(sim)]
|
||||
let FetchDecodeStageOutput::<_> {
|
||||
next_pc_stage_output,
|
||||
|
|
@ -1252,6 +1297,22 @@ struct RetireStageInput<C: PhantomConstGet<CpuConfig>> {
|
|||
retire_interface_per_insn: RetireToNextPcInterfacePerInsn<C>,
|
||||
}
|
||||
|
||||
impl SimValueDefault for RetireStageInput<PhantomConst<CpuConfig>> {
|
||||
#[hdl]
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
let Self {
|
||||
rename_dispatch_execute_stage_output,
|
||||
retire_interface_per_insn,
|
||||
} = self;
|
||||
#[hdl(sim)]
|
||||
Self {
|
||||
rename_dispatch_execute_stage_output: rename_dispatch_execute_stage_output
|
||||
.sim_value_default(),
|
||||
retire_interface_per_insn: retire_interface_per_insn.sim_value_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct RetireStageState<C: PhantomConstGet<CpuConfig>> {
|
||||
config: C,
|
||||
|
|
@ -2048,6 +2109,9 @@ impl<T: Type, Capacity: Size> Queue<T, Capacity> {
|
|||
let capacity = this.ty().capacity();
|
||||
(*this.tail + capacity - *this.head) % capacity
|
||||
}
|
||||
fn space_left(this: &SimValue<Self>) -> usize {
|
||||
this.ty().capacity() - Self::len(this)
|
||||
}
|
||||
fn clear(this: &mut SimValue<Self>) {
|
||||
*this.head = 0;
|
||||
*this.tail = 0;
|
||||
|
|
@ -2075,6 +2139,13 @@ impl<T: Type, Capacity: Size> Queue<T, Capacity> {
|
|||
Some(data)
|
||||
}
|
||||
}
|
||||
fn peek(this: &SimValue<Self>) -> Option<SimValue<T>> {
|
||||
if Self::is_empty(this) {
|
||||
None
|
||||
} else {
|
||||
Some(this.data[*this.tail].clone())
|
||||
}
|
||||
}
|
||||
fn pop(this: &mut SimValue<Self>) -> Option<SimValue<T>> {
|
||||
if Self::is_empty(this) {
|
||||
None
|
||||
|
|
@ -2140,101 +2211,456 @@ const BRANCH_PREDICTOR_LOG2_SIZE: usize = 8;
|
|||
const BRANCH_PREDICTOR_SIZE: usize = 1 << BRANCH_PREDICTOR_LOG2_SIZE;
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct NextPcState<C: PhantomConstGet<CpuConfig>> {
|
||||
struct CancelInProgress<C: PhantomConstGet<CpuConfig>> {
|
||||
cancel: Cancel<C>,
|
||||
br_pred_stage_inputs_to_cancel: UIntInRangeInclusive<0, 32>,
|
||||
br_pred_stage_cancel: Bool,
|
||||
fetch_decode_stage_inputs_to_cancel:
|
||||
UIntInRangeInclusiveType<ConstUsize<0>, CpuConfigMaxFetchesInFlight<C>>,
|
||||
fetch_decode_stage_cancel: Bool,
|
||||
post_decode_stage_inputs_to_cancel: UIntInRangeInclusive<0, 1>,
|
||||
post_decode_stage_cancel: Bool,
|
||||
post_decode_stage_outputs_to_cancel:
|
||||
UIntInRangeInclusiveType<ConstUsize<0>, TwiceCpuConfigFetchWidth<C>>,
|
||||
rename_dispatch_execute_stage_inputs_to_cancel: UIntInRangeInclusive<0, 256>,
|
||||
rename_dispatch_execute_stage_cancel: Bool,
|
||||
retire_stage_inputs_to_cancel: UIntInRangeInclusive<0, 1>,
|
||||
retire_stage_cancel: Bool,
|
||||
config: C,
|
||||
}
|
||||
|
||||
impl CancelInProgress<PhantomConst<CpuConfig>> {
|
||||
#[hdl]
|
||||
fn to_fetch_cancel_data(
|
||||
this: &SimValue<Self>,
|
||||
) -> SimValue<
|
||||
HdlOption<
|
||||
UIntInRangeInclusiveType<ConstUsize<1>, CpuConfigMaxFetchesInFlight<PhantomConst<CpuConfig>>>,
|
||||
>,
|
||||
> {
|
||||
let NextPcStateOutputs {
|
||||
to_fetch_cancel_data,
|
||||
..
|
||||
} = NextPcStateOutputs[this.config.ty()];
|
||||
if *this.fetch_decode_stage_inputs_to_cancel > 0 {
|
||||
#[hdl(sim)]
|
||||
to_fetch_cancel_data.HdlSome(*this.fetch_decode_stage_inputs_to_cancel)
|
||||
} else {
|
||||
#[hdl(sim)]
|
||||
to_fetch_cancel_data.HdlNone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct StatesAndQueues<C: PhantomConstGet<CpuConfig>> {
|
||||
next_pc_stage_state: NextPcStageState<C>,
|
||||
next_pc_stage_outputs: Queue<NextPcStageOutput<C>, ConstUsize<1>>,
|
||||
br_pred_stage_inputs: Queue<NextPcStageOutput<C>, ConstUsize<32>>,
|
||||
br_pred_stage_state: BrPredStageState<C>,
|
||||
br_pred_stage_outputs: Queue<BrPredStageOutput<C>, ConstUsize<32>>,
|
||||
fetch_decode_stage_inputs: Queue<NextPcStageOutput<C>, CpuConfigMaxFetchesInFlight<C>>,
|
||||
fetch_decode_stage_state: FetchDecodeStageState<C>,
|
||||
fetch_decode_stage_outputs: Queue<FetchDecodeStageOutput<C>, ConstUsize<32>>,
|
||||
post_decode_stage_inputs: Queue<PostDecodeStageInput<C>, ConstUsize<1>>,
|
||||
post_decode_stage_state: PostDecodeStageState<C>,
|
||||
post_decode_stage_outputs: Queue<PostDecodeStageOutput<C>, ConstUsize<1>>,
|
||||
post_decode_stage_outputs: Queue<PostDecodeStageOutput<C>, CpuConfigFetchWidth<C>>,
|
||||
rename_dispatch_execute_stage_inputs: Queue<PostDecodeStageOutput<C>, ConstUsize<256>>,
|
||||
rename_dispatch_execute_stage_state: RenameDispatchExecuteStageState<C>,
|
||||
rename_dispatch_execute_stage_outputs:
|
||||
Queue<RenameDispatchExecuteStageOutput<C>, ConstUsize<256>>,
|
||||
retire_stage_inputs: Queue<RetireStageInput<C>, ConstUsize<1>>,
|
||||
retire_stage_state: RetireStageState<C>,
|
||||
config: C,
|
||||
}
|
||||
|
||||
impl SimValueDefault for NextPcState<PhantomConst<CpuConfig>> {
|
||||
impl SimValueDefault for StatesAndQueues<PhantomConst<CpuConfig>> {
|
||||
#[hdl]
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
let Self {
|
||||
next_pc_stage_state,
|
||||
next_pc_stage_outputs,
|
||||
br_pred_stage_inputs,
|
||||
br_pred_stage_state,
|
||||
br_pred_stage_outputs,
|
||||
fetch_decode_stage_inputs,
|
||||
fetch_decode_stage_state,
|
||||
fetch_decode_stage_outputs,
|
||||
post_decode_stage_inputs,
|
||||
post_decode_stage_state,
|
||||
post_decode_stage_outputs,
|
||||
rename_dispatch_execute_stage_inputs,
|
||||
rename_dispatch_execute_stage_state,
|
||||
rename_dispatch_execute_stage_outputs,
|
||||
retire_stage_inputs,
|
||||
retire_stage_state,
|
||||
config,
|
||||
} = self;
|
||||
#[hdl(sim)]
|
||||
Self {
|
||||
next_pc_stage_state: next_pc_stage_state.sim_value_default(),
|
||||
next_pc_stage_outputs: next_pc_stage_outputs.sim_value_default(),
|
||||
br_pred_stage_inputs: br_pred_stage_inputs.sim_value_default(),
|
||||
br_pred_stage_state: br_pred_stage_state.sim_value_default(),
|
||||
br_pred_stage_outputs: br_pred_stage_outputs.sim_value_default(),
|
||||
fetch_decode_stage_inputs: fetch_decode_stage_inputs.sim_value_default(),
|
||||
fetch_decode_stage_state: fetch_decode_stage_state.sim_value_default(),
|
||||
fetch_decode_stage_outputs: fetch_decode_stage_outputs.sim_value_default(),
|
||||
post_decode_stage_inputs: post_decode_stage_inputs.sim_value_default(),
|
||||
post_decode_stage_state: post_decode_stage_state.sim_value_default(),
|
||||
post_decode_stage_outputs: post_decode_stage_outputs.sim_value_default(),
|
||||
rename_dispatch_execute_stage_inputs: rename_dispatch_execute_stage_inputs
|
||||
.sim_value_default(),
|
||||
rename_dispatch_execute_stage_state: rename_dispatch_execute_stage_state
|
||||
.sim_value_default(),
|
||||
rename_dispatch_execute_stage_outputs: rename_dispatch_execute_stage_outputs
|
||||
.sim_value_default(),
|
||||
retire_stage_inputs: retire_stage_inputs.sim_value_default(),
|
||||
retire_stage_state: retire_stage_state.sim_value_default(),
|
||||
config,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResetSteps for StatesAndQueues<PhantomConst<CpuConfig>> {
|
||||
#[hdl]
|
||||
fn reset_step(this: &mut SimValue<Self>, step: usize) -> ResetStatus {
|
||||
#[hdl(sim)]
|
||||
let Self {
|
||||
next_pc_stage_state,
|
||||
br_pred_stage_inputs,
|
||||
br_pred_stage_state,
|
||||
fetch_decode_stage_inputs,
|
||||
fetch_decode_stage_state,
|
||||
post_decode_stage_inputs,
|
||||
post_decode_stage_state,
|
||||
post_decode_stage_outputs,
|
||||
rename_dispatch_execute_stage_inputs,
|
||||
rename_dispatch_execute_stage_state,
|
||||
retire_stage_inputs,
|
||||
retire_stage_state,
|
||||
config: _,
|
||||
} = this;
|
||||
let next_pc_stage_state = ResetSteps::reset_step(next_pc_stage_state, step);
|
||||
let br_pred_stage_inputs = ResetSteps::reset_step(br_pred_stage_inputs, step);
|
||||
let br_pred_stage_state = ResetSteps::reset_step(br_pred_stage_state, step);
|
||||
let fetch_decode_stage_inputs = ResetSteps::reset_step(fetch_decode_stage_inputs, step);
|
||||
let fetch_decode_stage_state = ResetSteps::reset_step(fetch_decode_stage_state, step);
|
||||
let post_decode_stage_inputs = ResetSteps::reset_step(post_decode_stage_inputs, step);
|
||||
let post_decode_stage_state = ResetSteps::reset_step(post_decode_stage_state, step);
|
||||
let post_decode_stage_outputs = ResetSteps::reset_step(post_decode_stage_outputs, step);
|
||||
let rename_dispatch_execute_stage_inputs =
|
||||
ResetSteps::reset_step(rename_dispatch_execute_stage_inputs, step);
|
||||
let rename_dispatch_execute_stage_state =
|
||||
ResetSteps::reset_step(rename_dispatch_execute_stage_state, step);
|
||||
let retire_stage_inputs = ResetSteps::reset_step(retire_stage_inputs, step);
|
||||
let retire_stage_state = ResetSteps::reset_step(retire_stage_state, step);
|
||||
next_pc_stage_state
|
||||
.and(br_pred_stage_inputs)
|
||||
.and(br_pred_stage_state)
|
||||
.and(fetch_decode_stage_inputs)
|
||||
.and(fetch_decode_stage_state)
|
||||
.and(post_decode_stage_inputs)
|
||||
.and(post_decode_stage_state)
|
||||
.and(post_decode_stage_outputs)
|
||||
.and(rename_dispatch_execute_stage_inputs)
|
||||
.and(rename_dispatch_execute_stage_state)
|
||||
.and(retire_stage_inputs)
|
||||
.and(retire_stage_state)
|
||||
}
|
||||
}
|
||||
|
||||
impl StatesAndQueues<PhantomConst<CpuConfig>> {
|
||||
#[hdl]
|
||||
fn step_no_cancel(
|
||||
this: &mut SimValue<Self>,
|
||||
inputs: SimValue<NextPcStateStepInputs<PhantomConst<CpuConfig>>>,
|
||||
) -> SimValue<HdlOption<CancelInProgress<PhantomConst<CpuConfig>>>> {
|
||||
#[hdl(sim)]
|
||||
let NextPcStateStepInputs::<_> {
|
||||
to_fetch_fetch_triggered,
|
||||
to_fetch_cancel_triggered,
|
||||
from_decode_inner_triggered,
|
||||
post_decode_output_insns_triggered,
|
||||
from_retire_inner_triggered,
|
||||
} = inputs;
|
||||
assert!(!*to_fetch_cancel_triggered);
|
||||
#[hdl(sim)]
|
||||
let Self {
|
||||
next_pc_stage_state,
|
||||
br_pred_stage_inputs,
|
||||
br_pred_stage_state,
|
||||
fetch_decode_stage_inputs,
|
||||
fetch_decode_stage_state,
|
||||
post_decode_stage_inputs,
|
||||
post_decode_stage_state,
|
||||
post_decode_stage_outputs,
|
||||
rename_dispatch_execute_stage_inputs,
|
||||
rename_dispatch_execute_stage_state,
|
||||
retire_stage_inputs,
|
||||
retire_stage_state,
|
||||
config,
|
||||
} = this;
|
||||
let config = config.ty();
|
||||
let retval_ty = HdlOption[CancelInProgress[config]];
|
||||
let mut retval = #[hdl(sim)]
|
||||
retval_ty.HdlNone();
|
||||
if Queue::capacity(br_pred_stage_inputs) - Queue::len(br_pred_stage_inputs)
|
||||
#[hdl(sim)]
|
||||
let StageOutput::<_, _, _> { outputs, cancel } =
|
||||
Stage::run(next_pc_stage_state, &().to_sim_value());
|
||||
|
||||
retval
|
||||
}
|
||||
#[hdl]
|
||||
fn step_cancel(
|
||||
this: &mut SimValue<Self>,
|
||||
cancel_opt: &mut SimValue<HdlOption<CancelInProgress<PhantomConst<CpuConfig>>>>,
|
||||
inputs: SimValue<NextPcStateStepInputs<PhantomConst<CpuConfig>>>,
|
||||
) {
|
||||
#[hdl(sim)]
|
||||
let NextPcStateStepInputs::<_> {
|
||||
to_fetch_fetch_triggered,
|
||||
to_fetch_cancel_triggered,
|
||||
from_decode_inner_triggered,
|
||||
post_decode_output_insns_triggered,
|
||||
from_retire_inner_triggered,
|
||||
} = inputs;
|
||||
assert!(!*to_fetch_fetch_triggered);
|
||||
#[hdl(sim)]
|
||||
if let HdlSome(_) = from_decode_inner_triggered {
|
||||
unreachable!();
|
||||
}
|
||||
assert_eq!(**ArrayVec::len_sim(&post_decode_output_insns_triggered), 0);
|
||||
#[hdl(sim)]
|
||||
if let HdlSome(_) = from_retire_inner_triggered {
|
||||
unreachable!();
|
||||
}
|
||||
#[hdl(sim)]
|
||||
let Self {
|
||||
next_pc_stage_state,
|
||||
br_pred_stage_inputs,
|
||||
br_pred_stage_state,
|
||||
fetch_decode_stage_inputs,
|
||||
fetch_decode_stage_state,
|
||||
post_decode_stage_inputs,
|
||||
post_decode_stage_state,
|
||||
post_decode_stage_outputs,
|
||||
rename_dispatch_execute_stage_inputs,
|
||||
rename_dispatch_execute_stage_state,
|
||||
retire_stage_inputs,
|
||||
retire_stage_state,
|
||||
config: _,
|
||||
} = this;
|
||||
let cancel = #[hdl(sim)]
|
||||
match &mut *cancel_opt {
|
||||
HdlSome(cancel) => cancel,
|
||||
HdlNone => unreachable!(),
|
||||
};
|
||||
#[hdl(sim)]
|
||||
if let HdlSome(_) = CancelInProgress::to_fetch_cancel_data(cancel) {
|
||||
if !*to_fetch_cancel_triggered {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#[hdl(sim)]
|
||||
let CancelInProgress::<_> {
|
||||
cancel,
|
||||
br_pred_stage_inputs_to_cancel,
|
||||
br_pred_stage_cancel,
|
||||
fetch_decode_stage_inputs_to_cancel,
|
||||
fetch_decode_stage_cancel,
|
||||
post_decode_stage_inputs_to_cancel,
|
||||
post_decode_stage_cancel,
|
||||
post_decode_stage_outputs_to_cancel,
|
||||
rename_dispatch_execute_stage_inputs_to_cancel,
|
||||
rename_dispatch_execute_stage_cancel,
|
||||
retire_stage_inputs_to_cancel,
|
||||
retire_stage_cancel,
|
||||
config: _,
|
||||
} = cancel;
|
||||
Stage::cancel(next_pc_stage_state, cancel);
|
||||
for _ in 0..**br_pred_stage_inputs_to_cancel {
|
||||
Queue::undo_push(br_pred_stage_inputs).expect("known to be non-empty");
|
||||
}
|
||||
if **br_pred_stage_cancel {
|
||||
Stage::cancel(br_pred_stage_state, cancel);
|
||||
}
|
||||
for _ in 0..**fetch_decode_stage_inputs_to_cancel {
|
||||
Queue::undo_push(fetch_decode_stage_inputs).expect("known to be non-empty");
|
||||
}
|
||||
if **fetch_decode_stage_cancel {
|
||||
Stage::cancel(fetch_decode_stage_state, cancel);
|
||||
}
|
||||
for _ in 0..**post_decode_stage_inputs_to_cancel {
|
||||
Queue::undo_push(post_decode_stage_inputs).expect("known to be non-empty");
|
||||
}
|
||||
if **post_decode_stage_cancel {
|
||||
Stage::cancel(post_decode_stage_state, cancel);
|
||||
}
|
||||
for _ in 0..**post_decode_stage_outputs_to_cancel {
|
||||
Queue::undo_push(post_decode_stage_outputs).expect("known to be non-empty");
|
||||
}
|
||||
for _ in 0..**rename_dispatch_execute_stage_inputs_to_cancel {
|
||||
Queue::undo_push(rename_dispatch_execute_stage_inputs).expect("known to be non-empty");
|
||||
}
|
||||
if **rename_dispatch_execute_stage_cancel {
|
||||
Stage::cancel(rename_dispatch_execute_stage_state, cancel);
|
||||
}
|
||||
for _ in 0..**retire_stage_inputs_to_cancel {
|
||||
Queue::undo_push(retire_stage_inputs).expect("known to be non-empty");
|
||||
}
|
||||
if **retire_stage_cancel {
|
||||
Stage::cancel(retire_stage_state, cancel);
|
||||
}
|
||||
*cancel_opt = #[hdl(sim)]
|
||||
(cancel_opt.ty()).HdlNone();
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct NextPcState<C: PhantomConstGet<CpuConfig>> {
|
||||
states_and_queues: StatesAndQueues<C>,
|
||||
cancel: HdlOption<CancelInProgress<C>>,
|
||||
}
|
||||
|
||||
impl SimValueDefault for NextPcState<PhantomConst<CpuConfig>> {
|
||||
#[hdl]
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
let Self {
|
||||
states_and_queues,
|
||||
cancel,
|
||||
} = self;
|
||||
#[hdl(sim)]
|
||||
Self {
|
||||
states_and_queues: states_and_queues.sim_value_default(),
|
||||
cancel: cancel.sim_value_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResetSteps for NextPcState<PhantomConst<CpuConfig>> {
|
||||
#[hdl]
|
||||
fn reset_step(this: &mut SimValue<Self>, step: usize) -> ResetStatus {
|
||||
#[hdl(sim)]
|
||||
let NextPcState::<_> {
|
||||
next_pc_stage_state,
|
||||
next_pc_stage_outputs,
|
||||
br_pred_stage_state,
|
||||
br_pred_stage_outputs,
|
||||
fetch_decode_stage_state,
|
||||
fetch_decode_stage_outputs,
|
||||
post_decode_stage_state,
|
||||
post_decode_stage_outputs,
|
||||
rename_dispatch_execute_stage_state,
|
||||
rename_dispatch_execute_stage_outputs,
|
||||
retire_stage_state,
|
||||
config: _,
|
||||
let Self {
|
||||
states_and_queues,
|
||||
cancel,
|
||||
} = this;
|
||||
let next_pc_stage_state = ResetSteps::reset_step(next_pc_stage_state, step);
|
||||
let next_pc_stage_outputs = ResetSteps::reset_step(next_pc_stage_outputs, step);
|
||||
let br_pred_stage_state = ResetSteps::reset_step(br_pred_stage_state, step);
|
||||
let br_pred_stage_outputs = ResetSteps::reset_step(br_pred_stage_outputs, step);
|
||||
let fetch_decode_stage_state = ResetSteps::reset_step(fetch_decode_stage_state, step);
|
||||
let fetch_decode_stage_outputs = ResetSteps::reset_step(fetch_decode_stage_outputs, step);
|
||||
let post_decode_stage_state = ResetSteps::reset_step(post_decode_stage_state, step);
|
||||
let post_decode_stage_outputs = ResetSteps::reset_step(post_decode_stage_outputs, step);
|
||||
let rename_dispatch_execute_stage_state =
|
||||
ResetSteps::reset_step(rename_dispatch_execute_stage_state, step);
|
||||
let rename_dispatch_execute_stage_outputs =
|
||||
ResetSteps::reset_step(rename_dispatch_execute_stage_outputs, step);
|
||||
let retire_stage_state = ResetSteps::reset_step(retire_stage_state, step);
|
||||
next_pc_stage_state
|
||||
.and(next_pc_stage_outputs)
|
||||
.and(br_pred_stage_state)
|
||||
.and(br_pred_stage_outputs)
|
||||
.and(fetch_decode_stage_state)
|
||||
.and(fetch_decode_stage_outputs)
|
||||
.and(post_decode_stage_state)
|
||||
.and(post_decode_stage_outputs)
|
||||
.and(rename_dispatch_execute_stage_state)
|
||||
.and(rename_dispatch_execute_stage_outputs)
|
||||
.and(retire_stage_state)
|
||||
*cancel = #[hdl(sim)]
|
||||
(cancel.ty()).HdlNone();
|
||||
ResetSteps::reset_step(states_and_queues, step)
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct NextPcStateOutputs<C: PhantomConstGet<CpuConfig>> {
|
||||
to_fetch_fetch_data: HdlOption<NextPcToFetchInterfaceInner>,
|
||||
to_fetch_cancel_data:
|
||||
HdlOption<UIntInRangeInclusiveType<ConstUsize<1>, CpuConfigMaxFetchesInFlight<C>>>,
|
||||
from_decode_inner_ready: Bool,
|
||||
post_decode_output_insns: ArrayVec<WipDecodedInsn, CpuConfigFetchWidth<C>>,
|
||||
from_retire_inner_ready: Bool,
|
||||
config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct NextPcStateStepInputs<C: PhantomConstGet<CpuConfig>> {
|
||||
to_fetch_fetch_triggered: Bool,
|
||||
to_fetch_cancel_triggered: Bool,
|
||||
from_decode_inner_triggered: HdlOption<DecodeToPostDecodeInterfaceInner<C>>,
|
||||
post_decode_output_insns_triggered: ArrayVec<WipDecodedInsn, CpuConfigFetchWidth<C>>,
|
||||
from_retire_inner_triggered: HdlOption<RetireToNextPcInterfaceInner<C>>,
|
||||
}
|
||||
|
||||
impl NextPcState<PhantomConst<CpuConfig>> {
|
||||
#[hdl]
|
||||
fn outputs(this: &SimValue<Self>) -> SimValue<NextPcStateOutputs<PhantomConst<CpuConfig>>> {
|
||||
#[hdl(sim)]
|
||||
let Self {
|
||||
states_and_queues,
|
||||
cancel,
|
||||
} = this;
|
||||
#[hdl(sim)]
|
||||
let StatesAndQueues::<_> {
|
||||
next_pc_stage_state: _,
|
||||
br_pred_stage_inputs: _,
|
||||
br_pred_stage_state: _,
|
||||
fetch_decode_stage_inputs,
|
||||
fetch_decode_stage_state: _,
|
||||
post_decode_stage_inputs,
|
||||
post_decode_stage_state: _,
|
||||
post_decode_stage_outputs,
|
||||
rename_dispatch_execute_stage_inputs: _,
|
||||
rename_dispatch_execute_stage_state: _,
|
||||
retire_stage_inputs,
|
||||
retire_stage_state: _,
|
||||
config,
|
||||
} = states_and_queues;
|
||||
let config = config.ty();
|
||||
let NextPcStateOutputs {
|
||||
to_fetch_fetch_data: _,
|
||||
to_fetch_cancel_data: to_fetch_cancel_data_ty,
|
||||
from_decode_inner_ready: _,
|
||||
post_decode_output_insns: post_decode_output_insns_ty,
|
||||
from_retire_inner_ready: _,
|
||||
config: _,
|
||||
} = NextPcStateOutputs[config];
|
||||
#[hdl(sim)]
|
||||
if let HdlSome(cancel) = cancel {
|
||||
#[hdl(sim)]
|
||||
NextPcStateOutputs::<_> {
|
||||
to_fetch_fetch_data: #[hdl(sim)]
|
||||
HdlNone(),
|
||||
to_fetch_cancel_data: CancelInProgress::to_fetch_cancel_data(cancel),
|
||||
from_decode_inner_ready: false,
|
||||
post_decode_output_insns: post_decode_output_insns_ty.sim_value_default(),
|
||||
from_retire_inner_ready: false,
|
||||
config,
|
||||
}
|
||||
} else {
|
||||
let to_fetch_fetch_data = if let Some(data) = Queue::peek(fetch_decode_stage_inputs) {
|
||||
#[hdl(sim)]
|
||||
HdlSome(
|
||||
#[hdl(sim)]
|
||||
NextPcToFetchInterfaceInner {
|
||||
start_pc: data.start_pc,
|
||||
fetch_block_id: data.fetch_block_id,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
#[hdl(sim)]
|
||||
HdlNone()
|
||||
};
|
||||
let mut post_decode_output_insns =
|
||||
post_decode_output_insns_ty.new_sim(WipDecodedInsn.sim_value_default());
|
||||
let mut post_decode_stage_outputs = post_decode_stage_outputs.clone();
|
||||
while let Some(post_decode_stage_output) = Queue::pop(&mut post_decode_stage_outputs) {
|
||||
#[hdl(sim)]
|
||||
let PostDecodeStageOutput::<_> {
|
||||
insn,
|
||||
next_pc: _,
|
||||
btb_entry_index: _,
|
||||
start_branch_history: _,
|
||||
start_call_stack: _,
|
||||
branch_predictor_index: _,
|
||||
config: _,
|
||||
} = post_decode_stage_output;
|
||||
ArrayVec::try_push_sim(&mut post_decode_output_insns, insn).expect("known to fit");
|
||||
}
|
||||
#[hdl(sim)]
|
||||
NextPcStateOutputs::<_> {
|
||||
to_fetch_fetch_data,
|
||||
to_fetch_cancel_data: to_fetch_cancel_data_ty.HdlNone(),
|
||||
from_decode_inner_ready: !Queue::is_full(post_decode_stage_inputs),
|
||||
post_decode_output_insns,
|
||||
from_retire_inner_ready: !Queue::is_full(retire_stage_inputs),
|
||||
config,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
fn step(
|
||||
this: &mut SimValue<Self>,
|
||||
inputs: SimValue<NextPcStateStepInputs<PhantomConst<CpuConfig>>>,
|
||||
) {
|
||||
#[hdl(sim)]
|
||||
let Self {
|
||||
states_and_queues,
|
||||
cancel,
|
||||
} = this;
|
||||
#[hdl(sim)]
|
||||
if let HdlSome(_) = &cancel {
|
||||
StatesAndQueues::step_cancel(states_and_queues, cancel, inputs);
|
||||
} else {
|
||||
*cancel = StatesAndQueues::step_no_cancel(states_and_queues, inputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2279,10 +2705,71 @@ pub fn next_pc(config: PhantomConst<CpuConfig>) {
|
|||
}
|
||||
}
|
||||
loop {
|
||||
todo!();
|
||||
#[hdl(sim)]
|
||||
let NextPcStateOutputs::<_> {
|
||||
to_fetch_fetch_data,
|
||||
to_fetch_cancel_data,
|
||||
from_decode_inner_ready,
|
||||
post_decode_output_insns,
|
||||
from_retire_inner_ready,
|
||||
config: _,
|
||||
} = NextPcState::outputs(&state);
|
||||
sim.write(to_fetch.fetch.data, to_fetch_fetch_data).await;
|
||||
sim.write(to_fetch.cancel.data, to_fetch_cancel_data).await;
|
||||
sim.write(from_decode.inner.ready, from_decode_inner_ready)
|
||||
.await;
|
||||
sim.write(post_decode_output.insns, post_decode_output_insns)
|
||||
.await;
|
||||
sim.write(from_retire.inner.ready, from_retire_inner_ready)
|
||||
.await;
|
||||
sim.write(state_expr, state).await;
|
||||
sim.wait_for_clock_edge(cd.clk).await;
|
||||
state = sim.read_past(state_expr, cd.clk).await;
|
||||
let to_fetch_fetch_triggered =
|
||||
#[hdl(sim)]
|
||||
if let HdlSome(_) = sim.read_past(to_fetch.fetch.data, cd.clk).await {
|
||||
*sim.read_past(to_fetch.fetch.ready, cd.clk).await
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let to_fetch_cancel_triggered =
|
||||
#[hdl(sim)]
|
||||
if let HdlSome(_) = sim.read_past(to_fetch.cancel.data, cd.clk).await {
|
||||
*sim.read_past(to_fetch.cancel.ready, cd.clk).await
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let from_decode_inner_triggered =
|
||||
if *sim.read_past(from_decode.inner.ready, cd.clk).await {
|
||||
sim.read_past(from_decode.inner.data, cd.clk).await
|
||||
} else {
|
||||
#[hdl(sim)]
|
||||
(from_decode.ty().inner.data).HdlNone()
|
||||
};
|
||||
let mut post_decode_output_insns_triggered =
|
||||
sim.read_past(post_decode_output.insns, cd.clk).await;
|
||||
ArrayVec::truncate_sim(
|
||||
&mut post_decode_output_insns_triggered,
|
||||
*sim.read_past(post_decode_output.ready, cd.clk).await,
|
||||
);
|
||||
let from_retire_inner_triggered =
|
||||
if *sim.read_past(from_retire.inner.ready, cd.clk).await {
|
||||
sim.read_past(from_retire.inner.data, cd.clk).await
|
||||
} else {
|
||||
#[hdl(sim)]
|
||||
(from_retire.ty().inner.data).HdlNone()
|
||||
};
|
||||
NextPcState::step(
|
||||
&mut state,
|
||||
#[hdl(sim)]
|
||||
NextPcStateStepInputs::<_> {
|
||||
to_fetch_fetch_triggered,
|
||||
to_fetch_cancel_triggered,
|
||||
from_decode_inner_triggered,
|
||||
post_decode_output_insns_triggered,
|
||||
from_retire_inner_triggered,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
m.extern_module_simulation_fn(
|
||||
|
|
@ -2302,8 +2789,19 @@ pub fn next_pc(config: PhantomConst<CpuConfig>) {
|
|||
sim.resettable(
|
||||
cd,
|
||||
|mut sim: ExternModuleSimulationState| async move {
|
||||
sim.write(to_fetch.inner.data, HdlNone()).await;
|
||||
sim.write(to_fetch.fetch.data, HdlNone()).await;
|
||||
sim.write(to_fetch.cancel.data, to_fetch.ty().cancel.data.HdlNone())
|
||||
.await;
|
||||
sim.write(from_decode.inner.ready, false).await;
|
||||
sim.write(
|
||||
post_decode_output.insns,
|
||||
post_decode_output
|
||||
.ty()
|
||||
.insns
|
||||
.new_sim(SimValueDefault::sim_value_default(StaticType::TYPE)),
|
||||
)
|
||||
.await;
|
||||
sim.write(from_retire.inner.ready, false).await;
|
||||
},
|
||||
|sim, ()| {
|
||||
run(
|
||||
|
|
|
|||
|
|
@ -165,6 +165,9 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
|||
Err(value)
|
||||
}
|
||||
}
|
||||
pub fn truncate_sim(this: &mut SimValue<Self>, len: usize) {
|
||||
*this.len = len.min(*this.len);
|
||||
}
|
||||
pub fn mapped_ty<U: Type>(self, new_element_ty: U) -> ArrayVec<U, N> {
|
||||
ArrayVec {
|
||||
elements: ArrayType[new_element_ty][N::from_usize(self.elements.len())],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue