// This file is part of the Coriolis Project. // Copyright (C) Laboratoire LIP6 - Departement ASIM // Universite Pierre et Marie Curie // // Main contributors : // Christophe Alexandre // Sophie Belloeil // Hugo Clément // Jean-Paul Chaput // Damien Dupuis // Christian Masson // Marek Sroka // // The Coriolis Project is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. // // The Coriolis Project is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with the Coriolis Project; if not, write to the Free Software // Foundation, inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // // License-Tag // // Date : 29/01/2004 // Author : Christophe Alexandre // inspired by Andrew Caldwell's BranchSmallPlacer // Authors-Tag /************************************************************************** *** *** Copyright (c) 1995-2000 Regents of the University of California, *** Andrew E. Caldwell, Andrew B. Kahng and Igor L. Markov *** Copyright (c) 2000-2002 Regents of the University of Michigan, *** Saurabh N. Adya and Igor L. Markov *** *** Contact author(s): abk@cs.ucsd.edu, imarkov@umich.edu *** Original Affiliation: UCLA, computer Science Department, *** Los Angeles, CA 90095-1596 USA *** *** Permission is hereby granted, free of charge, to any person obtaining *** a copy of this software and associated documentation files (the *** "Software"), to deal in the Software without restriction, including *** without limitation *** the rights to use, copy, modify, merge, publish, distribute, sublicense, *** and/or sell copies of the Software, and to permit persons to whom the *** Software is furnished to do so, subject to the following conditions: *** *** The above copyright notice and this permission notice shall be included *** in all copies or substantial portions of the Software. *** *** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES *** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY *** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT *** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *** THE USE OR OTHER DEALINGS IN THE SOFTWARE. *** *** ***************************************************************************/ #include "hurricane/UpdateSession.h" #include "hurricane/Interval.h" #include "hurricane/Net.h" #include "hurricane/Cell.h" #include "crlcore/ToolBox.h" #include "crlcore/AllianceFramework.h" #include "mauka/MaukaEngine.h" #include "mauka/Surface.h" #include "mauka/Row.h" #include "mauka/SubRow.h" #include "mauka/Bin.h" #include "mauka/BBPlacer.h" namespace { using namespace std; using namespace Mauka; using namespace Hurricane; using namespace CRL; class CompareInstancePosition { private: BBPlacer* _bbPlacer; public: CompareInstancePosition(BBPlacer* bbplacer) : _bbPlacer(bbplacer) {} public: bool operator()(unsigned id1, unsigned id2) const { return _bbPlacer->getInstanceIdX(id1) < _bbPlacer->getInstanceIdX(id2); } }; } // End of anonymous namespace. namespace Mauka { using namespace std; using namespace Hurricane; using namespace CRL; //#define PLACE_DEBUG 1 BBPlacer::BBPlacer(MaukaEngine* mauka) : _mauka(mauka) , _subRowVector() , _subRowInstances() , _instanceX() , _instanceY() , _instancePlaced() , _netVector() , _netBBoxes() , _netCosts() , _netCurrCostMark() , _netFlags() , _instanceToOptimize() , _leftEdge(0) , _rightEdge(0) , _oldCost(0.0) , _cost(0.0) , _bestCost(0.0) , _costFlag(0) , _queue() , _stack() , _loopVect() , _bestSolution() , _idx(0) { for (unsigned i = 0; i < _mauka->_instanceOccurrencesVector.size(); i++) { _instanceMarginWidth.push_back(_mauka->_instanceWidths[i]); _instanceX.push_back(0); _instanceY.push_back(0); _instancePlaced.push_back(true); } for (unsigned netid = 0; netid < _mauka->_nets.size(); netid++) { vector bboxes(2); _netBBoxes.push_back(bboxes); vector costs(2); _netCosts.push_back(costs); _netFlags.push_back(0); _netCurrCostMark.push_back(0); } Surface::RowVector& rowVector = _mauka->_surface->_rowVector; for (Surface::RowVector::iterator rvit = rowVector.begin(); rvit != rowVector.end(); rvit++) { Row::SubRowVector& subRowVector = (*rvit)->_subRowVector; for (Row::SubRowVector::iterator srvit = subRowVector.begin(); srvit != subRowVector.end(); srvit++) { SubRow* subRow = *srvit; if (subRow->getSize() > 0) { _subRowVector.push_back(subRow); _subRowInstances.push_back(MaukaEngine::UVector()); DbU::Unit totalInstanceSizeInRow = 0; for (SubRow::BinVector::iterator bvit = subRow->_binVector.begin(); bvit != subRow->_binVector.end(); bvit++) { Bin* bin = *bvit; totalInstanceSizeInRow += bin->getSize(); for (MaukaEngine::UList::const_iterator ulit = bin->InstanceOccurrenceIdsBegin(); ulit != bin->InstanceOccurrenceIdsEnd(); ulit++) { unsigned instanceId = *ulit; _subRowInstances.back().push_back(instanceId); } } DbU::Unit pitch = _mauka->getPitch(); DbU::Unit whiteSpace = subRow->getWidth() - totalInstanceSizeInRow; DbU::Unit instanceWhiteSpacePitch = (whiteSpace / _subRowInstances.back().size()) / pitch; DbU::Unit whiteSpaceRemain = whiteSpace - (instanceWhiteSpacePitch * _subRowInstances.back().size() * pitch); assert(!(whiteSpaceRemain%pitch)); if (instanceWhiteSpacePitch > 0) { for (MaukaEngine::UVector::const_iterator uvit = _subRowInstances.back().begin(); uvit != _subRowInstances.back().end(); uvit++) { _instanceMarginWidth[*uvit] += instanceWhiteSpacePitch * pitch; } } MaukaEngine::UVector::const_iterator uvit = _subRowInstances.back().begin(); while (whiteSpaceRemain > 0) { _instanceMarginWidth[*uvit++] += pitch; whiteSpaceRemain -= pitch; assert(uvit != _subRowInstances.back().end()); } DbU::Unit xPos = subRow->getXMin(); DbU::Unit yPos = subRow->getYMin(); for (MaukaEngine::UVector::const_iterator uvit = _subRowInstances.back().begin(); uvit != _subRowInstances.back().end(); uvit++) { unsigned instanceId = *uvit; _instanceX[instanceId] = xPos; _instanceY[instanceId] = yPos; xPos += _instanceMarginWidth[instanceId]; } } } } } void BBPlacer::Save() { UpdateSession::open(); bool autoMaterialize = not Go::autoMaterializationIsDisabled(); Go::enableAutoMaterialization(); for (unsigned i = 0; i < _subRowInstances.size(); i++) { SubRow* subRow = _subRowVector[i]; Transformation::Orientation orientation = (subRow->getRow()->getOrientation()) ? Transformation::Orientation::MY : Transformation::Orientation::ID; for (unsigned j = 0; j < _subRowInstances[i].size(); j++) { unsigned instanceId = _subRowInstances[i][j]; DbU::Unit x = _instanceX[instanceId]; DbU::Unit y = _instanceY[instanceId]; Occurrence instanceOccurrence = _mauka->_instanceOccurrencesVector[instanceId]; Instance* instance = static_cast(instanceOccurrence.getEntity()); Box masterABox = instance->getMasterCell()->getAbutmentBox(); Transformation instanceTransformation = getTransformation(masterABox, x, y, orientation); #if 0 cerr << masterABox.getXMin() << "," << masterABox.getYMin() << masterABox.getXMax() << "," << masterABox.getYMax() << endl; cerr << x << "," << y << endl; cerr << instanceTransformation << endl; cerr << "occ transfo : " << instanceOccurrence.getPath().getTransformation() << endl; #endif instanceOccurrence.getPath().getTransformation().invert().applyOn(instanceTransformation); instance->setTransformation(instanceTransformation); instance->setPlacementStatus(Instance::PlacementStatus::PLACED); //setPlacementStatusRecursivelyToPlaced(instance); } } if ( autoMaterialize ) Go::enableAutoMaterialization (); else Go::disableAutoMaterialization (); UpdateSession::close(); } void BBPlacer::Plot(ofstream& out) const { for (unsigned i = 0; i < _mauka->_instanceOccurrencesVector.size(); i++) { DbU::Unit x = _instanceX[i]; DbU::Unit y = _instanceY[i]; Occurrence instanceOccurrence = _mauka->_instanceOccurrencesVector[i]; Instance* instance = static_cast(instanceOccurrence.getEntity()); Box masterABox = instance->getMasterCell()->getAbutmentBox(); Box instanceBox = Box( x, y, x + masterABox.getWidth(), y + masterABox.getHeight()); out << instanceBox.getXMin()+0.4 << " " << instanceBox.getYMin()+0.4 << endl << instanceBox.getXMin()+0.4 << " " << instanceBox.getYMax()-0.4 << endl << instanceBox.getXMax()-0.4 << " " << instanceBox.getYMax()-0.4 << endl << instanceBox.getXMax()-0.4 << " " << instanceBox.getYMin()+0.4 << endl << instanceBox.getXMin()+0.4 << " " << instanceBox.getYMin()+0.4 << endl << endl; } out << "EOF" << endl << endl; out << "#nets" << endl; for (unsigned i = 0; i < _mauka->_netInstances.size(); i++) { if (_mauka->_hasInitX[i]) continue; unsigned nbInstances = 0; DbU::Unit baryX = 0; DbU::Unit baryY = 0; for (unsigned j = 0; j < _mauka->_netInstances[i].size(); j++) { unsigned instanceId = _mauka->_netInstances[i][j]; Occurrence instanceOccurrence = _mauka->_instanceOccurrencesVector[instanceId]; Instance* instance = static_cast(instanceOccurrence.getEntity()); Box masterABox = instance->getMasterCell()->getAbutmentBox(); ++nbInstances; baryX += _instanceX[instanceId] + masterABox.getWidth() / 2; baryY += _instanceY[instanceId] + masterABox.getHeight() / 2; } baryX = baryX / nbInstances; baryY = baryY / nbInstances; for (unsigned j = 0; j < _mauka->_netInstances[i].size(); j++) { unsigned instanceId = _mauka->_netInstances[i][j]; Occurrence instanceOccurrence = _mauka->_instanceOccurrencesVector[instanceId]; Instance* instance = static_cast(instanceOccurrence.getEntity()); Box masterABox = instance->getMasterCell()->getAbutmentBox(); out << baryX << " " << baryY << endl << _instanceX[instanceId] + masterABox.getWidth() / 2 << " " << _instanceY[instanceId] + masterABox.getHeight() / 2 << endl << endl; } } out << "EOF" << endl << endl; out << "#nets with fixed point" << endl; for (unsigned i = 0; i < _mauka->_netInstances.size(); i++) { if (!_mauka->_hasInitX[i]) continue; unsigned nbInstances = 1; DbU::Unit baryX = 0; DbU::Unit baryY = 0; baryX += _mauka->_netInitX[i]; baryY += _mauka->_netInitY[i]; for (unsigned j = 0; j < _mauka->_netInstances[i].size(); j++) { unsigned instanceId = _mauka->_netInstances[i][j]; Occurrence instanceOccurrence = _mauka->_instanceOccurrencesVector[instanceId]; Instance* instance = static_cast(instanceOccurrence.getEntity()); Box masterABox = instance->getMasterCell()->getAbutmentBox(); ++nbInstances; baryX += _instanceX[instanceId] + masterABox.getWidth() / 2; baryY += _instanceY[instanceId] + masterABox.getHeight() / 2; } baryX = baryX / nbInstances; baryY = baryY / nbInstances; for (unsigned j = 0; j < _mauka->_netInstances[i].size(); j++) { unsigned instanceId = _mauka->_netInstances[i][j]; Occurrence instanceOccurrence = _mauka->_instanceOccurrencesVector[instanceId]; Instance* instance = static_cast(instanceOccurrence.getEntity()); Box masterABox = instance->getMasterCell()->getAbutmentBox(); out << baryX << " " << baryY << endl << _instanceX[instanceId] + masterABox.getWidth() / 2 << " " << _instanceY[instanceId] + masterABox.getHeight() / 2 << endl << endl; } out << baryX << " " << baryY << endl << _mauka->_netInitX[i] << " " << _mauka->_netInitY[i] << endl << endl; } out << "EOF" << endl << endl; } void BBPlacer::Run() { for (unsigned i = 0; i < _subRowInstances.size(); i++) { unsigned decal = 2; unsigned nInstancesToOptimize = 0; MaukaEngine::UVector::iterator ifirst = _subRowInstances[i].begin(); MaukaEngine::UVector::iterator ilast = _subRowInstances[i].end(); while (1) { _instanceToOptimize.clear(); while (1) { if (ifirst == ilast) break; _instanceToOptimize.push_back(*ifirst++); ++nInstancesToOptimize; if (nInstancesToOptimize >= 6) { nInstancesToOptimize = 0; break; } } Optimize(); if (ifirst == ilast) break; sort(_subRowInstances[i].begin(), _subRowInstances[i].end(), CompareInstancePosition(this)); if ((6 + decal) <= nInstancesToOptimize) { ifirst = _subRowInstances[i].begin() + decal; } else { ifirst = _subRowInstances[i].begin() + decal - 1; } decal += 2; } } } bool BBPlacer::Optimize() { bool optimizationResult = false; const int numberInstances = _instanceToOptimize.size(); // Save initial Solution _bestSolution.reserve(numberInstances); for (unsigned i=0; i<_instanceToOptimize.size(); i++) { _queue.push_back(_instanceToOptimize[i]); } MaukaEngine::UVector::iterator ifirst = _instanceToOptimize.begin(); MaukaEngine::UVector::iterator ilast = _instanceToOptimize.end(); vector::iterator it = _bestSolution.begin(); while (ifirst != ilast) *it++ = _instanceX[*ifirst++]; // init Best Cost _bestCost = initCost(); #ifdef PLACE_DEBUG cout<<" Orig Cost: "<< _bestCost << endl; cout<<" Actual Cost: " << CurrentCost() << endl; #endif // init initial Cost // init Edges _leftEdge = _instanceX[*_instanceToOptimize.begin()]; _rightEdge = _instanceX[*_instanceToOptimize.rbegin()] + _instanceMarginWidth[*_instanceToOptimize.rbegin()]; UnplaceAll(); _cost = initCost(); #ifdef PLACE_DEBUG cout << " init Cost: " << _cost << endl; #endif _loopVect.reserve(numberInstances + 2); for (int id = 0; id < numberInstances + 2; id++) _loopVect.push_back(0); _loopVect[numberInstances] = numberInstances; _loopVect[numberInstances + 1] = numberInstances + 1; _stack.reserve(numberInstances); _idx = numberInstances - 1; unsigned numAdds = 0; while(_idx < numberInstances) { addIns(); numAdds++; if(_loopVect[_idx] == 0 || _cost >= _bestCost) { _loopVect[_idx] = 0; //force a bound if(_cost < _bestCost) //got here if: // new best complete soln (curWL < best) // bounded partial soln (curWL > best) // so there is no need to additionally // check to ensure this is a complete soln { optimizationResult = true; _bestCost = _cost; #ifdef PLACE_DEBUG cout<<" New Best: "<< _cost <<" found after "<< numAdds << endl; cout << "Cost recalculated: " << initCost() << endl; cout << "Actual Cost: " << CurrentCost() << endl; #endif ifirst = _instanceToOptimize.begin(); it = _bestSolution.begin(); while (ifirst != ilast) { *it++ = _instanceX[*ifirst++]; } #if 0 Save(); for_each_view(view, _mauka->getCell()->getViews()) { if (CEditor* editor = dynamic_cast(view)) { editor->Stop("coucou"); break; } end_for; } #endif } while(_loopVect[_idx] == 0) { if(_idx < numberInstances) removeIns(); _loopVect[++_idx]--; } } --_idx; } ifirst = _instanceToOptimize.begin(); it = _bestSolution.begin(); while (ifirst != ilast) _instanceX[*ifirst++] = *it++; PlaceAll(); _bestSolution.clear(); #ifdef PLACE_DEBUG cout<<" Total add Operations: "<< numAdds<< endl; cout<<" Final solution has cost: "<< _bestCost << endl << endl; #endif _loopVect.clear(); _queue.clear(); _stack.clear(); return optimizationResult; } void BBPlacer::addIns() { _stack.push_back(_queue.front()); _queue.pop_front(); _loopVect[_idx] = _idx; unsigned instanceId = _stack.back(); //cerr << "adding: " << _instanceOccurrenceVector[instanceId] << " " ; if(_idx%2) { _instanceX[instanceId] = _rightEdge - _instanceMarginWidth[instanceId]; _rightEdge -= _instanceMarginWidth[instanceId]; } else { _instanceX[instanceId] = _leftEdge; _leftEdge += _instanceMarginWidth[instanceId]; } //cerr << _instanceX[instanceId] << " "; _instancePlaced[instanceId] = true; _cost += UpdateInstanceCost(instanceId); //cerr << _cost << endl; //cerr << "verify " << CurrentCost() << endl; } void BBPlacer::removeIns() { unsigned instanceId = _stack.back(); //cerr << "Removing: " << _instanceOccurrenceVector[instanceId] << " " ; _queue.push_back(instanceId); _stack.pop_back(); if(_idx%2) _rightEdge += _instanceMarginWidth[instanceId]; else _leftEdge -= _instanceMarginWidth[instanceId]; _instancePlaced[instanceId] = false; _cost += UpdateInstanceCost(instanceId); //cerr << _cost << endl; } void BBPlacer::PlaceAll() { for (MaukaEngine::UVector::iterator uvit = _instanceToOptimize.begin(); uvit != _instanceToOptimize.end(); uvit++) { _instancePlaced[*uvit] = true; } } void BBPlacer::UnplaceAll() { for (MaukaEngine::UVector::iterator uvit = _instanceToOptimize.begin(); uvit != _instanceToOptimize.end(); uvit++) { _instancePlaced[*uvit] = false; } } double BBPlacer::initCost() { ++_costFlag; double cost = 0.0; for (MaukaEngine::UVector::iterator uvit = _instanceToOptimize.begin(); uvit != _instanceToOptimize.end(); uvit++) { cost += initInstanceCost(*uvit); } return cost; } double BBPlacer::CurrentCost() { ++_costFlag; double cost = 0.0; for (MaukaEngine::UVector::iterator uvit = _instanceToOptimize.begin(); uvit != _instanceToOptimize.end(); uvit++) cost += CurrentInstanceCost(*uvit); return cost; } double BBPlacer::UpdateInstanceCost(unsigned instanceid) { double deltaCost = 0.0; for (MaukaEngine::UVector::const_iterator uvit = _mauka->_instanceNets[instanceid].begin(); uvit != _mauka->_instanceNets[instanceid].end(); uvit++) { deltaCost += UpdateNetCost(*uvit); } return deltaCost; } double BBPlacer::UpdateNetCost(unsigned netid) { Box& netBBox = _netBBoxes[netid][_netFlags[netid]]; double& netCost = _netCosts[netid][_netFlags[netid]]; double initCost = netCost; netBBox.makeEmpty(); if (_mauka->_hasInitX[netid]) netBBox.merge(_mauka->_netInitX[netid], netBBox.getYMin()); if (_mauka->_hasInitY[netid]) netBBox.merge(netBBox.getXMin(), _mauka->_netInitY[netid]); for (MaukaEngine::UVector::const_iterator uvit = _mauka->_netInstances[netid].begin(); uvit != _mauka->_netInstances[netid].end(); uvit++) { if (_instancePlaced[*uvit]) { //FIXME netBBox.merge(Point(_instanceX[*uvit], _instanceY[*uvit])); } } netCost = computeCost(netBBox); return (netCost - initCost); } double BBPlacer::initInstanceCost(unsigned instanceid) { double cost = 0.0; for (MaukaEngine::UVector::const_iterator uvit = _mauka->_instanceNets[instanceid].begin(); uvit != _mauka->_instanceNets[instanceid].end(); uvit++) { computeNetBBox(*uvit); //SaveNetTempValue(*uvit); cost += CurrentNetCost(*uvit); } return cost; } double BBPlacer::CurrentInstanceCost(unsigned instanceid) { double cost = 0.0; for (MaukaEngine::UVector::const_iterator uvit = _mauka->_instanceNets[instanceid].begin(); uvit != _mauka->_instanceNets[instanceid].end(); uvit++) { cost += CurrentNetCost(*uvit); } return cost; } void BBPlacer::SaveNetTempValue(unsigned netid) { _netFlags[netid] = !_netFlags[netid]; } void BBPlacer::computeNetBBox(unsigned netid) { //cerr << _netVector[netid] << endl; //Box& netTmpBBox = _netBBoxes[netid][!_netFlags[netid]]; Box& netTmpBBox = _netBBoxes[netid][_netFlags[netid]]; //FIXME netTmpBBox.makeEmpty(); if (_mauka->_hasInitX[netid]) netTmpBBox.merge(_mauka->_netInitX[netid], netTmpBBox.getYMin()); if (_mauka->_hasInitY[netid]) netTmpBBox.merge(netTmpBBox.getXMin(), _mauka->_netInitY[netid]); for (MaukaEngine::UVector::const_iterator uvit = _mauka->_netInstances[netid].begin(); uvit != _mauka->_netInstances[netid].end(); uvit++) { if (_instancePlaced[*uvit]) { //FIXME netTmpBBox.merge(Point(_instanceX[*uvit], _instanceY[*uvit])); //cerr << netTmpBBox << endl; } } _netCosts[netid][_netFlags[netid]] = computeCost(netTmpBBox); //_netCosts[netid][!_netFlags[netid]] = computeCost(netTmpBBox); //cerr << _netCosts[netid][!_netFlags[netid]] << endl; } double BBPlacer::computeCost(const Box& box) const { if (!box.isEmpty()) return DbU::getLambda(box.getYMax() - box.getYMin() + box.getXMax() - box.getXMin()); else return 0.0; } double BBPlacer::CurrentNetCost(unsigned netid) { if (_netCurrCostMark[netid] != _costFlag) { _netCurrCostMark[netid] = _costFlag; return _netCosts[netid][_netFlags[netid]]; } return 0; } }