inorder: tick scheduling
[gem5.git] / src / cpu / inorder / resource_pool.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 "cpu/inorder/resource_pool.hh"
33 #include "cpu/inorder/resources/resource_list.hh"
34
35 #include <vector>
36 #include <list>
37
38 using namespace std;
39 using namespace ThePipeline;
40
41 ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
42 : cpu(_cpu)
43 {
44 //@todo: use this function to instantiate the resources in resource pool.
45 //This will help in the auto-generation of this pipeline model.
46 //ThePipeline::addResources(resources, memObjects);
47
48 // Declare Resource Objects
49 // name - id - bandwidth - latency - CPU - Parameters
50 // --------------------------------------------------
51 resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq,
52 StageWidth * 2, 0, _cpu, params));
53
54 memObjects.push_back(ICache);
55 resources.push_back(new CacheUnit("icache_port", ICache,
56 StageWidth * MaxThreads, 0, _cpu,
57 params));
58
59 resources.push_back(new DecodeUnit("Decode-Unit", Decode,
60 StageWidth, 0, _cpu, params));
61
62 resources.push_back(new BranchPredictor("Branch-Predictor", BPred,
63 StageWidth, 0, _cpu, params));
64
65 resources.push_back(new InstBuffer("Fetch-Buffer-T0", FetchBuff, 4,
66 0, _cpu, params));
67
68 resources.push_back(new UseDefUnit("RegFile-Manager", RegManager,
69 StageWidth * MaxThreads, 0, _cpu,
70 params));
71
72 resources.push_back(new AGENUnit("AGEN-Unit", AGEN,
73 StageWidth, 0, _cpu, params));
74
75 resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit,
76 StageWidth, 0, _cpu, params));
77
78 resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu,
79 params));
80
81 memObjects.push_back(DCache);
82 resources.push_back(new CacheUnit("dcache_port", DCache,
83 StageWidth * MaxThreads, 0, _cpu,
84 params));
85
86 resources.push_back(new GraduationUnit("Graduation-Unit", Grad,
87 StageWidth * MaxThreads, 0, _cpu,
88 params));
89
90 resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4,
91 0, _cpu, params));
92 }
93
94 ResourcePool::~ResourcePool()
95 {
96 cout << "Deleting resources ..." << endl;
97
98 for (int i=0; i < resources.size(); i++) {
99 DPRINTF(Resource, "Deleting resource: %s.\n", resources[i]->name());
100
101 delete resources[i];
102 }
103 }
104
105
106 void
107 ResourcePool::init()
108 {
109 for (int i=0; i < resources.size(); i++) {
110 DPRINTF(Resource, "Initializing resource: %s.\n",
111 resources[i]->name());
112
113 resources[i]->init();
114 }
115 }
116
117 string
118 ResourcePool::name()
119 {
120 return cpu->name() + ".ResourcePool";
121 }
122
123
124 void
125 ResourcePool::regStats()
126 {
127 DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n");
128
129 int num_resources = resources.size();
130
131 for (int idx = 0; idx < num_resources; idx++) {
132 resources[idx]->regStats();
133 }
134 }
135
136 Port *
137 ResourcePool::getPort(const std::string &if_name, int idx)
138 {
139 DPRINTF(Resource, "Binding %s in Resource Pool.\n", if_name);
140
141 for (int i = 0; i < memObjects.size(); i++) {
142 int obj_idx = memObjects[i];
143 Port *port = resources[obj_idx]->getPort(if_name, idx);
144 if (port != NULL) {
145 DPRINTF(Resource, "%s set to resource %s(#%i) in Resource Pool.\n",
146 if_name, resources[obj_idx]->name(), obj_idx);
147 return port;
148 }
149 }
150
151 return NULL;
152 }
153
154 unsigned
155 ResourcePool::getPortIdx(const std::string &port_name)
156 {
157 DPRINTF(Resource, "Finding Port Idx for %s.\n", port_name);
158
159 for (int i = 0; i < memObjects.size(); i++) {
160 unsigned obj_idx = memObjects[i];
161 Port *port = resources[obj_idx]->getPort(port_name, obj_idx);
162 if (port != NULL) {
163 DPRINTF(Resource, "Returning Port Idx %i for %s.\n", obj_idx,
164 port_name);
165 return obj_idx;
166 }
167 }
168
169 return 0;
170 }
171
172 unsigned
173 ResourcePool::getResIdx(const std::string &res_name)
174 {
175 DPRINTF(Resource, "Finding Resource Idx for %s.\n", res_name);
176
177 int num_resources = resources.size();
178
179 for (int idx = 0; idx < num_resources; idx++) {
180 if (resources[idx]->name() == res_name)
181 return idx;
182 }
183
184 panic("Can't find resource idx for: %s\n", res_name);
185 return 0;
186 }
187
188 unsigned
189 ResourcePool::getResIdx(const ThePipeline::ResourceId &res_id)
190 {
191 int num_resources = resources.size();
192
193 for (int idx = 0; idx < num_resources; idx++) {
194 if (resources[idx]->getId() == res_id)
195 return idx;
196 }
197
198 // todo: change return value to int and return a -1 here
199 // maybe even have enumerated type
200 // panic for now...
201 panic("Can't find resource idx for: %i\n", res_id);
202
203 return 0;
204 }
205
206 ResReqPtr
207 ResourcePool::request(int res_idx, DynInstPtr inst)
208 {
209 //Make Sure This is a valid resource ID
210 assert(res_idx >= 0 && res_idx < resources.size());
211
212 return resources[res_idx]->request(inst);
213 }
214
215 void
216 ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num,
217 ThreadID tid)
218 {
219 resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num,
220 tid);
221 }
222
223 int
224 ResourcePool::slotsAvail(int res_idx)
225 {
226 return resources[res_idx]->slotsAvail();
227 }
228
229 int
230 ResourcePool::slotsInUse(int res_idx)
231 {
232 return resources[res_idx]->slotsInUse();
233 }
234
235 //@todo: split this function and call this version schedulePoolEvent
236 // and use this scheduleEvent for scheduling a specific event on
237 // a resource
238 //@todo: For arguments that arent being used in a ResPoolEvent, a dummyParam
239 // or some typedef can be used to signify what's important info
240 // to the event construction
241 void
242 ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
243 int delay, int res_idx, ThreadID tid)
244 {
245 assert(delay >= 0);
246
247 switch (e_type)
248 {
249 case InOrderCPU::ActivateThread:
250 {
251 DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event "
252 "for tick %i, [tid:%i].\n", curTick + delay,
253 inst->readTid());
254 ResPoolEvent *res_pool_event =
255 new ResPoolEvent(this,
256 e_type,
257 inst,
258 inst->squashingStage,
259 inst->bdelaySeqNum,
260 inst->readTid());
261 mainEventQueue.schedule(res_pool_event,
262 cpu->nextCycle(curTick + cpu->ticks(delay)));
263 }
264 break;
265
266 case InOrderCPU::HaltThread:
267 case InOrderCPU::DeactivateThread:
268 {
269
270 DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool "
271 "Event for tick %i.\n", curTick + delay);
272 ResPoolEvent *res_pool_event =
273 new ResPoolEvent(this,
274 e_type,
275 inst,
276 inst->squashingStage,
277 inst->bdelaySeqNum,
278 tid);
279
280 mainEventQueue.schedule(res_pool_event,
281 cpu->nextCycle(curTick + cpu->ticks(delay)));
282
283 }
284 break;
285
286 case InOrderCPU::SuspendThread:
287 {
288
289 DPRINTF(Resource, "Scheduling Suspend Thread Resource Pool Event for tick %i.\n",
290 cpu->nextCycle(cpu->nextCycle(curTick + cpu->ticks(delay))));
291 ResPoolEvent *res_pool_event = new ResPoolEvent(this,
292 e_type,
293 inst,
294 inst->squashingStage,
295 inst->bdelaySeqNum,
296 tid);
297
298 mainEventQueue.schedule(res_pool_event, cpu->nextCycle(cpu->nextCycle(curTick + cpu->ticks(delay))));
299
300 }
301 break;
302
303 case ResourcePool::InstGraduated:
304 {
305 DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool "
306 "Event for tick %i.\n", curTick + delay);
307 ResPoolEvent *res_pool_event =
308 new ResPoolEvent(this,e_type,
309 inst,
310 inst->squashingStage,
311 inst->seqNum,
312 inst->readTid());
313 mainEventQueue.schedule(res_pool_event,
314 cpu->nextCycle(curTick + cpu->ticks(delay)));
315
316 }
317 break;
318
319 case ResourcePool::SquashAll:
320 {
321 DPRINTF(Resource, "Scheduling Squash Resource Pool Event for "
322 "tick %i.\n", curTick + delay);
323 ResPoolEvent *res_pool_event =
324 new ResPoolEvent(this,e_type,
325 inst,
326 inst->squashingStage,
327 inst->bdelaySeqNum,
328 inst->readTid());
329 mainEventQueue.schedule(res_pool_event,
330 cpu->nextCycle(curTick + cpu->ticks(delay)));
331 }
332 break;
333
334 case InOrderCPU::SquashFromMemStall:
335 {
336 DPRINTF(Resource, "Scheduling Squash Due to Memory Stall Resource "
337 "Pool Event for tick %i.\n",
338 curTick + delay);
339 ResPoolEvent *res_pool_event =
340 new ResPoolEvent(this,e_type,
341 inst,
342 inst->squashingStage,
343 inst->seqNum - 1,
344 inst->readTid());
345 mainEventQueue.schedule(res_pool_event,
346 cpu->nextCycle(curTick + cpu->ticks(delay)));
347 }
348 break;
349
350 case ResourcePool::UpdateAfterContextSwitch:
351 {
352 DPRINTF(Resource, "Scheduling UpdatePC Resource Pool Event for tick %i.\n",
353 curTick + delay);
354 ResPoolEvent *res_pool_event = new ResPoolEvent(this,e_type,
355 inst,
356 inst->squashingStage,
357 inst->seqNum,
358 inst->readTid());
359 mainEventQueue.schedule(res_pool_event, cpu->nextCycle(curTick + cpu->ticks(delay)));
360
361 }
362 break;
363
364 default:
365 DPRINTF(Resource, "Ignoring Unrecognized CPU Event (%s).\n",
366 InOrderCPU::eventNames[e_type]);
367 }
368 }
369
370 void
371 ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
372 {
373 resources[res_idx]->unscheduleEvent(inst);
374 }
375
376 void
377 ResourcePool::squashAll(DynInstPtr inst, int stage_num,
378 InstSeqNum done_seq_num, ThreadID tid)
379 {
380 DPRINTF(Resource, "[tid:%i] Broadcasting Squash All Event "
381 " starting w/stage %i for all instructions above [sn:%i].\n",
382 tid, stage_num, done_seq_num);
383
384 int num_resources = resources.size();
385
386 for (int idx = 0; idx < num_resources; idx++) {
387 resources[idx]->squash(inst, stage_num, done_seq_num, tid);
388 }
389 }
390
391 void
392 ResourcePool::squashDueToMemStall(DynInstPtr inst, int stage_num,
393 InstSeqNum done_seq_num, ThreadID tid)
394 {
395 DPRINTF(Resource, "[tid:%i] Broadcasting SquashDueToMemStall Event"
396 " starting w/stage %i for all instructions above [sn:%i].\n",
397 tid, stage_num, done_seq_num);
398
399 int num_resources = resources.size();
400
401 for (int idx = 0; idx < num_resources; idx++) {
402 resources[idx]->squashDueToMemStall(inst, stage_num, done_seq_num,
403 tid);
404 }
405 }
406
407 void
408 ResourcePool::activateAll(ThreadID tid)
409 {
410 bool do_activate = cpu->threadModel != InOrderCPU::SwitchOnCacheMiss ||
411 cpu->numActiveThreads() < 1 ||
412 cpu->activeThreadId() == tid;
413
414
415 if (do_activate) {
416 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all "
417 "resources.\n", tid);
418
419 int num_resources = resources.size();
420
421 for (int idx = 0; idx < num_resources; idx++) {
422 resources[idx]->activateThread(tid);
423 }
424 } else {
425 DPRINTF(Resource, "[tid:%i] Ignoring Thread Activation to all "
426 "resources.\n", tid);
427 }
428 }
429
430 void
431 ResourcePool::deactivateAll(ThreadID tid)
432 {
433 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all "
434 "resources.\n", tid);
435
436 int num_resources = resources.size();
437
438 for (int idx = 0; idx < num_resources; idx++) {
439 resources[idx]->deactivateThread(tid);
440 }
441 }
442
443 void
444 ResourcePool::suspendAll(ThreadID tid)
445 {
446 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Suspension to all resources.\n",
447 tid);
448
449 int num_resources = resources.size();
450
451 for (int idx = 0; idx < num_resources; idx++) {
452 resources[idx]->suspendThread(tid);
453 }
454 }
455
456 void
457 ResourcePool::instGraduated(InstSeqNum seq_num, ThreadID tid)
458 {
459 DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all "
460 "resources.\n", tid, seq_num);
461
462 int num_resources = resources.size();
463
464 for (int idx = 0; idx < num_resources; idx++) {
465 resources[idx]->instGraduated(seq_num, tid);
466 }
467 }
468
469 void
470 ResourcePool::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
471 {
472 DPRINTF(Resource, "[tid:%i] Broadcasting Update PC to all resources.\n",
473 tid);
474
475 int num_resources = resources.size();
476
477 for (int idx = 0; idx < num_resources; idx++) {
478 resources[idx]->updateAfterContextSwitch(inst, tid);
479 }
480 }
481
482 ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool,
483 InOrderCPU::CPUEventType e_type,
484 DynInstPtr _inst,
485 int stage_num,
486 InstSeqNum seq_num,
487 ThreadID _tid)
488 : Event(CPU_Tick_Pri), resPool(_resPool),
489 eventType(e_type), inst(_inst), seqNum(seq_num),
490 stageNum(stage_num), tid(_tid)
491 { }
492
493
494 void
495 ResourcePool::ResPoolEvent::process()
496 {
497 switch (eventType)
498 {
499 case InOrderCPU::ActivateThread:
500 resPool->activateAll(tid);
501 break;
502
503 case InOrderCPU::DeactivateThread:
504 case InOrderCPU::HaltThread:
505 resPool->deactivateAll(tid);
506 break;
507
508 case InOrderCPU::SuspendThread:
509 resPool->suspendAll(tid);
510 break;
511
512 case ResourcePool::InstGraduated:
513 resPool->instGraduated(seqNum, tid);
514 break;
515
516 case ResourcePool::SquashAll:
517 resPool->squashAll(inst, stageNum, seqNum, tid);
518 break;
519
520 case InOrderCPU::SquashFromMemStall:
521 resPool->squashDueToMemStall(inst, stageNum, seqNum, tid);
522 break;
523
524 case ResourcePool::UpdateAfterContextSwitch:
525 resPool->updateAfterContextSwitch(inst, tid);
526 break;
527
528 default:
529 fatal("Unrecognized Event Type");
530 }
531
532 resPool->cpu->cpuEventRemoveList.push(this);
533 }
534
535
536 const char *
537 ResourcePool::ResPoolEvent::description()
538 {
539 return "Resource Pool event";
540 }
541
542 /** Schedule resource event, regardless of its current state. */
543 void
544 ResourcePool::ResPoolEvent::scheduleEvent(int delay)
545 {
546 if (squashed())
547 mainEventQueue.reschedule(this,resPool->cpu->nextCycle(curTick + resPool->cpu->ticks(delay)));
548 else if (!scheduled())
549 mainEventQueue.schedule(this, resPool->cpu->nextCycle(curTick + resPool->cpu->ticks(delay)));
550 }
551
552 /** Unschedule resource event, regardless of its current state. */
553 void
554 ResourcePool::ResPoolEvent::unscheduleEvent()
555 {
556 if (scheduled())
557 squash();
558 }