scoreboard.cc (13597:6b0f8e9cdeb5) scoreboard.cc (13610:5d5404ac6288)
1/*
1/*
2 * Copyright (c) 2013-2014, 2016 ARM Limited
2 * Copyright (c) 2013-2014, 2016-2017 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andrew Bardsley
38 */
39
40#include "cpu/minor/scoreboard.hh"
41
42#include "arch/registers.hh"
43#include "cpu/reg_class.hh"
44#include "debug/MinorScoreboard.hh"
45#include "debug/MinorTiming.hh"
46
47namespace Minor
48{
49
50bool
51Scoreboard::findIndex(const RegId& reg, Index &scoreboard_index)
52{
53 bool ret = false;
54
55 if (reg.isZeroReg()) {
56 /* Don't bother with the zero register */
57 ret = false;
58 } else {
59 switch (reg.classValue())
60 {
61 case IntRegClass:
62 scoreboard_index = reg.index();
63 ret = true;
64 break;
65 case FloatRegClass:
66 scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
67 reg.index();
68 ret = true;
69 break;
70 case VecRegClass:
71 scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
72 TheISA::NumFloatRegs + reg.index();
73 ret = true;
74 break;
75 case VecElemClass:
76 scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
77 TheISA::NumFloatRegs + reg.flatIndex();
78 ret = true;
79 break;
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andrew Bardsley
38 */
39
40#include "cpu/minor/scoreboard.hh"
41
42#include "arch/registers.hh"
43#include "cpu/reg_class.hh"
44#include "debug/MinorScoreboard.hh"
45#include "debug/MinorTiming.hh"
46
47namespace Minor
48{
49
50bool
51Scoreboard::findIndex(const RegId& reg, Index &scoreboard_index)
52{
53 bool ret = false;
54
55 if (reg.isZeroReg()) {
56 /* Don't bother with the zero register */
57 ret = false;
58 } else {
59 switch (reg.classValue())
60 {
61 case IntRegClass:
62 scoreboard_index = reg.index();
63 ret = true;
64 break;
65 case FloatRegClass:
66 scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
67 reg.index();
68 ret = true;
69 break;
70 case VecRegClass:
71 scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
72 TheISA::NumFloatRegs + reg.index();
73 ret = true;
74 break;
75 case VecElemClass:
76 scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
77 TheISA::NumFloatRegs + reg.flatIndex();
78 ret = true;
79 break;
80 case VecPredRegClass:
81 scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
82 TheISA::NumFloatRegs + TheISA::NumVecRegs + reg.index();
83 ret = true;
84 break;
80 case CCRegClass:
81 scoreboard_index = TheISA::NumIntRegs + reg.index();
82 ret = true;
83 break;
84 case MiscRegClass:
85 /* Don't bother with Misc registers */
86 ret = false;
87 break;
88 default:
89 panic("Unknown register class: %d",
90 static_cast<int>(reg.classValue()));
91 }
92 }
93
94 return ret;
95}
96
97/** Flatten a RegId, irrespective of what reg type it's pointing to */
98static RegId
99flattenRegIndex(const RegId& reg, ThreadContext *thread_context)
100{
101 return thread_context->flattenRegId(reg);
102}
103
104void
105Scoreboard::markupInstDests(MinorDynInstPtr inst, Cycles retire_time,
106 ThreadContext *thread_context, bool mark_unpredictable)
107{
108 if (inst->isFault())
109 return;
110
111 StaticInstPtr staticInst = inst->staticInst;
112 unsigned int num_dests = staticInst->numDestRegs();
113
114 /** Mark each destination register */
115 for (unsigned int dest_index = 0; dest_index < num_dests;
116 dest_index++)
117 {
118 RegId reg = flattenRegIndex(
119 staticInst->destRegIdx(dest_index), thread_context);
120 Index index;
121
122 if (findIndex(reg, index)) {
123 if (mark_unpredictable)
124 numUnpredictableResults[index]++;
125
126 inst->flatDestRegIdx[dest_index] = reg;
127
128 numResults[index]++;
129 returnCycle[index] = retire_time;
130 /* We should be able to rely on only being given accending
131 * execSeqNums, but sanity check */
132 if (inst->id.execSeqNum > writingInst[index]) {
133 writingInst[index] = inst->id.execSeqNum;
134 fuIndices[index] = inst->fuIndex;
135 }
136
137 DPRINTF(MinorScoreboard, "Marking up inst: %s"
138 " regIndex: %d final numResults: %d returnCycle: %d\n",
139 *inst, index, numResults[index], returnCycle[index]);
140 } else {
141 /* Use ZeroReg to mark invalid/untracked dests */
142 inst->flatDestRegIdx[dest_index] = RegId(IntRegClass,
143 TheISA::ZeroReg);
144 }
145 }
146}
147
148InstSeqNum
149Scoreboard::execSeqNumToWaitFor(MinorDynInstPtr inst,
150 ThreadContext *thread_context)
151{
152 InstSeqNum ret = 0;
153
154 if (inst->isFault())
155 return ret;
156
157 StaticInstPtr staticInst = inst->staticInst;
158 unsigned int num_srcs = staticInst->numSrcRegs();
159
160 for (unsigned int src_index = 0; src_index < num_srcs; src_index++) {
161 RegId reg = flattenRegIndex(staticInst->srcRegIdx(src_index),
162 thread_context);
163 unsigned short int index;
164
165 if (findIndex(reg, index)) {
166 if (writingInst[index] > ret)
167 ret = writingInst[index];
168 }
169 }
170
171 DPRINTF(MinorScoreboard, "Inst: %s depends on execSeqNum: %d\n",
172 *inst, ret);
173
174 return ret;
175}
176
177void
178Scoreboard::clearInstDests(MinorDynInstPtr inst, bool clear_unpredictable)
179{
180 if (inst->isFault())
181 return;
182
183 StaticInstPtr staticInst = inst->staticInst;
184 unsigned int num_dests = staticInst->numDestRegs();
185
186 /** Mark each destination register */
187 for (unsigned int dest_index = 0; dest_index < num_dests;
188 dest_index++)
189 {
190 const RegId& reg = inst->flatDestRegIdx[dest_index];
191 Index index;
192
193 if (findIndex(reg, index)) {
194 if (clear_unpredictable && numUnpredictableResults[index] != 0)
195 numUnpredictableResults[index] --;
196
197 numResults[index] --;
198
199 if (numResults[index] == 0) {
200 returnCycle[index] = Cycles(0);
201 writingInst[index] = 0;
202 fuIndices[index] = -1;
203 }
204
205 DPRINTF(MinorScoreboard, "Clearing inst: %s"
206 " regIndex: %d final numResults: %d\n",
207 *inst, index, numResults[index]);
208 }
209 }
210}
211
212bool
213Scoreboard::canInstIssue(MinorDynInstPtr inst,
214 const std::vector<Cycles> *src_reg_relative_latencies,
215 const std::vector<bool> *cant_forward_from_fu_indices,
216 Cycles now, ThreadContext *thread_context)
217{
218 /* Always allow fault to be issued */
219 if (inst->isFault())
220 return true;
221
222 StaticInstPtr staticInst = inst->staticInst;
223 unsigned int num_srcs = staticInst->numSrcRegs();
224
225 /* Default to saying you can issue */
226 bool ret = true;
227
228 unsigned int num_relative_latencies = 0;
229 Cycles default_relative_latency = Cycles(0);
230
231 /* Where relative latencies are given, the default is the last
232 * one as that allows the rel. lat. list to be shorted than the
233 * number of src. regs */
234 if (src_reg_relative_latencies &&
235 src_reg_relative_latencies->size() != 0)
236 {
237 num_relative_latencies = src_reg_relative_latencies->size();
238 default_relative_latency = (*src_reg_relative_latencies)
239 [num_relative_latencies-1];
240 }
241
242 /* For each source register, find the latest result */
243 unsigned int src_index = 0;
244 while (src_index < num_srcs && /* More registers */
245 ret /* Still possible */)
246 {
247 RegId reg = flattenRegIndex(staticInst->srcRegIdx(src_index),
248 thread_context);
249 unsigned short int index;
250
251 if (findIndex(reg, index)) {
252 bool cant_forward = fuIndices[index] != 1 &&
253 cant_forward_from_fu_indices &&
254 index < cant_forward_from_fu_indices->size() &&
255 (*cant_forward_from_fu_indices)[index];
256
257 Cycles relative_latency = (cant_forward ? Cycles(0) :
258 (src_index >= num_relative_latencies ?
259 default_relative_latency :
260 (*src_reg_relative_latencies)[src_index]));
261
262 if (returnCycle[index] > (now + relative_latency) ||
263 numUnpredictableResults[index] != 0)
264 {
265 ret = false;
266 }
267 }
268 src_index++;
269 }
270
271 if (DTRACE(MinorTiming)) {
272 if (ret && num_srcs > num_relative_latencies &&
273 num_relative_latencies != 0)
274 {
275 DPRINTF(MinorTiming, "Warning, inst: %s timing extra decode has"
276 " more src. regs: %d than relative latencies: %d\n",
277 staticInst->disassemble(0), num_srcs, num_relative_latencies);
278 }
279 }
280
281 return ret;
282}
283
284void
285Scoreboard::minorTrace() const
286{
287 std::ostringstream result_stream;
288
289 bool printed_element = false;
290
291 unsigned int i = 0;
292 while (i < numRegs) {
293 unsigned short int num_results = numResults[i];
294 unsigned short int num_unpredictable_results =
295 numUnpredictableResults[i];
296
297 if (!(num_results == 0 && num_unpredictable_results == Cycles(0))) {
298 if (printed_element)
299 result_stream << ',';
300
301 result_stream << '(' << i << ','
302 << num_results << '/'
303 << num_unpredictable_results << '/'
304 << returnCycle[i] << '/'
305 << writingInst[i] << ')';
306
307 printed_element = true;
308 }
309
310 i++;
311 }
312
313 MINORTRACE("busy=%s\n", result_stream.str());
314}
315
316}
85 case CCRegClass:
86 scoreboard_index = TheISA::NumIntRegs + reg.index();
87 ret = true;
88 break;
89 case MiscRegClass:
90 /* Don't bother with Misc registers */
91 ret = false;
92 break;
93 default:
94 panic("Unknown register class: %d",
95 static_cast<int>(reg.classValue()));
96 }
97 }
98
99 return ret;
100}
101
102/** Flatten a RegId, irrespective of what reg type it's pointing to */
103static RegId
104flattenRegIndex(const RegId& reg, ThreadContext *thread_context)
105{
106 return thread_context->flattenRegId(reg);
107}
108
109void
110Scoreboard::markupInstDests(MinorDynInstPtr inst, Cycles retire_time,
111 ThreadContext *thread_context, bool mark_unpredictable)
112{
113 if (inst->isFault())
114 return;
115
116 StaticInstPtr staticInst = inst->staticInst;
117 unsigned int num_dests = staticInst->numDestRegs();
118
119 /** Mark each destination register */
120 for (unsigned int dest_index = 0; dest_index < num_dests;
121 dest_index++)
122 {
123 RegId reg = flattenRegIndex(
124 staticInst->destRegIdx(dest_index), thread_context);
125 Index index;
126
127 if (findIndex(reg, index)) {
128 if (mark_unpredictable)
129 numUnpredictableResults[index]++;
130
131 inst->flatDestRegIdx[dest_index] = reg;
132
133 numResults[index]++;
134 returnCycle[index] = retire_time;
135 /* We should be able to rely on only being given accending
136 * execSeqNums, but sanity check */
137 if (inst->id.execSeqNum > writingInst[index]) {
138 writingInst[index] = inst->id.execSeqNum;
139 fuIndices[index] = inst->fuIndex;
140 }
141
142 DPRINTF(MinorScoreboard, "Marking up inst: %s"
143 " regIndex: %d final numResults: %d returnCycle: %d\n",
144 *inst, index, numResults[index], returnCycle[index]);
145 } else {
146 /* Use ZeroReg to mark invalid/untracked dests */
147 inst->flatDestRegIdx[dest_index] = RegId(IntRegClass,
148 TheISA::ZeroReg);
149 }
150 }
151}
152
153InstSeqNum
154Scoreboard::execSeqNumToWaitFor(MinorDynInstPtr inst,
155 ThreadContext *thread_context)
156{
157 InstSeqNum ret = 0;
158
159 if (inst->isFault())
160 return ret;
161
162 StaticInstPtr staticInst = inst->staticInst;
163 unsigned int num_srcs = staticInst->numSrcRegs();
164
165 for (unsigned int src_index = 0; src_index < num_srcs; src_index++) {
166 RegId reg = flattenRegIndex(staticInst->srcRegIdx(src_index),
167 thread_context);
168 unsigned short int index;
169
170 if (findIndex(reg, index)) {
171 if (writingInst[index] > ret)
172 ret = writingInst[index];
173 }
174 }
175
176 DPRINTF(MinorScoreboard, "Inst: %s depends on execSeqNum: %d\n",
177 *inst, ret);
178
179 return ret;
180}
181
182void
183Scoreboard::clearInstDests(MinorDynInstPtr inst, bool clear_unpredictable)
184{
185 if (inst->isFault())
186 return;
187
188 StaticInstPtr staticInst = inst->staticInst;
189 unsigned int num_dests = staticInst->numDestRegs();
190
191 /** Mark each destination register */
192 for (unsigned int dest_index = 0; dest_index < num_dests;
193 dest_index++)
194 {
195 const RegId& reg = inst->flatDestRegIdx[dest_index];
196 Index index;
197
198 if (findIndex(reg, index)) {
199 if (clear_unpredictable && numUnpredictableResults[index] != 0)
200 numUnpredictableResults[index] --;
201
202 numResults[index] --;
203
204 if (numResults[index] == 0) {
205 returnCycle[index] = Cycles(0);
206 writingInst[index] = 0;
207 fuIndices[index] = -1;
208 }
209
210 DPRINTF(MinorScoreboard, "Clearing inst: %s"
211 " regIndex: %d final numResults: %d\n",
212 *inst, index, numResults[index]);
213 }
214 }
215}
216
217bool
218Scoreboard::canInstIssue(MinorDynInstPtr inst,
219 const std::vector<Cycles> *src_reg_relative_latencies,
220 const std::vector<bool> *cant_forward_from_fu_indices,
221 Cycles now, ThreadContext *thread_context)
222{
223 /* Always allow fault to be issued */
224 if (inst->isFault())
225 return true;
226
227 StaticInstPtr staticInst = inst->staticInst;
228 unsigned int num_srcs = staticInst->numSrcRegs();
229
230 /* Default to saying you can issue */
231 bool ret = true;
232
233 unsigned int num_relative_latencies = 0;
234 Cycles default_relative_latency = Cycles(0);
235
236 /* Where relative latencies are given, the default is the last
237 * one as that allows the rel. lat. list to be shorted than the
238 * number of src. regs */
239 if (src_reg_relative_latencies &&
240 src_reg_relative_latencies->size() != 0)
241 {
242 num_relative_latencies = src_reg_relative_latencies->size();
243 default_relative_latency = (*src_reg_relative_latencies)
244 [num_relative_latencies-1];
245 }
246
247 /* For each source register, find the latest result */
248 unsigned int src_index = 0;
249 while (src_index < num_srcs && /* More registers */
250 ret /* Still possible */)
251 {
252 RegId reg = flattenRegIndex(staticInst->srcRegIdx(src_index),
253 thread_context);
254 unsigned short int index;
255
256 if (findIndex(reg, index)) {
257 bool cant_forward = fuIndices[index] != 1 &&
258 cant_forward_from_fu_indices &&
259 index < cant_forward_from_fu_indices->size() &&
260 (*cant_forward_from_fu_indices)[index];
261
262 Cycles relative_latency = (cant_forward ? Cycles(0) :
263 (src_index >= num_relative_latencies ?
264 default_relative_latency :
265 (*src_reg_relative_latencies)[src_index]));
266
267 if (returnCycle[index] > (now + relative_latency) ||
268 numUnpredictableResults[index] != 0)
269 {
270 ret = false;
271 }
272 }
273 src_index++;
274 }
275
276 if (DTRACE(MinorTiming)) {
277 if (ret && num_srcs > num_relative_latencies &&
278 num_relative_latencies != 0)
279 {
280 DPRINTF(MinorTiming, "Warning, inst: %s timing extra decode has"
281 " more src. regs: %d than relative latencies: %d\n",
282 staticInst->disassemble(0), num_srcs, num_relative_latencies);
283 }
284 }
285
286 return ret;
287}
288
289void
290Scoreboard::minorTrace() const
291{
292 std::ostringstream result_stream;
293
294 bool printed_element = false;
295
296 unsigned int i = 0;
297 while (i < numRegs) {
298 unsigned short int num_results = numResults[i];
299 unsigned short int num_unpredictable_results =
300 numUnpredictableResults[i];
301
302 if (!(num_results == 0 && num_unpredictable_results == Cycles(0))) {
303 if (printed_element)
304 result_stream << ',';
305
306 result_stream << '(' << i << ','
307 << num_results << '/'
308 << num_unpredictable_results << '/'
309 << returnCycle[i] << '/'
310 << writingInst[i] << ')';
311
312 printed_element = true;
313 }
314
315 i++;
316 }
317
318 MINORTRACE("busy=%s\n", result_stream.str());
319}
320
321}