Skip to content

Commit 6f2cbb7

Browse files
Random branch misprediction flush fix (#154)
CC: @danbone closes #153 --------- Co-authored-by: Knute Lingaard <[email protected]>
1 parent 71e636b commit 6f2cbb7

File tree

8 files changed

+62
-49
lines changed

8 files changed

+62
-49
lines changed

core/CPUTopology.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -343,13 +343,6 @@ void olympia::CoreTopologySimple::bindTree(sparta::RootTreeNode* root_node)
343343
;
344344
const std::string flush_manager = flushmanager_ports + ".out_flush_upper";
345345
bind_ports(exe_flush_in, flush_manager);
346-
347-
// Bind flush requests
348-
const std::string exe_flush_out =
349-
core_node + ".execute." + unit_name + ".ports.out_execute_flush";
350-
;
351-
const std::string flush_manager_in = flushmanager_ports + ".in_flush_request";
352-
bind_ports(exe_flush_out, flush_manager_in);
353346
}
354347

355348
const auto issue_queue_to_pipe_map = olympia::coreutils::getPipeTopology(
@@ -430,4 +423,4 @@ olympia::CPUTopology::allocateTopology(const std::string & topology)
430423
}
431424
sparta_assert(nullptr != new_topology);
432425
return new_topology;
433-
}
426+
}

core/ExecutePipe.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,7 @@ namespace olympia
8383
if (ex_inst->isBranch() && (std::rand() % 20) == 0)
8484
{
8585
ILOG("Randomly injecting a mispredicted branch: " << ex_inst);
86-
FlushManager::FlushingCriteria criteria(FlushManager::FlushCause::MISPREDICTION,
87-
ex_inst);
88-
out_execute_flush_.send(criteria);
86+
ex_inst->setMispredicted();
8987
}
9088
}
9189

core/ExecutePipe.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ namespace olympia
8484
sparta::DataOutPort<uint32_t> out_execute_pipe_{&unit_port_set_, "out_execute_pipe"};
8585
sparta::DataInPort<FlushManager::FlushingCriteria> in_reorder_flush_{
8686
&unit_port_set_, "in_reorder_flush", sparta::SchedulingPhase::Flush, 1};
87-
sparta::DataOutPort<FlushManager::FlushingCriteria> out_execute_flush_{&unit_port_set_,
88-
"out_execute_flush"};
8987

9088
// Scoreboards
9189
using ScoreboardViews =

core/FlushManager.hpp

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -50,44 +50,44 @@ namespace olympia
5050
TARGET_MISPREDICTION,
5151
MISFETCH,
5252
POST_SYNC,
53-
UKNOWN,
53+
UNKNOWN,
5454
__LAST
5555
};
5656

57+
static bool determineInclusive(FlushCause cause)
58+
{
59+
static const std::map<FlushCause, bool> inclusive_flush_map = {
60+
{FlushCause::TRAP, true},
61+
{FlushCause::MISFETCH, true},
62+
{FlushCause::MISPREDICTION, false},
63+
{FlushCause::TARGET_MISPREDICTION, false},
64+
{FlushCause::POST_SYNC, false}
65+
};
66+
67+
if(auto match = inclusive_flush_map.find(cause); match != inclusive_flush_map.end()) {
68+
return match->second;
69+
}
70+
sparta_assert(false, "Unknown flush cause: " << static_cast<uint16_t>(cause));
71+
return false;
72+
}
73+
5774
class FlushingCriteria
5875
{
5976
public:
60-
FlushingCriteria(FlushCause cause, InstPtr inst_ptr) :
77+
FlushingCriteria(FlushCause cause, const InstPtr & inst_ptr) :
6178
cause_(cause),
62-
inst_ptr_(inst_ptr) {}
79+
is_inclusive_(determineInclusive(cause_)),
80+
inst_ptr_(inst_ptr)
81+
{}
6382

6483
FlushingCriteria() = default;
6584
FlushingCriteria(const FlushingCriteria &rhs) = default;
6685
FlushingCriteria &operator=(const FlushingCriteria &rhs) = default;
6786

6887
FlushCause getCause() const { return cause_; }
6988
const InstPtr & getInstPtr() const { return inst_ptr_; }
70-
71-
bool isInclusiveFlush() const
72-
{
73-
static const std::map<FlushCause, bool> inclusive_flush_map = {
74-
{FlushCause::TRAP, true},
75-
{FlushCause::MISFETCH, true},
76-
{FlushCause::MISPREDICTION, false},
77-
{FlushCause::TARGET_MISPREDICTION, false},
78-
{FlushCause::POST_SYNC, false}
79-
};
80-
if(auto match = inclusive_flush_map.find(cause_); match != inclusive_flush_map.end()) {
81-
return match->second;
82-
}
83-
sparta_assert(false, "Unknown flush cause: " << static_cast<uint16_t>(cause_));
84-
return true;
85-
}
86-
87-
bool isLowerPipeFlush() const
88-
{
89-
return cause_ == FlushCause::MISFETCH;
90-
}
89+
bool isInclusiveFlush() const { return is_inclusive_; }
90+
bool isLowerPipeFlush() const { return cause_ == FlushCause::MISFETCH; }
9191

9292
bool includedInFlush(const InstPtr& other) const
9393
{
@@ -97,11 +97,12 @@ namespace olympia
9797
}
9898

9999
private:
100-
FlushCause cause_ = FlushCause::UKNOWN;
100+
// Cannot be const since these are copied into the PLE
101+
FlushCause cause_ = FlushCause::UNKNOWN;
102+
bool is_inclusive_ = false;
101103
InstPtr inst_ptr_;
102104
};
103105

