/* * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Kevin Lim * Korey Sewell */ #include "arch/regfile.hh" #include "cpu/o3/thread_context.hh" #include "cpu/quiesce_event.hh" #if FULL_SYSTEM template VirtualPort * O3ThreadContext::getVirtPort() { return thread->getVirtPort(); } template void O3ThreadContext::dumpFuncProfile() { thread->dumpFuncProfile(); } #endif template void O3ThreadContext::takeOverFrom(ThreadContext *old_context) { // some things should already be set up #if FULL_SYSTEM assert(getSystemPtr() == old_context->getSystemPtr()); #else assert(getProcessPtr() == old_context->getProcessPtr()); #endif // copy over functional state setStatus(old_context->status()); copyArchRegs(old_context); setContextId(old_context->contextId()); setThreadId(old_context->threadId()); #if !FULL_SYSTEM thread->funcExeInst = old_context->readFuncExeInst(); #else EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent(); if (other_quiesce) { // Point the quiesce event's TC at this TC so that it wakes up // the proper CPU. other_quiesce->tc = this; } if (thread->quiesceEvent) { thread->quiesceEvent->tc = this; } // Transfer kernel stats from one CPU to the other. thread->kernelStats = old_context->getKernelStats(); // storeCondFailures = 0; cpu->lockFlag = false; #endif old_context->setStatus(ThreadContext::Unallocated); thread->inSyscall = false; thread->trapPending = false; } template void O3ThreadContext::activate(int delay) { DPRINTF(O3CPU, "Calling activate on Thread Context %d\n", threadId()); if (thread->status() == ThreadContext::Active) return; #if FULL_SYSTEM thread->lastActivate = curTick; #endif if (thread->status() == ThreadContext::Unallocated) { cpu->activateWhenReady(thread->threadId()); return; } thread->setStatus(ThreadContext::Active); // status() == Suspended cpu->activateContext(thread->threadId(), delay); } template void O3ThreadContext::suspend(int delay) { DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n", threadId()); if (thread->status() == ThreadContext::Suspended) return; #if FULL_SYSTEM thread->lastActivate = curTick; thread->lastSuspend = curTick; #endif /* #if FULL_SYSTEM // Don't change the status from active if there are pending interrupts if (cpu->checkInterrupts()) { assert(status() == ThreadContext::Active); return; } #endif */ thread->setStatus(ThreadContext::Suspended); cpu->suspendContext(thread->threadId()); } template void O3ThreadContext::deallocate(int delay) { DPRINTF(O3CPU, "Calling deallocate on Thread Context %d delay %d\n", threadId(), delay); if (thread->status() == ThreadContext::Unallocated) return; thread->setStatus(ThreadContext::Unallocated); cpu->deallocateContext(thread->threadId(), true, delay); } template void O3ThreadContext::halt(int delay) { DPRINTF(O3CPU, "Calling halt on Thread Context %d\n", threadId()); if (thread->status() == ThreadContext::Halted) return; thread->setStatus(ThreadContext::Halted); cpu->haltContext(thread->threadId()); } template void O3ThreadContext::regStats(const std::string &name) { #if FULL_SYSTEM thread->kernelStats = new TheISA::Kernel::Statistics(cpu->system); thread->kernelStats->regStats(name + ".kern"); #endif } template void O3ThreadContext::serialize(std::ostream &os) { #if FULL_SYSTEM if (thread->kernelStats) thread->kernelStats->serialize(os); #endif } template void O3ThreadContext::unserialize(Checkpoint *cp, const std::string §ion) { #if FULL_SYSTEM if (thread->kernelStats) thread->kernelStats->unserialize(cp, section); #endif } #if FULL_SYSTEM template Tick O3ThreadContext::readLastActivate() { return thread->lastActivate; } template Tick O3ThreadContext::readLastSuspend() { return thread->lastSuspend; } template void O3ThreadContext::profileClear() { thread->profileClear(); } template void O3ThreadContext::profileSample() { thread->profileSample(); } #endif template TheISA::MachInst O3ThreadContext:: getInst() { return thread->getInst(); } template void O3ThreadContext::copyArchRegs(ThreadContext *tc) { // This function will mess things up unless the ROB is empty and // there are no instructions in the pipeline. unsigned tid = thread->threadId(); PhysRegIndex renamed_reg; // First loop through the integer registers. for (int i = 0; i < TheISA::NumIntRegs; ++i) { renamed_reg = cpu->renameMap[tid].lookup(i); DPRINTF(O3CPU, "Copying over register %i, had data %lli, " "now has data %lli.\n", renamed_reg, cpu->readIntReg(renamed_reg), tc->readIntReg(i)); cpu->setIntReg(renamed_reg, tc->readIntReg(i)); } // Then loop through the floating point registers. for (int i = 0; i < TheISA::NumFloatRegs; ++i) { renamed_reg = cpu->renameMap[tid].lookup(i + TheISA::FP_Base_DepTag); cpu->setFloatRegBits(renamed_reg, tc->readFloatRegBits(i)); } // Copy the misc regs. TheISA::copyMiscRegs(tc, this); // Then finally set the PC, the next PC, the nextNPC, the micropc, and the // next micropc. cpu->setPC(tc->readPC(), tid); cpu->setNextPC(tc->readNextPC(), tid); cpu->setNextNPC(tc->readNextNPC(), tid); cpu->setMicroPC(tc->readMicroPC(), tid); cpu->setNextMicroPC(tc->readNextMicroPC(), tid); #if !FULL_SYSTEM this->thread->funcExeInst = tc->readFuncExeInst(); #endif } template void O3ThreadContext::clearArchRegs() {} template uint64_t O3ThreadContext::readIntReg(int reg_idx) { reg_idx = TheISA::flattenIntIndex(this, reg_idx); return cpu->readArchIntReg(reg_idx, thread->threadId()); } template TheISA::FloatReg O3ThreadContext::readFloatReg(int reg_idx, int width) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); switch(width) { case 32: return cpu->readArchFloatRegSingle(reg_idx, thread->threadId()); case 64: return cpu->readArchFloatRegDouble(reg_idx, thread->threadId()); default: panic("Unsupported width!"); return 0; } } template TheISA::FloatReg O3ThreadContext::readFloatReg(int reg_idx) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); return cpu->readArchFloatRegSingle(reg_idx, thread->threadId()); } template TheISA::FloatRegBits O3ThreadContext::readFloatRegBits(int reg_idx, int width) { DPRINTF(Fault, "Reading floatint register through the TC!\n"); reg_idx = TheISA::flattenFloatIndex(this, reg_idx); return cpu->readArchFloatRegInt(reg_idx, thread->threadId()); } template TheISA::FloatRegBits O3ThreadContext::readFloatRegBits(int reg_idx) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); return cpu->readArchFloatRegInt(reg_idx, thread->threadId()); } template void O3ThreadContext::setIntReg(int reg_idx, uint64_t val) { reg_idx = TheISA::flattenIntIndex(this, reg_idx); cpu->setArchIntReg(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setFloatReg(int reg_idx, FloatReg val, int width) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); switch(width) { case 32: cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId()); break; case 64: cpu->setArchFloatRegDouble(reg_idx, val, thread->threadId()); break; } // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setFloatReg(int reg_idx, FloatReg val) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId()); if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val, int width) { DPRINTF(Fault, "Setting floatint register through the TC!\n"); reg_idx = TheISA::flattenFloatIndex(this, reg_idx); cpu->setArchFloatRegInt(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val) { reg_idx = TheISA::flattenFloatIndex(this, reg_idx); cpu->setArchFloatRegInt(reg_idx, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setPC(uint64_t val) { cpu->setPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setNextPC(uint64_t val) { cpu->setNextPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setMicroPC(uint64_t val) { cpu->setMicroPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setNextMicroPC(uint64_t val) { cpu->setNextMicroPC(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val) { cpu->setMiscRegNoEffect(misc_reg, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setMiscReg(int misc_reg, const MiscReg &val) { cpu->setMiscReg(misc_reg, val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } #if !FULL_SYSTEM template TheISA::IntReg O3ThreadContext::getSyscallArg(int i) { return cpu->getSyscallArg(i, thread->threadId()); } template void O3ThreadContext::setSyscallArg(int i, IntReg val) { cpu->setSyscallArg(i, val, thread->threadId()); } template void O3ThreadContext::setSyscallReturn(SyscallReturn return_value) { cpu->setSyscallReturn(return_value, thread->threadId()); } #endif // FULL_SYSTEM