514 lines
15 KiB
C++
514 lines
15 KiB
C++
|
|
// -*- 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 <algorithm>
|
|
|
|
#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<PowerRail*,PowerRail*,bool> {
|
|
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<RailSegment*> _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<RailSegment*>::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<RailSegment*>::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<RailSegment*>::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<PowerRail*> _hrails;
|
|
vector<PowerRail*> _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<PowerRail*>::const_iterator it
|
|
= lower_bound(_hrails.begin(),_hrails.end(),&bound,PowerRail::CompareByAxis());
|
|
return it - _hrails.begin();
|
|
}
|
|
|
|
vector<PowerRail*>::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<PowerRail*>* 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<const Layer*,PowerPlane*> _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<const Layer*,PowerPlane*>::iterator iplane = _planes.begin();
|
|
for ( ; iplane != _planes.end() ; iplane++ )
|
|
delete iplane->second;
|
|
}
|
|
|
|
|
|
PowerPlane* PowerGrid::getPlane ( const Layer* layer )
|
|
{
|
|
map<const Layer*,PowerPlane*>::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 Layer*,PowerPlane*>::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<Horizontal*>(*icomponent);
|
|
if ( horizontal )
|
|
powerGrid.merge ( pathTransf, horizontal );
|
|
else {
|
|
Vertical* vertical = dynamic_cast<Vertical*>(*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.
|