#ifndef __SIMPLE_FULL_CPU_CC__ #define __SIMPLE_FULL_CPU_CC__ #ifdef FULL_SYSTEM #include "sim/system.hh" #else #include "sim/process.hh" #endif #include "sim/universe.hh" #include "cpu/exec_context.hh" #include "cpu/beta_cpu/full_cpu.hh" #include "cpu/beta_cpu/alpha_impl.hh" #include "cpu/beta_cpu/alpha_dyn_inst.hh" using namespace std; #ifdef FULL_SYSTEM BaseFullCPU::BaseFullCPU(const std::string &_name, int number_of_threads, Counter max_insts_any_thread, Counter max_insts_all_threads, Counter max_loads_any_thread, Counter max_loads_all_threads, System *_system, Tick freq) : BaseCPU(_name, number_of_threads, max_insts_any_thread, max_insts_all_threads, max_loads_any_thread, max_loads_all_threads, _system, freq) { } #else BaseFullCPU::BaseFullCPU(const std::string &_name, int number_of_threads, Counter max_insts_any_thread, Counter max_insts_all_threads, Counter max_loads_any_thread, Counter max_loads_all_threads) : BaseCPU(_name, number_of_threads, max_insts_any_thread, max_insts_all_threads, max_loads_any_thread, max_loads_all_threads) { } #endif // FULL_SYSTEM template FullBetaCPU::TickEvent::TickEvent(FullBetaCPU *c) : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) { } template void FullBetaCPU::TickEvent::process() { cpu->tick(); } template const char * FullBetaCPU::TickEvent::description() { return "FullBetaCPU tick event"; } //Call constructor to all the pipeline stages here template FullBetaCPU::FullBetaCPU(Params ¶ms) #ifdef FULL_SYSTEM : BaseFullCPU(params.name, /* number_of_threads */ 1, params.maxInstsAnyThread, params.maxInstsAllThreads, params.maxLoadsAnyThread, params.maxLoadsAllThreads, params.system, params.freq), #else : BaseFullCPU(params.name, /* number_of_threads */ 1, params.maxInstsAnyThread, params.maxInstsAllThreads, params.maxLoadsAnyThread, params.maxLoadsAllThreads), #endif // FULL_SYSTEM tickEvent(this), fetch(params), decode(params), rename(params), iew(params), commit(params), regFile(params.numPhysIntRegs, params.numPhysFloatRegs), freeList(Impl::ISA::NumIntRegs, params.numPhysIntRegs, Impl::ISA::NumFloatRegs, params.numPhysFloatRegs), renameMap(Impl::ISA::NumIntRegs, params.numPhysIntRegs, Impl::ISA::NumFloatRegs, params.numPhysFloatRegs, Impl::ISA::NumMiscRegs, Impl::ISA::ZeroReg, Impl::ISA::ZeroReg), rob(params.numROBEntries, params.squashWidth), // What to pass to these time buffers? // For now just have these time buffers be pretty big. timeBuffer(20, 20), fetchQueue(20, 20), decodeQueue(20, 20), renameQueue(20, 20), iewQueue(20, 20), xc(NULL), globalSeqNum(1), #ifdef FULL_SYSTEM system(params.system), memCtrl(system->memCtrl), physmem(system->physmem), itb(params.itb), dtb(params.dtb), mem(params.mem), #else process(params.process), asid(params.asid), mem(process->getMemory()), #endif // FULL_SYSTEM icacheInterface(params.icacheInterface), dcacheInterface(params.dcacheInterface), deferRegistration(params.defReg), numInsts(0), funcExeInst(0) { _status = Idle; #ifdef FULL_SYSTEM xc = new ExecContext(this, 0, system, itb, dtb, mem); // initialize CPU, including PC TheISA::initCPU(&xc->regs); #else xc = new ExecContext(this, /* thread_num */ 0, process, /* asid */ 0); DPRINTF(FullCPU, "FullCPU: Process's starting PC is %#x, process is %#x", process->prog_entry, process); assert(process->getMemory() != NULL); assert(mem != NULL); #endif // !FULL_SYSTEM execContexts.push_back(xc); // 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 FullBetaCPU. // 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 FullBetaCPU::~FullBetaCPU() { } template void FullBetaCPU::tick() { DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullBetaCPU.\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 FullBetaCPU::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. // First loop through the integer registers. for (int i = 0; i < Impl::ISA::NumIntRegs; ++i) { regFile.intRegFile[i] = xc->regs.intRegFile[i]; } // Then loop through the floating point registers. for (int i = 0; i < Impl::ISA::NumFloatRegs; ++i) { regFile.floatRegFile[i].d = xc->regs.floatRegFile.d[i]; regFile.floatRegFile[i].q = xc->regs.floatRegFile.q[i]; } // Then loop through the misc registers. regFile.miscRegs.fpcr = xc->regs.miscRegs.fpcr; regFile.miscRegs.uniq = xc->regs.miscRegs.uniq; regFile.miscRegs.lock_flag = xc->regs.miscRegs.lock_flag; regFile.miscRegs.lock_addr = xc->regs.miscRegs.lock_addr; // Then finally set the PC and the next PC. regFile.pc = xc->regs.pc; regFile.npc = xc->regs.npc; } } template void FullBetaCPU::activateContext(int thread_num, int delay) { // Needs to set each stage to running as well. scheduleTickEvent(delay); _status = Running; } template void FullBetaCPU::suspendContext(int thread_num) { panic("suspendContext unimplemented!"); } template void FullBetaCPU::deallocateContext(int thread_num) { panic("deallocateContext unimplemented!"); } template void FullBetaCPU::haltContext(int thread_num) { panic("haltContext unimplemented!"); } template void FullBetaCPU::switchOut() { panic("FullBetaCPU does not have a switch out function.\n"); } template void FullBetaCPU::takeOverFrom(BaseCPU *oldCPU) { BaseCPU::takeOverFrom(oldCPU); assert(!tickEvent.scheduled()); // Set all status's to active, schedule the // CPU's tick event. tickEvent.schedule(curTick); for (int i = 0; i < execContexts.size(); ++i) { execContexts[i]->activate(); } // Switch out the other CPU. oldCPU->switchOut(); } template InstSeqNum FullBetaCPU::getAndIncrementInstSeq() { // Hopefully this works right. return globalSeqNum++; } template uint64_t FullBetaCPU::readIntReg(int reg_idx) { return regFile.readIntReg(reg_idx); } template float FullBetaCPU::readFloatRegSingle(int reg_idx) { return regFile.readFloatRegSingle(reg_idx); } template double FullBetaCPU::readFloatRegDouble(int reg_idx) { return regFile.readFloatRegDouble(reg_idx); } template uint64_t FullBetaCPU::readFloatRegInt(int reg_idx) { return regFile.readFloatRegInt(reg_idx); } template void FullBetaCPU::setIntReg(int reg_idx, uint64_t val) { regFile.setIntReg(reg_idx, val); } template void FullBetaCPU::setFloatRegSingle(int reg_idx, float val) { regFile.setFloatRegSingle(reg_idx, val); } template void FullBetaCPU::setFloatRegDouble(int reg_idx, double val) { regFile.setFloatRegDouble(reg_idx, val); } template void FullBetaCPU::setFloatRegInt(int reg_idx, uint64_t val) { regFile.setFloatRegInt(reg_idx, val); } template uint64_t FullBetaCPU::readPC() { return regFile.readPC(); } template void FullBetaCPU::setNextPC(uint64_t val) { regFile.setNextPC(val); } template void FullBetaCPU::setPC(Addr new_PC) { regFile.setPC(new_PC); } template void FullBetaCPU::addInst(DynInst *inst) { instList.push_back(inst); } template void FullBetaCPU::instDone() { // Keep an instruction count. numInsts++; // Check for instruction-count-based events. comInstEventQueue[0]->serviceEvents(numInsts); } template void FullBetaCPU::removeBackInst(DynInst *inst) { DynInst *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: Deleting instruction %#x, PC %#x\n", inst_to_delete, inst_to_delete->readPC()); // Remove the instruction from the list. instList.pop_back(); // Delete the instruction itself. delete inst_to_delete; } } template void FullBetaCPU::removeFrontInst(DynInst *inst) { DynInst *inst_to_delete; // The front instruction should be the same one being asked to be deleted. assert(instList.front() == inst); // Remove the front instruction. inst_to_delete = inst; instList.pop_front(); DPRINTF(FullCPU, "FullCPU: Deleting committed instruction %#x, PC %#x\n", inst_to_delete, inst_to_delete->readPC()); delete inst_to_delete; } template void FullBetaCPU::removeInstsNotInROB() { DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " "list.\n"); DynInst *rob_tail = rob.readTailInst(); removeBackInst(rob_tail); } template void FullBetaCPU::removeAllInsts() { instList.clear(); } template void FullBetaCPU::dumpInsts() { int num = 0; typename list::iterator inst_list_it = instList.begin(); while (inst_list_it != instList.end()) { cprintf("Instruction:%i\nInst:%#x\nPC:%#x\nSN:%lli\n\n", num, (*inst_list_it), (*inst_list_it)->readPC(), (*inst_list_it)->seqNum); inst_list_it++; ++num; } } template void FullBetaCPU::wakeDependents(DynInst *inst) { iew.wakeDependents(inst); } // Forward declaration of FullBetaCPU. template FullBetaCPU; #endif // __SIMPLE_FULL_CPU_HH__