2 * Copyright (c) 2006 The Regents of The University of Michigan
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.
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.
32 #include "arch/alpha/osfpal.hh"
33 #include "arch/isa_traits.hh" // For MachInst
34 #include "arch/kernel_stats.hh"
35 #include "arch/tlb.hh"
36 #include "arch/types.hh"
37 #include "arch/vtophys.hh"
38 #include "base/callback.hh"
39 #include "base/trace.hh"
40 #include "config/the_isa.hh"
41 #include "cpu/checker/thread_context.hh"
42 #include "cpu/ozone/cpu.hh"
43 #include "cpu/base.hh"
44 #include "cpu/exetrace.hh"
45 #include "cpu/profile.hh"
46 #include "cpu/quiesce_event.hh"
47 #include "cpu/simple_thread.hh"
48 #include "cpu/static_inst.hh"
49 #include "cpu/thread_context.hh"
50 #include "sim/faults.hh"
51 #include "sim/full_system.hh"
52 #include "sim/process.hh"
53 #include "sim/sim_events.hh"
54 #include "sim/sim_exit.hh"
55 #include "sim/sim_object.hh"
56 #include "sim/stats.hh"
57 #include "sim/system.hh"
59 using namespace TheISA;
62 OzoneCPU<Impl>::TickEvent::TickEvent(OzoneCPU *c, int w)
63 : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
69 OzoneCPU<Impl>::TickEvent::process()
76 OzoneCPU<Impl>::TickEvent::description() const
78 return "OzoneCPU tick";
82 OzoneCPU<Impl>::OzoneCPU(Params *p)
83 : BaseCPU(p), thread(this, 0, p->workload[0], 0), tickEvent(this,
90 frontEnd = new FrontEnd(p);
91 backEnd = new BackEnd(p);
96 BaseCPU *temp_checker = p->checker;
97 checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
98 checker->setSystem(p->system);
99 checkerTC = new CheckerThreadContext<OzoneTC>(&ozoneTC, checker);
100 thread.tc = checkerTC;
103 // If checker is not being used, then the xcProxy points
104 // directly to the CPU's ExecContext.
106 thread.tc = &ozoneTC;
111 ozoneTC.thread = &thread;
113 thread.inSyscall = false;
119 // Setup thread state stuff.
123 thread.quiesceEvent = new EndQuiesceEvent(tc);
126 physmem = p->system->physmem;
129 thread.profile = new FunctionProfile(p->system->kernelSymtab);
130 // @todo: This might be better as an ThreadContext instead of
133 new MakeCallback<OzoneTC,
134 &OzoneTC::dumpFuncProfile>(&ozoneTC);
135 registerExitCallback(cb);
138 // let's fill with a dummy node for now so we don't get a segfault
139 // on the first cycle when there's no node available.
140 static ProfileNode dummyNode;
141 thread.profileNode = &dummyNode;
142 thread.profilePC = 3;
150 threadContexts.push_back(tc);
152 frontEnd->setCPU(this);
153 backEnd->setCPU(this);
158 frontEnd->setThreadState(&thread);
159 backEnd->setThreadState(&thread);
161 frontEnd->setCommBuffer(&comm);
162 backEnd->setCommBuffer(&comm);
164 frontEnd->setBackEnd(backEnd);
165 backEnd->setFrontEnd(frontEnd);
171 // Setup rename table, initializing all values to ready.
172 for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
173 thread.renameTable[i] = new DynInst(this);
174 thread.renameTable[i]->setResultReady();
177 frontEnd->renameTable.copyFrom(thread.renameTable);
178 backEnd->renameTable.copyFrom(thread.renameTable);
180 thread.connectMemPorts(tc);
182 DPRINTF(OzoneCPU, "OzoneCPU: Created Ozone cpu object.\n");
185 template <class Impl>
186 OzoneCPU<Impl>::~OzoneCPU()
190 template <class Impl>
192 OzoneCPU<Impl>::switchOut()
194 BaseCPU::switchOut();
196 // Front end needs state from back end, so switch out the back end first.
197 backEnd->switchOut();
198 frontEnd->switchOut();
201 template <class Impl>
203 OzoneCPU<Impl>::signalSwitched()
205 // Only complete the switchout when both the front end and back
206 // end have signalled they are ready to switch.
207 if (++switchCount == 2) {
208 backEnd->doSwitchOut();
209 frontEnd->doSwitchOut();
212 checker->switchOut();
214 _status = SwitchedOut;
216 // Loop through all registers
217 for (int i = 0; i < AlphaISA::TotalNumRegs; ++i) {
218 assert(thread.renameTable[i] == frontEnd->renameTable[i]);
220 assert(thread.renameTable[i] == backEnd->renameTable[i]);
222 DPRINTF(OzoneCPU, "Checking if register %i matches.\n", i);
226 if (tickEvent.scheduled())
229 assert(switchCount <= 2);
232 template <class Impl>
234 OzoneCPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
236 BaseCPU::takeOverFrom(oldCPU);
238 thread.trapPending = false;
239 thread.inSyscall = false;
241 backEnd->takeOverFrom();
242 frontEnd->takeOverFrom();
243 frontEnd->renameTable.copyFrom(thread.renameTable);
244 backEnd->renameTable.copyFrom(thread.renameTable);
245 assert(!tickEvent.scheduled());
248 // Check rename table.
249 for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
250 assert(thread.renameTable[i]->isResultReady());
254 // @todo: Fix hardcoded number
255 // Clear out any old information in time buffer.
256 for (int i = 0; i < 15; ++i) {
260 // if any of this CPU's ThreadContexts are active, mark the CPU as
261 // running and schedule its tick event.
262 for (int i = 0; i < threadContexts.size(); ++i) {
263 ThreadContext *tc = threadContexts[i];
264 if (tc->status() == ThreadContext::Active &&
265 _status != Running) {
267 tickEvent.schedule(curTick());
270 // Nothing running, change status to reflect that we're no longer
272 if (_status == SwitchedOut) {
277 template <class Impl>
279 OzoneCPU<Impl>::activateContext(int thread_num, int delay)
281 // Eventually change this in SMT.
282 assert(thread_num == 0);
284 assert(_status == Idle);
286 scheduleTickEvent(delay);
288 if (thread.quiesceEvent && thread.quiesceEvent->scheduled())
289 thread.quiesceEvent->deschedule();
290 thread.setStatus(ThreadContext::Active);
291 frontEnd->wakeFromQuiesce();
294 template <class Impl>
296 OzoneCPU<Impl>::suspendContext(int thread_num)
298 // Eventually change this in SMT.
299 assert(thread_num == 0);
300 // @todo: Figure out how to initially set the status properly so
302 // assert(_status == Running);
304 unscheduleTickEvent();
308 template <class Impl>
310 OzoneCPU<Impl>::deallocateContext(int thread_num, int delay)
312 // for now, these are equivalent
313 suspendContext(thread_num);
316 template <class Impl>
318 OzoneCPU<Impl>::haltContext(int thread_num)
320 // for now, these are equivalent
321 suspendContext(thread_num);
324 template <class Impl>
326 OzoneCPU<Impl>::regStats()
328 using namespace Stats;
333 .name(name() + ".num_insts")
334 .desc("Number of instructions executed")
338 .name(name() + ".num_refs")
339 .desc("Number of memory references")
343 .name(name() + ".not_idle_fraction")
344 .desc("Percentage of non-idle cycles")
348 .name(name() + ".idle_fraction")
349 .desc("Percentage of idle cycles")
353 .name(name() + ".quiesce_cycles")
354 .desc("Number of cycles spent in quiesce")
357 idleFraction = constant(1.0) - notIdleFraction;
359 frontEnd->regStats();
363 template <class Impl>
365 OzoneCPU<Impl>::resetStats()
367 // startNumInst = numInst;
368 notIdleFraction = (_status != Idle);
371 template <class Impl>
373 OzoneCPU<Impl>::init()
377 // Mark this as in syscall so it won't need to squash
378 thread.inSyscall = true;
380 for (int i = 0; i < threadContexts.size(); ++i) {
381 ThreadContext *tc = threadContexts[i];
383 // initialize CPU, including PC
384 TheISA::initCPU(tc, tc->contextId());
387 frontEnd->renameTable.copyFrom(thread.renameTable);
388 backEnd->renameTable.copyFrom(thread.renameTable);
390 thread.inSyscall = false;
393 template <class Impl>
395 OzoneCPU<Impl>::serialize(std::ostream &os)
397 BaseCPU::serialize(os);
398 SERIALIZE_ENUM(_status);
399 nameOut(os, csprintf("%s.tc", name()));
400 ozoneTC.serialize(os);
401 nameOut(os, csprintf("%s.tickEvent", name()));
402 tickEvent.serialize(os);
404 // Use SimpleThread's ability to checkpoint to make it easier to
405 // write out the registers. Also make this static so it doesn't
406 // get instantiated multiple times (causes a panic in statistics).
407 static SimpleThread temp;
409 nameOut(os, csprintf("%s.xc.0", name()));
410 temp.copyTC(thread.getTC());
414 template <class Impl>
416 OzoneCPU<Impl>::unserialize(Checkpoint *cp, const std::string §ion)
418 BaseCPU::unserialize(cp, section);
419 UNSERIALIZE_ENUM(_status);
420 ozoneTC.unserialize(cp, csprintf("%s.tc", section));
421 tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
423 // Use SimpleThread's ability to checkpoint to make it easier to
424 // read in the registers. Also make this static so it doesn't
425 // get instantiated multiple times (causes a panic in statistics).
426 static SimpleThread temp;
428 temp.copyTC(thread.getTC());
429 temp.unserialize(cp, csprintf("%s.xc.0", section));
430 thread.getTC()->copyArchRegs(temp.getTC());
433 template <class Impl>
435 OzoneCPU<Impl>::dbg_vtophys(Addr addr)
437 return vtophys(tc, addr);
440 template <class Impl>
442 OzoneCPU<Impl>::wakeup()
444 if (_status == Idle) {
445 DPRINTF(IPI,"Suspended Processor awoke\n");
446 // Hack for now. Otherwise might have to go through the tc, or
447 // I need to figure out what's the right thing to call.
448 activateContext(thread.threadId(), 1);
452 /* start simulation, program loaded, processor precise state initialized */
453 template <class Impl>
455 OzoneCPU<Impl>::tick()
457 DPRINTF(OzoneCPU, "\n\nOzoneCPU: Ticking cpu.\n");
460 thread.renameTable[ZeroReg]->setIntResult(0);
461 thread.renameTable[ZeroReg+TheISA::FP_Base_DepTag]->
462 setDoubleResult(0.0);
468 // check for instruction-count-based events
469 comInstEventQueue[0]->serviceEvents(numInst);
471 if (!tickEvent.scheduled() && _status == Running)
472 tickEvent.schedule(curTick() + ticks(1));
475 template <class Impl>
477 OzoneCPU<Impl>::squashFromTC()
479 thread.inSyscall = true;
480 backEnd->generateTCEvent();
483 template <class Impl>
485 OzoneCPU<Impl>::syscall(uint64_t &callnum)
487 // Not sure this copy is needed, depending on how the TC proxy is made.
488 thread.renameTable.copyFrom(backEnd->renameTable);
490 thread.inSyscall = true;
492 thread.funcExeInst++;
494 DPRINTF(OzoneCPU, "FuncExeInst: %i\n", thread.funcExeInst);
496 thread.process->syscall(callnum, tc);
498 thread.funcExeInst--;
500 thread.inSyscall = false;
502 frontEnd->renameTable.copyFrom(thread.renameTable);
503 backEnd->renameTable.copyFrom(thread.renameTable);
506 template <class Impl>
508 OzoneCPU<Impl>::hwrei()
510 // Need to move this to ISA code
511 // May also need to make this per thread
514 lockAddrList.clear();
515 thread.kernelStats->hwrei();
517 // FIXME: XXX check for interrupts? XXX
521 template <class Impl>
523 OzoneCPU<Impl>::processInterrupts()
525 // Check for interrupts here. For now can copy the code that
526 // exists within isa_fullsys_traits.hh. Also assume that thread 0
527 // is the one that handles the interrupts.
529 // Check if there are any outstanding interrupts
530 //Handle the interrupts
531 Fault interrupt = this->interrupts->getInterrupt(thread.getTC());
533 if (interrupt != NoFault) {
534 this->interrupts->updateIntrInfo(thread.getTC());
535 interrupt->invoke(thread.getTC());
539 template <class Impl>
541 OzoneCPU<Impl>::simPalCheck(int palFunc)
543 // Need to move this to ISA code
544 // May also need to make this per thread
545 thread.kernelStats->callpal(palFunc, tc);
549 haltContext(thread.threadId());
550 if (--System::numSystemsRunning == 0)
551 exitSimLoop("all cpus halted");
556 if (system->breakpoint())
564 template <class Impl>
566 OzoneCPU<Impl>::OzoneTC::getCpuPtr()
571 template <class Impl>
573 OzoneCPU<Impl>::OzoneTC::setStatus(Status new_status)
575 thread->setStatus(new_status);
578 template <class Impl>
580 OzoneCPU<Impl>::OzoneTC::activate(int delay)
582 cpu->activateContext(thread->threadId(), delay);
585 /// Set the status to Suspended.
586 template <class Impl>
588 OzoneCPU<Impl>::OzoneTC::suspend()
590 cpu->suspendContext(thread->threadId());
593 /// Set the status to Halted.
594 template <class Impl>
596 OzoneCPU<Impl>::OzoneTC::halt()
598 cpu->haltContext(thread->threadId());
601 template <class Impl>
603 OzoneCPU<Impl>::OzoneTC::dumpFuncProfile()
605 thread->dumpFuncProfile();
608 template <class Impl>
610 OzoneCPU<Impl>::OzoneTC::takeOverFrom(ThreadContext *old_context)
612 // some things should already be set up
613 assert(getSystemPtr() == old_context->getSystemPtr());
614 assert(getProcessPtr() == old_context->getProcessPtr());
616 // copy over functional state
617 setStatus(old_context->status());
618 copyArchRegs(old_context);
619 setCpuId(old_context->cpuId());
620 setContextId(old_context->contextId());
622 setFuncExeInst(old_context->readFuncExeInst());
623 EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent();
625 // Point the quiesce event's TC at this TC so that it wakes up
627 other_quiesce->tc = this;
629 if (thread->quiesceEvent) {
630 thread->quiesceEvent->tc = this;
633 // Copy kernel stats pointer from old context.
634 thread->kernelStats = old_context->getKernelStats();
635 // storeCondFailures = 0;
636 cpu->lockFlag = false;
639 old_context->setStatus(ThreadContext::Halted);
642 template <class Impl>
644 OzoneCPU<Impl>::OzoneTC::regStats(const std::string &name)
647 thread->kernelStats = new TheISA::Kernel::Statistics(cpu->system);
648 thread->kernelStats->regStats(name + ".kern");
652 template <class Impl>
654 OzoneCPU<Impl>::OzoneTC::serialize(std::ostream &os)
656 // Once serialization is added, serialize the quiesce event and
657 // kernel stats. Will need to make sure there aren't multiple
658 // things that serialize them.
661 template <class Impl>
663 OzoneCPU<Impl>::OzoneTC::unserialize(Checkpoint *cp, const std::string §ion)
666 template <class Impl>
668 OzoneCPU<Impl>::OzoneTC::getQuiesceEvent()
670 return thread->quiesceEvent;
673 template <class Impl>
675 OzoneCPU<Impl>::OzoneTC::readLastActivate()
677 return thread->lastActivate;
680 template <class Impl>
682 OzoneCPU<Impl>::OzoneTC::readLastSuspend()
684 return thread->lastSuspend;
687 template <class Impl>
689 OzoneCPU<Impl>::OzoneTC::profileClear()
691 thread->profileClear();
694 template <class Impl>
696 OzoneCPU<Impl>::OzoneTC::profileSample()
698 thread->profileSample();
701 template <class Impl>
703 OzoneCPU<Impl>::OzoneTC::threadId()
705 return thread->threadId();
708 template <class Impl>
710 OzoneCPU<Impl>::OzoneTC::copyArchRegs(ThreadContext *tc)
712 thread->PC = tc->readPC();
713 thread->nextPC = tc->readNextPC();
715 cpu->frontEnd->setPC(thread->PC);
716 cpu->frontEnd->setNextPC(thread->nextPC);
718 // First loop through the integer registers.
719 for (int i = 0; i < TheISA::NumIntRegs; ++i) {
720 /* DPRINTF(OzoneCPU, "Copying over register %i, had data %lli, "
721 "now has data %lli.\n",
722 i, thread->renameTable[i]->readIntResult(),
725 thread->renameTable[i]->setIntResult(tc->readIntReg(i));
728 // Then loop through the floating point registers.
729 for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
730 int fp_idx = i + TheISA::FP_Base_DepTag;
731 thread->renameTable[fp_idx]->setIntResult(tc->readFloatRegBits(i));
734 thread->funcExeInst = tc->readFuncExeInst();
736 // Need to copy the TC values into the current rename table,
737 // copy the misc regs.
738 copyMiscRegs(tc, this);
741 template <class Impl>
743 OzoneCPU<Impl>::OzoneTC::clearArchRegs()
745 panic("Unimplemented!");
748 template <class Impl>
750 OzoneCPU<Impl>::OzoneTC::readIntReg(int reg_idx)
752 return thread->renameTable[reg_idx]->readIntResult();
755 template <class Impl>
757 OzoneCPU<Impl>::OzoneTC::readFloatReg(int reg_idx)
759 int idx = reg_idx + TheISA::FP_Base_DepTag;
760 return thread->renameTable[idx]->readFloatResult();
763 template <class Impl>
765 OzoneCPU<Impl>::OzoneTC::readFloatRegBits(int reg_idx)
767 int idx = reg_idx + TheISA::FP_Base_DepTag;
768 return thread->renameTable[idx]->readIntResult();
771 template <class Impl>
773 OzoneCPU<Impl>::OzoneTC::setIntReg(int reg_idx, uint64_t val)
775 thread->renameTable[reg_idx]->setIntResult(val);
777 if (!thread->inSyscall) {
782 template <class Impl>
784 OzoneCPU<Impl>::OzoneTC::setFloatReg(int reg_idx, FloatReg val)
786 int idx = reg_idx + TheISA::FP_Base_DepTag;
788 thread->renameTable[idx]->setDoubleResult(val);
790 if (!thread->inSyscall) {
795 template <class Impl>
797 OzoneCPU<Impl>::OzoneTC::setFloatRegBits(int reg_idx, FloatRegBits val)
799 panic("Unimplemented!");
802 template <class Impl>
804 OzoneCPU<Impl>::OzoneTC::setPC(Addr val)
807 cpu->frontEnd->setPC(val);
809 if (!thread->inSyscall) {
814 template <class Impl>
816 OzoneCPU<Impl>::OzoneTC::setNextPC(Addr val)
818 thread->nextPC = val;
819 cpu->frontEnd->setNextPC(val);
821 if (!thread->inSyscall) {
826 template <class Impl>
828 OzoneCPU<Impl>::OzoneTC::readMiscRegNoEffect(int misc_reg)
830 return thread->miscRegFile.readRegNoEffect(misc_reg);
833 template <class Impl>
835 OzoneCPU<Impl>::OzoneTC::readMiscReg(int misc_reg)
837 return thread->miscRegFile.readReg(misc_reg, this);
840 template <class Impl>
842 OzoneCPU<Impl>::OzoneTC::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
844 // Needs to setup a squash event unless we're in syscall mode
845 thread->miscRegFile.setRegNoEffect(misc_reg, val);
847 if (!thread->inSyscall) {
852 template <class Impl>
854 OzoneCPU<Impl>::OzoneTC::setMiscReg(int misc_reg, const MiscReg &val)
856 // Needs to setup a squash event unless we're in syscall mode
857 thread->miscRegFile.setReg(misc_reg, val, this);
859 if (!thread->inSyscall) {