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