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