WIP: adding ExecuteToUnitInterface::is_no_longer_speculative_prediction

This commit is contained in:
Jacob Lifshay 2026-07-31 16:51:04 -07:00
parent a81d85d9c0
commit 7038be9268
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
6 changed files with 133 additions and 24 deletions

View file

@ -203,6 +203,16 @@ pub struct UnitMOpCantCauseCancel<C: PhantomConstGet<CpuConfig>> {
pub config: C, pub config: C,
} }
/// This tells the Unit that if [`Self::if_cant_cause_cancel_id`] can no longer cause a cancel
/// (either via [`UnitMOpCantCauseCancel`] or [`UnitFinishCauseCancel`] without a cancel),
/// then [`Self::then_no_longer_speculative_id`] will no longer be speculative.
#[hdl(no_static)]
pub struct UnitMOpIsNoLongerSpeculativePrediction<C: PhantomConstGet<CpuConfig>> {
pub if_cant_cause_cancel_id: MOpId,
pub then_no_longer_speculative_id: MOpId,
pub config: C,
}
/// Interface from the Rename/Execute/Retire control logic to a single Unit. /// Interface from the Rename/Execute/Retire control logic to a single Unit.
/// ///
/// ## State diagram for a single &micro;Op in a Unit /// ## State diagram for a single &micro;Op in a Unit
@ -223,6 +233,8 @@ pub struct ExecuteToUnitInterface<C: PhantomConstGet<CpuConfig>> {
pub inputs_ready: HdlOption<UnitInputsReady<C>>, pub inputs_ready: HdlOption<UnitInputsReady<C>>,
/// if [`Self::unit_outputs_ready`] is `false`, then this is always [`HdlNone`] /// if [`Self::unit_outputs_ready`] is `false`, then this is always [`HdlNone`]
pub is_no_longer_speculative: HdlOption<UnitMOpIsNoLongerSpeculative<C>>, pub is_no_longer_speculative: HdlOption<UnitMOpIsNoLongerSpeculative<C>>,
/// if [`Self::unit_outputs_ready`] is `false`, then this is always [`HdlNone`]
pub is_no_longer_speculative_prediction: HdlOption<UnitMOpIsNoLongerSpeculativePrediction<C>>,
/// this uses [`Self::unit_outputs_ready`] as a shared ready flag /// this uses [`Self::unit_outputs_ready`] as a shared ready flag
#[hdl(flip)] #[hdl(flip)]
pub cant_cause_cancel: HdlOption<UnitMOpCantCauseCancel<C>>, pub cant_cause_cancel: HdlOption<UnitMOpCantCauseCancel<C>>,
@ -1263,31 +1275,62 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
fn get_unit_mop_is_no_longer_speculative( fn get_unit_mop_is_no_longer_speculative(
&self, &self,
unit_index: usize, unit_index: usize,
) -> SimValue<HdlOption<UnitMOpIsNoLongerSpeculative<C>>> { ) -> Option<SimValue<UnitMOpIsNoLongerSpeculative<C>>> {
let ret_ty = HdlOption[UnitMOpIsNoLongerSpeculative[self.config]];
if self.is_canceling() { if self.is_canceling() {
let retval = #[hdl(sim)] return None;
ret_ty.HdlNone();
return retval; // separate variable to work around rust-analyzer parse error
} }
for rob in self.rob.renamed() { for rob in self.rob.renamed() {
if rob.unit_index == unit_index if rob.unit_index == unit_index
&& !rob.is_speculative && !rob.is_speculative
&& let Some(_) = rob.mop_in_unit_state.without_speculative() && let Some(_) = rob.mop_in_unit_state.without_speculative()
{ {
let retval = #[hdl(sim)] return Some(
ret_ty.HdlSome(
#[hdl(sim)] #[hdl(sim)]
UnitMOpIsNoLongerSpeculative::<_> { UnitMOpIsNoLongerSpeculative::<_> {
id: &rob.mop.id, id: &rob.mop.id,
config: self.config, config: self.config,
}, },
); );
return retval; // separate variable to work around rust-analyzer parse error
} }
} }
None
}
#[hdl]
fn get_unit_mop_is_no_longer_speculative_prediction(
&self,
unit_index: usize,
) -> Option<SimValue<UnitMOpIsNoLongerSpeculativePrediction<C>>> {
if self.is_canceling() {
return None;
}
let mut renamed_iter = self.rob.renamed();
let if_cant_cause_cancel_id = loop {
let Some(renamed) = renamed_iter.next() else {
return None;
};
if renamed.can_cause_cancel() {
if renamed.unit_index != unit_index {
return None;
}
break &renamed.mop.id;
}
};
for renamed in renamed_iter {
if renamed.unit_index == unit_index {
return Some(
#[hdl(sim)] #[hdl(sim)]
ret_ty.HdlNone() UnitMOpIsNoLongerSpeculativePrediction::<_> {
if_cant_cause_cancel_id,
then_no_longer_speculative_id: &renamed.mop.id,
config: self.config,
},
);
}
if renamed.can_cause_cancel() {
break;
}
}
None
} }
#[hdl] #[hdl]
fn unit_output_ready(&mut self, output_ready: SimValue<UnitOutputReady<C>>) { fn unit_output_ready(&mut self, output_ready: SimValue<UnitOutputReady<C>>) {
@ -1618,21 +1661,8 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
}; };
} }
for renamed in self.rob.renamed_mut() { for renamed in self.rob.renamed_mut() {
let can_cause_cancel = match renamed.mop_in_unit_state {
MOpInUnitState::NotYetEnqueued => true,
MOpInUnitState::InputsNotReadySpeculative { can_cause_cancel } => can_cause_cancel,
MOpInUnitState::InputsReady {
speculative: _,
can_cause_cancel,
} => can_cause_cancel,
MOpInUnitState::OutputReady {
speculative: _,
can_cause_cancel,
} => can_cause_cancel,
MOpInUnitState::FinishedAndOrCausedCancel => renamed.caused_cancel.is_some(),
};
renamed.is_speculative = false; renamed.is_speculative = false;
if can_cause_cancel { if renamed.can_cause_cancel() {
break; break;
} }
} }
@ -1719,6 +1749,7 @@ async fn rename_execute_retire_run(
enqueue, enqueue,
inputs_ready, inputs_ready,
is_no_longer_speculative, is_no_longer_speculative,
is_no_longer_speculative_prediction,
cant_cause_cancel: _, cant_cause_cancel: _,
output_ready: _, output_ready: _,
finish_cause_cancel: _, finish_cause_cancel: _,
@ -1747,6 +1778,11 @@ async fn rename_execute_retire_run(
state.get_unit_mop_is_no_longer_speculative(unit_index), state.get_unit_mop_is_no_longer_speculative(unit_index),
) )
.await; .await;
sim.write(
is_no_longer_speculative_prediction,
state.get_unit_mop_is_no_longer_speculative_prediction(unit_index),
)
.await;
sim.write(unit_outputs_ready, !is_canceling).await; sim.write(unit_outputs_ready, !is_canceling).await;
} }
sim.wait_for_clock_edge(cd.clk).await; sim.wait_for_clock_edge(cd.clk).await;
@ -1767,6 +1803,7 @@ async fn rename_execute_retire_run(
enqueue, enqueue,
inputs_ready, inputs_ready,
is_no_longer_speculative, is_no_longer_speculative,
is_no_longer_speculative_prediction: _, // no action necessary
cant_cause_cancel, cant_cause_cancel,
output_ready, output_ready,
finish_cause_cancel, finish_cause_cancel,
@ -1959,6 +1996,7 @@ pub fn rename_execute_retire(config: PhantomConst<CpuConfig>) {
enqueue, enqueue,
inputs_ready, inputs_ready,
is_no_longer_speculative, is_no_longer_speculative,
is_no_longer_speculative_prediction,
cant_cause_cancel: _, cant_cause_cancel: _,
output_ready: _, output_ready: _,
finish_cause_cancel: _, finish_cause_cancel: _,
@ -1992,6 +2030,12 @@ pub fn rename_execute_retire(config: PhantomConst<CpuConfig>) {
(is_no_longer_speculative.ty()).HdlNone(), (is_no_longer_speculative.ty()).HdlNone(),
) )
.await; .await;
sim.write(
is_no_longer_speculative_prediction,
#[hdl(sim)]
(is_no_longer_speculative_prediction.ty()).HdlNone(),
)
.await;
sim.write(unit_outputs_ready, false).await; sim.write(unit_outputs_ready, false).await;
} }
}, },

