O3CPU: Make the instcount debugging stuff per-cpu.
[gem5.git] / src / cpu / ozone / cpu_impl.hh
1 /*
2 * Copyright (c) 2006 The Regents of The University of Michigan
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: Kevin Lim
29 * Nathan Binkert
30 */
31
32 #include "config/full_system.hh"
33 #include "config/use_checker.hh"
34
35 #include "arch/isa_traits.hh" // For MachInst
36 #include "base/trace.hh"
37 #include "cpu/base.hh"
38 #include "cpu/simple_thread.hh"
39 #include "cpu/thread_context.hh"
40 #include "cpu/exetrace.hh"
41 #include "cpu/ozone/cpu.hh"
42 #include "cpu/quiesce_event.hh"
43 #include "cpu/static_inst.hh"
44 #include "sim/sim_object.hh"
45 #include "sim/stats.hh"
46
47 #if FULL_SYSTEM
48 #include "arch/faults.hh"
49 #include "arch/alpha/osfpal.hh"
50 #include "arch/tlb.hh"
51 #include "arch/types.hh"
52 #include "arch/kernel_stats.hh"
53 #include "arch/vtophys.hh"
54 #include "base/callback.hh"
55 #include "cpu/profile.hh"
56 #include "sim/faults.hh"
57 #include "sim/sim_events.hh"
58 #include "sim/sim_exit.hh"
59 #include "sim/system.hh"
60 #else // !FULL_SYSTEM
61 #include "sim/process.hh"
62 #endif // FULL_SYSTEM
63
64 #if USE_CHECKER
65 #include "cpu/checker/thread_context.hh"
66 #endif
67
68 using namespace TheISA;
69
70 template <class Impl>
71 OzoneCPU<Impl>::TickEvent::TickEvent(OzoneCPU *c, int w)
72 : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
73 {
74 }
75
76 template <class Impl>
77 void
78 OzoneCPU<Impl>::TickEvent::process()
79 {
80 cpu->tick();
81 }
82
83 template <class Impl>
84 const char *
85 OzoneCPU<Impl>::TickEvent::description() const
86 {
87 return "OzoneCPU tick";
88 }
89
90 template <class Impl>
91 OzoneCPU<Impl>::OzoneCPU(Params *p)
92 #if FULL_SYSTEM
93 : BaseCPU(p), thread(this, 0), tickEvent(this, p->width),
94 #else
95 : BaseCPU(p), thread(this, 0, p->workload[0], 0),
96 tickEvent(this, p->width),
97 #endif
98 #ifndef NDEBUG
99 instcount(0),
100 #endif
101 comm(5, 5)
102 {
103 frontEnd = new FrontEnd(p);
104 backEnd = new BackEnd(p);
105
106 _status = Idle;
107
108 if (p->checker) {
109 #if USE_CHECKER
110 BaseCPU *temp_checker = p->checker;
111 checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
112 #if FULL_SYSTEM
113 checker->setSystem(p->system);
114 #endif
115 checkerTC = new CheckerThreadContext<OzoneTC>(&ozoneTC, checker);
116 thread.tc = checkerTC;
117 tc = checkerTC;
118 #else
119 panic("Checker enabled but not compiled in!");
120 #endif
121 } else {
122 // If checker is not being used, then the xcProxy points
123 // directly to the CPU's ExecContext.
124 checker = NULL;
125 thread.tc = &ozoneTC;
126 tc = &ozoneTC;
127 }
128
129 ozoneTC.cpu = this;
130 ozoneTC.thread = &thread;
131
132 thread.inSyscall = false;
133
134 thread.setStatus(ThreadContext::Suspended);
135 itb = p->itb;
136 dtb = p->dtb;
137 #if FULL_SYSTEM
138 // Setup thread state stuff.
139 thread.cpu = this;
140 thread.setTid(0);
141
142 thread.quiesceEvent = new EndQuiesceEvent(tc);
143
144 system = p->system;
145 physmem = p->system->physmem;
146
147 if (p->profile) {
148 thread.profile = new FunctionProfile(p->system->kernelSymtab);
149 // @todo: This might be better as an ThreadContext instead of OzoneTC
150 Callback *cb =
151 new MakeCallback<OzoneTC,
152 &OzoneTC::dumpFuncProfile>(&ozoneTC);
153 registerExitCallback(cb);
154 }
155
156 // let's fill with a dummy node for now so we don't get a segfault
157 // on the first cycle when there's no node available.
158 static ProfileNode dummyNode;
159 thread.profileNode = &dummyNode;
160 thread.profilePC = 3;
161 #else
162 thread.cpu = this;
163 #endif // !FULL_SYSTEM
164
165 numInst = 0;
166 startNumInst = 0;
167
168 threadContexts.push_back(tc);
169
170 frontEnd->setCPU(this);
171 backEnd->setCPU(this);
172
173 frontEnd->setTC(tc);
174 backEnd->setTC(tc);
175
176 frontEnd->setThreadState(&thread);
177 backEnd->setThreadState(&thread);
178
179 frontEnd->setCommBuffer(&comm);
180 backEnd->setCommBuffer(&comm);
181
182 frontEnd->setBackEnd(backEnd);
183 backEnd->setFrontEnd(frontEnd);
184
185 globalSeqNum = 1;
186
187 lockFlag = 0;
188
189 // Setup rename table, initializing all values to ready.
190 for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
191 thread.renameTable[i] = new DynInst(this);
192 thread.renameTable[i]->setResultReady();
193 }
194
195 frontEnd->renameTable.copyFrom(thread.renameTable);
196 backEnd->renameTable.copyFrom(thread.renameTable);
197
198 #if FULL_SYSTEM
199 Port *mem_port;
200 FunctionalPort *phys_port;
201 VirtualPort *virt_port;
202 phys_port = new FunctionalPort(csprintf("%s-%d-funcport",
203 name(), 0));
204 mem_port = system->physmem->getPort("functional");
205 mem_port->setPeer(phys_port);
206 phys_port->setPeer(mem_port);
207
208 virt_port = new VirtualPort(csprintf("%s-%d-vport",
209 name(), 0));
210 mem_port = system->physmem->getPort("functional");
211 mem_port->setPeer(virt_port);
212 virt_port->setPeer(mem_port);
213
214 thread.setPhysPort(phys_port);
215 thread.setVirtPort(virt_port);
216 #endif
217
218 DPRINTF(OzoneCPU, "OzoneCPU: Created Ozone cpu object.\n");
219 }
220
221 template <class Impl>
222 OzoneCPU<Impl>::~OzoneCPU()
223 {
224 }
225
226 template <class Impl>
227 void
228 OzoneCPU<Impl>::switchOut()
229 {
230 BaseCPU::switchOut();
231 switchCount = 0;
232 // Front end needs state from back end, so switch out the back end first.
233 backEnd->switchOut();
234 frontEnd->switchOut();
235 }
236
237 template <class Impl>
238 void
239 OzoneCPU<Impl>::signalSwitched()
240 {
241 // Only complete the switchout when both the front end and back
242 // end have signalled they are ready to switch.
243 if (++switchCount == 2) {
244 backEnd->doSwitchOut();
245 frontEnd->doSwitchOut();
246 #if USE_CHECKER
247 if (checker)
248 checker->switchOut();
249 #endif
250
251 _status = SwitchedOut;
252 #ifndef NDEBUG
253 // Loop through all registers
254 for (int i = 0; i < AlphaISA::TotalNumRegs; ++i) {
255 assert(thread.renameTable[i] == frontEnd->renameTable[i]);
256
257 assert(thread.renameTable[i] == backEnd->renameTable[i]);
258
259 DPRINTF(OzoneCPU, "Checking if register %i matches.\n", i);
260 }
261 #endif
262
263 if (tickEvent.scheduled())
264 tickEvent.squash();
265 }
266 assert(switchCount <= 2);
267 }
268
269 template <class Impl>
270 void
271 OzoneCPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
272 {
273 BaseCPU::takeOverFrom(oldCPU);
274
275 thread.trapPending = false;
276 thread.inSyscall = false;
277
278 backEnd->takeOverFrom();
279 frontEnd->takeOverFrom();
280 frontEnd->renameTable.copyFrom(thread.renameTable);
281 backEnd->renameTable.copyFrom(thread.renameTable);
282 assert(!tickEvent.scheduled());
283
284 #ifndef NDEBUG
285 // Check rename table.
286 for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
287 assert(thread.renameTable[i]->isResultReady());
288 }
289 #endif
290
291 // @todo: Fix hardcoded number
292 // Clear out any old information in time buffer.
293 for (int i = 0; i < 15; ++i) {
294 comm.advance();
295 }
296
297 // if any of this CPU's ThreadContexts are active, mark the CPU as
298 // running and schedule its tick event.
299 for (int i = 0; i < threadContexts.size(); ++i) {
300 ThreadContext *tc = threadContexts[i];
301 if (tc->status() == ThreadContext::Active &&
302 _status != Running) {
303 _status = Running;
304 tickEvent.schedule(curTick);
305 }
306 }
307 // Nothing running, change status to reflect that we're no longer
308 // switched out.
309 if (_status == SwitchedOut) {
310 _status = Idle;
311 }
312 }
313
314 template <class Impl>
315 void
316 OzoneCPU<Impl>::activateContext(int thread_num, int delay)
317 {
318 // Eventually change this in SMT.
319 assert(thread_num == 0);
320
321 assert(_status == Idle);
322 notIdleFraction++;
323 scheduleTickEvent(delay);
324 _status = Running;
325 #if FULL_SYSTEM
326 if (thread.quiesceEvent && thread.quiesceEvent->scheduled())
327 thread.quiesceEvent->deschedule();
328 #endif
329 thread.setStatus(ThreadContext::Active);
330 frontEnd->wakeFromQuiesce();
331 }
332
333 template <class Impl>
334 void
335 OzoneCPU<Impl>::suspendContext(int thread_num)
336 {
337 // Eventually change this in SMT.
338 assert(thread_num == 0);
339 // @todo: Figure out how to initially set the status properly so
340 // this is running.
341 // assert(_status == Running);
342 notIdleFraction--;
343 unscheduleTickEvent();
344 _status = Idle;
345 }
346
347 template <class Impl>
348 void
349 OzoneCPU<Impl>::deallocateContext(int thread_num, int delay)
350 {
351 // for now, these are equivalent
352 suspendContext(thread_num);
353 }
354
355 template <class Impl>
356 void
357 OzoneCPU<Impl>::haltContext(int thread_num)
358 {
359 // for now, these are equivalent
360 suspendContext(thread_num);
361 }
362
363 template <class Impl>
364 void
365 OzoneCPU<Impl>::regStats()
366 {
367 using namespace Stats;
368
369 BaseCPU::regStats();
370
371 thread.numInsts
372 .name(name() + ".num_insts")
373 .desc("Number of instructions executed")
374 ;
375
376 thread.numMemRefs
377 .name(name() + ".num_refs")
378 .desc("Number of memory references")
379 ;
380
381 notIdleFraction
382 .name(name() + ".not_idle_fraction")
383 .desc("Percentage of non-idle cycles")
384 ;
385
386 idleFraction
387 .name(name() + ".idle_fraction")
388 .desc("Percentage of idle cycles")
389 ;
390
391 quiesceCycles
392 .name(name() + ".quiesce_cycles")
393 .desc("Number of cycles spent in quiesce")
394 ;
395
396 idleFraction = constant(1.0) - notIdleFraction;
397
398 frontEnd->regStats();
399 backEnd->regStats();
400 }
401
402 template <class Impl>
403 void
404 OzoneCPU<Impl>::resetStats()
405 {
406 // startNumInst = numInst;
407 notIdleFraction = (_status != Idle);
408 }
409
410 template <class Impl>
411 void
412 OzoneCPU<Impl>::init()
413 {
414 BaseCPU::init();
415
416 // Mark this as in syscall so it won't need to squash
417 thread.inSyscall = true;
418 #if FULL_SYSTEM
419 for (int i = 0; i < threadContexts.size(); ++i) {
420 ThreadContext *tc = threadContexts[i];
421
422 // initialize CPU, including PC
423 TheISA::initCPU(tc, tc->contextId());
424 }
425 #endif
426 frontEnd->renameTable.copyFrom(thread.renameTable);
427 backEnd->renameTable.copyFrom(thread.renameTable);
428
429 thread.inSyscall = false;
430 }
431
432 template <class Impl>
433 Port *
434 OzoneCPU<Impl>::getPort(const std::string &if_name, int idx)
435 {
436 if (if_name == "dcache_port")
437 return backEnd->getDcachePort();
438 else if (if_name == "icache_port")
439 return frontEnd->getIcachePort();
440 else
441 panic("No Such Port\n");
442 }
443
444 template <class Impl>
445 void
446 OzoneCPU<Impl>::serialize(std::ostream &os)
447 {
448 BaseCPU::serialize(os);
449 SERIALIZE_ENUM(_status);
450 nameOut(os, csprintf("%s.tc", name()));
451 ozoneTC.serialize(os);
452 nameOut(os, csprintf("%s.tickEvent", name()));
453 tickEvent.serialize(os);
454
455 // Use SimpleThread's ability to checkpoint to make it easier to
456 // write out the registers. Also make this static so it doesn't
457 // get instantiated multiple times (causes a panic in statistics).
458 static SimpleThread temp;
459
460 nameOut(os, csprintf("%s.xc.0", name()));
461 temp.copyTC(thread.getTC());
462 temp.serialize(os);
463 }
464
465 template <class Impl>
466 void
467 OzoneCPU<Impl>::unserialize(Checkpoint *cp, const std::string &section)
468 {
469 BaseCPU::unserialize(cp, section);
470 UNSERIALIZE_ENUM(_status);
471 ozoneTC.unserialize(cp, csprintf("%s.tc", section));
472 tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
473
474 // Use SimpleThread's ability to checkpoint to make it easier to
475 // read in the registers. Also make this static so it doesn't
476 // get instantiated multiple times (causes a panic in statistics).
477 static SimpleThread temp;
478
479 temp.copyTC(thread.getTC());
480 temp.unserialize(cp, csprintf("%s.xc.0", section));
481 thread.getTC()->copyArchRegs(temp.getTC());
482 }
483
484 template <class Impl>
485 Fault
486 OzoneCPU<Impl>::copySrcTranslate(Addr src)
487 {
488 panic("Copy not implemented!\n");
489 return NoFault;
490 #if 0
491 static bool no_warn = true;
492 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
493 // Only support block sizes of 64 atm.
494 assert(blk_size == 64);
495 int offset = src & (blk_size - 1);
496
497 // Make sure block doesn't span page
498 if (no_warn &&
499 (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) &&
500 (src >> 40) != 0xfffffc) {
501 warn("Copied block source spans pages %x.", src);
502 no_warn = false;
503 }
504
505 memReq->reset(src & ~(blk_size - 1), blk_size);
506
507 // translate to physical address
508 Fault fault = tc->translateDataReadReq(memReq);
509
510 assert(fault != Alignment_Fault);
511
512 if (fault == NoFault) {
513 tc->copySrcAddr = src;
514 tc->copySrcPhysAddr = memReq->paddr + offset;
515 } else {
516 tc->copySrcAddr = 0;
517 tc->copySrcPhysAddr = 0;
518 }
519 return fault;
520 #endif
521 }
522
523 template <class Impl>
524 Fault
525 OzoneCPU<Impl>::copy(Addr dest)
526 {
527 panic("Copy not implemented!\n");
528 return NoFault;
529 #if 0
530 static bool no_warn = true;
531 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
532 // Only support block sizes of 64 atm.
533 assert(blk_size == 64);
534 uint8_t data[blk_size];
535 //assert(tc->copySrcAddr);
536 int offset = dest & (blk_size - 1);
537
538 // Make sure block doesn't span page
539 if (no_warn &&
540 (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) &&
541 (dest >> 40) != 0xfffffc) {
542 no_warn = false;
543 warn("Copied block destination spans pages %x. ", dest);
544 }
545
546 memReq->reset(dest & ~(blk_size -1), blk_size);
547 // translate to physical address
548 Fault fault = tc->translateDataWriteReq(memReq);
549
550 assert(fault != Alignment_Fault);
551
552 if (fault == NoFault) {
553 Addr dest_addr = memReq->paddr + offset;
554 // Need to read straight from memory since we have more than 8 bytes.
555 memReq->paddr = tc->copySrcPhysAddr;
556 tc->mem->read(memReq, data);
557 memReq->paddr = dest_addr;
558 tc->mem->write(memReq, data);
559 if (dcacheInterface) {
560 memReq->cmd = Copy;
561 memReq->completionEvent = NULL;
562 memReq->paddr = tc->copySrcPhysAddr;
563 memReq->dest = dest_addr;
564 memReq->size = 64;
565 memReq->time = curTick;
566 dcacheInterface->access(memReq);
567 }
568 }
569 return fault;
570 #endif
571 }
572
573 #if FULL_SYSTEM
574 template <class Impl>
575 Addr
576 OzoneCPU<Impl>::dbg_vtophys(Addr addr)
577 {
578 return vtophys(tc, addr);
579 }
580 #endif // FULL_SYSTEM
581
582 #if FULL_SYSTEM
583 template <class Impl>
584 void
585 OzoneCPU<Impl>::postInterrupt(int int_num, int index)
586 {
587 BaseCPU::postInterrupt(int_num, index);
588
589 if (_status == Idle) {
590 DPRINTF(IPI,"Suspended Processor awoke\n");
591 // thread.activate();
592 // Hack for now. Otherwise might have to go through the tc, or
593 // I need to figure out what's the right thing to call.
594 activateContext(thread.threadId(), 1);
595 }
596 }
597 #endif // FULL_SYSTEM
598
599 /* start simulation, program loaded, processor precise state initialized */
600 template <class Impl>
601 void
602 OzoneCPU<Impl>::tick()
603 {
604 DPRINTF(OzoneCPU, "\n\nOzoneCPU: Ticking cpu.\n");
605
606 _status = Running;
607 thread.renameTable[ZeroReg]->setIntResult(0);
608 thread.renameTable[ZeroReg+TheISA::FP_Base_DepTag]->
609 setDoubleResult(0.0);
610
611 comm.advance();
612 frontEnd->tick();
613 backEnd->tick();
614
615 // check for instruction-count-based events
616 comInstEventQueue[0]->serviceEvents(numInst);
617
618 if (!tickEvent.scheduled() && _status == Running)
619 tickEvent.schedule(curTick + ticks(1));
620 }
621
622 template <class Impl>
623 void
624 OzoneCPU<Impl>::squashFromTC()
625 {
626 thread.inSyscall = true;
627 backEnd->generateTCEvent();
628 }
629
630 #if !FULL_SYSTEM
631 template <class Impl>
632 void
633 OzoneCPU<Impl>::syscall(uint64_t &callnum)
634 {
635 // Not sure this copy is needed, depending on how the TC proxy is made.
636 thread.renameTable.copyFrom(backEnd->renameTable);
637
638 thread.inSyscall = true;
639
640 thread.funcExeInst++;
641
642 DPRINTF(OzoneCPU, "FuncExeInst: %i\n", thread.funcExeInst);
643
644 thread.process->syscall(callnum, tc);
645
646 thread.funcExeInst--;
647
648 thread.inSyscall = false;
649
650 frontEnd->renameTable.copyFrom(thread.renameTable);
651 backEnd->renameTable.copyFrom(thread.renameTable);
652 }
653
654 template <class Impl>
655 void
656 OzoneCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
657 {
658 // check for error condition. Alpha syscall convention is to
659 // indicate success/failure in reg a3 (r19) and put the
660 // return value itself in the standard return value reg (v0).
661 if (return_value.successful()) {
662 // no error
663 thread.renameTable[SyscallSuccessReg]->setIntResult(0);
664 thread.renameTable[ReturnValueReg]->setIntResult(
665 return_value.value());
666 } else {
667 // got an error, return details
668 thread.renameTable[SyscallSuccessReg]->setIntResult((IntReg) -1);
669 thread.renameTable[ReturnValueReg]->setIntResult(
670 -return_value.value());
671 }
672 }
673 #else
674 template <class Impl>
675 Fault
676 OzoneCPU<Impl>::hwrei()
677 {
678 // Need to move this to ISA code
679 // May also need to make this per thread
680
681 lockFlag = false;
682 lockAddrList.clear();
683 thread.kernelStats->hwrei();
684
685 // FIXME: XXX check for interrupts? XXX
686 return NoFault;
687 }
688
689 template <class Impl>
690 void
691 OzoneCPU<Impl>::processInterrupts()
692 {
693 // Check for interrupts here. For now can copy the code that
694 // exists within isa_fullsys_traits.hh. Also assume that thread 0
695 // is the one that handles the interrupts.
696
697 // Check if there are any outstanding interrupts
698 //Handle the interrupts
699 Fault interrupt = this->interrupts->getInterrupt(thread.getTC());
700
701 if (interrupt != NoFault) {
702 this->interrupts->updateIntrInfo(thread.getTC());
703 interrupt->invoke(thread.getTC());
704 }
705 }
706
707 template <class Impl>
708 bool
709 OzoneCPU<Impl>::simPalCheck(int palFunc)
710 {
711 // Need to move this to ISA code
712 // May also need to make this per thread
713 thread.kernelStats->callpal(palFunc, tc);
714
715 switch (palFunc) {
716 case PAL::halt:
717 haltContext(thread.threadId());
718 if (--System::numSystemsRunning == 0)
719 exitSimLoop("all cpus halted");
720 break;
721
722 case PAL::bpt:
723 case PAL::bugchk:
724 if (system->breakpoint())
725 return false;
726 break;
727 }
728
729 return true;
730 }
731 #endif
732
733 template <class Impl>
734 BaseCPU *
735 OzoneCPU<Impl>::OzoneTC::getCpuPtr()
736 {
737 return cpu;
738 }
739
740 template <class Impl>
741 void
742 OzoneCPU<Impl>::OzoneTC::setStatus(Status new_status)
743 {
744 thread->setStatus(new_status);
745 }
746
747 template <class Impl>
748 void
749 OzoneCPU<Impl>::OzoneTC::activate(int delay)
750 {
751 cpu->activateContext(thread->threadId(), delay);
752 }
753
754 /// Set the status to Suspended.
755 template <class Impl>
756 void
757 OzoneCPU<Impl>::OzoneTC::suspend()
758 {
759 cpu->suspendContext(thread->threadId());
760 }
761
762 /// Set the status to Unallocated.
763 template <class Impl>
764 void
765 OzoneCPU<Impl>::OzoneTC::deallocate(int delay)
766 {
767 cpu->deallocateContext(thread->threadId(), delay);
768 }
769
770 /// Set the status to Halted.
771 template <class Impl>
772 void
773 OzoneCPU<Impl>::OzoneTC::halt()
774 {
775 cpu->haltContext(thread->threadId());
776 }
777
778 #if FULL_SYSTEM
779 template <class Impl>
780 void
781 OzoneCPU<Impl>::OzoneTC::dumpFuncProfile()
782 {
783 thread->dumpFuncProfile();
784 }
785 #endif
786
787 template <class Impl>
788 void
789 OzoneCPU<Impl>::OzoneTC::takeOverFrom(ThreadContext *old_context)
790 {
791 // some things should already be set up
792 #if FULL_SYSTEM
793 assert(getSystemPtr() == old_context->getSystemPtr());
794 #else
795 assert(getProcessPtr() == old_context->getProcessPtr());
796 #endif
797
798 // copy over functional state
799 setStatus(old_context->status());
800 copyArchRegs(old_context);
801 setCpuId(old_context->cpuId());
802 setContextId(old_context->contextId());
803
804 thread->setInst(old_context->getInst());
805 #if !FULL_SYSTEM
806 setFuncExeInst(old_context->readFuncExeInst());
807 #else
808 EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent();
809 if (other_quiesce) {
810 // Point the quiesce event's TC at this TC so that it wakes up
811 // the proper CPU.
812 other_quiesce->tc = this;
813 }
814 if (thread->quiesceEvent) {
815 thread->quiesceEvent->tc = this;
816 }
817
818 // Copy kernel stats pointer from old context.
819 thread->kernelStats = old_context->getKernelStats();
820 // storeCondFailures = 0;
821 cpu->lockFlag = false;
822 #endif
823
824 old_context->setStatus(ThreadContext::Unallocated);
825 }
826
827 template <class Impl>
828 void
829 OzoneCPU<Impl>::OzoneTC::regStats(const std::string &name)
830 {
831 #if FULL_SYSTEM
832 thread->kernelStats = new TheISA::Kernel::Statistics(cpu->system);
833 thread->kernelStats->regStats(name + ".kern");
834 #endif
835 }
836
837 template <class Impl>
838 void
839 OzoneCPU<Impl>::OzoneTC::serialize(std::ostream &os)
840 {
841 // Once serialization is added, serialize the quiesce event and
842 // kernel stats. Will need to make sure there aren't multiple
843 // things that serialize them.
844 }
845
846 template <class Impl>
847 void
848 OzoneCPU<Impl>::OzoneTC::unserialize(Checkpoint *cp, const std::string &section)
849 { }
850
851 #if FULL_SYSTEM
852 template <class Impl>
853 EndQuiesceEvent *
854 OzoneCPU<Impl>::OzoneTC::getQuiesceEvent()
855 {
856 return thread->quiesceEvent;
857 }
858
859 template <class Impl>
860 Tick
861 OzoneCPU<Impl>::OzoneTC::readLastActivate()
862 {
863 return thread->lastActivate;
864 }
865
866 template <class Impl>
867 Tick
868 OzoneCPU<Impl>::OzoneTC::readLastSuspend()
869 {
870 return thread->lastSuspend;
871 }
872
873 template <class Impl>
874 void
875 OzoneCPU<Impl>::OzoneTC::profileClear()
876 {
877 thread->profileClear();
878 }
879
880 template <class Impl>
881 void
882 OzoneCPU<Impl>::OzoneTC::profileSample()
883 {
884 thread->profileSample();
885 }
886 #endif
887
888 template <class Impl>
889 int
890 OzoneCPU<Impl>::OzoneTC::threadId()
891 {
892 return thread->threadId();
893 }
894
895 template <class Impl>
896 TheISA::MachInst
897 OzoneCPU<Impl>::OzoneTC::getInst()
898 {
899 return thread->getInst();
900 }
901
902 template <class Impl>
903 void
904 OzoneCPU<Impl>::OzoneTC::copyArchRegs(ThreadContext *tc)
905 {
906 thread->PC = tc->readPC();
907 thread->nextPC = tc->readNextPC();
908
909 cpu->frontEnd->setPC(thread->PC);
910 cpu->frontEnd->setNextPC(thread->nextPC);
911
912 // First loop through the integer registers.
913 for (int i = 0; i < TheISA::NumIntRegs; ++i) {
914 /* DPRINTF(OzoneCPU, "Copying over register %i, had data %lli, "
915 "now has data %lli.\n",
916 i, thread->renameTable[i]->readIntResult(),
917 tc->readIntReg(i));
918 */
919 thread->renameTable[i]->setIntResult(tc->readIntReg(i));
920 }
921
922 // Then loop through the floating point registers.
923 for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
924 int fp_idx = i + TheISA::FP_Base_DepTag;
925 thread->renameTable[fp_idx]->setIntResult(tc->readFloatRegBits(i));
926 }
927
928 #if !FULL_SYSTEM
929 thread->funcExeInst = tc->readFuncExeInst();
930 #endif
931
932 // Need to copy the TC values into the current rename table,
933 // copy the misc regs.
934 copyMiscRegs(tc, this);
935 }
936
937 template <class Impl>
938 void
939 OzoneCPU<Impl>::OzoneTC::clearArchRegs()
940 {
941 panic("Unimplemented!");
942 }
943
944 template <class Impl>
945 uint64_t
946 OzoneCPU<Impl>::OzoneTC::readIntReg(int reg_idx)
947 {
948 return thread->renameTable[reg_idx]->readIntResult();
949 }
950
951 template <class Impl>
952 TheISA::FloatReg
953 OzoneCPU<Impl>::OzoneTC::readFloatReg(int reg_idx, int width)
954 {
955 int idx = reg_idx + TheISA::FP_Base_DepTag;
956 switch(width) {
957 case 32:
958 return thread->renameTable[idx]->readFloatResult();
959 case 64:
960 return thread->renameTable[idx]->readDoubleResult();
961 default:
962 panic("Unsupported width!");
963 return 0;
964 }
965 }
966
967 template <class Impl>
968 double
969 OzoneCPU<Impl>::OzoneTC::readFloatReg(int reg_idx)
970 {
971 int idx = reg_idx + TheISA::FP_Base_DepTag;
972 return thread->renameTable[idx]->readFloatResult();
973 }
974
975 template <class Impl>
976 uint64_t
977 OzoneCPU<Impl>::OzoneTC::readFloatRegBits(int reg_idx, int width)
978 {
979 int idx = reg_idx + TheISA::FP_Base_DepTag;
980 return thread->renameTable[idx]->readIntResult();
981 }
982
983 template <class Impl>
984 uint64_t
985 OzoneCPU<Impl>::OzoneTC::readFloatRegBits(int reg_idx)
986 {
987 int idx = reg_idx + TheISA::FP_Base_DepTag;
988 return thread->renameTable[idx]->readIntResult();
989 }
990
991 template <class Impl>
992 void
993 OzoneCPU<Impl>::OzoneTC::setIntReg(int reg_idx, uint64_t val)
994 {
995 thread->renameTable[reg_idx]->setIntResult(val);
996
997 if (!thread->inSyscall) {
998 cpu->squashFromTC();
999 }
1000 }
1001
1002 template <class Impl>
1003 void
1004 OzoneCPU<Impl>::OzoneTC::setFloatReg(int reg_idx, FloatReg val, int width)
1005 {
1006 int idx = reg_idx + TheISA::FP_Base_DepTag;
1007 switch(width) {
1008 case 32:
1009 panic("Unimplemented!");
1010 break;
1011 case 64:
1012 thread->renameTable[idx]->setDoubleResult(val);
1013 break;
1014 default:
1015 panic("Unsupported width!");
1016 }
1017
1018 if (!thread->inSyscall) {
1019 cpu->squashFromTC();
1020 }
1021 }
1022
1023 template <class Impl>
1024 void
1025 OzoneCPU<Impl>::OzoneTC::setFloatReg(int reg_idx, FloatReg val)
1026 {
1027 int idx = reg_idx + TheISA::FP_Base_DepTag;
1028
1029 thread->renameTable[idx]->setDoubleResult(val);
1030
1031 if (!thread->inSyscall) {
1032 cpu->squashFromTC();
1033 }
1034 }
1035
1036 template <class Impl>
1037 void
1038 OzoneCPU<Impl>::OzoneTC::setFloatRegBits(int reg_idx, FloatRegBits val,
1039 int width)
1040 {
1041 panic("Unimplemented!");
1042 }
1043
1044 template <class Impl>
1045 void
1046 OzoneCPU<Impl>::OzoneTC::setFloatRegBits(int reg_idx, FloatRegBits val)
1047 {
1048 panic("Unimplemented!");
1049 }
1050
1051 template <class Impl>
1052 void
1053 OzoneCPU<Impl>::OzoneTC::setPC(Addr val)
1054 {
1055 thread->PC = val;
1056 cpu->frontEnd->setPC(val);
1057
1058 if (!thread->inSyscall) {
1059 cpu->squashFromTC();
1060 }
1061 }
1062
1063 template <class Impl>
1064 void
1065 OzoneCPU<Impl>::OzoneTC::setNextPC(Addr val)
1066 {
1067 thread->nextPC = val;
1068 cpu->frontEnd->setNextPC(val);
1069
1070 if (!thread->inSyscall) {
1071 cpu->squashFromTC();
1072 }
1073 }
1074
1075 template <class Impl>
1076 TheISA::MiscReg
1077 OzoneCPU<Impl>::OzoneTC::readMiscRegNoEffect(int misc_reg)
1078 {
1079 return thread->miscRegFile.readRegNoEffect(misc_reg);
1080 }
1081
1082 template <class Impl>
1083 TheISA::MiscReg
1084 OzoneCPU<Impl>::OzoneTC::readMiscReg(int misc_reg)
1085 {
1086 return thread->miscRegFile.readReg(misc_reg, this);
1087 }
1088
1089 template <class Impl>
1090 void
1091 OzoneCPU<Impl>::OzoneTC::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
1092 {
1093 // Needs to setup a squash event unless we're in syscall mode
1094 thread->miscRegFile.setRegNoEffect(misc_reg, val);
1095
1096 if (!thread->inSyscall) {
1097 cpu->squashFromTC();
1098 }
1099 }
1100
1101 template <class Impl>
1102 void
1103 OzoneCPU<Impl>::OzoneTC::setMiscReg(int misc_reg, const MiscReg &val)
1104 {
1105 // Needs to setup a squash event unless we're in syscall mode
1106 thread->miscRegFile.setReg(misc_reg, val, this);
1107
1108 if (!thread->inSyscall) {
1109 cpu->squashFromTC();
1110 }
1111 }