/* * Copyright (c) 2010 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall * not be construed as granting a license to any other intellectual * property including but not limited to intellectual property relating * to a hardware implementation of the functionality of the software * licensed hereunder. You may use the software subject to the license * terms below provided that you ensure that this notice is replicated * unmodified and in its entirety in all distributions of the software, * modified or unmodified, in source code or in binary form. * * 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/registers.hh" #include "config/the_isa.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::Halted); 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 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::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 void O3ThreadContext::copyArchRegs(ThreadContext *tc) { // This function will mess things up unless the ROB is empty and // there are no instructions in the pipeline. ThreadID 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->pcState(tc->pcState(), tid); #if !FULL_SYSTEM this->thread->funcExeInst = tc->readFuncExeInst(); #endif } template void O3ThreadContext::clearArchRegs() { cpu->isa[thread->threadId()].clear(); } template uint64_t O3ThreadContext::readIntReg(int reg_idx) { reg_idx = cpu->isa[thread->threadId()].flattenIntIndex(reg_idx); return cpu->readArchIntReg(reg_idx, thread->threadId()); } template TheISA::FloatReg O3ThreadContext::readFloatReg(int reg_idx) { reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx); return cpu->readArchFloatReg(reg_idx, thread->threadId()); } template TheISA::FloatRegBits O3ThreadContext::readFloatRegBits(int reg_idx) { reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx); return cpu->readArchFloatRegInt(reg_idx, thread->threadId()); } template void O3ThreadContext::setIntReg(int reg_idx, uint64_t val) { reg_idx = cpu->isa[thread->threadId()].flattenIntIndex(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) { reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx); cpu->setArchFloatReg(reg_idx, val, thread->threadId()); if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template void O3ThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val) { reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(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::pcState(const TheISA::PCState &val) { cpu->pcState(val, thread->threadId()); // Squash if we're not already in a state update mode. if (!thread->trapPending && !thread->inSyscall) { cpu->squashFromTC(thread->threadId()); } } template int O3ThreadContext::flattenIntIndex(int reg) { return cpu->isa[thread->threadId()].flattenIntIndex(reg); } template int O3ThreadContext::flattenFloatIndex(int reg) { return cpu->isa[thread->threadId()].flattenFloatIndex(reg); } 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()); } }