diff options
Diffstat (limited to 'src/cpu/inorder/resource.cc')
-rw-r--r-- | src/cpu/inorder/resource.cc | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc new file mode 100644 index 000000000..3106628f0 --- /dev/null +++ b/src/cpu/inorder/resource.cc @@ -0,0 +1,434 @@ +/* + * 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 <vector> +#include <list> +#include "cpu/inorder/resource.hh" +#include "cpu/inorder/cpu.hh" +using namespace std; + +Resource::Resource(string res_name, int res_id, int res_width, + int res_latency, InOrderCPU *_cpu) + : resName(res_name), id(res_id), + width(res_width), latency(res_latency), cpu(_cpu) +{ + // Use to deny a instruction a resource. + deniedReq = new ResourceRequest(this, NULL, 0, 0, 0, 0); +} + +void +Resource::init() +{ + // Set Up Resource Events to Appropriate Resource BandWidth + resourceEvent = new ResourceEvent[width]; + + initSlots(); +} + +void +Resource::initSlots() +{ + // Add available slot numbers for resource + for (int slot_idx = 0; slot_idx < width; slot_idx++) { + availSlots.push_back(slot_idx); + resourceEvent[slot_idx].init(this, slot_idx); + } +} + +std::string +Resource::name() +{ + return cpu->name() + "." + resName; +} + +void +Resource::regStats() +{ + instReqsProcessed + .name(name() + ".instReqsProcessed") + .desc("Number of Instructions Requests that completed in this resource."); +} + +int +Resource::slotsAvail() +{ + return availSlots.size(); +} + +int +Resource::slotsInUse() +{ + return width - availSlots.size(); +} + +void +Resource::freeSlot(int slot_idx) +{ + DPRINTF(RefCount, "Removing [tid:%i] [sn:%i]'s request from resource [slot:%i].\n", + reqMap[slot_idx]->inst->readTid(), + reqMap[slot_idx]->inst->seqNum, + slot_idx); + + // Put slot number on this resource's free list + availSlots.push_back(slot_idx); + + // Erase Request Pointer From Request Map + std::map<int, ResReqPtr>::iterator req_it = reqMap.find(slot_idx); + + assert(req_it != reqMap.end()); + reqMap.erase(req_it); + +} + +// TODO: More efficiently search for instruction's slot within +// resource. +int +Resource::findSlot(DynInstPtr inst) +{ + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + int slot_num = -1; + + while (map_it != map_end) { + if ((*map_it).second->getInst()->seqNum == + inst->seqNum) { + slot_num = (*map_it).second->getSlot(); + } + map_it++; + } + + return slot_num; +} + +int +Resource::getSlot(DynInstPtr inst) +{ + int slot_num; + + if (slotsAvail() != 0) { + slot_num = availSlots[0]; + + vector<int>::iterator vect_it = availSlots.begin(); + + assert(slot_num == *vect_it); + + availSlots.erase(vect_it); + } else { + DPRINTF(Resource, "[tid:%i]: No slots in resource " + "available to service [sn:%i].\n", inst->readTid(), + inst->seqNum); + slot_num = -1; + + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + if ((*map_it).second) { + DPRINTF(Resource, "Currently Serving request from: [tid:%i] [sn:%i].\n", + (*map_it).second->getInst()->readTid(), + (*map_it).second->getInst()->seqNum); + } + map_it++; + } + } + + return slot_num; +} + +ResReqPtr +Resource::request(DynInstPtr inst) +{ + // See if the resource is already serving this instruction. + // If so, use that request; + bool try_request = false; + int slot_num; + int stage_num; + ResReqPtr inst_req = findRequest(inst); + + if (inst_req) { + // If some preprocessing has to be done on instruction + // that has already requested once, then handle it here. + // update the 'try_request' variable if we should + // re-execute the request. + requestAgain(inst, try_request); + + slot_num = inst_req->getSlot(); + stage_num = inst_req->getStageNum(); + } else { + // Get new slot # for instruction + slot_num = getSlot(inst); + + if (slot_num != -1) { + // Get Stage # from Schedule Entry + stage_num = inst->resSched.top()->stageNum; + unsigned cmd = inst->resSched.top()->cmd; + + // Generate Resource Request + inst_req = getRequest(inst, stage_num, id, slot_num, cmd); + + if (inst->staticInst) { + DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource.\n", + inst->readTid(), inst->seqNum); + } else { + DPRINTF(Resource, "[tid:%i]: instruction requesting this resource.\n", + inst->readTid()); + } + + reqMap[slot_num] = inst_req; + + try_request = true; + } + } + + if (try_request) { + // Schedule execution of resource + scheduleExecution(slot_num); + } else { + inst_req = deniedReq; + rejectRequest(inst); + } + + return inst_req; +} + +void +Resource::requestAgain(DynInstPtr inst, bool &do_request) +{ + do_request = true; + + if (inst->staticInst) { + DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource again.\n", + inst->readTid(), inst->seqNum); + } else { + DPRINTF(Resource, "[tid:%i]: requesting this resource again.\n", + inst->readTid()); + } +} + +ResReqPtr +Resource::getRequest(DynInstPtr inst, int stage_num, int res_idx, + int slot_num, unsigned cmd) +{ + return new ResourceRequest(this, inst, stage_num, id, slot_num, + cmd); +} + +ResReqPtr +Resource::findRequest(DynInstPtr inst) +{ + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + if ((*map_it).second && + (*map_it).second->getInst() == inst) { + return (*map_it).second; + } + map_it++; + } + + return NULL; +} + +void +Resource::rejectRequest(DynInstPtr inst) +{ + DPRINTF(RefCount, "[tid:%i]: Unable to grant request for [sn:%i].\n", + inst->readTid(), inst->seqNum); +} + +void +Resource::execute(int slot_idx) +{ + DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n", + reqMap[slot_idx]->getTid(), name()); + reqMap[slot_idx]->setCompleted(true); + reqMap[slot_idx]->fault = NoFault; + reqMap[slot_idx]->done(); +} + +void +Resource::deactivateThread(unsigned tid) +{ + // In the most basic case, deactivation means squashing everything + // from a particular thread + DynInstPtr dummy_inst = new InOrderDynInst(cpu, NULL, 0, tid); + squash(dummy_inst, 0, 0, tid); +} + +void +Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid) +{ + std::vector<int> slot_remove_list; + + map<int, ResReqPtr>::iterator map_it = reqMap.begin(); + map<int, ResReqPtr>::iterator map_end = reqMap.end(); + + while (map_it != map_end) { + ResReqPtr req_ptr = (*map_it).second; + + if (req_ptr && + req_ptr->getInst()->readTid() == tid && + req_ptr->getInst()->seqNum > squash_seq_num) { + + DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n", + req_ptr->getInst()->readTid(), + req_ptr->getInst()->seqNum); + + int req_slot_num = req_ptr->getSlot(); + + unscheduleEvent(req_slot_num); + + // Mark request for later removal + cpu->reqRemoveList.push(req_ptr); + + // Mark slot for removal from resource + slot_remove_list.push_back(req_ptr->getSlot()); + } + + map_it++; + } + + // Now Delete Slot Entry from Req. Map + for (int i = 0; i < slot_remove_list.size(); i++) { + freeSlot(slot_remove_list[i]); + } +} + + +Tick +Resource::ticks(int num_cycles) +{ + return cpu->ticks(num_cycles); +} + + +void +Resource::scheduleExecution(int slot_num) +{ + int res_latency = getLatency(slot_num); + + if (res_latency >= 1) { + scheduleEvent(slot_num, res_latency); + } else { + execute(slot_num); + } +} + +void +Resource::scheduleEvent(int slot_idx, int delay) +{ + DPRINTF(Resource, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n", + reqMap[slot_idx]->inst->readTid(), + reqMap[slot_idx]->inst->seqNum, + cpu->ticks(delay) + curTick); + resourceEvent[slot_idx].scheduleEvent(delay); +} + +bool +Resource::scheduleEvent(DynInstPtr inst, int delay) +{ + int slot_idx = findSlot(inst); + + if(slot_idx != -1) + resourceEvent[slot_idx].scheduleEvent(delay); + + return slot_idx; +} + +void +Resource::unscheduleEvent(int slot_idx) +{ + resourceEvent[slot_idx].unscheduleEvent(); +} + +bool +Resource::unscheduleEvent(DynInstPtr inst) +{ + int slot_idx = findSlot(inst); + + if(slot_idx != -1) + resourceEvent[slot_idx].unscheduleEvent(); + + return slot_idx; +} + +int ResourceRequest::resReqID = 0; + +int ResourceRequest::resReqCount = 0; + +void +ResourceRequest::done(bool completed) +{ + DPRINTF(Resource, "%s done with request from [sn:%i] [tid:%i].\n", + res->name(), inst->seqNum, inst->readTid()); + + setCompleted(completed); + + // Add to remove list + res->cpu->reqRemoveList.push(res->reqMap[slotNum]); + + // Free Slot So Another Instruction Can Use This Resource + res->freeSlot(slotNum); + + res->instReqsProcessed++; +} + +ResourceEvent::ResourceEvent() + : Event((Event::Priority)Resource_Event_Pri) +{ } + +ResourceEvent::ResourceEvent(Resource *res, int slot_idx) + : Event((Event::Priority)Resource_Event_Pri), resource(res), + slotIdx(slot_idx) +{ } + +void +ResourceEvent::init(Resource *res, int slot_idx) +{ + resource = res; + slotIdx = slot_idx; +} + +void +ResourceEvent::process() +{ + resource->execute(slotIdx); +} + +const char * +ResourceEvent::description() +{ + string desc = resource->name() + " event"; + + return desc.c_str(); +} |