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