diff --git a/crates/cpu/src/config.rs b/crates/cpu/src/config.rs index a7dd7d9..cf2fd08 100644 --- a/crates/cpu/src/config.rs +++ b/crates/cpu/src/config.rs @@ -163,3 +163,15 @@ pub type CpuConfigFetchWidthInBytes> = DynSize; #[hdl(get(|c| c.rob_size.get()))] pub type CpuConfigRobSize> = DynSize; + +pub trait PhantomConstCpuConfig: + PhantomConstGet + + Into> + + From> + + Type + + ToSimValue + + ToExpr +{ +} + +impl PhantomConstCpuConfig for PhantomConst {} diff --git a/crates/cpu/src/next_pc.rs b/crates/cpu/src/next_pc.rs index 45c3db5..e079640 100644 --- a/crates/cpu/src/next_pc.rs +++ b/crates/cpu/src/next_pc.rs @@ -14,7 +14,7 @@ use crate::{ config::{ CpuConfig, CpuConfigFetchWidth, CpuConfigMaxFetchesInFlight, CpuConfigRobSize, - TwiceCpuConfigFetchWidth, + PhantomConstCpuConfig, TwiceCpuConfigFetchWidth, }, util::array_vec::ArrayVec, }; @@ -115,7 +115,7 @@ pub struct RetireToNextPcInterfacePerInsn> { pub config: C, } -impl SimValueDefault for RetireToNextPcInterfacePerInsn> { +impl SimValueDefault for RetireToNextPcInterfacePerInsn { #[hdl] fn sim_value_default(self) -> SimValue { let Self { @@ -159,7 +159,7 @@ pub struct DecodeToPostDecodeInterfaceInner> { pub config: C, } -impl SimValueDefault for DecodeToPostDecodeInterfaceInner> { +impl SimValueDefault for DecodeToPostDecodeInterfaceInner { #[hdl] fn sim_value_default(self) -> SimValue { let Self { insns, config } = self; @@ -204,150 +204,383 @@ struct Cancel> { } /// the output of [`Stage::run`]. -/// when cancelling operations, the returned [`StageOutput.cancel`] should be the state after -/// running all operations returned in [`StageOutput.output`]. +/// when cancelling operations, the returned [`StageRunOutput.cancel`] should be the state after +/// running all operations returned in [`StageRunOutput.output`]. #[hdl(no_static)] -struct StageOutput> { - outputs: ArrayVec, +struct StageRunOutput + PhantomConstCpuConfig, S: Type + Stage> { + outputs: ArrayVec, StageMaxOutputsPerStep>, /// when set to [`HdlSome`], [`Stage::cancel`] is called on all previous stages cancel: HdlOption>, } -trait Stage: Type + SimValueDefault + ResetSteps { - type Input: Type; +trait Stages: Type { + type Outputs: Type + SimValueDefault; + type SimValueOutputQueueRefs<'a>: 'a + Copy; + type SimValueOutputQueueMuts<'a>: 'a; + fn outputs_ty(config: C) -> Self::Outputs; + fn reborrow_output_queues_as_refs<'a>( + output_queues: &'a Self::SimValueOutputQueueMuts<'_>, + ) -> Self::SimValueOutputQueueRefs<'a>; + fn reborrow_output_queue_muts<'a>( + output_queues: &'a mut Self::SimValueOutputQueueMuts<'_>, + ) -> Self::SimValueOutputQueueMuts<'a>; + fn peek_output_queues( + output_queues: Self::SimValueOutputQueueRefs<'_>, + max_peek_len: usize, + ) -> impl Iterator>; + /// pops all output queues; if this function returns `None`, none of the output queues will be modified + fn pop_output_queues( + output_queues: Self::SimValueOutputQueueMuts<'_>, + ) -> Option>; + fn visit_sim_value_ref>(this: &SimValue, visitor: &mut V); +} + +impl Stages for () { + type Outputs = (); + type SimValueOutputQueueRefs<'a> = (); + type SimValueOutputQueueMuts<'a> = (); + fn outputs_ty(_config: C) -> Self::Outputs { + () + } + fn reborrow_output_queues_as_refs<'a>( + output_queues: &'a Self::SimValueOutputQueueMuts<'_>, + ) -> Self::SimValueOutputQueueRefs<'a> { + let () = output_queues; + () + } + fn reborrow_output_queue_muts<'a>( + output_queues: &'a mut Self::SimValueOutputQueueMuts<'_>, + ) -> Self::SimValueOutputQueueMuts<'a> { + let () = output_queues; + () + } + #[hdl] + fn peek_output_queues( + output_queues: Self::SimValueOutputQueueRefs<'_>, + max_peek_len: usize, + ) -> impl Iterator> { + let () = output_queues; + std::iter::repeat_n( + #[hdl(sim)] + (), + max_peek_len, + ) + } + #[hdl] + fn pop_output_queues( + output_queues: Self::SimValueOutputQueueMuts<'_>, + ) -> Option> { + let () = output_queues; + Some( + #[hdl(sim)] + (), + ) + } + #[hdl] + fn visit_sim_value_ref>(this: &SimValue, _visitor: &mut V) { + #[hdl(sim)] + let () = this; + } +} + +impl> Stages for S1 { + type Outputs = S1::Output; + type SimValueOutputQueueRefs<'a> = + &'a SimValue, StageOutputQueueSize>>; + type SimValueOutputQueueMuts<'a> = + &'a mut SimValue, StageOutputQueueSize>>; + fn outputs_ty(config: C) -> Self::Outputs { + S1::output_ty(config) + } + fn reborrow_output_queues_as_refs<'a>( + output_queues: &'a Self::SimValueOutputQueueMuts<'_>, + ) -> Self::SimValueOutputQueueRefs<'a> { + output_queues + } + fn reborrow_output_queue_muts<'a>( + output_queues: &'a mut Self::SimValueOutputQueueMuts<'_>, + ) -> Self::SimValueOutputQueueMuts<'a> { + output_queues + } + fn peek_output_queues( + output_queues: Self::SimValueOutputQueueRefs<'_>, + max_peek_len: usize, + ) -> impl Iterator> { + Queue::peek_iter(output_queues).take(max_peek_len) + } + fn pop_output_queues( + output_queues: Self::SimValueOutputQueueMuts<'_>, + ) -> Option> { + Queue::pop(output_queues) + } + fn visit_sim_value_ref>(this: &SimValue, visitor: &mut V) { + visitor.visit(this); + } +} + +impl, S2: Stage> Stages for (S1, S2) { + type Outputs = (S1::Output, S2::Output); + type SimValueOutputQueueRefs<'a> = ( + &'a SimValue, StageOutputQueueSize>>, + &'a SimValue, StageOutputQueueSize>>, + ); + type SimValueOutputQueueMuts<'a> = ( + &'a mut SimValue, StageOutputQueueSize>>, + &'a mut SimValue, StageOutputQueueSize>>, + ); + fn outputs_ty(config: C) -> Self::Outputs { + (S1::output_ty(config), S2::output_ty(config)) + } + fn reborrow_output_queues_as_refs<'a>( + output_queues: &'a Self::SimValueOutputQueueMuts<'_>, + ) -> Self::SimValueOutputQueueRefs<'a> { + let (s1, s2) = output_queues; + (s1, s2) + } + fn reborrow_output_queue_muts<'a>( + output_queues: &'a mut Self::SimValueOutputQueueMuts<'_>, + ) -> Self::SimValueOutputQueueMuts<'a> { + let (s1, s2) = output_queues; + (s1, s2) + } + fn peek_output_queues( + output_queues: Self::SimValueOutputQueueRefs<'_>, + max_peek_len: usize, + ) -> impl Iterator> { + let (s1, s2) = output_queues; + Queue::peek_iter(s1) + .zip(Queue::peek_iter(s2)) + .take(max_peek_len) + .map(ToSimValue::into_sim_value) + } + #[hdl] + fn pop_output_queues( + output_queues: Self::SimValueOutputQueueMuts<'_>, + ) -> Option> { + let (s1, s2) = output_queues; + // make sure to only pop if all pops will succeed + if Queue::is_empty(s1) || Queue::is_empty(s2) { + None + } else { + Some( + #[hdl(sim)] + ( + Queue::pop(s1).expect("just checked"), + Queue::pop(s2).expect("just checked"), + ), + ) + } + } + #[hdl] + fn visit_sim_value_ref>(this: &SimValue, visitor: &mut V) { + #[hdl(sim)] + let (s1, s2) = this; + visitor.visit(s1); + visitor.visit(s2); + } +} + +trait StagesVisitSimValueRef { + fn visit>(&mut self, stage: &SimValue); +} + +trait Stage: Type + SimValueDefault + ResetSteps { + type InputStages: Stages; type Inputs: Type; - type Output: Type; + type Output: Type + SimValueDefault; + type ToExternalPipeInputInterface: Type; + type FromExternalPipeOutputInterface: Type; + type FromExternalPipeOutputItem: Type; type MaxOutputsPerStep: Size; + type ExternalPipeIoWidth: 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_outputs_per_step( - config: PhantomConst, - ) -> ::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_outputs_per_step(config)][config] - } - /// see [`StageOutput`] for docs on output + fn inputs_ty(config: C) -> Self::Inputs; + fn output_ty(config: C) -> Self::Output; + fn to_external_pipe_input_interface_ty(config: C) -> Self::ToExternalPipeInputInterface; + fn from_external_pipe_output_interface_ty(config: C) -> Self::FromExternalPipeOutputInterface; + fn from_external_pipe_output_item_ty(config: C) -> Self::FromExternalPipeOutputItem; + + fn max_outputs_per_step(config: C) -> ::SizeType; + fn external_pipe_io_width(config: C) -> ::SizeType; + fn input_queue_size(config: C) -> ::SizeType; + fn output_queue_size(config: C) -> ::SizeType; + + fn cancel_in_progress_for_stage_ref( + cancel: &SimValue>, + ) -> &SimValue>; + fn cancel_in_progress_for_stage_mut( + cancel: &mut SimValue>, + ) -> &mut SimValue>; + + fn make_inputs( + input_stages_outputs: &SimValue>, + from_external_pipe_output_item: &SimValue, + ) -> SimValue; + + /// see [`StageRunOutput`] 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>>); + 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:vis type $Type:ident<$C:ident: $PhantomConstCpuConfig:ident, $Arg:ident: $Trait:ident<$TraitC:ident>> = $Target:ty; ) => { - $vis type $Type<$Arg, $C> = <$Target as fayalite::phantom_const::ReturnSelfUnchanged<$C>>::Type; + $vis type $Type<$C, $Arg> = <$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); + const _: () = { + #[derive(Clone, PartialEq, Eq, Hash, Debug)] + $vis struct $OneGeneric<$C: $PhantomConstCpuConfig>($C); - impl<$Arg: $Trait> std::ops::Index<$Arg> for $WithoutGenerics { - type Output = $OneGeneric<$Arg>; + impl<$C: $PhantomConstCpuConfig> std::ops::Index<$C> for $WithoutGenerics { + type Output = $OneGeneric<$C>; - fn index(&self, arg: $Arg) -> &Self::Output { - fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($OneGeneric(arg))) + fn index(&self, config: $C) -> &Self::Output { + fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($OneGeneric(config))) + } } - } - impl<$Arg: $Trait, $C: PhantomConstGet> std::ops::Index<$C> for $OneGeneric<$Arg> { - type Output = $Type<$Arg, $C>; + impl<$C: $PhantomConstCpuConfig, $Arg: $Trait<$TraitC>> std::ops::Index<$Arg> for $OneGeneric<$C> { + type Output = $Type<$C, $Arg>; - fn index(&self, config: $C) -> &Self::Output { - fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($ty(self.0, config))) + fn index(&self, arg: $Arg) -> &Self::Output { + fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($ty(self.0, arg))) + } } - } + }; }; ( #[without_generics = $WithoutGenerics:ident, $OneGeneric:ident] #[size = $size:expr] - $vis:vis type $Type:ident<$Arg:ident: $Trait:ident, $C:ident: PhantomConstGet> = $Target:ty; + $vis:vis type $Type:ident<$C:ident: $PhantomConstCpuConfig:ident, $Arg:ident: $Trait:ident<$TraitC:ident>> = $Target:ty; ) => { - $vis type $Type<$Arg, $C> = <$Target as fayalite::phantom_const::ReturnSelfUnchanged<$C>>::Type; + $vis type $Type<$C, $Arg> = <$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); + const _: () = { + #[derive(Clone, PartialEq, Eq, Hash, Debug)] + $vis struct $OneGeneric<$C: $PhantomConstCpuConfig>($C); - impl<$Arg: $Trait> std::ops::Index<$Arg> for $WithoutGenerics { - type Output = $OneGeneric<$Arg>; + impl<$C: $PhantomConstCpuConfig> std::ops::Index<$C> for $WithoutGenerics { + type Output = $OneGeneric<$C>; - fn index(&self, arg: $Arg) -> &Self::Output { - fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($OneGeneric(arg))) + fn index(&self, config: $C) -> &Self::Output { + fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($OneGeneric(config))) + } } - } - impl<$Arg: $Trait, $C: PhantomConstGet> std::ops::Index<$C> for $OneGeneric<$Arg> { - type Output = <$Type<$Arg, $C> as Size>::SizeType; + impl<$C: $PhantomConstCpuConfig, $Arg: $Trait<$TraitC>> std::ops::Index<$Arg> for $OneGeneric<$C> { + type Output = <$Type<$C, $Arg> as Size>::SizeType; - fn index(&self, config: $C) -> &Self::Output { - fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($size(self.0, config))) + fn index(&self, arg: $Arg) -> &Self::Output { + fayalite::intern::Interned::into_inner(fayalite::intern::Intern::intern_sized($size(self.0, arg))) + } } - } + }; }; } hdl_type_alias_with_generics! { - #[without_generics = StageTraitInputWithoutGenerics, StageTraitInputWithStage] - #[ty = |_stage, config: C| T::input_ty(PhantomConst::new_interned(config.get()))] - type StageTraitInput> = ::Input; + #[without_generics = StageInputStagesOutputsWithoutGenerics, StageInputStagesOutputsWithStage] + #[ty = |config: C, _stage| >::InputStages::outputs_ty(config)] + type StageInputStagesOutputs> = <>::InputStages as Stages>::Outputs; } hdl_type_alias_with_generics! { - #[without_generics = StageTraitInputsWithoutGenerics, StageTraitInputsWithStage] - #[ty = |_stage, config: C| T::inputs_ty(PhantomConst::new_interned(config.get()))] - type StageTraitInputs> = ::Inputs; + #[without_generics = StageInputsWithoutGenerics, StageInputsWithStage] + #[ty = |config: C, _stage| T::inputs_ty(config)] + type StageInputs> = >::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; + #[without_generics = StageOutputWithoutGenerics, StageOutputWithStage] + #[ty = |config: C, _stage| T::output_ty(config)] + type StageOutput> = >::Output; +} + +hdl_type_alias_with_generics! { + #[without_generics = StageToExternalPipeInputInterfaceWithoutGenerics, StageToExternalPipeInputInterfaceWithStage] + #[ty = |config: C, _stage| T::to_external_pipe_input_interface_ty(config)] + type StageToExternalPipeInputInterface> = >::ToExternalPipeInputInterface; +} + +hdl_type_alias_with_generics! { + #[without_generics = StageFromExternalPipeOutputInterfaceWithoutGenerics, StageFromExternalPipeOutputInterfaceWithStage] + #[ty = |config: C, _stage| T::from_external_pipe_output_interface_ty(config)] + type StageFromExternalPipeOutputInterface> = >::FromExternalPipeOutputInterface; +} + +hdl_type_alias_with_generics! { + #[without_generics = StageFromExternalPipeOutputItemWithoutGenerics, StageFromExternalPipeOutputItemWithStage] + #[ty = |config: C, _stage| T::from_external_pipe_output_item_ty(config)] + type StageFromExternalPipeOutputItem> = >::FromExternalPipeOutputItem; } 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; + #[size = |config: C, _stage| T::max_outputs_per_step(config)] + 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; + #[size = |config: C, _stage| T::input_queue_size(config)] + type StageInputQueueSize> = >::InputQueueSize; +} + +hdl_type_alias_with_generics! { + #[without_generics = StageExternalPipeIoWidthWithoutGenerics, StageExternalPipeIoWidthWithStage] + #[size = |config: C, _stage| T::external_pipe_io_width(config)] + type StageExternalPipeIoWidth> = >::ExternalPipeIoWidth; } 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; + #[size = |config: C, _stage| T::output_queue_size(config)] + type StageOutputQueueSize> = >::OutputQueueSize; } +#[hdl] +type StageToExternalPipeInputInput< + C: PhantomConstGet + PhantomConstCpuConfig, + S: Type + Stage, +> = ArrayVec, StageExternalPipeIoWidth>; + +#[hdl] +type StageToExternalPipeInputCancel< + C: PhantomConstGet + PhantomConstCpuConfig, + S: Type + Stage, +> = HdlOption, StageInputQueueSize>>; + +#[hdl] +type StageExternalPipeIoReady< + C: PhantomConstGet + PhantomConstCpuConfig, + S: Type + Stage, +> = UIntInRangeInclusiveType, StageExternalPipeIoWidth>; + +#[hdl] +type StageFromExternalPipeOutputData< + C: PhantomConstGet + PhantomConstCpuConfig, + S: Type + Stage, +> = ArrayVec, StageExternalPipeIoWidth>; + #[hdl(no_static)] struct NextPcStageOutput> { start_pc: UInt<64>, @@ -361,7 +594,7 @@ struct NextPcStageOutput> { config: C, } -impl SimValueDefault for NextPcStageOutput> { +impl SimValueDefault for NextPcStageOutput { #[hdl] fn sim_value_default(self) -> SimValue { let Self { @@ -386,7 +619,7 @@ impl SimValueDefault for NextPcStageOutput> { } #[hdl(no_static)] -struct NextPcStageState> { +struct NextPcStageState + PhantomConstCpuConfig> { call_stack: CallStack, branch_target_buffer: BranchTargetBuffer, next_pc: UInt<64>, @@ -394,7 +627,7 @@ struct NextPcStageState> { config: C, } -impl SimValueDefault for NextPcStageState> { +impl SimValueDefault for NextPcStageState { #[hdl] fn sim_value_default(self) -> SimValue { let Self { @@ -417,7 +650,7 @@ impl SimValueDefault for NextPcStageState> { } } -impl ResetSteps for NextPcStageState> { +impl ResetSteps for NextPcStageState { #[hdl] fn reset_step(this: &mut SimValue, step: usize) -> ResetStatus { #[hdl(sim)] @@ -436,49 +669,85 @@ impl ResetSteps for NextPcStageState> { } } -impl Stage for NextPcStageState> { - type Input = (); +impl Stage for NextPcStageState { + type InputStages = (); type Inputs = (); - type Output = NextPcStageOutput>; + type Output = NextPcStageOutput; + type ToExternalPipeInputInterface = (); + type FromExternalPipeOutputInterface = (); + type FromExternalPipeOutputItem = (); type MaxOutputsPerStep = ConstUsize<1>; + type ExternalPipeIoWidth = ConstUsize<1>; type InputQueueSize = ConstUsize<1>; type OutputQueueSize = ConstUsize<1>; - fn input_ty(_config: PhantomConst) -> Self::Input { + fn inputs_ty(_config: C) -> Self::Inputs { () } - fn inputs_ty(_config: PhantomConst) -> Self::Inputs { - () - } - - fn output_ty(config: PhantomConst) -> Self::Output { + fn output_ty(config: C) -> Self::Output { NextPcStageOutput[config] } - fn max_outputs_per_step( - _config: PhantomConst, - ) -> ::SizeType { + fn to_external_pipe_input_interface_ty(_config: C) -> Self::ToExternalPipeInputInterface { + () + } + + fn from_external_pipe_output_interface_ty(_config: C) -> Self::FromExternalPipeOutputInterface { + () + } + + fn from_external_pipe_output_item_ty(_config: C) -> Self::FromExternalPipeOutputItem { + () + } + + fn max_outputs_per_step(_config: C) -> ::SizeType { ConstUsize } - fn input_queue_size( - _config: PhantomConst, - ) -> ::SizeType { + fn external_pipe_io_width(_config: C) -> ::SizeType { ConstUsize } - fn output_queue_size( - _config: PhantomConst, - ) -> ::SizeType { + fn input_queue_size(_config: C) -> ::SizeType { ConstUsize } + fn output_queue_size(_config: C) -> ::SizeType { + ConstUsize + } + + fn cancel_in_progress_for_stage_ref( + cancel: &SimValue>, + ) -> &SimValue> { + &cancel.next_pc + } + + fn cancel_in_progress_for_stage_mut( + cancel: &mut SimValue>, + ) -> &mut SimValue> { + &mut cancel.next_pc + } + + #[hdl] + fn make_inputs( + input_stages_outputs: &SimValue>, + from_external_pipe_output_item: &SimValue, + ) -> SimValue { + #[hdl(sim)] + let () = input_stages_outputs; + #[hdl(sim)] + let () = from_external_pipe_output_item; + #[hdl(sim)] + () + } + #[hdl] fn run( state: &mut SimValue, _inputs: &SimValue, - ) -> SimValue>> { + ) -> SimValue> { + let this_ty = state.ty(); let config = state.config.ty(); let start_call_stack = state.call_stack.clone(); let fetch_block_id = state.next_fetch_block_id.as_int(); @@ -557,15 +826,17 @@ impl Stage for NextPcStageState> { config, }; #[hdl(sim)] - StageOutput::<_, _, _> { - outputs: Self::stage_output_ty(config).outputs.new_full_sim([output]), + StageRunOutput::<_, _> { + outputs: StageRunOutput[config][this_ty] + .outputs + .new_full_sim([output]), cancel: #[hdl(sim)] (HdlOption[Cancel[config]]).HdlNone(), } } #[hdl] - fn cancel(state: &mut SimValue, cancel: &SimValue>>) { + fn cancel(state: &mut SimValue, cancel: &SimValue>) { #[hdl(sim)] let Self { call_stack, @@ -645,7 +916,7 @@ struct BrPredStageOutput> { config: C, } -impl SimValueDefault for BrPredStageOutput> { +impl SimValueDefault for BrPredStageOutput { #[hdl] fn sim_value_default(self) -> SimValue { #[hdl(sim)] @@ -659,7 +930,7 @@ impl SimValueDefault for BrPredStageOutput> { } #[hdl(no_static)] -struct BrPredStageState> { +struct BrPredStageState + PhantomConstCpuConfig> { branch_history: UInt<6>, branch_predictor: Array, config: C, @@ -670,7 +941,7 @@ fn step_branch_history(branch_history: &mut SimValue>, taken: bool) { ((&**branch_history << 1) | taken.cast_to_static::>()).cast_to_static::>(); } -impl BrPredStageState> { +impl BrPredStageState { fn branch_predictor_index(this: &SimValue, branch_pc: u64) -> usize { let mut t = this.branch_history.cast_to_static::>().as_int(); t ^= t.rotate_left(5) & !branch_pc.rotate_right(3); @@ -684,7 +955,7 @@ impl BrPredStageState> { } } -impl SimValueDefault for BrPredStageState> { +impl SimValueDefault for BrPredStageState { #[hdl] fn sim_value_default(self) -> SimValue { let Self { @@ -705,7 +976,7 @@ impl SimValueDefault for BrPredStageState> { } } -impl ResetSteps for BrPredStageState> { +impl ResetSteps for BrPredStageState { #[hdl] fn reset_step(this: &mut SimValue, step: usize) -> ResetStatus { #[hdl(sim)] @@ -719,49 +990,82 @@ impl ResetSteps for BrPredStageState> { } } -impl Stage for BrPredStageState> { - type Input = NextPcStageOutput>; - type Inputs = NextPcStageOutput>; - type Output = BrPredStageOutput>; +impl Stage for BrPredStageState { + type InputStages = NextPcStageState; + type Inputs = NextPcStageOutput; + type Output = BrPredStageOutput; + type ToExternalPipeInputInterface = (); + type FromExternalPipeOutputInterface = (); + type FromExternalPipeOutputItem = (); type MaxOutputsPerStep = ConstUsize<1>; + type ExternalPipeIoWidth = ConstUsize<1>; type InputQueueSize = ConstUsize<1>; - type OutputQueueSize = CpuConfigMaxFetchesInFlight>; + type OutputQueueSize = CpuConfigMaxFetchesInFlight; - fn input_ty(config: PhantomConst) -> Self::Input { + fn inputs_ty(config: C) -> Self::Inputs { NextPcStageOutput[config] } - fn inputs_ty(config: PhantomConst) -> Self::Inputs { - NextPcStageOutput[config] - } - - fn output_ty(config: PhantomConst) -> Self::Output { + fn output_ty(config: C) -> Self::Output { BrPredStageOutput[config] } - fn max_outputs_per_step( - _config: PhantomConst, - ) -> ::SizeType { + fn to_external_pipe_input_interface_ty(_config: C) -> Self::ToExternalPipeInputInterface { + () + } + + fn from_external_pipe_output_interface_ty(_config: C) -> Self::FromExternalPipeOutputInterface { + () + } + + fn from_external_pipe_output_item_ty(_config: C) -> Self::FromExternalPipeOutputItem { + () + } + + fn max_outputs_per_step(_config: C) -> ::SizeType { ConstUsize } - fn input_queue_size( - _config: PhantomConst, - ) -> ::SizeType { + fn external_pipe_io_width(_config: C) -> ::SizeType { ConstUsize } - fn output_queue_size( - config: PhantomConst, - ) -> ::SizeType { + fn input_queue_size(_config: C) -> ::SizeType { + ConstUsize + } + + fn output_queue_size(config: C) -> ::SizeType { CpuConfigMaxFetchesInFlight[config] } + fn cancel_in_progress_for_stage_ref( + cancel: &SimValue>, + ) -> &SimValue> { + &cancel.br_pred + } + + fn cancel_in_progress_for_stage_mut( + cancel: &mut SimValue>, + ) -> &mut SimValue> { + &mut cancel.br_pred + } + + #[hdl] + fn make_inputs( + input_stages_outputs: &SimValue>, + from_external_pipe_output_item: &SimValue, + ) -> SimValue { + #[hdl(sim)] + let () = from_external_pipe_output_item; + input_stages_outputs.clone() + } + #[hdl] fn run( state: &mut SimValue, inputs: &SimValue, - ) -> SimValue>> { + ) -> SimValue> { + let this_ty = state.ty(); let config = state.config.ty(); #[hdl(sim)] let NextPcStageOutput::<_> { @@ -806,9 +1110,9 @@ impl Stage for BrPredStageState> { let btb_entry_index = &btb_entry.0; let mut btb_entry = btb_entry.1.clone(); btb_entry.addr_kind = opposite_addr_kind; - let StageOutput { outputs, cancel } = Self::stage_output_ty(config); + let StageRunOutput { outputs, cancel } = StageRunOutput[config][this_ty]; let retval = #[hdl(sim)] - StageOutput::<_, _, _> { + StageRunOutput::<_, _> { outputs: outputs.sim_value_default(), cancel: #[hdl(sim)] cancel.HdlSome( @@ -839,15 +1143,17 @@ impl Stage for BrPredStageState> { config, }; #[hdl(sim)] - StageOutput::<_, _, _> { - outputs: Self::stage_output_ty(config).outputs.new_full_sim([output]), + StageRunOutput::<_, _> { + outputs: StageRunOutput[config][this_ty] + .outputs + .new_full_sim([output]), cancel: #[hdl(sim)] (HdlOption[Cancel[config]]).HdlNone(), } } #[hdl] - fn cancel(state: &mut SimValue, cancel: &SimValue>>) { + fn cancel(state: &mut SimValue, cancel: &SimValue>) { #[hdl(sim)] let Cancel::<_> { call_stack: _, @@ -861,7 +1167,7 @@ impl Stage for BrPredStageState> { } } -impl BrPredStageState> { +impl BrPredStageState { #[hdl] fn train_branch_predictor( this: &mut SimValue, @@ -884,11 +1190,11 @@ impl BrPredStageState> { } #[hdl(no_static)] -struct FetchDecodeStageState> { +struct FetchDecodeStageState + PhantomConstCpuConfig> { config: C, } -impl SimValueDefault for FetchDecodeStageState> { +impl SimValueDefault for FetchDecodeStageState { #[hdl] fn sim_value_default(self) -> SimValue { #[hdl(sim)] @@ -898,7 +1204,7 @@ impl SimValueDefault for FetchDecodeStageState> { } } -impl ResetSteps for FetchDecodeStageState> { +impl ResetSteps for FetchDecodeStageState { #[hdl] fn reset_step(this: &mut SimValue, _step: usize) -> ResetStatus { #[hdl(sim)] @@ -913,7 +1219,7 @@ struct FetchDecodeStageOutput> { decode_output: DecodeToPostDecodeInterfaceInner, } -impl SimValueDefault for FetchDecodeStageOutput> { +impl SimValueDefault for FetchDecodeStageOutput { #[hdl] fn sim_value_default(self) -> SimValue { let Self { @@ -928,55 +1234,90 @@ impl SimValueDefault for FetchDecodeStageOutput> { } } -impl Stage for FetchDecodeStageState> { - type Input = NextPcStageOutput>; - type Inputs = FetchDecodeStageOutput>; - type Output = FetchDecodeStageOutput>; +impl Stage for FetchDecodeStageState { + type InputStages = NextPcStageState; + type Inputs = FetchDecodeStageOutput; + type Output = FetchDecodeStageOutput; + type ToExternalPipeInputInterface = NextPcToFetchInterface; + type FromExternalPipeOutputInterface = DecodeToPostDecodeInterface; + type FromExternalPipeOutputItem = DecodeToPostDecodeInterfaceInner; type MaxOutputsPerStep = ConstUsize<1>; - type InputQueueSize = CpuConfigMaxFetchesInFlight>; + type ExternalPipeIoWidth = 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 { + fn inputs_ty(config: C) -> Self::Inputs { FetchDecodeStageOutput[config] } - fn output_ty(config: PhantomConst) -> Self::Output { + fn output_ty(config: C) -> Self::Output { FetchDecodeStageOutput[config] } - fn max_outputs_per_step( - _config: PhantomConst, - ) -> ::SizeType { + fn to_external_pipe_input_interface_ty(config: C) -> Self::ToExternalPipeInputInterface { + NextPcToFetchInterface[config] + } + + fn from_external_pipe_output_interface_ty(config: C) -> Self::FromExternalPipeOutputInterface { + DecodeToPostDecodeInterface[config] + } + + fn from_external_pipe_output_item_ty(config: C) -> Self::FromExternalPipeOutputItem { + DecodeToPostDecodeInterfaceInner[config] + } + + fn max_outputs_per_step(_config: C) -> ::SizeType { ConstUsize } - fn input_queue_size( - config: PhantomConst, - ) -> ::SizeType { + fn external_pipe_io_width(_config: C) -> ::SizeType { + ConstUsize + } + + fn input_queue_size(config: C) -> ::SizeType { CpuConfigMaxFetchesInFlight[config] } - fn output_queue_size( - _config: PhantomConst, - ) -> ::SizeType { + fn output_queue_size(_config: C) -> ::SizeType { ConstUsize } + fn cancel_in_progress_for_stage_ref( + cancel: &SimValue>, + ) -> &SimValue> { + &cancel.fetch_decode + } + + fn cancel_in_progress_for_stage_mut( + cancel: &mut SimValue>, + ) -> &mut SimValue> { + &mut cancel.fetch_decode + } + + #[hdl] + fn make_inputs( + input_stages_outputs: &SimValue>, + from_external_pipe_output_item: &SimValue, + ) -> SimValue { + #[hdl(sim)] + FetchDecodeStageOutput::<_> { + next_pc_stage_output: input_stages_outputs, + decode_output: from_external_pipe_output_item, + } + } + #[hdl] fn run( state: &mut SimValue, inputs: &SimValue, - ) -> SimValue>> { + ) -> SimValue> { + let this_ty = state.ty(); #[hdl(sim)] let Self { config } = state; let config = config.ty(); - let StageOutput { outputs, cancel } = Self::stage_output_ty(config); + let StageRunOutput { outputs, cancel } = StageRunOutput[config][this_ty]; #[hdl(sim)] - StageOutput::<_, _, _> { + StageRunOutput::<_, _> { outputs: outputs.new_full_sim([inputs]), cancel: #[hdl(sim)] cancel.HdlNone(), @@ -984,14 +1325,14 @@ impl Stage for FetchDecodeStageState> { } #[hdl] - fn cancel(state: &mut SimValue, _cancel: &SimValue>>) { + fn cancel(state: &mut SimValue, _cancel: &SimValue>) { #[hdl(sim)] let Self { config: _ } = state; } } #[hdl(no_static)] -struct PostDecodeStageState> { +struct PostDecodeStageState + PhantomConstCpuConfig> { config: C, } @@ -1001,7 +1342,7 @@ struct PostDecodeStageInput> { br_pred_stage_output: BrPredStageOutput, } -impl SimValueDefault for PostDecodeStageInput> { +impl SimValueDefault for PostDecodeStageInput { #[hdl] fn sim_value_default(self) -> SimValue { #[hdl(sim)] @@ -1023,7 +1364,7 @@ struct PostDecodeStageOutput> { config: C, } -impl SimValueDefault for PostDecodeStageOutput> { +impl SimValueDefault for PostDecodeStageOutput { #[hdl] fn sim_value_default(self) -> SimValue { #[hdl(sim)] @@ -1041,7 +1382,7 @@ impl SimValueDefault for PostDecodeStageOutput> { } } -impl SimValueDefault for PostDecodeStageState> { +impl SimValueDefault for PostDecodeStageState { #[hdl] fn sim_value_default(self) -> SimValue { #[hdl(sim)] @@ -1051,7 +1392,7 @@ impl SimValueDefault for PostDecodeStageState> { } } -impl ResetSteps for PostDecodeStageState> { +impl ResetSteps for PostDecodeStageState { #[hdl] fn reset_step(this: &mut SimValue, _step: usize) -> ResetStatus { #[hdl(sim)] @@ -1060,49 +1401,88 @@ impl ResetSteps for PostDecodeStageState> { } } -impl Stage for PostDecodeStageState> { - type Input = PostDecodeStageInput>; - type Inputs = PostDecodeStageInput>; - type Output = PostDecodeStageOutput>; - type MaxOutputsPerStep = CpuConfigFetchWidth>; +impl Stage for PostDecodeStageState { + type InputStages = (FetchDecodeStageState, BrPredStageState); + type Inputs = PostDecodeStageInput; + type Output = PostDecodeStageOutput; + type ToExternalPipeInputInterface = (); + type FromExternalPipeOutputInterface = (); + type FromExternalPipeOutputItem = (); + type MaxOutputsPerStep = CpuConfigFetchWidth; + type ExternalPipeIoWidth = ConstUsize<1>; type InputQueueSize = ConstUsize<1>; - type OutputQueueSize = TwiceCpuConfigFetchWidth>; + type OutputQueueSize = TwiceCpuConfigFetchWidth; - fn input_ty(config: PhantomConst) -> Self::Input { + fn inputs_ty(config: C) -> Self::Inputs { PostDecodeStageInput[config] } - fn inputs_ty(config: PhantomConst) -> Self::Inputs { - PostDecodeStageInput[config] - } - - fn output_ty(config: PhantomConst) -> Self::Output { + fn output_ty(config: C) -> Self::Output { PostDecodeStageOutput[config] } - fn max_outputs_per_step( - config: PhantomConst, - ) -> ::SizeType { + fn to_external_pipe_input_interface_ty(_config: C) -> Self::ToExternalPipeInputInterface { + () + } + + fn from_external_pipe_output_interface_ty(_config: C) -> Self::FromExternalPipeOutputInterface { + () + } + + fn from_external_pipe_output_item_ty(_config: C) -> Self::FromExternalPipeOutputItem { + () + } + + fn max_outputs_per_step(config: C) -> ::SizeType { CpuConfigFetchWidth[config] } - fn input_queue_size( - _config: PhantomConst, - ) -> ::SizeType { + fn external_pipe_io_width(_config: C) -> ::SizeType { ConstUsize } - fn output_queue_size( - config: PhantomConst, - ) -> ::SizeType { + fn input_queue_size(_config: C) -> ::SizeType { + ConstUsize + } + + fn output_queue_size(config: C) -> ::SizeType { TwiceCpuConfigFetchWidth[config] } + fn cancel_in_progress_for_stage_ref( + cancel: &SimValue>, + ) -> &SimValue> { + &cancel.post_decode + } + + fn cancel_in_progress_for_stage_mut( + cancel: &mut SimValue>, + ) -> &mut SimValue> { + &mut cancel.post_decode + } + + #[hdl] + fn make_inputs( + input_stages_outputs: &SimValue>, + from_external_pipe_output_item: &SimValue, + ) -> SimValue { + #[hdl(sim)] + let (fetch_decode_stage_output, br_pred_stage_output) = input_stages_outputs; + #[hdl(sim)] + let () = from_external_pipe_output_item; + #[hdl(sim)] + PostDecodeStageInput::<_> { + fetch_decode_stage_output, + br_pred_stage_output, + } + } + #[hdl] fn run( state: &mut SimValue, inputs: &SimValue, - ) -> SimValue>> { + ) -> SimValue> { + let this_ty = state.ty(); #[hdl(sim)] let Self { config } = state; let config = config.ty(); @@ -1140,10 +1520,10 @@ impl Stage for PostDecodeStageState> { -- either the decoded instructions or a WipDecodedInsnKind::Interrupt", ); let insns = ArrayVec::elements_sim_ref(&insns); - let StageOutput { + let StageRunOutput { outputs: outputs_ty, cancel: cancel_ty, - } = Self::stage_output_ty(config); + } = StageRunOutput[config][this_ty]; assert_eq!(outputs_ty.capacity(), decode_output.insns.ty().capacity()); let mut outputs = outputs_ty.sim_value_default(); let mut add_output_insn = |insn: &SimValue, @@ -1192,7 +1572,7 @@ impl Stage for PostDecodeStageState> { let mut call_stack = start_call_stack.clone(); CallStack::push(&mut call_stack, start_pc); let retval = #[hdl(sim)] - StageOutput::<_, _, _> { + StageRunOutput::<_, _> { outputs, cancel: #[hdl(sim)] cancel_ty.HdlSome( @@ -1389,7 +1769,7 @@ impl Stage for PostDecodeStageState> { }; if *new_btb_entry.cmp_ne(predicted_btb_entry) { #[hdl(sim)] - StageOutput::<_, _, _> { + StageRunOutput::<_, _> { outputs: outputs_ty.sim_value_default(), cancel: #[hdl(sim)] cancel_ty.HdlSome( @@ -1406,7 +1786,7 @@ impl Stage for PostDecodeStageState> { } } else { #[hdl(sim)] - StageOutput::<_, _, _> { + StageRunOutput::<_, _> { outputs, cancel: #[hdl(sim)] cancel_ty.HdlNone(), @@ -1415,7 +1795,7 @@ impl Stage for PostDecodeStageState> { } #[hdl] - fn cancel(state: &mut SimValue, _cancel: &SimValue>>) { + fn cancel(state: &mut SimValue, _cancel: &SimValue>) { #[hdl(sim)] let Self { config: _ } = state; } @@ -1427,7 +1807,7 @@ struct ExecuteRetireStageInput> { retire_interface_per_insn: RetireToNextPcInterfacePerInsn, } -impl SimValueDefault for ExecuteRetireStageInput> { +impl SimValueDefault for ExecuteRetireStageInput { #[hdl] fn sim_value_default(self) -> SimValue { let Self { @@ -1443,7 +1823,7 @@ impl SimValueDefault for ExecuteRetireStageInput> { } #[hdl(no_static)] -struct ExecuteRetireStageState> { +struct ExecuteRetireStageState + PhantomConstCpuConfig> { config: C, } @@ -1453,7 +1833,23 @@ struct ExecuteRetireStageOutput> { config: C, } -impl SimValueDefault for ExecuteRetireStageState> { +impl SimValueDefault for ExecuteRetireStageOutput { + #[hdl] + fn sim_value_default(self) -> SimValue { + let Self { + train_branch_predictor, + config, + } = self; + #[hdl(sim)] + Self { + train_branch_predictor: #[hdl(sim)] + train_branch_predictor.HdlNone(), + config, + } + } +} + +impl SimValueDefault for ExecuteRetireStageState { #[hdl] fn sim_value_default(self) -> SimValue { let Self { config } = self; @@ -1462,7 +1858,7 @@ impl SimValueDefault for ExecuteRetireStageState> { } } -impl ResetSteps for ExecuteRetireStageState> { +impl ResetSteps for ExecuteRetireStageState { #[hdl] fn reset_step(this: &mut SimValue, _step: usize) -> ResetStatus { #[hdl(sim)] @@ -1471,49 +1867,84 @@ impl ResetSteps for ExecuteRetireStageState> { } } -impl Stage for ExecuteRetireStageState> { - type Input = PostDecodeStageOutput>; - type Inputs = ExecuteRetireStageInput>; - type Output = ExecuteRetireStageOutput>; +impl Stage for ExecuteRetireStageState { + type InputStages = PostDecodeStageState; + type Inputs = ExecuteRetireStageInput; + type Output = ExecuteRetireStageOutput; + type ToExternalPipeInputInterface = PostDecodeOutputInterface; + type FromExternalPipeOutputInterface = RetireToNextPcInterface; + type FromExternalPipeOutputItem = RetireToNextPcInterfacePerInsn; type MaxOutputsPerStep = ConstUsize<1>; - type InputQueueSize = CpuConfigRobSize>; - type OutputQueueSize = ConstUsize<1>; + type ExternalPipeIoWidth = CpuConfigFetchWidth; + type InputQueueSize = CpuConfigRobSize; + type OutputQueueSize = CpuConfigFetchWidth; - fn input_ty(config: PhantomConst) -> Self::Input { - PostDecodeStageOutput[config] - } - - fn inputs_ty(config: PhantomConst) -> Self::Inputs { + fn inputs_ty(config: C) -> Self::Inputs { ExecuteRetireStageInput[config] } - fn output_ty(config: PhantomConst) -> Self::Output { + fn output_ty(config: C) -> Self::Output { ExecuteRetireStageOutput[config] } - fn max_outputs_per_step( - _config: PhantomConst, - ) -> ::SizeType { + fn to_external_pipe_input_interface_ty(config: C) -> Self::ToExternalPipeInputInterface { + PostDecodeOutputInterface[config] + } + + fn from_external_pipe_output_interface_ty(config: C) -> Self::FromExternalPipeOutputInterface { + RetireToNextPcInterface[config] + } + + fn from_external_pipe_output_item_ty(config: C) -> Self::FromExternalPipeOutputItem { + RetireToNextPcInterfacePerInsn[config] + } + + fn max_outputs_per_step(_config: C) -> ::SizeType { ConstUsize } - fn input_queue_size( - config: PhantomConst, - ) -> ::SizeType { + fn external_pipe_io_width(config: C) -> ::SizeType { + CpuConfigFetchWidth[config] + } + + fn input_queue_size(config: C) -> ::SizeType { CpuConfigRobSize[config] } - fn output_queue_size( - _config: PhantomConst, - ) -> ::SizeType { - ConstUsize + fn output_queue_size(config: C) -> ::SizeType { + CpuConfigFetchWidth[config] + } + + fn cancel_in_progress_for_stage_ref( + cancel: &SimValue>, + ) -> &SimValue> { + &cancel.execute_retire + } + + fn cancel_in_progress_for_stage_mut( + cancel: &mut SimValue>, + ) -> &mut SimValue> { + &mut cancel.execute_retire + } + + #[hdl] + fn make_inputs( + input_stages_outputs: &SimValue>, + from_external_pipe_output_item: &SimValue, + ) -> SimValue { + #[hdl(sim)] + ExecuteRetireStageInput::<_> { + post_decode_stage_output: input_stages_outputs, + retire_interface_per_insn: from_external_pipe_output_item, + } } #[hdl] fn run( state: &mut SimValue, inputs: &SimValue, - ) -> SimValue>> { + ) -> SimValue> { + let this_ty = state.ty(); #[hdl(sim)] let Self { config } = state; let config = config.ty(); @@ -1541,10 +1972,10 @@ impl Stage for ExecuteRetireStageState> { config: _, } = post_decode_stage_output; assert_eq!(*id, insn.id, "instruction queuing out of sync"); - let StageOutput { + let StageRunOutput { outputs: outputs_ty, cancel: cancel_ty, - } = Self::stage_output_ty(config); + } = StageRunOutput[config][this_ty]; let mut branch_history = start_branch_history.clone(); let train_branch_predictor = #[hdl(sim)] if let HdlSome(taken) = cond_br_taken { @@ -1671,7 +2102,7 @@ impl Stage for ExecuteRetireStageState> { CallStackOp::Unknown => unreachable!(), } #[hdl(sim)] - StageOutput::<_, _, _> { + StageRunOutput::<_, _> { outputs: outputs_ty.new_sim( #[hdl(sim)] ExecuteRetireStageOutput::<_> { @@ -1694,7 +2125,7 @@ impl Stage for ExecuteRetireStageState> { } } else { #[hdl(sim)] - StageOutput::<_, _, _> { + StageRunOutput::<_, _> { outputs: outputs_ty.new_full_sim([ #[hdl(sim)] ExecuteRetireStageOutput::<_> { @@ -1709,7 +2140,7 @@ impl Stage for ExecuteRetireStageState> { } #[hdl] - fn cancel(state: &mut SimValue, _cancel: &SimValue>>) { + fn cancel(state: &mut SimValue, _cancel: &SimValue>) { #[hdl(sim)] let Self { config: _ } = state; } @@ -1794,6 +2225,26 @@ impl SimValueDefault for SimOnly { } } +impl SimValueDefault for PhantomConst { + fn sim_value_default(self) -> SimValue { + self.to_sim_value() + } +} + +impl SimValueDefault for () { + fn sim_value_default(self) -> SimValue { + self.to_sim_value() + } +} + +impl SimValueDefault for (T1, T2) { + #[hdl] + fn sim_value_default(self) -> SimValue { + #[hdl(sim)] + (self.0.sim_value_default(), self.1.sim_value_default()) + } +} + impl SimValueDefault for ArrayVec { fn sim_value_default(self) -> SimValue { self.new_sim(self.element().sim_value_default()) @@ -2231,6 +2682,8 @@ struct Queue { head: UIntInRangeType, Capacity>, /// exclusive tail: UIntInRangeType, Capacity>, + /// used to disambiguate between a full and an empty queue + eq_head_tail_means_full: Bool, } impl Queue { @@ -2241,21 +2694,27 @@ impl Queue { assert_ne!(self.capacity(), 0); (pos + 1) % self.capacity() } + fn nth_pos_after(self, pos: usize, nth: usize) -> usize { + assert_ne!(self.capacity(), 0); + (pos + nth) % self.capacity() + } fn prev_pos(self, pos: usize) -> usize { assert_ne!(self.capacity(), 0); (pos + self.capacity() - 1) % self.capacity() } fn is_empty(this: &SimValue) -> bool { - this.head == this.tail + this.head == this.tail && !*this.eq_head_tail_means_full } fn is_full(this: &SimValue) -> bool { - let head = *this.head; - let tail = *this.tail; - this.ty().next_pos(head) == tail + this.head == this.tail && *this.eq_head_tail_means_full } fn len(this: &SimValue) -> usize { let capacity = this.ty().capacity(); - (*this.tail + capacity - *this.head) % capacity + if Self::is_full(this) { + capacity + } else { + (*this.tail + capacity - *this.head) % capacity + } } fn space_left(this: &SimValue) -> usize { this.ty().capacity() - Self::len(this) @@ -2263,6 +2722,7 @@ impl Queue { fn clear(this: &mut SimValue) { *this.head = 0; *this.tail = 0; + *this.eq_head_tail_means_full = false; } fn try_push(this: &mut SimValue, value: impl ToSimValueWithType) -> Result<(), ()> { if Self::is_full(this) { @@ -2271,6 +2731,7 @@ impl Queue { let head = *this.head; let head = this.ty().next_pos(head); *this.head = head; + *this.eq_head_tail_means_full = true; let data = &mut this.data[head]; *data = value.to_sim_value_with_type(data.ty()); Ok(()) @@ -2284,6 +2745,7 @@ impl Queue { let data = this.data[head].clone(); let head = this.ty().prev_pos(head); *this.head = head; + *this.eq_head_tail_means_full = false; Some(data) } } @@ -2294,6 +2756,11 @@ impl Queue { Some(this.data[*this.tail].clone()) } } + fn peek_iter( + this: &SimValue, + ) -> impl Clone + DoubleEndedIterator> + ExactSizeIterator { + (0..Self::len(this)).map(|nth| this.data[this.ty().nth_pos_after(*this.tail, nth)].clone()) + } fn pop(this: &mut SimValue) -> Option> { if Self::is_empty(this) { None @@ -2301,6 +2768,7 @@ impl Queue { let tail = *this.tail; let data = this.data[tail].clone(); *this.tail = this.ty().next_pos(tail); + *this.eq_head_tail_means_full = false; Some(data) } } @@ -2309,7 +2777,12 @@ impl Queue { impl SimValueDefault for Queue { #[hdl] fn sim_value_default(self) -> SimValue { - let Self { data, head, tail } = self; + let Self { + data, + head, + tail, + eq_head_tail_means_full: _, + } = self; #[hdl(sim)] Queue:: { data: repeat( @@ -2318,6 +2791,7 @@ impl SimValueDefault for Queue ), head: 0usize.to_sim_value_with_type(head), tail: 0usize.to_sim_value_with_type(tail), + eq_head_tail_means_full: false, } } } @@ -2326,55 +2800,268 @@ impl ResetSteps for Queue { #[hdl] fn reset_step(this: &mut SimValue, step: usize) -> ResetStatus { #[hdl(sim)] - let Queue:: { data, head, tail } = this; + let Queue:: { + data, + head, + tail, + eq_head_tail_means_full, + } = this; **head = 0; **tail = 0; + **eq_head_tail_means_full = false; ResetSteps::reset_step(data, step) } } #[hdl(no_static)] -struct StageWithQueues> { - state: S, - input_queue: Queue, StageInputQueueSize>, - output_queue: Queue, StageOutputQueueSize>, -} - -impl StageWithQueues> { - FIXME +struct CancelInProgressForStageWithQueues< + C: PhantomConstGet + PhantomConstCpuConfig, + S: Type + Stage, +> { + cancel_state: Bool, + input_queue_to_cancel: UIntInRangeInclusiveType, StageInputQueueSize>, + output_queue_to_cancel: UIntInRangeInclusiveType, StageOutputQueueSize>, } #[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, +struct StageWithQueues + PhantomConstCpuConfig, S: Type + Stage> { + input_queue: Queue, StageInputQueueSize>, + state: S, + output_queue: Queue, StageOutputQueueSize>, config: C, } -impl CancelInProgress> { +#[hdl(no_static)] +struct StageWithQueuesInputs< + C: PhantomConstGet + PhantomConstCpuConfig, + S: Type + Stage, +> { + to_external_pipe_input_input_ready: StageExternalPipeIoReady, + to_external_pipe_input_cancel_ready: Bool, + from_external_pipe_output_data: StageFromExternalPipeOutputData, +} + +#[hdl(no_static)] +struct StageWithQueuesOutputs< + C: PhantomConstGet + PhantomConstCpuConfig, + S: Type + Stage, +> { + to_external_pipe_input_input: StageToExternalPipeInputInput, + to_external_pipe_input_cancel: StageToExternalPipeInputCancel, + from_external_pipe_output_ready: StageExternalPipeIoReady, +} + +enum CancelResult { + Done, + InProgress, +} + +impl> StageWithQueues { + #[hdl] + fn outputs( + this: &SimValue, + cancel: Option<&SimValue>>, + input_stages_output_queues: >::SimValueOutputQueueRefs<'_>, + ) -> SimValue> { + #[hdl(sim)] + let Self { + input_queue, + state, + output_queue, + config, + } = this; + let config = config.ty(); + let state_ty = state.ty(); + let ty = StageWithQueuesOutputs[config][state_ty]; + let cancel_ty = ty.to_external_pipe_input_cancel; + if let Some(cancel) = cancel { + let input_queue_to_cancel = + *S::cancel_in_progress_for_stage_ref(cancel).input_queue_to_cancel; + let to_external_pipe_input_cancel = if input_queue_to_cancel > 0 { + #[hdl(sim)] + cancel_ty.HdlSome(input_queue_to_cancel.to_sim_value_with_type(cancel_ty.HdlSome)) + } else { + #[hdl(sim)] + cancel_ty.HdlNone() + }; + #[hdl(sim)] + StageWithQueuesOutputs::<_, _> { + to_external_pipe_input_input: ty.to_external_pipe_input_input.sim_value_default(), + to_external_pipe_input_cancel, + from_external_pipe_output_ready: 0usize + .to_sim_value_with_type(ty.from_external_pipe_output_ready), + } + } else { + let mut to_external_pipe_input_input = + ty.to_external_pipe_input_input.sim_value_default(); + for input in S::InputStages::peek_output_queues( + input_stages_output_queues, + Queue::space_left(&this.input_queue), + ) { + let Ok(_) = ArrayVec::try_push_sim(&mut to_external_pipe_input_input, input) else { + break; + }; + } + #[hdl(sim)] + StageWithQueuesOutputs::<_, _> { + to_external_pipe_input_input, + to_external_pipe_input_cancel: #[hdl(sim)] + cancel_ty.HdlNone(), + from_external_pipe_output_ready: Queue::space_left(output_queue) + .min(Size::as_usize(S::external_pipe_io_width(config))) + .to_sim_value_with_type(ty.from_external_pipe_output_ready), + } + } + } + #[hdl] + fn cancel( + this: &mut SimValue, + cancel: &mut SimValue>, + inputs: &SimValue>, + last_outputs: &SimValue>, + input_stages_output_queues: >::SimValueOutputQueueMuts<'_>, + ) -> CancelResult { + #[hdl(sim)] + let Self { + input_queue, + state, + output_queue, + config, + } = this; + let config = config.ty(); + let state_ty = state.ty(); + #[hdl(sim)] + let CancelInProgressForStageWithQueues::<_, _> { + cancel_state, + input_queue_to_cancel, + output_queue_to_cancel, + } = S::cancel_in_progress_for_stage_mut(cancel); + #[hdl(sim)] + let StageWithQueuesInputs::<_, _> { + to_external_pipe_input_input_ready: _, + to_external_pipe_input_cancel_ready, + from_external_pipe_output_data: _, + } = inputs; + #[hdl(sim)] + let StageWithQueuesOutputs::<_, _> { + to_external_pipe_input_input, + to_external_pipe_input_cancel, + from_external_pipe_output_ready, + } = last_outputs; + assert_eq!(**ArrayVec::len_sim(to_external_pipe_input_input), 0); + #[hdl(sim)] + if let HdlNone = to_external_pipe_input_cancel { + unreachable!(); + } + assert_eq!(**from_external_pipe_output_ready, 0); + if !**to_external_pipe_input_cancel_ready { + return CancelResult::InProgress; + } + for _ in 0..std::mem::replace(input_queue_to_cancel, 0) { + let Some(_) = Queue::undo_push(input_queue) else { + unreachable!(); + }; + } + for _ in 0..std::mem::replace(output_queue_to_cancel, 0) { + let Some(_) = Queue::undo_push(output_queue) else { + unreachable!(); + }; + } + if std::mem::replace(cancel_state, false) { + S::cancel(state, &cancel.cancel); + } + CancelResult::Done + } + #[hdl] + fn make_cancel_all( + this: &SimValue, + ) -> SimValue> { + #[hdl(sim)] + let Self { + input_queue, + state, + output_queue, + config, + } = this; + let CancelInProgressForStageWithQueues { + cancel_state: _, + input_queue_to_cancel, + output_queue_to_cancel, + } = CancelInProgressForStageWithQueues[config.ty()][state.ty()]; + #[hdl(sim)] + CancelInProgressForStageWithQueues::<_, _> { + cancel_state: true, + input_queue_to_cancel: Queue::len(input_queue) + .to_sim_value_with_type(input_queue_to_cancel), + output_queue_to_cancel: Queue::len(output_queue) + .to_sim_value_with_type(output_queue_to_cancel), + } + } + #[hdl] + fn run( + this: &mut SimValue, + inputs: &SimValue>, + last_outputs: &SimValue>, + input_stages_output_queues: >::SimValueOutputQueueMuts<'_>, + ) -> Result< + (), + ( + SimValue>, + SimValue>, + ), + > { + #[hdl(sim)] + let Self { + input_queue, + state, + output_queue, + config, + } = this; + let config = config.ty(); + let state_ty = state.ty(); + #[hdl(sim)] + let StageWithQueuesInputs::<_, _> { + to_external_pipe_input_input_ready, + to_external_pipe_input_cancel_ready: _, + from_external_pipe_output_data, + } = inputs; + #[hdl(sim)] + let StageWithQueuesOutputs::<_, _> { + to_external_pipe_input_input, + to_external_pipe_input_cancel, + from_external_pipe_output_ready, + } = last_outputs; + #[hdl(sim)] + if let HdlSome(_) = to_external_pipe_input_cancel { + unreachable!(); + } + let to_external_pipe_input_input_len = **ArrayVec::len_sim(to_external_pipe_input_input); + for _ in 0..to_external_pipe_input_input_len.min(**to_external_pipe_input_input_ready) { + let Some(v) = S::InputStages::pop_output_queues(input_stages_output_queues) else { + unreachable!(); + }; + } + todo!() + } +} + +#[hdl(no_static)] +struct CancelInProgress + PhantomConstCpuConfig> { + cancel: Cancel, + next_pc: CancelInProgressForStageWithQueues>, + br_pred: CancelInProgressForStageWithQueues>, + fetch_decode: CancelInProgressForStageWithQueues>, + post_decode: CancelInProgressForStageWithQueues>, + execute_retire: CancelInProgressForStageWithQueues>, + config: C, +} + +impl CancelInProgress { #[hdl] fn to_fetch_cancel_data( this: &SimValue, - ) -> SimValue< - HdlOption< - UIntInRangeInclusiveType< - ConstUsize<1>, - CpuConfigMaxFetchesInFlight>, - >, - >, - > { + ) -> SimValue, CpuConfigMaxFetchesInFlight>>> + { let NextPcStateOutputs { to_fetch_cancel_data, .. @@ -2406,7 +3093,7 @@ pub struct StatesAndQueues> { config: C, } -impl SimValueDefault for StatesAndQueues> { +impl SimValueDefault for StatesAndQueues { #[hdl] fn sim_value_default(self) -> SimValue { let Self { @@ -2445,7 +3132,7 @@ impl SimValueDefault for StatesAndQueues> { } } -impl ResetSteps for StatesAndQueues> { +impl ResetSteps for StatesAndQueues { #[hdl] fn reset_step(this: &mut SimValue, step: usize) -> ResetStatus { #[hdl(sim)] @@ -2493,12 +3180,12 @@ impl ResetSteps for StatesAndQueues> { } } -impl StatesAndQueues> { +impl StatesAndQueues { #[hdl] fn step_no_cancel( this: &mut SimValue, - inputs: SimValue>>, - ) -> SimValue>>> { + inputs: SimValue>, + ) -> SimValue>> { #[hdl(sim)] let NextPcStateStepInputs::<_> { to_fetch_fetch_triggered, @@ -2532,7 +3219,7 @@ impl StatesAndQueues> { todo!() } #[hdl(sim)] - let StageOutput::<_, _, _> { outputs, cancel } = + let StageRunOutput::<_, _> { outputs, cancel } = Stage::run(next_pc_stage_state, &().to_sim_value()); retval @@ -2540,8 +3227,8 @@ impl StatesAndQueues> { #[hdl] fn step_cancel( this: &mut SimValue, - cancel_opt: &mut SimValue>>>, - inputs: SimValue>>, + cancel_opt: &mut SimValue>>, + inputs: SimValue>, ) { #[hdl(sim)] let NextPcStateStepInputs::<_> { @@ -2649,7 +3336,7 @@ pub struct NextPcState> { cancel: HdlOption>, } -impl SimValueDefault for NextPcState> { +impl SimValueDefault for NextPcState { #[hdl] fn sim_value_default(self) -> SimValue { let Self { @@ -2664,7 +3351,7 @@ impl SimValueDefault for NextPcState> { } } -impl ResetSteps for NextPcState> { +impl ResetSteps for NextPcState { #[hdl] fn reset_step(this: &mut SimValue, step: usize) -> ResetStatus { #[hdl(sim)] @@ -2698,9 +3385,9 @@ struct NextPcStateStepInputs> { from_retire_inner_triggered: HdlOption>, } -impl NextPcState> { +impl NextPcState { #[hdl] - fn outputs(this: &SimValue) -> SimValue>> { + fn outputs(this: &SimValue) -> SimValue> { #[hdl(sim)] let Self { states_and_queues, @@ -2785,10 +3472,7 @@ impl NextPcState> { } } #[hdl] - fn step( - this: &mut SimValue, - inputs: SimValue>>, - ) { + fn step(this: &mut SimValue, inputs: SimValue>) { #[hdl(sim)] let Self { states_and_queues,