diff --git a/etesian/src/AddFeeds.cpp b/etesian/src/AddFeeds.cpp index a3bc3ecf..716a52f3 100644 --- a/etesian/src/AddFeeds.cpp +++ b/etesian/src/AddFeeds.cpp @@ -347,10 +347,12 @@ namespace Etesian { _ySpinSet = false; _yspinSlice0 = 0; - Box topCellAb = getBlockCell()->getAbutmentBox(); + Box blockAb = getBlockCell()->getAbutmentBox(); + if (not _placeArea.isEmpty()) + blockAb = _placeArea; - if (not topCellAb.isEmpty()) { - for ( Occurrence occurrence : getBlockCell()->getTerminalNetlistInstanceOccurrences() ) + if (not blockAb.isEmpty()) { + for ( Occurrence occurrence : getCell()->getTerminalNetlistInstanceOccurrences() ) { Instance* instance = static_cast(occurrence.getEntity()); Cell* masterCell = instance->getMasterCell(); @@ -360,11 +362,11 @@ namespace Etesian { occurrence.getPath().getTransformation().applyOn( instanceTransf ); instanceTransf.applyOn( instanceAb ); - if (not topCellAb.contains(instanceAb)) continue; + if (not blockAb.contains(instanceAb)) continue; _ySpinSet = true; - int islice = (instanceAb.getYMin() - getBlockCell()->getAbutmentBox().getYMin()) / getSliceHeight(); + int islice = (instanceAb.getYMin() - blockAb.getYMin()) / getSliceHeight(); switch ( instanceTransf.getOrientation() ) { case Transformation::Orientation::ID: diff --git a/etesian/src/CMakeLists.txt b/etesian/src/CMakeLists.txt index 2a15c050..9d15d126 100644 --- a/etesian/src/CMakeLists.txt +++ b/etesian/src/CMakeLists.txt @@ -25,6 +25,7 @@ set( cpps Configuration.cpp AddFeeds.cpp Placement.cpp + FlattenPower.cpp FeedCells.cpp BloatCells.cpp BloatProperty.cpp diff --git a/etesian/src/EtesianEngine.cpp b/etesian/src/EtesianEngine.cpp index ba860b07..c46049b8 100644 --- a/etesian/src/EtesianEngine.cpp +++ b/etesian/src/EtesianEngine.cpp @@ -469,6 +469,16 @@ namespace Etesian { , DbU::toFloor( placeArea.getXMax(), sliceHeight ) , DbU::toFloor( placeArea.getYMax(), sliceHeight ) ); + size_t bottomSlice = (_placeArea.getYMin() - topAb.getYMin()) / sliceHeight; + if (bottomSlice % 2) + throw Error( "EtesianEngine::setPlaceArea(): placedArea bottom must be on an even slice relative to topAb.\n" + " * placedArea=%s\n" + " * topAb=%s\n" + " * bottomSlice=%u\n" + , getString(placeArea).c_str() + , getString(topAb).c_str() + , bottomSlice + ); } void EtesianEngine::setDefaultAb () @@ -1292,7 +1302,7 @@ namespace Etesian { setDefaultAb(); } - findYSpin(); + //findYSpin(); if (not toColoquinte()) return; Effort placementEffort = getPlaceEffort(); diff --git a/etesian/src/FlattenPower.cpp b/etesian/src/FlattenPower.cpp new file mode 100644 index 00000000..34742677 --- /dev/null +++ b/etesian/src/FlattenPower.cpp @@ -0,0 +1,983 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2021-2021, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | E t e s i a n - A n a l y t i c P l a c e r | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +// | =============================================================== | +// | C++ Module : "./FlattenPower.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "vlsisapd/configuration/Configuration.h" +#include "hurricane/DebugSession.h" +#include "hurricane/UpdateSession.h" +#include "hurricane/Error.h" +#include "hurricane/Warning.h" +#include "hurricane/DataBase.h" +#include "hurricane/Technology.h" +#include "hurricane/BasicLayer.h" +#include "hurricane/RegularLayer.h" +#include "hurricane/Pad.h" +#include "hurricane/Horizontal.h" +#include "hurricane/Vertical.h" +#include "hurricane/Rectilinear.h" +#include "hurricane/RoutingPad.h" +#include "hurricane/NetExternalComponents.h" +#include "hurricane/NetRoutingProperty.h" +#include "hurricane/Instance.h" +#include "hurricane/Plug.h" +#include "hurricane/Path.h" +#include "hurricane/Query.h" +#include "crlcore/AllianceFramework.h" +#include "crlcore/RoutingGauge.h" +#include "etesian/EtesianEngine.h" + + +namespace { + + using namespace std; + using namespace Hurricane; + using CRL::AllianceFramework; + using CRL::RoutingGauge; + using CRL::RoutingLayerGauge; + + +// ------------------------------------------------------------------- +// Local Functions. + + void destroyRing ( Net* net ) + { + for( RoutingPad* rp : net->getRoutingPads() ) { + bool allMasters = true; + vector ring; + for( Hook* hook : rp->getBodyHook()->getHooks() ) { + if (not hook->isMaster()) { allMasters = false; break; } + ring.push_back( hook ); + } + if (allMasters) { + for ( auto hook : ring ) { + hook->_setNextHook( hook ); + } + } + } + } + + +// ------------------------------------------------------------------- +// Class : "::GlobalNetTable". + + class GlobalNetTable { + public: + GlobalNetTable ( Cell* ); + inline Cell* getTopCell () const; + Net* getRootNet ( const Net*, Path ) const; + inline Net* getVdd () const; + inline Net* getVss () const; + inline Net* getBlockage () const; + inline void setBlockage ( Net* ); + private: + bool guessGlobalNet ( const Name&, Net* ); + private: + uint32_t _flags; + Name _vddCoreName; + Name _vssCoreName; + Net* _vdd; + Net* _vss; + Net* _blockage; + Cell* _topCell; + }; + + + inline Cell* GlobalNetTable::getTopCell () const { return _topCell; } + inline Net* GlobalNetTable::getVdd () const { return _vdd; } + inline Net* GlobalNetTable::getVss () const { return _vss; } + inline Net* GlobalNetTable::getBlockage () const { return _blockage; } + inline void GlobalNetTable::setBlockage ( Net* net ) { _blockage=net; } + + GlobalNetTable::GlobalNetTable ( Cell* topCell ) + : _flags (0) + , _vddCoreName() + , _vssCoreName() + , _vdd (NULL) + , _vss (NULL) + , _blockage (NULL) + , _topCell (topCell) + { + if (_topCell == NULL) return; + + cmess1 << " o Looking for powers/grounds & clocks." << endl; + + for( Net* net : _topCell->getNets() ) { + Net::Type netType = net->getType(); + + if (NetRoutingExtension::isManualDetailRoute(net)) continue; + if (NetRoutingExtension::isManualGlobalRoute(net)) continue; + + if (netType == Net::Type::POWER) { + if (_vddCoreName.isEmpty()) { + _vddCoreName = net->getName(); + _vdd = net; + } else { + cerr << Error("Second power supply net <%s> net at top block level will be ignored.\n" + " (will consider only <%s>)" + , getString(net ->getName()).c_str() + , getString(_vdd->getName()).c_str() + ) << endl; + } + } + + if (netType == Net::Type::GROUND) { + if (_vssCoreName.isEmpty()) { + _vssCoreName = net->getName(); + _vss = net; + } else { + cerr << Error("Second power ground net <%s> net at top block level will be ignored.\n" + " (will consider only <%s>)" + , getString(net ->getName()).c_str() + , getString(_vss->getName()).c_str() + ) << endl; + } + } + } + + if (_vdd == NULL) cerr << Error("Missing POWER net at top block level." ) << endl; + else destroyRing( _vdd ); + if (_vss == NULL) cerr << Error("Missing GROUND net at top block level." ) << endl; + else destroyRing( _vss ); + } + + + bool GlobalNetTable::guessGlobalNet ( const Name& name, Net* net ) + { + if (name == _vddCoreName) { + cmess1 << " - Using <" << net->getName() << "> as core (internal:vdd) power net." << endl; + _vdd = net; + return true; + } + + if (name == _vssCoreName) { + cmess1 << " - Using <" << net->getName() << "> as core (internal:vss) ground net." << endl; + _vss = net; + return true; + } + + return false; + } + + + Net* GlobalNetTable::getRootNet ( const Net* net, Path path ) const + { + cdebug_log(159,0) << " getRootNet:" << path << ":" << net << endl; + + if (net == _blockage) return _blockage; + if (net->getType() == Net::Type::POWER ) return _vdd; + if (net->getType() == Net::Type::GROUND) return _vss; + return NULL; + } + + + class Rails; + class Plane; + + +// ------------------------------------------------------------------- +// Class : "::Rail". + + class Rail { + public: + Rail ( Rails*, DbU::Unit axis, DbU::Unit width ); + inline DbU::Unit getAxis () const; + inline DbU::Unit getWidth () const; + inline Rails* getRails () const; + inline uint32_t getDirection () const; + inline RoutingLayerGauge* getLayerGauge () const; + inline Net* getNet () const; + inline const Layer* getLayer () const; + void merge ( DbU::Unit source, DbU::Unit target ); + void doLayout ( const Layer* ); + string _getString () const; + private: + Rails* _rails; + DbU::Unit _axis; + DbU::Unit _width; + list _chunks; + }; + + + void Rail::merge ( DbU::Unit source, DbU::Unit target ) + { + Interval chunkToMerge ( source, target ); + cdebug_log(159,0) << " Rail::merge() " + << ((getDirection()==Constant::Horizontal) ? "Horizontal" : "Vertical") + << " " << chunkToMerge << endl; + cdebug_log(159,0) << " | " << _getString() << endl; + + list::iterator imerge = _chunks.end(); + list::iterator ichunk = _chunks.begin(); + + while ( ichunk != _chunks.end() ) { + if (imerge == _chunks.end()) { + if (chunkToMerge.getVMax() < (*ichunk).getVMin()) { + cdebug_log(159,0) << " | Insert before " << *ichunk << endl; + imerge = _chunks.insert( ichunk, chunkToMerge ); + break; + } + + if (chunkToMerge.intersect(*ichunk)) { + cdebug_log(159,0) << " | Merge with " << *ichunk << endl; + imerge = ichunk; + (*imerge).merge( chunkToMerge ); + } + } else { + if (chunkToMerge.getVMax() >= (*ichunk).getVMin()) { + (*imerge).merge( *ichunk ); + cdebug_log(159,0) << " | Absorb (erase) " << *ichunk << endl; + ichunk = _chunks.erase( ichunk ); + continue; + } else + break; + } + ++ichunk; + } + + if (imerge == _chunks.end()) { + _chunks.insert( ichunk, chunkToMerge ); + cdebug_log(159,0) << " | Insert at end " << DbU::getValueString(_axis) << " " << chunkToMerge << endl; + cdebug_log(159,0) << " | " << _getString() << endl; + } + } + + + void Rail::doLayout ( const Layer* layer ) + { + cdebug_log(159,0) << "Doing layout of rail: " + << " " << layer->getName() + << " " << ((getDirection()==Constant::Horizontal) ? "Horizontal" : "Vertical") + << " @" << DbU::getValueString(_axis) << endl; + cdebug_log(159,0) << _getString() << endl; + + Net* net = getNet(); + RoutingLayerGauge* rg = getLayerGauge(); + Segment* segment = NULL; + DbU::Unit extension = layer->getExtentionCap(); + + cdebug_log(159,0) << " (pitch:" << DbU::getValueString(rg->getPitch()) + << " , ww/2:" << DbU::getValueString(rg->getHalfWireWidth()) + << ")" << endl; + + // if ( type == Constant::PinOnly ) { + // cdebug_log(159,0) << " Layer is PinOnly." << endl; + // return; + // } + + if ( getDirection() == Constant::Horizontal ) { + list::iterator ichunk = _chunks.begin(); + list::iterator ichunknext = ichunk; + ++ichunknext; + + for ( ; ichunk != _chunks.end() ; ++ichunk, ++ichunknext ) { + + if (ichunknext != _chunks.end()) { + if ((*ichunk).intersect(*ichunknext)) + cerr << Error( "Overlaping consecutive chunks in %s %s Rail @%s:\n" + " %s" + , getString(layer->getName()).c_str() + , ((getDirection()==Constant::Horizontal) ? "Horizontal" : "Vertical") + , DbU::getValueString(_axis).c_str() + , _getString().c_str() + ) << endl; + } + + cdebug_log(159,0) << " chunk: [" << DbU::getValueString((*ichunk).getVMin()) + << ":" << DbU::getValueString((*ichunk).getVMax()) << "]" << endl; + + segment = Horizontal::create ( net + , layer + , _axis + , _width + , (*ichunk).getVMin()+extension + , (*ichunk).getVMax()-extension + ); + if ( segment and net->isExternal() ) + NetExternalComponents::setExternal ( segment ); + } + } else { + list::iterator ichunk = _chunks.begin(); + for ( ; ichunk != _chunks.end() ; ichunk++ ) { + cdebug_log(159,0) << " chunk: [" << DbU::getValueString((*ichunk).getVMin()) + << ":" << DbU::getValueString((*ichunk).getVMax()) << "]" << endl; + + segment = Vertical::create ( net + , layer + , _axis + , _width + , (*ichunk).getVMin()+extension + , (*ichunk).getVMax()-extension + ); + if ( segment and net->isExternal() ) + NetExternalComponents::setExternal ( segment ); + } + } + } + + + string Rail::_getString () const + { + ostringstream os; + + os << "::const_iterator ichunk = _chunks.begin(); + for ( ; ichunk != _chunks.end() ; ++ichunk ) { + if (ichunk != _chunks.begin()) os << " "; + os << "[" << DbU::getValueString((*ichunk).getVMin()) + << " " << DbU::getValueString((*ichunk).getVMax()) << "]"; + } + os << ">"; + return os.str(); + } + + +// ------------------------------------------------------------------- +// Class : "::RailCompare" & "::RailMatch". + + class RailCompare { + public: + bool operator() ( const Rail* lhs, const Rail* rhs ); + }; + + + inline bool RailCompare::operator() ( const Rail* lhs, const Rail* rhs ) + { + if ( lhs->getAxis () < rhs->getAxis () ) return true; + if ( lhs->getWidth() < rhs->getWidth() ) return true; + return false; + } + + + class RailMatch : public unary_function { + public: + inline RailMatch ( DbU::Unit axis, DbU::Unit width ); + inline bool operator() ( const Rail* ); + private: + DbU::Unit _axis; + DbU::Unit _width; + }; + + + inline RailMatch::RailMatch ( DbU::Unit axis, DbU::Unit width ) + : _axis(axis) + , _width(width) + { } + + + inline bool RailMatch::operator() ( const Rail* rail ) + { return (rail->getAxis() == _axis) and (rail->getWidth() == _width); } + + +// ------------------------------------------------------------------- +// Class : "::Rails". + + class Rails { + public: + Rails ( Plane*, uint32_t direction, Net* ); + ~Rails (); + inline Plane* getPlane (); + inline uint32_t getDirection () const; + inline RoutingLayerGauge* getLayerGauge () const; + inline Net* getNet () const; + void merge ( const Box& ); + void doLayout ( const Layer* ); + private: + Plane* _plane; + uint32_t _direction; + Net* _net; + vector _rails; + }; + + +// Delayed "::Rail" functions. + + Rail::Rail ( Rails* rails, DbU::Unit axis, DbU::Unit width ) + : _rails (rails) + , _axis (axis) + , _width (width) + , _chunks() + { + cdebug_log(159,0) << " new Rail " + << " @" << DbU::getValueString(axis) + << " " << getLayer()->getName() + << " " << getRails()->getNet() + << " " << ((getDirection()==Constant::Horizontal) ? "Horizontal" : "Vertical")<< endl; + } + + inline DbU::Unit Rail::getAxis () const { return _axis; } + inline DbU::Unit Rail::getWidth () const { return _width; } + inline Rails* Rail::getRails () const { return _rails; } + inline uint32_t Rail::getDirection () const { return _rails->getDirection(); } + inline RoutingLayerGauge* Rail::getLayerGauge () const { return _rails->getLayerGauge(); } + inline Net* Rail::getNet () const { return _rails->getNet(); } + +// Delayed "::Rail" functions. + + + Rails::Rails ( Plane* plane, uint32_t direction , Net* net ) + : _plane (plane) + , _direction (direction) + , _net (net) + , _rails () + { + cdebug_log(159,0) << " new Rails @" + << " " << getLayerGauge()->getLayer()->getName() + << " " << net + << " " << ((getDirection()==Constant::Horizontal) ? "Horizontal": "Vertical") << endl; + } + + + Rails::~Rails () + { + while ( not _rails.empty() ) { + delete (*_rails.begin()); + _rails.erase ( _rails.begin() ); + } + } + + + inline Plane* Rails::getPlane () { return _plane; } + inline uint32_t Rails::getDirection () const { return _direction; } + inline Net* Rails::getNet () const { return _net; } + + + void Rails::merge ( const Box& bb ) + { + DbU::Unit axis; + DbU::Unit width; + DbU::Unit sourceU; + DbU::Unit targetU; + + if (getDirection() == Constant::Horizontal) { + axis = bb.getYCenter(); + width = bb.getHeight(); + sourceU = bb.getXMin(); + targetU = bb.getXMax(); + } else { + axis = bb.getXCenter(); + width = bb.getWidth(); + sourceU = bb.getYMin(); + targetU = bb.getYMax(); + } + + vector::iterator irail = find_if ( _rails.begin(), _rails.end(), RailMatch(axis,width) ); + + Rail* rail = NULL; + if ( irail == _rails.end() ) { + rail = new Rail(this,axis,width); + _rails.push_back ( rail ); + stable_sort ( _rails.begin(), _rails.end(), RailCompare() ); + } else { + rail = *irail; + } + + rail->merge ( sourceU, targetU ); + } + + + void Rails::doLayout ( const Layer* layer ) + { + cdebug_log(159,0) << "Doing layout of rails: " << layer->getName() + << " " << ((_direction==Constant::Horizontal) ? "Horizontal" : "Vertical") + << " " << _net->getName() << endl; + + for ( size_t irail=0 ; irail<_rails.size() ; irail++ ) + _rails[irail]->doLayout ( layer ); + } + + +// ------------------------------------------------------------------- +// Class : "::Plane". + + class Plane { + public: + typedef map RailsMap; + public: + Plane ( const Layer*, RoutingLayerGauge* ); + ~Plane (); + inline const Layer* getLayer () const; + inline uint32_t getDirection () const; + inline RoutingLayerGauge* getLayerGauge () const; + inline uint32_t getPowerDirection () const; + void merge ( const Box&, Net* ); + void doLayout (); + private: + const Layer* _layer; + RoutingLayerGauge* _layerGauge; + RailsMap _horizontalRails; + RailsMap _verticalRails; + uint32_t _powerDirection; + }; + + + +// Delayed ::Rails function. + + inline const Layer* Rail::getLayer () const { return _rails->getPlane()->getLayer(); } + + inline RoutingLayerGauge* Rails::getLayerGauge () const { return _plane->getLayerGauge(); } + +// Delayed ::Rails function. + + + Plane::Plane ( const Layer* layer, RoutingLayerGauge* layerGauge ) + : _layer (layer) + , _layerGauge (layerGauge) + , _horizontalRails() + , _verticalRails () + , _powerDirection (layerGauge->getDirection()) + { + cdebug_log(159,0) << "New Plane " << _layer->getName() << " " << _layerGauge << endl; + + // Hard-coded SxLib gauge. + if (_layerGauge->getDepth() == 0) _powerDirection = Constant::Horizontal; + } + + + Plane::~Plane () + { + RailsMap::iterator irail = _horizontalRails.begin(); + for ( ; irail != _horizontalRails.end() ; ++irail ) { + delete (*irail).second; + } + irail = _verticalRails.begin(); + for ( ; irail != _verticalRails.end() ; ++irail ) { + delete (*irail).second; + } + } + + + inline const Layer* Plane::getLayer () const { return _layer; } + inline RoutingLayerGauge* Plane::getLayerGauge () const { return _layerGauge; } + inline uint32_t Plane::getDirection () const { return _layerGauge->getDirection(); } + inline uint32_t Plane::getPowerDirection () const { return _powerDirection; } + + void Plane::merge ( const Box& bb, Net* net ) + { + Rails* rails = NULL; + + cdebug_log(159,0) << " Plane::merge() " << net->getName() << " " << bb << endl; + + uint32_t direction = getDirection(); + if ( (net->getType() == Net::Type::POWER) or (net->getType() == Net::Type::GROUND) ) + direction = getPowerDirection(); + + if (direction == Constant::Horizontal) { + RailsMap::iterator irails = _horizontalRails.find(net); + if ( irails == _horizontalRails.end() ) { + rails = new Rails( this, Constant::Horizontal, net ); + _horizontalRails.insert ( make_pair(net,rails) ); + } else + rails = (*irails).second; + + rails->merge ( bb ); + } else { + RailsMap::iterator irails = _verticalRails.find(net); + if ( irails == _verticalRails.end() ) { + rails = new Rails( this, Constant::Vertical, net ); + _verticalRails.insert ( make_pair(net,rails) ); + } else + rails = (*irails).second; + + cdebug_log(159,0) << " Vertical Merging" << endl; + rails->merge ( bb ); + } + } + + + void Plane::doLayout () + { + cdebug_log(159,0) << "Doing layout of plane: " << _layer->getName() << endl; + + RailsMap::iterator irails = _horizontalRails.begin(); + for ( ; irails != _horizontalRails.end() ; ++irails ) { + (*irails).second->doLayout(_layer); + } + irails = _verticalRails.begin(); + for ( ; irails != _verticalRails.end() ; ++irails ) { + (*irails).second->doLayout(_layer); + } + } + + +// ------------------------------------------------------------------- +// Class : "::PowerRailsPlanes". + + class PowerRailsPlanes { + public: + typedef map PlanesMap; + public: + PowerRailsPlanes ( Cell*, RoutingGauge* ); + ~PowerRailsPlanes (); + inline Net* getRootNet ( Net*, Path ); + bool hasPlane ( const BasicLayer* ); + inline void setBlockageNet ( Net* ); + bool setActivePlane ( const BasicLayer* ); + inline Plane* getActivePlane () const; + inline Plane* getActiveBlockagePlane () const; + void merge ( const Box&, Net* ); + void doLayout (); + private: + Cell* _topCell; + GlobalNetTable _globalNets; + PlanesMap _planes; + Plane* _activePlane; + Plane* _activeBlockagePlane; + }; + + + PowerRailsPlanes::PowerRailsPlanes ( Cell* topCell, RoutingGauge* rg ) + : _topCell (topCell) + , _globalNets (topCell) + , _planes () + , _activePlane (NULL) + , _activeBlockagePlane(NULL) + { + for ( RoutingLayerGauge* lg : rg->getLayerGauges() ) { + cdebug_log(159,0) << "Gauge: [" << lg->getDepth() << "] " << lg << endl; + + const BasicLayer* basicLayer = dynamic_cast( lg->getLayer() ); + if (not basicLayer) + basicLayer = dynamic_cast( lg->getLayer() )->getBasicLayer(); + + _planes.insert( make_pair(basicLayer,new Plane(lg->getLayer(),lg)) ); + + //if (lg->getType() == Constant::PinOnly) continue; + const BasicLayer* blockageLayer = dynamic_cast( lg->getBlockageLayer() ); + if (not blockageLayer) continue; + + _planes.insert( make_pair(blockageLayer,new Plane(blockageLayer,lg)) ); + } + } + + + PowerRailsPlanes::~PowerRailsPlanes () + { + while ( not _planes.empty() ) { + delete _planes.begin()->second; + _planes.erase ( _planes.begin() ); + } + } + + + inline Net* PowerRailsPlanes::getRootNet ( Net* net, Path path ) + { return _globalNets.getRootNet(net,path); } + + + bool PowerRailsPlanes::hasPlane ( const BasicLayer* layer ) + { return (_planes.find(layer) != _planes.end()); } + + + inline void PowerRailsPlanes::setBlockageNet ( Net* blockageNet ) + { _globalNets.setBlockage( blockageNet ); } + + + bool PowerRailsPlanes::setActivePlane ( const BasicLayer* layer ) + { + PlanesMap::iterator iplane = _planes.find(layer); + if (iplane == _planes.end()) return false; + + _activePlane = iplane->second; + _activeBlockagePlane = NULL; + if (layer->getMaterial() != BasicLayer::Material::blockage) { + BasicLayer* blockageLayer = layer->getBlockageLayer(); + PlanesMap::iterator ibplane = _planes.find(blockageLayer); + if (ibplane != _planes.end()) + _activeBlockagePlane = ibplane->second; + } + return true; + } + + + inline Plane* PowerRailsPlanes::getActivePlane () const + { return _activePlane; } + + + inline Plane* PowerRailsPlanes::getActiveBlockagePlane () const + { return _activeBlockagePlane; } + + + void PowerRailsPlanes::merge ( const Box& bb, Net* net ) + { + if (not _activePlane) return; + + Net* topGlobalNet = _globalNets.getRootNet( net, Path() ); + if (topGlobalNet == NULL) { + cdebug_log(159,0) << "Not a global net: " << net << endl; + return; + } + + if ( (topGlobalNet == _globalNets.getBlockage()) and (_activeBlockagePlane != NULL) ) + _activeBlockagePlane->merge( bb, topGlobalNet ); + else + _activePlane->merge( bb, topGlobalNet ); + } + + + void PowerRailsPlanes::doLayout () + { + PlanesMap::iterator iplane = _planes.begin(); + for ( ; iplane != _planes.end() ; iplane++ ) + iplane->second->doLayout (); + } + + + +// ------------------------------------------------------------------- +// Class : "::QueryPowerRails". + + class QueryPowerRails : public Query { + public: + QueryPowerRails ( Cell*, RoutingGauge* ); + virtual bool hasGoCallback () const; + virtual void setBasicLayer ( const BasicLayer* ); + virtual bool hasBasicLayer ( const BasicLayer* ); + inline Net* getBlockageNet () const; + virtual void goCallback ( Go* ); + virtual void rubberCallback ( Rubber* ); + virtual void extensionGoCallback ( Go* ); + virtual void masterCellCallback (); + void addToPowerRail ( const Go* go + , const BasicLayer* basicLayer + , const Box& area + , const Transformation& transformation + ); + virtual void doQuery (); + inline void doLayout (); + inline uint32_t getGoMatchCount () const; + private: + AllianceFramework* _framework; + Cell* _topCell; + Net* _blockageNet; + RoutingGauge* _routingGauge; + PowerRailsPlanes _powerRailsPlanes; + bool _isBlockagePlane; + uint32_t _goMatchCount; + }; + + + QueryPowerRails::QueryPowerRails ( Cell* topCell, RoutingGauge* rg ) + : Query () + , _framework (AllianceFramework::get()) + , _topCell (topCell) + , _blockageNet (topCell->getNet("blockagenet")) + , _routingGauge (rg) + , _powerRailsPlanes(topCell,rg) + , _isBlockagePlane (false) + , _goMatchCount (0) + { + setCell ( topCell ); + setArea ( topCell->getAbutmentBox() ); + setBasicLayer ( NULL ); + setFilter ( Query::DoTerminalCells|Query::DoComponents ); + + if (not _blockageNet) { + _blockageNet = Net::create( topCell, "blockagenet" ); + _blockageNet->setType( Net::Type::BLOCKAGE ); + } + _powerRailsPlanes.setBlockageNet( _blockageNet ); + + cmess1 << " o Building power rails." << endl; + } + + + inline uint32_t QueryPowerRails::getGoMatchCount () const + { return _goMatchCount; } + + + inline Net* QueryPowerRails::getBlockageNet () const + { return _blockageNet; } + + + inline void QueryPowerRails::doLayout () + { return _powerRailsPlanes.doLayout(); } + + + bool QueryPowerRails::hasBasicLayer ( const BasicLayer* basicLayer ) + { return _powerRailsPlanes.hasPlane ( basicLayer ); } + + + void QueryPowerRails::setBasicLayer ( const BasicLayer* basicLayer ) + { + _isBlockagePlane = (basicLayer) and (basicLayer->getMaterial() == BasicLayer::Material::blockage); + _powerRailsPlanes.setActivePlane ( basicLayer ); + Query::setBasicLayer ( basicLayer ); + } + + + void QueryPowerRails::doQuery () + { + Plane* activePlane = _powerRailsPlanes.getActivePlane(); + + if (not activePlane) return; + + cmess1 << " - PowerRails in " << activePlane->getLayer()->getName() << " ..." << endl; + Query::doQuery(); + } + + + void QueryPowerRails::masterCellCallback () + { } + + + bool QueryPowerRails::hasGoCallback () const + { return true; } + + + void QueryPowerRails::goCallback ( Go* go ) + { + //ltrace(80) << "QueryPowerRails::goCallback() " << go->getId() << ":" << go + // << " " << getPath().getName() << endl; + addToPowerRail ( go, getBasicLayer(), getArea(), getTransformation() ); + } + + + void QueryPowerRails::addToPowerRail ( const Go* go + , const BasicLayer* basicLayer + , const Box& area + , const Transformation& transformation + ) + { + cdebug_log(159,0) << "addToPowerRail: go=" << go << endl; + const Component* component = dynamic_cast( go ); + if (component) { + if ( _framework->isPad(getMasterCell()) + and ( (_routingGauge->getLayerDepth(component->getLayer()) < 2) + or (component->getLayer()->getBasicLayers().getFirst()->getMaterial() + != BasicLayer::Material::blockage) ) ) + return; + + Net* rootNet = _blockageNet; + if (not _isBlockagePlane) { + rootNet = _powerRailsPlanes.getRootNet(component->getNet(),getPath()); + if (not NetExternalComponents::isExternal(component)) return; + } + if (not rootNet) { + cdebug_log(159,0) << " rootNet is NULL, not taken into account." << endl; + return; + } + cdebug_log(159,0) << " rootNet " << rootNet << " " + << go->getCell() << " (" << go->getCell()->isTerminal() << ")" << endl; + + const Segment* segment = dynamic_cast( component ); + if (segment) { + _goMatchCount++; + cdebug_log(159,0) << " Merging PowerRail element: " << segment << endl; + + Box bb = segment->getBoundingBox( basicLayer ); + transformation.applyOn( bb ); + _powerRailsPlanes.merge( bb, rootNet ); + } else { + const Contact* contact = dynamic_cast( component ); + if (contact) { + _goMatchCount++; + + Box bb = contact->getBoundingBox( basicLayer ); + transformation.applyOn( bb ); + + cdebug_log(159,0) << " Merging PowerRail element: " << contact << " bb:" << bb + << " " << basicLayer << endl; + + _powerRailsPlanes.merge( bb, rootNet ); + } else { + const Pad* pad = dynamic_cast( component ); + if (pad) { + _goMatchCount++; + + Box bb = pad->getBoundingBox( basicLayer ); + transformation.applyOn( bb ); + + cdebug_log(159,0) << " Merging PowerRail element: " << pad << " bb:" << bb + << " " << basicLayer << endl; + + _powerRailsPlanes.merge( bb, rootNet ); + } else { + const Rectilinear* rectilinear = dynamic_cast( component ); + if (rectilinear and (rectilinear->getPoints().size() == 5)) { + _goMatchCount++; + + Box bb = rectilinear->getBoundingBox( basicLayer ); + transformation.applyOn( bb ); + + cdebug_log(159,0) << " Merging PowerRail element: " << rectilinear << " bb:" << bb + << " " << basicLayer << endl; + + _powerRailsPlanes.merge( bb, rootNet ); + } + } + } + } + } + } + + + void QueryPowerRails::rubberCallback ( Rubber* ) + { } + + + void QueryPowerRails::extensionGoCallback ( Go* ) + { } + + +} // anonymous namespace. + + +namespace Etesian { + + + using Hurricane::UpdateSession; + using Hurricane::DataBase; + using Hurricane::Technology; + using Hurricane::BasicLayer; + + + void EtesianEngine::flattenPower () + { + string gaugeName = Cfg::getParamString("anabatic.routingGauge","sxlib")->asString(); + RoutingGauge* rg = AllianceFramework::get()->getRoutingGauge( gaugeName ); + if (not rg) + throw Error( "EtesianEngine::falttenPower(): No routing gauge named \"%s\"", gaugeName.c_str() ); + + //DebugSession::open( 150, 160 ); + UpdateSession::open(); + + Technology* technology = DataBase::getDB()->getTechnology(); + QueryPowerRails query ( getCell(), rg ); + query.setStopCellFlags( Cell::Flags::AbstractedSupply ); + + for ( BasicLayer* layer : technology->getBasicLayers() ) { + if ( (layer->getMaterial() != BasicLayer::Material::metal) + and (layer->getMaterial() != BasicLayer::Material::blockage) ) + continue; + if (not query.hasBasicLayer(layer)) continue; + + query.setBasicLayer( layer ); + query.doQuery (); + } + query.doLayout(); + cmess1 << " - " << query.getGoMatchCount() << " power rails elements found." << endl; + + getCell()->setFlags( Cell::Flags::AbstractedSupply ); + + UpdateSession::close(); + //DebugSession::close(); + } + + +} // Etesian namespace. diff --git a/etesian/src/PyEtesianEngine.cpp b/etesian/src/PyEtesianEngine.cpp index 12258222..baefcda5 100644 --- a/etesian/src/PyEtesianEngine.cpp +++ b/etesian/src/PyEtesianEngine.cpp @@ -75,6 +75,7 @@ extern "C" { DirectVoidMethod(EtesianEngine,etesian,setDefaultAb) DirectVoidMethod(EtesianEngine,etesian,resetPlacement) DirectVoidMethod(EtesianEngine,etesian,clearColoquinte) + DirectVoidMethod(EtesianEngine,etesian,flattenPower) DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine) DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine) DirectSetDoubleAttribute(PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine) @@ -261,6 +262,8 @@ extern "C" { , "De-allocate the Coloquinte related data structures." } , { "place" , (PyCFunction)PyEtesianEngine_place , METH_NOARGS , "Run the placer (Etesian)." } + , { "flattenPower" , (PyCFunction)PyEtesianEngine_flattenPower , METH_NOARGS + , "Build abstract interface in top cell for supply & blockages." } , { "destroy" , (PyCFunction)PyEtesianEngine_destroy , METH_NOARGS , "Destroy the associated hurricane object. The python object remains." } , {NULL, NULL, 0, NULL} /* sentinel */ diff --git a/etesian/src/etesian/EtesianEngine.h b/etesian/src/etesian/EtesianEngine.h index 5bcb9a41..dd3ca0ae 100644 --- a/etesian/src/etesian/EtesianEngine.h +++ b/etesian/src/etesian/EtesianEngine.h @@ -134,6 +134,7 @@ namespace Etesian { size_t findYSpin (); void addFeeds (); void toHurricane (); + void flattenPower (); inline void selectBloat ( std::string ); virtual Record* _getRecord () const; virtual std::string _getString () const;