GCC: Get everything working with gcc 4.6.1.
[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 int 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 > 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, 0);
300 }
301
302 void
303 Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num,
304 ThreadID tid)
305 {
306 //@todo: check squash seq num before squashing. can save time going
307 // through this function.
308 for (int i = 0; i < width; i++) {
309 ResReqPtr req_ptr = reqs[i];
310 DynInstPtr inst = req_ptr->getInst();
311
312 if (req_ptr->valid &&
313 inst->readTid() == tid &&
314 inst->seqNum > squash_seq_num) {
315
316 DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n",
317 req_ptr->getInst()->readTid(),
318 req_ptr->getInst()->seqNum);
319
320 req_ptr->setSquashed();
321
322 int req_slot_num = req_ptr->getSlot();
323
324 if (latency > 0) {
325 if (resourceEvent[req_slot_num].scheduled())
326 unscheduleEvent(req_slot_num);
327 }
328
329 freeSlot(req_slot_num);
330 }
331 }
332 }
333
334 void
335 Resource::squashDueToMemStall(DynInstPtr inst, int stage_num,
336 InstSeqNum squash_seq_num,
337 ThreadID tid)
338 {
339 squash(inst, stage_num, squash_seq_num, tid);
340 }
341
342 void
343 Resource::squashThenTrap(int stage_num, DynInstPtr inst)
344 {
345 ThreadID tid = inst->readTid();
346
347 inst->setSquashInfo(stage_num);
348 setupSquash(inst, stage_num, tid);
349
350 if (inst->traceData) {
351 if (inst->staticInst &&
352 inst->fault != NoFault && DTRACE(ExecFaulting)) {
353 inst->traceData->setStageCycle(stage_num, curTick());
354 inst->traceData->setFetchSeq(inst->seqNum);
355 inst->traceData->dump();
356 }
357
358 delete inst->traceData;
359 inst->traceData = NULL;
360 }
361
362 cpu->trapContext(inst->fault, tid, inst);
363 }
364
365 Tick
366 Resource::ticks(int num_cycles)
367 {
368 return cpu->ticks(num_cycles);
369 }
370
371
372 void
373 Resource::scheduleExecution(int slot_num)
374 {
375 if (latency >= 1) {
376 scheduleEvent(slot_num, latency);
377 } else {
378 execute(slot_num);
379 }
380 }
381
382 void
383 Resource::scheduleEvent(int slot_idx, int delay)
384 {
385 DPRINTF(Resource, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n",
386 reqs[slot_idx]->inst->readTid(),
387 reqs[slot_idx]->inst->seqNum,
388 cpu->ticks(delay) + curTick());
389 resourceEvent[slot_idx].scheduleEvent(delay);
390 }
391
392 bool
393 Resource::scheduleEvent(DynInstPtr inst, int delay)
394 {
395 int slot_idx = findSlot(inst);
396
397 if(slot_idx != -1)
398 resourceEvent[slot_idx].scheduleEvent(delay);
399
400 return slot_idx;
401 }
402
403 void
404 Resource::unscheduleEvent(int slot_idx)
405 {
406 resourceEvent[slot_idx].unscheduleEvent();
407 }
408
409 bool
410 Resource::unscheduleEvent(DynInstPtr inst)
411 {
412 int slot_idx = findSlot(inst);
413
414 if(slot_idx != -1)
415 resourceEvent[slot_idx].unscheduleEvent();
416
417 return slot_idx;
418 }
419
420 int ResourceRequest::resReqID = 0;
421
422 int ResourceRequest::maxReqCount = 0;
423
424 ResourceRequest::ResourceRequest(Resource *_res)
425 : res(_res), inst(NULL), stagePasses(0), valid(false), doneInResource(false),
426 completed(false), squashed(false), processing(false),
427 memStall(false)
428 {
429 }
430
431 ResourceRequest::~ResourceRequest()
432 {
433 #ifdef DEBUG
434 res->cpu->resReqCount--;
435 DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID,
436 res->cpu->resReqCount);
437 #endif
438 inst = NULL;
439 }
440
441 std::string
442 ResourceRequest::name()
443 {
444 return csprintf("%s[slot:%i]:", res->name(), slotNum);
445 }
446
447 void
448 ResourceRequest::setRequest(DynInstPtr _inst, int stage_num,
449 int res_idx, int slot_num, unsigned _cmd)
450 {
451 valid = true;
452 inst = _inst;
453 stageNum = stage_num;
454 resIdx = res_idx;
455 slotNum = slot_num;
456 cmd = _cmd;
457 }
458
459 void
460 ResourceRequest::clearRequest()
461 {
462 valid = false;
463 inst = NULL;
464 stagePasses = 0;
465 completed = false;
466 doneInResource = false;
467 squashed = false;
468 memStall = false;
469 }
470
471 void
472 ResourceRequest::freeSlot()
473 {
474 assert(res);
475
476 // Free Slot So Another Instruction Can Use This Resource
477 res->freeSlot(slotNum);
478 }
479
480 void
481 ResourceRequest::done(bool completed)
482 {
483 DPRINTF(Resource, "done with request from "
484 "[sn:%i] [tid:%i].\n",
485 inst->seqNum, inst->readTid());
486
487 setCompleted(completed);
488
489 doneInResource = true;
490 }
491
492 ResourceEvent::ResourceEvent()
493 : Event((Event::Priority)Resource_Event_Pri)
494 { }
495
496 ResourceEvent::ResourceEvent(Resource *res, int slot_idx)
497 : Event((Event::Priority)Resource_Event_Pri), resource(res),
498 slotIdx(slot_idx)
499 { }
500
501 void
502 ResourceEvent::init(Resource *res, int slot_idx)
503 {
504 resource = res;
505 slotIdx = slot_idx;
506 }
507
508 void
509 ResourceEvent::process()
510 {
511 resource->execute(slotIdx);
512 }
513
514 const char *
515 ResourceEvent::description()
516 {
517 string desc = resource->name() + "-event:slot[" + to_string(slotIdx)
518 + "]";
519
520 return desc.c_str();
521 }
522
523 void
524 ResourceEvent::scheduleEvent(int delay)
525 {
526 assert(!scheduled() || squashed());
527 resource->cpu->reschedule(this,
528 curTick() + resource->ticks(delay), true);
529 }