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