From 1d8adba04cb0eb25a4700835fab9e82e57808636 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 9 Dec 2025 22:36:48 -0800 Subject: [PATCH] WIP linking next_pc stages together --- crates/cpu/src/config.rs | 14 + crates/cpu/src/next_pc.rs | 636 +++++++++++++++++++++++++++---- crates/cpu/src/util/array_vec.rs | 3 + 3 files changed, 584 insertions(+), 69 deletions(-) diff --git a/crates/cpu/src/config.rs b/crates/cpu/src/config.rs index b3d9905..acbec47 100644 --- a/crates/cpu/src/config.rs +++ b/crates/cpu/src/config.rs @@ -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> = DynSize; +#[hdl(get(|c| c.fetch_width.get() * 2))] +pub type TwiceCpuConfigFetchWidth> = DynSize; + #[hdl(get(|c| c.max_branches_per_fetch.get()))] pub type CpuConfigMaxBranchesPerFetch> = DynSize; +#[hdl(get(|c| c.max_fetches_in_flight.get()))] +pub type CpuConfigMaxFetchesInFlight> = DynSize; + #[hdl(get(|c| c.log2_fetch_width_in_bytes.into()))] pub type CpuConfigLog2FetchWidthInBytes> = DynSize; diff --git a/crates/cpu/src/next_pc.rs b/crates/cpu/src/next_pc.rs index f87ba35..97d2f33 100644 --- a/crates/cpu/src/next_pc.rs +++ b/crates/cpu/src/next_pc.rs @@ -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> { - pub inner: ReadyValid, + pub fetch: ReadyValid, + pub cancel: ReadyValid, CpuConfigMaxFetchesInFlight>>, pub config: C, } @@ -111,6 +112,29 @@ pub struct RetireToNextPcInterfacePerInsn> { pub config: C, } +impl SimValueDefault for RetireToNextPcInterfacePerInsn> { + #[hdl] + fn sim_value_default(self) -> SimValue { + 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> { pub insns: ArrayVec, CpuConfigFetchWidth>, @@ -151,7 +175,9 @@ pub struct DecodeToPostDecodeInterface> { #[hdl(no_static)] pub struct PostDecodeOutputInterface> { - // TODO: add needed fields + pub insns: ArrayVec>, + #[hdl(flip)] + pub ready: UIntInRangeInclusiveType, CpuConfigFetchWidth>, pub config: C, } @@ -171,12 +197,13 @@ struct Cancel> { 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> { outputs: ArrayVec, + /// when set to [`HdlSome`], [`Stage::cancel`] is called on all previous stages cancel: HdlOption>, } @@ -194,6 +221,7 @@ trait Stage: Type + SimValueDefault + ResetSteps { ) -> StageOutput> { StageOutput[Self::output_ty(config)][Self::max_output_count(config)][config] } + /// see [`StageOutput`] for docs on output fn run( state: &mut SimValue, inputs: &SimValue, @@ -780,6 +808,23 @@ struct PostDecodeStageState> { config: C, } +#[hdl(no_static)] +struct PostDecodeStageInput> { + fetch_decode_stage_output: FetchDecodeStageOutput, + br_pred_stage_output: BrPredStageOutput, +} + +impl SimValueDefault for PostDecodeStageInput> { + #[hdl] + fn sim_value_default(self) -> SimValue { + #[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> { insn: WipDecodedInsn, @@ -829,10 +874,7 @@ impl ResetSteps for PostDecodeStageState> { } impl Stage for PostDecodeStageState> { - type Inputs = ( - FetchDecodeStageOutput>, - BrPredStageOutput>, - ); + type Inputs = PostDecodeStageInput>; type Output = PostDecodeStageOutput>; type MaxOutputCount = CpuConfigFetchWidth>; @@ -855,7 +897,10 @@ impl Stage for PostDecodeStageState> { 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> { retire_interface_per_insn: RetireToNextPcInterfacePerInsn, } +impl SimValueDefault for RetireStageInput> { + #[hdl] + fn sim_value_default(self) -> SimValue { + 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> { config: C, @@ -2048,6 +2109,9 @@ impl Queue { let capacity = this.ty().capacity(); (*this.tail + capacity - *this.head) % capacity } + fn space_left(this: &SimValue) -> usize { + this.ty().capacity() - Self::len(this) + } fn clear(this: &mut SimValue) { *this.head = 0; *this.tail = 0; @@ -2075,6 +2139,13 @@ impl Queue { Some(data) } } + fn peek(this: &SimValue) -> Option> { + if Self::is_empty(this) { + None + } else { + Some(this.data[*this.tail].clone()) + } + } fn pop(this: &mut SimValue) -> Option> { 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> { +struct CancelInProgress> { + cancel: Cancel, + br_pred_stage_inputs_to_cancel: UIntInRangeInclusive<0, 32>, + br_pred_stage_cancel: Bool, + fetch_decode_stage_inputs_to_cancel: + UIntInRangeInclusiveType, CpuConfigMaxFetchesInFlight>, + 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, TwiceCpuConfigFetchWidth>, + 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> { + #[hdl] + fn to_fetch_cancel_data( + this: &SimValue, + ) -> SimValue< + HdlOption< + UIntInRangeInclusiveType, CpuConfigMaxFetchesInFlight>>, + >, + > { + 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> { next_pc_stage_state: NextPcStageState, - next_pc_stage_outputs: Queue, ConstUsize<1>>, + br_pred_stage_inputs: Queue, ConstUsize<32>>, br_pred_stage_state: BrPredStageState, - br_pred_stage_outputs: Queue, ConstUsize<32>>, + fetch_decode_stage_inputs: Queue, CpuConfigMaxFetchesInFlight>, fetch_decode_stage_state: FetchDecodeStageState, - fetch_decode_stage_outputs: Queue, ConstUsize<32>>, + post_decode_stage_inputs: Queue, ConstUsize<1>>, post_decode_stage_state: PostDecodeStageState, - post_decode_stage_outputs: Queue, ConstUsize<1>>, + post_decode_stage_outputs: Queue, CpuConfigFetchWidth>, + rename_dispatch_execute_stage_inputs: Queue, ConstUsize<256>>, rename_dispatch_execute_stage_state: RenameDispatchExecuteStageState, - rename_dispatch_execute_stage_outputs: - Queue, ConstUsize<256>>, + retire_stage_inputs: Queue, ConstUsize<1>>, retire_stage_state: RetireStageState, config: C, } -impl SimValueDefault for NextPcState> { +impl SimValueDefault for StatesAndQueues> { #[hdl] fn sim_value_default(self) -> SimValue { 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> { + #[hdl] + fn reset_step(this: &mut SimValue, 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> { + #[hdl] + fn step_no_cancel( + this: &mut SimValue, + inputs: SimValue>>, + ) -> SimValue>>> { + #[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, + cancel_opt: &mut SimValue>>>, + inputs: SimValue>>, + ) { + #[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> { + states_and_queues: StatesAndQueues, + cancel: HdlOption>, +} + +impl SimValueDefault for NextPcState> { + #[hdl] + fn sim_value_default(self) -> SimValue { + 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> { #[hdl] fn reset_step(this: &mut SimValue, 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> { + to_fetch_fetch_data: HdlOption, + to_fetch_cancel_data: + HdlOption, CpuConfigMaxFetchesInFlight>>, + from_decode_inner_ready: Bool, + post_decode_output_insns: ArrayVec>, + from_retire_inner_ready: Bool, + config: C, +} + +#[hdl(no_static)] +struct NextPcStateStepInputs> { + to_fetch_fetch_triggered: Bool, + to_fetch_cancel_triggered: Bool, + from_decode_inner_triggered: HdlOption>, + post_decode_output_insns_triggered: ArrayVec>, + from_retire_inner_triggered: HdlOption>, +} + +impl NextPcState> { + #[hdl] + fn outputs(this: &SimValue) -> SimValue>> { + #[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, + inputs: SimValue>>, + ) { + #[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) { } } 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) { 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( diff --git a/crates/cpu/src/util/array_vec.rs b/crates/cpu/src/util/array_vec.rs index b28b029..0f6fc6f 100644 --- a/crates/cpu/src/util/array_vec.rs +++ b/crates/cpu/src/util/array_vec.rs @@ -165,6 +165,9 @@ impl ArrayVec { Err(value) } } + pub fn truncate_sim(this: &mut SimValue, len: usize) { + *this.len = len.min(*this.len); + } pub fn mapped_ty(self, new_element_ty: U) -> ArrayVec { ArrayVec { elements: ArrayType[new_element_ty][N::from_usize(self.elements.len())],