forked from libre-chip/cpu
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:
parent
3e08a282ec
commit
bf2cb688c7
6 changed files with 198817 additions and 95647 deletions
|
|
@ -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(_) => {}
|
|
||||||
RenameTableEntry::<_>::L2(l2) => {
|
|
||||||
if L2RegNum::value_sim(l2) == L2RegNum::value_sim(src) {
|
if L2RegNum::value_sim(l2) == L2RegNum::value_sim(src) {
|
||||||
println!(
|
println!(
|
||||||
"{rename_table_name}: UpdateForReadL2Reg: {unrenamed_reg_num:#x} \
|
"{rename_table_name}: UpdateForReadL2Reg: {unrenamed_reg_num:#x} \
|
||||||
updating from {entry:?} to {new:?}",
|
updating from {entry:?} to {new:?}",
|
||||||
);
|
);
|
||||||
*entry = new.to_trace_as_string();
|
#[hdl(sim)]
|
||||||
|
if let HdlSome(_) = &entry.inner().l1 {
|
||||||
|
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)]
|
||||||
|
if let HdlSome(_) = &entry.inner().l2 {
|
||||||
|
unreachable!("l2 should be HdlNone: {entry:?}");
|
||||||
|
}
|
||||||
*entry = new.to_trace_as_string();
|
*entry = new.to_trace_as_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RenameTableEntry::<_>::L2(_) => {}
|
}
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -395,14 +431,11 @@ 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,14 +1326,11 @@ 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,14 +1542,11 @@ 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 {
|
||||||
println!(
|
println!(
|
||||||
|
|
@ -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
4482
crates/cpu/tests/expected/rename_execute_retire_head_n1.vcd
generated
4482
crates/cpu/tests/expected/rename_execute_retire_head_n1.vcd
generated
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
132651
crates/cpu/tests/expected/rename_execute_retire_slow_loop.vcd
generated
132651
crates/cpu/tests/expected/rename_execute_retire_slow_loop.vcd
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue