// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC/LIP6 2008-2013, All Rights Reserved // // +-----------------------------------------------------------------+ // | 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@lip6.fr | // | =============================================================== | // | C++ Module : "./PowerRails.cpp" | // +-----------------------------------------------------------------+ #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 (not _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 (not 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 (not _hrails.empty()) { delete _hrails.back(); _hrails.pop_back(); } while (not _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()) or ((*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 (not inet->isExternal()) { cerr << Warning("Ignoring non-external power net %s." ,getString(*inet).c_str()) << endl; continue; } _powerNet = *inet; break; } } if (not _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 (not inet->isExternal()) { cerr << Warning("Ignoring non-external ground net %s." ,getString(*inet).c_str()) << endl; continue; } _groundNet = *inet; break; } } if (not _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 (not 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 ); } } } // Anonymous 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(); } } // Katabatic namespace.