-
Notifications
You must be signed in to change notification settings - Fork 72
Expand file tree
/
Copy pathfetch_target_queue.cc
More file actions
325 lines (295 loc) · 10.2 KB
/
fetch_target_queue.cc
File metadata and controls
325 lines (295 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#include "cpu/pred/btb/fetch_target_queue.hh"
#include "base/trace.hh"
#ifdef UNIT_TEST
#include "cpu/pred/btb/test/test_dprintf.hh"
#else
#include "debug/DecoupleBP.hh"
#include "debug/DecoupleBPProbe.hh"
#endif
namespace gem5
{
namespace branch_prediction
{
namespace btb_pred
{
/**
* @brief Constructor for the Fetch Target Queue
*
* Initializes the FTQ with a specified maximum size and sets up the
* initial state for fetch target enqueuing and demand tracking.
*
* @param size Maximum number of entries the queue can hold
*/
FetchTargetQueue::FetchTargetQueue(unsigned size) :
ftqSize(size)
{
fetchTargetEnqState.pc = 0x80000000; // Initialize PC to default boot address
fetchDemandTargetId = 0; // Start with target ID 0
supplyFetchTargetState.valid = false; // No valid supply state initially
}
/**
* @brief Clear all entries and reset queue state after a pipeline flush
*
* This method is called after a branch misprediction or other event that
* requires the pipeline to be flushed. It resets the state of the FTQ to
* start fetching from a new PC and stream.
*
* @param new_enq_target_id New target ID to begin enqueueing at
* @param new_enq_stream_id New stream ID to associate with new entries
* @param new_enq_pc New PC to begin fetching from
*/
void
FetchTargetQueue::squash(FetchTargetId new_enq_target_id,
FetchStreamId new_enq_stream_id, Addr new_enq_pc)
{
ftq.clear(); // Remove all entries from the queue
// Because we squash the whole ftq, head and tail should be the same
auto new_fetch_demand_target_id = new_enq_target_id;
// Update enqueue state
fetchTargetEnqState.nextEnqTargetId = new_enq_target_id;
fetchTargetEnqState.streamId = new_enq_stream_id;
fetchTargetEnqState.pc = new_enq_pc;
// Reset supply state
supplyFetchTargetState.valid = false;
supplyFetchTargetState.entry = nullptr;
fetchDemandTargetId = new_fetch_demand_target_id;
DPRINTF(DecoupleBP,
"FTQ demand stream ID update to %lu, ftqEnqPC update to "
"%#lx, fetch demand target Id updated to %lu\n",
new_enq_stream_id, new_enq_pc, fetchDemandTargetId);
}
/**
* @brief Check if a fetch target is available for the current demand
*
* This method checks if there is a valid fetch target entry that
* matches the current demand target ID.
*
* @return true if a matching target is available, false otherwise
*/
bool
FetchTargetQueue::fetchTargetAvailable() const
{
return supplyFetchTargetState.valid &&
supplyFetchTargetState.targetId == fetchDemandTargetId;
}
/**
* @brief Get the currently available fetch target
*
* @return Reference to the current fetch target entry
* @pre fetchTargetAvailable() must be true
*/
FtqEntry&
FetchTargetQueue::getTarget()
{
assert(fetchTargetAvailable());
return *supplyFetchTargetState.entry;
}
/**
* @brief Mark the current fetch target as finished and advance to the next
*
* This method is called when the fetch unit has consumed the current
* fetch target. It removes the entry from the queue and advances the
* demand target ID.
*/
void
FetchTargetQueue::finishCurrentFetchTarget()
{
++fetchDemandTargetId; // Move to next target
ftq.erase(supplyFetchTargetState.targetId); // Remove current target from queue
supplyFetchTargetState.valid = false; // Invalidate supply state
supplyFetchTargetState.entry = nullptr;
DPRINTF(DecoupleBP,
"Finish current fetch target: %lu, inc demand to %lu\n",
supplyFetchTargetState.targetId, fetchDemandTargetId);
}
/**
* @brief Try to supply fetch with a target matching the demand PC
*
* This method attempts to find a fetch target that matches the current
* demand target ID. If found, it updates the supply state to provide
* this target to the fetch unit.
*
* @param fetch_demand_pc The PC that fetch is requesting
* @param in_loop Output parameter set to true if the target is in a loop
* @return true if a target was successfully located and supplied
*/
bool
FetchTargetQueue::trySupplyFetchWithTarget(Addr fetch_demand_pc, bool &in_loop)
{
// If we don't already have a valid supply state matching the demand
if (!supplyFetchTargetState.valid ||
supplyFetchTargetState.targetId != fetchDemandTargetId) {
// Try to find the target in the queue
auto it = ftq.find(fetchDemandTargetId);
if (it != ftq.end()) {
// Special case: fetch PC is already past the end of this target
if (M5_UNLIKELY(fetch_demand_pc >= it->second.endPC)) {
// In this case, we should just finish the current target
// and supply the fetch with the next one
DPRINTF(DecoupleBP,
"Skip ftq entry %lu: [%#lx, %#lx),", it->first,
it->second.startPC, it->second.endPC);
++fetchDemandTargetId; // Move to next target
it = ftq.erase(it); // Remove current target
if (it == ftq.end()) {
// No next target available
in_loop = false;
return false;
}
DPRINTFR(DecoupleBP,
" use %lu: [%#lx, %#lx) instead. because demand pc "
"past the first entry.\n",
it->first, it->second.startPC, it->second.endPC);
}
// Update supply state with found target
DPRINTF(DecoupleBP,
"Found ftq entry with id %lu, writing to "
"fetchReadFtqEntryBuffer\n",
fetchDemandTargetId);
supplyFetchTargetState.valid = true;
supplyFetchTargetState.targetId = fetchDemandTargetId;
supplyFetchTargetState.entry = &(it->second);
return true;
} else {
// Target not found in queue
DPRINTF(DecoupleBP, "Target id %lu not found\n",
fetchDemandTargetId);
if (!ftq.empty()) {
// Sanity check: demand ID should not be less than smallest entry
--it;
DPRINTF(DecoupleBP, "Last entry of target queue: %lu\n",
it->first);
if (it->first > fetchDemandTargetId) {
dump("targets in buffer goes beyond demand\n");
}
assert(it->first < fetchDemandTargetId);
}
in_loop = false;
return false;
}
}
// Already have valid supply state
DPRINTF(DecoupleBP,
"FTQ supplying, valid: %u, supply id: %lu, demand id: %lu\n",
supplyFetchTargetState.valid, supplyFetchTargetState.targetId,
fetchDemandTargetId);
return true;
}
/**
* @brief Get the iterator for the currently demanded target
*
* @return Pair containing a boolean (true if found) and the iterator
*/
std::pair<bool, FetchTargetQueue::FTQIt>
FetchTargetQueue::getDemandTargetIt()
{
FTQIt it = ftq.find(fetchDemandTargetId);
return std::make_pair(it != ftq.end(), it);
}
/**
* @brief Add a new entry to the queue
*
* This method adds a new fetch target entry to the queue and
* advances the next enqueue target ID.
*
* @param entry The fetch target entry to add
*/
void
FetchTargetQueue::enqueue(FtqEntry entry)
{
DPRINTF(DecoupleBP, "Enqueueing target %lu with pc %#lx and stream %lu\n",
fetchTargetEnqState.nextEnqTargetId, entry.startPC, entry.fsqID);
ftq[fetchTargetEnqState.nextEnqTargetId] = entry;
++fetchTargetEnqState.nextEnqTargetId;
}
/**
* @brief Print debug information about the queue
*
* Dumps the contents of the queue for debugging purposes.
*
* @param when String describing when the dump was triggered
*/
void
FetchTargetQueue::dump(const char* when)
{
DPRINTF(DecoupleBPProbe, "%s, dump FTQ\n", when);
for (auto it = ftq.begin(); it != ftq.end(); ++it) {
DPRINTFR(DecoupleBPProbe, "FTQ entry: %lu, start pc: %#lx, end pc: %#lx, stream ID: %lu\n",
it->first, it->second.startPC, it->second.endPC, it->second.fsqID);
}
}
/**
* @brief Check if the supply fetch target state is valid
*
* @return true if there is a valid target in the supply state
*/
bool
FetchTargetQueue::validSupplyFetchTargetState() const
{
return supplyFetchTargetState.valid;
}
/**
* @brief Reset the program counter for the enqueue state
*
* This method is used when changing the PC but not doing a full squash.
*
* @param new_pc New program counter value
*/
void
FetchTargetQueue::resetPC(Addr new_pc)
{
supplyFetchTargetState.valid = false;
fetchTargetEnqState.pc = new_pc;
}
// NEW: 2Fetch support methods implementation
/**
* @brief Check if there is a next available FTQ entry
*
* @return true if next FTQ entry is available
*/
bool
FetchTargetQueue::hasNext() const
{
// Check if there's an entry with ID = fetchDemandTargetId + 1
auto next_it = ftq.find(fetchDemandTargetId + 1);
return next_it != ftq.end();
}
/**
* @brief Peek at the next FTQ entry without consuming it
*
* @return Reference to the next FTQ entry
*/
const FtqEntry&
FetchTargetQueue::peekNext() const
{
assert(hasNext());
auto next_it = ftq.find(fetchDemandTargetId + 1);
return next_it->second;
}
/**
* @brief Advance to the next FTQ entry without dequeuing current one
*
* Used for 2fetch when we want to process the next entry
* while keeping the current one active
*/
void
FetchTargetQueue::advance()
{
// Already moved to next target ID in processFetchTargetCompletion
// Update supply state to point to new target
auto next_it = ftq.find(fetchDemandTargetId);
if (next_it != ftq.end()) {
supplyFetchTargetState.valid = true;
supplyFetchTargetState.targetId = fetchDemandTargetId;
supplyFetchTargetState.entry = &(next_it->second);
DPRINTF(DecoupleBP,
"Advanced to next FTQ entry: ID %lu, PC [%#lx, %#lx)\n",
fetchDemandTargetId, next_it->second.startPC, next_it->second.endPC);
} else {
supplyFetchTargetState.valid = false;
supplyFetchTargetState.entry = nullptr;
}
}
} // namespace btb_pred
} // namespace branch_prediction
} // namespace gem5