cpu: `Minor' in-order CPU model
[gem5.git] / src / cpu / minor / scoreboard.cc
1 /*
2 * Copyright (c) 2013-2014 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 "arch/registers.hh"
41 #include "cpu/minor/scoreboard.hh"
42 #include "cpu/reg_class.hh"
43 #include "debug/MinorScoreboard.hh"
44 #include "debug/MinorTiming.hh"
45
46 namespace Minor
47 {
48
49 bool
50 Scoreboard::findIndex(RegIndex reg, Index &scoreboard_index)
51 {
52 RegClass reg_class = regIdxToClass(reg);
53 bool ret = false;
54
55 if (reg == TheISA::ZeroReg) {
56 /* Don't bother with the zero register */
57 ret = false;
58 } else {
59 switch (reg_class)
60 {
61 case IntRegClass:
62 scoreboard_index = reg;
63 ret = true;
64 break;
65 case FloatRegClass:
66 scoreboard_index = TheISA::NumIntRegs + TheISA::NumCCRegs +
67 reg - TheISA::FP_Reg_Base;
68 ret = true;
69 break;
70 case CCRegClass:
71 scoreboard_index = TheISA::NumIntRegs + reg - TheISA::FP_Reg_Base;
72 ret = true;
73 break;
74 case MiscRegClass:
75 /* Don't bother with Misc registers */
76 ret = false;
77 break;
78 }
79 }
80
81 return ret;
82 }
83
84 /** Flatten a RegIndex, irrespective of what reg type it's pointing to */
85 static TheISA::RegIndex
86 flattenRegIndex(TheISA::RegIndex reg, ThreadContext *thread_context)
87 {
88 RegClass reg_class = regIdxToClass(reg);
89 TheISA::RegIndex ret = reg;
90
91 switch (reg_class)
92 {
93 case IntRegClass:
94 ret = thread_context->flattenIntIndex(reg);
95 break;
96 case FloatRegClass:
97 ret = thread_context->flattenFloatIndex(reg);
98 break;
99 case CCRegClass:
100 ret = thread_context->flattenCCIndex(reg);
101 break;
102 case MiscRegClass:
103 /* Don't bother to flatten misc regs as we don't need them here */
104 /* return thread_context->flattenMiscIndex(reg); */
105 ret = reg;
106 break;
107 }
108
109 return ret;
110 }
111
112 void
113 Scoreboard::markupInstDests(MinorDynInstPtr inst, Cycles retire_time,
114 ThreadContext *thread_context, bool mark_unpredictable)
115 {
116 if (inst->isFault())
117 return;
118
119 StaticInstPtr staticInst = inst->staticInst;
120 unsigned int num_dests = staticInst->numDestRegs();
121
122 /** Mark each destination register */
123 for (unsigned int dest_index = 0; dest_index < num_dests;
124 dest_index++)
125 {
126 RegIndex reg = flattenRegIndex(
127 staticInst->destRegIdx(dest_index), thread_context);
128 Index index;
129
130 if (findIndex(reg, index)) {
131 if (mark_unpredictable)
132 numUnpredictableResults[index]++;
133
134 inst->flatDestRegIdx[dest_index] = reg;
135
136 numResults[index]++;
137 returnCycle[index] = retire_time;
138 /* We should be able to rely on only being given accending
139 * execSeqNums, but sanity check */
140 if (inst->id.execSeqNum > writingInst[index]) {
141 writingInst[index] = inst->id.execSeqNum;
142 fuIndices[index] = inst->fuIndex;
143 }
144
145 DPRINTF(MinorScoreboard, "Marking up inst: %s"
146 " regIndex: %d final numResults: %d returnCycle: %d\n",
147 *inst, index, numResults[index], returnCycle[index]);
148 } else {
149 /* Use ZeroReg to mark invalid/untracked dests */
150 inst->flatDestRegIdx[dest_index] = TheISA::ZeroReg;
151 }
152 }
153 }
154
155 InstSeqNum
156 Scoreboard::execSeqNumToWaitFor(MinorDynInstPtr inst,
157 ThreadContext *thread_context)
158 {
159 InstSeqNum ret = 0;
160
161 if (inst->isFault())
162 return ret;
163
164 StaticInstPtr staticInst = inst->staticInst;
165 unsigned int num_srcs = staticInst->numSrcRegs();
166
167 for (unsigned int src_index = 0; src_index < num_srcs; src_index++) {
168 RegIndex reg = flattenRegIndex(staticInst->srcRegIdx(src_index),
169 thread_context);
170 unsigned short int index;
171
172 if (findIndex(reg, index)) {
173 if (writingInst[index] > ret)
174 ret = writingInst[index];
175 }
176 }
177
178 DPRINTF(MinorScoreboard, "Inst: %s depends on execSeqNum: %d\n",
179 *inst, ret);
180
181 return ret;
182 }
183
184 void
185 Scoreboard::clearInstDests(MinorDynInstPtr inst, bool clear_unpredictable)
186 {
187 if (inst->isFault())
188 return;
189
190 StaticInstPtr staticInst = inst->staticInst;
191 unsigned int num_dests = staticInst->numDestRegs();
192
193 /** Mark each destination register */
194 for (unsigned int dest_index = 0; dest_index < num_dests;
195 dest_index++)
196 {
197 RegIndex reg = inst->flatDestRegIdx[dest_index];
198 Index index;
199
200 if (findIndex(reg, index)) {
201 if (clear_unpredictable && numUnpredictableResults[index] != 0)
202 numUnpredictableResults[index] --;
203
204 numResults[index] --;
205
206 if (numResults[index] == 0) {
207 returnCycle[index] = Cycles(0);
208 writingInst[index] = 0;
209 fuIndices[index] = -1;
210 }
211
212 DPRINTF(MinorScoreboard, "Clearing inst: %s"
213 " regIndex: %d final numResults: %d\n",
214 *inst, index, numResults[index]);
215 }
216 }
217 }
218
219 bool
220 Scoreboard::canInstIssue(MinorDynInstPtr inst,
221 const std::vector<Cycles> *src_reg_relative_latencies,
222 const std::vector<bool> *cant_forward_from_fu_indices,
223 Cycles now, ThreadContext *thread_context)
224 {
225 /* Always allow fault to be issued */
226 if (inst->isFault())
227 return true;
228
229 StaticInstPtr staticInst = inst->staticInst;
230 unsigned int num_srcs = staticInst->numSrcRegs();
231
232 /* Default to saying you can issue */
233 bool ret = true;
234
235 unsigned int num_relative_latencies = 0;
236 Cycles default_relative_latency = Cycles(0);
237
238 /* Where relative latencies are given, the default is the last
239 * one as that allows the rel. lat. list to be shorted than the
240 * number of src. regs */
241 if (src_reg_relative_latencies &&
242 src_reg_relative_latencies->size() != 0)
243 {
244 num_relative_latencies = src_reg_relative_latencies->size();
245 default_relative_latency = (*src_reg_relative_latencies)
246 [num_relative_latencies-1];
247 }
248
249 /* For each source register, find the latest result */
250 unsigned int src_index = 0;
251 while (src_index < num_srcs && /* More registers */
252 ret /* Still possible */)
253 {
254 RegIndex reg = flattenRegIndex(staticInst->srcRegIdx(src_index),
255 thread_context);
256 unsigned short int index;
257
258 if (findIndex(reg, index)) {
259 bool cant_forward = fuIndices[index] != 1 &&
260 cant_forward_from_fu_indices &&
261 index < cant_forward_from_fu_indices->size() &&
262 (*cant_forward_from_fu_indices)[index];
263
264 Cycles relative_latency = (cant_forward ? Cycles(0) :
265 (src_index >= num_relative_latencies ?
266 default_relative_latency :
267 (*src_reg_relative_latencies)[src_index]));
268
269 if (returnCycle[index] > (now + relative_latency) ||
270 numUnpredictableResults[index] != 0)
271 {
272 ret = false;
273 }
274 }
275 src_index++;
276 }
277
278 if (DTRACE(MinorTiming)) {
279 if (ret && num_srcs > num_relative_latencies &&
280 num_relative_latencies != 0)
281 {
282 DPRINTF(MinorTiming, "Warning, inst: %s timing extra decode has"
283 " more src. regs: %d than relative latencies: %d\n",
284 staticInst->disassemble(0), num_srcs, num_relative_latencies);
285 }
286 }
287
288 return ret;
289 }
290
291 void
292 Scoreboard::minorTrace() const
293 {
294 std::ostringstream result_stream;
295
296 bool printed_element = false;
297
298 unsigned int i = 0;
299 while (i < numRegs) {
300 unsigned short int num_results = numResults[i];
301 unsigned short int num_unpredictable_results =
302 numUnpredictableResults[i];
303
304 if (!(num_results == 0 && num_unpredictable_results == Cycles(0))) {
305 if (printed_element)
306 result_stream << ',';
307
308 result_stream << '(' << i << ','
309 << num_results << '/'
310 << num_unpredictable_results << '/'
311 << returnCycle[i] << '/'
312 << writingInst[i] << ')';
313
314 printed_element = true;
315 }
316
317 i++;
318 }
319
320 MINORTRACE("busy=%s\n", result_stream.str());
321 }
322
323 }