62d68bb3389020992357e78b8313fab2e6221691
[gem5.git] / cpu / o3 / cpu.cc
1 /*
2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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
29 #include "config/full_system.hh"
30
31 #if FULL_SYSTEM
32 #include "sim/system.hh"
33 #else
34 #include "sim/process.hh"
35 #endif
36 #include "sim/root.hh"
37
38 #include "cpu/cpu_exec_context.hh"
39 #include "cpu/exec_context.hh"
40 #include "cpu/o3/alpha_dyn_inst.hh"
41 #include "cpu/o3/alpha_impl.hh"
42 #include "cpu/o3/cpu.hh"
43
44 using namespace std;
45
46 BaseFullCPU::BaseFullCPU(Params &params)
47 : BaseCPU(&params), cpu_id(0)
48 {
49 }
50
51 template <class Impl>
52 FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c)
53 : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
54 {
55 }
56
57 template <class Impl>
58 void
59 FullO3CPU<Impl>::TickEvent::process()
60 {
61 cpu->tick();
62 }
63
64 template <class Impl>
65 const char *
66 FullO3CPU<Impl>::TickEvent::description()
67 {
68 return "FullO3CPU tick event";
69 }
70
71 //Call constructor to all the pipeline stages here
72 template <class Impl>
73 FullO3CPU<Impl>::FullO3CPU(Params &params)
74 #if FULL_SYSTEM
75 : BaseFullCPU(params),
76 #else
77 : BaseFullCPU(params),
78 #endif // FULL_SYSTEM
79 tickEvent(this),
80 fetch(params),
81 decode(params),
82 rename(params),
83 iew(params),
84 commit(params),
85
86 regFile(params.numPhysIntRegs, params.numPhysFloatRegs),
87
88 freeList(TheISA::NumIntRegs, params.numPhysIntRegs,
89 TheISA::NumFloatRegs, params.numPhysFloatRegs),
90
91 renameMap(TheISA::NumIntRegs, params.numPhysIntRegs,
92 TheISA::NumFloatRegs, params.numPhysFloatRegs,
93 TheISA::NumMiscRegs,
94 TheISA::ZeroReg,
95 TheISA::ZeroReg + TheISA::NumIntRegs),
96
97 rob(params.numROBEntries, params.squashWidth),
98
99 // What to pass to these time buffers?
100 // For now just have these time buffers be pretty big.
101 timeBuffer(5, 5),
102 fetchQueue(5, 5),
103 decodeQueue(5, 5),
104 renameQueue(5, 5),
105 iewQueue(5, 5),
106
107 cpuXC(NULL),
108
109 globalSeqNum(1),
110
111 #if FULL_SYSTEM
112 system(params.system),
113 memCtrl(system->memctrl),
114 physmem(system->physmem),
115 itb(params.itb),
116 dtb(params.dtb),
117 mem(params.mem),
118 #else
119 // Hardcoded for a single thread!!
120 mem(params.workload[0]->getMemory()),
121 #endif // FULL_SYSTEM
122
123 icacheInterface(params.icacheInterface),
124 dcacheInterface(params.dcacheInterface),
125 deferRegistration(params.defReg),
126 numInsts(0),
127 funcExeInst(0)
128 {
129 _status = Idle;
130
131 #if !FULL_SYSTEM
132 thread.resize(this->number_of_threads);
133 #endif
134
135 for (int i = 0; i < this->number_of_threads; ++i) {
136 #if FULL_SYSTEM
137 assert(i == 0);
138 thread[i] = new CPUExecContext(this, 0, system, itb, dtb, mem);
139 system->execContexts[i] = thread[i]->getProxy();
140
141 execContexts.push_back(system->execContexts[i]);
142 #else
143 if (i < params.workload.size()) {
144 DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, "
145 "process is %#x",
146 i, params.workload[i]->prog_entry, thread[i]);
147 thread[i] = new CPUExecContext(this, i, params.workload[i], i);
148 }
149 assert(params.workload[i]->getMemory() != NULL);
150 assert(mem != NULL);
151 execContexts.push_back(thread[i]->getProxy());
152 #endif // !FULL_SYSTEM
153 }
154
155 // Note that this is a hack so that my code which still uses xc-> will
156 // still work. I should remove this eventually
157 cpuXC = thread[0];
158
159 // The stages also need their CPU pointer setup. However this must be
160 // done at the upper level CPU because they have pointers to the upper
161 // level CPU, and not this FullO3CPU.
162
163 // Give each of the stages the time buffer they will use.
164 fetch.setTimeBuffer(&timeBuffer);
165 decode.setTimeBuffer(&timeBuffer);
166 rename.setTimeBuffer(&timeBuffer);
167 iew.setTimeBuffer(&timeBuffer);
168 commit.setTimeBuffer(&timeBuffer);
169
170 // Also setup each of the stages' queues.
171 fetch.setFetchQueue(&fetchQueue);
172 decode.setFetchQueue(&fetchQueue);
173 decode.setDecodeQueue(&decodeQueue);
174 rename.setDecodeQueue(&decodeQueue);
175 rename.setRenameQueue(&renameQueue);
176 iew.setRenameQueue(&renameQueue);
177 iew.setIEWQueue(&iewQueue);
178 commit.setIEWQueue(&iewQueue);
179 commit.setRenameQueue(&renameQueue);
180
181 // Setup the rename map for whichever stages need it.
182 rename.setRenameMap(&renameMap);
183 iew.setRenameMap(&renameMap);
184
185 // Setup the free list for whichever stages need it.
186 rename.setFreeList(&freeList);
187 renameMap.setFreeList(&freeList);
188
189 // Setup the ROB for whichever stages need it.
190 commit.setROB(&rob);
191 }
192
193 template <class Impl>
194 FullO3CPU<Impl>::~FullO3CPU()
195 {
196 }
197
198 template <class Impl>
199 void
200 FullO3CPU<Impl>::fullCPURegStats()
201 {
202 // Register any of the FullCPU's stats here.
203 }
204
205 template <class Impl>
206 void
207 FullO3CPU<Impl>::tick()
208 {
209 DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n");
210
211 //Tick each of the stages if they're actually running.
212 //Will want to figure out a way to unschedule itself if they're all
213 //going to be idle for a long time.
214 fetch.tick();
215
216 decode.tick();
217
218 rename.tick();
219
220 iew.tick();
221
222 commit.tick();
223
224 // Now advance the time buffers, unless the stage is stalled.
225 timeBuffer.advance();
226
227 fetchQueue.advance();
228 decodeQueue.advance();
229 renameQueue.advance();
230 iewQueue.advance();
231
232 if (_status == Running && !tickEvent.scheduled())
233 tickEvent.schedule(curTick + 1);
234 }
235
236 template <class Impl>
237 void
238 FullO3CPU<Impl>::init()
239 {
240 if(!deferRegistration)
241 {
242 this->registerExecContexts();
243
244 // Need to do a copy of the xc->regs into the CPU's regfile so
245 // that it can start properly.
246 #if FULL_SYSTEM
247 ExecContext *src_xc = system->execContexts[0];
248 TheISA::initCPU(src_xc, src_xc->readCpuId());
249 #else
250 ExecContext *src_xc = thread[0]->getProxy();
251 #endif
252 // First loop through the integer registers.
253 for (int i = 0; i < TheISA::NumIntRegs; ++i)
254 {
255 regFile.intRegFile[i] = src_xc->readIntReg(i);
256 }
257
258 // Then loop through the floating point registers.
259 for (int i = 0; i < TheISA::NumFloatRegs; ++i)
260 {
261 regFile.floatRegFile[i].d = src_xc->readFloatRegDouble(i);
262 regFile.floatRegFile[i].q = src_xc->readFloatRegInt(i);
263 }
264 /*
265 // Then loop through the misc registers.
266 regFile.miscRegs.fpcr = src_xc->regs.miscRegs.fpcr;
267 regFile.miscRegs.uniq = src_xc->regs.miscRegs.uniq;
268 regFile.miscRegs.lock_flag = src_xc->regs.miscRegs.lock_flag;
269 regFile.miscRegs.lock_addr = src_xc->regs.miscRegs.lock_addr;
270 */
271 // Then finally set the PC and the next PC.
272 regFile.pc = src_xc->readPC();
273 regFile.npc = src_xc->readNextPC();
274 }
275 }
276
277 template <class Impl>
278 void
279 FullO3CPU<Impl>::activateContext(int thread_num, int delay)
280 {
281 // Needs to set each stage to running as well.
282
283 scheduleTickEvent(delay);
284
285 _status = Running;
286 }
287
288 template <class Impl>
289 void
290 FullO3CPU<Impl>::suspendContext(int thread_num)
291 {
292 panic("suspendContext unimplemented!");
293 }
294
295 template <class Impl>
296 void
297 FullO3CPU<Impl>::deallocateContext(int thread_num)
298 {
299 panic("deallocateContext unimplemented!");
300 }
301
302 template <class Impl>
303 void
304 FullO3CPU<Impl>::haltContext(int thread_num)
305 {
306 panic("haltContext unimplemented!");
307 }
308
309 template <class Impl>
310 void
311 FullO3CPU<Impl>::switchOut()
312 {
313 panic("FullO3CPU does not have a switch out function.\n");
314 }
315
316 template <class Impl>
317 void
318 FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
319 {
320 BaseCPU::takeOverFrom(oldCPU);
321
322 assert(!tickEvent.scheduled());
323
324 // Set all status's to active, schedule the
325 // CPU's tick event.
326 for (int i = 0; i < execContexts.size(); ++i) {
327 ExecContext *xc = execContexts[i];
328 if (xc->status() == ExecContext::Active && _status != Running) {
329 _status = Running;
330 tickEvent.schedule(curTick);
331 }
332 }
333 }
334
335 template <class Impl>
336 InstSeqNum
337 FullO3CPU<Impl>::getAndIncrementInstSeq()
338 {
339 // Hopefully this works right.
340 return globalSeqNum++;
341 }
342
343 template <class Impl>
344 uint64_t
345 FullO3CPU<Impl>::readIntReg(int reg_idx)
346 {
347 return regFile.readIntReg(reg_idx);
348 }
349
350 template <class Impl>
351 float
352 FullO3CPU<Impl>::readFloatRegSingle(int reg_idx)
353 {
354 return regFile.readFloatRegSingle(reg_idx);
355 }
356
357 template <class Impl>
358 double
359 FullO3CPU<Impl>::readFloatRegDouble(int reg_idx)
360 {
361 return regFile.readFloatRegDouble(reg_idx);
362 }
363
364 template <class Impl>
365 uint64_t
366 FullO3CPU<Impl>::readFloatRegInt(int reg_idx)
367 {
368 return regFile.readFloatRegInt(reg_idx);
369 }
370
371 template <class Impl>
372 void
373 FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val)
374 {
375 regFile.setIntReg(reg_idx, val);
376 }
377
378 template <class Impl>
379 void
380 FullO3CPU<Impl>::setFloatRegSingle(int reg_idx, float val)
381 {
382 regFile.setFloatRegSingle(reg_idx, val);
383 }
384
385 template <class Impl>
386 void
387 FullO3CPU<Impl>::setFloatRegDouble(int reg_idx, double val)
388 {
389 regFile.setFloatRegDouble(reg_idx, val);
390 }
391
392 template <class Impl>
393 void
394 FullO3CPU<Impl>::setFloatRegInt(int reg_idx, uint64_t val)
395 {
396 regFile.setFloatRegInt(reg_idx, val);
397 }
398
399 template <class Impl>
400 uint64_t
401 FullO3CPU<Impl>::readPC()
402 {
403 return regFile.readPC();
404 }
405
406 template <class Impl>
407 void
408 FullO3CPU<Impl>::setNextPC(uint64_t val)
409 {
410 regFile.setNextPC(val);
411 }
412
413 template <class Impl>
414 void
415 FullO3CPU<Impl>::setPC(Addr new_PC)
416 {
417 regFile.setPC(new_PC);
418 }
419
420 template <class Impl>
421 void
422 FullO3CPU<Impl>::addInst(DynInstPtr &inst)
423 {
424 instList.push_back(inst);
425 }
426
427 template <class Impl>
428 void
429 FullO3CPU<Impl>::instDone()
430 {
431 // Keep an instruction count.
432 numInsts++;
433
434 // Check for instruction-count-based events.
435 comInstEventQueue[0]->serviceEvents(numInsts);
436 }
437
438 template <class Impl>
439 void
440 FullO3CPU<Impl>::removeBackInst(DynInstPtr &inst)
441 {
442 DynInstPtr inst_to_delete;
443
444 // Walk through the instruction list, removing any instructions
445 // that were inserted after the given instruction, inst.
446 while (instList.back() != inst)
447 {
448 assert(!instList.empty());
449
450 // Obtain the pointer to the instruction.
451 inst_to_delete = instList.back();
452
453 DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n",
454 inst_to_delete->seqNum, inst_to_delete->readPC());
455
456 // Remove the instruction from the list.
457 instList.pop_back();
458
459 // Mark it as squashed.
460 inst_to_delete->setSquashed();
461 }
462 }
463
464 template <class Impl>
465 void
466 FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst)
467 {
468 DynInstPtr inst_to_remove;
469
470 // The front instruction should be the same one being asked to be removed.
471 assert(instList.front() == inst);
472
473 // Remove the front instruction.
474 inst_to_remove = inst;
475 instList.pop_front();
476
477 DPRINTF(FullCPU, "FullCPU: Removing committed instruction %#x, PC %#x\n",
478 inst_to_remove, inst_to_remove->readPC());
479 }
480
481 template <class Impl>
482 void
483 FullO3CPU<Impl>::removeInstsNotInROB()
484 {
485 DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
486 "list.\n");
487
488 DynInstPtr rob_tail = rob.readTailInst();
489
490 removeBackInst(rob_tail);
491 }
492
493 template <class Impl>
494 void
495 FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num)
496 {
497 DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
498 "list.\n");
499
500 DynInstPtr inst_to_delete;
501
502 while (instList.back()->seqNum > seq_num) {
503 assert(!instList.empty());
504
505 // Obtain the pointer to the instruction.
506 inst_to_delete = instList.back();
507
508 DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n",
509 inst_to_delete->seqNum, inst_to_delete->readPC());
510
511 // Remove the instruction from the list.
512 instList.back() = NULL;
513 instList.pop_back();
514
515 // Mark it as squashed.
516 inst_to_delete->setSquashed();
517 }
518
519 }
520
521 template <class Impl>
522 void
523 FullO3CPU<Impl>::removeAllInsts()
524 {
525 instList.clear();
526 }
527
528 template <class Impl>
529 void
530 FullO3CPU<Impl>::dumpInsts()
531 {
532 int num = 0;
533 typename list<DynInstPtr>::iterator inst_list_it = instList.begin();
534
535 while (inst_list_it != instList.end())
536 {
537 cprintf("Instruction:%i\nPC:%#x\nSN:%lli\nIssued:%i\nSquashed:%i\n\n",
538 num, (*inst_list_it)->readPC(), (*inst_list_it)->seqNum,
539 (*inst_list_it)->isIssued(), (*inst_list_it)->isSquashed());
540 inst_list_it++;
541 ++num;
542 }
543 }
544
545 template <class Impl>
546 void
547 FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
548 {
549 iew.wakeDependents(inst);
550 }
551
552 // Forward declaration of FullO3CPU.
553 template class FullO3CPU<AlphaSimpleImpl>;