WIP linking next_pc stages together

This commit is contained in:
Jacob Lifshay 2025-12-09 22:36:48 -08:00
parent e3ebbe6b40
commit 1d8adba04c
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
3 changed files with 584 additions and 69 deletions

View file

@ -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;

View file

@ -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(

View file

@ -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())],