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