inorder: suspend in respool
[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 void
205 ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
206 int delay, int res_idx, ThreadID tid)
207 {
208 assert(delay >= 0);
209
210 switch (e_type)
211 {
212 case InOrderCPU::ActivateThread:
213 {
214 DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event "
215 "for tick %i, [tid:%i].\n", curTick + delay,
216 inst->readTid());
217 ResPoolEvent *res_pool_event =
218 new ResPoolEvent(this,
219 e_type,
220 inst,
221 inst->squashingStage,
222 inst->bdelaySeqNum,
223 inst->readTid());
224 mainEventQueue.schedule(res_pool_event,
225 curTick + cpu->ticks(delay));
226 }
227 break;
228
229 case InOrderCPU::DeactivateThread:
230 case InOrderCPU::DeallocateThread:
231 {
232
233 DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool "
234 "Event for tick %i.\n", curTick + delay);
235 ResPoolEvent *res_pool_event =
236 new ResPoolEvent(this,
237 e_type,
238 inst,
239 inst->squashingStage,
240 inst->bdelaySeqNum,
241 tid);
242
243 mainEventQueue.schedule(res_pool_event,
244 curTick + cpu->ticks(delay));
245
246 }
247 break;
248
249 case InOrderCPU::SuspendThread:
250 {
251
252 DPRINTF(Resource, "Scheduling Suspend Thread Resource Pool Event for tick %i.\n",
253 curTick + delay);
254 ResPoolEvent *res_pool_event = new ResPoolEvent(this,
255 e_type,
256 inst,
257 inst->squashingStage,
258 inst->bdelaySeqNum,
259 tid);
260
261 mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
262
263 }
264 break;
265
266 case ResourcePool::InstGraduated:
267 {
268 DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool "
269 "Event for tick %i.\n", curTick + delay);
270 ResPoolEvent *res_pool_event =
271 new ResPoolEvent(this,e_type,
272 inst,
273 inst->squashingStage,
274 inst->seqNum,
275 inst->readTid());
276 mainEventQueue.schedule(res_pool_event,
277 curTick + cpu->ticks(delay));
278
279 }
280 break;
281
282 case ResourcePool::SquashAll:
283 {
284 DPRINTF(Resource, "Scheduling Squash Resource Pool Event for "
285 "tick %i.\n", curTick + delay);
286 ResPoolEvent *res_pool_event =
287 new ResPoolEvent(this,e_type,
288 inst,
289 inst->squashingStage,
290 inst->bdelaySeqNum,
291 inst->readTid());
292 mainEventQueue.schedule(res_pool_event,
293 curTick + cpu->ticks(delay));
294 }
295 break;
296
297 case InOrderCPU::SquashFromMemStall:
298 {
299 DPRINTF(Resource, "Scheduling Squash Due to Memory Stall Resource "
300 "Pool Event for tick %i.\n",
301 curTick + delay);
302 ResPoolEvent *res_pool_event =
303 new ResPoolEvent(this,e_type,
304 inst,
305 inst->squashingStage,
306 inst->seqNum - 1,
307 inst->readTid());
308 mainEventQueue.schedule(res_pool_event,
309 curTick + cpu->ticks(delay));
310 }
311 break;
312
313 default:
314 DPRINTF(Resource, "Ignoring Unrecognized CPU Event (%s).\n",
315 InOrderCPU::eventNames[e_type]);
316 }
317 }
318
319 void
320 ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
321 {
322 resources[res_idx]->unscheduleEvent(inst);
323 }
324
325 void
326 ResourcePool::squashAll(DynInstPtr inst, int stage_num,
327 InstSeqNum done_seq_num, ThreadID tid)
328 {
329 DPRINTF(Resource, "[tid:%i] Broadcasting Squash All Event "
330 " starting w/stage %i for all instructions above [sn:%i].\n",
331 tid, stage_num, done_seq_num);
332
333 int num_resources = resources.size();
334
335 for (int idx = 0; idx < num_resources; idx++) {
336 resources[idx]->squash(inst, stage_num, done_seq_num, tid);
337 }
338 }
339
340 void
341 ResourcePool::squashDueToMemStall(DynInstPtr inst, int stage_num,
342 InstSeqNum done_seq_num, ThreadID tid)
343 {
344 DPRINTF(Resource, "[tid:%i] Broadcasting SquashDueToMemStall Event"
345 " starting w/stage %i for all instructions above [sn:%i].\n",
346 tid, stage_num, done_seq_num);
347
348 int num_resources = resources.size();
349
350 for (int idx = 0; idx < num_resources; idx++) {
351 resources[idx]->squashDueToMemStall(inst, stage_num, done_seq_num,
352 tid);
353 }
354 }
355
356 void
357 ResourcePool::activateAll(ThreadID tid)
358 {
359 bool do_activate = cpu->threadModel != InOrderCPU::SwitchOnCacheMiss ||
360 cpu->numActiveThreads() < 1 ||
361 cpu->activeThreadId() == tid;
362
363
364 if (do_activate) {
365 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all "
366 "resources.\n", tid);
367
368 int num_resources = resources.size();
369
370 for (int idx = 0; idx < num_resources; idx++) {
371 resources[idx]->activateThread(tid);
372 }
373 } else {
374 DPRINTF(Resource, "[tid:%i] Ignoring Thread Activation to all "
375 "resources.\n", tid);
376 }
377 }
378
379 void
380 ResourcePool::deactivateAll(ThreadID tid)
381 {
382 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all "
383 "resources.\n", tid);
384
385 int num_resources = resources.size();
386
387 for (int idx = 0; idx < num_resources; idx++) {
388 resources[idx]->deactivateThread(tid);
389 }
390 }
391
392 void
393 ResourcePool::suspendAll(ThreadID tid)
394 {
395 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Suspension to all resources.\n",
396 tid);
397
398 int num_resources = resources.size();
399
400 for (int idx = 0; idx < num_resources; idx++) {
401 resources[idx]->suspendThread(tid);
402 }
403 }
404
405 void
406 ResourcePool::instGraduated(InstSeqNum seq_num, ThreadID tid)
407 {
408 DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all "
409 "resources.\n", tid, seq_num);
410
411 int num_resources = resources.size();
412
413 for (int idx = 0; idx < num_resources; idx++) {
414 resources[idx]->instGraduated(seq_num, tid);
415 }
416 }
417
418 ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool)
419 : Event((Event::Priority)((unsigned)CPU_Tick_Pri+5)), resPool(_resPool),
420 eventType((InOrderCPU::CPUEventType) Default)
421 { }
422
423 ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool,
424 InOrderCPU::CPUEventType e_type,
425 DynInstPtr _inst,
426 int stage_num,
427 InstSeqNum seq_num,
428 ThreadID _tid)
429 : Event(CPU_Tick_Pri), resPool(_resPool),
430 eventType(e_type), inst(_inst), seqNum(seq_num),
431 stageNum(stage_num), tid(_tid)
432 { }
433
434
435 void
436 ResourcePool::ResPoolEvent::process()
437 {
438 switch (eventType)
439 {
440 case InOrderCPU::ActivateThread:
441 resPool->activateAll(tid);
442 break;
443
444 case InOrderCPU::DeactivateThread:
445 case InOrderCPU::DeallocateThread:
446 resPool->deactivateAll(tid);
447 break;
448
449 case InOrderCPU::SuspendThread:
450 resPool->suspendAll(tid);
451 break;
452
453 case ResourcePool::InstGraduated:
454 resPool->instGraduated(seqNum, tid);
455 break;
456
457 case ResourcePool::SquashAll:
458 resPool->squashAll(inst, stageNum, seqNum, tid);
459 break;
460
461 case InOrderCPU::SquashFromMemStall:
462 resPool->squashDueToMemStall(inst, stageNum, seqNum, tid);
463 break;
464
465 default:
466 fatal("Unrecognized Event Type");
467 }
468
469 resPool->cpu->cpuEventRemoveList.push(this);
470 }
471
472
473 const char *
474 ResourcePool::ResPoolEvent::description()
475 {
476 return "Resource Pool event";
477 }
478
479 /** Schedule resource event, regardless of its current state. */
480 void
481 ResourcePool::ResPoolEvent::scheduleEvent(int delay)
482 {
483 if (squashed())
484 mainEventQueue.reschedule(this,curTick + resPool->cpu->ticks(delay));
485 else if (!scheduled())
486 mainEventQueue.schedule(this,curTick + resPool->cpu->ticks(delay));
487 }
488
489 /** Unschedule resource event, regardless of its current state. */
490 void
491 ResourcePool::ResPoolEvent::unscheduleEvent()
492 {
493 if (scheduled())
494 squash();
495 }