diff --git a/crates/cpu/src/config.rs b/crates/cpu/src/config.rs index b3d9905..a7dd7d9 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,11 +146,20 @@ 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; #[hdl(get(|c| c.fetch_width_in_bytes()))] pub type CpuConfigFetchWidthInBytes> = DynSize; + +#[hdl(get(|c| c.rob_size.get()))] +pub type CpuConfigRobSize> = DynSize; diff --git a/crates/cpu/src/next_pc.rs b/crates/cpu/src/next_pc.rs index f87ba35..45c3db5 100644 --- a/crates/cpu/src/next_pc.rs +++ b/crates/cpu/src/next_pc.rs @@ -12,14 +12,18 @@ #![doc = simple_mermaid::mermaid!("next_pc/next_pc.mermaid")] use crate::{ - config::{CpuConfig, CpuConfigFetchWidth}, + config::{ + CpuConfig, CpuConfigFetchWidth, CpuConfigMaxFetchesInFlight, CpuConfigRobSize, + TwiceCpuConfigFetchWidth, + }, 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 +33,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 +115,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,10 +178,15 @@ 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, } +const BRANCH_PREDICTOR_LOG2_SIZE: usize = 8; +const BRANCH_PREDICTOR_SIZE: usize = 1 << BRANCH_PREDICTOR_LOG2_SIZE; + #[hdl] struct TrainBranchPredictor { branch_predictor_index: UIntInRange<0, { BRANCH_PREDICTOR_SIZE }>, @@ -171,37 +203,151 @@ 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>, } trait Stage: Type + SimValueDefault + ResetSteps { + type Input: Type; type Inputs: Type; type Output: Type; - type MaxOutputCount: Size; + type MaxOutputsPerStep: Size; + type InputQueueSize: Size; + type OutputQueueSize: Size; + fn input_ty(config: PhantomConst) -> Self::Input; + fn inputs_ty(config: PhantomConst) -> Self::Inputs; fn output_ty(config: PhantomConst) -> Self::Output; - fn max_output_count( + fn max_outputs_per_step( config: PhantomConst, - ) -> ::SizeType; + ) -> ::SizeType; + fn input_queue_size( + config: PhantomConst, + ) -> ::SizeType; + fn output_queue_size( + config: PhantomConst, + ) -> ::SizeType; fn stage_output_ty( config: PhantomConst, - ) -> StageOutput> { - StageOutput[Self::output_ty(config)][Self::max_output_count(config)][config] + ) -> StageOutput> { + StageOutput[Self::output_ty(config)][Self::max_outputs_per_step(config)][config] } + /// see [`StageOutput`] for docs on output fn run( state: &mut SimValue, inputs: &SimValue, - ) -> SimValue>>; + ) -> SimValue>>; /// changes state to match `cancel` fn cancel(state: &mut SimValue, cancel: &SimValue>>); } +macro_rules! hdl_type_alias_with_generics { + ( + #[without_generics = $WithoutGenerics:ident, $OneGeneric:ident] + #[ty = $ty:expr] + $vis:vis type $Type:ident<$Arg:ident: $Trait:ident, $C:ident: PhantomConstGet> = $Target:ty; + ) => { + $vis type $Type<$Arg, $C> = <$Target as fayalite::phantom_const::ReturnSelfUnchanged<$C>>::Type; + + $vis struct $WithoutGenerics {} + + #[allow(non_upper_case_globals)] + $vis const $Type: $WithoutGenerics = $WithoutGenerics {}; + + #[derive(Clone, PartialEq, Eq, Hash, Debug)] + $vis struct $OneGeneric<$Arg: $Trait>($Arg); + + impl<$Arg: $Trait> std::ops::Index<$Arg> for $WithoutGenerics { + type Output = $OneGeneric<$Arg>; + + fn index(&self, arg: $Arg) -> &Self::Output { + fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($OneGeneric(arg))) + } + } + + impl<$Arg: $Trait, $C: PhantomConstGet> std::ops::Index<$C> for $OneGeneric<$Arg> { + type Output = $Type<$Arg, $C>; + + fn index(&self, config: $C) -> &Self::Output { + fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($ty(self.0, config))) + } + } + }; + ( + #[without_generics = $WithoutGenerics:ident, $OneGeneric:ident] + #[size = $size:expr] + $vis:vis type $Type:ident<$Arg:ident: $Trait:ident, $C:ident: PhantomConstGet> = $Target:ty; + ) => { + $vis type $Type<$Arg, $C> = <$Target as fayalite::phantom_const::ReturnSelfUnchanged<$C>>::Type; + + $vis struct $WithoutGenerics {} + + #[allow(non_upper_case_globals)] + $vis const $Type: $WithoutGenerics = $WithoutGenerics {}; + + #[derive(Clone, PartialEq, Eq, Hash, Debug)] + $vis struct $OneGeneric<$Arg: $Trait>($Arg); + + impl<$Arg: $Trait> std::ops::Index<$Arg> for $WithoutGenerics { + type Output = $OneGeneric<$Arg>; + + fn index(&self, arg: $Arg) -> &Self::Output { + fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($OneGeneric(arg))) + } + } + + impl<$Arg: $Trait, $C: PhantomConstGet> std::ops::Index<$C> for $OneGeneric<$Arg> { + type Output = <$Type<$Arg, $C> as Size>::SizeType; + + fn index(&self, config: $C) -> &Self::Output { + fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($size(self.0, config))) + } + } + }; +} + +hdl_type_alias_with_generics! { + #[without_generics = StageTraitInputWithoutGenerics, StageTraitInputWithStage] + #[ty = |_stage, config: C| T::input_ty(PhantomConst::new_interned(config.get()))] + type StageTraitInput> = ::Input; +} + +hdl_type_alias_with_generics! { + #[without_generics = StageTraitInputsWithoutGenerics, StageTraitInputsWithStage] + #[ty = |_stage, config: C| T::inputs_ty(PhantomConst::new_interned(config.get()))] + type StageTraitInputs> = ::Inputs; +} + +hdl_type_alias_with_generics! { + #[without_generics = StageTraitOutputWithoutGenerics, StageTraitOutputWithStage] + #[ty = |_stage, config: C| T::output_ty(PhantomConst::new_interned(config.get()))] + type StageTraitOutput> = ::Output; +} + +hdl_type_alias_with_generics! { + #[without_generics = StageMaxOutputsPerStepWithoutGenerics, StageMaxOutputsPerStepWithStage] + #[size = |_stage, config: C| T::max_outputs_per_step(PhantomConst::new_interned(config.get()))] + type StageMaxOutputsPerStep> = ::MaxOutputsPerStep; +} + +hdl_type_alias_with_generics! { + #[without_generics = StageInputQueueSizeWithoutGenerics, StageInputQueueSizeWithStage] + #[size = |_stage, config: C| T::input_queue_size(PhantomConst::new_interned(config.get()))] + type StageInputQueueSize> = ::InputQueueSize; +} + +hdl_type_alias_with_generics! { + #[without_generics = StageOutputQueueSizeWithoutGenerics, StageOutputQueueSizeWithStage] + #[size = |_stage, config: C| T::output_queue_size(PhantomConst::new_interned(config.get()))] + type StageOutputQueueSize> = ::OutputQueueSize; +} + #[hdl(no_static)] struct NextPcStageOutput> { start_pc: UInt<64>, @@ -291,17 +437,40 @@ impl ResetSteps for NextPcStageState> { } impl Stage for NextPcStageState> { + type Input = (); type Inputs = (); type Output = NextPcStageOutput>; - type MaxOutputCount = ConstUsize<1>; + type MaxOutputsPerStep = ConstUsize<1>; + type InputQueueSize = ConstUsize<1>; + type OutputQueueSize = ConstUsize<1>; + + fn input_ty(_config: PhantomConst) -> Self::Input { + () + } + + fn inputs_ty(_config: PhantomConst) -> Self::Inputs { + () + } fn output_ty(config: PhantomConst) -> Self::Output { NextPcStageOutput[config] } - fn max_output_count( + fn max_outputs_per_step( _config: PhantomConst, - ) -> ::SizeType { + ) -> ::SizeType { + ConstUsize + } + + fn input_queue_size( + _config: PhantomConst, + ) -> ::SizeType { + ConstUsize + } + + fn output_queue_size( + _config: PhantomConst, + ) -> ::SizeType { ConstUsize } @@ -309,7 +478,7 @@ impl Stage for NextPcStageState> { fn run( state: &mut SimValue, _inputs: &SimValue, - ) -> SimValue>> { + ) -> SimValue>> { let config = state.config.ty(); let start_call_stack = state.call_stack.clone(); let fetch_block_id = state.next_fetch_block_id.as_int(); @@ -551,25 +720,48 @@ impl ResetSteps for BrPredStageState> { } impl Stage for BrPredStageState> { + type Input = NextPcStageOutput>; type Inputs = NextPcStageOutput>; type Output = BrPredStageOutput>; - type MaxOutputCount = ConstUsize<1>; + type MaxOutputsPerStep = ConstUsize<1>; + type InputQueueSize = ConstUsize<1>; + type OutputQueueSize = CpuConfigMaxFetchesInFlight>; + + fn input_ty(config: PhantomConst) -> Self::Input { + NextPcStageOutput[config] + } + + fn inputs_ty(config: PhantomConst) -> Self::Inputs { + NextPcStageOutput[config] + } fn output_ty(config: PhantomConst) -> Self::Output { BrPredStageOutput[config] } - fn max_output_count( + fn max_outputs_per_step( _config: PhantomConst, - ) -> ::SizeType { + ) -> ::SizeType { ConstUsize } + fn input_queue_size( + _config: PhantomConst, + ) -> ::SizeType { + ConstUsize + } + + fn output_queue_size( + config: PhantomConst, + ) -> ::SizeType { + CpuConfigMaxFetchesInFlight[config] + } + #[hdl] fn run( state: &mut SimValue, inputs: &SimValue, - ) -> SimValue>> { + ) -> SimValue>> { let config = state.config.ty(); #[hdl(sim)] let NextPcStageOutput::<_> { @@ -737,17 +929,40 @@ impl SimValueDefault for FetchDecodeStageOutput> { } impl Stage for FetchDecodeStageState> { + type Input = NextPcStageOutput>; type Inputs = FetchDecodeStageOutput>; type Output = FetchDecodeStageOutput>; - type MaxOutputCount = ConstUsize<1>; + type MaxOutputsPerStep = ConstUsize<1>; + type InputQueueSize = CpuConfigMaxFetchesInFlight>; + type OutputQueueSize = ConstUsize<1>; + + fn input_ty(config: PhantomConst) -> Self::Input { + NextPcStageOutput[config] + } + + fn inputs_ty(config: PhantomConst) -> Self::Inputs { + FetchDecodeStageOutput[config] + } fn output_ty(config: PhantomConst) -> Self::Output { FetchDecodeStageOutput[config] } - fn max_output_count( + fn max_outputs_per_step( _config: PhantomConst, - ) -> ::SizeType { + ) -> ::SizeType { + ConstUsize + } + + fn input_queue_size( + config: PhantomConst, + ) -> ::SizeType { + CpuConfigMaxFetchesInFlight[config] + } + + fn output_queue_size( + _config: PhantomConst, + ) -> ::SizeType { ConstUsize } @@ -755,7 +970,7 @@ impl Stage for FetchDecodeStageState> { fn run( state: &mut SimValue, inputs: &SimValue, - ) -> SimValue>> { + ) -> SimValue>> { #[hdl(sim)] let Self { config } = state; let config = config.ty(); @@ -780,6 +995,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,33 +1061,56 @@ impl ResetSteps for PostDecodeStageState> { } impl Stage for PostDecodeStageState> { - type Inputs = ( - FetchDecodeStageOutput>, - BrPredStageOutput>, - ); + type Input = PostDecodeStageInput>; + type Inputs = PostDecodeStageInput>; type Output = PostDecodeStageOutput>; - type MaxOutputCount = CpuConfigFetchWidth>; + type MaxOutputsPerStep = CpuConfigFetchWidth>; + type InputQueueSize = ConstUsize<1>; + type OutputQueueSize = TwiceCpuConfigFetchWidth>; + + fn input_ty(config: PhantomConst) -> Self::Input { + PostDecodeStageInput[config] + } + + fn inputs_ty(config: PhantomConst) -> Self::Inputs { + PostDecodeStageInput[config] + } fn output_ty(config: PhantomConst) -> Self::Output { PostDecodeStageOutput[config] } - fn max_output_count( + fn max_outputs_per_step( config: PhantomConst, - ) -> ::SizeType { + ) -> ::SizeType { CpuConfigFetchWidth[config] } + fn input_queue_size( + _config: PhantomConst, + ) -> ::SizeType { + ConstUsize + } + + fn output_queue_size( + config: PhantomConst, + ) -> ::SizeType { + TwiceCpuConfigFetchWidth[config] + } + #[hdl] fn run( state: &mut SimValue, inputs: &SimValue, - ) -> SimValue>> { + ) -> SimValue>> { #[hdl(sim)] 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, @@ -1167,103 +1422,38 @@ impl Stage for PostDecodeStageState> { } #[hdl(no_static)] -struct RenameDispatchExecuteStageState> { - config: C, -} - -#[hdl(no_static)] -struct RenameDispatchExecuteStageOutput> { +struct ExecuteRetireStageInput> { post_decode_stage_output: PostDecodeStageOutput, + retire_interface_per_insn: RetireToNextPcInterfacePerInsn, } -impl SimValueDefault for RenameDispatchExecuteStageOutput> { +impl SimValueDefault for ExecuteRetireStageInput> { #[hdl] fn sim_value_default(self) -> SimValue { let Self { post_decode_stage_output, + retire_interface_per_insn, } = self; #[hdl(sim)] Self { post_decode_stage_output: post_decode_stage_output.sim_value_default(), + retire_interface_per_insn: retire_interface_per_insn.sim_value_default(), } } } -impl SimValueDefault for RenameDispatchExecuteStageState> { - #[hdl] - fn sim_value_default(self) -> SimValue { - let Self { config } = self; - #[hdl(sim)] - Self { config } - } -} - -impl ResetSteps for RenameDispatchExecuteStageState> { - #[hdl] - fn reset_step(this: &mut SimValue, _step: usize) -> ResetStatus { - #[hdl(sim)] - let Self { config: _ } = this; - ResetStatus::Done - } -} - -impl Stage for RenameDispatchExecuteStageState> { - type Inputs = RenameDispatchExecuteStageOutput>; - type Output = RenameDispatchExecuteStageOutput>; - type MaxOutputCount = ConstUsize<1>; - - fn output_ty(config: PhantomConst) -> Self::Output { - RenameDispatchExecuteStageOutput[config] - } - - fn max_output_count( - _config: PhantomConst, - ) -> ::SizeType { - ConstUsize - } - - #[hdl] - fn run( - state: &mut SimValue, - inputs: &SimValue, - ) -> SimValue>> { - #[hdl(sim)] - let Self { config } = state; - let config = config.ty(); - let StageOutput { outputs, cancel } = Self::stage_output_ty(config); - #[hdl(sim)] - StageOutput::<_, _, _> { - outputs: outputs.new_full_sim([inputs]), - cancel: #[hdl(sim)] - cancel.HdlNone(), - } - } - - #[hdl] - fn cancel(state: &mut SimValue, _cancel: &SimValue>>) { - #[hdl(sim)] - let Self { config: _ } = state; - } -} - #[hdl(no_static)] -struct RetireStageInput> { - rename_dispatch_execute_stage_output: RenameDispatchExecuteStageOutput, - retire_interface_per_insn: RetireToNextPcInterfacePerInsn, -} - -#[hdl(no_static)] -struct RetireStageState> { +struct ExecuteRetireStageState> { config: C, } #[hdl(no_static)] -struct RetireStageOutput> { +struct ExecuteRetireStageOutput> { train_branch_predictor: HdlOption, config: C, } -impl SimValueDefault for RetireStageState> { +impl SimValueDefault for ExecuteRetireStageState> { #[hdl] fn sim_value_default(self) -> SimValue { let Self { config } = self; @@ -1272,7 +1462,7 @@ impl SimValueDefault for RetireStageState> { } } -impl ResetSteps for RetireStageState> { +impl ResetSteps for ExecuteRetireStageState> { #[hdl] fn reset_step(this: &mut SimValue, _step: usize) -> ResetStatus { #[hdl(sim)] @@ -1281,18 +1471,41 @@ impl ResetSteps for RetireStageState> { } } -impl Stage for RetireStageState> { - type Inputs = RetireStageInput>; - type Output = RetireStageOutput>; - type MaxOutputCount = ConstUsize<1>; +impl Stage for ExecuteRetireStageState> { + type Input = PostDecodeStageOutput>; + type Inputs = ExecuteRetireStageInput>; + type Output = ExecuteRetireStageOutput>; + type MaxOutputsPerStep = ConstUsize<1>; + type InputQueueSize = CpuConfigRobSize>; + type OutputQueueSize = ConstUsize<1>; - fn output_ty(config: PhantomConst) -> Self::Output { - RetireStageOutput[config] + fn input_ty(config: PhantomConst) -> Self::Input { + PostDecodeStageOutput[config] } - fn max_output_count( + fn inputs_ty(config: PhantomConst) -> Self::Inputs { + ExecuteRetireStageInput[config] + } + + fn output_ty(config: PhantomConst) -> Self::Output { + ExecuteRetireStageOutput[config] + } + + fn max_outputs_per_step( _config: PhantomConst, - ) -> ::SizeType { + ) -> ::SizeType { + ConstUsize + } + + fn input_queue_size( + config: PhantomConst, + ) -> ::SizeType { + CpuConfigRobSize[config] + } + + fn output_queue_size( + _config: PhantomConst, + ) -> ::SizeType { ConstUsize } @@ -1300,13 +1513,13 @@ impl Stage for RetireStageState> { fn run( state: &mut SimValue, inputs: &SimValue, - ) -> SimValue>> { + ) -> SimValue>> { #[hdl(sim)] let Self { config } = state; let config = config.ty(); #[hdl(sim)] - let RetireStageInput::<_> { - rename_dispatch_execute_stage_output, + let ExecuteRetireStageInput::<_> { + post_decode_stage_output, retire_interface_per_insn, } = inputs; #[hdl(sim)] @@ -1318,10 +1531,6 @@ impl Stage for RetireStageState> { config: _, } = retire_interface_per_insn; #[hdl(sim)] - let RenameDispatchExecuteStageOutput::<_> { - post_decode_stage_output, - } = rename_dispatch_execute_stage_output; - #[hdl(sim)] let PostDecodeStageOutput::<_> { insn, next_pc: predicted_next_pc, @@ -1465,7 +1674,7 @@ impl Stage for RetireStageState> { StageOutput::<_, _, _> { outputs: outputs_ty.new_sim( #[hdl(sim)] - RetireStageOutput::<_> { + ExecuteRetireStageOutput::<_> { train_branch_predictor, config, }, @@ -1488,7 +1697,7 @@ impl Stage for RetireStageState> { StageOutput::<_, _, _> { outputs: outputs_ty.new_full_sim([ #[hdl(sim)] - RetireStageOutput::<_> { + ExecuteRetireStageOutput::<_> { train_branch_predictor, config, }, @@ -2048,6 +2257,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 +2287,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 @@ -2114,127 +2333,473 @@ impl ResetSteps for Queue { } } -#[hdl] -struct FetchQueueEntry { - fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>, - btb_entry: HdlOption, - btb_entry_index: UIntInRange<0, { BranchTargetBuffer::SIZE }>, - next_pc: UInt<64>, +#[hdl(no_static)] +struct StageWithQueues> { + state: S, + input_queue: Queue, StageInputQueueSize>, + output_queue: Queue, StageOutputQueueSize>, } -impl SimValueDefault for FetchQueueEntry { +impl StageWithQueues> { + FIXME +} + +#[hdl(no_static)] +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 sim_value_default(self) -> SimValue { - #[hdl(sim)] - FetchQueueEntry { - fetch_block_id: 0 as FetchBlockIdInt, - btb_entry: #[hdl(sim)] - HdlNone(), - btb_entry_index: 0usize.to_sim_value_with_type(FetchQueueEntry.btb_entry_index), - next_pc: 0u64, + fn to_fetch_cancel_data( + this: &SimValue, + ) -> SimValue< + HdlOption< + UIntInRangeInclusiveType< + ConstUsize<1>, + 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() } } } -const BRANCH_PREDICTOR_LOG2_SIZE: usize = 8; -const BRANCH_PREDICTOR_SIZE: usize = 1 << BRANCH_PREDICTOR_LOG2_SIZE; - #[hdl(no_static)] -pub struct NextPcState> { +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_state: RetireStageState, + retire_stage_inputs: Queue, ConstUsize<1>>, + retire_stage_state: ExecuteRetireStageState, 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) { + todo!() + } + #[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 +2844,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 +2928,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/next_pc/next_pc.mermaid b/crates/cpu/src/next_pc/next_pc.mermaid index 05ac31c..613e4b3 100644 --- a/crates/cpu/src/next_pc/next_pc.mermaid +++ b/crates/cpu/src/next_pc/next_pc.mermaid @@ -16,10 +16,7 @@ stateDiagram-v2 br_pred --> post_decode post_decode --> next_pc: cancel following - state "Rename\nDispatch\nExecute" as execute - post_decode --> execute - - state "Retire" as retire - execute --> retire - retire --> [*] - retire --> next_pc: cancel following \ No newline at end of file + state "Execute/Retire" as execute_retire + post_decode --> execute_retire + execute_retire --> [*] + execute_retire --> next_pc: cancel following \ No newline at end of file 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())],