arch,cpu,gpu-compute,mem: Remove asid from Request objects.
[gem5.git] / src / cpu / base.cc
1 /*
2 * Copyright (c) 2011-2012,2016-2017, 2019 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2002-2005 The Regents of The University of Michigan
15 * Copyright (c) 2011 Regents of the University of California
16 * Copyright (c) 2013 Advanced Micro Devices, Inc.
17 * Copyright (c) 2013 Mark D. Hill and David A. Wood
18 * All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are
22 * met: redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer;
24 * redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution;
27 * neither the name of the copyright holders nor the names of its
28 * contributors may be used to endorse or promote products derived from
29 * this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
37 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
39 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
41 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 #include "cpu/base.hh"
45
46 #include <iostream>
47 #include <sstream>
48 #include <string>
49
50 #include "arch/generic/tlb.hh"
51 #include "base/cprintf.hh"
52 #include "base/loader/symtab.hh"
53 #include "base/logging.hh"
54 #include "base/output.hh"
55 #include "base/trace.hh"
56 #include "cpu/checker/cpu.hh"
57 #include "cpu/cpuevent.hh"
58 #include "cpu/profile.hh"
59 #include "cpu/thread_context.hh"
60 #include "debug/Mwait.hh"
61 #include "debug/SyscallVerbose.hh"
62 #include "debug/Thread.hh"
63 #include "mem/page_table.hh"
64 #include "params/BaseCPU.hh"
65 #include "sim/clocked_object.hh"
66 #include "sim/full_system.hh"
67 #include "sim/process.hh"
68 #include "sim/sim_events.hh"
69 #include "sim/sim_exit.hh"
70 #include "sim/system.hh"
71
72 // Hack
73 #include "sim/stat_control.hh"
74
75 using namespace std;
76
77 vector<BaseCPU *> BaseCPU::cpuList;
78
79 // This variable reflects the max number of threads in any CPU. Be
80 // careful to only use it once all the CPUs that you care about have
81 // been initialized
82 int maxThreadsPerCPU = 1;
83
84 CPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival)
85 : Event(Event::Progress_Event_Pri), _interval(ival), lastNumInst(0),
86 cpu(_cpu), _repeatEvent(true)
87 {
88 if (_interval)
89 cpu->schedule(this, curTick() + _interval);
90 }
91
92 void
93 CPUProgressEvent::process()
94 {
95 Counter temp = cpu->totalOps();
96
97 if (_repeatEvent)
98 cpu->schedule(this, curTick() + _interval);
99
100 if (cpu->switchedOut()) {
101 return;
102 }
103
104 #ifndef NDEBUG
105 double ipc = double(temp - lastNumInst) / (_interval / cpu->clockPeriod());
106
107 DPRINTFN("%s progress event, total committed:%i, progress insts committed: "
108 "%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst,
109 ipc);
110 ipc = 0.0;
111 #else
112 cprintf("%lli: %s progress event, total committed:%i, progress insts "
113 "committed: %lli\n", curTick(), cpu->name(), temp,
114 temp - lastNumInst);
115 #endif
116 lastNumInst = temp;
117 }
118
119 const char *
120 CPUProgressEvent::description() const
121 {
122 return "CPU Progress";
123 }
124
125 BaseCPU::BaseCPU(Params *p, bool is_checker)
126 : ClockedObject(p), instCnt(0), _cpuId(p->cpu_id), _socketId(p->socket_id),
127 _instMasterId(p->system->getMasterId(this, "inst")),
128 _dataMasterId(p->system->getMasterId(this, "data")),
129 _taskId(ContextSwitchTaskId::Unknown), _pid(invldPid),
130 _switchedOut(p->switched_out), _cacheLineSize(p->system->cacheLineSize()),
131 interrupts(p->interrupts), profileEvent(NULL),
132 numThreads(p->numThreads), system(p->system),
133 previousCycle(0), previousState(CPU_STATE_SLEEP),
134 functionTraceStream(nullptr), currentFunctionStart(0),
135 currentFunctionEnd(0), functionEntryTick(0),
136 addressMonitor(p->numThreads),
137 syscallRetryLatency(p->syscallRetryLatency),
138 pwrGatingLatency(p->pwr_gating_latency),
139 powerGatingOnIdle(p->power_gating_on_idle),
140 enterPwrGatingEvent([this]{ enterPwrGating(); }, name())
141 {
142 // if Python did not provide a valid ID, do it here
143 if (_cpuId == -1 ) {
144 _cpuId = cpuList.size();
145 }
146
147 // add self to global list of CPUs
148 cpuList.push_back(this);
149
150 DPRINTF(SyscallVerbose, "Constructing CPU with id %d, socket id %d\n",
151 _cpuId, _socketId);
152
153 if (numThreads > maxThreadsPerCPU)
154 maxThreadsPerCPU = numThreads;
155
156 functionTracingEnabled = false;
157 if (p->function_trace) {
158 const string fname = csprintf("ftrace.%s", name());
159 functionTraceStream = simout.findOrCreate(fname)->stream();
160
161 currentFunctionStart = currentFunctionEnd = 0;
162 functionEntryTick = p->function_trace_start;
163
164 if (p->function_trace_start == 0) {
165 functionTracingEnabled = true;
166 } else {
167 Event *event = new EventFunctionWrapper(
168 [this]{ enableFunctionTrace(); }, name(), true);
169 schedule(event, p->function_trace_start);
170 }
171 }
172
173 // The interrupts should always be present unless this CPU is
174 // switched in later or in case it is a checker CPU
175 if (!params()->switched_out && !is_checker) {
176 fatal_if(interrupts.size() != numThreads,
177 "CPU %s has %i interrupt controllers, but is expecting one "
178 "per thread (%i)\n",
179 name(), interrupts.size(), numThreads);
180 for (ThreadID tid = 0; tid < numThreads; tid++)
181 interrupts[tid]->setCPU(this);
182 }
183
184 if (FullSystem) {
185 if (params()->profile)
186 profileEvent = new EventFunctionWrapper(
187 [this]{ processProfileEvent(); },
188 name());
189 }
190 tracer = params()->tracer;
191
192 if (params()->isa.size() != numThreads) {
193 fatal("Number of ISAs (%i) assigned to the CPU does not equal number "
194 "of threads (%i).\n", params()->isa.size(), numThreads);
195 }
196 }
197
198 void
199 BaseCPU::enableFunctionTrace()
200 {
201 functionTracingEnabled = true;
202 }
203
204 BaseCPU::~BaseCPU()
205 {
206 delete profileEvent;
207 }
208
209 void
210 BaseCPU::armMonitor(ThreadID tid, Addr address)
211 {
212 assert(tid < numThreads);
213 AddressMonitor &monitor = addressMonitor[tid];
214
215 monitor.armed = true;
216 monitor.vAddr = address;
217 monitor.pAddr = 0x0;
218 DPRINTF(Mwait,"[tid:%d] Armed monitor (vAddr=0x%lx)\n", tid, address);
219 }
220
221 bool
222 BaseCPU::mwait(ThreadID tid, PacketPtr pkt)
223 {
224 assert(tid < numThreads);
225 AddressMonitor &monitor = addressMonitor[tid];
226
227 if (!monitor.gotWakeup) {
228 int block_size = cacheLineSize();
229 uint64_t mask = ~((uint64_t)(block_size - 1));
230
231 assert(pkt->req->hasPaddr());
232 monitor.pAddr = pkt->getAddr() & mask;
233 monitor.waiting = true;
234
235 DPRINTF(Mwait,"[tid:%d] mwait called (vAddr=0x%lx, "
236 "line's paddr=0x%lx)\n", tid, monitor.vAddr, monitor.pAddr);
237 return true;
238 } else {
239 monitor.gotWakeup = false;
240 return false;
241 }
242 }
243
244 void
245 BaseCPU::mwaitAtomic(ThreadID tid, ThreadContext *tc, BaseTLB *dtb)
246 {
247 assert(tid < numThreads);
248 AddressMonitor &monitor = addressMonitor[tid];
249
250 RequestPtr req = std::make_shared<Request>();
251
252 Addr addr = monitor.vAddr;
253 int block_size = cacheLineSize();
254 uint64_t mask = ~((uint64_t)(block_size - 1));
255 int size = block_size;
256
257 //The address of the next line if it crosses a cache line boundary.
258 Addr secondAddr = roundDown(addr + size - 1, block_size);
259
260 if (secondAddr > addr)
261 size = secondAddr - addr;
262
263 req->setVirt(addr, size, 0x0, dataMasterId(), tc->instAddr());
264
265 // translate to physical address
266 Fault fault = dtb->translateAtomic(req, tc, BaseTLB::Read);
267 assert(fault == NoFault);
268
269 monitor.pAddr = req->getPaddr() & mask;
270 monitor.waiting = true;
271
272 DPRINTF(Mwait,"[tid:%d] mwait called (vAddr=0x%lx, line's paddr=0x%lx)\n",
273 tid, monitor.vAddr, monitor.pAddr);
274 }
275
276 void
277 BaseCPU::init()
278 {
279 // Set up instruction-count-based termination events, if any. This needs
280 // to happen after threadContexts has been constructed.
281 if (params()->max_insts_any_thread != 0) {
282 const char *cause = "a thread reached the max instruction count";
283 for (ThreadID tid = 0; tid < numThreads; ++tid)
284 scheduleInstStop(tid, params()->max_insts_any_thread, cause);
285 }
286
287 // Set up instruction-count-based termination events for SimPoints
288 // Typically, there are more than one action points.
289 // Simulation.py is responsible to take the necessary actions upon
290 // exitting the simulation loop.
291 if (!params()->simpoint_start_insts.empty()) {
292 const char *cause = "simpoint starting point found";
293 for (size_t i = 0; i < params()->simpoint_start_insts.size(); ++i)
294 scheduleInstStop(0, params()->simpoint_start_insts[i], cause);
295 }
296
297 if (params()->max_insts_all_threads != 0) {
298 const char *cause = "all threads reached the max instruction count";
299
300 // allocate & initialize shared downcounter: each event will
301 // decrement this when triggered; simulation will terminate
302 // when counter reaches 0
303 int *counter = new int;
304 *counter = numThreads;
305 for (ThreadID tid = 0; tid < numThreads; ++tid) {
306 Event *event = new CountedExitEvent(cause, *counter);
307 threadContexts[tid]->scheduleInstCountEvent(
308 event, params()->max_insts_all_threads);
309 }
310 }
311
312 if (!params()->switched_out) {
313 registerThreadContexts();
314
315 verifyMemoryMode();
316 }
317 }
318
319 void
320 BaseCPU::startup()
321 {
322 if (FullSystem) {
323 if (!params()->switched_out && profileEvent)
324 schedule(profileEvent, curTick());
325 }
326
327 if (params()->progress_interval) {
328 new CPUProgressEvent(this, params()->progress_interval);
329 }
330
331 if (_switchedOut)
332 ClockedObject::pwrState(Enums::PwrState::OFF);
333
334 // Assumption CPU start to operate instantaneously without any latency
335 if (ClockedObject::pwrState() == Enums::PwrState::UNDEFINED)
336 ClockedObject::pwrState(Enums::PwrState::ON);
337
338 }
339
340 ProbePoints::PMUUPtr
341 BaseCPU::pmuProbePoint(const char *name)
342 {
343 ProbePoints::PMUUPtr ptr;
344 ptr.reset(new ProbePoints::PMU(getProbeManager(), name));
345
346 return ptr;
347 }
348
349 void
350 BaseCPU::regProbePoints()
351 {
352 ppAllCycles = pmuProbePoint("Cycles");
353 ppActiveCycles = pmuProbePoint("ActiveCycles");
354
355 ppRetiredInsts = pmuProbePoint("RetiredInsts");
356 ppRetiredInstsPC = pmuProbePoint("RetiredInstsPC");
357 ppRetiredLoads = pmuProbePoint("RetiredLoads");
358 ppRetiredStores = pmuProbePoint("RetiredStores");
359 ppRetiredBranches = pmuProbePoint("RetiredBranches");
360
361 ppSleeping = new ProbePointArg<bool>(this->getProbeManager(),
362 "Sleeping");
363 }
364
365 void
366 BaseCPU::probeInstCommit(const StaticInstPtr &inst, Addr pc)
367 {
368 if (!inst->isMicroop() || inst->isLastMicroop()) {
369 ppRetiredInsts->notify(1);
370 ppRetiredInstsPC->notify(pc);
371 }
372
373 if (inst->isLoad())
374 ppRetiredLoads->notify(1);
375
376 if (inst->isStore() || inst->isAtomic())
377 ppRetiredStores->notify(1);
378
379 if (inst->isControl())
380 ppRetiredBranches->notify(1);
381 }
382
383 void
384 BaseCPU::regStats()
385 {
386 ClockedObject::regStats();
387
388 using namespace Stats;
389
390 numCycles
391 .name(name() + ".numCycles")
392 .desc("number of cpu cycles simulated")
393 ;
394
395 numWorkItemsStarted
396 .name(name() + ".numWorkItemsStarted")
397 .desc("number of work items this cpu started")
398 ;
399
400 numWorkItemsCompleted
401 .name(name() + ".numWorkItemsCompleted")
402 .desc("number of work items this cpu completed")
403 ;
404
405 int size = threadContexts.size();
406 if (size > 1) {
407 for (int i = 0; i < size; ++i) {
408 stringstream namestr;
409 ccprintf(namestr, "%s.ctx%d", name(), i);
410 threadContexts[i]->regStats(namestr.str());
411 }
412 } else if (size == 1)
413 threadContexts[0]->regStats(name());
414 }
415
416 Port &
417 BaseCPU::getPort(const string &if_name, PortID idx)
418 {
419 // Get the right port based on name. This applies to all the
420 // subclasses of the base CPU and relies on their implementation
421 // of getDataPort and getInstPort.
422 if (if_name == "dcache_port")
423 return getDataPort();
424 else if (if_name == "icache_port")
425 return getInstPort();
426 else
427 return ClockedObject::getPort(if_name, idx);
428 }
429
430 void
431 BaseCPU::registerThreadContexts()
432 {
433 assert(system->multiThread || numThreads == 1);
434
435 ThreadID size = threadContexts.size();
436 for (ThreadID tid = 0; tid < size; ++tid) {
437 ThreadContext *tc = threadContexts[tid];
438
439 if (system->multiThread) {
440 tc->setContextId(system->registerThreadContext(tc));
441 } else {
442 tc->setContextId(system->registerThreadContext(tc, _cpuId));
443 }
444
445 if (!FullSystem)
446 tc->getProcessPtr()->assignThreadContext(tc->contextId());
447 }
448 }
449
450 void
451 BaseCPU::deschedulePowerGatingEvent()
452 {
453 if (enterPwrGatingEvent.scheduled()){
454 deschedule(enterPwrGatingEvent);
455 }
456 }
457
458 void
459 BaseCPU::schedulePowerGatingEvent()
460 {
461 for (auto tc : threadContexts) {
462 if (tc->status() == ThreadContext::Active)
463 return;
464 }
465
466 if (ClockedObject::pwrState() == Enums::PwrState::CLK_GATED &&
467 powerGatingOnIdle) {
468 assert(!enterPwrGatingEvent.scheduled());
469 // Schedule a power gating event when clock gated for the specified
470 // amount of time
471 schedule(enterPwrGatingEvent, clockEdge(pwrGatingLatency));
472 }
473 }
474
475 int
476 BaseCPU::findContext(ThreadContext *tc)
477 {
478 ThreadID size = threadContexts.size();
479 for (ThreadID tid = 0; tid < size; ++tid) {
480 if (tc == threadContexts[tid])
481 return tid;
482 }
483 return 0;
484 }
485
486 void
487 BaseCPU::activateContext(ThreadID thread_num)
488 {
489 DPRINTF(Thread, "activate contextId %d\n",
490 threadContexts[thread_num]->contextId());
491 // Squash enter power gating event while cpu gets activated
492 if (enterPwrGatingEvent.scheduled())
493 deschedule(enterPwrGatingEvent);
494 // For any active thread running, update CPU power state to active (ON)
495 ClockedObject::pwrState(Enums::PwrState::ON);
496
497 updateCycleCounters(CPU_STATE_WAKEUP);
498 }
499
500 void
501 BaseCPU::suspendContext(ThreadID thread_num)
502 {
503 DPRINTF(Thread, "suspend contextId %d\n",
504 threadContexts[thread_num]->contextId());
505 // Check if all threads are suspended
506 for (auto t : threadContexts) {
507 if (t->status() != ThreadContext::Suspended) {
508 return;
509 }
510 }
511
512 // All CPU thread are suspended, update cycle count
513 updateCycleCounters(CPU_STATE_SLEEP);
514
515 // All CPU threads suspended, enter lower power state for the CPU
516 ClockedObject::pwrState(Enums::PwrState::CLK_GATED);
517
518 // If pwrGatingLatency is set to 0 then this mechanism is disabled
519 if (powerGatingOnIdle) {
520 // Schedule power gating event when clock gated for pwrGatingLatency
521 // cycles
522 schedule(enterPwrGatingEvent, clockEdge(pwrGatingLatency));
523 }
524 }
525
526 void
527 BaseCPU::haltContext(ThreadID thread_num)
528 {
529 updateCycleCounters(BaseCPU::CPU_STATE_SLEEP);
530 }
531
532 void
533 BaseCPU::enterPwrGating(void)
534 {
535 ClockedObject::pwrState(Enums::PwrState::OFF);
536 }
537
538 void
539 BaseCPU::switchOut()
540 {
541 assert(!_switchedOut);
542 _switchedOut = true;
543 if (profileEvent && profileEvent->scheduled())
544 deschedule(profileEvent);
545
546 // Flush all TLBs in the CPU to avoid having stale translations if
547 // it gets switched in later.
548 flushTLBs();
549
550 // Go to the power gating state
551 ClockedObject::pwrState(Enums::PwrState::OFF);
552 }
553
554 void
555 BaseCPU::takeOverFrom(BaseCPU *oldCPU)
556 {
557 assert(threadContexts.size() == oldCPU->threadContexts.size());
558 assert(_cpuId == oldCPU->cpuId());
559 assert(_switchedOut);
560 assert(oldCPU != this);
561 _pid = oldCPU->getPid();
562 _taskId = oldCPU->taskId();
563 // Take over the power state of the switchedOut CPU
564 ClockedObject::pwrState(oldCPU->pwrState());
565
566 previousState = oldCPU->previousState;
567 previousCycle = oldCPU->previousCycle;
568
569 _switchedOut = false;
570
571 ThreadID size = threadContexts.size();
572 for (ThreadID i = 0; i < size; ++i) {
573 ThreadContext *newTC = threadContexts[i];
574 ThreadContext *oldTC = oldCPU->threadContexts[i];
575
576 newTC->takeOverFrom(oldTC);
577
578 CpuEvent::replaceThreadContext(oldTC, newTC);
579
580 assert(newTC->contextId() == oldTC->contextId());
581 assert(newTC->threadId() == oldTC->threadId());
582 system->replaceThreadContext(newTC, newTC->contextId());
583
584 /* This code no longer works since the zero register (e.g.,
585 * r31 on Alpha) doesn't necessarily contain zero at this
586 * point.
587 if (DTRACE(Context))
588 ThreadContext::compare(oldTC, newTC);
589 */
590
591 Port *old_itb_port = oldTC->getITBPtr()->getTableWalkerPort();
592 Port *old_dtb_port = oldTC->getDTBPtr()->getTableWalkerPort();
593 Port *new_itb_port = newTC->getITBPtr()->getTableWalkerPort();
594 Port *new_dtb_port = newTC->getDTBPtr()->getTableWalkerPort();
595
596 // Move over any table walker ports if they exist
597 if (new_itb_port)
598 new_itb_port->takeOverFrom(old_itb_port);
599 if (new_dtb_port)
600 new_dtb_port->takeOverFrom(old_dtb_port);
601 newTC->getITBPtr()->takeOverFrom(oldTC->getITBPtr());
602 newTC->getDTBPtr()->takeOverFrom(oldTC->getDTBPtr());
603
604 // Checker whether or not we have to transfer CheckerCPU
605 // objects over in the switch
606 CheckerCPU *oldChecker = oldTC->getCheckerCpuPtr();
607 CheckerCPU *newChecker = newTC->getCheckerCpuPtr();
608 if (oldChecker && newChecker) {
609 Port *old_checker_itb_port =
610 oldChecker->getITBPtr()->getTableWalkerPort();
611 Port *old_checker_dtb_port =
612 oldChecker->getDTBPtr()->getTableWalkerPort();
613 Port *new_checker_itb_port =
614 newChecker->getITBPtr()->getTableWalkerPort();
615 Port *new_checker_dtb_port =
616 newChecker->getDTBPtr()->getTableWalkerPort();
617
618 newChecker->getITBPtr()->takeOverFrom(oldChecker->getITBPtr());
619 newChecker->getDTBPtr()->takeOverFrom(oldChecker->getDTBPtr());
620
621 // Move over any table walker ports if they exist for checker
622 if (new_checker_itb_port)
623 new_checker_itb_port->takeOverFrom(old_checker_itb_port);
624 if (new_checker_dtb_port)
625 new_checker_dtb_port->takeOverFrom(old_checker_dtb_port);
626 }
627 }
628
629 interrupts = oldCPU->interrupts;
630 for (ThreadID tid = 0; tid < numThreads; tid++) {
631 interrupts[tid]->setCPU(this);
632 }
633 oldCPU->interrupts.clear();
634
635 if (FullSystem) {
636 for (ThreadID i = 0; i < size; ++i)
637 threadContexts[i]->profileClear();
638
639 if (profileEvent)
640 schedule(profileEvent, curTick());
641 }
642
643 // All CPUs have an instruction and a data port, and the new CPU's
644 // ports are dangling while the old CPU has its ports connected
645 // already. Unbind the old CPU and then bind the ports of the one
646 // we are switching to.
647 getInstPort().takeOverFrom(&oldCPU->getInstPort());
648 getDataPort().takeOverFrom(&oldCPU->getDataPort());
649 }
650
651 void
652 BaseCPU::flushTLBs()
653 {
654 for (ThreadID i = 0; i < threadContexts.size(); ++i) {
655 ThreadContext &tc(*threadContexts[i]);
656 CheckerCPU *checker(tc.getCheckerCpuPtr());
657
658 tc.getITBPtr()->flushAll();
659 tc.getDTBPtr()->flushAll();
660 if (checker) {
661 checker->getITBPtr()->flushAll();
662 checker->getDTBPtr()->flushAll();
663 }
664 }
665 }
666
667 void
668 BaseCPU::processProfileEvent()
669 {
670 ThreadID size = threadContexts.size();
671
672 for (ThreadID i = 0; i < size; ++i)
673 threadContexts[i]->profileSample();
674
675 schedule(profileEvent, curTick() + params()->profile);
676 }
677
678 void
679 BaseCPU::serialize(CheckpointOut &cp) const
680 {
681 SERIALIZE_SCALAR(instCnt);
682
683 if (!_switchedOut) {
684 /* Unlike _pid, _taskId is not serialized, as they are dynamically
685 * assigned unique ids that are only meaningful for the duration of
686 * a specific run. We will need to serialize the entire taskMap in
687 * system. */
688 SERIALIZE_SCALAR(_pid);
689
690 // Serialize the threads, this is done by the CPU implementation.
691 for (ThreadID i = 0; i < numThreads; ++i) {
692 ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
693 interrupts[i]->serialize(cp);
694 serializeThread(cp, i);
695 }
696 }
697 }
698
699 void
700 BaseCPU::unserialize(CheckpointIn &cp)
701 {
702 UNSERIALIZE_SCALAR(instCnt);
703
704 if (!_switchedOut) {
705 UNSERIALIZE_SCALAR(_pid);
706
707 // Unserialize the threads, this is done by the CPU implementation.
708 for (ThreadID i = 0; i < numThreads; ++i) {
709 ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
710 interrupts[i]->unserialize(cp);
711 unserializeThread(cp, i);
712 }
713 }
714 }
715
716 void
717 BaseCPU::scheduleInstStop(ThreadID tid, Counter insts, const char *cause)
718 {
719 const Tick now(getCurrentInstCount(tid));
720 Event *event(new LocalSimLoopExitEvent(cause, 0));
721
722 threadContexts[tid]->scheduleInstCountEvent(event, now + insts);
723 }
724
725 Tick
726 BaseCPU::getCurrentInstCount(ThreadID tid)
727 {
728 return threadContexts[tid]->getCurrentInstCount();
729 }
730
731 AddressMonitor::AddressMonitor() {
732 armed = false;
733 waiting = false;
734 gotWakeup = false;
735 }
736
737 bool AddressMonitor::doMonitor(PacketPtr pkt) {
738 assert(pkt->req->hasPaddr());
739 if (armed && waiting) {
740 if (pAddr == pkt->getAddr()) {
741 DPRINTF(Mwait,"pAddr=0x%lx invalidated: waking up core\n",
742 pkt->getAddr());
743 waiting = false;
744 return true;
745 }
746 }
747 return false;
748 }
749
750
751 void
752 BaseCPU::traceFunctionsInternal(Addr pc)
753 {
754 if (!debugSymbolTable)
755 return;
756
757 // if pc enters different function, print new function symbol and
758 // update saved range. Otherwise do nothing.
759 if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
760 string sym_str;
761 bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
762 currentFunctionStart,
763 currentFunctionEnd);
764
765 if (!found) {
766 // no symbol found: use addr as label
767 sym_str = csprintf("0x%x", pc);
768 currentFunctionStart = pc;
769 currentFunctionEnd = pc + 1;
770 }
771
772 ccprintf(*functionTraceStream, " (%d)\n%d: %s",
773 curTick() - functionEntryTick, curTick(), sym_str);
774 functionEntryTick = curTick();
775 }
776 }
777
778 bool
779 BaseCPU::waitForRemoteGDB() const
780 {
781 return params()->wait_for_remote_gdb;
782 }