Yet another merge with the main repository.
[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 "base/bigint.hh"
36 #include "config/the_isa.hh"
37 #include "cpu/inorder/resources/resource_list.hh"
38 #include "cpu/inorder/cpu.hh"
39 #include "cpu/inorder/first_stage.hh"
40 #include "cpu/inorder/inorder_dyn_inst.hh"
41 #include "cpu/inorder/pipeline_traits.hh"
42 #include "cpu/inorder/resource_pool.hh"
43 #include "cpu/inorder/thread_context.hh"
44 #include "cpu/inorder/thread_state.hh"
45 #include "cpu/activity.hh"
46 #include "cpu/base.hh"
47 #include "cpu/exetrace.hh"
48 #include "cpu/quiesce_event.hh"
49 #include "cpu/simple_thread.hh"
50 #include "cpu/thread_context.hh"
51 #include "debug/Activity.hh"
52 #include "debug/InOrderCPU.hh"
53 #include "debug/Interrupt.hh"
54 #include "debug/RefCount.hh"
55 #include "debug/SkedCache.hh"
56 #include "debug/Quiesce.hh"
57 #include "params/InOrderCPU.hh"
58 #include "sim/full_system.hh"
59 #include "sim/process.hh"
60 #include "sim/stat_control.hh"
61 #include "sim/system.hh"
62
63 #if THE_ISA == ALPHA_ISA
64 #include "arch/alpha/osfpal.hh"
65 #endif
66
67 using namespace std;
68 using namespace TheISA;
69 using namespace ThePipeline;
70
71 InOrderCPU::TickEvent::TickEvent(InOrderCPU *c)
72 : Event(CPU_Tick_Pri), cpu(c)
73 { }
74
75
76 void
77 InOrderCPU::TickEvent::process()
78 {
79 cpu->tick();
80 }
81
82
83 const char *
84 InOrderCPU::TickEvent::description()
85 {
86 return "InOrderCPU tick event";
87 }
88
89 InOrderCPU::CPUEvent::CPUEvent(InOrderCPU *_cpu, CPUEventType e_type,
90 Fault fault, ThreadID _tid, DynInstPtr inst,
91 CPUEventPri event_pri)
92 : Event(event_pri), cpu(_cpu)
93 {
94 setEvent(e_type, fault, _tid, inst);
95 }
96
97
98 std::string InOrderCPU::eventNames[NumCPUEvents] =
99 {
100 "ActivateThread",
101 "ActivateNextReadyThread",
102 "DeactivateThread",
103 "HaltThread",
104 "SuspendThread",
105 "Trap",
106 "Syscall",
107 "SquashFromMemStall",
108 "UpdatePCs"
109 };
110
111 void
112 InOrderCPU::CPUEvent::process()
113 {
114 switch (cpuEventType)
115 {
116 case ActivateThread:
117 cpu->activateThread(tid);
118 cpu->resPool->activateThread(tid);
119 break;
120
121 case ActivateNextReadyThread:
122 cpu->activateNextReadyThread();
123 break;
124
125 case DeactivateThread:
126 cpu->deactivateThread(tid);
127 cpu->resPool->deactivateThread(tid);
128 break;
129
130 case HaltThread:
131 cpu->haltThread(tid);
132 cpu->resPool->deactivateThread(tid);
133 break;
134
135 case SuspendThread:
136 cpu->suspendThread(tid);
137 cpu->resPool->suspendThread(tid);
138 break;
139
140 case SquashFromMemStall:
141 cpu->squashDueToMemStall(inst->squashingStage, inst->seqNum, tid);
142 cpu->resPool->squashDueToMemStall(inst, inst->squashingStage,
143 inst->seqNum, tid);
144 break;
145
146 case Trap:
147 DPRINTF(InOrderCPU, "Trapping CPU\n");
148 cpu->trap(fault, tid, inst);
149 cpu->resPool->trap(fault, tid, inst);
150 cpu->trapPending[tid] = false;
151 break;
152
153 case Syscall:
154 cpu->syscall(inst->syscallNum, tid);
155 cpu->resPool->trap(fault, tid, inst);
156 break;
157
158 default:
159 fatal("Unrecognized Event Type %s", eventNames[cpuEventType]);
160 }
161
162 cpu->cpuEventRemoveList.push(this);
163 }
164
165
166
167 const char *
168 InOrderCPU::CPUEvent::description()
169 {
170 return "InOrderCPU event";
171 }
172
173 void
174 InOrderCPU::CPUEvent::scheduleEvent(int delay)
175 {
176 assert(!scheduled() || squashed());
177 cpu->reschedule(this, cpu->nextCycle(curTick() + cpu->ticks(delay)), true);
178 }
179
180 void
181 InOrderCPU::CPUEvent::unscheduleEvent()
182 {
183 if (scheduled())
184 squash();
185 }
186
187 InOrderCPU::InOrderCPU(Params *params)
188 : BaseCPU(params),
189 cpu_id(params->cpu_id),
190 coreType("default"),
191 _status(Idle),
192 tickEvent(this),
193 stageWidth(params->stageWidth),
194 timeBuffer(2 , 2),
195 removeInstsThisCycle(false),
196 activityRec(params->name, NumStages, 10, params->activity),
197 system(params->system),
198 #ifdef DEBUG
199 cpuEventNum(0),
200 resReqCount(0),
201 #endif // DEBUG
202 drainCount(0),
203 deferRegistration(false/*params->deferRegistration*/),
204 stageTracing(params->stageTracing),
205 lastRunningCycle(0),
206 instsPerSwitch(0)
207 {
208 cpu_params = params;
209
210 resPool = new ResourcePool(this, params);
211
212 // Resize for Multithreading CPUs
213 thread.resize(numThreads);
214
215 ThreadID active_threads = params->workload.size();
216 if (FullSystem) {
217 active_threads = 1;
218 } else {
219 active_threads = params->workload.size();
220
221 if (active_threads > MaxThreads) {
222 panic("Workload Size too large. Increase the 'MaxThreads'"
223 "in your InOrder implementation or "
224 "edit your workload size.");
225 }
226
227
228 if (active_threads > 1) {
229 threadModel = (InOrderCPU::ThreadModel) params->threadModel;
230
231 if (threadModel == SMT) {
232 DPRINTF(InOrderCPU, "Setting Thread Model to SMT.\n");
233 } else if (threadModel == SwitchOnCacheMiss) {
234 DPRINTF(InOrderCPU, "Setting Thread Model to "
235 "Switch On Cache Miss\n");
236 }
237
238 } else {
239 threadModel = Single;
240 }
241 }
242
243 // Bind the fetch & data ports from the resource pool.
244 fetchPortIdx = resPool->getPortIdx(params->fetchMemPort);
245 if (fetchPortIdx == 0) {
246 fatal("Unable to find port to fetch instructions from.\n");
247 }
248
249 dataPortIdx = resPool->getPortIdx(params->dataMemPort);
250 if (dataPortIdx == 0) {
251 fatal("Unable to find port for data.\n");
252 }
253
254 for (ThreadID tid = 0; tid < numThreads; ++tid) {
255 pc[tid].set(0);
256 lastCommittedPC[tid].set(0);
257
258 if (FullSystem) {
259 // SMT is not supported in FS mode yet.
260 assert(numThreads == 1);
261 thread[tid] = new Thread(this, 0, NULL);
262 } else {
263 if (tid < (ThreadID)params->workload.size()) {
264 DPRINTF(InOrderCPU, "Workload[%i] process is %#x\n",
265 tid, params->workload[tid]->prog_fname);
266 thread[tid] =
267 new Thread(this, tid, params->workload[tid]);
268 } else {
269 //Allocate Empty thread so M5 can use later
270 //when scheduling threads to CPU
271 Process* dummy_proc = params->workload[0];
272 thread[tid] = new Thread(this, tid, dummy_proc);
273 }
274
275 // Eventually set this with parameters...
276 asid[tid] = tid;
277 }
278
279 // Setup the TC that will serve as the interface to the threads/CPU.
280 InOrderThreadContext *tc = new InOrderThreadContext;
281 tc->cpu = this;
282 tc->thread = thread[tid];
283
284 // Setup quiesce event.
285 this->thread[tid]->quiesceEvent = new EndQuiesceEvent(tc);
286
287 // Give the thread the TC.
288 thread[tid]->tc = tc;
289 thread[tid]->setFuncExeInst(0);
290 globalSeqNum[tid] = 1;
291
292 // Add the TC to the CPU's list of TC's.
293 this->threadContexts.push_back(tc);
294 }
295
296 // Initialize TimeBuffer Stage Queues
297 for (int stNum=0; stNum < NumStages - 1; stNum++) {
298 stageQueue[stNum] = new StageQueue(NumStages, NumStages);
299 stageQueue[stNum]->id(stNum);
300 }
301
302
303 // Set Up Pipeline Stages
304 for (int stNum=0; stNum < NumStages; stNum++) {
305 if (stNum == 0)
306 pipelineStage[stNum] = new FirstStage(params, stNum);
307 else
308 pipelineStage[stNum] = new PipelineStage(params, stNum);
309
310 pipelineStage[stNum]->setCPU(this);
311 pipelineStage[stNum]->setActiveThreads(&activeThreads);
312 pipelineStage[stNum]->setTimeBuffer(&timeBuffer);
313
314 // Take Care of 1st/Nth stages
315 if (stNum > 0)
316 pipelineStage[stNum]->setPrevStageQueue(stageQueue[stNum - 1]);
317 if (stNum < NumStages - 1)
318 pipelineStage[stNum]->setNextStageQueue(stageQueue[stNum]);
319 }
320
321 // Initialize thread specific variables
322 for (ThreadID tid = 0; tid < numThreads; tid++) {
323 archRegDepMap[tid].setCPU(this);
324
325 nonSpecInstActive[tid] = false;
326 nonSpecSeqNum[tid] = 0;
327
328 squashSeqNum[tid] = MaxAddr;
329 lastSquashCycle[tid] = 0;
330
331 memset(intRegs[tid], 0, sizeof(intRegs[tid]));
332 memset(floatRegs.i[tid], 0, sizeof(floatRegs.i[tid]));
333 isa[tid].clear();
334
335 // Define dummy instructions and resource requests to be used.
336 dummyInst[tid] = new InOrderDynInst(this,
337 thread[tid],
338 0,
339 tid,
340 asid[tid]);
341
342 dummyReq[tid] = new ResourceRequest(resPool->getResource(0));
343
344
345 if (FullSystem) {
346 // Use this dummy inst to force squashing behind every instruction
347 // in pipeline
348 dummyTrapInst[tid] = new InOrderDynInst(this, NULL, 0, 0, 0);
349 dummyTrapInst[tid]->seqNum = 0;
350 dummyTrapInst[tid]->squashSeqNum = 0;
351 dummyTrapInst[tid]->setTid(tid);
352 }
353
354 trapPending[tid] = false;
355
356 }
357
358 dummyReqInst = new InOrderDynInst(this, NULL, 0, 0, 0);
359 dummyReqInst->setSquashed();
360 dummyReqInst->resetInstCount();
361
362 dummyBufferInst = new InOrderDynInst(this, NULL, 0, 0, 0);
363 dummyBufferInst->setSquashed();
364 dummyBufferInst->resetInstCount();
365
366 endOfSkedIt = skedCache.end();
367 frontEndSked = createFrontEndSked();
368 faultSked = createFaultSked();
369
370 lastRunningCycle = curTick();
371
372 lockAddr = 0;
373 lockFlag = false;
374
375 // Schedule First Tick Event, CPU will reschedule itself from here on out.
376 scheduleTickEvent(0);
377 }
378
379 InOrderCPU::~InOrderCPU()
380 {
381 delete resPool;
382
383 SkedCacheIt sked_it = skedCache.begin();
384 SkedCacheIt sked_end = skedCache.end();
385
386 while (sked_it != sked_end) {
387 delete (*sked_it).second;
388 sked_it++;
389 }
390 skedCache.clear();
391 }
392
393 m5::hash_map<InOrderCPU::SkedID, ThePipeline::RSkedPtr> InOrderCPU::skedCache;
394
395 RSkedPtr
396 InOrderCPU::createFrontEndSked()
397 {
398 RSkedPtr res_sked = new ResourceSked();
399 int stage_num = 0;
400 StageScheduler F(res_sked, stage_num++);
401 StageScheduler D(res_sked, stage_num++);
402
403 // FETCH
404 F.needs(FetchSeq, FetchSeqUnit::AssignNextPC);
405 F.needs(ICache, FetchUnit::InitiateFetch);
406
407 // DECODE
408 D.needs(ICache, FetchUnit::CompleteFetch);
409 D.needs(Decode, DecodeUnit::DecodeInst);
410 D.needs(BPred, BranchPredictor::PredictBranch);
411 D.needs(FetchSeq, FetchSeqUnit::UpdateTargetPC);
412
413
414 DPRINTF(SkedCache, "Resource Sked created for instruction Front End\n");
415
416 return res_sked;
417 }
418
419 RSkedPtr
420 InOrderCPU::createFaultSked()
421 {
422 RSkedPtr res_sked = new ResourceSked();
423 StageScheduler W(res_sked, NumStages - 1);
424 W.needs(Grad, GraduationUnit::CheckFault);
425 DPRINTF(SkedCache, "Resource Sked created for instruction Faults\n");
426 return res_sked;
427 }
428
429 RSkedPtr
430 InOrderCPU::createBackEndSked(DynInstPtr inst)
431 {
432 RSkedPtr res_sked = lookupSked(inst);
433 if (res_sked != NULL) {
434 DPRINTF(SkedCache, "Found %s in sked cache.\n",
435 inst->instName());
436 return res_sked;
437 } else {
438 res_sked = new ResourceSked();
439 }
440
441 int stage_num = ThePipeline::BackEndStartStage;
442 StageScheduler X(res_sked, stage_num++);
443 StageScheduler M(res_sked, stage_num++);
444 StageScheduler W(res_sked, stage_num++);
445
446 if (!inst->staticInst) {
447 warn_once("Static Instruction Object Not Set. Can't Create"
448 " Back End Schedule");
449 return NULL;
450 }
451
452 // EXECUTE
453 X.needs(RegManager, UseDefUnit::MarkDestRegs);
454 for (int idx=0; idx < inst->numSrcRegs(); idx++) {
455 if (!idx || !inst->isStore()) {
456 X.needs(RegManager, UseDefUnit::ReadSrcReg, idx);
457 }
458 }
459
460 //@todo: schedule non-spec insts to operate on this cycle
461 // as long as all previous insts are done
462 if ( inst->isNonSpeculative() ) {
463 // skip execution of non speculative insts until later
464 } else if ( inst->isMemRef() ) {
465 if ( inst->isLoad() ) {
466 X.needs(AGEN, AGENUnit::GenerateAddr);
467 }
468 } else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
469 X.needs(MDU, MultDivUnit::StartMultDiv);
470 } else {
471 X.needs(ExecUnit, ExecutionUnit::ExecuteInst);
472 }
473
474 // MEMORY
475 if (!inst->isNonSpeculative()) {
476 if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
477 M.needs(MDU, MultDivUnit::EndMultDiv);
478 }
479
480 if ( inst->isLoad() ) {
481 M.needs(DCache, CacheUnit::InitiateReadData);
482 if (inst->splitInst)
483 M.needs(DCache, CacheUnit::InitSecondSplitRead);
484 } else if ( inst->isStore() ) {
485 for (int i = 1; i < inst->numSrcRegs(); i++ ) {
486 M.needs(RegManager, UseDefUnit::ReadSrcReg, i);
487 }
488 M.needs(AGEN, AGENUnit::GenerateAddr);
489 M.needs(DCache, CacheUnit::InitiateWriteData);
490 if (inst->splitInst)
491 M.needs(DCache, CacheUnit::InitSecondSplitWrite);
492 }
493 }
494
495 // WRITEBACK
496 if (!inst->isNonSpeculative()) {
497 if ( inst->isLoad() ) {
498 W.needs(DCache, CacheUnit::CompleteReadData);
499 if (inst->splitInst)
500 W.needs(DCache, CacheUnit::CompleteSecondSplitRead);
501 } else if ( inst->isStore() ) {
502 W.needs(DCache, CacheUnit::CompleteWriteData);
503 if (inst->splitInst)
504 W.needs(DCache, CacheUnit::CompleteSecondSplitWrite);
505 }
506 } else {
507 // Finally, Execute Speculative Data
508 if (inst->isMemRef()) {
509 if (inst->isLoad()) {
510 W.needs(AGEN, AGENUnit::GenerateAddr);
511 W.needs(DCache, CacheUnit::InitiateReadData);
512 if (inst->splitInst)
513 W.needs(DCache, CacheUnit::InitSecondSplitRead);
514 W.needs(DCache, CacheUnit::CompleteReadData);
515 if (inst->splitInst)
516 W.needs(DCache, CacheUnit::CompleteSecondSplitRead);
517 } else if (inst->isStore()) {
518 if ( inst->numSrcRegs() >= 2 ) {
519 W.needs(RegManager, UseDefUnit::ReadSrcReg, 1);
520 }
521 W.needs(AGEN, AGENUnit::GenerateAddr);
522 W.needs(DCache, CacheUnit::InitiateWriteData);
523 if (inst->splitInst)
524 W.needs(DCache, CacheUnit::InitSecondSplitWrite);
525 W.needs(DCache, CacheUnit::CompleteWriteData);
526 if (inst->splitInst)
527 W.needs(DCache, CacheUnit::CompleteSecondSplitWrite);
528 }
529 } else {
530 W.needs(ExecUnit, ExecutionUnit::ExecuteInst);
531 }
532 }
533
534 W.needs(Grad, GraduationUnit::CheckFault);
535
536 for (int idx=0; idx < inst->numDestRegs(); idx++) {
537 W.needs(RegManager, UseDefUnit::WriteDestReg, idx);
538 }
539
540 if (inst->isControl())
541 W.needs(BPred, BranchPredictor::UpdatePredictor);
542
543 W.needs(Grad, GraduationUnit::GraduateInst);
544
545 // Insert Back Schedule into our cache of
546 // resource schedules
547 addToSkedCache(inst, res_sked);
548
549 DPRINTF(SkedCache, "Back End Sked Created for instruction: %s (%08p)\n",
550 inst->instName(), inst->getMachInst());
551 res_sked->print();
552
553 return res_sked;
554 }
555
556 void
557 InOrderCPU::regStats()
558 {
559 /* Register the Resource Pool's stats here.*/
560 resPool->regStats();
561
562 /* Register for each Pipeline Stage */
563 for (int stage_num=0; stage_num < ThePipeline::NumStages; stage_num++) {
564 pipelineStage[stage_num]->regStats();
565 }
566
567 /* Register any of the InOrderCPU's stats here.*/
568 instsPerCtxtSwitch
569 .name(name() + ".instsPerContextSwitch")
570 .desc("Instructions Committed Per Context Switch")
571 .prereq(instsPerCtxtSwitch);
572
573 numCtxtSwitches
574 .name(name() + ".contextSwitches")
575 .desc("Number of context switches");
576
577 comLoads
578 .name(name() + ".comLoads")
579 .desc("Number of Load instructions committed");
580
581 comStores
582 .name(name() + ".comStores")
583 .desc("Number of Store instructions committed");
584
585 comBranches
586 .name(name() + ".comBranches")
587 .desc("Number of Branches instructions committed");
588
589 comNops
590 .name(name() + ".comNops")
591 .desc("Number of Nop instructions committed");
592
593 comNonSpec
594 .name(name() + ".comNonSpec")
595 .desc("Number of Non-Speculative instructions committed");
596
597 comInts
598 .name(name() + ".comInts")
599 .desc("Number of Integer instructions committed");
600
601 comFloats
602 .name(name() + ".comFloats")
603 .desc("Number of Floating Point instructions committed");
604
605 timesIdled
606 .name(name() + ".timesIdled")
607 .desc("Number of times that the entire CPU went into an idle state and"
608 " unscheduled itself")
609 .prereq(timesIdled);
610
611 idleCycles
612 .name(name() + ".idleCycles")
613 .desc("Number of cycles cpu's stages were not processed");
614
615 runCycles
616 .name(name() + ".runCycles")
617 .desc("Number of cycles cpu stages are processed.");
618
619 activity
620 .name(name() + ".activity")
621 .desc("Percentage of cycles cpu is active")
622 .precision(6);
623 activity = (runCycles / numCycles) * 100;
624
625 threadCycles
626 .init(numThreads)
627 .name(name() + ".threadCycles")
628 .desc("Total Number of Cycles A Thread Was Active in CPU (Per-Thread)");
629
630 smtCycles
631 .name(name() + ".smtCycles")
632 .desc("Total number of cycles that the CPU was in SMT-mode");
633
634 committedInsts
635 .init(numThreads)
636 .name(name() + ".committedInsts")
637 .desc("Number of Instructions Simulated (Per-Thread)");
638
639 smtCommittedInsts
640 .init(numThreads)
641 .name(name() + ".smtCommittedInsts")
642 .desc("Number of SMT Instructions Simulated (Per-Thread)");
643
644 totalCommittedInsts
645 .name(name() + ".committedInsts_total")
646 .desc("Number of Instructions Simulated (Total)");
647
648 cpi
649 .name(name() + ".cpi")
650 .desc("CPI: Cycles Per Instruction (Per-Thread)")
651 .precision(6);
652 cpi = numCycles / committedInsts;
653
654 smtCpi
655 .name(name() + ".smt_cpi")
656 .desc("CPI: Total SMT-CPI")
657 .precision(6);
658 smtCpi = smtCycles / smtCommittedInsts;
659
660 totalCpi
661 .name(name() + ".cpi_total")
662 .desc("CPI: Total CPI of All Threads")
663 .precision(6);
664 totalCpi = numCycles / totalCommittedInsts;
665
666 ipc
667 .name(name() + ".ipc")
668 .desc("IPC: Instructions Per Cycle (Per-Thread)")
669 .precision(6);
670 ipc = committedInsts / numCycles;
671
672 smtIpc
673 .name(name() + ".smt_ipc")
674 .desc("IPC: Total SMT-IPC")
675 .precision(6);
676 smtIpc = smtCommittedInsts / smtCycles;
677
678 totalIpc
679 .name(name() + ".ipc_total")
680 .desc("IPC: Total IPC of All Threads")
681 .precision(6);
682 totalIpc = totalCommittedInsts / numCycles;
683
684 BaseCPU::regStats();
685 }
686
687
688 void
689 InOrderCPU::tick()
690 {
691 DPRINTF(InOrderCPU, "\n\nInOrderCPU: Ticking main, InOrderCPU.\n");
692
693 ++numCycles;
694
695 checkForInterrupts();
696
697 bool pipes_idle = true;
698 //Tick each of the stages
699 for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) {
700 pipelineStage[stNum]->tick();
701
702 pipes_idle = pipes_idle && pipelineStage[stNum]->idle;
703 }
704
705 if (pipes_idle)
706 idleCycles++;
707 else
708 runCycles++;
709
710 // Now advance the time buffers one tick
711 timeBuffer.advance();
712 for (int sqNum=0; sqNum < NumStages - 1; sqNum++) {
713 stageQueue[sqNum]->advance();
714 }
715 activityRec.advance();
716
717 // Any squashed events, or insts then remove them now
718 cleanUpRemovedEvents();
719 cleanUpRemovedInsts();
720
721 // Re-schedule CPU for this cycle
722 if (!tickEvent.scheduled()) {
723 if (_status == SwitchedOut) {
724 // increment stat
725 lastRunningCycle = curTick();
726 } else if (!activityRec.active()) {
727 DPRINTF(InOrderCPU, "sleeping CPU.\n");
728 lastRunningCycle = curTick();
729 timesIdled++;
730 } else {
731 //Tick next_tick = curTick() + cycles(1);
732 //tickEvent.schedule(next_tick);
733 schedule(&tickEvent, nextCycle(curTick() + 1));
734 DPRINTF(InOrderCPU, "Scheduled CPU for next tick @ %i.\n",
735 nextCycle(curTick() + 1));
736 }
737 }
738
739 tickThreadStats();
740 updateThreadPriority();
741 }
742
743
744 void
745 InOrderCPU::init()
746 {
747 if (!deferRegistration) {
748 registerThreadContexts();
749 }
750
751 // Set inSyscall so that the CPU doesn't squash when initially
752 // setting up registers.
753 for (ThreadID tid = 0; tid < numThreads; ++tid)
754 thread[tid]->inSyscall = true;
755
756 if (FullSystem) {
757 for (ThreadID tid = 0; tid < numThreads; tid++) {
758 ThreadContext *src_tc = threadContexts[tid];
759 TheISA::initCPU(src_tc, src_tc->contextId());
760 // Initialise the ThreadContext's memory proxies
761 thread[tid]->initMemProxies(thread[tid]->getTC());
762 }
763 }
764
765 // Clear inSyscall.
766 for (ThreadID tid = 0; tid < numThreads; ++tid)
767 thread[tid]->inSyscall = false;
768
769 // Call Initializiation Routine for Resource Pool
770 resPool->init();
771 }
772
773 Port*
774 InOrderCPU::getPort(const std::string &if_name, int idx)
775 {
776 return resPool->getPort(if_name, idx);
777 }
778
779 Fault
780 InOrderCPU::hwrei(ThreadID tid)
781 {
782 #if THE_ISA == ALPHA_ISA
783 // Need to clear the lock flag upon returning from an interrupt.
784 setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid);
785
786 thread[tid]->kernelStats->hwrei();
787 // FIXME: XXX check for interrupts? XXX
788 #endif
789
790 return NoFault;
791 }
792
793
794 bool
795 InOrderCPU::simPalCheck(int palFunc, ThreadID tid)
796 {
797 #if THE_ISA == ALPHA_ISA
798 if (this->thread[tid]->kernelStats)
799 this->thread[tid]->kernelStats->callpal(palFunc,
800 this->threadContexts[tid]);
801
802 switch (palFunc) {
803 case PAL::halt:
804 halt();
805 if (--System::numSystemsRunning == 0)
806 exitSimLoop("all cpus halted");
807 break;
808
809 case PAL::bpt:
810 case PAL::bugchk:
811 if (this->system->breakpoint())
812 return false;
813 break;
814 }
815 #endif
816 return true;
817 }
818
819 void
820 InOrderCPU::checkForInterrupts()
821 {
822 for (int i = 0; i < threadContexts.size(); i++) {
823 ThreadContext *tc = threadContexts[i];
824
825 if (interrupts->checkInterrupts(tc)) {
826 Fault interrupt = interrupts->getInterrupt(tc);
827
828 if (interrupt != NoFault) {
829 DPRINTF(Interrupt, "Processing Intterupt for [tid:%i].\n",
830 tc->threadId());
831
832 ThreadID tid = tc->threadId();
833 interrupts->updateIntrInfo(tc);
834
835 // Squash from Last Stage in Pipeline
836 unsigned last_stage = NumStages - 1;
837 dummyTrapInst[tid]->squashingStage = last_stage;
838 pipelineStage[last_stage]->setupSquash(dummyTrapInst[tid],
839 tid);
840
841 // By default, setupSquash will always squash from stage + 1
842 pipelineStage[BackEndStartStage - 1]->setupSquash(dummyTrapInst[tid],
843 tid);
844
845 // Schedule Squash Through-out Resource Pool
846 resPool->scheduleEvent(
847 (InOrderCPU::CPUEventType)ResourcePool::SquashAll,
848 dummyTrapInst[tid], 0);
849
850 // Finally, Setup Trap to happen at end of cycle
851 trapContext(interrupt, tid, dummyTrapInst[tid]);
852 }
853 }
854 }
855 }
856
857 Fault
858 InOrderCPU::getInterrupts()
859 {
860 // Check if there are any outstanding interrupts
861 return interrupts->getInterrupt(threadContexts[0]);
862 }
863
864 void
865 InOrderCPU::processInterrupts(Fault interrupt)
866 {
867 // Check for interrupts here. For now can copy the code that
868 // exists within isa_fullsys_traits.hh. Also assume that thread 0
869 // is the one that handles the interrupts.
870 // @todo: Possibly consolidate the interrupt checking code.
871 // @todo: Allow other threads to handle interrupts.
872
873 assert(interrupt != NoFault);
874 interrupts->updateIntrInfo(threadContexts[0]);
875
876 DPRINTF(InOrderCPU, "Interrupt %s being handled\n", interrupt->name());
877
878 // Note: Context ID ok here? Impl. of FS mode needs to revisit this
879 trap(interrupt, threadContexts[0]->contextId(), dummyBufferInst);
880 }
881
882 void
883 InOrderCPU::trapContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay)
884 {
885 scheduleCpuEvent(Trap, fault, tid, inst, delay);
886 trapPending[tid] = true;
887 }
888
889 void
890 InOrderCPU::trap(Fault fault, ThreadID tid, DynInstPtr inst)
891 {
892 fault->invoke(tcBase(tid), inst->staticInst);
893 removePipelineStalls(tid);
894 }
895
896 void
897 InOrderCPU::squashFromMemStall(DynInstPtr inst, ThreadID tid, int delay)
898 {
899 scheduleCpuEvent(SquashFromMemStall, NoFault, tid, inst, delay);
900 }
901
902
903 void
904 InOrderCPU::squashDueToMemStall(int stage_num, InstSeqNum seq_num,
905 ThreadID tid)
906 {
907 DPRINTF(InOrderCPU, "Squashing Pipeline Stages Due to Memory Stall...\n");
908
909 // Squash all instructions in each stage including
910 // instruction that caused the squash (seq_num - 1)
911 // NOTE: The stage bandwidth needs to be cleared so thats why
912 // the stalling instruction is squashed as well. The stalled
913 // instruction is previously placed in another intermediate buffer
914 // while it's stall is being handled.
915 InstSeqNum squash_seq_num = seq_num - 1;
916
917 for (int stNum=stage_num; stNum >= 0 ; stNum--) {
918 pipelineStage[stNum]->squashDueToMemStall(squash_seq_num, tid);
919 }
920 }
921
922 void
923 InOrderCPU::scheduleCpuEvent(CPUEventType c_event, Fault fault,
924 ThreadID tid, DynInstPtr inst,
925 unsigned delay, CPUEventPri event_pri)
926 {
927 CPUEvent *cpu_event = new CPUEvent(this, c_event, fault, tid, inst,
928 event_pri);
929
930 Tick sked_tick = nextCycle(curTick() + ticks(delay));
931 if (delay >= 0) {
932 DPRINTF(InOrderCPU, "Scheduling CPU Event (%s) for cycle %i, [tid:%i].\n",
933 eventNames[c_event], curTick() + delay, tid);
934 schedule(cpu_event, sked_tick);
935 } else {
936 cpu_event->process();
937 cpuEventRemoveList.push(cpu_event);
938 }
939
940 // Broadcast event to the Resource Pool
941 // Need to reset tid just in case this is a dummy instruction
942 inst->setTid(tid);
943 resPool->scheduleEvent(c_event, inst, 0, 0, tid);
944 }
945
946 bool
947 InOrderCPU::isThreadActive(ThreadID tid)
948 {
949 list<ThreadID>::iterator isActive =
950 std::find(activeThreads.begin(), activeThreads.end(), tid);
951
952 return (isActive != activeThreads.end());
953 }
954
955 bool
956 InOrderCPU::isThreadReady(ThreadID tid)
957 {
958 list<ThreadID>::iterator isReady =
959 std::find(readyThreads.begin(), readyThreads.end(), tid);
960
961 return (isReady != readyThreads.end());
962 }
963
964 bool
965 InOrderCPU::isThreadSuspended(ThreadID tid)
966 {
967 list<ThreadID>::iterator isSuspended =
968 std::find(suspendedThreads.begin(), suspendedThreads.end(), tid);
969
970 return (isSuspended != suspendedThreads.end());
971 }
972
973 void
974 InOrderCPU::activateNextReadyThread()
975 {
976 if (readyThreads.size() >= 1) {
977 ThreadID ready_tid = readyThreads.front();
978
979 // Activate in Pipeline
980 activateThread(ready_tid);
981
982 // Activate in Resource Pool
983 resPool->activateThread(ready_tid);
984
985 list<ThreadID>::iterator ready_it =
986 std::find(readyThreads.begin(), readyThreads.end(), ready_tid);
987 readyThreads.erase(ready_it);
988 } else {
989 DPRINTF(InOrderCPU,
990 "Attempting to activate new thread, but No Ready Threads to"
991 "activate.\n");
992 DPRINTF(InOrderCPU,
993 "Unable to switch to next active thread.\n");
994 }
995 }
996
997 void
998 InOrderCPU::activateThread(ThreadID tid)
999 {
1000 if (isThreadSuspended(tid)) {
1001 DPRINTF(InOrderCPU,
1002 "Removing [tid:%i] from suspended threads list.\n", tid);
1003
1004 list<ThreadID>::iterator susp_it =
1005 std::find(suspendedThreads.begin(), suspendedThreads.end(),
1006 tid);
1007 suspendedThreads.erase(susp_it);
1008 }
1009
1010 if (threadModel == SwitchOnCacheMiss &&
1011 numActiveThreads() == 1) {
1012 DPRINTF(InOrderCPU,
1013 "Ignoring activation of [tid:%i], since [tid:%i] is "
1014 "already running.\n", tid, activeThreadId());
1015
1016 DPRINTF(InOrderCPU,"Placing [tid:%i] on ready threads list\n",
1017 tid);
1018
1019 readyThreads.push_back(tid);
1020
1021 } else if (!isThreadActive(tid)) {
1022 DPRINTF(InOrderCPU,
1023 "Adding [tid:%i] to active threads list.\n", tid);
1024 activeThreads.push_back(tid);
1025
1026 activateThreadInPipeline(tid);
1027
1028 thread[tid]->lastActivate = curTick();
1029
1030 tcBase(tid)->setStatus(ThreadContext::Active);
1031
1032 wakeCPU();
1033
1034 numCtxtSwitches++;
1035 }
1036 }
1037
1038 void
1039 InOrderCPU::activateThreadInPipeline(ThreadID tid)
1040 {
1041 for (int stNum=0; stNum < NumStages; stNum++) {
1042 pipelineStage[stNum]->activateThread(tid);
1043 }
1044 }
1045
1046 void
1047 InOrderCPU::deactivateContext(ThreadID tid, int delay)
1048 {
1049 DPRINTF(InOrderCPU,"[tid:%i]: Deactivating ...\n", tid);
1050
1051 scheduleCpuEvent(DeactivateThread, NoFault, tid, dummyInst[tid], delay);
1052
1053 // Be sure to signal that there's some activity so the CPU doesn't
1054 // deschedule itself.
1055 activityRec.activity();
1056
1057 _status = Running;
1058 }
1059
1060 void
1061 InOrderCPU::deactivateThread(ThreadID tid)
1062 {
1063 DPRINTF(InOrderCPU, "[tid:%i]: Calling deactivate thread.\n", tid);
1064
1065 if (isThreadActive(tid)) {
1066 DPRINTF(InOrderCPU,"[tid:%i]: Removing from active threads list\n",
1067 tid);
1068 list<ThreadID>::iterator thread_it =
1069 std::find(activeThreads.begin(), activeThreads.end(), tid);
1070
1071 removePipelineStalls(*thread_it);
1072
1073 activeThreads.erase(thread_it);
1074
1075 // Ideally, this should be triggered from the
1076 // suspendContext/Thread functions
1077 tcBase(tid)->setStatus(ThreadContext::Suspended);
1078 }
1079
1080 assert(!isThreadActive(tid));
1081 }
1082
1083 void
1084 InOrderCPU::removePipelineStalls(ThreadID tid)
1085 {
1086 DPRINTF(InOrderCPU,"[tid:%i]: Removing all pipeline stalls\n",
1087 tid);
1088
1089 for (int stNum = 0; stNum < NumStages ; stNum++) {
1090 pipelineStage[stNum]->removeStalls(tid);
1091 }
1092
1093 }
1094
1095 void
1096 InOrderCPU::updateThreadPriority()
1097 {
1098 if (activeThreads.size() > 1)
1099 {
1100 //DEFAULT TO ROUND ROBIN SCHEME
1101 //e.g. Move highest priority to end of thread list
1102 list<ThreadID>::iterator list_begin = activeThreads.begin();
1103
1104 unsigned high_thread = *list_begin;
1105
1106 activeThreads.erase(list_begin);
1107
1108 activeThreads.push_back(high_thread);
1109 }
1110 }
1111
1112 inline void
1113 InOrderCPU::tickThreadStats()
1114 {
1115 /** Keep track of cycles that each thread is active */
1116 list<ThreadID>::iterator thread_it = activeThreads.begin();
1117 while (thread_it != activeThreads.end()) {
1118 threadCycles[*thread_it]++;
1119 thread_it++;
1120 }
1121
1122 // Keep track of cycles where SMT is active
1123 if (activeThreads.size() > 1) {
1124 smtCycles++;
1125 }
1126 }
1127
1128 void
1129 InOrderCPU::activateContext(ThreadID tid, int delay)
1130 {
1131 DPRINTF(InOrderCPU,"[tid:%i]: Activating ...\n", tid);
1132
1133
1134 scheduleCpuEvent(ActivateThread, NoFault, tid, dummyInst[tid], delay);
1135
1136 // Be sure to signal that there's some activity so the CPU doesn't
1137 // deschedule itself.
1138 activityRec.activity();
1139
1140 _status = Running;
1141 }
1142
1143 void
1144 InOrderCPU::activateNextReadyContext(int delay)
1145 {
1146 DPRINTF(InOrderCPU,"Activating next ready thread\n");
1147
1148 scheduleCpuEvent(ActivateNextReadyThread, NoFault, 0/*tid*/, dummyInst[0],
1149 delay, ActivateNextReadyThread_Pri);
1150
1151 // Be sure to signal that there's some activity so the CPU doesn't
1152 // deschedule itself.
1153 activityRec.activity();
1154
1155 _status = Running;
1156 }
1157
1158 void
1159 InOrderCPU::haltContext(ThreadID tid, int delay)
1160 {
1161 DPRINTF(InOrderCPU, "[tid:%i]: Calling Halt Context...\n", tid);
1162
1163 scheduleCpuEvent(HaltThread, NoFault, tid, dummyInst[tid], delay);
1164
1165 activityRec.activity();
1166 }
1167
1168 void
1169 InOrderCPU::haltThread(ThreadID tid)
1170 {
1171 DPRINTF(InOrderCPU, "[tid:%i]: Placing on Halted Threads List...\n", tid);
1172 deactivateThread(tid);
1173 squashThreadInPipeline(tid);
1174 haltedThreads.push_back(tid);
1175
1176 tcBase(tid)->setStatus(ThreadContext::Halted);
1177
1178 if (threadModel == SwitchOnCacheMiss) {
1179 activateNextReadyContext();
1180 }
1181 }
1182
1183 void
1184 InOrderCPU::suspendContext(ThreadID tid, int delay)
1185 {
1186 scheduleCpuEvent(SuspendThread, NoFault, tid, dummyInst[tid], delay);
1187 }
1188
1189 void
1190 InOrderCPU::suspendThread(ThreadID tid)
1191 {
1192 DPRINTF(InOrderCPU, "[tid:%i]: Placing on Suspended Threads List...\n",
1193 tid);
1194 deactivateThread(tid);
1195 suspendedThreads.push_back(tid);
1196 thread[tid]->lastSuspend = curTick();
1197
1198 tcBase(tid)->setStatus(ThreadContext::Suspended);
1199 }
1200
1201 void
1202 InOrderCPU::squashThreadInPipeline(ThreadID tid)
1203 {
1204 //Squash all instructions in each stage
1205 for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) {
1206 pipelineStage[stNum]->squash(0 /*seq_num*/, tid);
1207 }
1208 }
1209
1210 PipelineStage*
1211 InOrderCPU::getPipeStage(int stage_num)
1212 {
1213 return pipelineStage[stage_num];
1214 }
1215
1216
1217 RegIndex
1218 InOrderCPU::flattenRegIdx(RegIndex reg_idx, RegType &reg_type, ThreadID tid)
1219 {
1220 if (reg_idx < FP_Base_DepTag) {
1221 reg_type = IntType;
1222 return isa[tid].flattenIntIndex(reg_idx);
1223 } else if (reg_idx < Ctrl_Base_DepTag) {
1224 reg_type = FloatType;
1225 reg_idx -= FP_Base_DepTag;
1226 return isa[tid].flattenFloatIndex(reg_idx);
1227 } else {
1228 reg_type = MiscType;
1229 return reg_idx - TheISA::Ctrl_Base_DepTag;
1230 }
1231 }
1232
1233 uint64_t
1234 InOrderCPU::readIntReg(RegIndex reg_idx, ThreadID tid)
1235 {
1236 DPRINTF(IntRegs, "[tid:%i]: Reading Int. Reg %i as %x\n",
1237 tid, reg_idx, intRegs[tid][reg_idx]);
1238
1239 return intRegs[tid][reg_idx];
1240 }
1241
1242 FloatReg
1243 InOrderCPU::readFloatReg(RegIndex reg_idx, ThreadID tid)
1244 {
1245 DPRINTF(FloatRegs, "[tid:%i]: Reading Float Reg %i as %x, %08f\n",
1246 tid, reg_idx, floatRegs.i[tid][reg_idx], floatRegs.f[tid][reg_idx]);
1247
1248 return floatRegs.f[tid][reg_idx];
1249 }
1250
1251 FloatRegBits
1252 InOrderCPU::readFloatRegBits(RegIndex reg_idx, ThreadID tid)
1253 {
1254 DPRINTF(FloatRegs, "[tid:%i]: Reading Float Reg %i as %x, %08f\n",
1255 tid, reg_idx, floatRegs.i[tid][reg_idx], floatRegs.f[tid][reg_idx]);
1256
1257 return floatRegs.i[tid][reg_idx];
1258 }
1259
1260 void
1261 InOrderCPU::setIntReg(RegIndex reg_idx, uint64_t val, ThreadID tid)
1262 {
1263 if (reg_idx == TheISA::ZeroReg) {
1264 DPRINTF(IntRegs, "[tid:%i]: Ignoring Setting of ISA-ZeroReg "
1265 "(Int. Reg %i) to %x\n", tid, reg_idx, val);
1266 return;
1267 } else {
1268 DPRINTF(IntRegs, "[tid:%i]: Setting Int. Reg %i to %x\n",
1269 tid, reg_idx, val);
1270
1271 intRegs[tid][reg_idx] = val;
1272 }
1273 }
1274
1275
1276 void
1277 InOrderCPU::setFloatReg(RegIndex reg_idx, FloatReg val, ThreadID tid)
1278 {
1279 floatRegs.f[tid][reg_idx] = val;
1280 DPRINTF(FloatRegs, "[tid:%i]: Setting Float. Reg %i bits to "
1281 "%x, %08f\n",
1282 tid, reg_idx,
1283 floatRegs.i[tid][reg_idx],
1284 floatRegs.f[tid][reg_idx]);
1285 }
1286
1287
1288 void
1289 InOrderCPU::setFloatRegBits(RegIndex reg_idx, FloatRegBits val, ThreadID tid)
1290 {
1291 floatRegs.i[tid][reg_idx] = val;
1292 DPRINTF(FloatRegs, "[tid:%i]: Setting Float. Reg %i bits to "
1293 "%x, %08f\n",
1294 tid, reg_idx,
1295 floatRegs.i[tid][reg_idx],
1296 floatRegs.f[tid][reg_idx]);
1297 }
1298
1299 uint64_t
1300 InOrderCPU::readRegOtherThread(unsigned reg_idx, ThreadID tid)
1301 {
1302 // If Default value is set, then retrieve target thread
1303 if (tid == InvalidThreadID) {
1304 tid = TheISA::getTargetThread(tcBase(tid));
1305 }
1306
1307 if (reg_idx < FP_Base_DepTag) {
1308 // Integer Register File
1309 return readIntReg(reg_idx, tid);
1310 } else if (reg_idx < Ctrl_Base_DepTag) {
1311 // Float Register File
1312 reg_idx -= FP_Base_DepTag;
1313 return readFloatRegBits(reg_idx, tid);
1314 } else {
1315 reg_idx -= Ctrl_Base_DepTag;
1316 return readMiscReg(reg_idx, tid); // Misc. Register File
1317 }
1318 }
1319 void
1320 InOrderCPU::setRegOtherThread(unsigned reg_idx, const MiscReg &val,
1321 ThreadID tid)
1322 {
1323 // If Default value is set, then retrieve target thread
1324 if (tid == InvalidThreadID) {
1325 tid = TheISA::getTargetThread(tcBase(tid));
1326 }
1327
1328 if (reg_idx < FP_Base_DepTag) { // Integer Register File
1329 setIntReg(reg_idx, val, tid);
1330 } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
1331 reg_idx -= FP_Base_DepTag;
1332 setFloatRegBits(reg_idx, val, tid);
1333 } else {
1334 reg_idx -= Ctrl_Base_DepTag;
1335 setMiscReg(reg_idx, val, tid); // Misc. Register File
1336 }
1337 }
1338
1339 MiscReg
1340 InOrderCPU::readMiscRegNoEffect(int misc_reg, ThreadID tid)
1341 {
1342 return isa[tid].readMiscRegNoEffect(misc_reg);
1343 }
1344
1345 MiscReg
1346 InOrderCPU::readMiscReg(int misc_reg, ThreadID tid)
1347 {
1348 return isa[tid].readMiscReg(misc_reg, tcBase(tid));
1349 }
1350
1351 void
1352 InOrderCPU::setMiscRegNoEffect(int misc_reg, const MiscReg &val, ThreadID tid)
1353 {
1354 isa[tid].setMiscRegNoEffect(misc_reg, val);
1355 }
1356
1357 void
1358 InOrderCPU::setMiscReg(int misc_reg, const MiscReg &val, ThreadID tid)
1359 {
1360 isa[tid].setMiscReg(misc_reg, val, tcBase(tid));
1361 }
1362
1363
1364 InOrderCPU::ListIt
1365 InOrderCPU::addInst(DynInstPtr inst)
1366 {
1367 ThreadID tid = inst->readTid();
1368
1369 instList[tid].push_back(inst);
1370
1371 return --(instList[tid].end());
1372 }
1373
1374 InOrderCPU::ListIt
1375 InOrderCPU::findInst(InstSeqNum seq_num, ThreadID tid)
1376 {
1377 ListIt it = instList[tid].begin();
1378 ListIt end = instList[tid].end();
1379
1380 while (it != end) {
1381 if ((*it)->seqNum == seq_num)
1382 return it;
1383 else if ((*it)->seqNum > seq_num)
1384 break;
1385
1386 it++;
1387 }
1388
1389 return instList[tid].end();
1390 }
1391
1392 void
1393 InOrderCPU::updateContextSwitchStats()
1394 {
1395 // Set Average Stat Here, then reset to 0
1396 instsPerCtxtSwitch = instsPerSwitch;
1397 instsPerSwitch = 0;
1398 }
1399
1400
1401 void
1402 InOrderCPU::instDone(DynInstPtr inst, ThreadID tid)
1403 {
1404 // Set the nextPC to be fetched if this is the last instruction
1405 // committed
1406 // ========
1407 // This contributes to the precise state of the CPU
1408 // which can be used when restoring a thread to the CPU after after any
1409 // type of context switching activity (fork, exception, etc.)
1410 TheISA::PCState comm_pc = inst->pcState();
1411 lastCommittedPC[tid] = comm_pc;
1412 TheISA::advancePC(comm_pc, inst->staticInst);
1413 pcState(comm_pc, tid);
1414
1415 //@todo: may be unnecessary with new-ISA-specific branch handling code
1416 if (inst->isControl()) {
1417 thread[tid]->lastGradIsBranch = true;
1418 thread[tid]->lastBranchPC = inst->pcState();
1419 TheISA::advancePC(thread[tid]->lastBranchPC, inst->staticInst);
1420 } else {
1421 thread[tid]->lastGradIsBranch = false;
1422 }
1423
1424
1425 // Finalize Trace Data For Instruction
1426 if (inst->traceData) {
1427 //inst->traceData->setCycle(curTick());
1428 inst->traceData->setFetchSeq(inst->seqNum);
1429 //inst->traceData->setCPSeq(cpu->tcBase(tid)->numInst);
1430 inst->traceData->dump();
1431 delete inst->traceData;
1432 inst->traceData = NULL;
1433 }
1434
1435 // Increment active thread's instruction count
1436 instsPerSwitch++;
1437
1438 // Increment thread-state's instruction count
1439 thread[tid]->numInst++;
1440
1441 // Increment thread-state's instruction stats
1442 thread[tid]->numInsts++;
1443
1444 // Count committed insts per thread stats
1445 committedInsts[tid]++;
1446
1447 // Count total insts committed stat
1448 totalCommittedInsts++;
1449
1450 // Count SMT-committed insts per thread stat
1451 if (numActiveThreads() > 1) {
1452 smtCommittedInsts[tid]++;
1453 }
1454
1455 // Instruction-Mix Stats
1456 if (inst->isLoad()) {
1457 comLoads++;
1458 } else if (inst->isStore()) {
1459 comStores++;
1460 } else if (inst->isControl()) {
1461 comBranches++;
1462 } else if (inst->isNop()) {
1463 comNops++;
1464 } else if (inst->isNonSpeculative()) {
1465 comNonSpec++;
1466 } else if (inst->isInteger()) {
1467 comInts++;
1468 } else if (inst->isFloating()) {
1469 comFloats++;
1470 }
1471
1472 // Check for instruction-count-based events.
1473 comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
1474
1475 // Finally, remove instruction from CPU
1476 removeInst(inst);
1477 }
1478
1479 // currently unused function, but substitute repetitive code w/this function
1480 // call
1481 void
1482 InOrderCPU::addToRemoveList(DynInstPtr inst)
1483 {
1484 removeInstsThisCycle = true;
1485 if (!inst->isRemoveList()) {
1486 DPRINTF(InOrderCPU, "Pushing instruction [tid:%i] PC %s "
1487 "[sn:%lli] to remove list\n",
1488 inst->threadNumber, inst->pcState(), inst->seqNum);
1489 inst->setRemoveList();
1490 removeList.push(inst->getInstListIt());
1491 } else {
1492 DPRINTF(InOrderCPU, "Ignoring instruction removal for [tid:%i] PC %s "
1493 "[sn:%lli], already remove list\n",
1494 inst->threadNumber, inst->pcState(), inst->seqNum);
1495 }
1496
1497 }
1498
1499 void
1500 InOrderCPU::removeInst(DynInstPtr inst)
1501 {
1502 DPRINTF(InOrderCPU, "Removing graduated instruction [tid:%i] PC %s "
1503 "[sn:%lli]\n",
1504 inst->threadNumber, inst->pcState(), inst->seqNum);
1505
1506 removeInstsThisCycle = true;
1507
1508 // Remove the instruction.
1509 if (!inst->isRemoveList()) {
1510 DPRINTF(InOrderCPU, "Pushing instruction [tid:%i] PC %s "
1511 "[sn:%lli] to remove list\n",
1512 inst->threadNumber, inst->pcState(), inst->seqNum);
1513 inst->setRemoveList();
1514 removeList.push(inst->getInstListIt());
1515 } else {
1516 DPRINTF(InOrderCPU, "Ignoring instruction removal for [tid:%i] PC %s "
1517 "[sn:%lli], already on remove list\n",
1518 inst->threadNumber, inst->pcState(), inst->seqNum);
1519 }
1520
1521 }
1522
1523 void
1524 InOrderCPU::removeInstsUntil(const InstSeqNum &seq_num, ThreadID tid)
1525 {
1526 //assert(!instList[tid].empty());
1527
1528 removeInstsThisCycle = true;
1529
1530 ListIt inst_iter = instList[tid].end();
1531
1532 inst_iter--;
1533
1534 DPRINTF(InOrderCPU, "Squashing instructions from CPU instruction "
1535 "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
1536 tid, seq_num, (*inst_iter)->seqNum);
1537
1538 while ((*inst_iter)->seqNum > seq_num) {
1539
1540 bool break_loop = (inst_iter == instList[tid].begin());
1541
1542 squashInstIt(inst_iter, tid);
1543
1544 inst_iter--;
1545
1546 if (break_loop)
1547 break;
1548 }
1549 }
1550
1551
1552 inline void
1553 InOrderCPU::squashInstIt(const ListIt inst_it, ThreadID tid)
1554 {
1555 DynInstPtr inst = (*inst_it);
1556 if (inst->threadNumber == tid) {
1557 DPRINTF(InOrderCPU, "Squashing instruction, "
1558 "[tid:%i] [sn:%lli] PC %s\n",
1559 inst->threadNumber,
1560 inst->seqNum,
1561 inst->pcState());
1562
1563 inst->setSquashed();
1564 archRegDepMap[tid].remove(inst);
1565
1566 if (!inst->isRemoveList()) {
1567 DPRINTF(InOrderCPU, "Pushing instruction [tid:%i] PC %s "
1568 "[sn:%lli] to remove list\n",
1569 inst->threadNumber, inst->pcState(),
1570 inst->seqNum);
1571 inst->setRemoveList();
1572 removeList.push(inst_it);
1573 } else {
1574 DPRINTF(InOrderCPU, "Ignoring instruction removal for [tid:%i]"
1575 " PC %s [sn:%lli], already on remove list\n",
1576 inst->threadNumber, inst->pcState(),
1577 inst->seqNum);
1578 }
1579
1580 }
1581
1582 }
1583
1584
1585 void
1586 InOrderCPU::cleanUpRemovedInsts()
1587 {
1588 while (!removeList.empty()) {
1589 DPRINTF(InOrderCPU, "Removing instruction, "
1590 "[tid:%i] [sn:%lli] PC %s\n",
1591 (*removeList.front())->threadNumber,
1592 (*removeList.front())->seqNum,
1593 (*removeList.front())->pcState());
1594
1595 DynInstPtr inst = *removeList.front();
1596 ThreadID tid = inst->threadNumber;
1597
1598 // Remove From Register Dependency Map, If Necessary
1599 // archRegDepMap[tid].remove(inst);
1600
1601 // Clear if Non-Speculative
1602 if (inst->staticInst &&
1603 inst->seqNum == nonSpecSeqNum[tid] &&
1604 nonSpecInstActive[tid] == true) {
1605 nonSpecInstActive[tid] = false;
1606 }
1607
1608 inst->onInstList = false;
1609
1610 instList[tid].erase(removeList.front());
1611
1612 removeList.pop();
1613 }
1614
1615 removeInstsThisCycle = false;
1616 }
1617
1618 void
1619 InOrderCPU::cleanUpRemovedEvents()
1620 {
1621 while (!cpuEventRemoveList.empty()) {
1622 Event *cpu_event = cpuEventRemoveList.front();
1623 cpuEventRemoveList.pop();
1624 delete cpu_event;
1625 }
1626 }
1627
1628
1629 void
1630 InOrderCPU::dumpInsts()
1631 {
1632 int num = 0;
1633
1634 ListIt inst_list_it = instList[0].begin();
1635
1636 cprintf("Dumping Instruction List\n");
1637
1638 while (inst_list_it != instList[0].end()) {
1639 cprintf("Instruction:%i\nPC:%s\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
1640 "Squashed:%i\n\n",
1641 num, (*inst_list_it)->pcState(),
1642 (*inst_list_it)->threadNumber,
1643 (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
1644 (*inst_list_it)->isSquashed());
1645 inst_list_it++;
1646 ++num;
1647 }
1648 }
1649
1650 void
1651 InOrderCPU::wakeCPU()
1652 {
1653 if (/*activityRec.active() || */tickEvent.scheduled()) {
1654 DPRINTF(Activity, "CPU already running.\n");
1655 return;
1656 }
1657
1658 DPRINTF(Activity, "Waking up CPU\n");
1659
1660 Tick extra_cycles = tickToCycles((curTick() - 1) - lastRunningCycle);
1661
1662 idleCycles += extra_cycles;
1663 for (int stage_num = 0; stage_num < NumStages; stage_num++) {
1664 pipelineStage[stage_num]->idleCycles += extra_cycles;
1665 }
1666
1667 numCycles += extra_cycles;
1668
1669 schedule(&tickEvent, nextCycle(curTick()));
1670 }
1671
1672 // Lots of copied full system code...place into BaseCPU class?
1673 void
1674 InOrderCPU::wakeup()
1675 {
1676 if (thread[0]->status() != ThreadContext::Suspended)
1677 return;
1678
1679 wakeCPU();
1680
1681 DPRINTF(Quiesce, "Suspended Processor woken\n");
1682 threadContexts[0]->activate();
1683 }
1684
1685 void
1686 InOrderCPU::syscallContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay)
1687 {
1688 // Syscall must be non-speculative, so squash from last stage
1689 unsigned squash_stage = NumStages - 1;
1690 inst->setSquashInfo(squash_stage);
1691
1692 // Squash In Pipeline Stage
1693 pipelineStage[squash_stage]->setupSquash(inst, tid);
1694
1695 // Schedule Squash Through-out Resource Pool
1696 resPool->scheduleEvent(
1697 (InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
1698 scheduleCpuEvent(Syscall, fault, tid, inst, delay, Syscall_Pri);
1699 }
1700
1701 void
1702 InOrderCPU::syscall(int64_t callnum, ThreadID tid)
1703 {
1704 DPRINTF(InOrderCPU, "[tid:%i] Executing syscall().\n\n", tid);
1705
1706 DPRINTF(Activity,"Activity: syscall() called.\n");
1707
1708 // Temporarily increase this by one to account for the syscall
1709 // instruction.
1710 ++(this->thread[tid]->funcExeInst);
1711
1712 // Execute the actual syscall.
1713 this->thread[tid]->syscall(callnum);
1714
1715 // Decrease funcExeInst by one as the normal commit will handle
1716 // incrementing it.
1717 --(this->thread[tid]->funcExeInst);
1718
1719 // Clear Non-Speculative Block Variable
1720 nonSpecInstActive[tid] = false;
1721 }
1722
1723 TheISA::TLB*
1724 InOrderCPU::getITBPtr()
1725 {
1726 CacheUnit *itb_res =
1727 dynamic_cast<CacheUnit*>(resPool->getResource(fetchPortIdx));
1728 return itb_res->tlb();
1729 }
1730
1731
1732 TheISA::TLB*
1733 InOrderCPU::getDTBPtr()
1734 {
1735 CacheUnit *dtb_res =
1736 dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
1737 return dtb_res->tlb();
1738 }
1739
1740 Decoder *
1741 InOrderCPU::getDecoderPtr()
1742 {
1743 FetchUnit *fetch_res =
1744 dynamic_cast<FetchUnit*>(resPool->getResource(fetchPortIdx));
1745 return &fetch_res->decoder;
1746 }
1747
1748 Fault
1749 InOrderCPU::read(DynInstPtr inst, Addr addr,
1750 uint8_t *data, unsigned size, unsigned flags)
1751 {
1752 //@TODO: Generalize name "CacheUnit" to "MemUnit" just in case
1753 // you want to run w/out caches?
1754 CacheUnit *cache_res =
1755 dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
1756
1757 return cache_res->read(inst, addr, data, size, flags);
1758 }
1759
1760 Fault
1761 InOrderCPU::write(DynInstPtr inst, uint8_t *data, unsigned size,
1762 Addr addr, unsigned flags, uint64_t *write_res)
1763 {
1764 //@TODO: Generalize name "CacheUnit" to "MemUnit" just in case
1765 // you want to run w/out caches?
1766 CacheUnit *cache_res =
1767 dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
1768 return cache_res->write(inst, data, size, addr, flags, write_res);
1769 }