diff options
Diffstat (limited to 'src/cpu/o3/cpu.cc')
-rw-r--r-- | src/cpu/o3/cpu.cc | 566 |
1 files changed, 566 insertions, 0 deletions
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc new file mode 100644 index 000000000..a268dbc23 --- /dev/null +++ b/src/cpu/o3/cpu.cc @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2004-2005 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. + */ + +#include "config/full_system.hh" + +#if FULL_SYSTEM +#include "sim/system.hh" +#else +#include "sim/process.hh" +#endif +#include "sim/root.hh" + +#include "cpu/cpu_exec_context.hh" +#include "cpu/exec_context.hh" +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/cpu.hh" + +using namespace std; + +BaseFullCPU::BaseFullCPU(Params ¶ms) + : BaseCPU(¶ms), cpu_id(0) +{ +} + +template <class Impl> +FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) +{ +} + +template <class Impl> +void +FullO3CPU<Impl>::TickEvent::process() +{ + cpu->tick(); +} + +template <class Impl> +const char * +FullO3CPU<Impl>::TickEvent::description() +{ + return "FullO3CPU tick event"; +} + +//Call constructor to all the pipeline stages here +template <class Impl> +FullO3CPU<Impl>::FullO3CPU(Params ¶ms) +#if FULL_SYSTEM + : BaseFullCPU(params), +#else + : BaseFullCPU(params), +#endif // FULL_SYSTEM + tickEvent(this), + fetch(params), + decode(params), + rename(params), + iew(params), + commit(params), + + regFile(params.numPhysIntRegs, params.numPhysFloatRegs), + + freeList(TheISA::NumIntRegs, params.numPhysIntRegs, + TheISA::NumFloatRegs, params.numPhysFloatRegs), + + renameMap(TheISA::NumIntRegs, params.numPhysIntRegs, + TheISA::NumFloatRegs, params.numPhysFloatRegs, + TheISA::NumMiscRegs, + TheISA::ZeroReg, + TheISA::ZeroReg + TheISA::NumIntRegs), + + rob(params.numROBEntries, params.squashWidth), + + // What to pass to these time buffers? + // For now just have these time buffers be pretty big. + timeBuffer(5, 5), + fetchQueue(5, 5), + decodeQueue(5, 5), + renameQueue(5, 5), + iewQueue(5, 5), + + cpuXC(NULL), + + globalSeqNum(1), + +#if FULL_SYSTEM + system(params.system), + memCtrl(system->memctrl), + physmem(system->physmem), + itb(params.itb), + dtb(params.dtb), + mem(params.mem), +#else + // Hardcoded for a single thread!! + mem(params.workload[0]->getMemory()), +#endif // FULL_SYSTEM + + icacheInterface(params.icacheInterface), + dcacheInterface(params.dcacheInterface), + deferRegistration(params.defReg), + numInsts(0), + funcExeInst(0) +{ + _status = Idle; + +#if !FULL_SYSTEM + thread.resize(this->number_of_threads); +#endif + + for (int i = 0; i < this->number_of_threads; ++i) { +#if FULL_SYSTEM + assert(i == 0); + thread[i] = new CPUExecContext(this, 0, system, itb, dtb, mem); + system->execContexts[i] = thread[i]->getProxy(); + + execContexts.push_back(system->execContexts[i]); +#else + if (i < params.workload.size()) { + DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, " + "process is %#x", + i, params.workload[i]->prog_entry, thread[i]); + thread[i] = new CPUExecContext(this, i, params.workload[i], i); + } + assert(params.workload[i]->getMemory() != NULL); + assert(mem != NULL); + execContexts.push_back(thread[i]->getProxy()); +#endif // !FULL_SYSTEM + } + + // Note that this is a hack so that my code which still uses xc-> will + // still work. I should remove this eventually + cpuXC = thread[0]; + + // The stages also need their CPU pointer setup. However this must be + // done at the upper level CPU because they have pointers to the upper + // level CPU, and not this FullO3CPU. + + // Give each of the stages the time buffer they will use. + fetch.setTimeBuffer(&timeBuffer); + decode.setTimeBuffer(&timeBuffer); + rename.setTimeBuffer(&timeBuffer); + iew.setTimeBuffer(&timeBuffer); + commit.setTimeBuffer(&timeBuffer); + + // Also setup each of the stages' queues. + fetch.setFetchQueue(&fetchQueue); + decode.setFetchQueue(&fetchQueue); + decode.setDecodeQueue(&decodeQueue); + rename.setDecodeQueue(&decodeQueue); + rename.setRenameQueue(&renameQueue); + iew.setRenameQueue(&renameQueue); + iew.setIEWQueue(&iewQueue); + commit.setIEWQueue(&iewQueue); + commit.setRenameQueue(&renameQueue); + + // Setup the rename map for whichever stages need it. + rename.setRenameMap(&renameMap); + iew.setRenameMap(&renameMap); + + // Setup the free list for whichever stages need it. + rename.setFreeList(&freeList); + renameMap.setFreeList(&freeList); + + // Setup the ROB for whichever stages need it. + commit.setROB(&rob); +} + +template <class Impl> +FullO3CPU<Impl>::~FullO3CPU() +{ +} + +template <class Impl> +void +FullO3CPU<Impl>::fullCPURegStats() +{ + // Register any of the FullCPU's stats here. +} + +template <class Impl> +void +FullO3CPU<Impl>::tick() +{ + DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n"); + + //Tick each of the stages if they're actually running. + //Will want to figure out a way to unschedule itself if they're all + //going to be idle for a long time. + fetch.tick(); + + decode.tick(); + + rename.tick(); + + iew.tick(); + + commit.tick(); + + // Now advance the time buffers, unless the stage is stalled. + timeBuffer.advance(); + + fetchQueue.advance(); + decodeQueue.advance(); + renameQueue.advance(); + iewQueue.advance(); + + if (_status == Running && !tickEvent.scheduled()) + tickEvent.schedule(curTick + 1); +} + +template <class Impl> +void +FullO3CPU<Impl>::init() +{ + if(!deferRegistration) + { + this->registerExecContexts(); + + // Need to do a copy of the xc->regs into the CPU's regfile so + // that it can start properly. +#if FULL_SYSTEM + ExecContext *src_xc = system->execContexts[0]; + TheISA::initCPU(src_xc, src_xc->readCpuId()); +#else + ExecContext *src_xc = thread[0]->getProxy(); +#endif + // First loop through the integer registers. + for (int i = 0; i < TheISA::NumIntRegs; ++i) + { + regFile.intRegFile[i] = src_xc->readIntReg(i); + } + + // Then loop through the floating point registers. + for (int i = 0; i < TheISA::NumFloatRegs; ++i) + { + regFile.floatRegFile.setRegBits(i, src_xc->readRegBits(i)) + } +/* + // Then loop through the misc registers. + regFile.miscRegs.fpcr = src_xc->regs.miscRegs.fpcr; + regFile.miscRegs.uniq = src_xc->regs.miscRegs.uniq; + regFile.miscRegs.lock_flag = src_xc->regs.miscRegs.lock_flag; + regFile.miscRegs.lock_addr = src_xc->regs.miscRegs.lock_addr; +*/ + // Then finally set the PC and the next PC. + regFile.pc = src_xc->readPC(); + regFile.npc = src_xc->readNextPC(); + } +} + +template <class Impl> +void +FullO3CPU<Impl>::activateContext(int thread_num, int delay) +{ + // Needs to set each stage to running as well. + + scheduleTickEvent(delay); + + _status = Running; +} + +template <class Impl> +void +FullO3CPU<Impl>::suspendContext(int thread_num) +{ + panic("suspendContext unimplemented!"); +} + +template <class Impl> +void +FullO3CPU<Impl>::deallocateContext(int thread_num) +{ + panic("deallocateContext unimplemented!"); +} + +template <class Impl> +void +FullO3CPU<Impl>::haltContext(int thread_num) +{ + panic("haltContext unimplemented!"); +} + +template <class Impl> +void +FullO3CPU<Impl>::switchOut() +{ + panic("FullO3CPU does not have a switch out function.\n"); +} + +template <class Impl> +void +FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) +{ + BaseCPU::takeOverFrom(oldCPU); + + assert(!tickEvent.scheduled()); + + // Set all status's to active, schedule the + // CPU's tick event. + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + if (xc->status() == ExecContext::Active && _status != Running) { + _status = Running; + tickEvent.schedule(curTick); + } + } +} + +template <class Impl> +InstSeqNum +FullO3CPU<Impl>::getAndIncrementInstSeq() +{ + // Hopefully this works right. + return globalSeqNum++; +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readIntReg(int reg_idx) +{ + return regFile.readIntReg(reg_idx); +} + +template <class Impl> +FloatReg +FullO3CPU<Impl>::readFloatReg(int reg_idx, int width) +{ + return regFile.readFloatReg(reg_idx, width); +} + +template <class Impl> +FloatReg +FullO3CPU<Impl>::readFloatReg(int reg_idx) +{ + return regFile.readFloatReg(reg_idx); +} + +template <class Impl> +FloatRegBits +FullO3CPU<Impl>::readFloatRegBits(int reg_idx, int width) +{ + return regFile.readFloatRegBits(reg_idx, width); +} + +template <class Impl> +FloatRegBits +FullO3CPU<Impl>::readFloatRegBits(int reg_idx) +{ + return regFile.readFloatRegBits(reg_idx); +} + +template <class Impl> +void +FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val) +{ + regFile.setIntReg(reg_idx, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val, int width) +{ + regFile.setFloatReg(reg_idx, val, width); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val) +{ + regFile.setFloatReg(reg_idx, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val, int width) +{ + regFile.setFloatRegBits(reg_idx, val, width); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val) +{ + regFile.setFloatRegBits(reg_idx, val); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readPC() +{ + return regFile.readPC(); +} + +template <class Impl> +void +FullO3CPU<Impl>::setNextPC(uint64_t val) +{ + regFile.setNextPC(val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setPC(Addr new_PC) +{ + regFile.setPC(new_PC); +} + +template <class Impl> +void +FullO3CPU<Impl>::addInst(DynInstPtr &inst) +{ + instList.push_back(inst); +} + +template <class Impl> +void +FullO3CPU<Impl>::instDone() +{ + // Keep an instruction count. + numInsts++; + + // Check for instruction-count-based events. + comInstEventQueue[0]->serviceEvents(numInsts); +} + +template <class Impl> +void +FullO3CPU<Impl>::removeBackInst(DynInstPtr &inst) +{ + DynInstPtr inst_to_delete; + + // Walk through the instruction list, removing any instructions + // that were inserted after the given instruction, inst. + while (instList.back() != inst) + { + assert(!instList.empty()); + + // Obtain the pointer to the instruction. + inst_to_delete = instList.back(); + + DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n", + inst_to_delete->seqNum, inst_to_delete->readPC()); + + // Remove the instruction from the list. + instList.pop_back(); + + // Mark it as squashed. + inst_to_delete->setSquashed(); + } +} + +template <class Impl> +void +FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst) +{ + DynInstPtr inst_to_remove; + + // The front instruction should be the same one being asked to be removed. + assert(instList.front() == inst); + + // Remove the front instruction. + inst_to_remove = inst; + instList.pop_front(); + + DPRINTF(FullCPU, "FullCPU: Removing committed instruction %#x, PC %#x\n", + inst_to_remove, inst_to_remove->readPC()); +} + +template <class Impl> +void +FullO3CPU<Impl>::removeInstsNotInROB() +{ + DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " + "list.\n"); + + DynInstPtr rob_tail = rob.readTailInst(); + + removeBackInst(rob_tail); +} + +template <class Impl> +void +FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num) +{ + DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " + "list.\n"); + + DynInstPtr inst_to_delete; + + while (instList.back()->seqNum > seq_num) { + assert(!instList.empty()); + + // Obtain the pointer to the instruction. + inst_to_delete = instList.back(); + + DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n", + inst_to_delete->seqNum, inst_to_delete->readPC()); + + // Remove the instruction from the list. + instList.back() = NULL; + instList.pop_back(); + + // Mark it as squashed. + inst_to_delete->setSquashed(); + } + +} + +template <class Impl> +void +FullO3CPU<Impl>::removeAllInsts() +{ + instList.clear(); +} + +template <class Impl> +void +FullO3CPU<Impl>::dumpInsts() +{ + int num = 0; + typename list<DynInstPtr>::iterator inst_list_it = instList.begin(); + + while (inst_list_it != instList.end()) + { + cprintf("Instruction:%i\nPC:%#x\nSN:%lli\nIssued:%i\nSquashed:%i\n\n", + num, (*inst_list_it)->readPC(), (*inst_list_it)->seqNum, + (*inst_list_it)->isIssued(), (*inst_list_it)->isSquashed()); + inst_list_it++; + ++num; + } +} + +template <class Impl> +void +FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst) +{ + iew.wakeDependents(inst); +} + +// Forward declaration of FullO3CPU. +template class FullO3CPU<AlphaSimpleImpl>; |