implement register fences and use for L2 reg file writes and when running out of L2 reg file output regs

fixes deadlock when running rename_execute_retire_save_restore_gprs
This commit is contained in:
Jacob Lifshay 2026-05-20 23:37:23 -07:00
parent 3e08a282ec
commit bf2cb688c7
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
6 changed files with 198817 additions and 95647 deletions

View file

@ -256,16 +256,21 @@ impl<C: PhantomConstCpuConfig> SimValueDefault for RenameExecuteRetireDebugState
} }
#[hdl(no_static)] #[hdl(no_static)]
enum RenameTableEntry<C: PhantomConstGet<CpuConfig>> { struct RenameTableEntry<C: PhantomConstGet<CpuConfig>> {
L1(PRegNum<C>), l1: HdlOption<PRegNum<C>>,
L2(L2RegNum), l2: HdlOption<L2RegNum>,
} }
impl<C: PhantomConstCpuConfig> RenameTableEntry<C> { impl<C: PhantomConstCpuConfig> RenameTableEntry<C> {
#[hdl] #[hdl]
fn const_zero(self) -> SimValue<Self> { fn const_zero(self) -> SimValue<Self> {
#[hdl(sim)] #[hdl(sim)]
self.L1(self.L1.const_zero()) Self {
l1: #[hdl(sim)]
(self.l1).HdlSome(self.l1.HdlSome.const_zero()),
l2: #[hdl(sim)]
HdlNone(),
}
} }
} }
@ -313,6 +318,7 @@ enum RenameTableUpdate<C: PhantomConstCpuConfig> {
dest: SimValue<L2RegNum>, dest: SimValue<L2RegNum>,
src: SimValue<PRegNum<C>>, src: SimValue<PRegNum<C>>,
}, },
DropAllL2RegFileOutputs,
} }
impl<C: PhantomConstCpuConfig> RenameTable<C> { impl<C: PhantomConstCpuConfig> RenameTable<C> {
@ -352,39 +358,69 @@ impl<C: PhantomConstCpuConfig> RenameTable<C> {
} }
RenameTableUpdate::UpdateForReadL2Reg { dest, src } => { RenameTableUpdate::UpdateForReadL2Reg { dest, src } => {
let new = #[hdl(sim)] let new = #[hdl(sim)]
(RenameTableEntry[self.config]).L1(dest); RenameTableEntry::<_> {
l1: #[hdl(sim)]
(HdlOption[dest.ty()]).HdlSome(dest),
l2: #[hdl(sim)]
HdlSome(src),
};
for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() { for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() {
#[hdl(sim)] #[hdl(sim)]
match entry.inner() { if let HdlSome(l2) = &entry.inner().l2 {
RenameTableEntry::<_>::L1(_) => {} if L2RegNum::value_sim(l2) == L2RegNum::value_sim(src) {
RenameTableEntry::<_>::L2(l2) => { println!(
if L2RegNum::value_sim(l2) == L2RegNum::value_sim(src) { "{rename_table_name}: UpdateForReadL2Reg: {unrenamed_reg_num:#x} \
println!( updating from {entry:?} to {new:?}",
"{rename_table_name}: UpdateForReadL2Reg: {unrenamed_reg_num:#x} \ );
updating from {entry:?} to {new:?}", #[hdl(sim)]
); if let HdlSome(_) = &entry.inner().l1 {
*entry = new.to_trace_as_string(); unreachable!("l1 should be HdlNone: {entry:?}");
} }
*entry = new.to_trace_as_string();
} }
} }
} }
} }
RenameTableUpdate::UpdateForWriteL2Reg { dest, src } => { RenameTableUpdate::UpdateForWriteL2Reg { dest, src } => {
let new = #[hdl(sim)] let new = #[hdl(sim)]
(RenameTableEntry[self.config]).L2(dest); RenameTableEntry::<_> {
l1: #[hdl(sim)]
(HdlOption[src.ty()]).HdlNone(),
l2: #[hdl(sim)]
HdlSome(dest),
};
for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() { for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() {
#[hdl(sim)] #[hdl(sim)]
match entry.inner() { if let HdlSome(l1) = &entry.inner().l1 {
RenameTableEntry::<_>::L1(l1) => { if l1 == src {
if l1 == src { println!(
println!( "{rename_table_name}: UpdateForWriteL2Reg: {unrenamed_reg_num:#x} \
"{rename_table_name}: UpdateForWriteL2Reg: {unrenamed_reg_num:#x} \ updating from {entry:?} to {new:?}",
updating from {entry:?} to {new:?}", );
); #[hdl(sim)]
*entry = new.to_trace_as_string(); if let HdlSome(_) = &entry.inner().l2 {
unreachable!("l2 should be HdlNone: {entry:?}");
} }
*entry = new.to_trace_as_string();
}
}
}
}
RenameTableUpdate::DropAllL2RegFileOutputs => {
for (unrenamed_reg_num, entry) in self.entries.iter_mut().enumerate() {
#[hdl(sim)]
if let HdlSome(_) = &entry.inner().l1 {
#[hdl(sim)]
if let HdlSome(_) = &entry.inner().l2 {
let mut new = entry.inner().clone();
new.l1 = #[hdl(sim)]
(new.l1.ty()).HdlNone();
println!(
"{rename_table_name}: DropAllL2RegFileOutputs: {unrenamed_reg_num:#x} \
updating from {entry:?} to {new:?}",
);
*entry = new.to_trace_as_string();
} }
RenameTableEntry::<_>::L2(_) => {}
} }
} }
} }
@ -395,13 +431,10 @@ impl<C: PhantomConstCpuConfig> RenameTable<C> {
let mut seen = BTreeSet::new(); let mut seen = BTreeSet::new();
for entry in self.entries.iter() { for entry in self.entries.iter() {
#[hdl(sim)] #[hdl(sim)]
match entry.inner() { if let HdlSome(v) = &entry.inner().l1 {
RenameTableEntry::<_>::L1(v) => { if UnitNum::index_sim(&v.unit_num) == Some(unit_index) {
if UnitNum::index_sim(&v.unit_num) == Some(unit_index) { seen.insert(UnitOutRegNum::value_sim(&v.unit_out_reg));
seen.insert(UnitOutRegNum::value_sim(&v.unit_out_reg));
}
} }
RenameTableEntry::<_>::L2(_) => {}
} }
} }
seen.len() seen.len()
@ -581,7 +614,7 @@ impl MOpInUnitState {
Self::FinishedAndOrCausedCancel => None, Self::FinishedAndOrCausedCancel => None,
} }
} }
fn is_completed(self) -> bool { fn is_finished_and_or_caused_cancel(self) -> bool {
match self { match self {
Self::NotYetEnqueued => false, Self::NotYetEnqueued => false,
Self::InputsNotReadySpeculative { .. } => false, Self::InputsNotReadySpeculative { .. } => false,
@ -603,11 +636,15 @@ type SimOnlyMOpInUnitState = SimOnly<MOpInUnitState>;
#[hdl(no_static)] #[hdl(no_static)]
struct RobEntryDebugState<C: PhantomConstGet<CpuConfig>> { struct RobEntryDebugState<C: PhantomConstGet<CpuConfig>> {
/// See [`RobEntry::is_register_fence`]
is_register_fence: Bool,
/// See [`RobEntry::is_register_fence`]
done_waiting_for_register_fences: Bool,
mop: MOpInstance<RenamedMOp<C>>, mop: MOpInstance<RenamedMOp<C>>,
unit_index: UIntInRangeType<ConstUsize<0>, CpuConfigUnitCount<C>>, unit_index: UIntInRangeType<ConstUsize<0>, CpuConfigUnitCount<C>>,
mop_in_unit_state: SimOnlyMOpInUnitState, mop_in_unit_state: SimOnlyMOpInUnitState,
is_speculative: Bool, is_speculative: Bool,
all_prior_mops_are_finished: Bool, all_prior_mops_finished_and_or_caused_cancel: Bool,
output: HdlOption<NextPcPredictorOp<C>>, output: HdlOption<NextPcPredictorOp<C>>,
caused_cancel: HdlOption<UnitCausedCancel<C>>, caused_cancel: HdlOption<UnitCausedCancel<C>>,
} }
@ -617,20 +654,24 @@ impl<C: PhantomConstCpuConfig> SimValueDefault for RobEntryDebugState<C> {
fn sim_value_default(self) -> SimValue<Self> { fn sim_value_default(self) -> SimValue<Self> {
let Self { let Self {
mop, mop,
is_register_fence: _,
done_waiting_for_register_fences: _,
unit_index, unit_index,
mop_in_unit_state: _, mop_in_unit_state: _,
is_speculative: _, is_speculative: _,
all_prior_mops_are_finished: _, all_prior_mops_finished_and_or_caused_cancel: _,
output, output,
caused_cancel, caused_cancel,
} = self; } = self;
#[hdl(sim)] #[hdl(sim)]
Self { Self {
mop: zeroed(mop), mop: zeroed(mop),
is_register_fence: false,
done_waiting_for_register_fences: false,
unit_index: zeroed(unit_index), unit_index: zeroed(unit_index),
mop_in_unit_state: SimOnlyValue::default(), mop_in_unit_state: SimOnlyValue::default(),
is_speculative: false, is_speculative: false,
all_prior_mops_are_finished: false, all_prior_mops_finished_and_or_caused_cancel: false,
output: #[hdl(sim)] output: #[hdl(sim)]
output.HdlNone(), output.HdlNone(),
caused_cancel: #[hdl(sim)] caused_cancel: #[hdl(sim)]
@ -641,23 +682,34 @@ impl<C: PhantomConstCpuConfig> SimValueDefault for RobEntryDebugState<C> {
#[derive(Debug)] #[derive(Debug)]
struct RobEntry<C: PhantomConstCpuConfig> { struct RobEntry<C: PhantomConstCpuConfig> {
/// Block this and all later µOps until all prior µOps are finished and didn't cause a cancel.
/// Not to be confused with memory fences.
is_register_fence: bool,
/// See [`Self::is_register_fence`]
done_waiting_for_register_fences: bool,
mop: SimValue<MOpInstance<RenamedMOp<C>>>, mop: SimValue<MOpInstance<RenamedMOp<C>>>,
unit_index: usize, unit_index: usize,
mop_in_unit_state: MOpInUnitState, mop_in_unit_state: MOpInUnitState,
is_speculative: bool, is_speculative: bool,
all_prior_mops_are_finished: bool, all_prior_mops_finished_and_or_caused_cancel: bool,
output: Option<SimValue<NextPcPredictorOp<C>>>, output: Option<SimValue<NextPcPredictorOp<C>>>,
caused_cancel: Option<SimValue<UnitCausedCancel<C>>>, caused_cancel: Option<SimValue<UnitCausedCancel<C>>>,
} }
impl<C: PhantomConstCpuConfig> RobEntry<C> { impl<C: PhantomConstCpuConfig> RobEntry<C> {
fn new(mop: SimValue<MOpInstance<RenamedMOp<C>>>, unit_index: usize) -> Self { fn new(
mop: SimValue<MOpInstance<RenamedMOp<C>>>,
unit_index: usize,
is_register_fence: bool,
) -> Self {
Self { Self {
mop, mop,
is_register_fence,
done_waiting_for_register_fences: false,
unit_index, unit_index,
mop_in_unit_state: MOpInUnitState::NotYetEnqueued, mop_in_unit_state: MOpInUnitState::NotYetEnqueued,
is_speculative: true, is_speculative: true,
all_prior_mops_are_finished: false, all_prior_mops_finished_and_or_caused_cancel: false,
output: None, output: None,
caused_cancel: None, caused_cancel: None,
} }
@ -677,22 +729,26 @@ impl<C: PhantomConstCpuConfig> RobEntry<C> {
#[hdl] #[hdl]
fn debug_state(&self, config: C) -> SimValue<RobEntryDebugState<C>> { fn debug_state(&self, config: C) -> SimValue<RobEntryDebugState<C>> {
let Self { let Self {
is_register_fence,
done_waiting_for_register_fences,
mop, mop,
unit_index, unit_index,
mop_in_unit_state, mop_in_unit_state,
is_speculative, is_speculative,
all_prior_mops_are_finished, all_prior_mops_finished_and_or_caused_cancel,
output, output,
caused_cancel, caused_cancel,
} = self; } = self;
let ret_ty = RobEntryDebugState[config]; let ret_ty = RobEntryDebugState[config];
#[hdl(sim)] #[hdl(sim)]
RobEntryDebugState::<C> { RobEntryDebugState::<C> {
is_register_fence,
done_waiting_for_register_fences,
mop, mop,
unit_index: unit_index.into_sim_value_with_type(ret_ty.unit_index), unit_index: unit_index.into_sim_value_with_type(ret_ty.unit_index),
mop_in_unit_state: SimOnlyValue::new(*mop_in_unit_state), mop_in_unit_state: SimOnlyValue::new(*mop_in_unit_state),
is_speculative, is_speculative,
all_prior_mops_are_finished, all_prior_mops_finished_and_or_caused_cancel,
output: output.into_sim_value_with_type(ret_ty.output), output: output.into_sim_value_with_type(ret_ty.output),
caused_cancel: caused_cancel.into_sim_value_with_type(ret_ty.caused_cancel), caused_cancel: caused_cancel.into_sim_value_with_type(ret_ty.caused_cancel),
} }
@ -1019,6 +1075,12 @@ impl<C: PhantomConstCpuConfig> ReorderBuffer<C> {
.rename_table_updates .rename_table_updates
.push(update); .push(update);
} }
fn all_mops_are_finished_and_or_caused_cancel(&self) -> bool {
self.renamed().next().is_none_or(|entry| {
entry.all_prior_mops_finished_and_or_caused_cancel
&& entry.mop_in_unit_state.is_finished_and_or_caused_cancel()
})
}
} }
type SimOnlyString = SimOnly<String>; type SimOnlyString = SimOnly<String>;
@ -1028,16 +1090,11 @@ const SimOnlyString: SimOnlyString = SimOnlyString::TYPE;
#[hdl(get(|c| c.rob_size.get().next_power_of_two()))] #[hdl(get(|c| c.rob_size.get().next_power_of_two()))]
type PerInsnTimelineLen<C: PhantomConstGet<CpuConfig>> = DynSize; type PerInsnTimelineLen<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(no_static)]
struct RenameDelayedForL2Store<C: PhantomConstGet<CpuConfig>> {
chosen_dest: PRegNum<C>,
l2_store_id: MOpId,
}
#[hdl(no_static)] #[hdl(no_static)]
struct RenameDelayedEntry<C: PhantomConstGet<CpuConfig>> { struct RenameDelayedEntry<C: PhantomConstGet<CpuConfig>> {
is_register_fence: Bool,
mop: MOpInstance<MOp>, mop: MOpInstance<MOp>,
delayed_for_l2_store: HdlOption<RenameDelayedForL2Store<C>>, chosen_dest: HdlOption<PRegNum<C>>,
} }
#[hdl(no_static)] #[hdl(no_static)]
@ -1106,11 +1163,13 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
let mut retval = let mut retval =
SimValue::from_array_elements(retval_ty, (0..len).map(|_| empty_string.clone())); SimValue::from_array_elements(retval_ty, (0..len).map(|_| empty_string.clone()));
for RobEntry { for RobEntry {
is_register_fence,
done_waiting_for_register_fences,
mop, mop,
unit_index: _, unit_index: _,
mop_in_unit_state, mop_in_unit_state,
is_speculative, is_speculative,
all_prior_mops_are_finished, all_prior_mops_finished_and_or_caused_cancel,
output, output,
caused_cancel, caused_cancel,
} in self.rob.renamed() } in self.rob.renamed()
@ -1118,11 +1177,17 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
let masked_id = mop.id.as_int() as usize & mask; let masked_id = mop.id.as_int() as usize & mask;
**retval[masked_id] = fmt::from_fn(|f| { **retval[masked_id] = fmt::from_fn(|f| {
f.write_str(mop_in_unit_state.debug_str())?; f.write_str(mop_in_unit_state.debug_str())?;
if *is_register_fence {
f.write_str("(rf)")?;
}
if !*done_waiting_for_register_fences {
f.write_str("(wfrf)")?;
}
if *is_speculative { if *is_speculative {
f.write_str("(s)")?; f.write_str("(s)")?;
} }
if *all_prior_mops_are_finished { if *all_prior_mops_finished_and_or_caused_cancel {
f.write_str("(apf)")?; f.write_str("(apfc)")?;
} }
if output.is_some() { if output.is_some() {
f.write_str("(output)")?; f.write_str("(output)")?;
@ -1222,7 +1287,9 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
fn space_available_for_unit(&self, unit_index: usize) -> usize { fn space_available_for_unit(&self, unit_index: usize) -> usize {
let mut retval = self.config.get().unit_max_in_flight(unit_index); let mut retval = self.config.get().unit_max_in_flight(unit_index);
for renamed in self.rob.renamed() { for renamed in self.rob.renamed() {
if renamed.unit_index == unit_index && !renamed.mop_in_unit_state.is_completed() { if renamed.unit_index == unit_index
&& !renamed.mop_in_unit_state.is_finished_and_or_caused_cancel()
{
let Some(v) = NonZero::new(retval.get() - 1) else { let Some(v) = NonZero::new(retval.get() - 1) else {
return 0; return 0;
}; };
@ -1259,13 +1326,10 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
.chain(self.retire_rename_table.entries.iter()) .chain(self.retire_rename_table.entries.iter())
{ {
#[hdl(sim)] #[hdl(sim)]
match entry.inner() { if let HdlSome(l1) = &entry.inner().l1 {
RenameTableEntry::<_>::L1(entry) => { if Some(unit_index) == UnitNum::index_sim(&l1.unit_num) {
if Some(unit_index) == UnitNum::index_sim(&entry.unit_num) { allocated_regs[UnitOutRegNum::value_sim(&l1.unit_out_reg)] = true;
allocated_regs[UnitOutRegNum::value_sim(&entry.unit_out_reg)] = true;
}
} }
RenameTableEntry::<_>::L2(_) => {}
} }
} }
allocated_regs.iter().position(|v| !v) allocated_regs.iter().position(|v| !v)
@ -1292,11 +1356,8 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
.chain(self.retire_rename_table.entries.iter()) .chain(self.retire_rename_table.entries.iter())
{ {
#[hdl(sim)] #[hdl(sim)]
match entry.inner() { if let HdlSome(l2) = &entry.inner().l2 {
RenameTableEntry::<_>::L1(_) => {} allocated_regs[L2RegNum::value_sim(l2)] = true;
RenameTableEntry::<_>::L2(entry) => {
allocated_regs[L2RegNum::value_sim(entry)] = true;
}
} }
} }
allocated_regs.iter().position(|v| !v) allocated_regs.iter().position(|v| !v)
@ -1306,9 +1367,6 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
unrenamed: &SimValue<MOpInstance<MOp>>, unrenamed: &SimValue<MOpInstance<MOp>>,
renamed: RobEntry<C>, renamed: RobEntry<C>,
) -> &SimValue<MOpId> { ) -> &SimValue<MOpId> {
if let Some(unit_out_reg_index) = renamed.unit_out_reg_index() {
self.l1_reg_file[renamed.unit_index][unit_out_reg_index] = None;
}
self.rob.renamed_push_back_with_new_id(unrenamed, renamed) self.rob.renamed_push_back_with_new_id(unrenamed, renamed)
} }
fn update_rename_table( fn update_rename_table(
@ -1327,8 +1385,9 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
) -> Result<(), SimValue<RenameDelayedEntry<C>>> { ) -> Result<(), SimValue<RenameDelayedEntry<C>>> {
#[hdl(sim)] #[hdl(sim)]
let RenameDelayedEntry::<_> { let RenameDelayedEntry::<_> {
is_register_fence,
mop: insn, mop: insn,
delayed_for_l2_store, chosen_dest,
} = entry; } = entry;
println!("try_rename: insn: {insn:?}"); println!("try_rename: insn: {insn:?}");
if self.rob.unrenamed_len() >= self.config.get().rob_size.get() { if self.rob.unrenamed_len() >= self.config.get().rob_size.get() {
@ -1336,8 +1395,9 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
return Err( return Err(
#[hdl(sim)] #[hdl(sim)]
RenameDelayedEntry::<_> { RenameDelayedEntry::<_> {
is_register_fence,
mop: insn, mop: insn,
delayed_for_l2_store, chosen_dest,
}, },
); );
} }
@ -1346,14 +1406,16 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
return Err( return Err(
#[hdl(sim)] #[hdl(sim)]
RenameDelayedEntry::<_> { RenameDelayedEntry::<_> {
is_register_fence,
mop: insn, mop: insn,
delayed_for_l2_store, chosen_dest,
}, },
); );
} }
let unit_kind = UnitMOp::kind_sim(insn.mop.inner()); let unit_kind = UnitMOp::kind_sim(insn.mop.inner());
#[hdl(sim)] #[hdl(sim)]
if let MOp::TransformedMove(move_reg_mop) = insn.mop.inner() { if let MOp::TransformedMove(move_reg_mop) = insn.mop.inner() {
assert!(!*is_register_fence);
let mut src_regs = [MOpRegNum::const_zero_sim()]; let mut src_regs = [MOpRegNum::const_zero_sim()];
MOpTrait::for_each_src_reg_sim_ref(move_reg_mop, &mut |src_reg, index| { MOpTrait::for_each_src_reg_sim_ref(move_reg_mop, &mut |src_reg, index| {
src_regs[index] = src_reg.clone(); src_regs[index] = src_reg.clone();
@ -1398,32 +1460,12 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
} }
} }
let chosen_unit = #[hdl(sim)] let chosen_unit = #[hdl(sim)]
if let HdlSome(l2_store) = &delayed_for_l2_store { if let HdlSome(chosen_dest) = &chosen_dest {
let RobEntry { let unit_index = UnitNum::index_sim(&chosen_dest.unit_num).expect("known to be some");
mop: _,
unit_index: _,
mop_in_unit_state: MOpInUnitState::FinishedAndOrCausedCancel,
is_speculative: _,
all_prior_mops_are_finished: true,
output: _,
caused_cancel: None,
} = self.rob.renamed_by_id(&l2_store.l2_store_id)
else {
println!("try_rename: delaying for l2 store that isn't yet finished");
return Err(
#[hdl(sim)]
RenameDelayedEntry::<_> {
mop: insn,
delayed_for_l2_store,
},
);
};
let unit_index =
UnitNum::index_sim(&l2_store.chosen_dest.unit_num).expect("known to be some");
assert_eq!(self.config.get().units[unit_index].kind, unit_kind); assert_eq!(self.config.get().units[unit_index].kind, unit_kind);
ChosenUnit { ChosenUnit {
unit_index, unit_index,
out_reg_num: Some(UnitOutRegNum::value_sim(&l2_store.chosen_dest.unit_out_reg)), out_reg_num: Some(UnitOutRegNum::value_sim(&chosen_dest.unit_out_reg)),
space_available: self.space_available_for_unit(unit_index), space_available: self.space_available_for_unit(unit_index),
} }
} else { } else {
@ -1460,8 +1502,9 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
return Err( return Err(
#[hdl(sim)] #[hdl(sim)]
RenameDelayedEntry::<_> { RenameDelayedEntry::<_> {
is_register_fence,
mop: insn, mop: insn,
delayed_for_l2_store, chosen_dest,
}, },
); );
} }
@ -1499,13 +1542,10 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
"try_rename: checking that mop src reg ({renamed:?}) doesn't conflict with picked reg" "try_rename: checking that mop src reg ({renamed:?}) doesn't conflict with picked reg"
); );
#[hdl(sim)] #[hdl(sim)]
match renamed.inner() { if let HdlSome(l1) = &renamed.inner().l1 {
RenameTableEntry::<_>::L1(v) => { if reg_to_free == *l1 {
if reg_to_free == *v { any_collisions = true;
any_collisions = true;
}
} }
RenameTableEntry::<_>::L2(_) => {}
} }
}); });
if any_collisions { if any_collisions {
@ -1515,8 +1555,9 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
return Err( return Err(
#[hdl(sim)] #[hdl(sim)]
RenameDelayedEntry::<_> { RenameDelayedEntry::<_> {
is_register_fence,
mop: insn, mop: insn,
delayed_for_l2_store, chosen_dest,
}, },
); );
} }
@ -1548,28 +1589,25 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
.into_trace_as_string(), .into_trace_as_string(),
}, },
self.l2_reg_file_unit_index, self.l2_reg_file_unit_index,
*is_register_fence,
), ),
); );
return Err( return Err(
#[hdl(sim)] #[hdl(sim)]
RenameDelayedEntry::<_> { RenameDelayedEntry::<_> {
is_register_fence: true,
mop: insn, mop: insn,
delayed_for_l2_store: #[hdl(sim)] chosen_dest: #[hdl(sim)]
(delayed_for_l2_store.ty()).HdlSome( (chosen_dest.ty()).HdlSome(reg_to_free),
#[hdl(sim)]
RenameDelayedForL2Store::<_> {
chosen_dest: reg_to_free,
l2_store_id,
},
),
}, },
); );
} }
return Err( return Err(
#[hdl(sim)] #[hdl(sim)]
RenameDelayedEntry::<_> { RenameDelayedEntry::<_> {
is_register_fence,
mop: insn, mop: insn,
delayed_for_l2_store, chosen_dest,
}, },
); );
}; };
@ -1600,10 +1638,16 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
let renamed = &self.rename_table.entries[MOpRegNum::reg_num_sim(&src_reg) as usize]; let renamed = &self.rename_table.entries[MOpRegNum::reg_num_sim(&src_reg) as usize];
println!("renaming src[{index}] from {src_reg:?} to {renamed:?}"); println!("renaming src[{index}] from {src_reg:?} to {renamed:?}");
#[hdl(sim)] #[hdl(sim)]
match renamed.inner() { match &renamed.inner().l1 {
RenameTableEntry::<_>::L1(v) => v.clone(), HdlSome(l1) => l1.clone(),
RenameTableEntry::<_>::L2(v) => { HdlNone => {
needed_load.get_or_insert_with(|| v.clone()); let l2 = #[hdl(sim)]
if let HdlSome(l2) = &renamed.inner().l2 {
l2
} else {
unreachable!("rename table entry has neither l1 nor l2: {src_reg:?}");
};
needed_load.get_or_insert_with(|| l2.clone());
PRegNum[self.config].const_zero_sim() PRegNum[self.config].const_zero_sim()
} }
} }
@ -1645,23 +1689,39 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
.into_trace_as_string(), .into_trace_as_string(),
}, },
self.l2_reg_file_unit_index, self.l2_reg_file_unit_index,
*is_register_fence,
), ),
); );
println!("try_rename: l2 reg file has no space and/or has no free output regs"); println!("try_rename: read l2 reg");
Err( Err(
#[hdl(sim)] #[hdl(sim)]
RenameDelayedEntry::<_> { RenameDelayedEntry::<_> {
is_register_fence: false,
mop: insn, mop: insn,
delayed_for_l2_store, chosen_dest,
},
)
} else if self.rob.all_mops_are_finished_and_or_caused_cancel() {
println!("try_rename: dropping all l2 reg file outputs");
self.update_rename_table(&insn, RenameTableUpdate::DropAllL2RegFileOutputs);
Err(
#[hdl(sim)]
RenameDelayedEntry::<_> {
is_register_fence: true,
mop: insn,
chosen_dest,
}, },
) )
} else { } else {
println!("try_rename: l2 reg file has no space and/or has no free output regs"); println!(
"try_rename: waiting for all mops to finish before dropping all l2 reg file outputs"
);
Err( Err(
#[hdl(sim)] #[hdl(sim)]
RenameDelayedEntry::<_> { RenameDelayedEntry::<_> {
is_register_fence,
mop: insn, mop: insn,
delayed_for_l2_store, chosen_dest,
}, },
) )
}; };
@ -1673,7 +1733,12 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
) )
.into_trace_as_string(); .into_trace_as_string();
let renamed_dest_reg = #[hdl(sim)] let renamed_dest_reg = #[hdl(sim)]
(RenameTableEntry[self.config]).L1(renamed_dest_reg); RenameTableEntry::<_> {
l1: #[hdl(sim)]
(HdlOption[renamed_dest_reg.ty()]).HdlSome(renamed_dest_reg),
l2: #[hdl(sim)]
HdlNone(),
};
for unrenamed_reg_num in unrenamed_dest_regs { for unrenamed_reg_num in unrenamed_dest_regs {
self.update_rename_table( self.update_rename_table(
&insn, &insn,
@ -1698,6 +1763,7 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
mop, mop,
}, },
unit_index, unit_index,
*is_register_fence,
), ),
); );
self.rob.finished_unrenamed_push_back(&insn); self.rob.finished_unrenamed_push_back(&insn);
@ -1739,13 +1805,25 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
} }
let zero_reg = PRegNum[self.config].const_zero().into_sim_value(); let zero_reg = PRegNum[self.config].const_zero().into_sim_value();
let zero_value = zeroed(TraceAsString[PRegValue]); let zero_value = zeroed(TraceAsString[PRegValue]);
for rob in self.rob.renamed() { for RobEntry {
if rob.unit_index == unit_index is_register_fence: _,
&& let Some(_) = rob.mop_in_unit_state.with_inputs_ready() done_waiting_for_register_fences,
mop,
unit_index: rob_unit_index,
mop_in_unit_state,
is_speculative: _,
all_prior_mops_finished_and_or_caused_cancel: _,
output: _,
caused_cancel: _,
} in self.rob.renamed()
{
if *done_waiting_for_register_fences
&& *rob_unit_index == unit_index
&& let Some(_) = mop_in_unit_state.with_inputs_ready()
{ {
let mut src_values: [_; COMMON_MOP_SRC_LEN] = let mut src_values: [_; COMMON_MOP_SRC_LEN] =
std::array::from_fn(|_| Some(zero_value.clone())); std::array::from_fn(|_| Some(zero_value.clone()));
MOpTrait::for_each_src_reg_sim_ref(rob.mop.mop.inner(), &mut |src_reg, index| { MOpTrait::for_each_src_reg_sim_ref(mop.mop.inner(), &mut |src_reg, index| {
#[hdl(sim)] #[hdl(sim)]
let PRegNum::<_> { let PRegNum::<_> {
unit_num, unit_num,
@ -1765,7 +1843,7 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
ret_ty.HdlSome( ret_ty.HdlSome(
#[hdl(sim)] #[hdl(sim)]
UnitInputsReady::<_> { UnitInputsReady::<_> {
mop: &rob.mop, mop,
src_values, src_values,
config: self.config, config: self.config,
}, },
@ -1819,11 +1897,13 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
let rob = self.rob.renamed_by_id_mut(&id); let rob = self.rob.renamed_by_id_mut(&id);
let out_reg_index = rob.unit_out_reg_index(); let out_reg_index = rob.unit_out_reg_index();
let RobEntry { let RobEntry {
is_register_fence: _,
done_waiting_for_register_fences: _,
mop: _, mop: _,
unit_index, unit_index,
mop_in_unit_state, mop_in_unit_state,
is_speculative: _, is_speculative: _,
all_prior_mops_are_finished: _, all_prior_mops_finished_and_or_caused_cancel: _,
output, output,
caused_cancel, caused_cancel,
} = rob; } = rob;
@ -1852,11 +1932,13 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
} = finish_cause_cancel; } = finish_cause_cancel;
assert!(!self.is_canceling()); assert!(!self.is_canceling());
let RobEntry { let RobEntry {
is_register_fence: _,
done_waiting_for_register_fences: _,
mop: _, mop: _,
unit_index: _, unit_index: _,
mop_in_unit_state, mop_in_unit_state,
is_speculative: _, is_speculative: _,
all_prior_mops_are_finished: _, all_prior_mops_finished_and_or_caused_cancel: _,
output, output,
caused_cancel, caused_cancel,
} = self.rob.renamed_by_id_mut(&id); } = self.rob.renamed_by_id_mut(&id);
@ -1906,10 +1988,10 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
self.rename_delayed.push_back( self.rename_delayed.push_back(
#[hdl(sim)] #[hdl(sim)]
RenameDelayedEntry::<_> { RenameDelayedEntry::<_> {
is_register_fence: false,
mop: insn, mop: insn,
delayed_for_l2_store: #[hdl(sim)] chosen_dest: #[hdl(sim)]
(HdlOption[RenameDelayedForL2Store[self.config]]) (HdlOption[PRegNum[self.config]]).HdlNone(),
.HdlNone(),
}, },
); );
} }
@ -1963,11 +2045,13 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
for retire_group in self.rob.retire_groups() { for retire_group in self.rob.retire_groups() {
for renamed_entry in retire_group.clone().flat_map(|v| &v.renamed_entries) { for renamed_entry in retire_group.clone().flat_map(|v| &v.renamed_entries) {
if let RobEntry { if let RobEntry {
is_register_fence: _,
done_waiting_for_register_fences: _,
mop: _, mop: _,
unit_index: _, unit_index: _,
mop_in_unit_state: MOpInUnitState::FinishedAndOrCausedCancel, mop_in_unit_state: MOpInUnitState::FinishedAndOrCausedCancel,
is_speculative: _, is_speculative: _,
all_prior_mops_are_finished: _, all_prior_mops_finished_and_or_caused_cancel: _,
output, output,
caused_cancel, caused_cancel,
} = renamed_entry } = renamed_entry
@ -2096,11 +2180,13 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
.iter() .iter()
.for_each(|v| self.retire_rename_table.update(v, "retire_rename_table")); .for_each(|v| self.retire_rename_table.update(v, "retire_rename_table"));
for RobEntry { for RobEntry {
is_register_fence: _,
done_waiting_for_register_fences: _,
mop: _, mop: _,
unit_index: _, unit_index: _,
mop_in_unit_state, mop_in_unit_state,
is_speculative: _, is_speculative: _,
all_prior_mops_are_finished: _, all_prior_mops_finished_and_or_caused_cancel: _,
output: _, output: _,
caused_cancel, caused_cancel,
} in renamed_entries } in renamed_entries
@ -2131,7 +2217,7 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
return; return;
} }
for renamed in self.rob.renamed_mut() { for renamed in self.rob.renamed_mut() {
renamed.all_prior_mops_are_finished = true; renamed.all_prior_mops_finished_and_or_caused_cancel = true;
let MOpInUnitState::FinishedAndOrCausedCancel = renamed.mop_in_unit_state else { let MOpInUnitState::FinishedAndOrCausedCancel = renamed.mop_in_unit_state else {
break; break;
}; };
@ -2155,13 +2241,39 @@ impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
break; break;
} }
} }
for renamed in self.rob.renamed_mut() {
let RobEntry {
is_register_fence,
done_waiting_for_register_fences,
mop: _,
unit_index,
mop_in_unit_state: _,
is_speculative,
all_prior_mops_finished_and_or_caused_cancel,
output: _,
caused_cancel: _,
} = &renamed;
if *is_register_fence {
if !*all_prior_mops_finished_and_or_caused_cancel || *is_speculative {
break;
}
}
if !*done_waiting_for_register_fences {
if let Some(unit_out_reg_index) = renamed.unit_out_reg_index() {
self.l1_reg_file[*unit_index][unit_out_reg_index] = None;
}
}
renamed.done_waiting_for_register_fences = true;
}
let first_renamed = self.rob.renamed().next(); let first_renamed = self.rob.renamed().next();
if let Some(RobEntry { if let Some(RobEntry {
is_register_fence: _,
done_waiting_for_register_fences: _,
mop: _, mop: _,
unit_index: _, unit_index: _,
mop_in_unit_state: MOpInUnitState::FinishedAndOrCausedCancel, mop_in_unit_state: MOpInUnitState::FinishedAndOrCausedCancel,
is_speculative: _, is_speculative: _,
all_prior_mops_are_finished: _, all_prior_mops_finished_and_or_caused_cancel: _,
output: _, output: _,
caused_cancel: Some(caused_cancel), caused_cancel: Some(caused_cancel),
}) = first_renamed }) = first_renamed
@ -2269,11 +2381,13 @@ async fn rename_execute_retire_run(
if let HdlSome(enqueue) = sim.read_past(enqueue.data, cd.clk).await { if let HdlSome(enqueue) = sim.read_past(enqueue.data, cd.clk).await {
assert!(!state.is_canceling()); assert!(!state.is_canceling());
let RobEntry { let RobEntry {
is_register_fence: _,
done_waiting_for_register_fences: _,
mop: _, mop: _,
unit_index: _, unit_index: _,
mop_in_unit_state, mop_in_unit_state,
is_speculative: _, is_speculative: _,
all_prior_mops_are_finished: _, all_prior_mops_finished_and_or_caused_cancel: _,
output, output,
caused_cancel, caused_cancel,
} = state.rob.renamed_by_id_mut(&enqueue.mop.id); } = state.rob.renamed_by_id_mut(&enqueue.mop.id);
@ -2288,14 +2402,17 @@ async fn rename_execute_retire_run(
if let HdlSome(inputs_ready) = sim.read_past(inputs_ready, cd.clk).await { if let HdlSome(inputs_ready) = sim.read_past(inputs_ready, cd.clk).await {
assert!(!state.is_canceling()); assert!(!state.is_canceling());
let RobEntry { let RobEntry {
is_register_fence: _,
done_waiting_for_register_fences,
mop: _, mop: _,
unit_index: _, unit_index: _,
mop_in_unit_state, mop_in_unit_state,
is_speculative: _, is_speculative: _,
all_prior_mops_are_finished: _, all_prior_mops_finished_and_or_caused_cancel: _,
output, output,
caused_cancel, caused_cancel,
} = state.rob.renamed_by_id_mut(&inputs_ready.mop.id); } = state.rob.renamed_by_id_mut(&inputs_ready.mop.id);
assert!(*done_waiting_for_register_fences);
assert!(output.is_none()); assert!(output.is_none());
assert!(caused_cancel.is_none()); assert!(caused_cancel.is_none());
*mop_in_unit_state = mop_in_unit_state *mop_in_unit_state = mop_in_unit_state
@ -2308,11 +2425,13 @@ async fn rename_execute_retire_run(
{ {
assert!(!state.is_canceling()); assert!(!state.is_canceling());
let RobEntry { let RobEntry {
is_register_fence: _,
done_waiting_for_register_fences: _,
mop: _, mop: _,
unit_index: _, unit_index: _,
mop_in_unit_state, mop_in_unit_state,
is_speculative: _, is_speculative: _,
all_prior_mops_are_finished: _, all_prior_mops_finished_and_or_caused_cancel: _,
output: _, output: _,
caused_cancel: _, caused_cancel: _,
} = state.rob.renamed_by_id_mut(&is_no_longer_speculative.id); } = state.rob.renamed_by_id_mut(&is_no_longer_speculative.id);
@ -2327,11 +2446,13 @@ async fn rename_execute_retire_run(
let UnitMOpCantCauseCancel::<_> { id, config: _ } = cant_cause_cancel; let UnitMOpCantCauseCancel::<_> { id, config: _ } = cant_cause_cancel;
assert!(!state.is_canceling()); assert!(!state.is_canceling());
let RobEntry { let RobEntry {
is_register_fence: _,
done_waiting_for_register_fences: _,
mop: _, mop: _,
unit_index: _, unit_index: _,
mop_in_unit_state, mop_in_unit_state,
is_speculative: _, is_speculative: _,
all_prior_mops_are_finished: _, all_prior_mops_finished_and_or_caused_cancel: _,
output: _, output: _,
caused_cancel, caused_cancel,
} = state.rob.renamed_by_id_mut(&id); } = state.rob.renamed_by_id_mut(&id);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff