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