/* * 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. * * Authors: Kevin Lim */ #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 FullO3CPU::TickEvent::TickEvent(FullO3CPU *c) : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) { } template void FullO3CPU::TickEvent::process() { cpu->tick(); } template const char * FullO3CPU::TickEvent::description() { return "FullO3CPU tick event"; } //Call constructor to all the pipeline stages here template FullO3CPU::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 FullO3CPU::~FullO3CPU() { } template void FullO3CPU::fullCPURegStats() { // Register any of the FullCPU's stats here. } template void FullO3CPU::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 void FullO3CPU::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 void FullO3CPU::activateContext(int thread_num, int delay) { // Needs to set each stage to running as well. scheduleTickEvent(delay); _status = Running; } template void FullO3CPU::suspendContext(int thread_num) { panic("suspendContext unimplemented!"); } template void FullO3CPU::deallocateContext(int thread_num) { panic("deallocateContext unimplemented!"); } template void FullO3CPU::haltContext(int thread_num) { panic("haltContext unimplemented!"); } template void FullO3CPU::switchOut() { panic("FullO3CPU does not have a switch out function.\n"); } template void FullO3CPU::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 InstSeqNum FullO3CPU::getAndIncrementInstSeq() { // Hopefully this works right. return globalSeqNum++; } template uint64_t FullO3CPU::readIntReg(int reg_idx) { return regFile.readIntReg(reg_idx); } template FloatReg FullO3CPU::readFloatReg(int reg_idx, int width) { return regFile.readFloatReg(reg_idx, width); } template FloatReg FullO3CPU::readFloatReg(int reg_idx) { return regFile.readFloatReg(reg_idx); } template FloatRegBits FullO3CPU::readFloatRegBits(int reg_idx, int width) { return regFile.readFloatRegBits(reg_idx, width); } template FloatRegBits FullO3CPU::readFloatRegBits(int reg_idx) { return regFile.readFloatRegBits(reg_idx); } template void FullO3CPU::setIntReg(int reg_idx, uint64_t val) { regFile.setIntReg(reg_idx, val); } template void FullO3CPU::setFloatReg(int reg_idx, FloatReg val, int width) { regFile.setFloatReg(reg_idx, val, width); } template void FullO3CPU::setFloatReg(int reg_idx, FloatReg val) { regFile.setFloatReg(reg_idx, val); } template void FullO3CPU::setFloatRegBits(int reg_idx, FloatRegBits val, int width) { regFile.setFloatRegBits(reg_idx, val, width); } template void FullO3CPU::setFloatRegBits(int reg_idx, FloatRegBits val) { regFile.setFloatRegBits(reg_idx, val); } template uint64_t FullO3CPU::readPC() { return regFile.readPC(); } template void FullO3CPU::setNextPC(uint64_t val) { regFile.setNextPC(val); } template void FullO3CPU::setPC(Addr new_PC) { regFile.setPC(new_PC); } template void FullO3CPU::addInst(DynInstPtr &inst) { instList.push_back(inst); } template void FullO3CPU::instDone() { // Keep an instruction count. numInsts++; // Check for instruction-count-based events. comInstEventQueue[0]->serviceEvents(numInsts); } template void FullO3CPU::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 void FullO3CPU::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 void FullO3CPU::removeInstsNotInROB() { DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " "list.\n"); DynInstPtr rob_tail = rob.readTailInst(); removeBackInst(rob_tail); } template void FullO3CPU::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 void FullO3CPU::removeAllInsts() { instList.clear(); } template void FullO3CPU::dumpInsts() { int num = 0; typename list::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 void FullO3CPU::wakeDependents(DynInstPtr &inst) { iew.wakeDependents(inst); } // Forward declaration of FullO3CPU. template class FullO3CPU;