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