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