Registers: Eliminate the ISA defined integer register file.
[gem5.git] / src / cpu / inorder / cpu.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 <algorithm>
33
34 #include "arch/utility.hh"
35 #include "config/full_system.hh"
36 #include "cpu/exetrace.hh"
37 #include "cpu/activity.hh"
38 #include "cpu/simple_thread.hh"
39 #include "cpu/thread_context.hh"
40 #include "cpu/base.hh"
41 #include "cpu/inorder/inorder_dyn_inst.hh"
42 #include "cpu/inorder/thread_context.hh"
43 #include "cpu/inorder/thread_state.hh"
44 #include "cpu/inorder/cpu.hh"
45 #include "params/InOrderCPU.hh"
46 #include "cpu/inorder/pipeline_traits.hh"
47 #include "cpu/inorder/first_stage.hh"
48 #include "cpu/inorder/resources/resource_list.hh"
49 #include "cpu/inorder/resource_pool.hh"
50 #include "mem/translating_port.hh"
51 #include "sim/process.hh"
52 #include "sim/stat_control.hh"
53
54 using namespace std;
55 using namespace TheISA;
56 using namespace ThePipeline;
57
58 InOrderCPU::TickEvent::TickEvent(InOrderCPU *c)
59 : Event(CPU_Tick_Pri), cpu(c)
60 { }
61
62
63 void
64 InOrderCPU::TickEvent::process()
65 {
66 cpu->tick();
67 }
68
69
70 const char *
71 InOrderCPU::TickEvent::description()
72 {
73 return "InOrderCPU tick event";
74 }
75
76 InOrderCPU::CPUEvent::CPUEvent(InOrderCPU *_cpu, CPUEventType e_type,
77 Fault fault, ThreadID _tid, unsigned _vpe)
78 : Event(CPU_Tick_Pri), cpu(_cpu)
79 {
80 setEvent(e_type, fault, _tid, _vpe);
81 }
82
83
84 std::string InOrderCPU::eventNames[NumCPUEvents] =
85 {
86 "ActivateThread",
87 "DeallocateThread",
88 "SuspendThread",
89 "DisableThreads",
90 "EnableThreads",
91 "DisableVPEs",
92 "EnableVPEs",
93 "Trap",
94 "InstGraduated",
95 "SquashAll",
96 "UpdatePCs"
97 };
98
99 void
100 InOrderCPU::CPUEvent::process()
101 {
102 switch (cpuEventType)
103 {
104 case ActivateThread:
105 cpu->activateThread(tid);
106 break;
107
108 //@TODO: Consider Implementing "Suspend Thread" as Separate from Deallocate
109 case SuspendThread: // Suspend & Deallocate are same for now.
110 //cpu->suspendThread(tid);
111 //break;
112 case DeallocateThread:
113 cpu->deallocateThread(tid);
114 break;
115
116 case EnableVPEs:
117 cpu->enableVPEs(vpe);
118 break;
119
120 case DisableVPEs:
121 cpu->disableVPEs(tid, vpe);
122 break;
123
124 case EnableThreads:
125 cpu->enableThreads(vpe);
126 break;
127
128 case DisableThreads:
129 cpu->disableThreads(tid, vpe);
130 break;
131
132 case Trap:
133 cpu->trapCPU(fault, tid);
134 break;
135
136 default:
137 fatal("Unrecognized Event Type %d", cpuEventType);
138 }
139
140 cpu->cpuEventRemoveList.push(this);
141 }
142
143 const char *
144 InOrderCPU::CPUEvent::description()
145 {
146 return "InOrderCPU event";
147 }
148
149 void
150 InOrderCPU::CPUEvent::scheduleEvent(int delay)
151 {
152 if (squashed())
153 mainEventQueue.reschedule(this,curTick + cpu->ticks(delay));
154 else if (!scheduled())
155 mainEventQueue.schedule(this,curTick + cpu->ticks(delay));
156 }
157
158 void
159 InOrderCPU::CPUEvent::unscheduleEvent()
160 {
161 if (scheduled())
162 squash();
163 }
164
165 InOrderCPU::InOrderCPU(Params *params)
166 : BaseCPU(params),
167 cpu_id(params->cpu_id),
168 coreType("default"),
169 _status(Idle),
170 tickEvent(this),
171 timeBuffer(2 , 2),
172 removeInstsThisCycle(false),
173 activityRec(params->name, NumStages, 10, params->activity),
174 switchCount(0),
175 deferRegistration(false/*params->deferRegistration*/),
176 stageTracing(params->stageTracing),
177 numVirtProcs(1)
178 {
179 cpu_params = params;
180
181 resPool = new ResourcePool(this, params);
182
183 // Resize for Multithreading CPUs
184 thread.resize(numThreads);
185
186 ThreadID active_threads = params->workload.size();
187
188 if (active_threads > MaxThreads) {
189 panic("Workload Size too large. Increase the 'MaxThreads'"
190 "in your InOrder implementation or "
191 "edit your workload size.");
192 }
193
194 // Bind the fetch & data ports from the resource pool.
195 fetchPortIdx = resPool->getPortIdx(params->fetchMemPort);
196 if (fetchPortIdx == 0) {
197 fatal("Unable to find port to fetch instructions from.\n");
198 }
199
200 dataPortIdx = resPool->getPortIdx(params->dataMemPort);
201 if (dataPortIdx == 0) {
202 fatal("Unable to find port for data.\n");
203 }
204
205 for (ThreadID tid = 0; tid < numThreads; ++tid) {
206 if (tid < (ThreadID)params->workload.size()) {
207 DPRINTF(InOrderCPU, "Workload[%i] process is %#x\n",
208 tid, this->thread[tid]);
209 this->thread[tid] =
210 new Thread(this, tid, params->workload[tid], tid);
211 } else {
212 //Allocate Empty thread so M5 can use later
213 //when scheduling threads to CPU
214 Process* dummy_proc = params->workload[0];
215 this->thread[tid] = new Thread(this, tid, dummy_proc, tid);
216 }
217
218 // Setup the TC that will serve as the interface to the threads/CPU.
219 InOrderThreadContext *tc = new InOrderThreadContext;
220 tc->cpu = this;
221 tc->thread = thread[tid];
222
223 // Give the thread the TC.
224 thread[tid]->tc = tc;
225 thread[tid]->setFuncExeInst(0);
226 globalSeqNum[tid] = 1;
227
228 // Add the TC to the CPU's list of TC's.
229 this->threadContexts.push_back(tc);
230 }
231
232 // Initialize TimeBuffer Stage Queues
233 for (int stNum=0; stNum < NumStages - 1; stNum++) {
234 stageQueue[stNum] = new StageQueue(NumStages, NumStages);
235 stageQueue[stNum]->id(stNum);
236 }
237
238
239 // Set Up Pipeline Stages
240 for (int stNum=0; stNum < NumStages; stNum++) {
241 if (stNum == 0)
242 pipelineStage[stNum] = new FirstStage(params, stNum);
243 else
244 pipelineStage[stNum] = new PipelineStage(params, stNum);
245
246 pipelineStage[stNum]->setCPU(this);
247 pipelineStage[stNum]->setActiveThreads(&activeThreads);
248 pipelineStage[stNum]->setTimeBuffer(&timeBuffer);
249
250 // Take Care of 1st/Nth stages
251 if (stNum > 0)
252 pipelineStage[stNum]->setPrevStageQueue(stageQueue[stNum - 1]);
253 if (stNum < NumStages - 1)
254 pipelineStage[stNum]->setNextStageQueue(stageQueue[stNum]);
255 }
256
257 // Initialize thread specific variables
258 for (ThreadID tid = 0; tid < numThreads; tid++) {
259 archRegDepMap[tid].setCPU(this);
260
261 nonSpecInstActive[tid] = false;
262 nonSpecSeqNum[tid] = 0;
263
264 squashSeqNum[tid] = MaxAddr;
265 lastSquashCycle[tid] = 0;
266
267 memset(intRegs[tid], 0, sizeof(intRegs[tid]));
268 memset(floatRegs.i[tid], 0, sizeof(floatRegs.i[tid]));
269 isa[tid].clear();
270
271 isa[tid].expandForMultithreading(numThreads, numVirtProcs);
272 }
273
274 lastRunningCycle = curTick;
275 contextSwitch = false;
276
277 // Define dummy instructions and resource requests to be used.
278 DynInstPtr dummyBufferInst = new InOrderDynInst(this, NULL, 0, 0);
279 dummyReq = new ResourceRequest(NULL, NULL, 0, 0, 0, 0);
280
281 // Reset CPU to reset state.
282 #if FULL_SYSTEM
283 Fault resetFault = new ResetFault();
284 resetFault->invoke(tcBase());
285 #else
286 reset();
287 #endif
288
289 // Schedule First Tick Event, CPU will reschedule itself from here on out.
290 scheduleTickEvent(0);
291 }
292
293
294 void
295 InOrderCPU::regStats()
296 {
297 /* Register the Resource Pool's stats here.*/
298 resPool->regStats();
299
300 /* Register any of the InOrderCPU's stats here.*/
301 timesIdled
302 .name(name() + ".timesIdled")
303 .desc("Number of times that the entire CPU went into an idle state and"
304 " unscheduled itself")
305 .prereq(timesIdled);
306
307 idleCycles
308 .name(name() + ".idleCycles")
309 .desc("Total number of cycles that the CPU has spent unscheduled due "
310 "to idling")
311 .prereq(idleCycles);
312
313 threadCycles
314 .init(numThreads)
315 .name(name() + ".threadCycles")
316 .desc("Total Number of Cycles A Thread Was Active in CPU (Per-Thread)");
317
318 smtCycles
319 .name(name() + ".smtCycles")
320 .desc("Total number of cycles that the CPU was simultaneous multithreading.(SMT)");
321
322 committedInsts
323 .init(numThreads)
324 .name(name() + ".committedInsts")
325 .desc("Number of Instructions Simulated (Per-Thread)");
326
327 smtCommittedInsts
328 .init(numThreads)
329 .name(name() + ".smtCommittedInsts")
330 .desc("Number of SMT Instructions Simulated (Per-Thread)");
331
332 totalCommittedInsts
333 .name(name() + ".committedInsts_total")
334 .desc("Number of Instructions Simulated (Total)");
335
336 cpi
337 .name(name() + ".cpi")
338 .desc("CPI: Cycles Per Instruction (Per-Thread)")
339 .precision(6);
340 cpi = threadCycles / committedInsts;
341
342 smtCpi
343 .name(name() + ".smt_cpi")
344 .desc("CPI: Total SMT-CPI")
345 .precision(6);
346 smtCpi = smtCycles / smtCommittedInsts;
347
348 totalCpi
349 .name(name() + ".cpi_total")
350 .desc("CPI: Total CPI of All Threads")
351 .precision(6);
352 totalCpi = numCycles / totalCommittedInsts;
353
354 ipc
355 .name(name() + ".ipc")
356 .desc("IPC: Instructions Per Cycle (Per-Thread)")
357 .precision(6);
358 ipc = committedInsts / threadCycles;
359
360 smtIpc
361 .name(name() + ".smt_ipc")
362 .desc("IPC: Total SMT-IPC")
363 .precision(6);
364 smtIpc = smtCommittedInsts / smtCycles;
365
366 totalIpc
367 .name(name() + ".ipc_total")
368 .desc("IPC: Total IPC of All Threads")
369 .precision(6);
370 totalIpc = totalCommittedInsts / numCycles;
371
372 BaseCPU::regStats();
373 }
374
375
376 void
377 InOrderCPU::tick()
378 {
379 DPRINTF(InOrderCPU, "\n\nInOrderCPU: Ticking main, InOrderCPU.\n");
380
381 ++numCycles;
382
383 //Tick each of the stages
384 for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) {
385 pipelineStage[stNum]->tick();
386 }
387
388 // Now advance the time buffers one tick
389 timeBuffer.advance();
390 for (int sqNum=0; sqNum < NumStages - 1; sqNum++) {
391 stageQueue[sqNum]->advance();
392 }
393 activityRec.advance();
394
395 // Any squashed requests, events, or insts then remove them now
396 cleanUpRemovedReqs();
397 cleanUpRemovedEvents();
398 cleanUpRemovedInsts();
399
400 // Re-schedule CPU for this cycle
401 if (!tickEvent.scheduled()) {
402 if (_status == SwitchedOut) {
403 // increment stat
404 lastRunningCycle = curTick;
405 } else if (!activityRec.active()) {
406 DPRINTF(InOrderCPU, "sleeping CPU.\n");
407 lastRunningCycle = curTick;
408 timesIdled++;
409 } else {
410 //Tick next_tick = curTick + cycles(1);
411 //tickEvent.schedule(next_tick);
412 mainEventQueue.schedule(&tickEvent, nextCycle(curTick + 1));
413 DPRINTF(InOrderCPU, "Scheduled CPU for next tick @ %i.\n", nextCycle() + curTick);
414 }
415 }
416
417 tickThreadStats();
418 updateThreadPriority();
419 }
420
421
422 void
423 InOrderCPU::init()
424 {
425 if (!deferRegistration) {
426 registerThreadContexts();
427 }
428
429 // Set inSyscall so that the CPU doesn't squash when initially
430 // setting up registers.
431 for (ThreadID tid = 0; tid < numThreads; ++tid)
432 thread[tid]->inSyscall = true;
433
434 #if FULL_SYSTEM
435 for (ThreadID tid = 0; tid < numThreads; tid++) {
436 ThreadContext *src_tc = threadContexts[tid];
437 TheISA::initCPU(src_tc, src_tc->contextId());
438 }
439 #endif
440
441 // Clear inSyscall.
442 for (ThreadID tid = 0; tid < numThreads; ++tid)
443 thread[tid]->inSyscall = false;
444
445 // Call Initializiation Routine for Resource Pool
446 resPool->init();
447 }
448
449 void
450 InOrderCPU::readFunctional(Addr addr, uint32_t &buffer)
451 {
452 tcBase()->getMemPort()->readBlob(addr, (uint8_t*)&buffer, sizeof(uint32_t));
453 buffer = gtoh(buffer);
454 }
455
456 void
457 InOrderCPU::reset()
458 {
459 for (int i = 0; i < numThreads; i++) {
460 isa[i].reset(coreType, numThreads,
461 numVirtProcs, dynamic_cast<BaseCPU*>(this));
462 }
463 }
464
465 Port*
466 InOrderCPU::getPort(const std::string &if_name, int idx)
467 {
468 return resPool->getPort(if_name, idx);
469 }
470
471 void
472 InOrderCPU::trap(Fault fault, ThreadID tid, int delay)
473 {
474 //@ Squash Pipeline during TRAP
475 scheduleCpuEvent(Trap, fault, tid, 0/*vpe*/, delay);
476 }
477
478 void
479 InOrderCPU::trapCPU(Fault fault, ThreadID tid)
480 {
481 fault->invoke(tcBase(tid));
482 }
483
484 void
485 InOrderCPU::scheduleCpuEvent(CPUEventType c_event, Fault fault,
486 ThreadID tid, unsigned vpe, unsigned delay)
487 {
488 CPUEvent *cpu_event = new CPUEvent(this, c_event, fault, tid, vpe);
489
490 if (delay >= 0) {
491 DPRINTF(InOrderCPU, "Scheduling CPU Event (%s) for cycle %i.\n",
492 eventNames[c_event], curTick + delay);
493 mainEventQueue.schedule(cpu_event,curTick + delay);
494 } else {
495 cpu_event->process();
496 cpuEventRemoveList.push(cpu_event);
497 }
498
499 // Broadcast event to the Resource Pool
500 DynInstPtr dummy_inst =
501 new InOrderDynInst(this, NULL, getNextEventNum(), tid);
502 resPool->scheduleEvent(c_event, dummy_inst, 0, 0, tid);
503 }
504
505 inline bool
506 InOrderCPU::isThreadActive(ThreadID tid)
507 {
508 list<ThreadID>::iterator isActive =
509 std::find(activeThreads.begin(), activeThreads.end(), tid);
510
511 return (isActive != activeThreads.end());
512 }
513
514
515 void
516 InOrderCPU::activateThread(ThreadID tid)
517 {
518 if (!isThreadActive(tid)) {
519 DPRINTF(InOrderCPU,
520 "Adding Thread %i to active threads list in CPU.\n", tid);
521 activeThreads.push_back(tid);
522
523 wakeCPU();
524 }
525 }
526
527 void
528 InOrderCPU::deactivateThread(ThreadID tid)
529 {
530 DPRINTF(InOrderCPU, "[tid:%i]: Calling deactivate thread.\n", tid);
531
532 if (isThreadActive(tid)) {
533 DPRINTF(InOrderCPU,"[tid:%i]: Removing from active threads list\n",
534 tid);
535 list<ThreadID>::iterator thread_it =
536 std::find(activeThreads.begin(), activeThreads.end(), tid);
537
538 removePipelineStalls(*thread_it);
539
540 //@TODO: change stage status' to Idle?
541
542 activeThreads.erase(thread_it);
543 }
544 }
545
546 void
547 InOrderCPU::removePipelineStalls(ThreadID tid)
548 {
549 DPRINTF(InOrderCPU,"[tid:%i]: Removing all pipeline stalls\n",
550 tid);
551
552 for (int stNum = 0; stNum < NumStages ; stNum++) {
553 pipelineStage[stNum]->removeStalls(tid);
554 }
555
556 }
557 bool
558 InOrderCPU::isThreadInCPU(ThreadID tid)
559 {
560 list<ThreadID>::iterator isCurrent =
561 std::find(currentThreads.begin(), currentThreads.end(), tid);
562
563 return (isCurrent != currentThreads.end());
564 }
565
566 void
567 InOrderCPU::addToCurrentThreads(ThreadID tid)
568 {
569 if (!isThreadInCPU(tid)) {
570 DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n",
571 tid);
572 currentThreads.push_back(tid);
573 }
574 }
575
576 void
577 InOrderCPU::removeFromCurrentThreads(ThreadID tid)
578 {
579 if (isThreadInCPU(tid)) {
580 DPRINTF(InOrderCPU,
581 "Adding Thread %i to current threads list in CPU.\n", tid);
582 list<ThreadID>::iterator isCurrent =
583 std::find(currentThreads.begin(), currentThreads.end(), tid);
584 currentThreads.erase(isCurrent);
585 }
586 }
587
588 bool
589 InOrderCPU::isThreadSuspended(ThreadID tid)
590 {
591 list<ThreadID>::iterator isSuspended =
592 std::find(suspendedThreads.begin(), suspendedThreads.end(), tid);
593
594 return (isSuspended!= suspendedThreads.end());
595 }
596
597 void
598 InOrderCPU::enableVirtProcElement(unsigned vpe)
599 {
600 DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling "
601 "Enabling of concurrent virtual processor execution",
602 vpe);
603
604 scheduleCpuEvent(EnableVPEs, NoFault, 0/*tid*/, vpe);
605 }
606
607 void
608 InOrderCPU::enableVPEs(unsigned vpe)
609 {
610 DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Concurrent Execution "
611 "virtual processors %i", vpe);
612
613 list<ThreadID>::iterator thread_it = currentThreads.begin();
614
615 while (thread_it != currentThreads.end()) {
616 if (!isThreadSuspended(*thread_it)) {
617 activateThread(*thread_it);
618 }
619 thread_it++;
620 }
621 }
622
623 void
624 InOrderCPU::disableVirtProcElement(ThreadID tid, unsigned vpe)
625 {
626 DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling "
627 "Disabling of concurrent virtual processor execution",
628 vpe);
629
630 scheduleCpuEvent(DisableVPEs, NoFault, 0/*tid*/, vpe);
631 }
632
633 void
634 InOrderCPU::disableVPEs(ThreadID tid, unsigned vpe)
635 {
636 DPRINTF(InOrderCPU, "[vpe:%i]: Disabling Concurrent Execution of "
637 "virtual processors %i", vpe);
638
639 unsigned base_vpe = TheISA::getVirtProcNum(tcBase(tid));
640
641 list<ThreadID>::iterator thread_it = activeThreads.begin();
642
643 vector<list<ThreadID>::iterator> removeList;
644
645 while (thread_it != activeThreads.end()) {
646 if (base_vpe != vpe) {
647 removeList.push_back(thread_it);
648 }
649 thread_it++;
650 }
651
652 for (int i = 0; i < removeList.size(); i++) {
653 activeThreads.erase(removeList[i]);
654 }
655 }
656
657 void
658 InOrderCPU::enableMultiThreading(unsigned vpe)
659 {
660 // Schedule event to take place at end of cycle
661 DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling Enable Multithreading on "
662 "virtual processor %i", vpe);
663
664 scheduleCpuEvent(EnableThreads, NoFault, 0/*tid*/, vpe);
665 }
666
667 void
668 InOrderCPU::enableThreads(unsigned vpe)
669 {
670 DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Multithreading on "
671 "virtual processor %i", vpe);
672
673 list<ThreadID>::iterator thread_it = currentThreads.begin();
674
675 while (thread_it != currentThreads.end()) {
676 if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) {
677 if (!isThreadSuspended(*thread_it)) {
678 activateThread(*thread_it);
679 }
680 }
681 thread_it++;
682 }
683 }
684 void
685 InOrderCPU::disableMultiThreading(ThreadID tid, unsigned vpe)
686 {
687 // Schedule event to take place at end of cycle
688 DPRINTF(InOrderCPU, "[tid:%i]: Scheduling Disable Multithreading on "
689 "virtual processor %i", tid, vpe);
690
691 scheduleCpuEvent(DisableThreads, NoFault, tid, vpe);
692 }
693
694 void
695 InOrderCPU::disableThreads(ThreadID tid, unsigned vpe)
696 {
697 DPRINTF(InOrderCPU, "[tid:%i]: Disabling Multithreading on "
698 "virtual processor %i", tid, vpe);
699
700 list<ThreadID>::iterator thread_it = activeThreads.begin();
701
702 vector<list<ThreadID>::iterator> removeList;
703
704 while (thread_it != activeThreads.end()) {
705 if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) {
706 removeList.push_back(thread_it);
707 }
708 thread_it++;
709 }
710
711 for (int i = 0; i < removeList.size(); i++) {
712 activeThreads.erase(removeList[i]);
713 }
714 }
715
716 void
717 InOrderCPU::updateThreadPriority()
718 {
719 if (activeThreads.size() > 1)
720 {
721 //DEFAULT TO ROUND ROBIN SCHEME
722 //e.g. Move highest priority to end of thread list
723 list<ThreadID>::iterator list_begin = activeThreads.begin();
724 list<ThreadID>::iterator list_end = activeThreads.end();
725
726 unsigned high_thread = *list_begin;
727
728 activeThreads.erase(list_begin);
729
730 activeThreads.push_back(high_thread);
731 }
732 }
733
734 inline void
735 InOrderCPU::tickThreadStats()
736 {
737 /** Keep track of cycles that each thread is active */
738 list<ThreadID>::iterator thread_it = activeThreads.begin();
739 while (thread_it != activeThreads.end()) {
740 threadCycles[*thread_it]++;
741 thread_it++;
742 }
743
744 // Keep track of cycles where SMT is active
745 if (activeThreads.size() > 1) {
746 smtCycles++;
747 }
748 }
749
750 void
751 InOrderCPU::activateContext(ThreadID tid, int delay)
752 {
753 DPRINTF(InOrderCPU,"[tid:%i]: Activating ...\n", tid);
754
755 scheduleCpuEvent(ActivateThread, NoFault, tid, 0/*vpe*/, delay);
756
757 // Be sure to signal that there's some activity so the CPU doesn't
758 // deschedule itself.
759 activityRec.activity();
760
761 _status = Running;
762 }
763
764
765 void
766 InOrderCPU::suspendContext(ThreadID tid, int delay)
767 {
768 scheduleCpuEvent(SuspendThread, NoFault, tid, 0/*vpe*/, delay);
769 //_status = Idle;
770 }
771
772 void
773 InOrderCPU::suspendThread(ThreadID tid)
774 {
775 DPRINTF(InOrderCPU,"[tid: %i]: Suspended ...\n", tid);
776 deactivateThread(tid);
777 }
778
779 void
780 InOrderCPU::deallocateContext(ThreadID tid, int delay)
781 {
782 scheduleCpuEvent(DeallocateThread, NoFault, tid, 0/*vpe*/, delay);
783 }
784
785 void
786 InOrderCPU::deallocateThread(ThreadID tid)
787 {
788 DPRINTF(InOrderCPU,"[tid:%i]: Deallocating ...", tid);
789
790 removeFromCurrentThreads(tid);
791
792 deactivateThread(tid);
793
794 squashThreadInPipeline(tid);
795 }
796
797 void
798 InOrderCPU::squashThreadInPipeline(ThreadID tid)
799 {
800 //Squash all instructions in each stage
801 for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) {
802 pipelineStage[stNum]->squash(0 /*seq_num*/, tid);
803 }
804 }
805
806 void
807 InOrderCPU::haltContext(ThreadID tid, int delay)
808 {
809 DPRINTF(InOrderCPU, "[tid:%i]: Halt context called.\n", tid);
810
811 // Halt is same thing as deallocate for now
812 // @TODO: Differentiate between halt & deallocate in the CPU
813 // model
814 deallocateContext(tid, delay);
815 }
816
817 void
818 InOrderCPU::insertThread(ThreadID tid)
819 {
820 panic("Unimplemented Function\n.");
821 }
822
823 void
824 InOrderCPU::removeThread(ThreadID tid)
825 {
826 DPRINTF(InOrderCPU, "Removing Thread %i from CPU.\n", tid);
827
828 /** Broadcast to CPU resources*/
829 }
830
831 PipelineStage*
832 InOrderCPU::getPipeStage(int stage_num)
833 {
834 return pipelineStage[stage_num];
835 }
836
837
838 void
839 InOrderCPU::activateWhenReady(ThreadID tid)
840 {
841 panic("Unimplemented Function\n.");
842 }
843
844
845 uint64_t
846 InOrderCPU::readPC(ThreadID tid)
847 {
848 return PC[tid];
849 }
850
851
852 void
853 InOrderCPU::setPC(Addr new_PC, ThreadID tid)
854 {
855 PC[tid] = new_PC;
856 }
857
858
859 uint64_t
860 InOrderCPU::readNextPC(ThreadID tid)
861 {
862 return nextPC[tid];
863 }
864
865
866 void
867 InOrderCPU::setNextPC(uint64_t new_NPC, ThreadID tid)
868 {
869 nextPC[tid] = new_NPC;
870 }
871
872
873 uint64_t
874 InOrderCPU::readNextNPC(ThreadID tid)
875 {
876 return nextNPC[tid];
877 }
878
879
880 void
881 InOrderCPU::setNextNPC(uint64_t new_NNPC, ThreadID tid)
882 {
883 nextNPC[tid] = new_NNPC;
884 }
885
886 uint64_t
887 InOrderCPU::readIntReg(int reg_idx, ThreadID tid)
888 {
889 return intRegs[tid][reg_idx];
890 }
891
892 FloatReg
893 InOrderCPU::readFloatReg(int reg_idx, ThreadID tid)
894 {
895 return floatRegs.f[tid][reg_idx];
896 }
897
898 FloatRegBits
899 InOrderCPU::readFloatRegBits(int reg_idx, ThreadID tid)
900 {;
901 return floatRegs.i[tid][reg_idx];
902 }
903
904 void
905 InOrderCPU::setIntReg(int reg_idx, uint64_t val, ThreadID tid)
906 {
907 intRegs[tid][reg_idx] = val;
908 }
909
910
911 void
912 InOrderCPU::setFloatReg(int reg_idx, FloatReg val, ThreadID tid)
913 {
914 floatRegs.f[tid][reg_idx] = val;
915 }
916
917
918 void
919 InOrderCPU::setFloatRegBits(int reg_idx, FloatRegBits val, ThreadID tid)
920 {
921 floatRegs.i[tid][reg_idx] = val;
922 }
923
924 uint64_t
925 InOrderCPU::readRegOtherThread(unsigned reg_idx, ThreadID tid)
926 {
927 // If Default value is set, then retrieve target thread
928 if (tid == InvalidThreadID) {
929 tid = TheISA::getTargetThread(tcBase(tid));
930 }
931
932 if (reg_idx < FP_Base_DepTag) { // Integer Register File
933 return readIntReg(reg_idx, tid);
934 } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
935 reg_idx -= FP_Base_DepTag;
936 return readFloatRegBits(reg_idx, tid);
937 } else {
938 reg_idx -= Ctrl_Base_DepTag;
939 return readMiscReg(reg_idx, tid); // Misc. Register File
940 }
941 }
942 void
943 InOrderCPU::setRegOtherThread(unsigned reg_idx, const MiscReg &val,
944 ThreadID tid)
945 {
946 // If Default value is set, then retrieve target thread
947 if (tid == InvalidThreadID) {
948 tid = TheISA::getTargetThread(tcBase(tid));
949 }
950
951 if (reg_idx < FP_Base_DepTag) { // Integer Register File
952 setIntReg(reg_idx, val, tid);
953 } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
954 reg_idx -= FP_Base_DepTag;
955 setFloatRegBits(reg_idx, val, tid);
956 } else {
957 reg_idx -= Ctrl_Base_DepTag;
958 setMiscReg(reg_idx, val, tid); // Misc. Register File
959 }
960 }
961
962 MiscReg
963 InOrderCPU::readMiscRegNoEffect(int misc_reg, ThreadID tid)
964 {
965 return isa[tid].readMiscRegNoEffect(misc_reg);
966 }
967
968 MiscReg
969 InOrderCPU::readMiscReg(int misc_reg, ThreadID tid)
970 {
971 return isa[tid].readMiscReg(misc_reg, tcBase(tid));
972 }
973
974 void
975 InOrderCPU::setMiscRegNoEffect(int misc_reg, const MiscReg &val, ThreadID tid)
976 {
977 isa[tid].setMiscRegNoEffect(misc_reg, val);
978 }
979
980 void
981 InOrderCPU::setMiscReg(int misc_reg, const MiscReg &val, ThreadID tid)
982 {
983 isa[tid].setMiscReg(misc_reg, val, tcBase(tid));
984 }
985
986
987 InOrderCPU::ListIt
988 InOrderCPU::addInst(DynInstPtr &inst)
989 {
990 ThreadID tid = inst->readTid();
991
992 instList[tid].push_back(inst);
993
994 return --(instList[tid].end());
995 }
996
997 void
998 InOrderCPU::instDone(DynInstPtr inst, ThreadID tid)
999 {
1000 // Set the CPU's PCs - This contributes to the precise state of the CPU which can be used
1001 // when restoring a thread to the CPU after a fork or after an exception
1002 // @TODO: Set-Up Grad-Info/Committed-Info to let ThreadState know if it's a branch or not
1003 setPC(inst->readPC(), tid);
1004 setNextPC(inst->readNextPC(), tid);
1005 setNextNPC(inst->readNextNPC(), tid);
1006
1007 // Finalize Trace Data For Instruction
1008 if (inst->traceData) {
1009 //inst->traceData->setCycle(curTick);
1010 inst->traceData->setFetchSeq(inst->seqNum);
1011 //inst->traceData->setCPSeq(cpu->tcBase(tid)->numInst);
1012 inst->traceData->dump();
1013 delete inst->traceData;
1014 inst->traceData = NULL;
1015 }
1016
1017 // Set Last Graduated Instruction In Thread State
1018 //thread[tid]->lastGradInst = inst;
1019
1020 // Increment thread-state's instruction count
1021 thread[tid]->numInst++;
1022
1023 // Increment thread-state's instruction stats
1024 thread[tid]->numInsts++;
1025
1026 // Count committed insts per thread stats
1027 committedInsts[tid]++;
1028
1029 // Count total insts committed stat
1030 totalCommittedInsts++;
1031
1032 // Count SMT-committed insts per thread stat
1033 if (numActiveThreads() > 1) {
1034 smtCommittedInsts[tid]++;
1035 }
1036
1037 // Check for instruction-count-based events.
1038 comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
1039
1040 // Broadcast to other resources an instruction
1041 // has been completed
1042 resPool->scheduleEvent((CPUEventType)ResourcePool::InstGraduated, inst, tid);
1043
1044 // Finally, remove instruction from CPU
1045 removeInst(inst);
1046 }
1047
1048 void
1049 InOrderCPU::addToRemoveList(DynInstPtr &inst)
1050 {
1051 removeInstsThisCycle = true;
1052
1053 removeList.push(inst->getInstListIt());
1054 }
1055
1056 void
1057 InOrderCPU::removeInst(DynInstPtr &inst)
1058 {
1059 DPRINTF(InOrderCPU, "Removing graduated instruction [tid:%i] PC %#x "
1060 "[sn:%lli]\n",
1061 inst->threadNumber, inst->readPC(), inst->seqNum);
1062
1063 removeInstsThisCycle = true;
1064
1065 // Remove the instruction.
1066 removeList.push(inst->getInstListIt());
1067 }
1068
1069 void
1070 InOrderCPU::removeInstsUntil(const InstSeqNum &seq_num, ThreadID tid)
1071 {
1072 //assert(!instList[tid].empty());
1073
1074 removeInstsThisCycle = true;
1075
1076 ListIt inst_iter = instList[tid].end();
1077
1078 inst_iter--;
1079
1080 DPRINTF(InOrderCPU, "Deleting instructions from CPU instruction "
1081 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1082 tid, seq_num, (*inst_iter)->seqNum);
1083
1084 while ((*inst_iter)->seqNum > seq_num) {
1085
1086 bool break_loop = (inst_iter == instList[tid].begin());
1087
1088 squashInstIt(inst_iter, tid);
1089
1090 inst_iter--;
1091
1092 if (break_loop)
1093 break;
1094 }
1095 }
1096
1097
1098 inline void
1099 InOrderCPU::squashInstIt(const ListIt &instIt, ThreadID tid)
1100 {
1101 if ((*instIt)->threadNumber == tid) {
1102 DPRINTF(InOrderCPU, "Squashing instruction, "
1103 "[tid:%i] [sn:%lli] PC %#x\n",
1104 (*instIt)->threadNumber,
1105 (*instIt)->seqNum,
1106 (*instIt)->readPC());
1107
1108 (*instIt)->setSquashed();
1109
1110 removeList.push(instIt);
1111 }
1112 }
1113
1114
1115 void
1116 InOrderCPU::cleanUpRemovedInsts()
1117 {
1118 while (!removeList.empty()) {
1119 DPRINTF(InOrderCPU, "Removing instruction, "
1120 "[tid:%i] [sn:%lli] PC %#x\n",
1121 (*removeList.front())->threadNumber,
1122 (*removeList.front())->seqNum,
1123 (*removeList.front())->readPC());
1124
1125 DynInstPtr inst = *removeList.front();
1126 ThreadID tid = inst->threadNumber;
1127
1128 // Make Sure Resource Schedule Is Emptied Out
1129 ThePipeline::ResSchedule *inst_sched = &inst->resSched;
1130 while (!inst_sched->empty()) {
1131 ThePipeline::ScheduleEntry* sch_entry = inst_sched->top();
1132 inst_sched->pop();
1133 delete sch_entry;
1134 }
1135
1136 // Remove From Register Dependency Map, If Necessary
1137 archRegDepMap[(*removeList.front())->threadNumber].
1138 remove((*removeList.front()));
1139
1140
1141 // Clear if Non-Speculative
1142 if (inst->staticInst &&
1143 inst->seqNum == nonSpecSeqNum[tid] &&
1144 nonSpecInstActive[tid] == true) {
1145 nonSpecInstActive[tid] = false;
1146 }
1147
1148 instList[tid].erase(removeList.front());
1149
1150 removeList.pop();
1151
1152 DPRINTF(RefCount, "pop from remove list: [sn:%i]: Refcount = %i.\n",
1153 inst->seqNum,
1154 0/*inst->curCount()*/);
1155
1156 }
1157
1158 removeInstsThisCycle = false;
1159 }
1160
1161 void
1162 InOrderCPU::cleanUpRemovedReqs()
1163 {
1164 while (!reqRemoveList.empty()) {
1165 ResourceRequest *res_req = reqRemoveList.front();
1166
1167 DPRINTF(RefCount, "[tid:%i]: Removing Request, "
1168 "[sn:%lli] [slot:%i] [stage_num:%i] [res:%s] [refcount:%i].\n",
1169 res_req->inst->threadNumber,
1170 res_req->inst->seqNum,
1171 res_req->getSlot(),
1172 res_req->getStageNum(),
1173 res_req->res->name(),
1174 0/*res_req->inst->curCount()*/);
1175
1176 reqRemoveList.pop();
1177
1178 delete res_req;
1179
1180 DPRINTF(RefCount, "after remove request: [sn:%i]: Refcount = %i.\n",
1181 res_req->inst->seqNum,
1182 0/*res_req->inst->curCount()*/);
1183 }
1184 }
1185
1186 void
1187 InOrderCPU::cleanUpRemovedEvents()
1188 {
1189 while (!cpuEventRemoveList.empty()) {
1190 Event *cpu_event = cpuEventRemoveList.front();
1191 cpuEventRemoveList.pop();
1192 delete cpu_event;
1193 }
1194 }
1195
1196
1197 void
1198 InOrderCPU::dumpInsts()
1199 {
1200 int num = 0;
1201
1202 ListIt inst_list_it = instList[0].begin();
1203
1204 cprintf("Dumping Instruction List\n");
1205
1206 while (inst_list_it != instList[0].end()) {
1207 cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1208 "Squashed:%i\n\n",
1209 num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber,
1210 (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
1211 (*inst_list_it)->isSquashed());
1212 inst_list_it++;
1213 ++num;
1214 }
1215 }
1216
1217 void
1218 InOrderCPU::wakeCPU()
1219 {
1220 if (/*activityRec.active() || */tickEvent.scheduled()) {
1221 DPRINTF(Activity, "CPU already running.\n");
1222 return;
1223 }
1224
1225 DPRINTF(Activity, "Waking up CPU\n");
1226
1227 //@todo: figure out how to count idleCycles correctly
1228 //idleCycles += (curTick - 1) - lastRunningCycle;
1229
1230 mainEventQueue.schedule(&tickEvent, curTick);
1231 }
1232
1233 void
1234 InOrderCPU::syscall(int64_t callnum, ThreadID tid)
1235 {
1236 DPRINTF(InOrderCPU, "[tid:%i] Executing syscall().\n\n", tid);
1237
1238 DPRINTF(Activity,"Activity: syscall() called.\n");
1239
1240 // Temporarily increase this by one to account for the syscall
1241 // instruction.
1242 ++(this->thread[tid]->funcExeInst);
1243
1244 // Execute the actual syscall.
1245 this->thread[tid]->syscall(callnum);
1246
1247 // Decrease funcExeInst by one as the normal commit will handle
1248 // incrementing it.
1249 --(this->thread[tid]->funcExeInst);
1250
1251 // Clear Non-Speculative Block Variable
1252 nonSpecInstActive[tid] = false;
1253 }
1254
1255 void
1256 InOrderCPU::prefetch(DynInstPtr inst)
1257 {
1258 Resource *mem_res = resPool->getResource(dataPortIdx);
1259 return mem_res->prefetch(inst);
1260 }
1261
1262 void
1263 InOrderCPU::writeHint(DynInstPtr inst)
1264 {
1265 Resource *mem_res = resPool->getResource(dataPortIdx);
1266 return mem_res->writeHint(inst);
1267 }
1268
1269
1270 TheISA::TLB*
1271 InOrderCPU::getITBPtr()
1272 {
1273 CacheUnit *itb_res =
1274 dynamic_cast<CacheUnit*>(resPool->getResource(fetchPortIdx));
1275 return itb_res->tlb();
1276 }
1277
1278
1279 TheISA::TLB*
1280 InOrderCPU::getDTBPtr()
1281 {
1282 CacheUnit *dtb_res =
1283 dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
1284 return dtb_res->tlb();
1285 }
1286
1287 template <class T>
1288 Fault
1289 InOrderCPU::read(DynInstPtr inst, Addr addr, T &data, unsigned flags)
1290 {
1291 //@TODO: Generalize name "CacheUnit" to "MemUnit" just in case
1292 // you want to run w/out caches?
1293 CacheUnit *cache_res = dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
1294
1295 return cache_res->read(inst, addr, data, flags);
1296 }
1297
1298 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1299
1300 template
1301 Fault
1302 InOrderCPU::read(DynInstPtr inst, Addr addr, Twin32_t &data, unsigned flags);
1303
1304 template
1305 Fault
1306 InOrderCPU::read(DynInstPtr inst, Addr addr, Twin64_t &data, unsigned flags);
1307
1308 template
1309 Fault
1310 InOrderCPU::read(DynInstPtr inst, Addr addr, uint64_t &data, unsigned flags);
1311
1312 template
1313 Fault
1314 InOrderCPU::read(DynInstPtr inst, Addr addr, uint32_t &data, unsigned flags);
1315
1316 template
1317 Fault
1318 InOrderCPU::read(DynInstPtr inst, Addr addr, uint16_t &data, unsigned flags);
1319
1320 template
1321 Fault
1322 InOrderCPU::read(DynInstPtr inst, Addr addr, uint8_t &data, unsigned flags);
1323
1324 #endif //DOXYGEN_SHOULD_SKIP_THIS
1325
1326 template<>
1327 Fault
1328 InOrderCPU::read(DynInstPtr inst, Addr addr, double &data, unsigned flags)
1329 {
1330 return read(inst, addr, *(uint64_t*)&data, flags);
1331 }
1332
1333 template<>
1334 Fault
1335 InOrderCPU::read(DynInstPtr inst, Addr addr, float &data, unsigned flags)
1336 {
1337 return read(inst, addr, *(uint32_t*)&data, flags);
1338 }
1339
1340
1341 template<>
1342 Fault
1343 InOrderCPU::read(DynInstPtr inst, Addr addr, int32_t &data, unsigned flags)
1344 {
1345 return read(inst, addr, (uint32_t&)data, flags);
1346 }
1347
1348 template <class T>
1349 Fault
1350 InOrderCPU::write(DynInstPtr inst, T data, Addr addr, unsigned flags,
1351 uint64_t *write_res)
1352 {
1353 //@TODO: Generalize name "CacheUnit" to "MemUnit" just in case
1354 // you want to run w/out caches?
1355 CacheUnit *cache_res =
1356 dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
1357 return cache_res->write(inst, data, addr, flags, write_res);
1358 }
1359
1360 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1361
1362 template
1363 Fault
1364 InOrderCPU::write(DynInstPtr inst, Twin32_t data, Addr addr,
1365 unsigned flags, uint64_t *res);
1366
1367 template
1368 Fault
1369 InOrderCPU::write(DynInstPtr inst, Twin64_t data, Addr addr,
1370 unsigned flags, uint64_t *res);
1371
1372 template
1373 Fault
1374 InOrderCPU::write(DynInstPtr inst, uint64_t data, Addr addr,
1375 unsigned flags, uint64_t *res);
1376
1377 template
1378 Fault
1379 InOrderCPU::write(DynInstPtr inst, uint32_t data, Addr addr,
1380 unsigned flags, uint64_t *res);
1381
1382 template
1383 Fault
1384 InOrderCPU::write(DynInstPtr inst, uint16_t data, Addr addr,
1385 unsigned flags, uint64_t *res);
1386
1387 template
1388 Fault
1389 InOrderCPU::write(DynInstPtr inst, uint8_t data, Addr addr,
1390 unsigned flags, uint64_t *res);
1391
1392 #endif //DOXYGEN_SHOULD_SKIP_THIS
1393
1394 template<>
1395 Fault
1396 InOrderCPU::write(DynInstPtr inst, double data, Addr addr, unsigned flags, uint64_t *res)
1397 {
1398 return write(inst, *(uint64_t*)&data, addr, flags, res);
1399 }
1400
1401 template<>
1402 Fault
1403 InOrderCPU::write(DynInstPtr inst, float data, Addr addr, unsigned flags, uint64_t *res)
1404 {
1405 return write(inst, *(uint32_t*)&data, addr, flags, res);
1406 }
1407
1408
1409 template<>
1410 Fault
1411 InOrderCPU::write(DynInstPtr inst, int32_t data, Addr addr, unsigned flags, uint64_t *res)
1412 {
1413 return write(inst, (uint32_t)data, addr, flags, res);
1414 }