View file

@ -173,6 +173,21 @@ impl<C: PhantomConstCpuConfig> RobEntry<C> {
} }
} }
} }
pub(crate) fn can_cause_cancel(&self) -> bool {
match self.mop_in_unit_state {
MOpInUnitState::NotYetEnqueued => true,
MOpInUnitState::InputsNotReadySpeculative { can_cause_cancel } => can_cause_cancel,
MOpInUnitState::InputsReady {
speculative: _,
can_cause_cancel,
} => can_cause_cancel,
MOpInUnitState::OutputReady {
speculative: _,
can_cause_cancel,
} => can_cause_cancel,
MOpInUnitState::FinishedAndOrCausedCancel => self.caused_cancel.is_some(),
}
}
} }
#[hdl] #[hdl]

View file

@ -204,6 +204,7 @@ fn connect_to_unit_nop<C: Type + PhantomConstGet<CpuConfig>>(
enqueue, enqueue,
inputs_ready, inputs_ready,
is_no_longer_speculative, is_no_longer_speculative,
is_no_longer_speculative_prediction,
cant_cause_cancel: _, cant_cause_cancel: _,
output_ready: _, output_ready: _,
finish_cause_cancel: _, finish_cause_cancel: _,
@ -218,6 +219,10 @@ fn connect_to_unit_nop<C: Type + PhantomConstGet<CpuConfig>>(
is_no_longer_speculative, is_no_longer_speculative,
is_no_longer_speculative.ty().HdlNone(), is_no_longer_speculative.ty().HdlNone(),
); );
connect(
is_no_longer_speculative_prediction,
is_no_longer_speculative_prediction.ty().HdlNone(),
);
connect(unit_outputs_ready, false); connect(unit_outputs_ready, false);
connect(cancel_all.data, HdlNone()); connect(cancel_all.data, HdlNone());
} }
@ -506,6 +511,7 @@ impl<C: PhantomConstCpuConfig, MaxMOpCount: Size> DecodeAndRunSingleInsnState<C,
enqueue, enqueue,
inputs_ready, inputs_ready,
is_no_longer_speculative, is_no_longer_speculative,
is_no_longer_speculative_prediction,
cant_cause_cancel: _, // we don't track if it can cause a cancel cant_cause_cancel: _, // we don't track if it can cause a cancel
output_ready, output_ready,
finish_cause_cancel, finish_cause_cancel,
@ -513,6 +519,10 @@ impl<C: PhantomConstCpuConfig, MaxMOpCount: Size> DecodeAndRunSingleInsnState<C,
cancel_all, cancel_all,
config: _, config: _,
} = to_unit; } = to_unit;
connect(
is_no_longer_speculative_prediction,
is_no_longer_speculative_prediction.ty().HdlNone(),
);
connect(unit_outputs_ready, true); connect(unit_outputs_ready, true);
connect(cancel_all.data, HdlNone()); connect(cancel_all.data, HdlNone());
#[hdl] #[hdl]