104-
105106
static constexpr char name[] = "flushmanager";
106107

107108
class FlushManagerParameters : public sparta::ParameterSet
@@ -202,8 +203,8 @@ namespace olympia
202203
case FlushManager::FlushCause::POST_SYNC:
203204
os << "POST_SYNC";
204205
break;
205-
case FlushManager::FlushCause::UKNOWN:
206-
os << "UKNOWN";
206+
case FlushManager::FlushCause::UNKNOWN:
207+
os << "UNKNOWN";
207208
break;
208209
case FlushManager::FlushCause::__LAST:
209210
throw sparta::SpartaException("__LAST cannot be a valid enum state.");

core/Inst.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ namespace olympia
178178
// Branch instruction was taken (always set for JAL/JALR)
179179
void setTakenBranch(bool taken) { is_taken_branch_ = taken; }
180180

181+
// Is this branch instruction mispredicted?
182+
bool isMispredicted() const { return is_mispredicted_; }
183+
void setMispredicted() { is_mispredicted_ = true; }
184+
181185
// TBD -- add branch prediction
182186
void setSpeculative(bool spec) { is_speculative_ = spec; }
183187

@@ -276,6 +280,9 @@ namespace olympia
276280
const bool is_condbranch_;
277281
const bool is_call_;
278282
const bool is_return_;
283+
284+
// Did this instruction mispredict?
285+
bool is_mispredicted_ = false;
279286
bool is_taken_branch_ = false;
280287
sparta::Scheduleable* ev_retire_ = nullptr;
281288
Status status_state_;

core/ROB.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,6 @@ namespace olympia
7676
ev_ensure_forward_progress_.schedule(retire_timeout_interval_);
7777
}
7878

79-
void ROB::retireEvent_() {
80-
retireInstructions_();
81-
}
82-
8379
// An illustration of the use of the callback -- instead of
8480
// getting a reference, you can pull the data from the port
8581
// directly, albeit inefficient and superfluous here...
@@ -94,6 +90,10 @@ namespace olympia
9490

9591
void ROB::handleFlush_(const FlushManager::FlushingCriteria & criteria)
9692
{
93+
sparta_assert(expect_flush_, "Received a flush, but didn't expect one");
94+
95+
expect_flush_ = false;
96+
9797
uint32_t credits_to_send = 0;
9898

9999
// Clean up internals and send new credit count
@@ -117,6 +117,11 @@ namespace olympia
117117

118118
void ROB::retireInstructions_()
119119
{
120+
// ROB is expecting a flush (back to itself)
121+
if(expect_flush_) {
122+
return;
123+
}
124+
120125
const uint32_t num_to_retire = std::min(reorder_buffer_.size(), num_to_retire_);
121126

122127
ILOG("num to retire: " << num_to_retire);
@@ -171,6 +176,15 @@ namespace olympia
171176
break;
172177
}
173178

179+
// Is this a misprdicted branch requiring a refetch?
180+
if(ex_inst.isMispredicted()) {
181+
FlushManager::FlushingCriteria criteria
182+
(FlushManager::FlushCause::MISPREDICTION, ex_inst_ptr);
183+
out_retire_flush_.send(criteria);
184+
expect_flush_ = true;
185+
break;
186+
}
187+
174188
// This is rare for the example
175189
if(SPARTA_EXPECT_FALSE(ex_inst.getPipe() == InstArchInfo::TargetPipe::SYS))
176190
{

core/ROB.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,12 @@ namespace olympia
108108
sparta::DataInPort<FlushManager::FlushingCriteria> in_reorder_flush_
109109
{&unit_port_set_, "in_reorder_flush", sparta::SchedulingPhase::Flush, 1};
110110

111+
// Is the ROB expecting a flush?
112+
bool expect_flush_ = false;
113+
111114
// Events used by the ROB
112115
sparta::UniqueEvent<> ev_retire_ {&unit_event_set_, "retire_insts",
113-
CREATE_SPARTA_HANDLER(ROB, retireEvent_)};
116+
CREATE_SPARTA_HANDLER(ROB, retireInstructions_)};
114117

115118
// For correlation activities
116119
sparta::pevents::PeventCollector<InstPEventPairs> retire_event_{"RETIRE", getContainer(), getClock()};
@@ -124,7 +127,6 @@ namespace olympia
124127
std::unique_ptr<sparta::NotificationSource<bool>> rob_stopped_notif_source_;
125128

126129
void sendInitialCredits_();
127-
void retireEvent_();
128130
void robAppended_(const InstGroup &);
129131
void retireInstructions_();
130132
void checkForwardProgress_();

test/sim/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ sparta_named_test(olympia_json_test_fp_transfers olympia
5858

5959
# Test PEvent generation
6060
sparta_named_test(olympia_json_test_pevents olympia
61-
--workload traces/dhry_riscv.zstf
61+
--workload traces/dhry_riscv.zstf -i100k
6262
--pevents test_pevent.out RETIRE
6363
--pevents test_pevent.out COMPLETE)
6464
sparta_named_test(olympia_json_test_pevents_all olympia
65-
--workload traces/dhry_riscv.zstf
65+
--workload traces/dhry_riscv.zstf -i100k
6666
--pevents test_pevent.out all)
6767

6868
## Test the arches

0 commit comments

Comments
 (0)