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