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