cpu: Update DRAM traffic gen
[gem5.git] / src / cpu / inorder / resource.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 "base/str.hh"
36 #include "cpu/inorder/cpu.hh"
37 #include "cpu/inorder/resource.hh"
38 #include "cpu/inorder/resource_pool.hh"
39 #include "debug/ExecFaulting.hh"
40 #include "debug/RefCount.hh"
41 #include "debug/ResReqCount.hh"
42 #include "debug/Resource.hh"
43
44 using namespace std;
45
46 Resource::Resource(string res_name, int res_id, int res_width,
47 Cycles res_latency, InOrderCPU *_cpu)
48 : resName(res_name), id(res_id),
49 width(res_width), latency(res_latency), cpu(_cpu),
50 resourceEvent(NULL)
51 {
52 reqs.resize(width);
53
54 // Use to deny a instruction a resource.
55 deniedReq = new ResourceRequest(this);
56 deniedReq->valid = true;
57 }
58
59 Resource::~Resource()
60 {
61 if (resourceEvent) {
62 delete [] resourceEvent;
63 }
64
65 delete deniedReq;
66
67 for (int i = 0; i < width; i++) {
68 delete reqs[i];
69 }
70 }
71
72
73 void
74 Resource::init()
75 {
76 // If the resource has a zero-cycle (no latency)
77 // function, then no reason to have events
78 // that will process them for the right tick
79 if (latency > Cycles(0))
80 resourceEvent = new ResourceEvent[width];
81
82
83 for (int i = 0; i < width; i++)
84 reqs[i] = new ResourceRequest(this);
85
86
87 initSlots();
88 }
89
90 void
91 Resource::initSlots()
92 {
93 // Add available slot numbers for resource
94 for (int slot_idx = 0; slot_idx < width; slot_idx++) {
95 availSlots.push_back(slot_idx);
96
97 if (resourceEvent) {
98 resourceEvent[slot_idx].init(this, slot_idx);
99 }
100 }
101 }
102
103 std::string
104 Resource::name()
105 {
106 return cpu->name() + "." + resName;
107 }
108
109 int
110 Resource::slotsAvail()
111 {
112 return availSlots.size();
113 }
114
115 int
116 Resource::slotsInUse()
117 {
118 return width - availSlots.size();
119 }
120
121 void
122 Resource::freeSlot(int slot_idx)
123 {
124 DPRINTF(Resource, "Deallocating [slot:%i].\n",
125 slot_idx);
126
127 // Put slot number on this resource's free list
128 availSlots.push_back(slot_idx);
129
130 // Invalidate Request & Reset it's flags
131 reqs[slot_idx]->clearRequest();
132 }
133
134 int
135 Resource::findSlot(DynInstPtr inst)
136 {
137 int slot_num = -1;
138
139 for (int i = 0; i < width; i++) {
140 if (reqs[i]->valid &&
141 reqs[i]->getInst()->seqNum == inst->seqNum) {
142 slot_num = reqs[i]->getSlot();
143 }
144 }
145 return slot_num;
146 }
147
148 int
149 Resource::getSlot(DynInstPtr inst)
150 {
151 int slot_num = -1;
152
153 if (slotsAvail() != 0) {
154 slot_num = availSlots[0];
155
156 vector<int>::iterator vect_it = availSlots.begin();
157
158 assert(slot_num == *vect_it);
159
160 availSlots.erase(vect_it);
161 }
162
163 return slot_num;
164 }
165
166 ResReqPtr
167 Resource::request(DynInstPtr inst)
168 {
169 // See if the resource is already serving this instruction.
170 // If so, use that request;
171 bool try_request = false;
172 int slot_num = -1;
173 int stage_num;
174 ResReqPtr inst_req = findRequest(inst);
175
176 if (inst_req) {
177 // If some preprocessing has to be done on instruction
178 // that has already requested once, then handle it here.
179 // update the 'try_request' variable if we should
180 // re-execute the request.
181 requestAgain(inst, try_request);
182
183 slot_num = inst_req->getSlot();
184 stage_num = inst_req->getStageNum();
185 } else {
186 // Get new slot # for instruction
187 slot_num = getSlot(inst);
188
189 if (slot_num != -1) {
190 DPRINTF(Resource, "Allocating [slot:%i] for [tid:%i]: [sn:%i]\n",
191 slot_num, inst->readTid(), inst->seqNum);
192
193 // Get Stage # from Schedule Entry
194 stage_num = inst->curSkedEntry->stageNum;
195 unsigned cmd = inst->curSkedEntry->cmd;
196
197 // Generate Resource Request
198 inst_req = getRequest(inst, stage_num, id, slot_num, cmd);
199
200 if (inst->staticInst) {
201 DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this "
202 "resource.\n",
203 inst->readTid(), inst->seqNum);
204 } else {
205 DPRINTF(Resource, "[tid:%i]: instruction requesting this "
206 "resource.\n",
207 inst->readTid());
208 }
209
210 try_request = true;
211 } else {
212 DPRINTF(Resource, "No slot available for [tid:%i]: [sn:%i]\n",
213 inst->readTid(), inst->seqNum);
214 }
215
216 }
217
218 if (try_request) {
219 // Schedule execution of resource
220 scheduleExecution(slot_num);
221 } else {
222 inst_req = deniedReq;
223 rejectRequest(inst);
224 }
225
226 return inst_req;
227 }
228
229 void
230 Resource::requestAgain(DynInstPtr inst, bool &do_request)
231 {
232 do_request = true;
233
234 if (inst->staticInst) {
235 DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource "
236 "again.\n",
237 inst->readTid(), inst->seqNum);
238 } else {
239 DPRINTF(Resource, "[tid:%i]: requesting this resource again.\n",
240 inst->readTid());
241 }
242 }
243
244 ResReqPtr
245 Resource::getRequest(DynInstPtr inst, int stage_num, int res_idx,
246 int slot_num, unsigned cmd)
247 {
248 reqs[slot_num]->setRequest(inst, stage_num, id, slot_num, cmd);
249 return reqs[slot_num];
250 }
251
252 ResReqPtr
253 Resource::findRequest(DynInstPtr inst)
254 {
255 for (int i = 0; i < width; i++) {
256 if (reqs[i]->valid &&
257 reqs[i]->getInst() == inst) {
258 return reqs[i];
259 }
260 }
261
262 return NULL;
263 }
264
265 void
266 Resource::rejectRequest(DynInstPtr inst)
267 {
268 DPRINTF(RefCount, "[tid:%i]: Unable to grant request for [sn:%i].\n",
269 inst->readTid(), inst->seqNum);
270 }
271
272 void
273 Resource::execute(int slot_idx)
274 {
275 //@todo: have each resource print out command their executing
276 DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n",
277 reqs[slot_idx]->getTid(), name());
278 reqs[slot_idx]->setCompleted(true);
279 reqs[slot_idx]->done();
280 }
281
282 void
283 Resource::deactivateThread(ThreadID tid)
284 {
285 // In the most basic case, deactivation means squashing everything
286 // from a particular thread
287 DynInstPtr dummy_inst = new InOrderDynInst(cpu, NULL, 0, tid, tid);
288 squash(dummy_inst, 0, 0, tid);
289 }
290
291 void
292 Resource::setupSquash(DynInstPtr inst, int stage_num, ThreadID tid)
293 {
294 // Squash In Pipeline Stage
295 cpu->pipelineStage[stage_num]->setupSquash(inst, tid);
296
297 // Schedule Squash Through-out Resource Pool
298 cpu->resPool->scheduleEvent(
299 (InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst,
300 Cycles(0));
301 }
302
303 void
304 Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
305 ThreadID tid)
306 {
307 //@todo: check squash seq num before squashing. can save time going
308 // through this function.
309 for (int i = 0; i < width; i++) {
310 ResReqPtr req_ptr = reqs[i];
311 DynInstPtr inst = req_ptr->getInst();
312
313 if (req_ptr->valid &&
314 inst->readTid() == tid &&
315 inst->seqNum > squash_seq_num) {
316
317 DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n",
318 req_ptr->getInst()->readTid(),
319 req_ptr->getInst()->seqNum);
320
321 req_ptr->setSquashed();
322
323 int req_slot_num = req_ptr->getSlot();
324
325 if (latency > Cycles(0)) {
326 if (resourceEvent[req_slot_num].scheduled())
327 unscheduleEvent(req_slot_num);
328 }
329
330 freeSlot(req_slot_num);
331 }
332 }
333 }
334
335 void
336 Resource::squashDueToMemStall(DynInstPtr inst, int stage_num,
337 InstSeqNum squash_seq_num,
338 ThreadID tid)
339 {
340 squash(inst, stage_num, squash_seq_num, tid);
341 }
342
343 void
344 Resource::squashThenTrap(int stage_num, DynInstPtr inst)
345 {
346 ThreadID tid = inst->readTid();
347
348 inst->setSquashInfo(stage_num);
349 setupSquash(inst, stage_num, tid);
350
351 if (inst->traceData) {
352 if (inst->staticInst &&
353 inst->fault != NoFault && DTRACE(ExecFaulting)) {
354 inst->traceData->setStageCycle(stage_num, curTick());
355 inst->traceData->setFetchSeq(inst->seqNum);
356 inst->traceData->dump();
357 }
358
359 delete inst->traceData;
360 inst->traceData = NULL;
361 }
362
363 cpu->trapContext(inst->fault, tid, inst);
364 }
365
366 void
367 Resource::scheduleExecution(int slot_num)
368 {
369 if (latency > Cycles(0)) {
370 scheduleEvent(slot_num, latency);
371 } else {
372 execute(slot_num);
373 }
374 }
375
376 void
377 Resource::scheduleEvent(int slot_idx, Cycles delay)
378 {
379 DPRINTF(Resource, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n",
380 reqs[slot_idx]->inst->readTid(),
381 reqs[slot_idx]->inst->seqNum,
382 cpu->clockEdge(delay));
383 resourceEvent[slot_idx].scheduleEvent(delay);
384 }
385
386 bool
387 Resource::scheduleEvent(DynInstPtr inst, Cycles delay)
388 {
389 int slot_idx = findSlot(inst);
390
391 if(slot_idx != -1)
392 resourceEvent[slot_idx].scheduleEvent(delay);
393
394 return slot_idx;
395 }
396
397 void
398 Resource::unscheduleEvent(int slot_idx)
399 {
400 resourceEvent[slot_idx].unscheduleEvent();
401 }
402
403 bool
404 Resource::unscheduleEvent(DynInstPtr inst)
405 {
406 int slot_idx = findSlot(inst);
407
408 if(slot_idx != -1)
409 resourceEvent[slot_idx].unscheduleEvent();
410
411 return slot_idx;
412 }
413
414 int ResourceRequest::resReqID = 0;
415
416 int ResourceRequest::maxReqCount = 0;
417
418 ResourceRequest::ResourceRequest(Resource *_res)
419 : res(_res), inst(NULL), stagePasses(0), valid(false), doneInResource(false),
420 completed(false), squashed(false), processing(false),
421 memStall(false)
422 {
423 }
424
425 ResourceRequest::~ResourceRequest()
426 {
427 #ifdef DEBUG
428 res->cpu->resReqCount--;
429 DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID,
430 res->cpu->resReqCount);
431 #endif
432 inst = NULL;
433 }
434
435 std::string
436 ResourceRequest::name()
437 {
438 return csprintf("%s[slot:%i]:", res->name(), slotNum);
439 }
440
441 void
442 ResourceRequest::setRequest(DynInstPtr _inst, int stage_num,
443 int res_idx, int slot_num, unsigned _cmd)
444 {
445 valid = true;
446 inst = _inst;
447 stageNum = stage_num;
448 resIdx = res_idx;
449 slotNum = slot_num;
450 cmd = _cmd;
451 }
452
453 void
454 ResourceRequest::clearRequest()
455 {
456 valid = false;
457 inst = NULL;
458 stagePasses = 0;
459 completed = false;
460 doneInResource = false;
461 squashed = false;
462 memStall = false;
463 }
464
465 void
466 ResourceRequest::freeSlot()
467 {
468 assert(res);
469
470 // Free Slot So Another Instruction Can Use This Resource
471 res->freeSlot(slotNum);
472 }
473
474 void
475 ResourceRequest::done(bool completed)
476 {
477 DPRINTF(Resource, "done with request from "
478 "[sn:%i] [tid:%i].\n",
479 inst->seqNum, inst->readTid());
480
481 setCompleted(completed);
482
483 doneInResource = true;
484 }
485
486 ResourceEvent::ResourceEvent()
487 : Event((Event::Priority)Resource_Event_Pri)
488 { }
489
490 ResourceEvent::ResourceEvent(Resource *res, int slot_idx)
491 : Event((Event::Priority)Resource_Event_Pri), resource(res),
492 slotIdx(slot_idx)
493 { }
494
495 void
496 ResourceEvent::init(Resource *res, int slot_idx)
497 {
498 resource = res;
499 slotIdx = slot_idx;
500 }
501
502 void
503 ResourceEvent::process()
504 {
505 resource->execute(slotIdx);
506 }
507
508 const char *
509 ResourceEvent::description() const
510 {
511 string desc = resource->name() + "-event:slot[" + to_string(slotIdx)
512 + "]";
513
514 return desc.c_str();
515 }
516
517 void
518 ResourceEvent::scheduleEvent(Cycles delay)
519 {
520 assert(!scheduled() || squashed());
521 resource->cpu->reschedule(this,
522 resource->cpu->clockEdge(delay), true);
523 }