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