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