-
Notifications
You must be signed in to change notification settings - Fork 0
/
FetchUnitManager.cpp
237 lines (189 loc) · 5.05 KB
/
FetchUnitManager.cpp
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
// Luke Mitchell, 2015
#include <iostream>
#include <sstream>
#include <iomanip>
#include "FetchUnitManager.h"
FetchUnitManager::FetchUnitManager(unsigned int width, DecodeUnitManager* dum) {
// Store a local reference to the DU manager
this->dum = dum;
// Set up PC
pc.contents = 0;
// Nothing has been issued yet...
lastIssued = 0;
// Not speculative yet...
speculative = false;
// Set up the Fetch Units
fus.assign(width, FetchUnit(dum));
// Set debugging to false, by default
setDebug(false);
// Set branch prediction to true, by default
setDynamicBranchPrediction(true);
}
void FetchUnitManager::setDebug(bool debug) {
this->debug = debug;
for (int i = 0; i < fus.size(); i++) {
fus[i].debug = debug;
}
}
bool FetchUnitManager::getDebug() {
return debug;
}
void FetchUnitManager::setBranchPrediction(bool branchPrediction) {
this->branchPrediction = branchPrediction;
for (int i = 0; i < fus.size(); i++) {
fus[i].branchPrediction = branchPrediction;
}
}
bool FetchUnitManager::getBranchPrediction() {
return branchPrediction;
}
void FetchUnitManager::setDynamicBranchPrediction(bool dynamicBranchPrediction) {
// Set branch prediction to be the same
// We cannot be dynamically predicting if we're not predicting!
if (dynamicBranchPrediction) {
setBranchPrediction(dynamicBranchPrediction);
}
// Now set dynamic branch prediction flag
this->dynamicBranchPrediction = dynamicBranchPrediction;
// and propagate to Fetch Units
for (int i = 0; i < fus.size(); i++) {
fus[i].dynamicBranchPrediction = dynamicBranchPrediction;
}
}
bool FetchUnitManager::getDynamicBranchPrediction() {
return dynamicBranchPrediction;
}
void FetchUnitManager::setSpeculative(bool speculative) {
this->speculative = speculative;
for (int i = 0; i < fus.size(); i++) {
fus[i].speculative = speculative;
}
}
bool FetchUnitManager::getSpeculative() {
return speculative;
}
std::string FetchUnitManager::toString() {
std::ostringstream ss;
ss << "FetchUnitManager with " << fus.size() << " FUs." << std::endl;
for (int i = 0; i < fus.size(); i++) {
ss << "[FU #" << i << "]" << std::endl;
ss << fus[i].toString();
ss << std::endl;
}
return ss.str();
}
void FetchUnitManager::tick(std::vector<MemoryLocation>* m, bool pipeline,
BranchPredictionTable* bpt, BranchHistoryTable* bht) {
// Instructions should be issued to DU oldest-first;
// this is to prevent stagnation in the pipeline.
// According to Neil Burgess (a guest lecturer from ARM), this is
// fairly easy to do in hardware.
// Use a queue for simulation
while (!waiting.empty()){
auto i = waiting.front();
if (debug) {
std::cout << "[FU #" << i << "] trying to issue stored instruction." << std::endl;
}
if (!fus[i].passToDecodeUnit()) {
break;
}
waiting.pop();
}
// Resolve any stalls in pipeline
for (int i = 0; i < fus.size(); i++) {
if (fus[i].stalled) {
if (fus[i].checkForStallResolution(bpt, &pc)) {
if (debug) {
std::cout << "[FU #" << i << "] stall resolved!" << std::endl;
}
} else {
// We have stalled...
return;
}
break;
}
}
// Don't fetch if we're halted
for (int i = 0; i < fus.size(); i++) {
if (fus[i].halted) {
return;
}
}
// Tick all FUs
for (int i = 0; i < fus.size(); i++) {
// Skip a waiting FU
if (fus[i].fetched) {
continue;
}
if (debug) {
std::cout << "[FU #" << i << "] calling tick()." << std::endl;
}
// Create dependents vector. This is all
// other FUs.
std::vector<FetchUnit> dependents(fus);
dependents.erase(dependents.begin() + i);
// Call tick!
fus[i].speculative = getSpeculative();
fus[i].tick(m, &dependents, pipeline, bpt, bht, &pc);
// Add to waiting queue
if (fus[i].fetched) {
waiting.push(i);
}
if (fus[i].speculative) {
// All future instructions will be marked
// as speculative
speculative = true;
}
if (fus[i].dependent) {
// Don't fill up the other FUs
break;
}
if (fus[i].stalled) {
// Don't fill the other FUs
break;
}
if (fus[i].halted) {
// Don't fill the other FUs
break;
}
}
}
// Retrieve an available FU
// Returns the FU or NULL;
FetchUnit* FetchUnitManager::getAvailableFetchUnit() {
for (int i = 0; i < fus.size(); i++) {
if (fus[i].ready && !fus[i].fetched) {
if (debug) {
std::cout << "[FU #" << i << "] I am available!" << std::endl;
}
return &fus[i];
}
}
return NULL;
}
// Removes speculative values after incorrect branch prediction
void FetchUnitManager::clearPipeline(uint32_t pc) {
// Clear the FUs
for (int i = 0; i < fus.size(); i++) {
if (fus[i].speculative) {
fus[i].clear();
}
}
// Empty the waiting queue
std::queue<int>().swap(waiting);
// Reset the PC
this->pc.contents = pc;
if (debug) {
std::cout << "Setting PC to " << this->pc.toString() << " after clearing pipeline." << std::endl;
}
// Reset the speculative flags
setSpeculative(false);
}
unsigned int FetchUnitManager::getNumberOfBranches() {
unsigned int n = 0;
for (int i = 0; i < fus.size(); i++) {
n += fus[i].getNumberOfBranches();
}
return n;
}