// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC/LIP6 2008-2009, All Rights Reserved // // =================================================================== // // $Id$ // // x-----------------------------------------------------------------x // | | // | C O R I O L I S | // | K a t a b a t i c - Routing Toolbox | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@asim.lip6.fr | // | =============================================================== | // | C++ Header : "./PowerRails.cpp" | // | *************************************************************** | // | U p d a t e s | // | | // x-----------------------------------------------------------------x #include #include "hurricane/Warning.h" #include "hurricane/DataBase.h" #include "hurricane/Technology.h" #include "hurricane/Horizontal.h" #include "hurricane/Vertical.h" #include "hurricane/Net.h" #include "hurricane/NetExternalComponents.h" #include "hurricane/Cell.h" #include "hurricane/Instance.h" #include "crlcore/RoutingLayerGauge.h" #include "crlcore/RoutingGauge.h" #include "katabatic/KatabaticEngine.h" namespace { using namespace std; using namespace Hurricane; // ------------------------------------------------------------------- // Class : "::RailSegment". class RailSegment { public: RailSegment ( DbU::Unit axis, DbU::Unit width ); inline DbU::Unit getAxis () const; inline DbU::Unit getMin () const; inline DbU::Unit getMax () const; inline const Interval& getSpan () const; inline DbU::Unit getWidth () const; void merge ( DbU::Unit ); void doLayout ( Cell*, Net*, const Layer*, Constant::Direction ) const; private: DbU::Unit _axis; DbU::Unit _width; Interval _span; }; RailSegment::RailSegment ( DbU::Unit axis, DbU::Unit width ) : _axis (axis) , _width(width) , _span () { } inline DbU::Unit RailSegment::getAxis () const { return _axis; } inline DbU::Unit RailSegment::getMin () const { return _span.getVMin(); } inline DbU::Unit RailSegment::getMax () const { return _span.getVMax(); } inline const Interval& RailSegment::getSpan () const { return _span; } inline DbU::Unit RailSegment::getWidth () const { return _width; } inline void RailSegment::merge ( DbU::Unit bound ) { _span.merge(bound); } void RailSegment::doLayout ( Cell* cell, Net* net, const Layer* layer, Constant::Direction direction ) const { Segment* segment = NULL; switch ( direction ) { case Constant::Horizontal: segment = Horizontal::create ( net , layer , _axis , _width , _span.getVMin() , _span.getVMax() ); break; case Constant::Vertical: segment = Vertical::create ( net , layer , _axis , _width , _span.getVMin() , _span.getVMax() ); break; } if ( segment ) NetExternalComponents::setExternal ( segment ); } // ------------------------------------------------------------------- // Class : "::PowerRail". class PowerRail { public: struct CompareByAxis : binary_function { bool operator() ( const PowerRail* lhs, const PowerRail* rhs ); }; public: PowerRail ( Net::Type, const Layer*, Constant::Direction, DbU::Unit axis ); ~PowerRail (); inline Net::Type getType () const; inline const Layer* getLayer () const; inline DbU::Unit getAxis () const; void merge ( DbU::Unit width, DbU::Unit min, DbU::Unit max ); void doLayout ( Cell*, Net* powerNet, Net* groundNet ) const; private: Net::Type _type; const Layer* _layer; Constant::Direction _direction; DbU::Unit _axis; list _segments; }; PowerRail::PowerRail ( Net::Type type, const Layer* layer, Constant::Direction direction, DbU::Unit axis ) : _type (type) , _layer (layer) , _direction(direction) , _axis (axis) , _segments () { } PowerRail::~PowerRail () { while ( !_segments.empty() ) { delete _segments.front (); _segments.pop_front (); } } inline Net::Type PowerRail::getType () const { return _type; } inline const Layer* PowerRail::getLayer () const { return _layer; } inline DbU::Unit PowerRail::getAxis () const { return _axis; } void PowerRail::merge ( DbU::Unit width, DbU::Unit min, DbU::Unit max ) { RailSegment* inserted = NULL; list::iterator isegment = _segments.begin(); for ( ; (isegment != _segments.end()) && !inserted ; isegment++ ) { if ( (*isegment)->getWidth() != width ) continue; if ( (*isegment)->getMin() > max ) { inserted = new RailSegment ( _axis, width ); inserted->merge ( min ); inserted->merge ( max ); _segments.insert ( isegment, inserted ); break; } if ( (*isegment)->getMax() < min ) { continue; } inserted = *isegment; (*isegment)->merge ( min ); (*isegment)->merge ( max ); list::iterator imerge = isegment; if ( imerge != _segments.end() ) imerge++; while ( imerge != _segments.end() ) { if ( (*imerge)->getMin() > (*isegment)->getMax() ) break; (*isegment)->merge ( (*imerge)->getMax() ); delete *imerge; _segments.erase ( imerge ); imerge = isegment; imerge++; } break; } if ( !inserted ) { inserted = new RailSegment ( _axis, width ); inserted->merge ( min ); inserted->merge ( max ); _segments.insert ( _segments.end(), inserted ); } } void PowerRail::doLayout ( Cell* cell, Net* powerNet, Net* groundNet ) const { //const Layer* layer = DataBase::getDB()->getTechnology()->getLayer("METAL1"); Net* railNet = (_type == Net::Type::POWER) ? powerNet : groundNet; list::const_iterator isegment = _segments.begin(); for ( ; isegment != _segments.end() ; isegment++ ) (*isegment)->doLayout ( cell, railNet, _layer, _direction ); } bool PowerRail::CompareByAxis::operator() ( const PowerRail* lhs, const PowerRail* rhs ) { return lhs->getAxis() < rhs->getAxis(); } // ------------------------------------------------------------------- // Class : "::PowerPlane". class PowerPlane { public: PowerPlane ( const Layer* ); ~PowerPlane (); inline const Layer* getLayer () const; size_t find ( DbU::Unit axis, Constant::Direction ) const; void merge ( Net::Type, Constant::Direction, DbU::Unit axis, DbU::Unit width, DbU::Unit min, DbU::Unit max ); void doLayout ( Cell* cell, Net* powerNet, Net* groundNet ) const; private: const Layer* _layer; vector _hrails; vector _vrails; }; PowerPlane::PowerPlane ( const Layer* layer ) : _layer (layer) , _hrails() , _vrails() { } PowerPlane::~PowerPlane () { while ( !_hrails.empty() ) { delete _hrails.back(); _hrails.pop_back (); } while ( !_vrails.empty() ) { delete _vrails.back(); _vrails.pop_back (); } } size_t PowerPlane::find ( DbU::Unit axis, Constant::Direction direction ) const { PowerRail bound(Net::Type::GROUND,NULL,Constant::Horizontal,axis); if ( direction == Constant::Horizontal ) { vector::const_iterator it = lower_bound(_hrails.begin(),_hrails.end(),&bound,PowerRail::CompareByAxis()); return it - _hrails.begin(); } vector::const_iterator it = lower_bound(_vrails.begin(),_vrails.end(),&bound,PowerRail::CompareByAxis()); return it - _vrails.begin(); } void PowerPlane::merge ( Net::Type type , Constant::Direction direction , DbU::Unit axis , DbU::Unit width , DbU::Unit rmin , DbU::Unit rmax ) { vector* rails; switch ( direction ) { case Constant::Vertical : rails = &_vrails; break; case Constant::Horizontal: default: rails = &_hrails; break; } size_t i = find ( axis, direction ); if ( ( i == rails->size() ) || ( (*rails)[i]->getAxis() != axis ) ) { PowerRail* rail = new PowerRail (type,_layer,direction,axis); rail->merge ( width, rmin, rmax ); rails->push_back ( rail ); sort ( rails->begin(), rails->end(), PowerRail::CompareByAxis() ); } else { if ( (*rails)[i]->getType() != type ) { cerr << Error("Short between power rails at %d.",DbU::getValueString(axis).c_str()) << endl; return; } (*rails)[i]->merge ( width, rmin, rmax ); } } void PowerPlane::doLayout ( Cell* cell, Net* powerNet, Net* groundNet ) const { for ( size_t i=0 ; i<_hrails.size() ; i++ ) _hrails[i]->doLayout ( cell, powerNet, groundNet ); for ( size_t i=0 ; i<_vrails.size() ; i++ ) _vrails[i]->doLayout ( cell, powerNet, groundNet ); } // ------------------------------------------------------------------- // Class : "::PowerRail". class PowerGrid { public: PowerGrid ( Cell* ); ~PowerGrid (); PowerPlane* getPlane ( const Layer* ); void merge ( const Transformation&, Horizontal* ); void merge ( const Transformation&, Vertical* ); void doLayout () const; private: Cell* _cell; Net* _powerNet; Net* _groundNet; map _planes; }; PowerGrid::PowerGrid ( Cell* cell ) : _cell (cell) , _powerNet (NULL) , _groundNet(NULL) , _planes () { forEach ( Net*, inet, _cell->getNets() ) { if ( (inet->getType() == Net::Type::POWER) ) { if ( !inet->isExternal() ) { cerr << Warning("Ignoring non-external power net %s." ,getString(*inet).c_str()) << endl; continue; } _powerNet = *inet; break; } } if ( !_powerNet ) cerr << Error("Missing POWER net in Cell %s.",getString(_cell->getName()).c_str()) << endl; forEach ( Net*, inet, _cell->getNets() ) { if ( inet->getType() == Net::Type::GROUND ) { if ( !inet->isExternal() ) { cerr << Warning("Ignoring non-external ground net %s." ,getString(*inet).c_str()) << endl; continue; } _groundNet = *inet; break; } } if ( !_groundNet ) cerr << Error("Missing GROUND net in Cell %s.",getString(_cell->getName()).c_str()) << endl; } PowerGrid::~PowerGrid () { map::iterator iplane = _planes.begin(); for ( ; iplane != _planes.end() ; iplane++ ) delete iplane->second; } PowerPlane* PowerGrid::getPlane ( const Layer* layer ) { map::iterator iplane = _planes.find(layer); if ( iplane != _planes.end() ) return iplane->second; PowerPlane* plane = new PowerPlane ( layer ); _planes.insert ( make_pair(layer,plane) ); return plane; } void PowerGrid::merge ( const Transformation& transformation, Horizontal* horizontal ) { PowerPlane* plane = getPlane ( horizontal->getLayer() ); Point source = horizontal->getSourcePosition(); Point target = horizontal->getTargetPosition(); transformation.applyOn ( source ); transformation.applyOn ( target ); if ( source.getX() > target.getX() ) swap ( source, target ); plane->merge ( horizontal->getNet()->getType() , Constant::Horizontal , source.getY() , horizontal->getWidth() , source.getX() , target.getX() ); } void PowerGrid::merge ( const Transformation& transformation, Vertical* vertical ) { PowerPlane* plane = getPlane ( vertical->getLayer() ); Point source = vertical->getSourcePosition(); Point target = vertical->getTargetPosition(); transformation.applyOn ( source ); transformation.applyOn ( target ); if ( source.getY() > target.getY() ) swap ( source, target ); plane->merge ( vertical->getNet()->getType() , Constant::Vertical , source.getX() , vertical->getWidth() , source.getY() , target.getY() ); } void PowerGrid::doLayout () const { map::const_iterator iplane = _planes.begin (); for ( ; iplane != _planes.end() ; iplane++ ) iplane->second->doLayout ( _cell, _powerNet, _groundNet ); } void copyUpPowerRails ( const Transformation& pathTransf , Cell* instanceCell , PowerGrid& powerGrid ) { forEach ( Net*, inet, instanceCell->getNets() ) { switch ( inet->getType() ) { case Net::Type::POWER: case Net::Type::GROUND: break; default: continue; } forEach ( Component*, icomponent, inet->getComponents() ) { if ( !NetExternalComponents::isExternal(*icomponent) ) continue; Horizontal* horizontal = dynamic_cast(*icomponent); if ( horizontal ) powerGrid.merge ( pathTransf, horizontal ); else { Vertical* vertical = dynamic_cast(*icomponent); if ( vertical ) powerGrid.merge ( pathTransf, vertical ); } } } forEach ( Instance*, iinstance, instanceCell->getInstances() ) { Transformation instanceTransf = iinstance->getTransformation(); pathTransf.applyOn ( instanceTransf ); copyUpPowerRails ( instanceTransf, iinstance->getMasterCell(), powerGrid ); } } } // End of local namespace. namespace Katabatic { using Hurricane::Point; using Hurricane::Horizontal; using Hurricane::Net; using Hurricane::Cell; using Hurricane::Instance; void KatabaticEngine::makePowerRails () { PowerGrid powerGrid ( getCell() ); Transformation topTransformation; // ID. copyUpPowerRails ( topTransformation, getCell(), powerGrid ); powerGrid.doLayout (); } } // End of Katabatic namespace.