inorder: add/remove halt/deallocate context respectively
[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 void
95 ResourcePool::init()
96 {
97 for (int i=0; i < resources.size(); i++) {
98 DPRINTF(Resource, "Initializing resource: %s.\n",
99 resources[i]->name());
100
101 resources[i]->init();
102 }
103 }
104
105 string
106 ResourcePool::name()
107 {
108 return cpu->name() + ".ResourcePool";
109 }
110
111
112 void
113 ResourcePool::regStats()
114 {
115 DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n");
116
117 int num_resources = resources.size();
118
119 for (int idx = 0; idx < num_resources; idx++) {
120 resources[idx]->regStats();
121 }
122 }
123
124 Port *
125 ResourcePool::getPort(const std::string &if_name, int idx)
126 {
127 DPRINTF(Resource, "Binding %s in Resource Pool.\n", if_name);
128
129 for (int i = 0; i < memObjects.size(); i++) {
130 int obj_idx = memObjects[i];
131 Port *port = resources[obj_idx]->getPort(if_name, idx);
132 if (port != NULL) {
133 DPRINTF(Resource, "%s set to resource %s(#%i) in Resource Pool.\n",
134 if_name, resources[obj_idx]->name(), obj_idx);
135 return port;
136 }
137 }
138
139 return NULL;
140 }
141
142 unsigned
143 ResourcePool::getPortIdx(const std::string &port_name)
144 {
145 DPRINTF(Resource, "Finding Port Idx for %s.\n", port_name);
146
147 for (int i = 0; i < memObjects.size(); i++) {
148 unsigned obj_idx = memObjects[i];
149 Port *port = resources[obj_idx]->getPort(port_name, obj_idx);
150 if (port != NULL) {
151 DPRINTF(Resource, "Returning Port Idx %i for %s.\n", obj_idx,
152 port_name);
153 return obj_idx;
154 }
155 }
156
157 return 0;
158 }
159
160 unsigned
161 ResourcePool::getResIdx(const std::string &res_name)
162 {
163 DPRINTF(Resource, "Finding Resource Idx for %s.\n", res_name);
164
165 int num_resources = resources.size();
166
167 for (int idx = 0; idx < num_resources; idx++) {
168 if (resources[idx]->name() == res_name)
169 return idx;
170 }
171
172 return 0;
173 }
174
175 ResReqPtr
176 ResourcePool::request(int res_idx, DynInstPtr inst)
177 {
178 //Make Sure This is a valid resource ID
179 assert(res_idx >= 0 && res_idx < resources.size());
180
181 return resources[res_idx]->request(inst);
182 }
183
184 void
185 ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num,
186 ThreadID tid)
187 {
188 resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num,
189 tid);
190 }
191
192 int
193 ResourcePool::slotsAvail(int res_idx)
194 {
195 return resources[res_idx]->slotsAvail();
196 }
197
198 int
199 ResourcePool::slotsInUse(int res_idx)
200 {
201 return resources[res_idx]->slotsInUse();
202 }
203
204 //@todo: split this function and call this version schedulePoolEvent
205 // and use this scheduleEvent for scheduling a specific event on
206 // a resource
207 //@todo: For arguments that arent being used in a ResPoolEvent, a dummyParam
208 // or some typedef can be used to signify what's important info
209 // to the event construction
210 void
211 ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
212 int delay, int res_idx, ThreadID tid)
213 {
214 assert(delay >= 0);
215
216 switch (e_type)
217 {
218 case InOrderCPU::ActivateThread:
219 {
220 DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event "
221 "for tick %i, [tid:%i].\n", curTick + delay,
222 inst->readTid());
223 ResPoolEvent *res_pool_event =
224 new ResPoolEvent(this,
225 e_type,
226 inst,
227 inst->squashingStage,
228 inst->bdelaySeqNum,
229 inst->readTid());
230 mainEventQueue.schedule(res_pool_event,
231 curTick + cpu->ticks(delay));
232 }
233 break;
234
235 case InOrderCPU::HaltThread:
236 case InOrderCPU::DeactivateThread:
237 {
238
239 DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool "
240 "Event for tick %i.\n", curTick + delay);
241 ResPoolEvent *res_pool_event =
242 new ResPoolEvent(this,
243 e_type,
244 inst,
245 inst->squashingStage,
246 inst->bdelaySeqNum,
247 tid);
248
249 mainEventQueue.schedule(res_pool_event,
250 curTick + cpu->ticks(delay));
251
252 }
253 break;
254
255 case InOrderCPU::SuspendThread:
256 {
257
258 DPRINTF(Resource, "Scheduling Suspend Thread Resource Pool Event for tick %i.\n",
259 curTick + delay);
260 ResPoolEvent *res_pool_event = new ResPoolEvent(this,
261 e_type,
262 inst,
263 inst->squashingStage,
264 inst->bdelaySeqNum,
265 tid);
266
267 mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
268
269 }
270 break;
271
272 case ResourcePool::InstGraduated:
273 {
274 DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool "
275 "Event for tick %i.\n", curTick + delay);
276 ResPoolEvent *res_pool_event =
277 new ResPoolEvent(this,e_type,
278 inst,
279 inst->squashingStage,
280 inst->seqNum,
281 inst->readTid());
282 mainEventQueue.schedule(res_pool_event,
283 curTick + cpu->ticks(delay));
284
285 }
286 break;
287
288 case ResourcePool::SquashAll:
289 {
290 DPRINTF(Resource, "Scheduling Squash Resource Pool Event for "
291 "tick %i.\n", curTick + delay);
292 ResPoolEvent *res_pool_event =
293 new ResPoolEvent(this,e_type,
294 inst,
295 inst->squashingStage,
296 inst->bdelaySeqNum,
297 inst->readTid());
298 mainEventQueue.schedule(res_pool_event,
299 curTick + cpu->ticks(delay));
300 }
301 break;
302
303 case InOrderCPU::SquashFromMemStall:
304 {
305 DPRINTF(Resource, "Scheduling Squash Due to Memory Stall Resource "
306 "Pool Event for tick %i.\n",
307 curTick + delay);
308 ResPoolEvent *res_pool_event =
309 new ResPoolEvent(this,e_type,
310 inst,
311 inst->squashingStage,
312 inst->seqNum - 1,
313 inst->readTid());
314 mainEventQueue.schedule(res_pool_event,
315 curTick + cpu->ticks(delay));
316 }
317 break;
318
319 case ResourcePool::UpdateAfterContextSwitch:
320 {
321 DPRINTF(Resource, "Scheduling UpdatePC Resource Pool Event for tick %i.\n",
322 curTick + delay);
323 ResPoolEvent *res_pool_event = new ResPoolEvent(this,e_type,
324 inst,
325 inst->squashingStage,
326 inst->seqNum,
327 inst->readTid());
328 mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
329
330 }
331 break;
332
333 default:
334 DPRINTF(Resource, "Ignoring Unrecognized CPU Event (%s).\n",
335 InOrderCPU::eventNames[e_type]);
336 }
337 }
338
339 void
340 ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
341 {
342 resources[res_idx]->unscheduleEvent(inst);
343 }
344
345 void
346 ResourcePool::squashAll(DynInstPtr inst, int stage_num,
347 InstSeqNum done_seq_num, ThreadID tid)
348 {
349 DPRINTF(Resource, "[tid:%i] Broadcasting Squash All Event "
350 " starting w/stage %i for all instructions above [sn:%i].\n",
351 tid, stage_num, done_seq_num);
352
353 int num_resources = resources.size();
354
355 for (int idx = 0; idx < num_resources; idx++) {
356 resources[idx]->squash(inst, stage_num, done_seq_num, tid);
357 }
358 }
359
360 void
361 ResourcePool::squashDueToMemStall(DynInstPtr inst, int stage_num,
362 InstSeqNum done_seq_num, ThreadID tid)
363 {
364 DPRINTF(Resource, "[tid:%i] Broadcasting SquashDueToMemStall Event"
365 " starting w/stage %i for all instructions above [sn:%i].\n",
366 tid, stage_num, done_seq_num);
367
368 int num_resources = resources.size();
369
370 for (int idx = 0; idx < num_resources; idx++) {
371 resources[idx]->squashDueToMemStall(inst, stage_num, done_seq_num,
372 tid);
373 }
374 }
375
376 void
377 ResourcePool::activateAll(ThreadID tid)
378 {
379 bool do_activate = cpu->threadModel != InOrderCPU::SwitchOnCacheMiss ||
380 cpu->numActiveThreads() < 1 ||
381 cpu->activeThreadId() == tid;
382
383
384 if (do_activate) {
385 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all "
386 "resources.\n", tid);
387
388 int num_resources = resources.size();
389
390 for (int idx = 0; idx < num_resources; idx++) {
391 resources[idx]->activateThread(tid);
392 }
393 } else {
394 DPRINTF(Resource, "[tid:%i] Ignoring Thread Activation to all "
395 "resources.\n", tid);
396 }
397 }
398
399 void
400 ResourcePool::deactivateAll(ThreadID tid)
401 {
402 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all "
403 "resources.\n", tid);
404
405 int num_resources = resources.size();
406
407 for (int idx = 0; idx < num_resources; idx++) {
408 resources[idx]->deactivateThread(tid);
409 }
410 }
411
412 void
413 ResourcePool::suspendAll(ThreadID tid)
414 {
415 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Suspension to all resources.\n",
416 tid);
417
418 int num_resources = resources.size();
419
420 for (int idx = 0; idx < num_resources; idx++) {
421 resources[idx]->suspendThread(tid);
422 }
423 }
424
425 void
426 ResourcePool::instGraduated(InstSeqNum seq_num, ThreadID tid)
427 {
428 DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all "
429 "resources.\n", tid, seq_num);
430
431 int num_resources = resources.size();
432
433 for (int idx = 0; idx < num_resources; idx++) {
434 resources[idx]->instGraduated(seq_num, tid);
435 }
436 }
437
438 void
439 ResourcePool::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
440 {
441 DPRINTF(Resource, "[tid:%i] Broadcasting Update PC to all resources.\n",
442 tid);
443
444 int num_resources = resources.size();
445
446 for (int idx = 0; idx < num_resources; idx++) {
447 resources[idx]->updateAfterContextSwitch(inst, tid);
448 }
449 }
450
451 ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool)
452 : Event((Event::Priority)((unsigned)CPU_Tick_Pri+5)), resPool(_resPool),
453 eventType((InOrderCPU::CPUEventType) Default)
454 { }
455
456 ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool,
457 InOrderCPU::CPUEventType e_type,
458 DynInstPtr _inst,
459 int stage_num,
460 InstSeqNum seq_num,
461 ThreadID _tid)
462 : Event(CPU_Tick_Pri), resPool(_resPool),
463 eventType(e_type), inst(_inst), seqNum(seq_num),
464 stageNum(stage_num), tid(_tid)
465 { }
466
467
468 void
469 ResourcePool::ResPoolEvent::process()
470 {
471 switch (eventType)
472 {
473 case InOrderCPU::ActivateThread:
474 resPool->activateAll(tid);
475 break;
476
477 case InOrderCPU::DeactivateThread:
478 case InOrderCPU::HaltThread:
479 resPool->deactivateAll(tid);
480 break;
481
482 case InOrderCPU::SuspendThread:
483 resPool->suspendAll(tid);
484 break;
485
486 case ResourcePool::InstGraduated:
487 resPool->instGraduated(seqNum, tid);
488 break;
489
490 case ResourcePool::SquashAll:
491 resPool->squashAll(inst, stageNum, seqNum, tid);
492 break;
493
494 case InOrderCPU::SquashFromMemStall:
495 resPool->squashDueToMemStall(inst, stageNum, seqNum, tid);
496 break;
497
498 case ResourcePool::UpdateAfterContextSwitch:
499 resPool->updateAfterContextSwitch(inst, tid);
500 break;
501
502 default:
503 fatal("Unrecognized Event Type");
504 }
505
506 resPool->cpu->cpuEventRemoveList.push(this);
507 }
508
509
510 const char *
511 ResourcePool::ResPoolEvent::description()
512 {
513 return "Resource Pool event";
514 }
515
516 /** Schedule resource event, regardless of its current state. */
517 void
518 ResourcePool::ResPoolEvent::scheduleEvent(int delay)
519 {
520 if (squashed())
521 mainEventQueue.reschedule(this,curTick + resPool->cpu->ticks(delay));
522 else if (!scheduled())
523 mainEventQueue.schedule(this,curTick + resPool->cpu->ticks(delay));
524 }
525
526 /** Unschedule resource event, regardless of its current state. */
527 void
528 ResourcePool::ResPoolEvent::unscheduleEvent()
529 {
530 if (scheduled())
531 squash();
532 }