summaryrefslogtreecommitdiff
path: root/src/cpu/inorder/resource.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/inorder/resource.cc')
-rw-r--r--src/cpu/inorder/resource.cc434
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();
+}