e8400405aedeedaf47937eee57e5aa7585e8f203
[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 Tick when = cpu->nextCycle(curTick() + cpu->ticks(delay));
248
249 switch (e_type)
250 {
251 case InOrderCPU::ActivateThread:
252 {
253 DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event "
254 "for tick %i, [tid:%i].\n", curTick() + delay,
255 inst->readTid());
256 ResPoolEvent *res_pool_event =
257 new ResPoolEvent(this,
258 e_type,
259 inst,
260 inst->squashingStage,
261 inst->bdelaySeqNum,
262 inst->readTid());
263 cpu->schedule(res_pool_event, when);
264 }
265 break;
266
267 case InOrderCPU::HaltThread:
268 case InOrderCPU::DeactivateThread:
269 {
270
271 DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool "
272 "Event for tick %i.\n", curTick() + delay);
273 ResPoolEvent *res_pool_event =
274 new ResPoolEvent(this,
275 e_type,
276 inst,
277 inst->squashingStage,
278 inst->bdelaySeqNum,
279 tid);
280
281 cpu->schedule(res_pool_event, when);
282 }
283 break;
284
285 case InOrderCPU::SuspendThread:
286 {
287 // not sure why we add another nextCycle() call here...
288 Tick sked_tick = cpu->nextCycle(when);
289
290 DPRINTF(Resource, "Scheduling Suspend Thread Resource Pool "
291 "Event for tick %i.\n", sked_tick);
292
293 ResPoolEvent *res_pool_event = new ResPoolEvent(this,
294 e_type,
295 inst,
296 inst->squashingStage,
297 inst->bdelaySeqNum,
298 tid);
299
300 cpu->schedule(res_pool_event, sked_tick);
301 }
302 break;
303
304 case ResourcePool::InstGraduated:
305 {
306 DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool "
307 "Event for tick %i.\n", curTick() + delay);
308 ResPoolEvent *res_pool_event =
309 new ResPoolEvent(this,e_type,
310 inst,
311 inst->squashingStage,
312 inst->seqNum,
313 inst->readTid());
314 cpu->schedule(res_pool_event, when);
315 }
316 break;
317
318 case ResourcePool::SquashAll:
319 {
320 DPRINTF(Resource, "Scheduling Squash Resource Pool Event for "
321 "tick %i.\n", curTick() + delay);
322 ResPoolEvent *res_pool_event =
323 new ResPoolEvent(this,e_type,
324 inst,
325 inst->squashingStage,
326 inst->bdelaySeqNum,
327 inst->readTid());
328 cpu->schedule(res_pool_event, when);
329 }
330 break;
331
332 case InOrderCPU::SquashFromMemStall:
333 {
334 DPRINTF(Resource, "Scheduling Squash Due to Memory Stall Resource "
335 "Pool Event for tick %i.\n",
336 curTick() + delay);
337 ResPoolEvent *res_pool_event =
338 new ResPoolEvent(this,e_type,
339 inst,
340 inst->squashingStage,
341 inst->seqNum - 1,
342 inst->readTid());
343 cpu->schedule(res_pool_event, when);
344 }
345 break;
346
347 case ResourcePool::UpdateAfterContextSwitch:
348 {
349 DPRINTF(Resource, "Scheduling UpdatePC Resource Pool Event "
350 "for tick %i.\n",
351 curTick() + delay);
352 ResPoolEvent *res_pool_event = new ResPoolEvent(this,e_type,
353 inst,
354 inst->squashingStage,
355 inst->seqNum,
356 inst->readTid());
357 cpu->schedule(res_pool_event, when);
358 }
359 break;
360
361 default:
362 DPRINTF(Resource, "Ignoring Unrecognized CPU Event (%s).\n",
363 InOrderCPU::eventNames[e_type]);
364 }
365 }
366
367 void
368 ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
369 {
370 resources[res_idx]->unscheduleEvent(inst);
371 }
372
373 void
374 ResourcePool::squashAll(DynInstPtr inst, int stage_num,
375 InstSeqNum done_seq_num, ThreadID tid)
376 {
377 DPRINTF(Resource, "[tid:%i] Broadcasting Squash All Event "
378 " starting w/stage %i for all instructions above [sn:%i].\n",
379 tid, stage_num, done_seq_num);
380
381 int num_resources = resources.size();
382
383 for (int idx = 0; idx < num_resources; idx++) {
384 resources[idx]->squash(inst, stage_num, done_seq_num, tid);
385 }
386 }
387
388 void
389 ResourcePool::squashDueToMemStall(DynInstPtr inst, int stage_num,
390 InstSeqNum done_seq_num, ThreadID tid)
391 {
392 DPRINTF(Resource, "[tid:%i] Broadcasting SquashDueToMemStall Event"
393 " starting w/stage %i for all instructions above [sn:%i].\n",
394 tid, stage_num, done_seq_num);
395
396 int num_resources = resources.size();
397
398 for (int idx = 0; idx < num_resources; idx++) {
399 resources[idx]->squashDueToMemStall(inst, stage_num, done_seq_num,
400 tid);
401 }
402 }
403
404 void
405 ResourcePool::activateAll(ThreadID tid)
406 {
407 bool do_activate = cpu->threadModel != InOrderCPU::SwitchOnCacheMiss ||
408 cpu->numActiveThreads() < 1 ||
409 cpu->activeThreadId() == tid;
410
411
412 if (do_activate) {
413 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all "
414 "resources.\n", tid);
415
416 int num_resources = resources.size();
417
418 for (int idx = 0; idx < num_resources; idx++) {
419 resources[idx]->activateThread(tid);
420 }
421 } else {
422 DPRINTF(Resource, "[tid:%i] Ignoring Thread Activation to all "
423 "resources.\n", tid);
424 }
425 }
426
427 void
428 ResourcePool::deactivateAll(ThreadID tid)
429 {
430 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all "
431 "resources.\n", tid);
432
433 int num_resources = resources.size();
434
435 for (int idx = 0; idx < num_resources; idx++) {
436 resources[idx]->deactivateThread(tid);
437 }
438 }
439
440 void
441 ResourcePool::suspendAll(ThreadID tid)
442 {
443 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Suspension to all "
444 "resources.\n", tid);
445
446 int num_resources = resources.size();
447
448 for (int idx = 0; idx < num_resources; idx++) {
449 resources[idx]->suspendThread(tid);
450 }
451 }
452
453 void
454 ResourcePool::instGraduated(InstSeqNum seq_num, ThreadID tid)
455 {
456 DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all "
457 "resources.\n", tid, seq_num);
458
459 int num_resources = resources.size();
460
461 for (int idx = 0; idx < num_resources; idx++) {
462 resources[idx]->instGraduated(seq_num, tid);
463 }
464 }
465
466 void
467 ResourcePool::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
468 {
469 DPRINTF(Resource, "[tid:%i] Broadcasting Update PC to all resources.\n",
470 tid);
471
472 int num_resources = resources.size();
473
474 for (int idx = 0; idx < num_resources; idx++) {
475 resources[idx]->updateAfterContextSwitch(inst, tid);
476 }
477 }
478
479 ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool,
480 InOrderCPU::CPUEventType e_type,
481 DynInstPtr _inst,
482 int stage_num,
483 InstSeqNum seq_num,
484 ThreadID _tid)
485 : Event(CPU_Tick_Pri), resPool(_resPool),
486 eventType(e_type), inst(_inst), seqNum(seq_num),
487 stageNum(stage_num), tid(_tid)
488 { }
489
490
491 void
492 ResourcePool::ResPoolEvent::process()
493 {
494 switch (eventType)
495 {
496 case InOrderCPU::ActivateThread:
497 resPool->activateAll(tid);
498 break;
499
500 case InOrderCPU::DeactivateThread:
501 case InOrderCPU::HaltThread:
502 resPool->deactivateAll(tid);
503 break;
504
505 case InOrderCPU::SuspendThread:
506 resPool->suspendAll(tid);
507 break;
508
509 case ResourcePool::InstGraduated:
510 resPool->instGraduated(seqNum, tid);
511 break;
512
513 case ResourcePool::SquashAll:
514 resPool->squashAll(inst, stageNum, seqNum, tid);
515 break;
516
517 case InOrderCPU::SquashFromMemStall:
518 resPool->squashDueToMemStall(inst, stageNum, seqNum, tid);
519 break;
520
521 case ResourcePool::UpdateAfterContextSwitch:
522 resPool->updateAfterContextSwitch(inst, tid);
523 break;
524
525 default:
526 fatal("Unrecognized Event Type");
527 }
528
529 resPool->cpu->cpuEventRemoveList.push(this);
530 }
531
532
533 const char *
534 ResourcePool::ResPoolEvent::description()
535 {
536 return "Resource Pool event";
537 }
538
539 /** Schedule resource event, regardless of its current state. */
540 void
541 ResourcePool::ResPoolEvent::scheduleEvent(int delay)
542 {
543 InOrderCPU *cpu = resPool->cpu;
544 assert(!scheduled() || squashed());
545 cpu->reschedule(this, cpu->nextCycle(curTick() + cpu->ticks(delay)), true);
546 }
547
548 /** Unschedule resource event, regardless of its current state. */
549 void
550 ResourcePool::ResPoolEvent::unscheduleEvent()
551 {
552 if (scheduled())
553 squash();
554 }