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