2010-03-09 09:24:29 -06:00
|
|
|
|
|
|
|
// -*- C++ -*-
|
|
|
|
//
|
|
|
|
// This file is part of the Coriolis Software.
|
2010-04-23 08:13:54 -05:00
|
|
|
// Copyright (c) UPMC/LIP6 2008-2010, All Rights Reserved
|
2010-03-09 09:24:29 -06:00
|
|
|
//
|
|
|
|
// ===================================================================
|
|
|
|
//
|
|
|
|
// $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++ Module : "./AutoSegment.cpp" |
|
|
|
|
// | *************************************************************** |
|
|
|
|
// | U p d a t e s |
|
|
|
|
// | |
|
|
|
|
// x-----------------------------------------------------------------x
|
|
|
|
|
|
|
|
|
|
|
|
#include "hurricane/Warning.h"
|
|
|
|
#include "hurricane/Bug.h"
|
|
|
|
#include "hurricane/DataBase.h"
|
|
|
|
#include "hurricane/Technology.h"
|
|
|
|
#include "hurricane/Horizontal.h"
|
|
|
|
#include "hurricane/Vertical.h"
|
|
|
|
#include "crlcore/RoutingGauge.h"
|
|
|
|
|
|
|
|
#include "katabatic/Session.h"
|
|
|
|
#include "katabatic/AutoContact.h"
|
|
|
|
#include "katabatic/AutoSegment.h"
|
|
|
|
#include "katabatic/AutoHorizontal.h"
|
|
|
|
#include "katabatic/AutoVertical.h"
|
|
|
|
#include "katabatic/GCell.h"
|
|
|
|
#include "katabatic/KatabaticEngine.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace CRL;
|
|
|
|
using namespace Hurricane;
|
|
|
|
using namespace Katabatic;
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
|
|
// Local Variables.
|
|
|
|
|
|
|
|
|
|
|
|
const char* badAutoSegmentAnchor =
|
|
|
|
"AutoSegment::create() :\n\n"
|
|
|
|
" Source and/or target anchor is NOT an <AutoContact> (internal error).\n"
|
|
|
|
" Source: %s, Target: %s";
|
|
|
|
|
|
|
|
const char* dupAutoSegmentAnchor =
|
|
|
|
"AutoSegment::create() :\n\n"
|
|
|
|
" Source and Target anchor are the same : %s (internal error).";
|
|
|
|
|
|
|
|
const char* badSegment =
|
|
|
|
"Katabatic::AutoSegment::create () :\n\n"
|
|
|
|
" Segment between %s and %s\n"
|
|
|
|
" is neither horizontal nor vertical .\n";
|
|
|
|
|
|
|
|
const char* badSegmentSource =
|
|
|
|
"Katabatic::AutoSegment::create () :\n\n"
|
|
|
|
" Source anchor of segment %s is not a Contact\n"
|
|
|
|
" (%s)\n";
|
|
|
|
|
|
|
|
const char* badSegmentTarget =
|
|
|
|
"Katabatic::AutoSegment::create () :\n\n"
|
|
|
|
" Source anchor of segment %s is not a Contact\n"
|
|
|
|
" (%s)\n";
|
|
|
|
|
|
|
|
const char* mismatchSegmentSource =
|
|
|
|
"Katabatic::AutoSegment::create () :\n\n"
|
|
|
|
" Source anchor of segment %s is already an AutoContact\n"
|
|
|
|
" (%s)\n";
|
|
|
|
|
|
|
|
const char* mismatchSegmentTarget =
|
|
|
|
"Katabatic::AutoSegment::create () :\n\n"
|
|
|
|
" Target anchor of segment %s is already an AutoContact\n"
|
|
|
|
" (%s)\n";
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
|
|
// Local Functions.
|
|
|
|
|
|
|
|
|
|
|
|
bool getTerminalInterval ( AutoSegment* autoSegment
|
|
|
|
, AutoContact* fromContact
|
|
|
|
, bool isHorizontal
|
|
|
|
, DbU::Unit& min
|
|
|
|
, DbU::Unit& max
|
|
|
|
)
|
|
|
|
{
|
|
|
|
AutoContact* terminalContact = NULL;
|
|
|
|
|
|
|
|
if ( !fromContact ) {
|
|
|
|
bool found = getTerminalInterval ( autoSegment
|
|
|
|
, autoSegment->getAutoSource()
|
|
|
|
, autoSegment->isHorizontal()
|
|
|
|
, min
|
|
|
|
, max );
|
|
|
|
if ( !found )
|
|
|
|
found = getTerminalInterval ( autoSegment
|
|
|
|
, autoSegment->getAutoTarget()
|
|
|
|
, autoSegment->isHorizontal()
|
|
|
|
, min
|
|
|
|
, max );
|
|
|
|
|
|
|
|
//if ( !found )
|
|
|
|
// cerr << "[ERROR] Cannot find terminal of " << autoSegment << "." << endl;
|
|
|
|
|
|
|
|
return found;
|
|
|
|
} else {
|
|
|
|
if ( autoSegment->isGlobal() ) return false;
|
|
|
|
|
|
|
|
ltrace(88) << "Examining " << autoSegment << " " << fromContact << endl;
|
|
|
|
|
|
|
|
if ( autoSegment->getSource() == autoSegment->getTarget() ) {
|
|
|
|
cerr << Error("Source & Target are the same :\n"
|
|
|
|
" %s\n %s"
|
|
|
|
,getString(autoSegment).c_str()
|
|
|
|
,getString(autoSegment->getSource()).c_str()) << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
terminalContact = autoSegment->getAutoSource();
|
|
|
|
if ( terminalContact == fromContact ) {
|
|
|
|
terminalContact = autoSegment->getAutoTarget();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !terminalContact->isTerminal() ) {
|
|
|
|
AutoSegment* segment = NULL;
|
|
|
|
size_t segmentCount = 0;
|
|
|
|
forEach ( Component*, icomponent, terminalContact->getSlaveComponents() ) {
|
|
|
|
if ( *icomponent == autoSegment->getSegment() ) continue;
|
|
|
|
|
|
|
|
Segment* connex = dynamic_cast<Segment*>(*icomponent);
|
|
|
|
if ( !connex ) continue;
|
|
|
|
|
|
|
|
segment = Session::lookup ( connex );
|
|
|
|
if ( !segment || !segment->isTerminal() ) continue;
|
|
|
|
|
|
|
|
segmentCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( segmentCount == 1 ) {
|
|
|
|
return getTerminalInterval ( segment, terminalContact, isHorizontal, min, max );
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ltrace(88) << "Terminal is " << terminalContact << endl;
|
|
|
|
|
|
|
|
Box constraintBox = terminalContact->getConstraintBox();
|
|
|
|
if ( isHorizontal ) {
|
|
|
|
min = constraintBox.getXMin ();
|
|
|
|
max = constraintBox.getXMax ();
|
|
|
|
} else {
|
|
|
|
min = constraintBox.getYMin ();
|
|
|
|
max = constraintBox.getYMax ();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
|
|
// Class : "AttractorsMap".
|
|
|
|
|
|
|
|
|
|
|
|
class AttractorsMap {
|
|
|
|
// Constructor.
|
|
|
|
public:
|
|
|
|
inline AttractorsMap ();
|
|
|
|
inline size_t getAttractorsCount () const;
|
|
|
|
DbU::Unit getLowerMedian () const;
|
|
|
|
DbU::Unit getUpperMedian () const;
|
|
|
|
void addAttractor ( DbU::Unit position );
|
|
|
|
protected:
|
|
|
|
map<DbU::Unit,size_t> _attractors;
|
|
|
|
size_t _attractorsCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
inline AttractorsMap::AttractorsMap ()
|
|
|
|
: _attractors(), _attractorsCount(0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
inline size_t AttractorsMap::getAttractorsCount () const
|
|
|
|
{
|
|
|
|
return _attractorsCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AttractorsMap::addAttractor ( DbU::Unit position )
|
|
|
|
{
|
|
|
|
_attractors[position]++;
|
|
|
|
_attractorsCount++;
|
|
|
|
|
|
|
|
ltrace(88) << "add Attractor @" << DbU::getLambda(position)
|
|
|
|
<< " [" << _attractors[position] << "]" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DbU::Unit AttractorsMap::getLowerMedian () const
|
|
|
|
{
|
|
|
|
size_t median = (_attractorsCount/2) + (_attractorsCount%2);
|
|
|
|
size_t lower = 0;
|
|
|
|
|
|
|
|
map<DbU::Unit,size_t>::const_iterator it = _attractors.begin ();
|
|
|
|
for ( ; it != _attractors.end() ; it++ ) {
|
|
|
|
lower += it->second;
|
|
|
|
if ( lower >= median ) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return it->first;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DbU::Unit AttractorsMap::getUpperMedian () const
|
|
|
|
{
|
|
|
|
size_t median = _attractorsCount / 2;
|
|
|
|
size_t upper = 0;
|
|
|
|
|
|
|
|
map<DbU::Unit,size_t>::const_iterator it = _attractors.begin ();
|
|
|
|
for ( ; it != _attractors.end() ; it++ ) {
|
|
|
|
upper += it->second;
|
|
|
|
if ( upper > median ) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return it->first;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // End of local namespace.
|
|
|
|
|
|
|
|
|
|
|
|
namespace Katabatic {
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
// Class : "Katabatic::AutoSegment::CompareByDepthLength".
|
2010-03-09 09:24:29 -06:00
|
|
|
|
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
bool AutoSegment::CompareByDepthLength::operator() ( AutoSegment* lhs, AutoSegment* rhs ) const
|
2010-03-09 09:24:29 -06:00
|
|
|
{
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
int deltaDepth = (int)(Session::getRoutingGauge()->getLayerDepth(lhs->getLayer()))
|
|
|
|
- (int)(Session::getRoutingGauge()->getLayerDepth(rhs->getLayer()));
|
|
|
|
if ( deltaDepth < 0 ) return true; // Lowest layer first.
|
|
|
|
if ( deltaDepth > 0 ) return false;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
DbU::Unit deltaUnit = lhs->getSourceU() - rhs->getSourceU();
|
|
|
|
if ( deltaUnit < 0 ) return true; // Smallest source first.
|
|
|
|
if ( deltaUnit > 0 ) return false;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
deltaUnit = lhs->getLength() - rhs->getLength();
|
|
|
|
if ( deltaUnit > 0 ) return true; // Longest first.
|
|
|
|
if ( deltaUnit < 0 ) return true;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
deltaUnit = lhs->getAxis() - rhs->getAxis();
|
|
|
|
if ( deltaUnit < 0 ) return true; // Smallest axis first.
|
|
|
|
if ( deltaUnit > 0 ) return false;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
// if ( lhs->isCanonical () xor rhs->isCanonical () ) return lhs->isCanonical();
|
|
|
|
// if ( lhs->isCollapsed () xor rhs->isCollapsed () ) return rhs->isCollapsed();
|
|
|
|
// if ( lhs->isSlackenStrap() xor rhs->isSlackenStrap() ) return lhs->isSlackenStrap();
|
2010-03-09 09:24:29 -06:00
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
// if ( lhs->isGlobal () xor rhs->isGlobal () ) return lhs->isGlobal();
|
|
|
|
// if ( lhs->isTerminal () xor rhs->isTerminal () ) return rhs->isTerminal();
|
|
|
|
// if ( lhs->isHorizontal() xor rhs->isHorizontal() ) return lhs->isHorizontal();
|
2010-03-09 09:24:29 -06:00
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
// if ( lhs->isFixed() xor rhs->isFixed() ) return lhs->isFixed();
|
2010-03-09 09:24:29 -06:00
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
return lhs->getId() < rhs->getId();
|
2010-03-09 09:24:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-09 12:08:31 -06:00
|
|
|
// -------------------------------------------------------------------
|
|
|
|
// Class : "Katabatic::AutoSegment::CompareByDepthAxis".
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::CompareByDepthAxis::operator() ( AutoSegment* lhs, AutoSegment* rhs ) const
|
|
|
|
{
|
|
|
|
int deltaDepth = (int)(Session::getRoutingGauge()->getLayerDepth(lhs->getLayer()))
|
|
|
|
- (int)(Session::getRoutingGauge()->getLayerDepth(rhs->getLayer()));
|
|
|
|
if ( deltaDepth < 0 ) return true; // Lowest layer first.
|
|
|
|
if ( deltaDepth > 0 ) return false;
|
|
|
|
|
|
|
|
DbU::Unit deltaUnit = lhs->getAxis() - rhs->getAxis();
|
|
|
|
if ( deltaUnit < 0 ) return true; // Smallest axis first.
|
|
|
|
if ( deltaUnit > 0 ) return false;
|
|
|
|
|
|
|
|
deltaUnit = lhs->getSourceU() - rhs->getSourceU();
|
|
|
|
if ( deltaUnit < 0 ) return true; // Smallest source first.
|
|
|
|
if ( deltaUnit > 0 ) return false;
|
|
|
|
|
|
|
|
return lhs->getId() < rhs->getId(); // Smallest Id first.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-09 09:24:29 -06:00
|
|
|
// -------------------------------------------------------------------
|
|
|
|
// Class : "Katabatic::AutoSegment".
|
|
|
|
|
|
|
|
|
2010-04-23 08:13:54 -05:00
|
|
|
size_t AutoSegment::_allocateds = 0;
|
|
|
|
size_t AutoSegment::_globalsCount = 0;
|
|
|
|
unsigned long AutoSegment::_maxId = 0;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
|
|
|
|
|
|
|
DbU::Unit AutoSegment::getX () const
|
|
|
|
{
|
|
|
|
return getSegment()->getX();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DbU::Unit AutoSegment::getY () const
|
|
|
|
{
|
|
|
|
return getSegment()->getY();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoContact* AutoSegment::getOppositeAnchor ( AutoContact* anchor ) const
|
|
|
|
{
|
|
|
|
return Session::lookup(static_cast<Contact*>(getOppositeAnchor(anchor->getContact())));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Interval& AutoSegment::getOptimal ( Interval& i ) const
|
|
|
|
{
|
|
|
|
i.getVMin() = getOptimalMin();
|
|
|
|
i.getVMax() = getOptimalMax();
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::checkInvalidated () const
|
|
|
|
{
|
|
|
|
if ( isInvalidated() )
|
|
|
|
cerr << Error("%s is invalidated.",getString(this).c_str()) << endl;
|
|
|
|
|
|
|
|
return !isInvalidated();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::invalidate ()
|
|
|
|
{
|
|
|
|
if ( Session::doDestroyTool() ) return;
|
|
|
|
|
|
|
|
_invalidate ();
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() )
|
|
|
|
isegment->_invalidate ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::_invalidate ()
|
|
|
|
{
|
|
|
|
if ( !isInvalidated() ) {
|
|
|
|
ltrace(110) << "AutoSegment::_invalidate() " << this << endl;
|
|
|
|
|
|
|
|
setInvalidated ( true );
|
|
|
|
Session::invalidate ( this );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::revalidate ()
|
|
|
|
{
|
|
|
|
ltrace(110) << "AutoSegment::revalidate() " << this << endl;
|
|
|
|
ltracein(110);
|
|
|
|
|
|
|
|
setPositions ();
|
|
|
|
setInvalidated ( false );
|
|
|
|
|
|
|
|
ltraceout(110);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DbU::Unit AutoSegment::getSlack () const
|
|
|
|
{
|
|
|
|
DbU::Unit constraintMin;
|
|
|
|
DbU::Unit constraintMax;
|
|
|
|
|
|
|
|
getConstraints ( constraintMin, constraintMax );
|
|
|
|
|
|
|
|
return constraintMax - constraintMin;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DbU::Unit AutoSegment::getCost ( DbU::Unit axis ) const
|
|
|
|
{
|
|
|
|
DbU::Unit optimal = getOptimalMin();
|
|
|
|
if ( axis < optimal )
|
|
|
|
return optimal - axis;
|
|
|
|
|
|
|
|
optimal = getOptimalMax();
|
|
|
|
if ( axis > optimal )
|
|
|
|
return axis - optimal;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegment* AutoSegment::getCanonical ( DbU::Unit& min, DbU::Unit& max )
|
|
|
|
{
|
|
|
|
min = getSourcePosition ();
|
|
|
|
max = getTargetPosition ();
|
|
|
|
|
|
|
|
if ( max < min ) swap ( min, max );
|
|
|
|
|
|
|
|
AutoSegment* canonical = this;
|
|
|
|
size_t canonicals = isCanonical();
|
|
|
|
size_t aligneds = 1;
|
|
|
|
DbU::Unit collapsedMin;
|
|
|
|
DbU::Unit collapsedMax;
|
|
|
|
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
if ( isegment->isCanonical() ) {
|
|
|
|
canonical = *isegment;
|
|
|
|
canonicals++;
|
|
|
|
}
|
|
|
|
|
|
|
|
collapsedMin = isegment->getSourcePosition();
|
|
|
|
collapsedMax = isegment->getTargetPosition();
|
|
|
|
if ( collapsedMax < collapsedMin ) swap ( collapsedMin, collapsedMax );
|
|
|
|
if ( collapsedMin < min ) min = collapsedMin;
|
|
|
|
if ( collapsedMax > max ) max = collapsedMax;
|
|
|
|
|
|
|
|
aligneds++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (canonicals > 1) || ( !canonicals && (aligneds > 2) ) ) {
|
|
|
|
cerr << Bug("AutoSegment::getCanonical(): %p:%s"
|
|
|
|
"\n Bad canonization: %d canonicals out of %d collapseds."
|
|
|
|
, base(), _getString().c_str(), canonicals, aligneds ) << endl;
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
cerr << " " << count++ << ": " << this << endl;
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() )
|
|
|
|
cerr << " " << count++ << ": " << *isegment << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return canonical;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegments AutoSegment::getOnSourceContact ( unsigned int direction )
|
|
|
|
{
|
|
|
|
return AutoSegments_OnContact
|
|
|
|
( this, getSource() ).getSubSet ( AutoSegments_InDirection(direction) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegments AutoSegment::getOnTargetContact ( unsigned int direction )
|
|
|
|
{
|
|
|
|
return AutoSegments_OnContact
|
|
|
|
( this, getTarget() ).getSubSet ( AutoSegments_InDirection(direction) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegments AutoSegment::getCollapseds ( bool withPerpand )
|
|
|
|
{
|
|
|
|
return AutoSegments_Collapsed ( this, withPerpand );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegments AutoSegment::getCollapsedPerpandiculars ()
|
|
|
|
{
|
|
|
|
return AutoSegments_CollapsedPerpandicular ( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::isCanonicalStrap () const
|
|
|
|
{
|
|
|
|
if ( not isStrap() ) return false;
|
|
|
|
forEach ( AutoSegment*, isegment, const_cast<AutoSegment*>(this)->getCollapseds() ) {
|
|
|
|
if ( not isegment->isStrap() ) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::collapse ()
|
|
|
|
{
|
|
|
|
if ( _isGlobal ) {
|
|
|
|
cerr << Error("Global %s cannot be collapsed.",getString(this).c_str()) << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( _isCollapsed ) return true;
|
|
|
|
|
|
|
|
_isCollapsed = true;
|
|
|
|
|
|
|
|
unsigned int direction = (_isHorizontal) ? Constant::Vertical : Constant::Horizontal;
|
|
|
|
forEach ( AutoSegment*, isegment, AutoSegments_AnchoredBySource(getAutoSource(),direction) ) {
|
|
|
|
isegment->setCanonical ( false );
|
|
|
|
}
|
|
|
|
forEach ( AutoSegment*, isegment, AutoSegments_AnchoredBySource(getAutoTarget(),direction) ) {
|
|
|
|
isegment->setCanonical ( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::expand ()
|
|
|
|
{
|
|
|
|
if ( _isGlobal ) {
|
|
|
|
cerr << Warning("Global %s already uncollapsed.",getString(this).c_str()) << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( !_isCollapsed ) {
|
|
|
|
cerr << Warning("Local %s already uncollapsed.",getString(this).c_str()) << endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
_isCollapsed = false;
|
|
|
|
|
|
|
|
canonize ();
|
|
|
|
|
|
|
|
unsigned int direction = (_isHorizontal) ? Constant::Vertical : Constant::Horizontal;
|
|
|
|
forEach ( AutoSegment*, segment, getOnSourceContact(direction) ) {
|
|
|
|
segment->canonize ();
|
|
|
|
}
|
|
|
|
forEach ( AutoSegment*, segment, getOnTargetContact(direction) ) {
|
|
|
|
segment->canonize ();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::toConstraintAxis ( set<AutoSegment*>* processeds )
|
|
|
|
{
|
|
|
|
if ( processeds && (processeds->find(this) != processeds->end()) ) return false;
|
|
|
|
|
|
|
|
DbU::Unit constraintMin;
|
|
|
|
DbU::Unit constraintMax;
|
|
|
|
|
|
|
|
getConstraints ( constraintMin, constraintMax );
|
|
|
|
|
2010-05-11 06:04:23 -05:00
|
|
|
// Empty constraint interval: ignore.
|
|
|
|
if ( constraintMin > constraintMax ) return false;
|
|
|
|
|
2011-01-25 11:16:27 -06:00
|
|
|
if ( isDogleg() ) {
|
2010-03-09 09:24:29 -06:00
|
|
|
// Ugly: hard-wired value of the track spacing.
|
2011-01-25 11:16:27 -06:00
|
|
|
constraintMin -= DbU::lambda(25.0);
|
|
|
|
constraintMax += DbU::lambda(25.0);
|
2010-03-09 09:24:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( getAxis() < constraintMin ) {
|
|
|
|
setAxis ( constraintMin, Realignate, processeds );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( getAxis() > constraintMax ) {
|
|
|
|
setAxis ( constraintMax, Realignate, processeds );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::toOptimalAxis ( set<AutoSegment*>* processeds )
|
|
|
|
{
|
|
|
|
if ( processeds && (processeds->find(this) != processeds->end()) ) return false;
|
|
|
|
|
|
|
|
DbU::Unit constraintMin;
|
|
|
|
DbU::Unit constraintMax;
|
|
|
|
|
|
|
|
getConstraints ( constraintMin, constraintMax );
|
|
|
|
|
|
|
|
DbU::Unit optimalMin = max ( min(getOptimalMin(),constraintMax), constraintMin );
|
|
|
|
DbU::Unit optimalMax = min ( max(getOptimalMax(),constraintMin), constraintMax );
|
|
|
|
|
|
|
|
if ( getAxis() < optimalMin ) {
|
|
|
|
#if defined(CHECK_DETERMINISM)
|
|
|
|
cerr << "Order: toOptimalMin "
|
|
|
|
<< DbU::getValueString(optimalMin) << " ["
|
|
|
|
<< DbU::getValueString(optimalMin) << ":"
|
|
|
|
<< DbU::getValueString(optimalMax) << "] ["
|
|
|
|
<< DbU::getValueString(constraintMin) << ":"
|
|
|
|
<< DbU::getValueString(constraintMax) << "] "
|
|
|
|
<< this << endl;
|
|
|
|
#endif
|
|
|
|
setAxis ( optimalMin, Realignate|AxisSet, processeds );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( getAxis() > optimalMax ) {
|
|
|
|
#if defined(CHECK_DETERMINISM)
|
|
|
|
cerr << "Order: toOptimalMax "
|
|
|
|
<< DbU::getValueString(optimalMin) << " ["
|
|
|
|
<< DbU::getValueString(optimalMin) << ":"
|
|
|
|
<< DbU::getValueString(optimalMax) << "] ["
|
|
|
|
<< DbU::getValueString(constraintMin) << ":"
|
|
|
|
<< DbU::getValueString(constraintMax) << "] "
|
|
|
|
<< this << endl;
|
|
|
|
#endif
|
|
|
|
setAxis ( optimalMax, Realignate|AxisSet, processeds );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CHECK_DETERMINISM)
|
|
|
|
cerr << "Order: in optimal position "
|
|
|
|
<< DbU::getValueString(optimalMin) << " ["
|
|
|
|
<< DbU::getValueString(optimalMin) << ":"
|
|
|
|
<< DbU::getValueString(optimalMax) << "] ["
|
|
|
|
<< DbU::getValueString(constraintMin) << ":"
|
|
|
|
<< DbU::getValueString(constraintMax) << "] "
|
|
|
|
<< this << endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::setAxis ( DbU::Unit axis, unsigned int flags, set<AutoSegment*>* processeds )
|
|
|
|
{
|
|
|
|
if ( processeds and (processeds->find(this) != processeds->end()) ) return;
|
|
|
|
|
|
|
|
if ( ( axis != getAxis() ) and isFixed() ) {
|
* ./katabatic:
- Change: In loadGlobalRouting(), more exlicit message as to why a net is
filtered out the routing set (POWER, GROUND, CLOCK or BLOCKAGE).
- New: ChipTool, module with utilities specific to chip routing. Containing
a function to pre-break wires around a block.
- New: In loadGlobalRouting/GCellConfiguration, adds supports for RoutingPad
connected on chip's pad.
- New: In GCellGrid/GCell, can compute the density in three modes: average,
max of H/V and max of layer. Currently implemented in getMaxHVDensity(),
should be unificated with getDensity(). Used for display purposes.
- Bug: In AutoContact, when splitting a contact, add a specific check for
"one layer span".
- Bug: In AutoSegment::canMoveUp(), do not move up fixed segments.
2010-11-16 07:59:38 -06:00
|
|
|
cerr << Error("AutoSegment::setAxis(): Cannot move fixed segment to %s.\n"
|
|
|
|
" (on: %s)"
|
|
|
|
,DbU::getValueString(axis).c_str()
|
|
|
|
,_getString().c_str()
|
|
|
|
) << endl;
|
2010-03-09 09:24:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( _isUnsetAxis and (flags & AxisSet) ) {
|
|
|
|
ltrace(200) << "setAxis() - AxisSet flag raised " << this << endl;
|
|
|
|
_isUnsetAxis = false;
|
|
|
|
}
|
|
|
|
if ( ( axis == getAxis() ) and not (flags & Realignate) ) return;
|
|
|
|
|
|
|
|
ltrace(200) << "setAxis() @"
|
|
|
|
<< ((_isHorizontal)?"Y ":"X ") << DbU::getLambda(getAxis())
|
|
|
|
<< " to " << DbU::getLambda(axis) << " on " << this << endl;
|
|
|
|
ltracein(80);
|
|
|
|
|
|
|
|
alignate ( axis );
|
|
|
|
if ( processeds ) processeds->insert ( this );
|
|
|
|
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
isegment->alignate ( getAxis() );
|
|
|
|
if ( flags & AxisSet ) isegment->_isUnsetAxis = false;
|
|
|
|
if ( processeds ) processeds->insert ( *isegment );
|
|
|
|
}
|
|
|
|
|
|
|
|
ltraceout(80);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::computeOptimal ( set<AutoSegment*>* processeds )
|
|
|
|
{
|
|
|
|
ltrace(89) << "computeOptimal() - " << this << endl;
|
|
|
|
ltracein(89);
|
|
|
|
|
|
|
|
if ( processeds && (processeds->find(this) != processeds->end()) ) { ltraceout(89); return; }
|
|
|
|
|
|
|
|
if ( _isCollapsed ) {
|
|
|
|
_optimalMin = 0;
|
|
|
|
setOptimalMax ( (_isHorizontal) ? _gcell->getBoundingBox().getYMax()
|
|
|
|
: _gcell->getBoundingBox().getXMax() );
|
|
|
|
ltraceout(89);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DbU::Unit minGCell = getOrigin();
|
|
|
|
DbU::Unit maxGCell = getExtremity();
|
|
|
|
DbU::Unit terminalMin;
|
|
|
|
DbU::Unit terminalMax;
|
|
|
|
AttractorsMap attractors;
|
|
|
|
|
|
|
|
AutoContact* anchor = getAutoSource();
|
|
|
|
if ( anchor->isTerminal() ) {
|
|
|
|
Box constraintBox = anchor->getConstraintBox();
|
|
|
|
if ( isHorizontal() ) {
|
|
|
|
terminalMin = constraintBox.getYMin ();
|
|
|
|
terminalMax = constraintBox.getYMax ();
|
|
|
|
} else {
|
|
|
|
terminalMin = constraintBox.getXMin ();
|
|
|
|
terminalMax = constraintBox.getXMax ();
|
|
|
|
}
|
|
|
|
|
|
|
|
attractors.addAttractor ( terminalMin );
|
|
|
|
if ( terminalMin != terminalMax )
|
|
|
|
attractors.addAttractor ( terminalMax );
|
|
|
|
}
|
|
|
|
|
|
|
|
anchor = getAutoTarget();
|
|
|
|
if ( anchor->isTerminal() ) {
|
|
|
|
Box constraintBox = anchor->getConstraintBox();
|
|
|
|
if ( isHorizontal() ) {
|
|
|
|
terminalMin = constraintBox.getYMin ();
|
|
|
|
terminalMax = constraintBox.getYMax ();
|
|
|
|
} else {
|
|
|
|
terminalMin = constraintBox.getXMin ();
|
|
|
|
terminalMax = constraintBox.getXMax ();
|
|
|
|
}
|
|
|
|
|
|
|
|
attractors.addAttractor ( terminalMin );
|
|
|
|
if ( terminalMin != terminalMax )
|
|
|
|
attractors.addAttractor ( terminalMax );
|
|
|
|
}
|
|
|
|
|
|
|
|
forEach ( AutoSegment*, autoSegment, getCollapsedPerpandiculars() ) {
|
|
|
|
ltrace(89) << "Perpandicular " << *autoSegment << endl;
|
|
|
|
ltracein(89);
|
|
|
|
if ( autoSegment->isLocal() ) {
|
|
|
|
if ( !autoSegment->isTerminal() ) { ltraceout(89); continue; }
|
|
|
|
|
|
|
|
DbU::Unit terminalMin;
|
|
|
|
DbU::Unit terminalMax;
|
|
|
|
|
|
|
|
if ( getTerminalInterval ( *autoSegment
|
|
|
|
, NULL
|
|
|
|
, isHorizontal()
|
|
|
|
, terminalMin
|
|
|
|
, terminalMax ) ) {
|
|
|
|
attractors.addAttractor ( terminalMin );
|
|
|
|
if ( terminalMin != terminalMax )
|
|
|
|
attractors.addAttractor ( terminalMax );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bool isMin = true;
|
|
|
|
if ( isHorizontal()
|
|
|
|
&& ( autoSegment->getAutoSource()->getGCell()->getRow() == _gcell->getRow() ) )
|
|
|
|
isMin = false;
|
|
|
|
if ( isVertical()
|
|
|
|
&& ( autoSegment->getAutoSource()->getGCell()->getColumn() == _gcell->getColumn() ) )
|
|
|
|
isMin = false;
|
|
|
|
attractors.addAttractor ( (isMin) ? minGCell : maxGCell );
|
|
|
|
}
|
|
|
|
ltraceout(89);
|
|
|
|
}
|
|
|
|
|
|
|
|
DbU::Unit optimalMin;
|
|
|
|
DbU::Unit optimalMax;
|
|
|
|
DbU::Unit constraintMin;
|
|
|
|
DbU::Unit constraintMax;
|
|
|
|
getConstraints ( constraintMin, constraintMax );
|
|
|
|
|
|
|
|
if ( attractors.getAttractorsCount() ) {
|
|
|
|
ltrace(89) << "Lower Median " << DbU::getLambda(attractors.getLowerMedian()) << endl;
|
|
|
|
ltrace(89) << "Upper Median " << DbU::getLambda(attractors.getUpperMedian()) << endl;
|
|
|
|
|
|
|
|
optimalMin = attractors.getLowerMedian();
|
|
|
|
optimalMax = attractors.getUpperMedian();
|
|
|
|
} else {
|
|
|
|
optimalMin = 0;
|
|
|
|
optimalMax = (_isHorizontal) ? _gcell->getBoundingBox().getYMax()
|
|
|
|
: _gcell->getBoundingBox().getXMax();
|
|
|
|
}
|
|
|
|
|
|
|
|
setInBound ( constraintMin, constraintMax, optimalMin );
|
|
|
|
setInBound ( constraintMin, constraintMax, optimalMax );
|
|
|
|
|
|
|
|
if ( processeds ) processeds->insert ( this );
|
|
|
|
setOptimalMin ( optimalMin );
|
|
|
|
setOptimalMax ( optimalMax );
|
|
|
|
forEach ( AutoSegment*, autoSegment, getCollapseds() ) {
|
|
|
|
if ( processeds ) processeds->insert ( *autoSegment );
|
|
|
|
autoSegment->setOptimalMin ( optimalMin );
|
|
|
|
autoSegment->setOptimalMax ( optimalMax );
|
|
|
|
}
|
|
|
|
|
|
|
|
ltraceout(89);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegment* AutoSegment::canonize ()
|
|
|
|
{
|
|
|
|
ltrace(159) << "canonize() - " << this << endl;
|
|
|
|
|
|
|
|
if ( isCanonical() ) {
|
|
|
|
ltrace(159) << "* " << this << " canonical" << endl;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
AutoSegment* canonical = this;
|
|
|
|
bool hasCanonical = false;
|
|
|
|
bool isCanonicalLocal = true;
|
|
|
|
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
if ( isegment->isGlobal() ) isCanonicalLocal = false;
|
|
|
|
|
|
|
|
if ( isegment->isCanonical() ) {
|
|
|
|
ltrace(159) << "* " << *isegment << " canonical" << endl;
|
|
|
|
//return *isegment;
|
|
|
|
canonical = *isegment;
|
|
|
|
hasCanonical = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
if ( not hasCanonical ) {
|
|
|
|
if ( CompareId()(*isegment,canonical) )
|
2010-03-09 09:24:29 -06:00
|
|
|
canonical = *isegment;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
canonical->setCanonical ( true );
|
|
|
|
canonical->setCanonicalLocal ( isCanonicalLocal );
|
|
|
|
|
|
|
|
// ltrace: 159
|
|
|
|
if ( isCanonical() ) cerr << "* " << this << " canonical" << endl;
|
|
|
|
else cerr << "* " << this << endl;
|
|
|
|
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
if ( isegment->isCanonical() ) cerr << "| " << *isegment << " canonical" << endl;
|
|
|
|
else cerr << "| " << *isegment << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return canonical;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegment::AutoSegment ( Segment* segment
|
|
|
|
, bool isHorizontal
|
|
|
|
, int type
|
|
|
|
, bool terminal
|
|
|
|
, bool collapsed
|
|
|
|
)
|
|
|
|
: _isUnsetAxis (true)
|
|
|
|
, _invalidated (false)
|
|
|
|
, _isHorizontal (isHorizontal)
|
2011-01-25 11:16:27 -06:00
|
|
|
, _isTopologicEnd (false)
|
2010-03-09 09:24:29 -06:00
|
|
|
, _isTerminal (terminal)
|
2011-01-25 11:16:27 -06:00
|
|
|
, _isDogleg (false)
|
2010-03-09 09:24:29 -06:00
|
|
|
, _isCollapsed (collapsed)
|
|
|
|
, _isCanonical (false)
|
|
|
|
, _isFixed (false)
|
|
|
|
, _strap (false)
|
|
|
|
, _layerChange (false)
|
|
|
|
, _slackened (false)
|
|
|
|
, _slackenStrap (false)
|
|
|
|
, _allowOutsideGCell(false)
|
|
|
|
, _id (_maxId++)
|
|
|
|
, _optimalMin (0)
|
|
|
|
, _userConstraints (false)
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
, _parent (NULL)
|
2010-03-09 09:24:29 -06:00
|
|
|
{
|
|
|
|
//cerr << "AutoSegment::AutoSegment() - <id:" << _id << ">" << endl;
|
|
|
|
#if defined(CHECK_DETERMINISM)
|
|
|
|
cerr << "Order: AutoSegment::AutoSegment() - <id:" << _id << ">" << endl;
|
|
|
|
#endif
|
|
|
|
AutoContact* source = Session::lookup(dynamic_cast<Contact*>(segment->getSource()));
|
|
|
|
AutoContact* target = Session::lookup(dynamic_cast<Contact*>(segment->getTarget()));
|
|
|
|
|
2010-04-23 08:13:54 -05:00
|
|
|
_allocateds++;
|
|
|
|
|
2010-03-09 09:24:29 -06:00
|
|
|
_gcell = source->getGCell();
|
|
|
|
setOptimalMax ( (_isHorizontal) ? _gcell->getBoundingBox().getYMax()
|
|
|
|
: _gcell->getBoundingBox().getXMax() );
|
|
|
|
|
|
|
|
switch ( type ) {
|
|
|
|
case AutoSegment::Global: _isGlobal = true; break;
|
|
|
|
case AutoSegment::Local : _isGlobal = false; break;
|
|
|
|
case AutoSegment::Guess :
|
|
|
|
_isGlobal = ( source->getGCell() != target->getGCell() );
|
|
|
|
break;
|
|
|
|
}
|
2010-04-23 08:13:54 -05:00
|
|
|
_globalsCount += (_isGlobal) ? 1 : 0;
|
|
|
|
_isCanonicalLocal = not _isGlobal;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
|
|
|
_computeTerminal ( segment );
|
|
|
|
//if ( source->isTerminal() or target->isTerminal() ) _isTerminal = true;
|
|
|
|
|
|
|
|
//if ( source->isTerminal()
|
|
|
|
// and target->isTerminal()
|
|
|
|
// /*and (segment->getLength() < DbU::lambda(25.0))*/
|
|
|
|
// and (source->getGCell() == target->getGCell()) ) {
|
|
|
|
// _strap = true;
|
|
|
|
//}
|
|
|
|
|
|
|
|
source->setInvalidatedTopology ( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::_preCreate ( Component* source, Component* target )
|
|
|
|
{
|
|
|
|
AutoContact* acSource = Session::lookup(dynamic_cast<Contact*>(source));
|
|
|
|
AutoContact* acTarget = Session::lookup(dynamic_cast<Contact*>(target));
|
|
|
|
|
|
|
|
_preCreate ( acSource, acTarget );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::_preCreate ( AutoContact* source, AutoContact* target )
|
|
|
|
{
|
|
|
|
if ( !source || !target )
|
|
|
|
throw Error ( badAutoSegmentAnchor
|
|
|
|
, ((source)?getString(source).c_str():"NULL")
|
|
|
|
, ((target)?getString(target).c_str():"NULL")
|
|
|
|
);
|
|
|
|
|
|
|
|
if ( source == target )
|
|
|
|
throw Error ( dupAutoSegmentAnchor, getString(source).c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::_postCreate ()
|
|
|
|
{
|
|
|
|
Session::invalidate ( getNet() );
|
|
|
|
Session::link ( this );
|
|
|
|
invalidate ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::_preDestroy ()
|
|
|
|
{
|
|
|
|
ltrace(200) << "AutoSegment::_preDestroy() - " << (void*)this << endl;
|
|
|
|
ltracein(90);
|
|
|
|
|
|
|
|
Session::unlink ( this );
|
|
|
|
ltraceout(90);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegment::~AutoSegment ()
|
|
|
|
{
|
|
|
|
_allocateds--;
|
2010-04-23 08:13:54 -05:00
|
|
|
if ( _isGlobal and (_globalsCount > 0) ) _globalsCount--;
|
2010-03-09 09:24:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::_computeTerminal ( Segment* segment )
|
|
|
|
{
|
|
|
|
AutoContact* source = Session::lookup(dynamic_cast<Contact*>(segment->getSource()));
|
|
|
|
AutoContact* target = Session::lookup(dynamic_cast<Contact*>(segment->getTarget()));
|
|
|
|
|
* ./katabatic:
- New: ChipTools, regroup all datas and utilities to manage a full-chip
design.
- Change: In LoadGrByNet/GCellConfiguration::_GCell_xG_1Pad(), uses straight
perpandicular wires on top & right pads. The GCells under those connectors
are fully saturated, wires must go out as straight as possible.
- Change: In AutoHorizontal/AutoVertical, update the "terminal" flag after
slackening. This is to avoid global that are no longer connected to
terminals behave as such.
- Change: In AutoSegment::canMoveUp() & canPivotUp(), prevent all local segments
to go up. This is to avoid cluttering upper levels with small segments.
- Change: In GCellConfiguration, for xG_xL3, detect straight vertical topologies
and for them to be fixed (new flag FIXED_GLOBAL set by the topological
builder instead of the constructor). This prevent the router to do
stupid things...
To sets the "Fixed" flag *after* the axis of global segments have been
positionned correctly adds a "_toFixGlobals" static table lookup.
- Change: In GCell::stepDesaturate(), if less than one free track remains in
the upper layer, do not move up the segment. This allows from a minimum
free room for expansion.
- Change: In GCell::_getString(), display indexes and layer names in various
saturation tables.
- Change: In AutoSegment, allow move up of local Segment. ::moveUp() and
::canMoveUp() arguments go from booleans to flags, which are more
explicits.
2010-12-04 09:25:18 -06:00
|
|
|
_isTerminal = source->isTerminal() or target->isTerminal();
|
2010-03-09 09:24:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
size_t AutoSegment::getAlignedContacts ( map<AutoContact*,int>& innerContacts )
|
|
|
|
{
|
|
|
|
map<AutoContact*,int>::iterator icontact;
|
|
|
|
|
|
|
|
innerContacts.clear ();
|
|
|
|
innerContacts.insert ( make_pair(getAutoSource(),0x1) );
|
|
|
|
innerContacts.insert ( make_pair(getAutoTarget(),0x4) );
|
|
|
|
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
if ( (icontact = innerContacts.find(isegment->getAutoSource())) != innerContacts.end() ) {
|
|
|
|
if ( icontact->second & 0x1 ) icontact->second |= 0x2;
|
|
|
|
else icontact->second |= 0x1;
|
|
|
|
} else
|
|
|
|
innerContacts.insert ( make_pair(getAutoSource(),0x1) );
|
|
|
|
|
|
|
|
if ( (icontact = innerContacts.find(isegment->getAutoTarget())) != innerContacts.end() ) {
|
|
|
|
if ( icontact->second & 0x4 ) icontact->second |= 0x8;
|
|
|
|
else icontact->second |= 0x4;
|
|
|
|
} else
|
|
|
|
innerContacts.insert ( make_pair(getAutoTarget(),0x4) );
|
|
|
|
}
|
|
|
|
|
|
|
|
return innerContacts.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
size_t AutoSegment::getPerpandicularsBound ( set<AutoSegment*>& bounds )
|
|
|
|
{
|
|
|
|
map<AutoContact*,int> contacts;
|
|
|
|
map<AutoContact*,int>::iterator icontact;
|
|
|
|
|
|
|
|
getAlignedContacts ( contacts );
|
|
|
|
|
|
|
|
for ( icontact=contacts.begin() ; icontact != contacts.end() ; icontact++ ) {
|
|
|
|
if ( (icontact->second == 0x1) or (icontact->second == 0x4) ) {
|
|
|
|
forEach ( Segment*, isegment, icontact->first->getSlaveComponents().getSubSet<Segment*>() ) {
|
|
|
|
AutoSegment* autoSegment = Session::lookup ( *isegment );
|
|
|
|
if ( !autoSegment ) continue;
|
|
|
|
if ( autoSegment->getDirection() == getDirection() ) continue;
|
|
|
|
|
|
|
|
bounds.insert ( autoSegment );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return bounds.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Interval AutoSegment::getMinSpanU ()
|
|
|
|
{
|
|
|
|
map<AutoContact*,int> contacts;
|
|
|
|
map<AutoContact*,int>::iterator icontact;
|
|
|
|
|
|
|
|
getAlignedContacts ( contacts );
|
|
|
|
|
|
|
|
DbU::Unit spanMin = DbU::Min;
|
|
|
|
DbU::Unit spanMax = DbU::Max;
|
|
|
|
Interval constraints;
|
|
|
|
unsigned int direction = Constant::perpandicular(getDirection());
|
|
|
|
|
|
|
|
for ( icontact=contacts.begin() ; icontact != contacts.end() ; icontact++ ) {
|
|
|
|
constraints = icontact->first->getUConstraints ( direction );
|
|
|
|
if ( icontact->second == 0x1 ) {
|
|
|
|
spanMin = max ( spanMin, constraints.getVMax() );
|
|
|
|
}
|
|
|
|
if ( icontact->second == 0x4 ) {
|
|
|
|
spanMax = min ( spanMax, constraints.getVMin() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Interval(spanMin,spanMax);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::setAllowOutsideGCell ( bool state, bool propagate )
|
|
|
|
{
|
|
|
|
if ( allowOutsideGCell() ) return;
|
|
|
|
|
|
|
|
_setAllowOutsideGCell ( state );
|
|
|
|
|
|
|
|
if ( propagate ) {
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
isegment->_setAllowOutsideGCell ( state );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::_setAllowOutsideGCell ( bool state )
|
|
|
|
{
|
|
|
|
ltrace(200) << "_setAllowOutsideGCell() - " << this << endl;
|
|
|
|
_allowOutsideGCell = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::canGoOutsideGCell () const
|
|
|
|
{
|
|
|
|
ltracein(200);
|
|
|
|
|
|
|
|
bool goOutsideGCell = getAutoSource()->canGoOutsideGCell(this);
|
|
|
|
goOutsideGCell = goOutsideGCell and getAutoTarget()->canGoOutsideGCell(this);
|
|
|
|
|
|
|
|
if ( !goOutsideGCell ) {
|
|
|
|
ltraceout(200);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
GCell* sourceGCell = getAutoSource()->getGCell();
|
|
|
|
GCell* leftGCell = NULL;
|
|
|
|
GCell* rightGCell = NULL;
|
|
|
|
Interval uside;
|
|
|
|
bool goLeft = false;
|
|
|
|
bool goRight = false;
|
|
|
|
|
|
|
|
if ( isHorizontal() ) {
|
|
|
|
uside = sourceGCell->getUSide ( Constant::Vertical );
|
|
|
|
leftGCell = sourceGCell->getDown();
|
|
|
|
rightGCell = sourceGCell->getUp ();
|
|
|
|
} else {
|
|
|
|
uside = sourceGCell->getUSide ( Constant::Horizontal );
|
|
|
|
leftGCell = sourceGCell->getLeft ();
|
|
|
|
rightGCell = sourceGCell->getRight();
|
|
|
|
}
|
|
|
|
|
|
|
|
DbU::Unit constraintMin;
|
|
|
|
DbU::Unit constraintMax;
|
|
|
|
getConstraints ( constraintMin, constraintMax );
|
|
|
|
|
|
|
|
if ( leftGCell && (uside.getVMin() >= constraintMin) ) {
|
|
|
|
ltrace(200) << "Can go Left." << endl;
|
|
|
|
goLeft = true;
|
|
|
|
}
|
|
|
|
// Ugly: Must use the right compensator for VMax.
|
|
|
|
if ( rightGCell && (uside.getVMax() <= constraintMax)+DbU::lambda(1.0) ) {
|
|
|
|
ltrace(200) << "Can go Right." << endl;
|
|
|
|
goRight = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
goOutsideGCell = goOutsideGCell and (goRight or goLeft);
|
|
|
|
|
|
|
|
// Override.
|
|
|
|
//goOutsideGCell = !isGlobal() && !isTerminal();
|
|
|
|
|
|
|
|
ltrace(200) << "AutoSegment::canGoOutsideGCell() - " << goOutsideGCell << endl;
|
|
|
|
ltraceout(200);
|
|
|
|
|
|
|
|
return goOutsideGCell;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::canDesalignate ()
|
|
|
|
{
|
|
|
|
ltrace(200) << "AutoSegment::canDesalignate()" << endl;
|
|
|
|
|
|
|
|
map<AutoContact*,int> innerContacts;
|
|
|
|
map<AutoContact*,int>::iterator icontact;
|
|
|
|
|
|
|
|
getAlignedContacts ( innerContacts );
|
|
|
|
|
|
|
|
for ( icontact=innerContacts.begin() ; icontact != innerContacts.end() ; icontact++ ) {
|
|
|
|
ltrace(200) << "| " << "flags:" << icontact->second
|
|
|
|
<< " " << (void*)icontact->first->base() << ":" << icontact->first << endl;
|
|
|
|
if ( (icontact->second & 0x5 ) && canDesalignate(icontact->first) ) return true;
|
|
|
|
//if ( (icontact->second & 0x3 ) && canDesalignate(icontact->first) ) return true;
|
|
|
|
//if ( (icontact->second & 0x12) && canDesalignate(icontact->first) ) return true;
|
|
|
|
}
|
|
|
|
ltrace(200) << "No AutoContact suitable for desalignment." << endl;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::desalignate ()
|
|
|
|
{
|
|
|
|
map<AutoContact*,int> innerContacts;
|
|
|
|
map<AutoContact*,int>::iterator icontact;
|
|
|
|
vector<AutoSegment*> segments;
|
|
|
|
|
|
|
|
// Ugly. Must fusion with the inner contact loop.
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
segments.push_back ( *isegment );
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidate ();
|
|
|
|
getAlignedContacts ( innerContacts );
|
|
|
|
|
|
|
|
for ( icontact=innerContacts.begin() ; icontact != innerContacts.end() ; icontact++ ) {
|
|
|
|
desalignate ( icontact->first );
|
|
|
|
//if ( icontact->second & 0x3 ) desalignate ( icontact->first );
|
|
|
|
//if ( icontact->second & 0x3 ) desalignate ( icontact->first );
|
|
|
|
//if ( icontact->second & 0x12) desalignate ( icontact->first );
|
|
|
|
}
|
|
|
|
|
* ./katabatic:
- New: ChipTools, regroup all datas and utilities to manage a full-chip
design.
- Change: In LoadGrByNet/GCellConfiguration::_GCell_xG_1Pad(), uses straight
perpandicular wires on top & right pads. The GCells under those connectors
are fully saturated, wires must go out as straight as possible.
- Change: In AutoHorizontal/AutoVertical, update the "terminal" flag after
slackening. This is to avoid global that are no longer connected to
terminals behave as such.
- Change: In AutoSegment::canMoveUp() & canPivotUp(), prevent all local segments
to go up. This is to avoid cluttering upper levels with small segments.
- Change: In GCellConfiguration, for xG_xL3, detect straight vertical topologies
and for them to be fixed (new flag FIXED_GLOBAL set by the topological
builder instead of the constructor). This prevent the router to do
stupid things...
To sets the "Fixed" flag *after* the axis of global segments have been
positionned correctly adds a "_toFixGlobals" static table lookup.
- Change: In GCell::stepDesaturate(), if less than one free track remains in
the upper layer, do not move up the segment. This allows from a minimum
free room for expansion.
- Change: In GCell::_getString(), display indexes and layer names in various
saturation tables.
- Change: In AutoSegment, allow move up of local Segment. ::moveUp() and
::canMoveUp() arguments go from booleans to flags, which are more
explicits.
2010-12-04 09:25:18 -06:00
|
|
|
// for ( size_t i=0 ; i<segments.size() ; ++i ) {
|
|
|
|
// segments[i]->_computeTerminal ( segments[i]->base() );
|
|
|
|
// ltrace(99) << "_computeTerminals() - " << segments[i] << endl;
|
|
|
|
// }
|
|
|
|
|
2010-03-09 09:24:29 -06:00
|
|
|
Session::invalidate ( getNet() );
|
|
|
|
Session::revalidateTopology ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::changeDepth ( unsigned int depth, bool propagate, bool standAlone )
|
|
|
|
{
|
|
|
|
invalidate ();
|
|
|
|
Session::invalidate ( getNet() );
|
|
|
|
Session::setInvalidateMask ( Session::NetSplitContacts );
|
|
|
|
|
|
|
|
_changeDepth ( depth, true );
|
|
|
|
|
|
|
|
if ( propagate ) {
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
isegment->_changeDepth ( depth, true );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( standAlone ) Session::revalidateTopology();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::_changeDepth ( unsigned int depth, bool withNeighbors )
|
|
|
|
{
|
|
|
|
ltrace(200) << "_changeDepth() - " << this << endl;
|
|
|
|
ltracein(200);
|
|
|
|
|
|
|
|
const Layer* layer0 = Session::getRoutingGauge()->getRoutingLayer(depth);
|
|
|
|
if ( getLayer() != layer0 ) {
|
|
|
|
setLayer ( layer0 );
|
|
|
|
|
|
|
|
getAutoSource()->invalidate();
|
|
|
|
getAutoTarget()->invalidate();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !withNeighbors ) {
|
|
|
|
ltraceout(200);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
forEach ( Component*, icomponent, getAutoSource()->getSlaveComponents() ) {
|
|
|
|
if ( *icomponent == base() ) continue;
|
|
|
|
|
|
|
|
Segment* segment = dynamic_cast<Segment*>(*icomponent);
|
|
|
|
if ( !segment ) continue;
|
|
|
|
|
|
|
|
AutoSegment* autoSegment = Session::lookup ( segment );
|
|
|
|
if ( !autoSegment ) continue;
|
|
|
|
if ( autoSegment->isGlobal () ) continue;
|
|
|
|
if ( autoSegment->isTerminal() ) continue;
|
|
|
|
|
|
|
|
if ( !( autoSegment->isHorizontal() xor isHorizontal() ) ) {
|
|
|
|
autoSegment->_changeDepth ( depth, false );
|
|
|
|
} else {
|
|
|
|
autoSegment->_changeDepth ( depth-1, false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
forEach ( Component*, icomponent, getAutoTarget()->getSlaveComponents() ) {
|
|
|
|
if ( *icomponent == base() ) continue;
|
|
|
|
|
|
|
|
Segment* segment = dynamic_cast<Segment*>(*icomponent);
|
|
|
|
if ( !segment ) continue;
|
|
|
|
|
|
|
|
AutoSegment* autoSegment = Session::lookup ( segment );
|
|
|
|
if ( !autoSegment ) continue;
|
|
|
|
if ( autoSegment->isGlobal () ) continue;
|
|
|
|
if ( autoSegment->isTerminal() ) continue;
|
|
|
|
|
|
|
|
if ( !( autoSegment->isHorizontal() xor isHorizontal() ) ) {
|
|
|
|
autoSegment->_changeDepth ( depth, false );
|
|
|
|
} else {
|
|
|
|
autoSegment->_changeDepth ( depth-1, false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<GCell*> gcells;
|
|
|
|
getGCells ( gcells );
|
|
|
|
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
|
|
|
|
gcells[i]->invalidate ();
|
|
|
|
}
|
|
|
|
|
|
|
|
ltraceout(200);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::canSlacken ( bool propagate )
|
|
|
|
{
|
|
|
|
ltrace(200) << "AutoSegment::canSlacken()" << endl;
|
|
|
|
|
|
|
|
if ( !isGlobal() && !propagate ) return false;
|
|
|
|
|
|
|
|
if ( _canSlacken() ) return true;
|
|
|
|
if ( propagate ) {
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
if ( isegment->_canSlacken() ) return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::slacken ( bool propagate )
|
|
|
|
{
|
|
|
|
invalidate ();
|
|
|
|
|
|
|
|
set<AutoSegment*,AutoSegment::CompareId> collapseds;
|
|
|
|
collapseds.insert ( this );
|
|
|
|
|
|
|
|
if ( propagate ) {
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() )
|
|
|
|
collapseds.insert ( *isegment );
|
|
|
|
}
|
|
|
|
|
|
|
|
set<AutoSegment*>::iterator isegment = collapseds.begin();
|
|
|
|
for ( ; isegment != collapseds.end() ; isegment++ )
|
|
|
|
(*isegment)->_slacken ();
|
|
|
|
|
|
|
|
Session::invalidate ( getNet() );
|
|
|
|
Session::revalidateTopology ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-25 11:16:27 -06:00
|
|
|
float AutoSegment::getMaxUnderDensity ( unsigned int flags )
|
|
|
|
{
|
|
|
|
ltrace(200) << "AutoSegment::getMaxUnderDensity() " << endl;
|
|
|
|
|
|
|
|
GCell* begin = NULL;
|
|
|
|
GCell* end = NULL;
|
|
|
|
|
|
|
|
size_t depth = Session::getRoutingGauge()->getLayerDepth(getLayer());
|
|
|
|
|
|
|
|
vector<GCell*> gcells;
|
|
|
|
getGCells ( gcells );
|
|
|
|
begin = *gcells.begin ();
|
|
|
|
end = *gcells.rbegin();
|
|
|
|
|
|
|
|
float maxDensity = 0.0;
|
|
|
|
|
|
|
|
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
|
|
|
|
maxDensity = std::max ( maxDensity, gcells[i]->getFeedthroughs(depth) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( flags & Propagate ) {
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
isegment->getGCells ( gcells );
|
|
|
|
if ( (*gcells.begin ())->getIndex() < begin->getIndex() ) begin = *gcells.begin ();
|
|
|
|
if ( (*gcells.rbegin())->getIndex() > end ->getIndex() ) end = *gcells.rbegin();
|
|
|
|
|
|
|
|
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
|
|
|
|
maxDensity = std::max ( maxDensity, gcells[i]->getFeedthroughs(depth) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return maxDensity;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
bool AutoSegment::canPivotUp ( float reserve, unsigned int flags )
|
2010-03-09 09:24:29 -06:00
|
|
|
{
|
2011-01-09 12:08:31 -06:00
|
|
|
ltrace(200) << "AutoSegment::canPivotUp() - " << flags
|
|
|
|
<< " (reserve:" << reserve << ")" << endl;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
* ./katabatic:
- New: ChipTools, regroup all datas and utilities to manage a full-chip
design.
- Change: In LoadGrByNet/GCellConfiguration::_GCell_xG_1Pad(), uses straight
perpandicular wires on top & right pads. The GCells under those connectors
are fully saturated, wires must go out as straight as possible.
- Change: In AutoHorizontal/AutoVertical, update the "terminal" flag after
slackening. This is to avoid global that are no longer connected to
terminals behave as such.
- Change: In AutoSegment::canMoveUp() & canPivotUp(), prevent all local segments
to go up. This is to avoid cluttering upper levels with small segments.
- Change: In GCellConfiguration, for xG_xL3, detect straight vertical topologies
and for them to be fixed (new flag FIXED_GLOBAL set by the topological
builder instead of the constructor). This prevent the router to do
stupid things...
To sets the "Fixed" flag *after* the axis of global segments have been
positionned correctly adds a "_toFixGlobals" static table lookup.
- Change: In GCell::stepDesaturate(), if less than one free track remains in
the upper layer, do not move up the segment. This allows from a minimum
free room for expansion.
- Change: In GCell::_getString(), display indexes and layer names in various
saturation tables.
- Change: In AutoSegment, allow move up of local Segment. ::moveUp() and
::canMoveUp() arguments go from booleans to flags, which are more
explicits.
2010-12-04 09:25:18 -06:00
|
|
|
if ( isLayerChange() or isFixed() ) return false;
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
if ( isTerminal () or isLocal() ) return false;
|
* ./katabatic:
- New: ChipTools, regroup all datas and utilities to manage a full-chip
design.
- Change: In LoadGrByNet/GCellConfiguration::_GCell_xG_1Pad(), uses straight
perpandicular wires on top & right pads. The GCells under those connectors
are fully saturated, wires must go out as straight as possible.
- Change: In AutoHorizontal/AutoVertical, update the "terminal" flag after
slackening. This is to avoid global that are no longer connected to
terminals behave as such.
- Change: In AutoSegment::canMoveUp() & canPivotUp(), prevent all local segments
to go up. This is to avoid cluttering upper levels with small segments.
- Change: In GCellConfiguration, for xG_xL3, detect straight vertical topologies
and for them to be fixed (new flag FIXED_GLOBAL set by the topological
builder instead of the constructor). This prevent the router to do
stupid things...
To sets the "Fixed" flag *after* the axis of global segments have been
positionned correctly adds a "_toFixGlobals" static table lookup.
- Change: In GCell::stepDesaturate(), if less than one free track remains in
the upper layer, do not move up the segment. This allows from a minimum
free room for expansion.
- Change: In GCell::_getString(), display indexes and layer names in various
saturation tables.
- Change: In AutoSegment, allow move up of local Segment. ::moveUp() and
::canMoveUp() arguments go from booleans to flags, which are more
explicits.
2010-12-04 09:25:18 -06:00
|
|
|
|
2010-03-09 09:24:29 -06:00
|
|
|
//if ( isTerminal() ) return false;
|
|
|
|
|
|
|
|
size_t depth = Session::getRoutingGauge()->getLayerDepth(getLayer());
|
|
|
|
if ( depth+2 >= Session::getRoutingGauge()->getDepth() ) return false;
|
|
|
|
|
|
|
|
vector<GCell*> gcells;
|
|
|
|
getGCells ( gcells );
|
|
|
|
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
if ( not gcells[i]->hasFreeTrack(depth+2,reserve) ) return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( not (flags&IgnoreContact) ) {
|
|
|
|
ltrace(200) << getAutoSource() << endl;
|
|
|
|
ltrace(200) << getAutoTarget() << endl;
|
|
|
|
ltrace(200) << "min depths, Segment:" << depth
|
|
|
|
<< " S:" << getAutoSource()->getMinDepth()
|
|
|
|
<< " T:" << getAutoTarget()->getMinDepth() << endl;
|
|
|
|
|
|
|
|
if ( getAutoSource()->getMinDepth() < depth ) return false;
|
|
|
|
if ( getAutoTarget()->getMinDepth() < depth ) return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( flags & Propagate ) {
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
isegment->getGCells ( gcells );
|
|
|
|
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
|
|
|
|
if ( not gcells[i]->hasFreeTrack(depth+2,reserve) ) return false;
|
|
|
|
}
|
|
|
|
if ( isegment->getAutoSource()->getMinDepth() < depth ) return false;
|
|
|
|
if ( isegment->getAutoTarget()->getMinDepth() < depth ) return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ltrace(200) << "AutoSegment::canPivotUp() - true [no propagate]" << endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ltrace(200) << "AutoSegment::canPivotUp() - true [propagate]" << endl;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::canPivotDown ( bool propagate, float reserve )
|
|
|
|
{
|
2011-01-09 12:08:31 -06:00
|
|
|
ltrace(200) << "AutoSegment::canPivotDown()"
|
|
|
|
<< " (reserve:" << reserve << ")" << endl;
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
|
|
|
|
if ( isLayerChange() or isFixed() ) return false;
|
|
|
|
if ( isTerminal () or isLocal() ) return false;
|
|
|
|
//if ( isTerminal () ) return false;
|
|
|
|
|
|
|
|
size_t depth = Session::getRoutingGauge()->getLayerDepth(getLayer());
|
|
|
|
if ( depth < 3 ) return false;
|
|
|
|
|
|
|
|
vector<GCell*> gcells;
|
|
|
|
getGCells ( gcells );
|
|
|
|
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
|
|
|
|
if ( not gcells[i]->hasFreeTrack(depth-2,reserve) ) return false;
|
2010-03-09 09:24:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
ltrace(200) << getAutoSource() << endl;
|
|
|
|
ltrace(200) << getAutoTarget() << endl;
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
ltrace(200) << "max depths, Segment:" << depth
|
|
|
|
<< " S:" << getAutoSource()->getMaxDepth()
|
|
|
|
<< " T:" << getAutoTarget()->getMaxDepth() << endl;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
if ( getAutoSource()->getMaxDepth() > depth ) return false;
|
|
|
|
if ( getAutoTarget()->getMaxDepth() > depth ) return false;
|
2010-03-09 09:24:29 -06:00
|
|
|
if ( not propagate ) {
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
ltrace(200) << "AutoSegment::canPivotDown() - true [no propagate]" << endl;
|
2010-03-09 09:24:29 -06:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( propagate ) {
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
isegment->getGCells ( gcells );
|
|
|
|
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
if ( not gcells[i]->hasFreeTrack(depth-2,reserve) ) return false;
|
2010-03-09 09:24:29 -06:00
|
|
|
}
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
if ( isegment->getAutoSource()->getMaxDepth() < depth ) return false;
|
|
|
|
if ( isegment->getAutoTarget()->getMaxDepth() < depth ) return false;
|
2010-03-09 09:24:29 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-09 12:08:31 -06:00
|
|
|
ltrace(200) << "AutoSegment::canPivotDown() - true [propagate]" << endl;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
* ./katabatic:
- New: ChipTools, regroup all datas and utilities to manage a full-chip
design.
- Change: In LoadGrByNet/GCellConfiguration::_GCell_xG_1Pad(), uses straight
perpandicular wires on top & right pads. The GCells under those connectors
are fully saturated, wires must go out as straight as possible.
- Change: In AutoHorizontal/AutoVertical, update the "terminal" flag after
slackening. This is to avoid global that are no longer connected to
terminals behave as such.
- Change: In AutoSegment::canMoveUp() & canPivotUp(), prevent all local segments
to go up. This is to avoid cluttering upper levels with small segments.
- Change: In GCellConfiguration, for xG_xL3, detect straight vertical topologies
and for them to be fixed (new flag FIXED_GLOBAL set by the topological
builder instead of the constructor). This prevent the router to do
stupid things...
To sets the "Fixed" flag *after* the axis of global segments have been
positionned correctly adds a "_toFixGlobals" static table lookup.
- Change: In GCell::stepDesaturate(), if less than one free track remains in
the upper layer, do not move up the segment. This allows from a minimum
free room for expansion.
- Change: In GCell::_getString(), display indexes and layer names in various
saturation tables.
- Change: In AutoSegment, allow move up of local Segment. ::moveUp() and
::canMoveUp() arguments go from booleans to flags, which are more
explicits.
2010-12-04 09:25:18 -06:00
|
|
|
bool AutoSegment::canMoveUp ( float reserve, unsigned int flags )
|
2010-03-09 09:24:29 -06:00
|
|
|
{
|
2011-01-09 12:08:31 -06:00
|
|
|
ltrace(200) << "AutoSegment::canMoveUp() " << flags
|
|
|
|
<< " (reserve:" << reserve << ")" << endl;
|
|
|
|
|
|
|
|
GCell* begin = NULL;
|
|
|
|
GCell* end = NULL;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
2010-12-12 15:43:25 -06:00
|
|
|
if ( isLayerChange() or isFixed() ) return false;
|
|
|
|
if ( isTerminal() and (not (flags & AllowTerminal)) ) return false;
|
|
|
|
if ( isLocal() and (not (flags & AllowLocal )) ) return false;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
|
|
|
size_t depth = Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2;
|
2010-05-27 11:12:28 -05:00
|
|
|
if ( depth >= Session::getConfiguration()->getAllowedDepth() ) return false;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
|
|
|
vector<GCell*> gcells;
|
|
|
|
getGCells ( gcells );
|
2011-01-09 12:08:31 -06:00
|
|
|
begin = *gcells.begin ();
|
|
|
|
end = *gcells.rbegin();
|
|
|
|
|
2010-03-09 09:24:29 -06:00
|
|
|
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
|
* ./katabatic:
- New: ChipTools, regroup all datas and utilities to manage a full-chip
design.
- Change: In LoadGrByNet/GCellConfiguration::_GCell_xG_1Pad(), uses straight
perpandicular wires on top & right pads. The GCells under those connectors
are fully saturated, wires must go out as straight as possible.
- Change: In AutoHorizontal/AutoVertical, update the "terminal" flag after
slackening. This is to avoid global that are no longer connected to
terminals behave as such.
- Change: In AutoSegment::canMoveUp() & canPivotUp(), prevent all local segments
to go up. This is to avoid cluttering upper levels with small segments.
- Change: In GCellConfiguration, for xG_xL3, detect straight vertical topologies
and for them to be fixed (new flag FIXED_GLOBAL set by the topological
builder instead of the constructor). This prevent the router to do
stupid things...
To sets the "Fixed" flag *after* the axis of global segments have been
positionned correctly adds a "_toFixGlobals" static table lookup.
- Change: In GCell::stepDesaturate(), if less than one free track remains in
the upper layer, do not move up the segment. This allows from a minimum
free room for expansion.
- Change: In GCell::_getString(), display indexes and layer names in various
saturation tables.
- Change: In AutoSegment, allow move up of local Segment. ::moveUp() and
::canMoveUp() arguments go from booleans to flags, which are more
explicits.
2010-12-04 09:25:18 -06:00
|
|
|
if ( not gcells[i]->hasFreeTrack(depth,reserve) ) {
|
|
|
|
ltrace(200) << "Not enough free track in " << gcells[i] << endl;
|
|
|
|
return false;
|
|
|
|
}
|
2010-03-09 09:24:29 -06:00
|
|
|
}
|
|
|
|
|
* ./katabatic:
- New: ChipTools, regroup all datas and utilities to manage a full-chip
design.
- Change: In LoadGrByNet/GCellConfiguration::_GCell_xG_1Pad(), uses straight
perpandicular wires on top & right pads. The GCells under those connectors
are fully saturated, wires must go out as straight as possible.
- Change: In AutoHorizontal/AutoVertical, update the "terminal" flag after
slackening. This is to avoid global that are no longer connected to
terminals behave as such.
- Change: In AutoSegment::canMoveUp() & canPivotUp(), prevent all local segments
to go up. This is to avoid cluttering upper levels with small segments.
- Change: In GCellConfiguration, for xG_xL3, detect straight vertical topologies
and for them to be fixed (new flag FIXED_GLOBAL set by the topological
builder instead of the constructor). This prevent the router to do
stupid things...
To sets the "Fixed" flag *after* the axis of global segments have been
positionned correctly adds a "_toFixGlobals" static table lookup.
- Change: In GCell::stepDesaturate(), if less than one free track remains in
the upper layer, do not move up the segment. This allows from a minimum
free room for expansion.
- Change: In GCell::_getString(), display indexes and layer names in various
saturation tables.
- Change: In AutoSegment, allow move up of local Segment. ::moveUp() and
::canMoveUp() arguments go from booleans to flags, which are more
explicits.
2010-12-04 09:25:18 -06:00
|
|
|
ltrace(200) << "Enough free track under canonical segment." << endl;
|
|
|
|
|
|
|
|
if ( isLocal() and not (flags & Propagate) ) {
|
2010-03-09 09:24:29 -06:00
|
|
|
if ( not getAutoSource()->canMoveUp(this) ) return false;
|
|
|
|
if ( not getAutoTarget()->canMoveUp(this) ) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
* ./katabatic:
- New: ChipTools, regroup all datas and utilities to manage a full-chip
design.
- Change: In LoadGrByNet/GCellConfiguration::_GCell_xG_1Pad(), uses straight
perpandicular wires on top & right pads. The GCells under those connectors
are fully saturated, wires must go out as straight as possible.
- Change: In AutoHorizontal/AutoVertical, update the "terminal" flag after
slackening. This is to avoid global that are no longer connected to
terminals behave as such.
- Change: In AutoSegment::canMoveUp() & canPivotUp(), prevent all local segments
to go up. This is to avoid cluttering upper levels with small segments.
- Change: In GCellConfiguration, for xG_xL3, detect straight vertical topologies
and for them to be fixed (new flag FIXED_GLOBAL set by the topological
builder instead of the constructor). This prevent the router to do
stupid things...
To sets the "Fixed" flag *after* the axis of global segments have been
positionned correctly adds a "_toFixGlobals" static table lookup.
- Change: In GCell::stepDesaturate(), if less than one free track remains in
the upper layer, do not move up the segment. This allows from a minimum
free room for expansion.
- Change: In GCell::_getString(), display indexes and layer names in various
saturation tables.
- Change: In AutoSegment, allow move up of local Segment. ::moveUp() and
::canMoveUp() arguments go from booleans to flags, which are more
explicits.
2010-12-04 09:25:18 -06:00
|
|
|
bool hasGlobalSegment = false;
|
|
|
|
if ( flags & Propagate ) {
|
2010-03-09 09:24:29 -06:00
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
* ./katabatic:
- Change: In loadGlobalRouting(), more exlicit message as to why a net is
filtered out the routing set (POWER, GROUND, CLOCK or BLOCKAGE).
- New: ChipTool, module with utilities specific to chip routing. Containing
a function to pre-break wires around a block.
- New: In loadGlobalRouting/GCellConfiguration, adds supports for RoutingPad
connected on chip's pad.
- New: In GCellGrid/GCell, can compute the density in three modes: average,
max of H/V and max of layer. Currently implemented in getMaxHVDensity(),
should be unificated with getDensity(). Used for display purposes.
- Bug: In AutoContact, when splitting a contact, add a specific check for
"one layer span".
- Bug: In AutoSegment::canMoveUp(), do not move up fixed segments.
2010-11-16 07:59:38 -06:00
|
|
|
if ( isegment->isFixed () ) return false;
|
2010-03-09 09:24:29 -06:00
|
|
|
if ( isegment->isGlobal() ) hasGlobalSegment = true;
|
|
|
|
|
|
|
|
isegment->getGCells ( gcells );
|
2011-01-09 12:08:31 -06:00
|
|
|
if ( (*gcells.begin ())->getIndex() < begin->getIndex() ) begin = *gcells.begin ();
|
|
|
|
if ( (*gcells.rbegin())->getIndex() > end ->getIndex() ) end = *gcells.rbegin();
|
|
|
|
|
2010-03-09 09:24:29 -06:00
|
|
|
for ( size_t i=0 ; i<gcells.size() ; i++ ) {
|
2010-04-23 08:13:54 -05:00
|
|
|
if ( not gcells[i]->hasFreeTrack(depth,reserve) ) {
|
2010-03-09 09:24:29 -06:00
|
|
|
ltrace(200) << "Not enough free track in " << gcells[i] << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-09 12:08:31 -06:00
|
|
|
if ( (depth >= 4) and (flags & PerpandicularFrag) ) {
|
|
|
|
float fragmentation = begin->getFragmentation(depth-1);
|
|
|
|
ltrace(200) << "Check begin GCell perpandicular fragmentation: " << fragmentation << endl;
|
|
|
|
|
|
|
|
if ( fragmentation < 0.5 ) {
|
|
|
|
ltrace(200) << "Not enough free track for perpandicular in begin GCell "
|
|
|
|
<< "(frag:" << fragmentation << ")."
|
|
|
|
<< endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fragmentation = end->getFragmentation(depth-1);
|
|
|
|
ltrace(200) << "Check end GCell perpandicular fragmentation: " << fragmentation << endl;
|
|
|
|
|
|
|
|
if ( fragmentation < 0.5 ) {
|
|
|
|
ltrace(200) << "Not enough free track for perpandicular in end GCell "
|
|
|
|
<< "(frag:" << fragmentation << ")."
|
|
|
|
<< endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-09 09:24:29 -06:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
* ./katabatic:
- New: ChipTools, regroup all datas and utilities to manage a full-chip
design.
- Change: In LoadGrByNet/GCellConfiguration::_GCell_xG_1Pad(), uses straight
perpandicular wires on top & right pads. The GCells under those connectors
are fully saturated, wires must go out as straight as possible.
- Change: In AutoHorizontal/AutoVertical, update the "terminal" flag after
slackening. This is to avoid global that are no longer connected to
terminals behave as such.
- Change: In AutoSegment::canMoveUp() & canPivotUp(), prevent all local segments
to go up. This is to avoid cluttering upper levels with small segments.
- Change: In GCellConfiguration, for xG_xL3, detect straight vertical topologies
and for them to be fixed (new flag FIXED_GLOBAL set by the topological
builder instead of the constructor). This prevent the router to do
stupid things...
To sets the "Fixed" flag *after* the axis of global segments have been
positionned correctly adds a "_toFixGlobals" static table lookup.
- Change: In GCell::stepDesaturate(), if less than one free track remains in
the upper layer, do not move up the segment. This allows from a minimum
free room for expansion.
- Change: In GCell::_getString(), display indexes and layer names in various
saturation tables.
- Change: In AutoSegment, allow move up of local Segment. ::moveUp() and
::canMoveUp() arguments go from booleans to flags, which are more
explicits.
2010-12-04 09:25:18 -06:00
|
|
|
bool AutoSegment::moveUp ( unsigned int flags )
|
2010-03-09 09:24:29 -06:00
|
|
|
{
|
2011-01-25 11:16:27 -06:00
|
|
|
//if ( not canMoveUp(0.0,flags) ) return false;
|
* ./katabatic:
- New: ChipTools, regroup all datas and utilities to manage a full-chip
design.
- Change: In LoadGrByNet/GCellConfiguration::_GCell_xG_1Pad(), uses straight
perpandicular wires on top & right pads. The GCells under those connectors
are fully saturated, wires must go out as straight as possible.
- Change: In AutoHorizontal/AutoVertical, update the "terminal" flag after
slackening. This is to avoid global that are no longer connected to
terminals behave as such.
- Change: In AutoSegment::canMoveUp() & canPivotUp(), prevent all local segments
to go up. This is to avoid cluttering upper levels with small segments.
- Change: In GCellConfiguration, for xG_xL3, detect straight vertical topologies
and for them to be fixed (new flag FIXED_GLOBAL set by the topological
builder instead of the constructor). This prevent the router to do
stupid things...
To sets the "Fixed" flag *after* the axis of global segments have been
positionned correctly adds a "_toFixGlobals" static table lookup.
- Change: In GCell::stepDesaturate(), if less than one free track remains in
the upper layer, do not move up the segment. This allows from a minimum
free room for expansion.
- Change: In GCell::_getString(), display indexes and layer names in various
saturation tables.
- Change: In AutoSegment, allow move up of local Segment. ::moveUp() and
::canMoveUp() arguments go from booleans to flags, which are more
explicits.
2010-12-04 09:25:18 -06:00
|
|
|
changeDepth ( Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2, flags&Propagate );
|
2010-03-09 09:24:29 -06:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
bool AutoSegment::moveDown ( unsigned int flags )
|
|
|
|
{
|
2011-01-25 11:16:27 -06:00
|
|
|
//if ( not canPivotDown(0.0,flags) ) return false;
|
* ./katabatic:
- New: In AutoSegment, adds a "_parent" attribute to keep track of the fragmentation
processus. Currently used only for strap segments, points to the original
segment in the appropriate direction (before the split).
- New: In GCell & LayerAssign, new method of layer assignment. Move up
the whole net trunk if only one of it's segment is inside an over-saturated
GCell. AutoSegment are moved up only if there is at least 2 free tracks
remaining on the upper level.
- Change: In Session::_canonize(), uses the lowest segment Id as canonical.
More reliable than geometricals criterions in the end. Assuming that the
segments are being created in deterministic order, which *should* be the
case consediring the way we are walking through the global routing.
- Change: In AutoSegment, completly suppress the CompareCanonical(), replace
it by the much simpler CompareId().
- Change: In GCell::rpDesaturate(), stops desaturation when bottom density
is under 0.5, otherwise we are causing a severe imbalance in M2/M4
densities. All wires pushed up to M4...
- Change: In ChipTools, for the Pad's RoutingPad, reslect the best component
using the one in the lowest layer. To avoid problem when splitting
AutoContact as we expect the base Contact to be on the lower layer.
- Bug: In GCellConfiguration::_GCell_xG_xL1_xL3(), add H/V alignement constraints
in fork case. This allow NE/SW contact to be splitted correctly later.
- Bug: In AutoContact::split(), the connexity on the splitted contacts was
not correctly restored, leading to canonization and parentage looping
errors. This was concealed by the Kite Track::_check() bug (incomplete
individual TrackSegment checking).
2010-12-30 12:41:19 -06:00
|
|
|
changeDepth ( Session::getRoutingGauge()->getLayerDepth(getLayer()) - 2, flags&Propagate );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-12 15:43:25 -06:00
|
|
|
bool AutoSegment::shearUp ( GCell* upGCell, AutoSegment*& movedUp, float reserve, unsigned int flags )
|
|
|
|
{
|
|
|
|
ltrace(200) << "AutoSegment::shearUp() " << this << endl;
|
|
|
|
|
|
|
|
movedUp = NULL;
|
|
|
|
|
|
|
|
if ( isLayerChange() or isFixed() /*or isTerminal()*/ or isLocal() ) return false;
|
|
|
|
|
|
|
|
size_t upDepth = Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2;
|
|
|
|
if ( upDepth >= Session::getConfiguration()->getAllowedDepth() ) return false;
|
|
|
|
|
|
|
|
vector<GCell*> gcells;
|
|
|
|
getGCells ( gcells );
|
|
|
|
|
|
|
|
size_t iupGCell = 0;
|
|
|
|
for ( ; iupGCell<gcells.size() ; ++iupGCell ) {
|
|
|
|
if ( gcells[iupGCell] == upGCell ) break;
|
|
|
|
}
|
|
|
|
if ( iupGCell == gcells.size() ) {
|
|
|
|
cerr << Warning("Shear start %s not under %s."
|
|
|
|
,getString(upGCell).c_str()
|
|
|
|
,getString(this).c_str()
|
|
|
|
) << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
GCell* rightShear = NULL;
|
|
|
|
for ( size_t i=iupGCell ; i<gcells.size() ; i++ ) {
|
|
|
|
if ( not gcells[i]->hasFreeTrack(upDepth,reserve) ) {
|
|
|
|
ltrace(200) << "Right shearing @ " << gcells[i] << endl;
|
|
|
|
rightShear = gcells[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GCell* leftShear = NULL;
|
|
|
|
if ( iupGCell > 0 ) {
|
|
|
|
size_t i = iupGCell;
|
|
|
|
do {
|
|
|
|
--i;
|
|
|
|
if ( not gcells[i]->hasFreeTrack(upDepth,reserve) ) {
|
|
|
|
ltrace(200) << "Left shearing @ " << gcells[i] << endl;
|
|
|
|
leftShear = gcells[i];
|
|
|
|
}
|
|
|
|
} while (i > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
AutoSegment* before = this;
|
|
|
|
const vector<AutoSegment*>& doglegs = Session::getDogLegs();
|
|
|
|
|
|
|
|
if ( leftShear ) {
|
|
|
|
makeDogLeg ( leftShear, true );
|
|
|
|
movedUp = doglegs[2];
|
|
|
|
} else {
|
|
|
|
before = NULL;
|
|
|
|
movedUp = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( rightShear ) makeDogLeg(rightShear,true);
|
|
|
|
|
|
|
|
if ( movedUp->moveUp(flags) ) {
|
|
|
|
if ( rightShear or leftShear )
|
|
|
|
cinfo << "Shearing Up " << this << "." << endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
movedUp = NULL;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-09 09:24:29 -06:00
|
|
|
bool AutoSegment::canDogLeg ( Interval interval )
|
|
|
|
{
|
|
|
|
ltrace(200) << "AutoSegment::canDogLeg(Interval) " << interval << endl;
|
|
|
|
|
|
|
|
size_t leftDogleg = 0;
|
|
|
|
size_t rightDogleg = 0;
|
|
|
|
if ( getSpanU().contains(interval.getVMin()) ) leftDogleg++;
|
|
|
|
if ( getSpanU().contains(interval.getVMax()) ) rightDogleg++;
|
|
|
|
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
if ( isegment->getSpanU().contains(interval.getVMin()) ) {
|
|
|
|
if ( isegment->isFixed() ) return false;
|
|
|
|
leftDogleg++;
|
|
|
|
}
|
|
|
|
if ( isegment->getSpanU().contains(interval.getVMax()) ) {
|
|
|
|
if ( isegment->isFixed() ) return false;
|
|
|
|
rightDogleg++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (leftDogleg == 1) and (rightDogleg <= 1) ) return true;
|
|
|
|
if ( (leftDogleg <= 1) and (rightDogleg == 1) ) return true;
|
|
|
|
|
|
|
|
ltrace(200) << "leftCount:" << leftDogleg << " rightCount:" << rightDogleg << endl;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::makeDogLeg ( Interval interval, bool upLayer, bool& leftDogleg )
|
|
|
|
{
|
|
|
|
ltrace(200) << "AutoSegment::makeDogLeg(Interval)" << endl;
|
|
|
|
|
|
|
|
size_t leftDoglegCount = 0;
|
|
|
|
size_t rightDoglegCount = 0;
|
|
|
|
AutoSegment* leftCandidate = NULL;
|
|
|
|
AutoSegment* rightCandidate = NULL;
|
|
|
|
|
|
|
|
if ( getSpanU().contains(interval.getVMin()) ) { leftCandidate = this; leftDoglegCount++; }
|
|
|
|
if ( getSpanU().contains(interval.getVMax()) ) { rightCandidate = this; rightDoglegCount++; }
|
|
|
|
|
|
|
|
forEach ( AutoSegment*, isegment, getCollapseds() ) {
|
|
|
|
if ( isegment->getSpanU().contains(interval.getVMin()) ) { leftCandidate = *isegment; leftDoglegCount++; }
|
|
|
|
if ( isegment->getSpanU().contains(interval.getVMax()) ) { rightCandidate = *isegment; rightDoglegCount++; }
|
|
|
|
}
|
|
|
|
|
|
|
|
leftDogleg = true;
|
|
|
|
if ( (leftDoglegCount != 1) and (rightDoglegCount != 1) ) return;
|
|
|
|
if ( !leftDoglegCount ) {
|
|
|
|
leftDogleg = false;
|
|
|
|
leftCandidate = rightCandidate;
|
|
|
|
rightCandidate = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( leftCandidate && rightCandidate ) {
|
|
|
|
ltrace(200) << "Left Constraint: " << leftCandidate->getSourceConstraints(true) << endl;
|
|
|
|
ltrace(200) << "Right Constraint: " << rightCandidate->getTargetConstraints(true) << endl;
|
|
|
|
|
|
|
|
if ( leftCandidate ->getTargetConstraints(true).getSize()
|
|
|
|
< rightCandidate->getSourceConstraints(true).getSize() ) {
|
|
|
|
leftCandidate = rightCandidate;
|
|
|
|
leftDogleg = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( !leftCandidate ) {
|
|
|
|
leftCandidate = rightCandidate;
|
|
|
|
leftDogleg = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( leftCandidate ) {
|
|
|
|
leftCandidate->_makeDogLeg ( getAutoSource()->getGCell(), upLayer );
|
|
|
|
|
|
|
|
const vector<AutoSegment*>& dogLegs = Session::getDogLegs();
|
|
|
|
if ( dogLegs.size() >= 2 ) {
|
|
|
|
DbU::Unit axis;
|
|
|
|
if ( leftDogleg )
|
|
|
|
axis = interval.getVMin() - DbU::lambda(5.0); // Ugly: Hard-wired track spacing.
|
|
|
|
else
|
|
|
|
axis = interval.getVMax() + DbU::lambda(5.0); // Ugly: Hard-wired track spacing.
|
|
|
|
|
|
|
|
ltrace(200) << "AutoSegment::makeDogLeg(): @" << DbU::getValueString(axis) << endl;
|
|
|
|
dogLegs[1]->setAxis ( axis );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::makeDogLeg ( GCell* dogLegGCell, bool upLayer )
|
|
|
|
{
|
|
|
|
ltrace(160) << "AutoSegment::makeDogLeg(GCell*)" << endl;
|
|
|
|
ltracein(160);
|
|
|
|
|
|
|
|
if ( isFixed() ) {
|
|
|
|
cerr << Error("AutoSegment::makeDogLeg(): Cannot make a dog leg on a fixed segment.\n"
|
|
|
|
" (on: %s)",_getString().c_str()) << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidate ();
|
|
|
|
|
|
|
|
if ( dogLegGCell->getUSide(getDirection()).intersect(getSpanU()) ) {
|
|
|
|
ltrace(159) << "Dogleg in " << this << endl;
|
|
|
|
_makeDogLeg ( dogLegGCell, upLayer );
|
|
|
|
//Session::revalidate ( getNet() );
|
|
|
|
} else {
|
|
|
|
ltrace(159) << "Looking in aligneds." << endl;
|
|
|
|
forEach ( AutoSegment*, aligned, getCollapseds() ) {
|
|
|
|
ltrace(159) << "| Try in " << *aligned << endl;
|
|
|
|
if ( dogLegGCell->getUSide(getDirection()).intersect(aligned->getSpanU()) ) {
|
|
|
|
ltrace(159) << "Dogleg in " << *aligned << endl;
|
|
|
|
aligned->_makeDogLeg ( dogLegGCell, upLayer );
|
|
|
|
//Session::revalidate ( getNet() );
|
|
|
|
ltraceout(160);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cerr << Bug("Cannot make a dogleg in %s at %s"
|
|
|
|
,_getString().c_str(), getString(dogLegGCell).c_str()) << endl;
|
|
|
|
}
|
|
|
|
ltraceout(160);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::_check () const
|
|
|
|
{
|
|
|
|
bool coherency = true;
|
|
|
|
|
|
|
|
coherency = coherency && checkInvalidated();
|
|
|
|
coherency = coherency && checkPositions();
|
|
|
|
coherency = coherency && checkConstraints();
|
|
|
|
|
|
|
|
return coherency;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string AutoSegment::_getString () const
|
|
|
|
{
|
|
|
|
string s = getSegment()->_getString();
|
|
|
|
s.insert ( 1, "id: " );
|
|
|
|
s.insert ( 4, getString(_id) );
|
2011-01-25 11:16:27 -06:00
|
|
|
s.insert ( s.size()-1, (_isFixed )?" F":" -" );
|
|
|
|
s.insert ( s.size()-1, (_strap )? "S": "-" );
|
|
|
|
s.insert ( s.size()-1, (_isCanonical )? "C": "-" );
|
|
|
|
s.insert ( s.size()-1, (_isCollapsed )? "c": "-" );
|
|
|
|
s.insert ( s.size()-1, (_isGlobal )? "g": "-" );
|
|
|
|
s.insert ( s.size()-1, (_isTopologicEnd)? "e": "-" );
|
|
|
|
s.insert ( s.size()-1, (_isTerminal )? "t": "-" );
|
|
|
|
s.insert ( s.size()-1, (_slackened )? "S": "-" );
|
|
|
|
s.insert ( s.size()-1, (_invalidated )? "i": "-" );
|
2010-03-09 09:24:29 -06:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Record* AutoSegment::_getRecord () const
|
|
|
|
{
|
|
|
|
Record* record = getSegment()->_getRecord ();
|
|
|
|
record->add ( getSlot ( "_gcell" , _gcell ) );
|
|
|
|
record->add ( getSlot ( "_isHorizontal" , &_isHorizontal ) );
|
|
|
|
record->add ( getSlot ( "_isFixed" , &_isFixed ) );
|
|
|
|
record->add ( getSlot ( "_strap" , &_strap ) );
|
|
|
|
record->add ( getSlot ( "_layerChange" , &_layerChange ) );
|
|
|
|
record->add ( getSlot ( "_isCanonical" , &_isCanonical ) );
|
|
|
|
record->add ( getSlot ( "_isCollapsed" , &_isCollapsed ) );
|
|
|
|
record->add ( getSlot ( "_isGlobal" , &_isGlobal ) );
|
|
|
|
record->add ( getSlot ( "_isTerminal" , &_isTerminal ) );
|
|
|
|
record->add ( getSlot ( "_slackened" , &_slackened ) );
|
|
|
|
record->add ( getSlot ( "_invalidated" , &_invalidated ) );
|
|
|
|
record->add ( getSlot ( "_sourcePosition", &_sourcePosition ) );
|
|
|
|
record->add ( getSlot ( "_targetPosition", &_targetPosition ) );
|
|
|
|
return record;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegment* AutoSegment::create ( AutoContact* source
|
|
|
|
, AutoContact* target
|
|
|
|
, Segment* hurricaneSegment
|
|
|
|
)
|
|
|
|
{
|
|
|
|
static Layer* verticalLayer = DataBase::getDB()->getTechnology()->getLayer ( "METAL3" );
|
|
|
|
static Layer* horizontalLayer = DataBase::getDB()->getTechnology()->getLayer ( "METAL2" );
|
|
|
|
|
|
|
|
AutoSegment* segment;
|
|
|
|
Horizontal* horizontal;
|
|
|
|
Vertical* vertical;
|
|
|
|
|
|
|
|
Contact* contact = dynamic_cast<Contact*>(hurricaneSegment->getSource());
|
|
|
|
AutoContact* autoContact = Session::lookup(contact);
|
2010-04-23 08:13:54 -05:00
|
|
|
if ( contact == NULL ) {
|
2010-03-09 09:24:29 -06:00
|
|
|
throw Error ( badSegmentSource, getString(hurricaneSegment).c_str() );
|
2010-04-23 08:13:54 -05:00
|
|
|
if ( autoContact and ( autoContact != source ) )
|
2010-03-09 09:24:29 -06:00
|
|
|
throw Error ( mismatchSegmentSource
|
|
|
|
, getString(hurricaneSegment).c_str()
|
|
|
|
, getString(contact).c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
contact = dynamic_cast<Contact*>(hurricaneSegment->getTarget());
|
|
|
|
autoContact = Session::lookup(contact);
|
2010-04-23 08:13:54 -05:00
|
|
|
if ( contact == NULL ) {
|
2010-03-09 09:24:29 -06:00
|
|
|
throw Error ( badSegmentTarget, getString(hurricaneSegment).c_str() );
|
2010-04-23 08:13:54 -05:00
|
|
|
if ( autoContact and ( autoContact != target ) )
|
2010-03-09 09:24:29 -06:00
|
|
|
throw Error ( mismatchSegmentTarget
|
|
|
|
, getString(hurricaneSegment).c_str()
|
|
|
|
, getString(contact).c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
Hook* hook = hurricaneSegment->getSourceHook();
|
|
|
|
hook->detach ();
|
|
|
|
hook->attach ( source->getBodyHook() );
|
|
|
|
|
|
|
|
hook = hurricaneSegment->getTargetHook();
|
|
|
|
hook->detach ();
|
|
|
|
hook->attach ( target->getBodyHook() );
|
|
|
|
|
|
|
|
if ( (horizontal = dynamic_cast<Horizontal*>(hurricaneSegment) ) ) {
|
|
|
|
if ( horizontal->getLayer() != horizontalLayer ) {
|
|
|
|
if ( !Session::getKatabatic()->isGMetal(horizontal->getLayer()) )
|
|
|
|
cerr << Warning("Segment %s forced to %s."
|
|
|
|
,getString(horizontal).c_str()
|
|
|
|
,getString(horizontalLayer).c_str()) << endl;
|
|
|
|
horizontal->setLayer ( horizontalLayer );
|
|
|
|
}
|
|
|
|
|
|
|
|
segment = AutoHorizontal::create ( horizontal
|
|
|
|
, AutoSegment::Global
|
|
|
|
, false
|
|
|
|
, false
|
|
|
|
);
|
|
|
|
} else if ( (vertical = dynamic_cast<Vertical*>(hurricaneSegment)) ) {
|
|
|
|
if ( vertical->getLayer() != verticalLayer ) {
|
|
|
|
if ( !Session::getKatabatic()->isGMetal(vertical->getLayer()) )
|
|
|
|
cerr << Warning("Segment %s forced to %s."
|
|
|
|
,getString(vertical).c_str()
|
|
|
|
,getString(verticalLayer).c_str()) << endl;
|
|
|
|
vertical->setLayer ( verticalLayer );
|
|
|
|
}
|
|
|
|
|
|
|
|
segment = AutoVertical::create ( vertical
|
|
|
|
, AutoSegment::Global
|
|
|
|
, false
|
|
|
|
, false
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw Error ( badSegment, getString(source).c_str(), getString(target).c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
ltrace(99) << "Creating " << segment << endl;
|
|
|
|
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegment* AutoSegment::create ( AutoContact* source
|
|
|
|
, AutoContact* target
|
|
|
|
, unsigned int dir
|
|
|
|
, int type
|
|
|
|
, bool terminal
|
|
|
|
, bool collapsed
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//static Layer* verticalLayer = DataBase::getDB()->getTechnology()->getLayer ( "METAL3" );
|
|
|
|
//static Layer* horizontalLayer = DataBase::getDB()->getTechnology()->getLayer ( "METAL2" );
|
|
|
|
|
|
|
|
static const Layer* horizontalLayer = Session::getRoutingLayer ( 1 );
|
|
|
|
static const Layer* verticalLayer = Session::getRoutingLayer ( 2 );
|
|
|
|
|
|
|
|
GCell* gcell;
|
|
|
|
GCell* end;
|
|
|
|
AutoSegment* segment;
|
|
|
|
|
|
|
|
if ( dir & Constant::Horizontal ) {
|
|
|
|
segment = AutoHorizontal::create ( source
|
|
|
|
, target
|
|
|
|
, horizontalLayer
|
|
|
|
, source->getY()
|
|
|
|
, DbU::lambda(2.0)
|
|
|
|
, type
|
|
|
|
, terminal
|
|
|
|
, collapsed
|
|
|
|
);
|
|
|
|
if ( type == AutoSegment::Global ) {
|
|
|
|
if ( source->getGCell()->getX() < target->getGCell()->getX() ) {
|
|
|
|
gcell = source->getGCell()->getRight();
|
|
|
|
end = target->getGCell();
|
|
|
|
} else {
|
|
|
|
gcell = target->getGCell()->getRight();
|
|
|
|
end = source->getGCell();
|
|
|
|
}
|
|
|
|
for ( ; gcell != end ; gcell = gcell->getRight() ) {
|
|
|
|
if ( !gcell ) {
|
|
|
|
cerr << Error("AutoSegment::create() : NULL GCell.") << endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gcell->addHSegment ( segment );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( dir & Constant::Vertical ) {
|
|
|
|
segment = AutoVertical::create ( source
|
|
|
|
, target
|
|
|
|
, verticalLayer
|
|
|
|
, source->getX()
|
|
|
|
, DbU::lambda(2.0)
|
|
|
|
, type
|
|
|
|
, terminal
|
|
|
|
, collapsed
|
|
|
|
);
|
|
|
|
if ( type == AutoSegment::Global ) {
|
|
|
|
if ( source->getGCell()->getY() < target->getGCell()->getY() ) {
|
|
|
|
gcell = source->getGCell()->getUp();
|
|
|
|
end = target->getGCell();
|
|
|
|
} else {
|
|
|
|
gcell = target->getGCell()->getUp();
|
|
|
|
end = source->getGCell();
|
|
|
|
}
|
|
|
|
for ( ; gcell != end ; gcell = gcell->getUp() ) {
|
|
|
|
if ( !gcell ) {
|
|
|
|
cerr << Error("AutoSegment::create() : NULL GCell.") << endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gcell->addVSegment ( segment );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
throw Error ( badSegment, getString(source).c_str(), getString(target).c_str() );
|
|
|
|
|
|
|
|
ltrace(99) << "create() " << segment << endl;
|
|
|
|
|
|
|
|
return segment;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::destroy ()
|
|
|
|
{
|
|
|
|
_preDestroy ();
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoSegment::isTopologicalBound ( AutoSegment* seed
|
|
|
|
, bool superior
|
|
|
|
, bool isHorizontal )
|
|
|
|
{
|
|
|
|
ltrace(80) << "isTopologicalBound() - " << seed << endl;
|
|
|
|
ltracein(80);
|
|
|
|
|
|
|
|
set<AutoContact*> exploreds;
|
|
|
|
vector<AutoContact*> stack;
|
|
|
|
DbU::Unit axis;
|
|
|
|
|
|
|
|
if ( superior ) axis = seed->getTargetU();
|
|
|
|
else axis = seed->getSourceU();
|
|
|
|
|
|
|
|
ltrace(80) << "check for bound " << DbU::getValueString(axis) << endl;
|
|
|
|
|
|
|
|
exploreds.insert ( seed->getAutoSource() );
|
|
|
|
exploreds.insert ( seed->getAutoTarget() );
|
|
|
|
|
|
|
|
if ( seed->getLength() ) {
|
|
|
|
if ( superior ) stack.push_back ( seed->getAutoTarget() );
|
|
|
|
else stack.push_back ( seed->getAutoSource() );
|
|
|
|
} else {
|
|
|
|
stack.push_back ( seed->getAutoTarget() );
|
|
|
|
stack.push_back ( seed->getAutoSource() );
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( !stack.empty() ) {
|
|
|
|
AutoContact* currentContact = stack.back();
|
|
|
|
stack.pop_back ();
|
|
|
|
|
|
|
|
ltrace(80) << "Exploring: " << (void*)currentContact
|
|
|
|
<< " " << currentContact << endl;
|
|
|
|
|
|
|
|
exploreds.insert ( currentContact );
|
|
|
|
|
|
|
|
if ( currentContact->getAnchor() ) { ltraceout(80); return true; }
|
|
|
|
|
|
|
|
forEach ( Component*, component, currentContact->getSlaveComponents() ) {
|
|
|
|
Segment* segment = dynamic_cast<Segment*>(*component);
|
|
|
|
if ( !segment ) continue;
|
|
|
|
|
|
|
|
AutoSegment* autoSegment = Session::lookup ( segment );
|
|
|
|
if ( !autoSegment ) continue;
|
|
|
|
|
|
|
|
if ( !autoSegment->getLength() ) {
|
|
|
|
AutoContact* contact = autoSegment->getAutoSource();
|
|
|
|
if ( contact && ( contact != currentContact ) ) {
|
|
|
|
if ( exploreds.find(contact) == exploreds.end() )
|
|
|
|
stack.push_back ( contact );
|
|
|
|
}
|
|
|
|
|
|
|
|
contact = autoSegment->getAutoTarget();
|
|
|
|
if ( contact && ( contact != currentContact ) ) {
|
|
|
|
if ( exploreds.find(contact) == exploreds.end() )
|
|
|
|
stack.push_back ( contact );
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( autoSegment->isHorizontal() != isHorizontal ) continue;
|
|
|
|
|
|
|
|
ltrace(80) << "| " << autoSegment << endl;
|
|
|
|
|
|
|
|
if ( superior ) {
|
|
|
|
if ( autoSegment->getTargetU() > axis ) { ltraceout(80); return true; }
|
|
|
|
} else {
|
|
|
|
if ( autoSegment->getSourceU() < axis ) { ltraceout(80); return true; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ltraceout(80);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int AutoSegment::getPerpandicularState ( AutoContact* contact
|
|
|
|
, AutoSegment* source
|
|
|
|
, AutoSegment* current
|
|
|
|
, bool isHorizontalMaster
|
|
|
|
, const Layer* masterLayer )
|
|
|
|
{
|
|
|
|
unsigned int state = 0;
|
|
|
|
|
|
|
|
bool sourcePerpandicular = arePerpandiculars ( isHorizontalMaster, source );
|
|
|
|
bool currentPerpandicular = arePerpandiculars ( isHorizontalMaster, current );
|
|
|
|
bool contactAlignate
|
|
|
|
= (contact->isHAlignate() and current->isHorizontal() and isHorizontalMaster)
|
|
|
|
or (contact->isVAlignate() and !current->isHorizontal() and !isHorizontalMaster);
|
|
|
|
|
|
|
|
if ( not currentPerpandicular and masterLayer and (masterLayer != current->getLayer()) )
|
|
|
|
state |= ParallelAndLayerChange;
|
|
|
|
|
|
|
|
if ( currentPerpandicular and !current->isCollapsed() )
|
|
|
|
state |= PerpandicularAny;
|
|
|
|
|
|
|
|
if ( sourcePerpandicular ) {
|
|
|
|
// Source segment is perpandicular to master.
|
|
|
|
if ( currentPerpandicular and !current->isCollapsed() )
|
|
|
|
state |= PerpandicularIndirect;
|
|
|
|
} else {
|
|
|
|
// Source segment is parallel to master.
|
|
|
|
if ( not (currentPerpandicular and current->isCollapsed()) and not contactAlignate ) {
|
|
|
|
// Current segment is parallel OR expanded.
|
|
|
|
state |= ParallelOrExpanded;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoSegment::getTopologicalInfos ( AutoSegment* seed
|
|
|
|
, vector<AutoSegment*>& collapseds
|
|
|
|
, vector<AutoSegment*>& perpandiculars
|
|
|
|
, DbU::Unit& leftBound
|
|
|
|
, DbU::Unit& rightBound
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ltrace(80) << "getTopologicalInfos() - " << seed << endl;
|
|
|
|
|
|
|
|
leftBound = DbU::Max;
|
|
|
|
rightBound = DbU::Min;
|
|
|
|
|
|
|
|
AutoSegmentStack stack;
|
|
|
|
|
|
|
|
stack.push ( seed->getAutoSource(), seed );
|
|
|
|
stack.push ( seed->getAutoTarget(), seed );
|
|
|
|
|
2011-01-09 12:08:31 -06:00
|
|
|
while ( not stack.isEmpty() ) {
|
2010-03-09 09:24:29 -06:00
|
|
|
AutoContact* sourceContact = stack.getAutoContact ();
|
|
|
|
AutoSegment* sourceSegment = stack.getAutoSegment ();
|
|
|
|
|
|
|
|
stack.pop ();
|
|
|
|
|
|
|
|
DbU::Unit constraint;
|
|
|
|
|
|
|
|
if ( seed->isHorizontal() ) constraint = sourceContact->getCBXMax();
|
|
|
|
else constraint = sourceContact->getCBYMax();
|
|
|
|
if ( constraint < leftBound ) leftBound = constraint;
|
|
|
|
|
|
|
|
if ( seed->isHorizontal() ) constraint = sourceContact->getCBXMin();
|
|
|
|
else constraint = sourceContact->getCBYMin();
|
|
|
|
if ( constraint > rightBound ) rightBound = constraint;
|
|
|
|
|
|
|
|
forEach ( Component*, component, sourceContact->getSlaveComponents() ) {
|
|
|
|
Segment* segment = dynamic_cast<Segment*>(*component);
|
2011-01-09 12:08:31 -06:00
|
|
|
if ( ( not segment ) || ( segment == sourceSegment->getSegment() ) ) continue;
|
2010-03-09 09:24:29 -06:00
|
|
|
|
|
|
|
AutoSegment* currentSegment = Session::lookup ( segment );
|
2011-01-09 12:08:31 -06:00
|
|
|
if ( not currentSegment ) {
|
2010-03-09 09:24:29 -06:00
|
|
|
cerr << Error("Can't lookup <AutoSegment> for %s.",getString(segment).c_str()) << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int state = getPerpandicularState ( sourceContact
|
|
|
|
, sourceSegment
|
|
|
|
, currentSegment
|
|
|
|
, seed );
|
|
|
|
if ( state & PerpandicularAny ) {
|
|
|
|
ltrace(79) << "Perpandicular: " << currentSegment << endl;
|
|
|
|
perpandiculars.push_back ( currentSegment );
|
|
|
|
}
|
|
|
|
if ( state & (PerpandicularIndirect
|
|
|
|
|ParallelOrExpanded
|
|
|
|
|ParallelAndLayerChange ) ) {
|
|
|
|
ltrace(79) << "Reject: " << currentSegment << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-01-09 12:08:31 -06:00
|
|
|
if ( not areAligneds(currentSegment,seed) ) {
|
2010-03-09 09:24:29 -06:00
|
|
|
collapseds.push_back ( currentSegment );
|
|
|
|
ltrace(79) << "collapsed: " << currentSegment << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
Component* opposite = segment->getOppositeAnchor ( sourceContact->getContact() );
|
|
|
|
AutoContact* targetContact = Session::lookup(static_cast<Contact*>(opposite));
|
|
|
|
if ( targetContact ) stack.push ( targetContact, currentSegment );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int AutoSegment::getTerminalCount ( AutoSegment* seed, vector<AutoSegment*>& collapseds )
|
|
|
|
{
|
|
|
|
ltrace(80) << "getTerminalCount() - " << seed << " (+collapseds)" << endl;
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
for ( size_t i=0 ; i < collapseds.size() ; i++ ) {
|
|
|
|
if ( collapseds[i]->isTerminal() )
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
if ( seed->getAutoSource()->isTerminal() ) count++;
|
|
|
|
if ( seed->getAutoTarget()->isTerminal() ) count++;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // End of Katabatic namespace.
|