/* * Copyright (c) 2007 MIPS Technologies, Inc. * 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: Korey Sewell * */ #include "cpu/inorder/resource_pool.hh" #include "cpu/inorder/resources/resource_list.hh" #include #include using namespace std; using namespace ThePipeline; ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params) : cpu(_cpu) { //@todo: use this function to instantiate the resources in resource pool. This will help in the //auto-generation of this pipeline model. //ThePipeline::addResources(resources, memObjects); // Declare Resource Objects // name - id - bandwidth - latency - CPU - Parameters // -------------------------------------------------- resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params)); resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params)); memObjects.push_back(ICache); resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params)); resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params)); resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params)); resources.push_back(new InstBuffer("Fetch-Buffer-T0", FetchBuff, 4, 0, _cpu, params)); resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params)); resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params)); resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params)); resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params)); resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params)); memObjects.push_back(DCache); resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params)); resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params)); resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4, 0, _cpu, params)); } void ResourcePool::init() { for (int i=0; i < resources.size(); i++) { DPRINTF(Resource, "Initializing resource: %s.\n", resources[i]->name()); resources[i]->init(); } } string ResourcePool::name() { return cpu->name() + ".ResourcePool"; } void ResourcePool::regStats() { DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n"); int num_resources = resources.size(); for (int idx = 0; idx < num_resources; idx++) { resources[idx]->regStats(); } } Port * ResourcePool::getPort(const std::string &if_name, int idx) { DPRINTF(Resource, "Binding %s in Resource Pool.\n", if_name); for (int i = 0; i < memObjects.size(); i++) { int obj_idx = memObjects[i]; Port *port = resources[obj_idx]->getPort(if_name, idx); if (port != NULL) { DPRINTF(Resource, "%s set to resource %s(#%i) in Resource Pool.\n", if_name, resources[obj_idx]->name(), obj_idx); return port; } } return NULL; } unsigned ResourcePool::getPortIdx(const std::string &port_name) { DPRINTF(Resource, "Finding Port Idx for %s.\n", port_name); for (int i = 0; i < memObjects.size(); i++) { unsigned obj_idx = memObjects[i]; Port *port = resources[obj_idx]->getPort(port_name, obj_idx); if (port != NULL) { DPRINTF(Resource, "Returning Port Idx %i for %s.\n", obj_idx, port_name); return obj_idx; } } return 0; } unsigned ResourcePool::getResIdx(const std::string &res_name) { DPRINTF(Resource, "Finding Resource Idx for %s.\n", res_name); int num_resources = resources.size(); for (int idx = 0; idx < num_resources; idx++) { if (resources[idx]->name() == res_name) return idx; } return 0; } ResReqPtr ResourcePool::request(int res_idx, DynInstPtr inst) { //Make Sure This is a valid resource ID assert(res_idx >= 0 && res_idx < resources.size()); return resources[res_idx]->request(inst); } void ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid) { resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid); } int ResourcePool::slotsAvail(int res_idx) { return resources[res_idx]->slotsAvail(); } int ResourcePool::slotsInUse(int res_idx) { return resources[res_idx]->slotsInUse(); } void ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst, int delay, int res_idx, int tid) { assert(delay >= 0); ResPoolEvent *res_pool_event = new ResPoolEvent(this); switch (e_type) { case InOrderCPU::ActivateThread: { DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n", curTick + delay); res_pool_event->setEvent(e_type, inst, inst->squashingStage, inst->bdelaySeqNum, inst->readTid()); mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); } break; case InOrderCPU::SuspendThread: case InOrderCPU::DeallocateThread: { DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n", curTick + delay); res_pool_event->setEvent(e_type, inst, inst->squashingStage, inst->bdelaySeqNum, tid); mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); } break; case ResourcePool::InstGraduated: { DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n", curTick + delay); res_pool_event->setEvent(e_type, inst, inst->squashingStage, inst->seqNum, inst->readTid()); mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); } break; case ResourcePool::SquashAll: { DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n", curTick + delay); res_pool_event->setEvent(e_type, inst, inst->squashingStage, inst->bdelaySeqNum, inst->readTid()); mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay)); } break; default: DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type); ; // If Resource Pool doesnt recognize event, we ignore it. } } void ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst) { resources[res_idx]->unscheduleEvent(inst); } void ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid) { DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n", stage_num, tid, done_seq_num); int num_resources = resources.size(); for (int idx = 0; idx < num_resources; idx++) { resources[idx]->squash(inst, stage_num, done_seq_num, tid); } } void ResourcePool::activateAll(unsigned tid) { DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n", tid); int num_resources = resources.size(); for (int idx = 0; idx < num_resources; idx++) { resources[idx]->activateThread(tid); } } void ResourcePool::deactivateAll(unsigned tid) { DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n", tid); int num_resources = resources.size(); for (int idx = 0; idx < num_resources; idx++) { resources[idx]->deactivateThread(tid); } } void ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid) { DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n", tid, seq_num); int num_resources = resources.size(); for (int idx = 0; idx < num_resources; idx++) { resources[idx]->instGraduated(seq_num, tid); } } ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool) : Event(CPU_Tick_Pri), resPool(_resPool) { eventType = (InOrderCPU::CPUEventType) Default; } void ResourcePool::ResPoolEvent::process() { switch (eventType) { case InOrderCPU::ActivateThread: resPool->activateAll(tid); break; case InOrderCPU::SuspendThread: case InOrderCPU::DeallocateThread: resPool->deactivateAll(tid); break; case ResourcePool::InstGraduated: resPool->instGraduated(seqNum, tid); break; case ResourcePool::SquashAll: resPool->squashAll(inst, stageNum, seqNum, tid); break; default: fatal("Unrecognized Event Type"); } resPool->cpu->cpuEventRemoveList.push(this); } const char * ResourcePool::ResPoolEvent::description() { return "Resource Pool event"; } /** Schedule resource event, regardless of its current state. */ void ResourcePool::ResPoolEvent::scheduleEvent(int delay) { if (squashed()) mainEventQueue.reschedule(this,curTick + resPool->cpu->ticks(delay)); else if (!scheduled()) mainEventQueue.schedule(this,curTick + resPool->cpu->ticks(delay)); } /** Unschedule resource event, regardless of its current state. */ void ResourcePool::ResPoolEvent::unscheduleEvent() { if (scheduled()) squash(); }