View file

@ -1260,6 +1260,7 @@ pub fn alu_branch(
enqueue, enqueue,
inputs_ready, inputs_ready,
is_no_longer_speculative: _, // we don't care about being speculative for these instructions is_no_longer_speculative: _, // we don't care about being speculative for these instructions
is_no_longer_speculative_prediction: _,
cant_cause_cancel, cant_cause_cancel,
output_ready, output_ready,
finish_cause_cancel, finish_cause_cancel,

View file

@ -988,6 +988,7 @@ async fn load_store_impl(
enqueue, enqueue,
inputs_ready: _, inputs_ready: _,
is_no_longer_speculative: _, is_no_longer_speculative: _,
is_no_longer_speculative_prediction: _,
cant_cause_cancel, cant_cause_cancel,
output_ready, output_ready,
finish_cause_cancel, finish_cause_cancel,
@ -1042,6 +1043,7 @@ async fn load_store_impl(
enqueue, enqueue,
inputs_ready, inputs_ready,
is_no_longer_speculative, is_no_longer_speculative,
is_no_longer_speculative_prediction,
cant_cause_cancel, cant_cause_cancel,
output_ready, output_ready,
finish_cause_cancel, finish_cause_cancel,
@ -1066,6 +1068,15 @@ async fn load_store_impl(
{ {
state.from_execute_is_no_longer_speculative(is_no_longer_speculative); state.from_execute_is_no_longer_speculative(is_no_longer_speculative);
} }
#[hdl(sim)]
if let HdlSome(is_no_longer_speculative_prediction) = sim
.read_past(is_no_longer_speculative_prediction, cd.clk)
.await
{
state.from_execute_is_no_longer_speculative_prediction(
is_no_longer_speculative_prediction,
);
}
if sim.read_past_bool(unit_outputs_ready, cd.clk).await { if sim.read_past_bool(unit_outputs_ready, cd.clk).await {
#[hdl(sim)] #[hdl(sim)]
if let HdlSome(cant_cause_cancel) = sim.read_past(cant_cause_cancel, cd.clk).await { if let HdlSome(cant_cause_cancel) = sim.read_past(cant_cause_cancel, cd.clk).await {
@ -1221,6 +1232,7 @@ pub fn load_store(
enqueue, enqueue,
inputs_ready: _, inputs_ready: _,
is_no_longer_speculative: _, is_no_longer_speculative: _,
is_no_longer_speculative_prediction: _,
cant_cause_cancel, cant_cause_cancel,
output_ready, output_ready,
finish_cause_cancel, finish_cause_cancel,

View file

@ -2149,6 +2149,7 @@ async fn load_store_tester_impl<C: PhantomConstCpuConfig>(
enqueue, enqueue,
inputs_ready, inputs_ready,
is_no_longer_speculative, is_no_longer_speculative,
is_no_longer_speculative_prediction,
cant_cause_cancel: _, cant_cause_cancel: _,
output_ready: _, output_ready: _,
finish_cause_cancel: _, finish_cause_cancel: _,
@ -2168,6 +2169,11 @@ async fn load_store_tester_impl<C: PhantomConstCpuConfig>(
state.to_load_store_is_no_longer_speculative(), state.to_load_store_is_no_longer_speculative(),
) )
.await; .await;
sim.write(
is_no_longer_speculative_prediction,
state.to_load_store_is_no_longer_speculative_prediction(),
)
.await;
} else { } else {
sim.write(enqueue.data, enqueue.ty().data.HdlNone()).await; sim.write(enqueue.data, enqueue.ty().data.HdlNone()).await;
sim.write(inputs_ready, inputs_ready.ty().HdlNone()).await; sim.write(inputs_ready, inputs_ready.ty().HdlNone()).await;
@ -2176,6 +2182,11 @@ async fn load_store_tester_impl<C: PhantomConstCpuConfig>(
is_no_longer_speculative.ty().HdlNone(), is_no_longer_speculative.ty().HdlNone(),
) )
.await; .await;
sim.write(
is_no_longer_speculative_prediction,
is_no_longer_speculative_prediction.ty().HdlNone(),
)
.await;
} }
sim.write(cancel_all.data, state.to_load_store_cancel_all()) sim.write(cancel_all.data, state.to_load_store_cancel_all())
.await; .await;
@ -2190,6 +2201,7 @@ async fn load_store_tester_impl<C: PhantomConstCpuConfig>(
enqueue, enqueue,
inputs_ready, inputs_ready,
is_no_longer_speculative, is_no_longer_speculative,
is_no_longer_speculative_prediction,
cant_cause_cancel, cant_cause_cancel,
output_ready, output_ready,
finish_cause_cancel, finish_cause_cancel,
@ -2213,6 +2225,15 @@ async fn load_store_tester_impl<C: PhantomConstCpuConfig>(
{ {
state.handle_to_load_store_is_no_longer_speculative(is_no_longer_speculative); state.handle_to_load_store_is_no_longer_speculative(is_no_longer_speculative);
} }
#[hdl(sim)]
if let HdlSome(is_no_longer_speculative_prediction) = sim
.read_past(is_no_longer_speculative_prediction, cd.clk)
.await
{
state.handle_to_load_store_is_no_longer_speculative_prediction(
is_no_longer_speculative_prediction,
);
}
if sim.read_past_bool(unit_outputs_ready, cd.clk).await { if sim.read_past_bool(unit_outputs_ready, cd.clk).await {
#[hdl(sim)] #[hdl(sim)]
if let HdlSome(cant_cause_cancel) = sim.read_past(cant_cause_cancel, cd.clk).await { if let HdlSome(cant_cause_cancel) = sim.read_past(cant_cause_cancel, cd.clk).await {
@ -2293,6 +2314,7 @@ fn load_store_tester(config: PhantomConst<CpuConfig>) {
enqueue, enqueue,
inputs_ready, inputs_ready,
is_no_longer_speculative, is_no_longer_speculative,
is_no_longer_speculative_prediction,
cant_cause_cancel: _, cant_cause_cancel: _,
output_ready: _, output_ready: _,
finish_cause_cancel: _, finish_cause_cancel: _,
@ -2318,6 +2340,11 @@ fn load_store_tester(config: PhantomConst<CpuConfig>) {
is_no_longer_speculative.ty().HdlNone(), is_no_longer_speculative.ty().HdlNone(),
) )
.await; .await;
sim.write(
is_no_longer_speculative_prediction,
is_no_longer_speculative_prediction.ty().HdlNone(),
)
.await;
sim.write(unit_outputs_ready, false).await; sim.write(unit_outputs_ready, false).await;
sim.write(cancel_all.data, HdlNone()).await; sim.write(cancel_all.data, HdlNone()).await;
sim.write(test_passed, false).await; sim.write(test_passed, false).await;