ruby: move stall and wakeup functions to AbstractController
[gem5.git] / src / cpu / inorder / resource_pool.cc
1 /*
2 * Copyright (c) 2012 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2007 MIPS Technologies, Inc.
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Korey Sewell
41 *
42 */
43
44 #include <list>
45 #include <vector>
46
47 #include "cpu/inorder/resources/resource_list.hh"
48 #include "cpu/inorder/resource_pool.hh"
49 #include "debug/Resource.hh"
50
51 using namespace std;
52 using namespace ThePipeline;
53
54 ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
55 : cpu(_cpu), instUnit(NULL), dataUnit(NULL)
56 {
57 //@todo: use this function to instantiate the resources in resource pool.
58 //This will help in the auto-generation of this pipeline model.
59 //ThePipeline::addResources(resources, memObjects);
60
61 int stage_width = cpu->stageWidth;
62
63 // Declare Resource Objects
64 // name - id - bandwidth - latency - CPU - Parameters
65 // --------------------------------------------------
66 resources.push_back(new FetchSeqUnit("fetch_seq_unit", FetchSeq,
67 stage_width * 2, Cycles(0),
68 _cpu, params));
69
70 // Keep track of the instruction fetch unit so we can easily
71 // provide a pointer to it in the CPU.
72 instUnit = new FetchUnit("icache_port", ICache,
73 stage_width * 2 + MaxThreads, Cycles(0), _cpu,
74 params);
75 resources.push_back(instUnit);
76
77 resources.push_back(new DecodeUnit("decode_unit", Decode,
78 stage_width, Cycles(0), _cpu,
79 params));
80
81 resources.push_back(new BranchPredictor("branch_predictor", BPred,
82 stage_width, Cycles(0),
83 _cpu, params));
84
85 resources.push_back(new InstBuffer("fetch_buffer_t0", FetchBuff, 4,
86 Cycles(0), _cpu, params));
87
88 resources.push_back(new UseDefUnit("regfile_manager", RegManager,
89 stage_width * 3, Cycles(0), _cpu,
90 params));
91
92 resources.push_back(new AGENUnit("agen_unit", AGEN,
93 stage_width, Cycles(0), _cpu,
94 params));
95
96 resources.push_back(new ExecutionUnit("execution_unit", ExecUnit,
97 stage_width, Cycles(0), _cpu,
98 params));
99
100 resources.push_back(new MultDivUnit("mult_div_unit", MDU,
101 stage_width * 2, Cycles(0),
102 _cpu, params));
103
104 // Keep track of the data load/store unit so we can easily provide
105 // a pointer to it in the CPU.
106 dataUnit = new CacheUnit("dcache_port", DCache,
107 stage_width * 2 + MaxThreads, Cycles(0), _cpu,
108 params);
109 resources.push_back(dataUnit);
110
111 gradObjects.push_back(BPred);
112 resources.push_back(new GraduationUnit("graduation_unit", Grad,
113 stage_width, Cycles(0), _cpu,
114 params));
115
116 resources.push_back(new InstBuffer("fetch_buffer_t1", FetchBuff2, 4,
117 Cycles(0), _cpu, params));
118
119 }
120
121 ResourcePool::~ResourcePool()
122 {
123 cout << "Deleting resources ..." << endl;
124
125 for (int i=0; i < resources.size(); i++) {
126 DPRINTF(Resource, "Deleting resource: %s.\n", resources[i]->name());
127
128 delete resources[i];
129 }
130 }
131
132
133 void
134 ResourcePool::init()
135 {
136 for (int i=0; i < resources.size(); i++) {
137 DPRINTF(Resource, "Initializing resource: %s.\n",
138 resources[i]->name());
139
140 resources[i]->init();
141 }
142 }
143
144 string
145 ResourcePool::name()
146 {
147 return cpu->name() + ".ResourcePool";
148 }
149
150 void
151 ResourcePool::print()
152 {
153 for (int i=0; i < resources.size(); i++) {
154 DPRINTF(InOrderDynInst, "Res:%i %s\n",
155 i, resources[i]->name());
156 }
157
158 }
159
160
161 void
162 ResourcePool::regStats()
163 {
164 DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n");
165
166 int num_resources = resources.size();
167
168 for (int idx = 0; idx < num_resources; idx++) {
169 resources[idx]->regStats();
170 }
171 }
172
173 unsigned
174 ResourcePool::getResIdx(const ThePipeline::ResourceId &res_id)
175 {
176 int num_resources = resources.size();
177
178 for (int idx = 0; idx < num_resources; idx++) {
179 if (resources[idx]->getId() == res_id)
180 return idx;
181 }
182
183 // todo: change return value to int and return a -1 here
184 // maybe even have enumerated type
185 // panic for now...
186 panic("Can't find resource idx for: %i\n", res_id);
187
188 return 0;
189 }
190
191 ResReqPtr
192 ResourcePool::request(int res_idx, DynInstPtr inst)
193 {
194 //Make Sure This is a valid resource ID
195 assert(res_idx >= 0 && res_idx < resources.size());
196
197 return resources[res_idx]->request(inst);
198 }
199
200 void
201 ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num,
202 ThreadID tid)
203 {
204 resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num,
205 tid);
206 }
207
208 void
209 ResourcePool::trap(Fault fault, ThreadID tid, DynInstPtr inst)
210 {
211 DPRINTF(Resource, "[tid:%i] Broadcasting Trap to all "
212 "resources.\n", tid);
213
214 int num_resources = resources.size();
215
216 for (int idx = 0; idx < num_resources; idx++)
217 resources[idx]->trap(fault, tid, inst);
218 }
219
220 int
221 ResourcePool::slotsAvail(int res_idx)
222 {
223 return resources[res_idx]->slotsAvail();
224 }
225
226 int
227 ResourcePool::slotsInUse(int res_idx)
228 {
229 return resources[res_idx]->slotsInUse();
230 }
231
232 //@todo: split this function and call this version schedulePoolEvent
233 // and use this scheduleEvent for scheduling a specific event on
234 // a resource
235 //@todo: For arguments that arent being used in a ResPoolEvent, a dummyParam
236 // or some typedef can be used to signify what's important info
237 // to the event construction
238 void
239 ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
240 Cycles delay, int res_idx, ThreadID tid)
241 {
242 assert(delay >= 0);
243
244 Tick when = cpu->clockEdge(delay);
245
246 switch ((int)e_type)
247 {
248 case ResourcePool::InstGraduated:
249 {
250 DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool "
251 "Event for tick %i.\n", curTick() + delay);
252 ResPoolEventPri grad_pri = ResGrad_Pri;
253 ResPoolEvent *res_pool_event =
254 new ResPoolEvent(this,
255 e_type,
256 inst,
257 inst->squashingStage,
258 inst->seqNum,
259 inst->readTid(),
260 grad_pri);
261 cpu->schedule(res_pool_event, when);
262 }
263 break;
264
265 case ResourcePool::SquashAll:
266 {
267 DPRINTF(Resource, "Scheduling Squash Resource Pool Event for "
268 "tick %i.\n", curTick() + delay);
269 ResPoolEventPri squash_pri = ResSquash_Pri;
270 ResPoolEvent *res_pool_event =
271 new ResPoolEvent(this,
272 e_type,
273 inst,
274 inst->squashingStage,
275 inst->squashSeqNum,
276 inst->readTid(),
277 squash_pri);
278 cpu->schedule(res_pool_event, when);
279 }
280 break;
281
282 case ResourcePool::UpdateAfterContextSwitch:
283 {
284 DPRINTF(Resource, "Scheduling UpdatePC Resource Pool Event "
285 "for tick %i.\n",
286 curTick() + delay);
287 ResPoolEvent *res_pool_event = new ResPoolEvent(this,
288 e_type,
289 inst,
290 inst->squashingStage,
291 inst->seqNum,
292 inst->readTid());
293 cpu->schedule(res_pool_event, when);
294 }
295 break;
296
297 default:
298 DPRINTF(Resource, "Ignoring Unrecognized CPU Event (%s).\n",
299 InOrderCPU::eventNames[e_type]);
300 }
301 }
302
303 void
304 ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
305 {
306 resources[res_idx]->unscheduleEvent(inst);
307 }
308
309 void
310 ResourcePool::squashAll(DynInstPtr inst, int stage_num,
311 InstSeqNum done_seq_num, ThreadID tid)
312 {
313 DPRINTF(Resource, "[tid:%i] Broadcasting Squash All Event "
314 " starting w/stage %i for all instructions above [sn:%i].\n",
315 tid, stage_num, done_seq_num);
316
317 int num_resources = resources.size();
318
319 for (int idx = 0; idx < num_resources; idx++) {
320 resources[idx]->squash(inst, stage_num, done_seq_num, tid);
321 }
322 }
323
324 void
325 ResourcePool::squashDueToMemStall(DynInstPtr inst, int stage_num,
326 InstSeqNum done_seq_num, ThreadID tid)
327 {
328 DPRINTF(Resource, "[tid:%i] Broadcasting SquashDueToMemStall Event"
329 " starting w/stage %i for all instructions above [sn:%i].\n",
330 tid, stage_num, done_seq_num);
331
332 int num_resources = resources.size();
333
334 for (int idx = 0; idx < num_resources; idx++) {
335 resources[idx]->squashDueToMemStall(inst, stage_num, done_seq_num,
336 tid);
337 }
338 }
339
340 void
341 ResourcePool::activateThread(ThreadID tid)
342 {
343 bool do_activate = cpu->threadModel != InOrderCPU::SwitchOnCacheMiss ||
344 cpu->numActiveThreads() < 1 ||
345 cpu->activeThreadId() == tid;
346
347
348 if (do_activate) {
349 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all "
350 "resources.\n", tid);
351
352 int num_resources = resources.size();
353
354 for (int idx = 0; idx < num_resources; idx++) {
355 resources[idx]->activateThread(tid);
356 }
357 } else {
358 DPRINTF(Resource, "[tid:%i] Ignoring Thread Activation to all "
359 "resources.\n", tid);
360 }
361 }
362
363 void
364 ResourcePool::deactivateThread(ThreadID tid)
365 {
366 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all "
367 "resources.\n", tid);
368
369 int num_resources = resources.size();
370
371 for (int idx = 0; idx < num_resources; idx++) {
372 resources[idx]->deactivateThread(tid);
373 }
374 }
375
376 void
377 ResourcePool::suspendThread(ThreadID tid)
378 {
379 DPRINTF(Resource, "[tid:%i] Broadcasting Thread Suspension to all "
380 "resources.\n", tid);
381
382 int num_resources = resources.size();
383
384 for (int idx = 0; idx < num_resources; idx++) {
385 resources[idx]->suspendThread(tid);
386 }
387 }
388
389 void
390 ResourcePool::instGraduated(InstSeqNum seq_num, ThreadID tid)
391 {
392 DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to "
393 "appropriate resources.\n", tid, seq_num);
394
395 int num_resources = gradObjects.size();
396
397 for (int idx = 0; idx < num_resources; idx++) {
398 resources[gradObjects[idx]]->instGraduated(seq_num, tid);
399 }
400 }
401
402 void
403 ResourcePool::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
404 {
405 DPRINTF(Resource, "[tid:%i] Broadcasting Update PC to all resources.\n",
406 tid);
407
408 int num_resources = resources.size();
409
410 for (int idx = 0; idx < num_resources; idx++) {
411 resources[idx]->updateAfterContextSwitch(inst, tid);
412 }
413 }
414
415 ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool,
416 InOrderCPU::CPUEventType e_type,
417 DynInstPtr _inst,
418 int stage_num,
419 InstSeqNum seq_num,
420 ThreadID _tid,
421 ResPoolEventPri res_pri)
422 : Event(res_pri), resPool(_resPool),
423 eventType(e_type), inst(_inst), seqNum(seq_num),
424 stageNum(stage_num), tid(_tid)
425 { }
426
427
428 void
429 ResourcePool::ResPoolEvent::process()
430 {
431 switch ((int)eventType)
432 {
433
434 case ResourcePool::InstGraduated:
435 resPool->instGraduated(seqNum, tid);
436 break;
437
438 case ResourcePool::SquashAll:
439 resPool->squashAll(inst, stageNum, seqNum, tid);
440 break;
441
442 case ResourcePool::UpdateAfterContextSwitch:
443 resPool->updateAfterContextSwitch(inst, tid);
444 break;
445
446 default:
447 fatal("Unrecognized Event Type");
448 }
449
450 resPool->cpu->cpuEventRemoveList.push(this);
451 }
452
453
454 const char *
455 ResourcePool::ResPoolEvent::description() const
456 {
457 return "Resource Pool event";
458 }
459
460 /** Schedule resource event, regardless of its current state. */
461 void
462 ResourcePool::ResPoolEvent::scheduleEvent(Cycles delay)
463 {
464 InOrderCPU *cpu = resPool->cpu;
465 assert(!scheduled() || squashed());
466 cpu->reschedule(this, cpu->clockEdge(delay), true);
467 }
468
469 /** Unschedule resource event, regardless of its current state. */
470 void
471 ResourcePool::ResPoolEvent::unscheduleEvent()
472 {
473 if (scheduled())
474 squash();
475 }