includes: sort all includes
[gem5.git] / src / cpu / inorder / resources / use_def.cc
1 /*
2 * Copyright (c) 2007 MIPS Technologies, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Korey Sewell
29 *
30 */
31
32 #include <list>
33 #include <vector>
34
35 #include "arch/isa_traits.hh"
36 #include "config/the_isa.hh"
37 #include "cpu/inorder/resources/use_def.hh"
38 #include "cpu/inorder/cpu.hh"
39 #include "cpu/inorder/pipeline_traits.hh"
40
41 using namespace std;
42 using namespace TheISA;
43 using namespace ThePipeline;
44
45 UseDefUnit::UseDefUnit(string res_name, int res_id, int res_width,
46 int res_latency, InOrderCPU *_cpu,
47 ThePipeline::Params *params)
48 : Resource(res_name, res_id, res_width, res_latency, _cpu),
49 maxSeqNum((InstSeqNum)-1)
50 {
51 for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
52 nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
53 nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
54
55 outReadSeqNum[tid] = maxSeqNum;
56 outWriteSeqNum[tid] = maxSeqNum;
57
58 regDepMap[tid] = &cpu->archRegDepMap[tid];
59 }
60
61 }
62
63 void
64 UseDefUnit::regStats()
65 {
66 uniqueRegsPerSwitch
67 .name(name() + ".uniqueRegsPerSwitch")
68 .desc("Number of Unique Registers Needed Per Context Switch")
69 .prereq(uniqueRegsPerSwitch);
70
71 regFileReads
72 .name(name() + ".regFileReads")
73 .desc("Number of Reads from Register File");
74
75 regForwards
76 .name(name() + ".regForwards")
77 .desc("Number of Registers Read Through Forwarding Logic");
78
79 regFileWrites
80 .name(name() + ".regFileWrites")
81 .desc("Number of Writes to Register File");
82
83 regFileAccs
84 .name(name() + ".regFileAccesses")
85 .desc("Number of Total Accesses (Read+Write) to the Register File");
86 regFileAccs = regFileReads + regFileWrites;
87
88 Resource::regStats();
89 }
90
91 void
92 UseDefUnit::init()
93 {
94 // Set Up Resource Events to Appropriate Resource BandWidth
95 if (latency > 0) {
96 resourceEvent = new ResourceEvent[width];
97 } else {
98 resourceEvent = NULL;
99 }
100
101 for (int i = 0; i < width; i++) {
102 reqs[i] = new UseDefRequest(this);
103 }
104
105 initSlots();
106 }
107
108 ResReqPtr
109 UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
110 int slot_num, unsigned cmd)
111 {
112 UseDefRequest *ud_req = dynamic_cast<UseDefRequest*>(reqs[slot_num]);
113 ud_req->setRequest(inst, stage_num, id, slot_num, cmd,
114 inst->curSkedEntry->idx);
115 return ud_req;
116 }
117
118
119 ResReqPtr
120 UseDefUnit::findRequest(DynInstPtr inst)
121 {
122 for (int i = 0; i < width; i++) {
123 UseDefRequest* ud_req =
124 dynamic_cast<UseDefRequest*>(reqs[i]);
125 assert(ud_req);
126
127 if (ud_req->valid &&
128 ud_req->getInst() == inst &&
129 ud_req->cmd == inst->curSkedEntry->cmd &&
130 ud_req->useDefIdx == inst->curSkedEntry->idx) {
131 return ud_req;
132 }
133 }
134
135 return NULL;
136 }
137
138 void
139 UseDefUnit::execute(int slot_idx)
140 {
141 // After this is working, change this to a reinterpret cast
142 // for performance considerations
143 UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqs[slot_idx]);
144 assert(ud_req);
145
146 DynInstPtr inst = ud_req->inst;
147 ThreadID tid = inst->readTid();
148 InstSeqNum seq_num = inst->seqNum;
149 int ud_idx = ud_req->useDefIdx;
150
151 // If there is a non-speculative instruction
152 // in the pipeline then stall instructions here
153 if (*nonSpecInstActive[tid] == true &&
154 seq_num > *nonSpecSeqNum[tid]) {
155 DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] cannot execute because"
156 "there is non-speculative instruction [sn:%i] has not "
157 "graduated.\n", tid, seq_num, *nonSpecSeqNum[tid]);
158 return;
159 } else if (inst->isNonSpeculative()) {
160 *nonSpecInstActive[tid] = true;
161 *nonSpecSeqNum[tid] = seq_num;
162 }
163
164 switch (ud_req->cmd)
165 {
166 case ReadSrcReg:
167 {
168 int reg_idx = inst->_srcRegIdx[ud_idx];
169
170 DPRINTF(InOrderUseDef, "[tid:%i]: Attempting to read source "
171 "register idx %i (reg #%i).\n",
172 tid, ud_idx, reg_idx);
173
174 // Ask register dependency map if it is OK to read from Arch.
175 // Reg. File
176 if (regDepMap[tid]->canRead(reg_idx, inst)) {
177
178 uniqueRegMap[reg_idx] = true;
179
180 if (inst->seqNum <= outReadSeqNum[tid]) {
181 if (reg_idx < FP_Base_DepTag) {
182 DPRINTF(InOrderUseDef, "[tid:%i]: Reading Int Reg %i"
183 "from Register File:%i.\n",
184 tid,
185 reg_idx,
186 cpu->readIntReg(reg_idx,inst->readTid()));
187 inst->setIntSrc(ud_idx,
188 cpu->readIntReg(reg_idx,
189 inst->readTid()));
190 } else if (reg_idx < Ctrl_Base_DepTag) {
191 reg_idx -= FP_Base_DepTag;
192 DPRINTF(InOrderUseDef, "[tid:%i]: Reading Float Reg %i"
193 "from Register File:%x (%08f).\n",
194 tid,
195 reg_idx,
196 cpu->readFloatRegBits(reg_idx,
197 inst->readTid()),
198 cpu->readFloatReg(reg_idx,
199 inst->readTid()));
200
201 inst->setFloatSrc(ud_idx,
202 cpu->readFloatReg(reg_idx,
203 inst->readTid()));
204 } else {
205 reg_idx -= Ctrl_Base_DepTag;
206 DPRINTF(InOrderUseDef, "[tid:%i]: Reading Misc Reg %i "
207 "from Register File:%i.\n",
208 tid,
209 reg_idx,
210 cpu->readMiscReg(reg_idx,
211 inst->readTid()));
212 inst->setIntSrc(ud_idx,
213 cpu->readMiscReg(reg_idx,
214 inst->readTid()));
215 }
216
217 outReadSeqNum[tid] = maxSeqNum;
218 regFileReads++;
219 ud_req->done();
220 } else {
221 DPRINTF(InOrderUseDef, "[tid:%i]: Unable to read because "
222 "of [sn:%i] hasnt read it's registers yet.\n",
223 tid, outReadSeqNum[tid]);
224 DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for "
225 "[sn:%i] to write\n",
226 tid, outReadSeqNum[tid]);
227 ud_req->done(false);
228 }
229
230 } else {
231 // Look for forwarding opportunities
232 DynInstPtr forward_inst = regDepMap[tid]->canForward(reg_idx,
233 inst);
234
235 if (forward_inst) {
236
237 if (inst->seqNum <= outReadSeqNum[tid]) {
238 int dest_reg_idx =
239 forward_inst->getDestIdxNum(reg_idx);
240
241 if (reg_idx < FP_Base_DepTag) {
242 DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
243 " reg value 0x%x from "
244 "[sn:%i] to [sn:%i] source #%i.\n",
245 tid,
246 forward_inst->readIntResult(dest_reg_idx),
247 forward_inst->seqNum,
248 inst->seqNum, ud_idx);
249 inst->setIntSrc(ud_idx,
250 forward_inst->
251 readIntResult(dest_reg_idx));
252 } else if (reg_idx < Ctrl_Base_DepTag) {
253 DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
254 " reg value 0x%x from "
255 "[sn:%i] to [sn:%i] source #%i.\n",
256 tid,
257 forward_inst->readFloatResult(dest_reg_idx),
258 forward_inst->seqNum, inst->seqNum, ud_idx);
259 inst->setFloatSrc(ud_idx,
260 forward_inst->
261 readFloatResult(dest_reg_idx));
262 } else {
263 DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest."
264 " reg value 0x%x from "
265 "[sn:%i] to [sn:%i] source #%i.\n",
266 tid,
267 forward_inst->readIntResult(dest_reg_idx),
268 forward_inst->seqNum,
269 inst->seqNum, ud_idx);
270 inst->setIntSrc(ud_idx,
271 forward_inst->
272 readIntResult(dest_reg_idx));
273 }
274
275 outReadSeqNum[tid] = maxSeqNum;
276 regForwards++;
277 ud_req->done();
278 } else {
279 DPRINTF(InOrderUseDef, "[tid:%i]: Unable to read "
280 "because of [sn:%i] hasnt read it's"
281 " registers yet.\n", tid, outReadSeqNum[tid]);
282 DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for "
283 "[sn:%i] to forward\n",
284 tid, outReadSeqNum[tid]);
285 ud_req->done(false);
286 }
287 } else {
288 DPRINTF(InOrderUseDef, "[tid:%i]: Source register idx: %i"
289 "is not ready to read.\n",
290 tid, reg_idx);
291 DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to read "
292 "register (idx=%i)\n",
293 tid, reg_idx);
294 outReadSeqNum[tid] = inst->seqNum;
295 ud_req->done(false);
296 }
297 }
298 }
299 break;
300
301 case WriteDestReg:
302 {
303 int reg_idx = inst->_destRegIdx[ud_idx];
304
305 if (regDepMap[tid]->canWrite(reg_idx, inst)) {
306 DPRINTF(InOrderUseDef, "[tid:%i]: Flattening register idx %i &"
307 "Attempting to write to Register File.\n",
308 tid, reg_idx);
309 uniqueRegMap[reg_idx] = true;
310 if (inst->seqNum <= outReadSeqNum[tid]) {
311 if (reg_idx < FP_Base_DepTag) {
312 DPRINTF(InOrderUseDef, "[tid:%i]: Writing Int. Result "
313 "0x%x to register idx %i.\n",
314 tid, inst->readIntResult(ud_idx), reg_idx);
315
316 // Remove Dependencies
317 regDepMap[tid]->removeFront(reg_idx, inst);
318
319 cpu->setIntReg(reg_idx,
320 inst->readIntResult(ud_idx),
321 inst->readTid());
322 } else if(reg_idx < Ctrl_Base_DepTag) {
323 // Remove Dependencies
324 regDepMap[tid]->removeFront(reg_idx, inst);
325
326 reg_idx -= FP_Base_DepTag;
327
328 if (inst->resultType(ud_idx) ==
329 InOrderDynInst::Integer) {
330 DPRINTF(InOrderUseDef, "[tid:%i]: Writing FP-Bits "
331 "Result 0x%x (bits:0x%x) to register "
332 "idx %i.\n",
333 tid,
334 inst->readFloatResult(ud_idx),
335 inst->readIntResult(ud_idx),
336 reg_idx);
337
338 // Check for FloatRegBits Here
339 cpu->setFloatRegBits(reg_idx,
340 inst->readIntResult(ud_idx),
341 inst->readTid());
342 } else if (inst->resultType(ud_idx) ==
343 InOrderDynInst::Float) {
344 DPRINTF(InOrderUseDef, "[tid:%i]: Writing Float "
345 "Result 0x%x (bits:0x%x) to register "
346 "idx %i.\n",
347 tid, inst->readFloatResult(ud_idx),
348 inst->readIntResult(ud_idx),
349 reg_idx);
350
351 cpu->setFloatReg(reg_idx,
352 inst->readFloatResult(ud_idx),
353 inst->readTid());
354 } else if (inst->resultType(ud_idx) ==
355 InOrderDynInst::Double) {
356 DPRINTF(InOrderUseDef, "[tid:%i]: Writing Double "
357 "Result 0x%x (bits:0x%x) to register "
358 "idx %i.\n",
359 tid,
360 inst->readFloatResult(ud_idx),
361 inst->readIntResult(ud_idx),
362 reg_idx);
363
364 // Check for FloatRegBits Here
365 cpu->setFloatReg(reg_idx,
366 inst->readFloatResult(ud_idx),
367 inst->readTid());
368 } else {
369 panic("Result Type Not Set For [sn:%i] %s.\n",
370 inst->seqNum, inst->instName());
371 }
372
373 } else {
374 DPRINTF(InOrderUseDef, "[tid:%i]: Writing Misc. 0x%x "
375 "to register idx %i.\n",
376 tid, inst->readIntResult(ud_idx), reg_idx);
377
378 // Remove Dependencies
379 regDepMap[tid]->removeFront(reg_idx, inst);
380
381 reg_idx -= Ctrl_Base_DepTag;
382
383 cpu->setMiscReg(reg_idx,
384 inst->readIntResult(ud_idx),
385 inst->readTid());
386 }
387
388 outWriteSeqNum[tid] = maxSeqNum;
389 regFileWrites++;
390 ud_req->done();
391 } else {
392 DPRINTF(InOrderUseDef, "[tid:%i]: Unable to write because "
393 "of [sn:%i] hasnt read it's"
394 " registers yet.\n", tid, outReadSeqNum);
395 DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for "
396 "[sn:%i] to read\n",
397 tid, outReadSeqNum);
398 ud_req->done(false);
399 }
400 } else {
401 DPRINTF(InOrderUseDef, "[tid:%i]: Dest. register idx: %i is "
402 "not ready to write.\n",
403 tid, reg_idx);
404 DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write "
405 "register (idx=%i)\n",
406 tid, reg_idx);
407 outWriteSeqNum[tid] = inst->seqNum;
408 ud_req->done(false);
409 }
410 }
411 break;
412
413 default:
414 fatal("Unrecognized command to %s", resName);
415 }
416
417 }
418
419 void
420 UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
421 ThreadID tid)
422 {
423 DPRINTF(InOrderUseDef, "[tid:%i]: Updating Due To Squash After [sn:%i].\n",
424 tid, squash_seq_num);
425
426 for (int i = 0; i < width; i++) {
427 ResReqPtr req_ptr = reqs[i];
428
429 if (req_ptr->valid &&
430 req_ptr->getInst()->readTid() == tid &&
431 req_ptr->getInst()->seqNum > squash_seq_num) {
432
433 DPRINTF(InOrderUseDef, "[tid:%i]: Squashing [sn:%i].\n",
434 req_ptr->getInst()->readTid(),
435 req_ptr->getInst()->seqNum);
436
437 int req_slot_num = req_ptr->getSlot();
438
439 if (latency > 0) {
440 assert(0);
441
442 unscheduleEvent(req_slot_num);
443 }
444
445 freeSlot(req_slot_num);
446 }
447 }
448
449 if (outReadSeqNum[tid] >= squash_seq_num) {
450 DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Read Seq Num Reset.\n",
451 tid);
452 outReadSeqNum[tid] = maxSeqNum;
453 } else if (outReadSeqNum[tid] != maxSeqNum) {
454 DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Read "
455 "Seq Num %i\n",
456 tid, outReadSeqNum[tid]);
457 }
458
459 if (outWriteSeqNum[tid] >= squash_seq_num) {
460 DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Write Seq Num Reset.\n",
461 tid);
462 outWriteSeqNum[tid] = maxSeqNum;
463 } else if (outWriteSeqNum[tid] != maxSeqNum) {
464 DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Write "
465 "Seq Num %i\n",
466 tid, outWriteSeqNum[tid]);
467 }
468 }
469
470 void
471 UseDefUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
472 {
473 uniqueRegsPerSwitch = uniqueRegMap.size();
474 uniqueRegMap.clear();
475 }