| /* |
| * Copyright (c) 2012-2013 ARM Limited |
| * All rights reserved |
| * |
| * The license below extends only to copyright in the software and shall |
| * not be construed as granting a license to any other intellectual |
| * property including but not limited to intellectual property relating |
| * to a hardware implementation of the functionality of the software |
| * licensed hereunder. You may use the software subject to the license |
| * terms below provided that you ensure that this notice is replicated |
| * unmodified and in its entirety in all distributions of the software, |
| * modified or unmodified, in source code or in binary form. |
| * |
| * Copyright (c) 2006 The Regents of The University of Michigan |
| * 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. |
| */ |
| |
| #include "cpu/o3/fu_pool.hh" |
| |
| #include <sstream> |
| |
| #include "cpu/func_unit.hh" |
| |
| namespace gem5 |
| { |
| |
| namespace o3 |
| { |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // |
| // A pool of function units |
| // |
| |
| inline void |
| FUPool::FUIdxQueue::addFU(int fu_idx) |
| { |
| funcUnitsIdx.push_back(fu_idx); |
| ++size; |
| } |
| |
| inline int |
| FUPool::FUIdxQueue::getFU() |
| { |
| int retval = funcUnitsIdx[idx++]; |
| |
| if (idx == size) |
| idx = 0; |
| |
| return retval; |
| } |
| |
| FUPool::~FUPool() |
| { |
| fuListIterator i = funcUnits.begin(); |
| fuListIterator end = funcUnits.end(); |
| for (; i != end; ++i) |
| delete *i; |
| } |
| |
| |
| // Constructor |
| FUPool::FUPool(const Params &p) |
| : SimObject(p) |
| { |
| numFU = 0; |
| |
| funcUnits.clear(); |
| |
| maxOpLatencies.fill(Cycles(0)); |
| pipelined.fill(true); |
| |
| // |
| // Iterate through the list of FUDescData structures |
| // |
| const std::vector<FUDesc *> ¶mList = p.FUList; |
| for (FUDDiterator i = paramList.begin(); i != paramList.end(); ++i) { |
| |
| // |
| // Don't bother with this if we're not going to create any FU's |
| // |
| if ((*i)->number) { |
| // |
| // Create the FuncUnit object from this structure |
| // - add the capabilities listed in the FU's operation |
| // description |
| // |
| // We create the first unit, then duplicate it as needed |
| // |
| FuncUnit *fu = new FuncUnit; |
| |
| OPDDiterator j = (*i)->opDescList.begin(); |
| OPDDiterator end = (*i)->opDescList.end(); |
| for (; j != end; ++j) { |
| // indicate that this pool has this capability |
| capabilityList.set((*j)->opClass); |
| |
| // Add each of the FU's that will have this capability to the |
| // appropriate queue. |
| for (int k = 0; k < (*i)->number; ++k) |
| fuPerCapList[(*j)->opClass].addFU(numFU + k); |
| |
| // indicate that this FU has the capability |
| fu->addCapability((*j)->opClass, (*j)->opLat, (*j)->pipelined); |
| |
| if ((*j)->opLat > maxOpLatencies[(*j)->opClass]) |
| maxOpLatencies[(*j)->opClass] = (*j)->opLat; |
| |
| if (!(*j)->pipelined) |
| pipelined[(*j)->opClass] = false; |
| } |
| |
| numFU++; |
| |
| // Add the appropriate number of copies of this FU to the list |
| fu->name = (*i)->name() + "(0)"; |
| funcUnits.push_back(fu); |
| |
| for (int c = 1; c < (*i)->number; ++c) { |
| std::ostringstream s; |
| numFU++; |
| FuncUnit *fu2 = new FuncUnit(*fu); |
| |
| s << (*i)->name() << "(" << c << ")"; |
| fu2->name = s.str(); |
| funcUnits.push_back(fu2); |
| } |
| } |
| } |
| |
| unitBusy.resize(numFU); |
| |
| for (int i = 0; i < numFU; i++) { |
| unitBusy[i] = false; |
| } |
| } |
| |
| int |
| FUPool::getUnit(OpClass capability) |
| { |
| // If this pool doesn't have the specified capability, |
| // return this information to the caller |
| if (!capabilityList[capability]) |
| return -2; |
| |
| int fu_idx = fuPerCapList[capability].getFU(); |
| int start_idx = fu_idx; |
| |
| // Iterate through the circular queue if needed, stopping if we've reached |
| // the first element again. |
| while (unitBusy[fu_idx]) { |
| fu_idx = fuPerCapList[capability].getFU(); |
| if (fu_idx == start_idx) { |
| // No FU available |
| return -1; |
| } |
| } |
| |
| assert(fu_idx < numFU); |
| |
| unitBusy[fu_idx] = true; |
| |
| return fu_idx; |
| } |
| |
| void |
| FUPool::freeUnitNextCycle(int fu_idx) |
| { |
| assert(unitBusy[fu_idx]); |
| unitsToBeFreed.push_back(fu_idx); |
| } |
| |
| void |
| FUPool::processFreeUnits() |
| { |
| while (!unitsToBeFreed.empty()) { |
| int fu_idx = unitsToBeFreed.back(); |
| unitsToBeFreed.pop_back(); |
| |
| assert(unitBusy[fu_idx]); |
| |
| unitBusy[fu_idx] = false; |
| } |
| } |
| |
| void |
| FUPool::dump() |
| { |
| std::cout << "Function Unit Pool (" << name() << ")\n"; |
| std::cout << "======================================\n"; |
| std::cout << "Free List:\n"; |
| |
| for (int i = 0; i < numFU; ++i) { |
| if (unitBusy[i]) { |
| continue; |
| } |
| |
| std::cout << " [" << i << "] : "; |
| |
| std::cout << funcUnits[i]->name << " "; |
| |
| std::cout << "\n"; |
| } |
| |
| std::cout << "======================================\n"; |
| std::cout << "Busy List:\n"; |
| for (int i = 0; i < numFU; ++i) { |
| if (!unitBusy[i]) { |
| continue; |
| } |
| |
| std::cout << " [" << i << "] : "; |
| |
| std::cout << funcUnits[i]->name << " "; |
| |
| std::cout << "\n"; |
| } |
| } |
| |
| bool |
| FUPool::isDrained() const |
| { |
| bool is_drained = true; |
| for (int i = 0; i < numFU; i++) |
| is_drained = is_drained && !unitBusy[i]; |
| |
| return is_drained; |
| } |
| |
| } // namespace o3 |
| } // namespace gem5 |