/* * 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 #include #include "cpu/inorder/resources/mult_div_unit.hh" #include "cpu/inorder/resource_pool.hh" #include "cpu/inorder/cpu.hh" #include "cpu/op_class.hh" using namespace std; using namespace ThePipeline; MultDivUnit::MultDivUnit(string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) : Resource(res_name, res_id, res_width, res_latency, _cpu), multRepeatRate(params->multRepeatRate), multLatency(params->multLatency), div8RepeatRate(params->div8RepeatRate), div8Latency(params->div8Latency), div16RepeatRate(params->div16RepeatRate), div16Latency(params->div16Latency), div24RepeatRate(params->div24RepeatRate), div24Latency(params->div24Latency), div32RepeatRate(params->div32RepeatRate), div32Latency(params->div32Latency), lastMDUCycle(0), lastOpType(No_OpClass) { } void MultDivUnit::regStats() { multInstReqsProcessed .name(name() + ".multInstReqsProcessed") .desc("Number of Multiply Requests Processed."); divInstReqsProcessed .name(name() + ".divInstReqsProcessed") .desc("Number of Divide Requests Processed."); Resource::regStats(); } void MultDivUnit::init() { // Set Up Resource Events to Appropriate Resource BandWidth resourceEvent = new MDUEvent[width]; initSlots(); } int MultDivUnit::findSlot(DynInstPtr inst) { DPRINTF(InOrderMDU, "Finding slot for inst:%i\n | slots-free:%i | slots-used:%i\n", inst->seqNum, slotsAvail(), slotsInUse()); return Resource::findSlot(inst); } void MultDivUnit::freeSlot(int slot_idx) { DPRINTF(InOrderMDU, "Freeing slot for inst:%i\n | slots-free:%i | slots-used:%i\n", reqMap[slot_idx]->getInst()->seqNum, slotsAvail(), slotsInUse()); Resource::freeSlot(slot_idx); } int MultDivUnit::getSlot(DynInstPtr inst) { // If MDU already has instruction, return current slot. int slot_num = findSlot(inst); // If we have this instruction's request already then return if (slot_num != -1 && inst->resSched.top()->cmd == reqMap[slot_num]->cmd) return slot_num; unsigned repeat_rate = 0; /** Enforce MDU dependencies after a multiply is seen last */ if (lastOpType == IntMultOp) { repeat_rate = multRepeatRate; } /** Enforce dependencies after a divide is seen last */ if (lastOpType == IntDivOp) { switch (lastDivSize) { case 8: repeat_rate = div8RepeatRate; break; case 16: repeat_rate = div16RepeatRate; break; case 24: repeat_rate = div24RepeatRate; break; case 32: repeat_rate = div32RepeatRate; break; } } if (lastMDUCycle + repeat_rate > curTick) { DPRINTF(InOrderMDU, "MDU not ready to process another inst. until %i, denying request.\n", lastMDUCycle + repeat_rate); return -1; } else { int rval = Resource::getSlot(inst); DPRINTF(InOrderMDU, "MDU request should pass: %i.\n", rval); if (rval != -1) { lastMDUCycle = curTick; lastOpType = inst->opClass(); lastInstName = inst->staticInst->getName(); } return rval; } } int MultDivUnit::getDivOpSize(DynInstPtr inst) { // Get RT Register from instruction (index #1) uint32_t div_op = inst->readIntSrc(1); if (div_op <= 0xFF) { return 8; } else if (div_op <= 0xFFFF) { return 16; } else if (div_op <= 0xFFFFFF) { return 24; } else { return 32; } } void MultDivUnit::execute(int slot_num) { ResourceRequest* mult_div_req = reqMap[slot_num]; DynInstPtr inst = reqMap[slot_num]->inst; Fault fault = reqMap[slot_num]->fault; //int tid = inst->readTid(); //int seq_num = inst->seqNum; switch (mult_div_req->cmd) { case StartMultDiv: DPRINTF(InOrderMDU, "Start MDU called ...\n"); if (inst->opClass() == IntMultOp) { scheduleEvent(slot_num, multLatency); multInstReqsProcessed++; } else if (inst->opClass() == IntDivOp) { int op_size = getDivOpSize(inst); switch (op_size) { case 8: scheduleEvent(slot_num, div8Latency); break; case 16: scheduleEvent(slot_num, div16Latency); break; case 24: scheduleEvent(slot_num, div24Latency); break; case 32: scheduleEvent(slot_num, div32Latency); break; } lastDivSize = op_size; divInstReqsProcessed++; } // Allow to pass through to next stage while // event processes mult_div_req->setCompleted(); break; case MultDiv: DPRINTF(InOrderMDU, "Execute MDU called ...\n"); exeMulDiv(slot_num); mult_div_req->done(); break; case EndMultDiv: //@TODO: Why not allow high-latency requests to sleep // within stage until event wakes up???? // Seems wasteful to continually check to see if // this is done when we have a event in parallel // counting down the time { DPRINTF(InOrderMDU, "End MDU called ...\n"); if (mult_div_req->getInst()->isExecuted()) mult_div_req->done(); } break; default: fatal("Unrecognized command to %s", resName); } } void MultDivUnit::exeMulDiv(int slot_num) { ResourceRequest* mult_div_req = reqMap[slot_num]; DynInstPtr inst = reqMap[slot_num]->inst; Fault fault = reqMap[slot_num]->fault; int tid = inst->readTid(); int seq_num = inst->seqNum; fault = inst->execute(); if (fault == NoFault) { inst->setExecuted(); mult_div_req->setCompleted(); DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n", inst->readTid(), inst->readIntResult(0)); } else { warn("inst [sn:%i] had a %s fault", seq_num, fault->name()); cpu->trap(fault, tid); } } MDUEvent::MDUEvent() : ResourceEvent() { } void MDUEvent::process() { MultDivUnit* mdu_res = reinterpret_cast(resource); mdu_res->exeMulDiv(slotIdx); ResourceRequest* mult_div_req = resource->reqMap[slotIdx]; mult_div_req->done(); }