coriolis/anabatic/src/Edge.cpp

533 lines
16 KiB
C++

// -*- mode: C++; explicit-buffer-name: "Edge.cpp<anabatic>" -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2016-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | A n a b a t i c - Global Routing Toolbox |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./Edge.cpp" |
// +-----------------------------------------------------------------+
#include <iostream>
#include "hurricane/Error.h"
#include "hurricane/Segment.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/DataBase.h"
#include "hurricane/Technology.h"
#include "anabatic/Edge.h"
#include "anabatic/GCell.h"
#include "anabatic/AnabaticEngine.h"
namespace {
using namespace std;
using namespace Hurricane;
class SortSegmentByLength {
public:
inline bool operator() ( const Segment*, const Segment* );
};
inline bool SortSegmentByLength::operator() ( const Segment* lhs, const Segment* rhs )
{
DbU::Unit delta = rhs->getLength() - lhs->getLength();
if (delta > 0) return true;
if (delta < 0) return false;
return (lhs->getId() < rhs->getId());
}
} // Anonymous namespace.
namespace Anabatic {
using std::cerr;
using std::endl;
using Hurricane::Error;
using Hurricane::RoutingPad;
Name Edge::_extensionName = "Anabatic::Edge";
DbU::Unit Edge::unity = 1;
Edge::Edge ( GCell* source, GCell* target, Flags flags )
: Super(source->getCell())
, _flags (flags|Flags::Invalidated)
, _capacities (NULL)
, _reservedCapacity (0)
, _realOccupancy (0)
, _estimateOccupancy(0.0)
, _historicCost (0.0)
, _source (source)
, _target (target)
, _axis (0)
, _segments ()
{ }
void Edge::_postCreate ()
{
Super::_postCreate();
if (_flags.isset(Flags::Horizontal)) {
_axis = std::max( _source->getYMin(), _target->getYMin() );
_source->_add( this, Flags::EastSide );
_target->_add( this, Flags::WestSide );
} else {
_axis = std::max( _source->getXMin(), _target->getXMin() );
_source->_add( this, Flags::NorthSide );
_target->_add( this, Flags::SouthSide );
}
}
Edge* Edge::create ( GCell* source, GCell* target, Flags flags )
{
if (not source) throw Error( "Edge::create(): NULL source argument." );
if (not target) throw Error( "Edge::create(): NULL target argument." );
if (source == target)
throw Error("Edge::create(): Source & target are the same (%s).", getString(source).c_str() );
if (not (flags.intersect(Flags::Horizontal|Flags::Vertical))) {
Box border = GCell::getBorder( source, target );
if (border.isEmpty())
throw Error( "Edge::create(): source & target GCells are *not* contiguous.\n"
" source:%s\n"
" target:%s"
, getString(source).c_str()
, getString(target).c_str()
);
if (border.getYMin() == border.getYMax()) flags |= Flags::Horizontal;
else flags |= Flags::Vertical;
}
Edge* edge = new Edge ( source, target, flags );
edge->_postCreate();
cdebug_log(110,1) << "Edge::create(): " << /*(void*)edge << ":" <<*/ edge << endl;
cdebug_log(110,0) << "source:" << /*(void*)source << ":" <<*/ edge->getSource() << endl;
cdebug_log(110,0) << "target:" << /*(void*)target << ":" <<*/ edge->getTarget() << endl;
cdebug_tabw(110,-1);
return edge;
}
Edge::~Edge ()
{ }
void Edge::_preDestroy ()
{
_source->getAnabatic()->_unrefCapacity( _capacities );
_source->_remove( this, _flags|Flags::Source );
_target->_remove( this, _flags|Flags::Target );
Super::_preDestroy();
}
void Edge::destroy ()
{
_preDestroy();
delete this;
}
AnabaticEngine* Edge::getAnabatic () const
{ return (_source) ? _source->getAnabatic() : NULL; }
DbU::Unit Edge::getAxisMin () const
{
if (_flags.isset(Flags::Vertical))
return std::max( _source->getXMin(), _target->getXMin() );
return std::max( _source->getYMin(), _target->getYMin() );
}
GCell* Edge::getOpposite ( const GCell* from ) const
{
if (from == _source) return _target;
if (from == _target) return _source;
cerr << Error( "Edge::getOpposite(): On %s,\n"
" \"from\" CGell id:%u is neither source nor target (S-id:%u, T-id:%u)."
, getString(this).c_str()
, from->getId()
, _source->getId()
, _target->getId()
) << endl;
return NULL;
}
Interval Edge::getSide () const
{
Interval side;
if (_flags.isset(Flags::Vertical))
side = Interval( std::max(_source->getXMin(),_target->getXMin())
, std::min(_source->getXMax(),_target->getXMax()) );
else
side = Interval( std::max(_source->getYMin(),_target->getYMin())
, std::min(_source->getYMax(),_target->getYMax()) );
return side;
}
DbU::Unit Edge::getDistance () const
{
Point sourceCenter = getSource()->getBoundingBox().getCenter();
Point targetCenter = getTarget()->getBoundingBox().getCenter();
DbU::Unit dx = targetCenter.getX() - sourceCenter.getX();
DbU::Unit dy = targetCenter.getY() - sourceCenter.getY();
if (dx < 0) dx = -dx;
//if (dx) dx += DbU::fromLambda( 0.1 );
return dx + ((dy > 0) ? dy : -dy);
}
void Edge::incRealOccupancy ( int delta )
{
unsigned int occupancy = 0;
if ((int)_realOccupancy + delta > 0) occupancy = _realOccupancy + delta;
if ((_realOccupancy <= getCapacity()) and (occupancy > getCapacity())) getAnabatic()->addOv ( this );
if ((_realOccupancy > getCapacity()) and (occupancy <= getCapacity())) getAnabatic()->removeOv( this );
_realOccupancy = occupancy;
}
void Edge::incRealOccupancy2 ( int value )
{
_realOccupancy += value;
}
Segment* Edge::getSegment ( const Net* owner ) const
{
for ( Segment* segment : _segments ) {
if (segment->getNet() == owner) return segment;
}
return NULL;
}
bool Edge::isEnding ( Segment* segment ) const
{
cdebug_log(112,0) << "Edge::isEnding() " << this << endl;
cdebug_log(112,0) << "| Sbb " << _source->getBoundingBox() << endl;
cdebug_log(112,0) << "| Tbb " << _target->getBoundingBox() << endl;
cdebug_log(112,0) << "| " << segment << endl;
if (Session::getRoutingGauge()->isTwoMetals()) {
Contact* contact = dynamic_cast<Contact*>( segment->getSource() );
cdebug_log(112,0) << "| source" << contact << endl;
if (contact) {
if ( (_source->isStdCellRow() and _source->getBoundingBox().contains(contact->getCenter()))
or (_target->isStdCellRow() and _target->getBoundingBox().contains(contact->getCenter())) )
return true;
}
contact = dynamic_cast<Contact*>( segment->getTarget() );
cdebug_log(112,0) << "| target" << contact << endl;
if (contact) {
if ( (_source->isStdCellRow() and _source->getBoundingBox().contains(contact->getCenter()))
or (_target->isStdCellRow() and _target->getBoundingBox().contains(contact->getCenter())) )
return true;
}
} else {
// This part is not used (yet). We don't call isEnding() when running
// in over-the-cell mode.
Contact* contact = dynamic_cast<Contact*>( segment->getSource() );
cdebug_log(112,0) << "| source" << contact << endl;
if (contact) {
for ( Hook* hook : contact->getBodyHook()->getHooks() ) {
if (dynamic_cast<RoutingPad*>(hook->getComponent())) {
if ( _source->getBoundingBox().contains(contact->getCenter())
or _target->getBoundingBox().contains(contact->getCenter()) )
return true;
break;
}
}
}
contact = dynamic_cast<Contact*>( segment->getTarget() );
cdebug_log(112,0) << "| target" << contact << endl;
if (contact) {
for ( Hook* hook : contact->getBodyHook()->getHooks() ) {
if (dynamic_cast<RoutingPad*>(hook->getComponent())) {
if ( _source->getBoundingBox().contains(contact->getCenter())
or _target->getBoundingBox().contains(contact->getCenter()) )
return true;
break;
}
}
}
}
return false;
}
void Edge::add ( Segment* segment )
{
_segments.push_back( segment );
Horizontal* h = dynamic_cast<Horizontal*>(segment);
Vertical* v = dynamic_cast<Vertical*>(segment);
DbU::Unit pitch = 0;
if (h) pitch = Session::getGHorizontalPitch();
if (v) pitch = Session::getGVerticalPitch();
int deltaOccupancy = 0;
if (not Session::getRoutingGauge()->isTwoMetals()) deltaOccupancy = segment->getWidth()/pitch;
else {
// In channel routing, do not increase edge occupancy on terminals,
// because the capacity has already been decreased in annotedGlobalGraph (Katana).
if (not isEnding(segment)) deltaOccupancy = segment->getWidth()/pitch;
}
incRealOccupancy( deltaOccupancy );
}
void Edge::remove ( Segment* segment )
{
for ( size_t i=0 ; i<_segments.size() ; ++i ) {
if (_segments[i] == segment) {
cdebug_log(110,0) << "On " << this << endl;
cdebug_log(110,0) << "| remove:" << segment << endl;
std::swap( _segments[i], _segments[_segments.size()-1] );
_segments.pop_back();
Horizontal* h = dynamic_cast<Horizontal*>(segment);
Vertical* v = dynamic_cast<Vertical*>(segment);
DbU::Unit pitch = 0;
if (h) pitch = Session::getGHorizontalPitch();
if (v) pitch = Session::getGVerticalPitch();
int deltaOccupancy = 0;
if (not Session::getRoutingGauge()->isTwoMetals()) deltaOccupancy = segment->getWidth()/pitch;
else {
// In channel routing, do not increase edge occupancy on terminals,
// because the capacity has already been decreased in annotedGlobalGraph (Katana).
if (not isEnding(segment)) deltaOccupancy = segment->getWidth()/pitch;
}
incRealOccupancy( -deltaOccupancy );
return;
}
}
cerr << Error( "On %s,\n segment doesn't belong: %s"
, getString(this).c_str()
, getString(segment).c_str() ) << endl;
}
void Edge::replace ( Segment* orig, Segment* repl )
{
for ( size_t i=0 ; i<_segments.size() ; ++i ) {
if (_segments[i] == orig) {
_segments[i] = repl;
return;
}
}
}
size_t Edge::ripup ()
{
AnabaticEngine* anabatic = getAnabatic();
DbU::Unit globalThreshold = Session::getSliceHeight()*3;
size_t netCount = 0;
sort( _segments.begin(), _segments.end(), SortSegmentByLength() );
if (Session::getRoutingGauge()->isTwoMetals()) {
for ( size_t i=0 ; i<_segments.size() ; ) {
if (not isEnding(_segments[i])) {
NetData* netData = anabatic->getNetData( _segments[i]->getNet() );
if (netData->isGlobalRouted()) ++netCount;
anabatic->ripup( _segments[i], Flags::Propagate );
continue;
}
++i;
}
} else {
size_t truncate = (size_t)( (getCapacity()*2) / 3 );
while ( _segments.size() > truncate ) {
NetData* netData = anabatic->getNetData( _segments[truncate]->getNet() );
if (netData->isGlobalRouted()) ++netCount;
anabatic->ripup( _segments[truncate], Flags::Propagate );
}
// for ( size_t i=0 ; i<_segments.size() ; ) {
// if (_segments[i]->getLength() >= globalThreshold) {
// NetData* netData = anabatic->getNetData( _segments[i]->getNet() );
// if (netData->isGlobalRouted()) ++netCount;
// anabatic->ripup( _segments[i], Flags::Propagate );
// } else {
// ++i;
// }
// }
}
return netCount;
}
void Edge::_setSource ( GCell* source )
{
if (source == _target)
throw Error("Edge::_setSource(): Source & target are the same (%s).", getString(source).c_str() );
invalidate( false );
_source=source;
}
void Edge::_setTarget ( GCell* target )
{
if (_source == target)
throw Error("Edge::_setTarget(): Source & target are the same (%s).", getString(target).c_str() );
invalidate( false );
_target=target;
}
void Edge::invalidate ( bool )
{
cdebug_log(110,1) << "Edge::invalidate() " << this << endl;
_flags |= Flags::Invalidated;
Super::invalidate( false );
cdebug_tabw(110,-1);
}
void Edge::materialize ()
{
cdebug_log(110,1) << "Edge::materialize() " << this << endl;
Flags flags = _flags;
Interval side = getSide();
_axis = side.getCenter();
if (getSource()->isStdCellRow() and getTarget()->isStdCellRow()) flags |= Flags::NullCapacity;
else if (getSource()->isChannelRow() and getTarget()->isChannelRow()) flags |= Flags::InfiniteCapacity;
_capacities = getAnabatic()->_createCapacity( _flags, side );
_flags.reset( Flags::Invalidated );
cdebug_log(110,0) << "Edge::materialize() " << this << endl;
Super::materialize();
cdebug_tabw(110,-1);
}
const Name& Edge::getName () const
{ return _extensionName; }
Box Edge::getBoundingBox () const
{
static DbU::Unit halfThickness = getAnabatic()->getConfiguration()->getEdgeWidth () / 2;
static DbU::Unit halfLength = getAnabatic()->getConfiguration()->getEdgeLength() / 2;
Box bb;
if (_flags.isset(Flags::Horizontal))
bb = Box( _target->getXMin() - halfLength, _axis - halfThickness
, _target->getXMin() + halfLength, _axis + halfThickness
);
else
bb = Box( _axis - halfThickness, _target->getYMin() - halfLength
, _axis + halfThickness, _target->getYMin() + halfLength
);
return bb;
}
bool Edge::isMaxCapacity ( Net* net ) const
{
unsigned int wpitch = 0;
if (net) {
cdebug_log(112,0) << "_capacity:" << getCapacity() << endl;
Hurricane::NetRoutingState* state = Hurricane::NetRoutingExtension::get( net );
wpitch = (state) ? state->getWPitch()-1 : 0;
}
return (_realOccupancy + wpitch >= getCapacity());
}
void Edge::translate ( const DbU::Unit&, const DbU::Unit& )
{
cerr << Error( "Edge::translate(): On %s,\n"
" Must never be called on a Edge object (ignored)."
, getString(this).c_str()
) << endl;
}
string Edge::_getTypeName () const
{ return getString(_extensionName); }
string Edge::_getString () const
{
Point center ( getSource()->getCenter() );
string s = Super::_getString();
s.insert( s.size()-1, " S:["+DbU::getValueString(center.getX()) );
s.insert( s.size()-1, " " +DbU::getValueString(center.getY()) );
s.insert( s.size()-1, "] " +DbU::getValueString(_axis) );
s.insert( s.size()-1, " " +getString(_realOccupancy) );
s.insert( s.size()-1, "/" +getString(getCapacity()) );
s.insert( s.size()-1, " h:" +getString(_historicCost) );
s.insert( s.size()-1, " " +getString(_flags) );
return s;
}
Record* Edge::_getRecord () const
{
Record* record = Super::_getRecord();
record->add( getSlot("_flags" , _flags ) );
record->add( getSlot("_capacities" , _capacities ) );
record->add( getSlot("_reservedCapacity" , _reservedCapacity ) );
record->add( getSlot("_realOccupancy" , _realOccupancy ) );
record->add( getSlot("_estimateOccupancy", _estimateOccupancy) );
record->add( getSlot("_source" , _source ) );
record->add( getSlot("_target" , _target ) );
record->add( DbU::getValueSlot("_axis", &_axis) );
record->add( getSlot("_segments" , &_segments ) );
return record;
}
} // Anabatic namespace.