2689 lines
89 KiB
C++
2689 lines
89 KiB
C++
|
|
// -*- C++ -*-
|
|
//
|
|
// This file is part of the Coriolis Software.
|
|
// Copyright (c) UPMC/LIP6 2008-2009, All Rights Reserved
|
|
//
|
|
// ===================================================================
|
|
//
|
|
// $Id$
|
|
//
|
|
// x-----------------------------------------------------------------x
|
|
// | |
|
|
// | C O R I O L I S |
|
|
// | K a t a b a t i c - Routing Toolbox |
|
|
// | |
|
|
// | Author : Jean-Paul CHAPUT |
|
|
// | E-mail : Jean-Paul.Chaput@asim.lip6.fr |
|
|
// | =============================================================== |
|
|
// | C++ Module : "./AutoContact.cpp" |
|
|
// | *************************************************************** |
|
|
// | U p d a t e s |
|
|
// | |
|
|
// x-----------------------------------------------------------------x
|
|
|
|
|
|
#include <cstdlib>
|
|
#include <climits>
|
|
#include <sstream>
|
|
|
|
#include "hurricane/Bug.h"
|
|
#include "hurricane/Error.h"
|
|
#include "hurricane/Warning.h"
|
|
#include "hurricane/Layer.h"
|
|
#include "hurricane/ViaLayer.h"
|
|
#include "hurricane/BasicLayer.h"
|
|
#include "hurricane/Technology.h"
|
|
#include "hurricane/Net.h"
|
|
#include "hurricane/Contact.h"
|
|
#include "hurricane/Plug.h"
|
|
#include "hurricane/RoutingPad.h"
|
|
#include "hurricane/Vertical.h"
|
|
#include "hurricane/Horizontal.h"
|
|
#include "hurricane/UpdateSession.h"
|
|
#include "hurricane/DebugSession.h"
|
|
|
|
#include "crlcore/RoutingGauge.h"
|
|
|
|
#include "katabatic/GCell.h"
|
|
#include "katabatic/AutoContact.h"
|
|
#include "katabatic/AutoSegment.h"
|
|
#include "katabatic/AutoVertical.h"
|
|
#include "katabatic/AutoHorizontal.h"
|
|
#include "katabatic/Session.h"
|
|
|
|
|
|
namespace {
|
|
|
|
/*! \class SegmentEnd
|
|
* \brief Segment manipulator (\b internal)
|
|
*
|
|
* SegmentPosition compute detailed informations about how an
|
|
* Segment is connected to the current AutoContact. This
|
|
* object act as a cache, avoiding to recalculate the position
|
|
* information many times.
|
|
*
|
|
* It also provide uniform way of resizing the Segment extention
|
|
* from the AutoContact.
|
|
*/
|
|
|
|
/*! \var bool SegmentEnd::_isSourceHook;
|
|
* set to \b true if the Segment is attached to the AutoContact
|
|
* through it's source hook (\b false for target \c hook).
|
|
*/
|
|
|
|
/*! \function SegmentEnd::SegmentEnd ( AutoSegment* segment, bool isSourceHook );
|
|
* \param segment the supporting segment.
|
|
* \param isSourceHook initialize _isSourceHook.
|
|
*/
|
|
|
|
/*! \function static SegmentEnd* SegmentEnd::create ( Hook* hook, bool checking );
|
|
* \param contact The AutoContact we are currently processing.
|
|
* \return The appropriate SegmentPosition.
|
|
*
|
|
* This create function allocate the relevant HorizontalPosition or
|
|
* VerticalPosition derived object, providing an uniform allocator
|
|
* function.
|
|
*/
|
|
|
|
/*! \function virtual bool SegmentEnd::isVertical () const;
|
|
* \return \b true if the associated Segment is vertical.
|
|
*/
|
|
|
|
/*! \function virtual bool SegmentEnd::isHorizontal () const;
|
|
* \return \b true if the associated Segment is horizontal.
|
|
*/
|
|
|
|
/*! \function bool SegmentEnd::isSourceHook () const;
|
|
* \return The _isSourceHook value (accessor).
|
|
*/
|
|
|
|
/*! \function bool SegmentEnd::isGlobal () const;
|
|
* \return The _isGlobal value (accessor).
|
|
*/
|
|
|
|
/*! \function virtual DbU::Unit SegmentEnd::getAxis () const;
|
|
* \return For horizontal segment, the Y coordinate and the X coordinate for
|
|
* vertical ones.
|
|
*/
|
|
|
|
/*! \function Layer* SegmentEnd::getLayer () const;
|
|
* \return The layer of the segment.
|
|
*/
|
|
|
|
/*! \function Point SegmentEnd::getEnd () const;
|
|
* \return The position of the segment's extremity attached to the AutoContact.
|
|
*/
|
|
|
|
|
|
/*! \function void SegmentEnd::setDelta ( DbU::Unit delta );
|
|
* \param delta the new value of the extention.
|
|
*
|
|
* Adjust the segment's extention. Coordinate must be expressed
|
|
* as an offset to the absolute coordinate of the relevant hook.
|
|
*/
|
|
|
|
/*! \function void SegmentEnd::orient ();
|
|
* restore correct orientation of the segment (source \e lower than
|
|
* target), usually needed after a setDelta().
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*! \class HorizontalEnd
|
|
* \brief Horizontal Segment manipulator (\b internal)
|
|
*
|
|
* This class must only be accessed through it's base class
|
|
* SegmentPosition, it's constructed through SegmentPosition::create().
|
|
*/
|
|
|
|
|
|
/*! \class VerticalEnd
|
|
* \brief Vertical Segment manipulator (\b internal)
|
|
*
|
|
* This class must only be accessed through it's base class
|
|
* SegmentPosition, it's constructed through SegmentPosition::create().
|
|
*/
|
|
|
|
|
|
using namespace std;
|
|
using namespace Hurricane;
|
|
using namespace Katabatic;
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Local Variables.
|
|
|
|
// const char* badAutoContactAnchor =
|
|
// "AutoContact::AutoContact() :\n\n"
|
|
// " Only <RoutinPad> are supported to anchor an AutoContact :\n"
|
|
// " %s\n";
|
|
|
|
// const char* nonAdjacentLayers =
|
|
// "%s :\n\n"
|
|
// " %s and %s are not adjacent, cannot build a VIA.\n";
|
|
|
|
// const char* missingAutoLayer =
|
|
// "AutoContact::create() :\n\n"
|
|
// " DataBase is lacking \"AutoLayer\" layer, please check technology file.\n";
|
|
|
|
// const char* emptyJunctionBox =
|
|
// " Empty JunctionBox in %s (internal error).";
|
|
|
|
const char* badHookType =
|
|
"Hook of %s is neither a SourceHook nor a TargetHook (internal error).";
|
|
|
|
const char* missingAutoSegment =
|
|
"No AutoSegment associated to %s (internal error).";
|
|
|
|
|
|
// Forward Declarations.
|
|
class StackedContact;
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "::UPoint".
|
|
|
|
|
|
class UPoint {
|
|
// Constructors.
|
|
public:
|
|
inline UPoint ( bool isHorizontal, DbU::Unit ux, DbU::Unit uy );
|
|
// Accessors.
|
|
inline DbU::Unit getUX () const;
|
|
inline DbU::Unit getUY () const;
|
|
inline DbU::Unit getX () const;
|
|
inline DbU::Unit getY () const;
|
|
// Modifiers.
|
|
inline void setUX ( DbU::Unit ux );
|
|
inline void setUY ( DbU::Unit uy );
|
|
// Attributes.
|
|
protected:
|
|
bool _isHorizontal;
|
|
DbU::Unit _ux;
|
|
DbU::Unit _uy;
|
|
};
|
|
|
|
|
|
// Inline Functions.
|
|
inline UPoint::UPoint ( bool isHorizontal, DbU::Unit ux, DbU::Unit uy )
|
|
: _isHorizontal(isHorizontal), _ux(ux), _uy(uy) {}
|
|
inline DbU::Unit UPoint::getUX () const { return _ux; }
|
|
inline DbU::Unit UPoint::getUY () const { return _uy; }
|
|
inline DbU::Unit UPoint::getX () const { return (_isHorizontal)?_ux:_uy; }
|
|
inline DbU::Unit UPoint::getY () const { return (_isHorizontal)?_uy:_ux; }
|
|
inline void UPoint::setUX ( DbU::Unit ux ) { _ux = ux; }
|
|
inline void UPoint::setUY ( DbU::Unit uy ) { _uy = uy; }
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "::SegmentEnd".
|
|
|
|
|
|
class SegmentEnd {
|
|
public:
|
|
struct Compare : public binary_function<SegmentEnd*,SegmentEnd*,bool> {
|
|
inline bool operator() ( const SegmentEnd* lhs, const SegmentEnd* rhs ) const;
|
|
};
|
|
public:
|
|
// AutoSegment & Segment wrapped functions.
|
|
inline bool isGlobal () const;
|
|
inline bool isLocal () const;
|
|
inline bool isHorizontal () const;
|
|
inline bool isVertical () const;
|
|
inline bool isSlackened () const;
|
|
inline Net* getNet () const;
|
|
inline const Layer* getLayer () const;
|
|
inline Hook* getSourceHook ();
|
|
inline Hook* getTargetHook ();
|
|
inline DbU::Unit getSourceX () const;
|
|
inline DbU::Unit getSourceY () const;
|
|
inline DbU::Unit getTargetX () const;
|
|
inline DbU::Unit getTargetY () const;
|
|
inline DbU::Unit getSourceU () const;
|
|
inline DbU::Unit getTargetU () const;
|
|
inline DbU::Unit getDuSource () const;
|
|
inline DbU::Unit getDuTarget () const;
|
|
inline DbU::Unit getAxis () const;
|
|
inline DbU::Unit getWidth () const;
|
|
inline void setDuSource ( DbU::Unit );
|
|
inline void setDuTarget ( DbU::Unit );
|
|
inline void invert ();
|
|
inline void invalidate ();
|
|
// Constructors & Destructors.
|
|
inline SegmentEnd ( AutoSegment* , bool isSourceHook );
|
|
virtual ~SegmentEnd ();
|
|
static SegmentEnd* create ( Hook*, bool checking );
|
|
// Accessors.
|
|
static size_t getAllocateds ();
|
|
inline bool isSourceHook () const;
|
|
inline AutoSegment* getSegment () const;
|
|
virtual Hook* getHook () const;
|
|
inline Point getEnd () const;
|
|
inline DbU::Unit getEndX () const;
|
|
inline DbU::Unit getEndY () const;
|
|
virtual vector<SegmentEnd*>* getForks ();
|
|
virtual vector<SegmentEnd*>* getAligneds ();
|
|
// Modifiers.
|
|
void setDelta ( DbU::Unit );
|
|
virtual void orient ();
|
|
virtual void addFork ( SegmentEnd* );
|
|
virtual void addAligned ( SegmentEnd* );
|
|
virtual void split ( vector<StackedContact*>& );
|
|
// Inspector Managment.
|
|
inline Record* _getRecord () const;
|
|
inline string _getString () const;
|
|
inline string _getTypeName () const;
|
|
protected:
|
|
// Attributes.
|
|
static size_t _allocateds;
|
|
AutoSegment* _autoSegment;
|
|
bool _isSourceHook;
|
|
};
|
|
|
|
|
|
}
|
|
|
|
INSPECTOR_P_SUPPORT(SegmentEnd);
|
|
|
|
namespace {
|
|
|
|
size_t SegmentEnd::_allocateds = 0;
|
|
|
|
SegmentEnd::~SegmentEnd () { _allocateds--; }
|
|
size_t SegmentEnd::getAllocateds () { return _allocateds; }
|
|
inline bool SegmentEnd::isGlobal () const { return _autoSegment->isGlobal(); }
|
|
inline bool SegmentEnd::isLocal () const { return _autoSegment->isLocal(); }
|
|
inline bool SegmentEnd::isHorizontal () const { return _autoSegment->isHorizontal(); }
|
|
inline bool SegmentEnd::isVertical () const { return _autoSegment->isVertical(); }
|
|
inline bool SegmentEnd::isSlackened () const { return _autoSegment->isSlackened(); }
|
|
inline AutoSegment* SegmentEnd::getSegment () const { return _autoSegment; }
|
|
inline Net* SegmentEnd::getNet () const { return _autoSegment->getNet(); }
|
|
inline const Layer* SegmentEnd::getLayer () const { return _autoSegment->getLayer(); }
|
|
inline Hook* SegmentEnd::getSourceHook () { return _autoSegment->getSourceHook(); }
|
|
inline Hook* SegmentEnd::getTargetHook () { return _autoSegment->getTargetHook(); }
|
|
inline DbU::Unit SegmentEnd::getSourceX () const { return _autoSegment->getSourceX(); }
|
|
inline DbU::Unit SegmentEnd::getSourceY () const { return _autoSegment->getSourceY(); }
|
|
inline DbU::Unit SegmentEnd::getTargetX () const { return _autoSegment->getTargetX(); }
|
|
inline DbU::Unit SegmentEnd::getTargetY () const { return _autoSegment->getTargetY(); }
|
|
inline DbU::Unit SegmentEnd::getSourceU () const { return _autoSegment->getSourceU(); }
|
|
inline DbU::Unit SegmentEnd::getTargetU () const { return _autoSegment->getTargetU(); }
|
|
inline DbU::Unit SegmentEnd::getDuSource () const { return _autoSegment->getDuSource(); }
|
|
inline DbU::Unit SegmentEnd::getDuTarget () const { return _autoSegment->getDuTarget(); }
|
|
inline DbU::Unit SegmentEnd::getAxis () const { return _autoSegment->getAxis(); }
|
|
inline DbU::Unit SegmentEnd::getWidth () const { return _autoSegment->getWidth(); }
|
|
inline void SegmentEnd::setDuSource ( DbU::Unit du ) { _autoSegment->setDuSource(du); }
|
|
inline void SegmentEnd::setDuTarget ( DbU::Unit du ) { _autoSegment->setDuTarget(du); }
|
|
inline void SegmentEnd::invert () { _autoSegment->invert(); }
|
|
inline void SegmentEnd::invalidate () { _autoSegment->invalidate(); }
|
|
inline bool SegmentEnd::isSourceHook () const { return _isSourceHook; }
|
|
inline Point SegmentEnd::getEnd () const { return isSourceHook() ? Point(getSourceX(),getSourceY()) : Point(getTargetX(),getTargetY()); }
|
|
inline DbU::Unit SegmentEnd::getEndX () const { return isSourceHook() ? getSourceX() : getTargetX(); }
|
|
inline DbU::Unit SegmentEnd::getEndY () const { return isSourceHook() ? getSourceY() : getTargetY(); }
|
|
vector<SegmentEnd*>* SegmentEnd::getForks () { return NULL; }
|
|
vector<SegmentEnd*>* SegmentEnd::getAligneds () { return NULL; }
|
|
void SegmentEnd::addFork ( SegmentEnd* ) {}
|
|
void SegmentEnd::addAligned ( SegmentEnd* ) {}
|
|
void SegmentEnd::split ( vector<StackedContact*>& ) {}
|
|
inline Record* SegmentEnd::_getRecord () const { return _autoSegment->_getRecord(); }
|
|
inline string SegmentEnd::_getString () const { return _autoSegment->_getString(); }
|
|
inline string SegmentEnd::_getTypeName () const { return "Katabatic::SegmentEnd"; }
|
|
|
|
inline bool SegmentEnd::Compare::operator() ( const SegmentEnd* lhs, const SegmentEnd* rhs ) const
|
|
{ return AutoSegment::CompareCanonical() ( lhs->getSegment(), rhs->getSegment() ); }
|
|
|
|
inline SegmentEnd::SegmentEnd ( AutoSegment* segment, bool isSourceHook )
|
|
: _autoSegment(segment)
|
|
, _isSourceHook(isSourceHook)
|
|
{
|
|
_allocateds++;
|
|
}
|
|
|
|
|
|
Hook* SegmentEnd::getHook () const
|
|
{
|
|
if ( isSourceHook() ) return _autoSegment->getSourceHook();
|
|
return _autoSegment->getTargetHook();
|
|
}
|
|
|
|
|
|
void SegmentEnd::orient ()
|
|
{
|
|
if ( ( !isGlobal() ) && ( getSourceU() > getTargetU() ) ) {
|
|
ltrace(99) << "Orient() before - " << this << endl;
|
|
|
|
invert ();
|
|
DbU::Unit duSource = getDuSource();
|
|
DbU::Unit duTarget = getDuTarget();
|
|
setDuSource ( duTarget );
|
|
setDuTarget ( duSource );
|
|
_isSourceHook = !_isSourceHook;
|
|
|
|
ltrace(99) << "Orient() after - " << this << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void SegmentEnd::setDelta ( DbU::Unit delta )
|
|
{
|
|
ltrace(99) << "setDelta(" << DbU::getLambda(delta) << ") - " << this << endl;
|
|
|
|
if ( isSourceHook() ) {
|
|
if ( getDuSource() != delta ) {
|
|
setDuSource ( delta );
|
|
ltrace(99) << "DuSource actualized: " << this << endl;
|
|
}
|
|
} else {
|
|
if ( getDuTarget() != delta ) {
|
|
setDuTarget ( delta );
|
|
ltrace(99) << "DuTarget actualized: " << this << endl;
|
|
}
|
|
}
|
|
|
|
orient ();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "::ForkCompare".
|
|
|
|
|
|
class ForkCompare {
|
|
public:
|
|
inline ForkCompare ( bool increasing ) : _increasing(increasing) {};
|
|
inline bool operator() ( SegmentEnd* lhs, SegmentEnd* rhs ) const;
|
|
protected:
|
|
bool _increasing;
|
|
};
|
|
|
|
|
|
bool ForkCompare::operator() ( SegmentEnd* lhs, SegmentEnd* rhs ) const
|
|
{
|
|
bool superior = rhs->isGlobal();
|
|
|
|
if ( lhs->getAxis() == rhs->getAxis() ) {
|
|
if ( lhs->isLocal() && rhs->isLocal() )
|
|
return false;
|
|
} else
|
|
superior = lhs->getAxis() > rhs->getAxis();
|
|
|
|
return (_increasing) ? !superior : superior;
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "::StackedContact".
|
|
|
|
|
|
class StackedContact : public Contact {
|
|
|
|
public:
|
|
static StackedContact* create ( Net* , const Layer* , DbU::Unit x, DbU::Unit y );
|
|
StackedContact ( Net* , const Layer* , DbU::Unit x, DbU::Unit y );
|
|
virtual ~StackedContact ();
|
|
public:
|
|
void setAnchor ( Component* );
|
|
void addLayer ( const Layer* );
|
|
void attachSlave ( SegmentEnd* );
|
|
void breakUp ();
|
|
|
|
protected:
|
|
vector<bool> _useds;
|
|
Component* _anchor;
|
|
private:
|
|
StackedContact ( const StackedContact& );
|
|
StackedContact& operator= ( const StackedContact& );
|
|
};
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "::GlobalEnd".
|
|
|
|
|
|
class GlobalEnd : public SegmentEnd {
|
|
public:
|
|
GlobalEnd ( AutoSegment* , bool isSourceHook );
|
|
virtual ~GlobalEnd ();
|
|
virtual vector<SegmentEnd*>* getForks ();
|
|
virtual vector<SegmentEnd*>* getAligneds ();
|
|
virtual void split ( vector<StackedContact*>& );
|
|
virtual void addFork ( SegmentEnd* );
|
|
virtual void addAligned ( SegmentEnd* );
|
|
virtual Segment* _create ( Contact* source, Contact* target ) = 0;
|
|
protected:
|
|
vector<SegmentEnd*> _forks;
|
|
vector<SegmentEnd*> _aligneds;
|
|
};
|
|
|
|
|
|
GlobalEnd::GlobalEnd ( AutoSegment* segment, bool isSourceHook )
|
|
: SegmentEnd(segment,isSourceHook)
|
|
, _forks()
|
|
, _aligneds()
|
|
{}
|
|
|
|
|
|
GlobalEnd::~GlobalEnd ()
|
|
{}
|
|
|
|
|
|
vector<SegmentEnd*>* GlobalEnd::getForks ()
|
|
{
|
|
return &_forks;
|
|
}
|
|
|
|
|
|
vector<SegmentEnd*>* GlobalEnd::getAligneds ()
|
|
{
|
|
return &_aligneds;
|
|
}
|
|
|
|
|
|
void GlobalEnd::addFork ( SegmentEnd* segmentEnd )
|
|
{
|
|
for ( size_t i = 0 ; i < _forks.size() ; i++ ) {
|
|
if ( _forks[i] == segmentEnd ) return;
|
|
}
|
|
_forks.push_back ( segmentEnd );
|
|
}
|
|
|
|
|
|
void GlobalEnd::addAligned ( SegmentEnd* segmentEnd )
|
|
{
|
|
for ( size_t i = 0 ; i < _aligneds.size() ; i++ ) {
|
|
if ( _aligneds[i] == segmentEnd ) return;
|
|
}
|
|
_aligneds.push_back ( segmentEnd );
|
|
}
|
|
|
|
|
|
void GlobalEnd::split ( vector<StackedContact*>& stackedContacts )
|
|
{
|
|
ltrace(99) << "GlobalEnd::split() - " << this << endl;
|
|
ltracein(99);
|
|
|
|
sort ( _forks.begin(), _forks.end(), ForkCompare(!isSourceHook()) );
|
|
|
|
StackedContact* contact1 = NULL;
|
|
StackedContact* contact2 = NULL;
|
|
const Layer* contactLayer = NULL;
|
|
Hook* hook = getHook();
|
|
vector<SegmentEnd*>::iterator it = _forks.begin();
|
|
|
|
if ( it == _forks.end() ) {
|
|
ltrace(99) << "No forks!" << endl;
|
|
stackedContacts.push_back ( StackedContact::create ( getNet()
|
|
, getLayer()
|
|
, getEndX()
|
|
, getEndY()
|
|
) );
|
|
stackedContacts.back()->attachSlave ( this );
|
|
|
|
ltraceout(99);
|
|
return;
|
|
}
|
|
|
|
ltrace(99) << "splitted Axis " << DbU::getLambda(getAxis()) << endl;
|
|
ltrace(99) << "iterator Axis " << DbU::getLambda((*it)->getAxis()) << " " << (*it) << endl;
|
|
|
|
UPoint center ( isHorizontal(), (*it)->getAxis(), getAxis() );
|
|
contactLayer = Session::getTechnology()->getViaBetween ( getLayer(), (*it)->getLayer() );
|
|
stackedContacts.push_back
|
|
( StackedContact::create ( getNet(), contactLayer, center.getX(), center.getY() ) );
|
|
contact1 = stackedContacts.back ();
|
|
contact1->attachSlave ( *it );
|
|
|
|
hook->detach ();
|
|
hook->attach ( contact1->getBodyHook() );
|
|
setDelta ( 0 );
|
|
|
|
for ( it++ ; it != _forks.end() ; it++ ) {
|
|
ltrace(99) << "splitted Axis " << DbU::getLambda(getAxis()) << endl;
|
|
ltrace(99) << "iterator Axis " << DbU::getLambda((*it)->getAxis()) << " " << (*it) << endl;
|
|
|
|
if ( (*(it-1))->getAxis() != (*it)->getAxis() ) {
|
|
UPoint center ( isHorizontal(), (*it)->getAxis(), getAxis() );
|
|
contactLayer = Session::getTechnology()->getViaBetween ( getLayer(), (*it)->getLayer() );
|
|
stackedContacts.push_back
|
|
( StackedContact::create ( getNet(), contactLayer, center.getX(), center.getY() ) );
|
|
contact2 = stackedContacts.back ();
|
|
} else {
|
|
contact2 = contact1;
|
|
}
|
|
|
|
if ( contact1 != contact2 ) {
|
|
if ( !isSourceHook() ) _create ( contact1, contact2 );
|
|
else _create ( contact2, contact1 );
|
|
}
|
|
|
|
contact2->attachSlave ( *it );
|
|
contact1 = contact2;
|
|
}
|
|
|
|
for ( it = _aligneds.begin() ; it != _aligneds.end() ; it++ ) {
|
|
if ( isSourceHook() == (*it)->isSourceHook() ) {
|
|
stackedContacts.front()->attachSlave ( *it );
|
|
} else {
|
|
stackedContacts.back()->attachSlave ( *it );
|
|
}
|
|
}
|
|
|
|
ltraceout(99);
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "::HorizontalEnd".
|
|
|
|
|
|
class HorizontalEnd : public GlobalEnd {
|
|
public:
|
|
HorizontalEnd ( AutoSegment* , bool isSourceHook );
|
|
virtual ~HorizontalEnd ();
|
|
virtual Segment* _create ( Contact* source , Contact* target );
|
|
};
|
|
|
|
|
|
HorizontalEnd::HorizontalEnd ( AutoSegment* horizontal, bool isSourceHook )
|
|
: GlobalEnd(horizontal,isSourceHook)
|
|
{ }
|
|
|
|
|
|
HorizontalEnd::~HorizontalEnd ()
|
|
{ }
|
|
|
|
|
|
Segment* HorizontalEnd::_create ( Contact* source , Contact* target )
|
|
{
|
|
return Horizontal::create ( source, target, getLayer(), getAxis(), getWidth() );
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "::VerticalEnd".
|
|
|
|
|
|
class VerticalEnd : public GlobalEnd {
|
|
public:
|
|
VerticalEnd ( AutoSegment* , bool isSourceHook );
|
|
virtual ~VerticalEnd ();
|
|
virtual Segment* _create ( Contact* source , Contact* target );
|
|
};
|
|
|
|
|
|
VerticalEnd::VerticalEnd ( AutoSegment* vertical, bool isSourceHook )
|
|
: GlobalEnd(vertical,isSourceHook)
|
|
{ }
|
|
|
|
|
|
VerticalEnd::~VerticalEnd ()
|
|
{ }
|
|
|
|
|
|
Segment* VerticalEnd::_create ( Contact* source , Contact* target )
|
|
{
|
|
return Vertical::create ( source, target, getLayer(), getAxis(), getWidth() );
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Static Generic Constructor for all SegmentEnd.
|
|
|
|
|
|
SegmentEnd* SegmentEnd::create ( Hook* hook, bool checking )
|
|
{
|
|
bool isSourceHook = (dynamic_cast<Segment::SourceHook*>(hook));
|
|
if ( !isSourceHook && ( dynamic_cast<Segment::TargetHook*>(hook) == NULL ) ) {
|
|
cerr << Error ( badHookType, getString(hook->getComponent()).c_str() ) << endl;
|
|
return NULL;
|
|
}
|
|
|
|
AutoSegment* autoSegment = Session::lookup ( dynamic_cast<Segment*>(hook->getComponent()) );
|
|
|
|
if ( !autoSegment )
|
|
throw Error ( missingAutoSegment, getString(hook->getComponent()).c_str() );
|
|
|
|
if ( !checking )
|
|
autoSegment->invalidate ();
|
|
|
|
if ( autoSegment->isGlobal() ) {
|
|
if ( autoSegment->isHorizontal() )
|
|
return new HorizontalEnd ( autoSegment, isSourceHook );
|
|
else
|
|
return new VerticalEnd ( autoSegment, isSourceHook );
|
|
} else {
|
|
if ( autoSegment->isHorizontal() )
|
|
return new SegmentEnd ( autoSegment, isSourceHook );
|
|
}
|
|
return new SegmentEnd ( autoSegment, isSourceHook );
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "::JunctionBox".
|
|
|
|
|
|
class JunctionBox {
|
|
|
|
public:
|
|
// Constructor & Destructor.
|
|
JunctionBox ( AutoContact*, bool checking );
|
|
~JunctionBox ();
|
|
// Predicates.
|
|
inline bool isVFlat ();
|
|
inline bool isHFlat ();
|
|
inline bool isFlat ();
|
|
inline bool isPunctual ();
|
|
inline bool isVEmpty ();
|
|
inline bool isHEmpty ();
|
|
inline bool isEmpty ();
|
|
bool isHExtended ();
|
|
bool isVExtended ();
|
|
bool canGoOutside ( const AutoSegment* ) const;
|
|
bool canHDesalignate () const;
|
|
bool canVDesalignate () const;
|
|
void getZSpan ( size_t& zMin, size_t& zMax ) const;
|
|
// Modifiers.
|
|
void checkTopology ();
|
|
void revalidateTopology ();
|
|
void computeGlobalStem ();
|
|
void computeAlignate ();
|
|
void mergeX ( DbU::Unit );
|
|
void mergeY ( DbU::Unit );
|
|
void mergeAnchor ();
|
|
void merge ( Hook* );
|
|
void postMerge ( SegmentEnd* );
|
|
void resizePunctual ();
|
|
void resize ();
|
|
void breakUpPunctual ();
|
|
void breakUp ();
|
|
void split ();
|
|
void splitTerminal ();
|
|
void updateContacts ( VirtualContacts& );
|
|
void restoreHConnexity ( DbU::Unit x, bool split );
|
|
void restoreVConnexity ( DbU::Unit y, bool split );
|
|
|
|
protected:
|
|
// Attributes.
|
|
RoutingGauge* _routingGauge;
|
|
AutoContact* _contact;
|
|
Component* _anchor;
|
|
DbU::Unit _xMin;
|
|
DbU::Unit _yMin;
|
|
DbU::Unit _xMax;
|
|
DbU::Unit _yMax;
|
|
SegmentEnd* _globalStem;
|
|
vector<SegmentEnd*> _globalEnds;
|
|
vector<SegmentEnd*> _localEnds;
|
|
vector<size_t> _layerStack;
|
|
size_t _wireCount;
|
|
bool _failsafe;
|
|
bool _checking;
|
|
};
|
|
|
|
|
|
inline bool JunctionBox::isVFlat () { return _yMin == _yMax; }
|
|
inline bool JunctionBox::isHFlat () { return _xMin == _xMax; }
|
|
inline bool JunctionBox::isFlat () { return isHFlat() || isVFlat(); }
|
|
inline bool JunctionBox::isPunctual () { return isHFlat() && isVFlat(); }
|
|
inline bool JunctionBox::isVEmpty () { return _yMin > _yMax; }
|
|
inline bool JunctionBox::isHEmpty () { return _xMin > _xMax; }
|
|
inline bool JunctionBox::isEmpty () { return isHEmpty() || isVEmpty(); }
|
|
|
|
|
|
JunctionBox::JunctionBox ( AutoContact* contact, bool checking )
|
|
: _routingGauge(Session::getRoutingGauge())
|
|
, _contact (contact)
|
|
, _anchor (NULL)
|
|
, _xMin (+1)
|
|
, _yMin (+1)
|
|
, _xMax (-1)
|
|
, _yMax (-1)
|
|
, _globalStem (NULL)
|
|
, _globalEnds ()
|
|
, _localEnds ()
|
|
, _layerStack (Session::getRoutingGauge()->getDepth())
|
|
, _wireCount (0)
|
|
, _failsafe (false)
|
|
, _checking (checking)
|
|
{
|
|
ltrace(110) << "JunctionBox() " << contact << endl;
|
|
ltracein(109);
|
|
|
|
forEach ( Hook*, hook, _contact->getBodyHook()->getSlaveHooks() ) merge ( *hook );
|
|
mergeAnchor ();
|
|
|
|
sort ( _globalEnds.begin(), _globalEnds.end(), SegmentEnd::Compare() );
|
|
sort ( _localEnds.begin() , _localEnds.end() , SegmentEnd::Compare() );
|
|
|
|
if ( ( _wireCount < 1 ) && !_contact->getAnchor() )
|
|
cerr << Warning("%s has less than 2 wires (%d)"
|
|
,getString(_contact).c_str(),_wireCount) << endl;
|
|
|
|
computeGlobalStem ();
|
|
if ( _globalStem ) {
|
|
ltrace(109) << "_globalStem: " << _globalStem << endl;
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ )
|
|
postMerge ( _localEnds[i] );
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ )
|
|
postMerge ( _globalEnds[i] );
|
|
|
|
ltraceout(109);
|
|
return;
|
|
}
|
|
|
|
if ( isPunctual() || (isFlat() && !_contact->getAnchor()) ) {
|
|
ltraceout(109);
|
|
return;
|
|
}
|
|
|
|
// JunctionBox is empty, non-flat or flat with anchor.
|
|
_failsafe = true;
|
|
ltraceout(109);
|
|
}
|
|
|
|
|
|
JunctionBox::~JunctionBox ()
|
|
{
|
|
for ( size_t i = 0 ; i < _globalEnds.size() ; i++ ) delete _globalEnds[i];
|
|
for ( size_t i = 0 ; i < _localEnds.size() ; i++ ) delete _localEnds[i];
|
|
}
|
|
|
|
|
|
bool JunctionBox::isHExtended ()
|
|
{
|
|
if ( _globalStem ) {
|
|
ltrace(109) << "JunctionBox::isHExtended(): " << _globalStem->isHorizontal() << endl;
|
|
return _globalStem->isHorizontal();
|
|
}
|
|
return _contact->isHAlignate();
|
|
}
|
|
|
|
|
|
bool JunctionBox::isVExtended ()
|
|
{
|
|
if ( _globalStem ) {
|
|
ltrace(109) << "JunctionBox::isVExtended(): " << _globalStem->isVertical() << endl;
|
|
return _globalStem->isVertical();
|
|
}
|
|
return _contact->isVAlignate();
|
|
}
|
|
|
|
|
|
void JunctionBox::getZSpan ( size_t& zMin, size_t& zMax ) const
|
|
{
|
|
bool minFound = false;
|
|
|
|
zMin = 0;
|
|
zMax = 0;
|
|
for ( size_t i=0 ; i<_layerStack.size() ; i++ ) {
|
|
if ( !minFound ) {
|
|
if ( _layerStack[i] > 0 ) {
|
|
zMin = zMax = i;
|
|
minFound = true;
|
|
}
|
|
} else {
|
|
if ( _layerStack[i] > 0 ) {
|
|
zMax = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void JunctionBox::revalidateTopology ()
|
|
{
|
|
_contact->setInvalidatedTopology ( false );
|
|
_contact->setCorner ( false );
|
|
if ( !_contact->getAnchor() ) {
|
|
size_t horizontals = 0;
|
|
size_t verticals = 0;
|
|
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
|
|
if ( _globalEnds[i]->isHorizontal() ) horizontals++;
|
|
else verticals++;
|
|
}
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
|
|
if ( _localEnds[i]->isHorizontal() ) horizontals++;
|
|
else verticals++;
|
|
}
|
|
_contact->setCorner ( (horizontals == 1)
|
|
and (verticals == 1)
|
|
and (not _contact->isHAlignate())
|
|
and (not _contact->isVAlignate()) );
|
|
}
|
|
|
|
checkTopology ();
|
|
}
|
|
|
|
|
|
void JunctionBox::checkTopology ()
|
|
{
|
|
vector<string> errors;
|
|
|
|
bool anchored = (_contact->getAnchor());
|
|
bool alignateHorizontal = _contact->isHAlignate() || anchored;
|
|
bool alignateVertical = _contact->isVAlignate() || anchored;
|
|
bool globalHorizontal = false;
|
|
bool globalVertical = false;
|
|
size_t localHorizontals = 0;
|
|
size_t localVerticals = 0;
|
|
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
|
|
if ( _globalEnds[i]->isHorizontal() ) {
|
|
globalHorizontal = true;
|
|
localHorizontals++;
|
|
} else {
|
|
globalVertical = true;
|
|
localVerticals++;
|
|
}
|
|
}
|
|
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
|
|
if ( _localEnds[i]->isHorizontal() ) localHorizontals++;
|
|
else localVerticals++;
|
|
}
|
|
|
|
if ( !(localHorizontals || globalHorizontal || anchored) )
|
|
errors.push_back ( "No horizontal components" );
|
|
|
|
if ( !(localVerticals || globalVertical || anchored) )
|
|
errors.push_back ( "No vertical components" );
|
|
|
|
if ( !alignateHorizontal && !globalVertical && (localHorizontals > 1) )
|
|
errors.push_back ( "Disconnecteds horizontals components" );
|
|
|
|
if ( !alignateVertical && !globalHorizontal && (localVerticals > 1) )
|
|
errors.push_back ( "Disconnecteds verticals components" );
|
|
|
|
if ( _globalEnds.size() > 3 )
|
|
errors.push_back ( "More than three globals" );
|
|
|
|
if ( ( _globalEnds.size() == 3 ) && ( _localEnds.size() ) )
|
|
errors.push_back ( "Three globals AND locals" );
|
|
|
|
if ( _globalEnds.size() + _localEnds.size() + ((anchored)?1:0) < 2 )
|
|
errors.push_back ( "Less than two connections" );
|
|
|
|
if ( errors.size() ) {
|
|
cerr << Error("AutoContact topology of %s",getString(_contact).c_str()) << endl;
|
|
if ( anchored )
|
|
cerr << " A: " << _contact->getAnchor() << endl;
|
|
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ )
|
|
cerr << " G: " << _globalEnds[i] << endl;
|
|
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ )
|
|
cerr << " L: " << _localEnds[i] << endl;
|
|
|
|
for ( size_t i=0 ; i < errors.size() ; i++ )
|
|
cerr << " " << errors[i] << endl;
|
|
}
|
|
}
|
|
|
|
|
|
bool JunctionBox::canGoOutside ( const AutoSegment* segment ) const
|
|
{
|
|
if ( _contact->isCorner () ) return true;
|
|
if ( _contact->getAnchor() ) return false;
|
|
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
|
|
if ( _globalEnds[i]->isHorizontal() xor segment->isHorizontal() ) {
|
|
ltrace(200) << "canGoOutside(): true (has global) " << _contact << endl;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool JunctionBox::canHDesalignate () const
|
|
{
|
|
if ( _contact->getAnchor () ) return false;
|
|
if ( !_contact->isHAlignate() ) return false;
|
|
|
|
SegmentEnd* globalHorizontal = NULL;
|
|
SegmentEnd* globalVertical = NULL;
|
|
|
|
size_t verticals = 0;
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
|
|
ltrace(109) << _globalEnds[i]->getSegment() << endl;
|
|
if ( _globalEnds[i]->isHorizontal() ) {
|
|
globalHorizontal = _globalEnds[i];
|
|
} else {
|
|
globalVertical = _globalEnds[i];
|
|
verticals++;
|
|
}
|
|
}
|
|
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
|
|
ltrace(109) << _localEnds[i]->getSegment() << endl;
|
|
if ( _localEnds[i]->isVertical() ) verticals++;
|
|
}
|
|
|
|
ltrace(200) << "canHDesalignate(Contact*) - " << _contact << endl;
|
|
ltrace(200) << " Vertical stem: " << globalVertical
|
|
<< " isVAlignate():" << _contact->isVAlignate()
|
|
<< " verticals:" << verticals
|
|
<< endl;
|
|
return (globalVertical != NULL) && (_contact->isVAlignate() || (verticals == 1));
|
|
}
|
|
|
|
|
|
bool JunctionBox::canVDesalignate () const
|
|
{
|
|
if ( _contact->getAnchor () ) return false;
|
|
if ( !_contact->isVAlignate() ) return false;
|
|
|
|
SegmentEnd* globalHorizontal = NULL;
|
|
SegmentEnd* globalVertical = NULL;
|
|
|
|
size_t horizontals = 0;
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
|
|
if ( _globalEnds[i]->isHorizontal() ) {
|
|
globalHorizontal = _globalEnds[i];
|
|
horizontals++;
|
|
} else {
|
|
globalVertical = _globalEnds[i];
|
|
}
|
|
}
|
|
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
|
|
ltrace(109) << _localEnds[i]->getSegment() << endl;
|
|
if ( _localEnds[i]->isHorizontal() ) horizontals++;
|
|
}
|
|
|
|
ltrace(200) << "canVDesalignate(Contact*) - " << _contact << endl;
|
|
ltrace(200) << " Vertical stem: " << globalHorizontal
|
|
<< " isHAlignate():" << _contact->isHAlignate()
|
|
<< " horizontals:" << horizontals
|
|
<< endl;
|
|
return (globalHorizontal != NULL) && (_contact->isHAlignate() || (horizontals == 1));
|
|
}
|
|
|
|
|
|
void JunctionBox::restoreHConnexity ( DbU::Unit x, bool split )
|
|
{
|
|
ltrace(200) << "restoreHConnexity() - @" << DbU::getValueString(x) << " " << _contact << endl;
|
|
|
|
_contact->invalidate ();
|
|
|
|
if ( _contact->isHAlignate() ) return;
|
|
if ( _contact->getAnchor () ) {
|
|
_contact->setHAlignate ( true );
|
|
return;
|
|
}
|
|
|
|
bool slackened = false;
|
|
SegmentEnd* verticalStem = NULL;
|
|
vector<SegmentEnd*> horizontals;
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
|
|
if ( _globalEnds[i]->isHorizontal() ) {
|
|
horizontals.push_back ( _globalEnds[i] ) ;
|
|
} else {
|
|
verticalStem = _globalEnds[i];
|
|
}
|
|
}
|
|
|
|
if ( verticalStem ) {
|
|
ltrace(200) << "Done nothing has vertical stem: " << verticalStem << endl;
|
|
return;
|
|
}
|
|
|
|
for ( size_t i=0 ; i<_localEnds.size() ; i++ ) {
|
|
if ( _localEnds[i]->isHorizontal() )
|
|
horizontals.push_back ( _localEnds[i] ) ;
|
|
else
|
|
slackened = slackened or _localEnds[i]->isSlackened();
|
|
}
|
|
|
|
if ( (horizontals.size() == 1) and (horizontals[0]->isGlobal()) ) {
|
|
ltrace(200) << "Done nothing, has only a horizontal stem: " << horizontals[0] << endl;
|
|
return;
|
|
}
|
|
|
|
if ( !split ) {
|
|
_contact->setHAlignate ( true );
|
|
return;
|
|
}
|
|
|
|
GCell* gcell = _contact->getGCell ();
|
|
Net* net = _contact->getNet ();
|
|
const Layer* layer = dynamic_cast<const ViaLayer*>(_contact->getLayer())->getTop();
|
|
if ( _routingGauge->getLayerDirection(layer) != Constant::Vertical )
|
|
layer = dynamic_cast<const ViaLayer*>(_contact->getLayer())->getBottom();
|
|
|
|
_contact->setVAlignate ( true );
|
|
AutoContact* splitContact = NULL;
|
|
for ( size_t i=1 ; i<horizontals.size() ; i++ ) {
|
|
if ( splitContact ) splitContact->setVAlignate ( true );
|
|
|
|
ltrace(200) << "| Separate " << horizontals[i]->getSegment()->base()
|
|
<< ":" << horizontals[i]->getSegment() << endl;
|
|
|
|
horizontals[i]->getHook()->detach();
|
|
|
|
splitContact = AutoContact::create ( gcell, net, _contact->getLayer() );
|
|
AutoSegment* segment = AutoVertical::create ( _contact
|
|
, splitContact
|
|
, layer
|
|
, x //globalHorizontals[i]->getAxis()
|
|
, DbU::lambda(2.0)
|
|
, AutoSegment::Local
|
|
, false
|
|
, false
|
|
);
|
|
horizontals[i]->getHook()->attach ( splitContact->getContact()->getBodyHook() );
|
|
segment->setSlackened ( slackened );
|
|
ltrace(200) << "restoreHConnexity() strap: " << segment << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void JunctionBox::restoreVConnexity ( DbU::Unit y, bool split )
|
|
{
|
|
ltrace(200) << "restoreVConnexity() - @" << DbU::getValueString(y) << " " << _contact << endl;
|
|
|
|
_contact->invalidate ();
|
|
|
|
if ( _contact->isVAlignate() ) return;
|
|
if ( _contact->getAnchor () ) {
|
|
_contact->setVAlignate ( true );
|
|
return;
|
|
}
|
|
|
|
bool slackened = false;
|
|
SegmentEnd* horizontalStem = NULL;
|
|
vector<SegmentEnd*> verticals;
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
|
|
if ( _globalEnds[i]->isVertical() ) {
|
|
verticals.push_back ( _globalEnds[i] ) ;
|
|
} else {
|
|
horizontalStem = _globalEnds[i];
|
|
}
|
|
}
|
|
|
|
if ( horizontalStem ) {
|
|
ltrace(200) << "Done nothing, has horizontal stem: " << horizontalStem << endl;
|
|
return;
|
|
}
|
|
|
|
for ( size_t i=0 ; i<_localEnds.size() ; i++ ) {
|
|
if ( _localEnds[i]->isVertical() )
|
|
verticals.push_back ( _localEnds[i] ) ;
|
|
else
|
|
slackened = slackened or _localEnds[i]->isSlackened();
|
|
}
|
|
|
|
if ( (verticals.size() == 1) and (verticals[0]->isGlobal()) ) {
|
|
ltrace(200) << "Done nothing, has only a vertical stem: " << verticals[0] << endl;
|
|
return;
|
|
}
|
|
|
|
if ( !split ) {
|
|
_contact->setVAlignate ( true );
|
|
return;
|
|
}
|
|
|
|
GCell* gcell = _contact->getGCell ();
|
|
Net* net = _contact->getNet ();
|
|
const Layer* layer = dynamic_cast<const ViaLayer*>(_contact->getLayer())->getBottom();
|
|
if ( _routingGauge->getLayerDirection(layer) != Constant::Horizontal )
|
|
layer = dynamic_cast<const ViaLayer*>(_contact->getLayer())->getTop();
|
|
|
|
_contact->setHAlignate ( true );
|
|
AutoContact* splitContact = NULL;
|
|
for ( size_t i=1 ; i<verticals.size() ; i++ ) {
|
|
if ( splitContact ) splitContact->setHAlignate ( true );
|
|
|
|
ltrace(200) << "| Separate " << verticals[i]->getSegment()->base()
|
|
<< ":" << verticals[i]->getSegment() << endl;
|
|
|
|
verticals[i]->getHook()->detach();
|
|
|
|
splitContact = AutoContact::create ( gcell, net, _contact->getLayer() );
|
|
AutoSegment* segment = AutoHorizontal::create ( _contact
|
|
, splitContact
|
|
, layer
|
|
, y //globalVerticals[i]->getAxis()
|
|
, DbU::lambda(2.0)
|
|
, AutoSegment::Local
|
|
, false
|
|
, false
|
|
);
|
|
verticals[i]->getHook()->attach ( splitContact->getContact()->getBodyHook() );
|
|
segment->setSlackened ( slackened );
|
|
ltrace(200) << "restoreVConnexity() strap: " << segment << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void JunctionBox::computeAlignate ()
|
|
{
|
|
|
|
bool globalHorizontal = false;
|
|
bool globalVertical = false;
|
|
size_t horizontals = 0;
|
|
size_t verticals = 0;
|
|
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
|
|
if ( _globalEnds[i]->isHorizontal() ) {
|
|
globalHorizontal = true;
|
|
horizontals++;
|
|
} else {
|
|
globalVertical = true;
|
|
verticals++;
|
|
}
|
|
}
|
|
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
|
|
if ( _localEnds[i]->isHorizontal() ) horizontals++;
|
|
else verticals++;
|
|
}
|
|
|
|
if ( !globalVertical && (horizontals > 1) )
|
|
_contact->setHAlignate ( true );
|
|
|
|
if ( !globalHorizontal && (verticals > 1) )
|
|
_contact->setVAlignate ( true );
|
|
|
|
ltrace(109) << "computeAlignate(): [AFTER] " << _contact << endl;
|
|
}
|
|
|
|
|
|
void JunctionBox::computeGlobalStem ()
|
|
{
|
|
SegmentEnd* globalHorizontal = NULL;
|
|
SegmentEnd* globalVertical = NULL;
|
|
size_t horizontals = 0;
|
|
size_t verticals = 0;
|
|
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
|
|
if ( _globalEnds[i]->isHorizontal() ) {
|
|
globalHorizontal = _globalEnds[i];
|
|
horizontals++;
|
|
} else {
|
|
globalVertical = _globalEnds[i];
|
|
verticals++;
|
|
}
|
|
}
|
|
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
|
|
if ( _localEnds[i]->isHorizontal() ) horizontals++;
|
|
else verticals++;
|
|
}
|
|
|
|
ltrace(109) << "computeGlobalStem(): " << _contact << endl;
|
|
ltrace(109) << "| h:" << horizontals << " v:" << verticals << endl;
|
|
|
|
if ( globalVertical && (horizontals > 1) && !_contact->isHAlignate() ) {
|
|
ltrace(109) << "| Vertical GlobalStem h:" << horizontals << " v:" << verticals << endl;
|
|
_globalStem = globalVertical;
|
|
}
|
|
|
|
if ( globalHorizontal && (verticals > 1) && !_contact->isVAlignate() ) {
|
|
ltrace(109) << "| Horizontal GlobalStem h:" << horizontals << " v:" << verticals << endl;
|
|
_globalStem = globalHorizontal;
|
|
}
|
|
|
|
|
|
if ( (horizontals > 1) && (verticals > 1) && !_contact->isVAlignate() && !_contact->isHAlignate() ) {
|
|
ltrace(109) << "* Bad AutoContact: " << _contact << endl;
|
|
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ )
|
|
ltrace(109) << "| G: " << _globalEnds[i] << endl;
|
|
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ )
|
|
ltrace(109) << "| L: " << _localEnds[i] << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void JunctionBox::mergeX ( DbU::Unit x )
|
|
{
|
|
if ( _xMin > _xMax ) { _xMin = _xMax = x; return; }
|
|
if ( x < _xMin ) { _xMin = x; return; }
|
|
if ( x > _xMax ) { _xMax = x; return; }
|
|
}
|
|
|
|
|
|
void JunctionBox::mergeY ( DbU::Unit y )
|
|
{
|
|
if ( _yMin > _yMax ) { _yMin = _yMax = y; return; }
|
|
if ( y < _yMin ) { _yMin = y; return; }
|
|
if ( y > _yMax ) { _yMax = y; return; }
|
|
}
|
|
|
|
|
|
void JunctionBox::mergeAnchor ()
|
|
{
|
|
_anchor = _contact->getAnchor ();
|
|
if ( !_anchor ) return;
|
|
|
|
RoutingPad* rp = dynamic_cast<RoutingPad*>(_anchor);
|
|
if ( !rp ) {
|
|
_failsafe = true;
|
|
return;
|
|
}
|
|
|
|
_layerStack [ _routingGauge->getLayerDepth(_anchor->getLayer()) ] ++;
|
|
_wireCount++;
|
|
|
|
Point source = rp->getSourcePosition ();
|
|
Point target = rp->getTargetPosition ();
|
|
if ( ( source.getX() == target.getX() ) || isHEmpty() ) {
|
|
ltrace(109) << "merge() Axis "
|
|
<< DbU::getLambda(source.getX()) << " [RoutingPad] "
|
|
<< rp->getLayer() << endl;
|
|
mergeX ( source.getX() );
|
|
}
|
|
if ( ( source.getY() == target.getY() ) || isVEmpty() ) {
|
|
ltrace(109) << "merge() Axis "
|
|
<< DbU::getLambda(source.getY()) << " [RoutingPad] "
|
|
<< rp->getLayer() << endl;
|
|
mergeY ( source.getY() );
|
|
}
|
|
}
|
|
|
|
|
|
void JunctionBox::merge ( Hook* hook )
|
|
{
|
|
SegmentEnd* segmentEnd = SegmentEnd::create ( hook, _checking );
|
|
if ( !segmentEnd ) return;
|
|
|
|
_layerStack [ _routingGauge->getLayerDepth(segmentEnd->getLayer()) ] ++;
|
|
_wireCount++;
|
|
|
|
if ( segmentEnd->isGlobal() ) {
|
|
ltrace(109) << "merge() Axis "
|
|
<< DbU::getLambda(segmentEnd->getAxis())
|
|
<< " [global] " << segmentEnd << endl;
|
|
_globalEnds.push_back ( segmentEnd );
|
|
} else {
|
|
ltrace(109) << "merge() Axis " << DbU::getLambda(segmentEnd->getAxis())
|
|
<< " [local] " << segmentEnd << endl;
|
|
_localEnds.push_back ( segmentEnd );
|
|
}
|
|
|
|
if ( segmentEnd->isHorizontal() ) mergeY ( segmentEnd->getAxis() );
|
|
else mergeX ( segmentEnd->getAxis() );
|
|
}
|
|
|
|
|
|
void JunctionBox::postMerge ( SegmentEnd* segmentEnd )
|
|
{
|
|
if ( segmentEnd == _globalStem ) return;
|
|
|
|
if ( _globalStem->isHorizontal() xor segmentEnd->isHorizontal() )
|
|
_globalStem->addFork ( segmentEnd );
|
|
else
|
|
_globalStem->addAligned ( segmentEnd );
|
|
}
|
|
|
|
|
|
void JunctionBox::resizePunctual ()
|
|
{
|
|
Point center;
|
|
DbU::Unit delta;
|
|
|
|
if ( isEmpty() ) center = _contact->getCenter();
|
|
else if ( isPunctual() ) {
|
|
center.setX ( _xMin );
|
|
center.setY ( _yMin );
|
|
} else {
|
|
center.setX ( (_xMin+_xMax)/2 );
|
|
center.setY ( (_yMin+_yMax)/2 );
|
|
}
|
|
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
|
|
if ( _globalEnds[i]->isHorizontal() )
|
|
delta = center.getX() - _contact->getX();
|
|
else
|
|
delta = center.getY() - _contact->getY();
|
|
_globalEnds[i]->setDelta ( delta );
|
|
}
|
|
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
|
|
if ( _localEnds[i]->isHorizontal() )
|
|
delta = center.getX() - _contact->getX();
|
|
else
|
|
delta = center.getY() - _contact->getY();
|
|
|
|
_localEnds[i]->setDelta ( delta );
|
|
}
|
|
|
|
Box constraint = _contact->getConstraintBox()/*.inflate(DbU::lambda(0.5))*/;
|
|
if ( !constraint.contains(center) )
|
|
cerr << Bug("%s [%s %s] outside constraint %s."
|
|
,getString(_contact).c_str()
|
|
,DbU::getValueString(center.getX()).c_str()
|
|
,DbU::getValueString(center.getY()).c_str()
|
|
,getString(constraint).c_str()) << endl;
|
|
}
|
|
|
|
|
|
void JunctionBox::resize ()
|
|
{
|
|
ltrace(99) << "JunctionBox::resize() - <Box "
|
|
<< DbU::getLambda(_xMin) << " " << DbU::getLambda(_yMin) << " "
|
|
<< DbU::getLambda(_xMax) << " " << DbU::getLambda(_yMax)
|
|
<< ">" << endl;
|
|
|
|
if ( !_wireCount ) {
|
|
cerr << Warning("Standalone %s skipped.",getString(_contact).c_str()) << endl;
|
|
return;
|
|
}
|
|
|
|
if ( _failsafe || isPunctual() || !_globalStem )
|
|
resizePunctual ();
|
|
else {
|
|
// Flat geometry.
|
|
DbU::Unit deltaMin;
|
|
DbU::Unit deltaMax;
|
|
DbU::Unit deltaFork;
|
|
|
|
if ( _globalStem->isHorizontal() ) {
|
|
deltaMin = _xMin - _contact->getX();
|
|
deltaMax = _xMax - _contact->getX();
|
|
deltaFork = _yMin - _contact->getY();
|
|
} else {
|
|
deltaMin = _yMin - _contact->getY();
|
|
deltaMax = _yMax - _contact->getY();
|
|
deltaFork = _xMin - _contact->getX();
|
|
}
|
|
|
|
_globalStem->setDelta ( _globalStem->isSourceHook() ? deltaMin : deltaMax );
|
|
|
|
vector<SegmentEnd*>* forks = _globalStem->getForks();
|
|
vector<SegmentEnd*>* aligneds = _globalStem->getAligneds();
|
|
|
|
for ( size_t i=0 ; i < aligneds->size() ; i++ )
|
|
(*aligneds)[i]->setDelta ( (*aligneds)[i]->isSourceHook() ? deltaMax : deltaMin );
|
|
|
|
for ( size_t i=0 ; i < forks->size() ; i++ )
|
|
(*forks)[i]->setDelta ( deltaFork );
|
|
}
|
|
}
|
|
|
|
|
|
void JunctionBox::split ()
|
|
{
|
|
ltrace(200) << "JunctionBox::split() - " << _contact << endl;
|
|
|
|
size_t zMin, zMax;
|
|
size_t anchorDepth = 0;
|
|
getZSpan ( zMin, zMax );
|
|
|
|
if ( _anchor ) {
|
|
ltrace(200) << "Anchor: " << _anchor << endl;
|
|
|
|
anchorDepth = _routingGauge->getLayerDepth(_anchor->getLayer());
|
|
if ( anchorDepth == 0 ) {
|
|
if ( zMax-zMin < 2 ) return;
|
|
splitTerminal ();
|
|
_contact->split ();
|
|
return;
|
|
}
|
|
}
|
|
|
|
ltracein(200);
|
|
ltrace(200) << "Z span: [" << zMin << ":" << zMax << "]" << endl;
|
|
ltrace(200) << "Global Stem: " << _globalStem << endl;
|
|
|
|
if ( zMax-zMin > 3 ) {
|
|
cerr << Error("AutoContact::split(): Spans on more than 4 layers, ignoring."
|
|
"\n %s",getString(_contact).c_str()) << endl;
|
|
ltraceout(200);
|
|
return;
|
|
}
|
|
|
|
_contact->invalidate ();
|
|
|
|
if ( zMax-zMin < 2 ) {
|
|
const Layer* contactLayer = _routingGauge->getContactLayer(zMin);
|
|
_contact->setLayer ( contactLayer );
|
|
ltrace(200) << "Needs only to change Layer." << endl;
|
|
ltraceout(200);
|
|
return;
|
|
}
|
|
|
|
// The complete case.
|
|
bool hExtended = isHExtended();
|
|
bool vExtended = isVExtended();
|
|
bool xFound = false;
|
|
bool yFound = false;
|
|
vector<SegmentEnd*> hBottom;
|
|
vector<SegmentEnd*> vBottom;
|
|
vector<SegmentEnd*> hTop;
|
|
vector<SegmentEnd*> vTop;
|
|
Point position;
|
|
|
|
for ( size_t i=0; i < _globalEnds.size() ; i++ ) {
|
|
ltrace(200) << "| G: " << _globalEnds[i] << endl;
|
|
if ( _globalEnds[i]->isHorizontal() ) {
|
|
if ( not yFound ) {
|
|
yFound = true;
|
|
position.setY ( _globalEnds[i]->getAxis() );
|
|
}
|
|
if ( _routingGauge->getLayerDepth(_globalEnds[i]->getLayer()) < zMin+2 )
|
|
hBottom.push_back ( _globalEnds[i] );
|
|
else
|
|
hTop.push_back ( _globalEnds[i] );
|
|
} else {
|
|
if ( not xFound ) {
|
|
xFound = true;
|
|
position.setX ( _globalEnds[i]->getAxis() );
|
|
}
|
|
if ( _routingGauge->getLayerDepth(_globalEnds[i]->getLayer()) < zMin+2 )
|
|
vBottom.push_back ( _globalEnds[i] );
|
|
else
|
|
vTop.push_back ( _globalEnds[i] );
|
|
}
|
|
}
|
|
|
|
for ( size_t i=0; i < _localEnds.size() ; i++ ) {
|
|
ltrace(200) << "| L: " << _localEnds[i] << endl;
|
|
if ( _localEnds[i]->isHorizontal() ) {
|
|
if ( not yFound ) {
|
|
yFound = true;
|
|
position.setY ( _localEnds[i]->getAxis() );
|
|
}
|
|
if ( _routingGauge->getLayerDepth(_localEnds[i]->getLayer()) < zMin+2 )
|
|
hBottom.push_back ( _localEnds[i] );
|
|
else
|
|
hTop.push_back ( _localEnds[i] );
|
|
} else {
|
|
if ( not xFound ) {
|
|
xFound = true;
|
|
position.setX ( _localEnds[i]->getAxis() );
|
|
}
|
|
if ( _routingGauge->getLayerDepth(_localEnds[i]->getLayer()) < zMin+2 )
|
|
vBottom.push_back ( _localEnds[i] );
|
|
else
|
|
vTop.push_back ( _localEnds[i] );
|
|
}
|
|
}
|
|
|
|
if ( not xFound ) position.setX ( _xMin );
|
|
if ( not yFound ) position.setY ( _yMin );
|
|
|
|
for ( size_t i=0 ; i<hTop.size() ; i++ ) hTop[i]->getHook()->detach ();
|
|
for ( size_t i=0 ; i<vTop.size() ; i++ ) vTop[i]->getHook()->detach ();
|
|
|
|
AutoContact* corner = AutoContact::create ( _contact->getGCell()
|
|
, _contact->getNet()
|
|
, _routingGauge->getContactLayer(zMin+1)
|
|
);
|
|
ltrace(200) << "Corner " << corner << endl;
|
|
|
|
AutoSegment* segment = AutoSegment::create ( _contact
|
|
, corner
|
|
, _routingGauge->getLayerDirection(zMin+1)
|
|
, AutoSegment::Local
|
|
);
|
|
DbU::Unit axis = (segment->isHorizontal()) ? position.getY() : position.getX();
|
|
segment->setLayer ( _routingGauge->getRoutingLayer(zMin+1) );
|
|
segment->setAxis ( axis );
|
|
segment->setSlackened ( true );
|
|
segment->setLayerChange ( true );
|
|
ltrace(200) << "Corner @" << DbU::getValueString(axis) << " " << segment << endl;
|
|
|
|
if ( vExtended ) _contact->setVAlignate ( true );
|
|
if ( hExtended ) _contact->setHAlignate ( true );
|
|
|
|
AutoContact* secondary = NULL;
|
|
if ( zMax-zMin == 3 ) {
|
|
secondary = AutoContact::create ( _contact->getGCell()
|
|
, _contact->getNet()
|
|
, _routingGauge->getContactLayer(zMin+2)
|
|
);
|
|
ltrace(200) << "Secondary " << secondary << endl;
|
|
|
|
segment = AutoSegment::create ( corner
|
|
, secondary
|
|
, _routingGauge->getLayerDirection(zMin+2)
|
|
, AutoSegment::Local
|
|
);
|
|
axis = (segment->isHorizontal()) ? position.getY() : position.getX();
|
|
segment->setLayer ( _routingGauge->getRoutingLayer(zMin+2) );
|
|
segment->setAxis ( axis );
|
|
segment->setCanonical ( true );
|
|
segment->setSlackened ( true );
|
|
segment->setLayerChange ( true );
|
|
ltrace(200) << "Secondary @" << DbU::getValueString(axis) << " " << segment << endl;
|
|
} else
|
|
secondary = corner;
|
|
|
|
for ( size_t i=0 ; i<hTop.size() ; i++ ) hTop[i]->getHook()->attach ( secondary->getBodyHook() );
|
|
for ( size_t i=0 ; i<vTop.size() ; i++ ) vTop[i]->getHook()->attach ( secondary->getBodyHook() );
|
|
|
|
if ( _contact->isVAlignate() ) secondary->setVAlignate(true);
|
|
if ( _contact->isHAlignate() ) secondary->setHAlignate(true);
|
|
|
|
if ( hExtended ) {
|
|
ltrace(200) << "Original was H extended: restore V connexity." << endl;
|
|
_contact ->restoreVConnexity ( position.getY(), true );
|
|
secondary->restoreVConnexity ( position.getY(), true );
|
|
}
|
|
|
|
if ( vExtended ) {
|
|
ltrace(200) << "Original was V extended: restore H connexity." << endl;
|
|
_contact ->restoreHConnexity ( position.getX(), true );
|
|
secondary->restoreHConnexity ( position.getX(), true );
|
|
}
|
|
|
|
ltraceout(200);
|
|
}
|
|
|
|
|
|
void JunctionBox::splitTerminal ()
|
|
{
|
|
ltrace(200) << "JunctionBox::splitTerminal(): AutoSegment connected to RoutingPad." << endl;
|
|
ltracein(200);
|
|
Point position = _contact->getPosition ();
|
|
|
|
_contact->getAnchorHook()->detach ();
|
|
|
|
RoutingPad* routingPad = dynamic_cast<RoutingPad*> ( _anchor );
|
|
if ( !routingPad ) {
|
|
cerr << Bug("JunctionBox::splitTerminal(): %s is not anchored on a <RoutingPad>."
|
|
,getString(_contact).c_str()) << endl;
|
|
ltraceout(200);
|
|
return;
|
|
}
|
|
|
|
AutoContact* rpContact = AutoContact::fromRp ( _contact->getGCell()
|
|
, routingPad
|
|
, _routingGauge->getContactLayer(0)
|
|
, position
|
|
, DbU::lambda(1.0), DbU::lambda(1.0)
|
|
);
|
|
AutoContact* via23 = AutoContact::create ( _contact->getGCell()
|
|
, _contact->getNet()
|
|
, _routingGauge->getContactLayer(1)
|
|
);
|
|
|
|
AutoSegment* segment = AutoSegment::create ( rpContact
|
|
, via23
|
|
, Constant::Horizontal
|
|
, AutoSegment::Local
|
|
, true // terminal.
|
|
, false // Temporary: *not* collapsed.
|
|
);
|
|
segment->setLayer ( _routingGauge->getRoutingLayer(1) );
|
|
segment->setAxis ( position.getY() );
|
|
ltrace(200) << "@" << DbU::getValueString(position.getY()) << segment << endl;
|
|
|
|
segment = AutoSegment::create ( via23
|
|
, _contact
|
|
, Constant::Vertical
|
|
, AutoSegment::Local
|
|
, false // terminal.
|
|
, false //true // collapsed.
|
|
);
|
|
segment->setAxis ( position.getX() );
|
|
segment->setLayer ( _routingGauge->getRoutingLayer(2) );
|
|
_contact->setLayer ( _routingGauge->getContactLayer(1) );
|
|
ltrace(200) << "@" << DbU::getValueString(position.getX()) << segment << endl;
|
|
|
|
ltraceout(200);
|
|
}
|
|
|
|
|
|
void JunctionBox::breakUpPunctual ()
|
|
{
|
|
Component* anchor = _contact->getAnchor();
|
|
Point center;
|
|
StackedContact* stackedContact;
|
|
|
|
if ( isEmpty() ) center = _contact->getCenter();
|
|
else if ( isPunctual() ) {
|
|
center.setX ( _xMin );
|
|
center.setY ( _yMin );
|
|
} else {
|
|
center.setX ( (_xMin+_xMax)/2 );
|
|
center.setY ( (_yMin+_yMax)/2 );
|
|
}
|
|
|
|
const Layer* layer = NULL;
|
|
if ( !_localEnds.empty () ) layer = _localEnds [0]->getLayer();
|
|
else if ( !_globalEnds.empty() ) layer = _globalEnds[0]->getLayer();
|
|
else if ( anchor ) layer = anchor->getLayer ();
|
|
|
|
stackedContact = StackedContact::create ( _contact->getNet()
|
|
, layer
|
|
, center.getX()
|
|
, center.getY()
|
|
);
|
|
|
|
if ( anchor ) stackedContact->setAnchor ( anchor );
|
|
|
|
for ( size_t i=0 ; i < _globalEnds.size() ; i++ )
|
|
stackedContact->attachSlave ( _globalEnds[i] );
|
|
|
|
for ( size_t i=0 ; i < _localEnds.size() ; i++ )
|
|
stackedContact->attachSlave ( _localEnds[i] );
|
|
|
|
stackedContact->breakUp ();
|
|
stackedContact->destroy ();
|
|
ltrace(99) << "JunctionBox::breakUpPunctual() succeded" << endl;
|
|
}
|
|
|
|
|
|
void JunctionBox::breakUp ()
|
|
{
|
|
ltrace(99) << "JunctionBox::breakUp() - <Box "
|
|
<< DbU::getLambda(_xMin) << " " << DbU::getLambda(_yMin) << " "
|
|
<< DbU::getLambda(_xMax) << " " << DbU::getLambda(_yMax)
|
|
<< ">" << endl;
|
|
|
|
if ( !_wireCount ) {
|
|
cerr << Warning("Standalone %s skipped.",getString(_contact).c_str()) << endl;
|
|
return;
|
|
}
|
|
|
|
if ( _failsafe or isPunctual() )
|
|
breakUpPunctual ();
|
|
else {
|
|
if ( not _globalStem ) {
|
|
cerr << Bug ( "JunctionBox::breakUp(): Flatten geometry whitout global stem,\n"
|
|
" on %p:%s."
|
|
, _contact->base()
|
|
, getString(_contact).c_str()
|
|
) << endl;
|
|
breakUpPunctual ();
|
|
} else {
|
|
// Flat geometry.
|
|
vector<StackedContact*> stackedContacts;
|
|
|
|
_globalStem->split ( stackedContacts );
|
|
for ( size_t i=0 ; i < stackedContacts.size() ; i++ ) {
|
|
stackedContacts[i]->breakUp ();
|
|
stackedContacts[i]->destroy ();
|
|
}
|
|
}
|
|
}
|
|
ltrace(99) << "JunctionBox::breakUp() succeded" << endl;
|
|
}
|
|
|
|
|
|
void JunctionBox::updateContacts ( VirtualContacts& vcs )
|
|
{
|
|
ltrace(109) << "JunctionBox::updateContacts()" << endl;
|
|
ltracein(109);
|
|
|
|
vcs.clear ();
|
|
|
|
Component* anchor = _contact->getAnchor ();
|
|
RoutingPad* rp = dynamic_cast<RoutingPad*>(anchor);
|
|
if ( rp )
|
|
vcs.merge ( Point(_xMin,_yMin), rp->getLayer() );
|
|
|
|
vector<SegmentEnd*>::iterator it = _localEnds.begin();
|
|
for ( ; it != _localEnds.end() ; it++ )
|
|
vcs.merge ( (*it)->getEnd(), (*it)->getLayer() );
|
|
|
|
for ( it = _globalEnds.begin() ; it != _globalEnds.end() ; it++ )
|
|
vcs.merge ( (*it)->getEnd(), (*it)->getLayer() );
|
|
|
|
ltraceout(109);
|
|
}
|
|
|
|
|
|
StackedContact::~StackedContact ()
|
|
{
|
|
ltrace(99) << "StackedContact::~StackedContact() - " << (void*)this << endl;
|
|
}
|
|
|
|
|
|
StackedContact::StackedContact ( Net* net, const Layer* layer, DbU::Unit x, DbU::Unit y )
|
|
: Contact(net,layer,x,y)
|
|
, _useds(Session::getRoutingGauge()->getDepth())
|
|
, _anchor(NULL)
|
|
{
|
|
for ( unsigned index = 0 ; index < Session::getRoutingGauge()->getDepth() ; index++ )
|
|
_useds [ index ] = false;
|
|
|
|
forEach ( BasicLayer*, basicLayer, getLayer()->getBasicLayers() )
|
|
addLayer ( *basicLayer );
|
|
}
|
|
|
|
|
|
StackedContact* StackedContact::create ( Net* net, const Layer* layer, DbU::Unit x, DbU::Unit y )
|
|
{
|
|
StackedContact* contact = new StackedContact ( net, layer, x, y );
|
|
contact->_postCreate ();
|
|
|
|
ltrace(99) << "create: " << contact << endl;
|
|
|
|
return contact;
|
|
}
|
|
|
|
|
|
void StackedContact::addLayer ( const Layer* layer )
|
|
{
|
|
if ( !Session::getTechnology()->isMetal(layer) ) return;
|
|
|
|
unsigned int index = Session::getRoutingGauge()->getLayerDepth ( layer );
|
|
if ( index == UINT_MAX ) return;
|
|
|
|
ltrace(99) << "StackedContact::addLayer() - " << layer << " [" << index << "]" << endl;
|
|
|
|
_useds [ index ] = true;
|
|
}
|
|
|
|
|
|
void StackedContact::setAnchor ( Component* anchor )
|
|
{
|
|
if ( (_anchor=anchor) ) {
|
|
forEach ( BasicLayer*, layer, _anchor->getLayer()->getBasicLayers() )
|
|
addLayer ( *layer );
|
|
}
|
|
}
|
|
|
|
|
|
void StackedContact::attachSlave ( SegmentEnd* segmentEnd )
|
|
{
|
|
ltrace(88) << "add at " << getCenter() << " " << segmentEnd->getLayer() << endl;
|
|
|
|
addLayer ( segmentEnd->getLayer() );
|
|
|
|
segmentEnd->setDelta ( 0 );
|
|
|
|
Hook* hook = segmentEnd->getHook();
|
|
hook->detach ();
|
|
hook->attach ( getBodyHook() );
|
|
}
|
|
|
|
|
|
void StackedContact::breakUp ()
|
|
{
|
|
ltrace(99) << "StakedContact::breakUp() - " << this << endl;
|
|
|
|
unsigned int zMin = 0;
|
|
unsigned int zMax = Session::getRoutingGauge()->getDepth() - 1;
|
|
Contact* contacts [ zMax+1 ];
|
|
|
|
for ( unsigned int i=0 ; i <= zMax ; i++ ) contacts[i] = NULL;
|
|
|
|
for ( ; (zMin <= zMax) && !_useds[zMin] ; zMin++ );
|
|
for ( ; (zMax > 0 ) && !_useds[zMax] ; zMax-- );
|
|
|
|
ltrace(99) << "Contact depth span [" << zMin << ":" << zMax << "]" << endl;
|
|
|
|
if ( zMin > zMax ) return;
|
|
if ( zMin == zMax ) {
|
|
if ( _anchor )
|
|
contacts[zMin] = Contact::create ( _anchor
|
|
, Session::getRoutingGauge()->getRoutingLayer(zMin)
|
|
, getX() - _anchor->getX()
|
|
, getY() - _anchor->getY()
|
|
, DbU::lambda(1.0), DbU::lambda(1.0)
|
|
);
|
|
else
|
|
contacts[zMin] = Contact::create ( getNet()
|
|
, Session::getRoutingGauge()->getRoutingLayer(zMin)
|
|
, getX()
|
|
, getY()
|
|
, DbU::lambda(1.0), DbU::lambda(1.0)
|
|
);
|
|
ltrace(88) << "Creating [" << zMin << "] " << contacts[zMin] << endl;
|
|
} else {
|
|
if ( _anchor )
|
|
contacts[zMin] = contacts[zMin+1]
|
|
= Contact::create ( _anchor
|
|
, Session::getRoutingGauge()->getContactLayer(zMin)
|
|
, getX() - _anchor->getX()
|
|
, getY() - _anchor->getY()
|
|
, DbU::lambda(1.0), DbU::lambda(1.0)
|
|
);
|
|
else
|
|
contacts[zMin] = contacts[zMin+1]
|
|
= Contact::create ( getNet()
|
|
, Session::getRoutingGauge()->getContactLayer(zMin)
|
|
, getX()
|
|
, getY()
|
|
, DbU::lambda(1.0), DbU::lambda(1.0)
|
|
);
|
|
ltrace(88) << "Creating [" << zMin << "] " << contacts[zMin] << endl;
|
|
|
|
for ( unsigned int j = zMin+1 ; j < zMax ; j++ ) {
|
|
contacts[j] = contacts[j+1]
|
|
= Contact::create ( contacts[j-1]
|
|
, Session::getRoutingGauge()->getContactLayer(j)
|
|
, 0
|
|
, 0
|
|
, DbU::lambda(1.0), DbU::lambda(1.0)
|
|
);
|
|
ltrace(88) << "Creating [" << j << "] " << contacts[j] << endl;
|
|
}
|
|
}
|
|
|
|
Hook* bodyHook = getBodyHook ();
|
|
Hook* currHook = bodyHook->getNextHook ();
|
|
|
|
while ( currHook != bodyHook ) {
|
|
Hook* nextHook = currHook->getNextHook ();
|
|
|
|
currHook->_setNextHook ( currHook );
|
|
Segment* segment = dynamic_cast<Segment*>(currHook->getComponent());
|
|
ltrace(88) << "Reattach [" << Session::getRoutingGauge()->getLayerDepth(segment->getLayer())
|
|
<< "] " << segment << endl;
|
|
currHook->attach ( contacts[Session::getRoutingGauge()->getLayerDepth(segment->getLayer())]->getBodyHook() );
|
|
|
|
currHook = nextHook;
|
|
}
|
|
|
|
bodyHook->_setNextHook ( bodyHook );
|
|
ltrace(99) << "StakedContact::breakUp() succeeded" << endl;
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "::FixedJunctionBox".
|
|
|
|
|
|
class FixedJunctionBox {
|
|
|
|
public:
|
|
// Constructor & Destructor.
|
|
FixedJunctionBox ( AutoContact*, bool checking );
|
|
~FixedJunctionBox ();
|
|
// Modifiers.
|
|
void checkTopology ();
|
|
void merge ( Hook* );
|
|
void resize ();
|
|
void breakUp ();
|
|
|
|
protected:
|
|
// Attributes.
|
|
AutoContact* _contact;
|
|
vector<SegmentEnd*> _segmentEnds;
|
|
bool _checking;
|
|
};
|
|
|
|
|
|
FixedJunctionBox::FixedJunctionBox ( AutoContact* contact, bool checking )
|
|
: _contact(contact)
|
|
, _segmentEnds()
|
|
, _checking(checking)
|
|
{
|
|
ltrace(110) << "FixedJunctionBox() " << contact << endl;
|
|
ltracein(109);
|
|
|
|
forEach ( Hook*, hook, _contact->getBodyHook()->getSlaveHooks() ) merge ( *hook );
|
|
|
|
ltraceout(109);
|
|
}
|
|
|
|
|
|
FixedJunctionBox::~FixedJunctionBox ()
|
|
{
|
|
for ( size_t i=0 ; i<_segmentEnds.size() ; i++ ) delete _segmentEnds[i];
|
|
}
|
|
|
|
|
|
void FixedJunctionBox::checkTopology ()
|
|
{ }
|
|
|
|
|
|
void FixedJunctionBox::merge ( Hook* hook )
|
|
{
|
|
SegmentEnd* segmentEnd = SegmentEnd::create ( hook, _checking );
|
|
if ( !segmentEnd ) return;
|
|
|
|
ltrace(109) << "merge() Axis "
|
|
<< DbU::getLambda(segmentEnd->getAxis())
|
|
<< " [global] " << segmentEnd << endl;
|
|
_segmentEnds.push_back ( segmentEnd );
|
|
}
|
|
|
|
|
|
void FixedJunctionBox::resize ()
|
|
{
|
|
for ( size_t i=0 ; i<_segmentEnds.size() ; i++ ) _segmentEnds[i]->setDelta(0);
|
|
}
|
|
|
|
|
|
void FixedJunctionBox::breakUp ()
|
|
{
|
|
Component* anchor = _contact->getAnchor();
|
|
StackedContact* stackedContact;
|
|
|
|
const Layer* layer = NULL;
|
|
if ( !_segmentEnds.empty () ) layer = _segmentEnds[0]->getLayer();
|
|
else if ( anchor ) layer = anchor->getLayer ();
|
|
|
|
stackedContact = StackedContact::create ( _contact->getNet()
|
|
, layer
|
|
, _contact->getX()
|
|
, _contact->getY()
|
|
);
|
|
|
|
if ( anchor ) stackedContact->setAnchor ( anchor );
|
|
|
|
for ( size_t i=0 ; i < _segmentEnds.size() ; i++ )
|
|
stackedContact->attachSlave ( _segmentEnds[i] );
|
|
|
|
stackedContact->breakUp ();
|
|
stackedContact->destroy ();
|
|
ltrace(99) << "FixedJunctionBox::breakUp() succeded" << endl;
|
|
}
|
|
|
|
|
|
} // End of local namespace.
|
|
|
|
|
|
|
|
|
|
namespace Katabatic {
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "Katabatic::VirtualContacts::VC".
|
|
|
|
|
|
bool operator== ( const VirtualContacts::VC& lhs
|
|
, const VirtualContacts::VC& rhs )
|
|
{
|
|
return lhs._point == rhs._point;
|
|
}
|
|
|
|
|
|
void VirtualContacts::VC::merge ( const Layer* layer )
|
|
{
|
|
if ( _layer->contains(layer) ) return;
|
|
Layer *newLayer = Session::getTechnology()->getLayer ( _layer->getMask() & layer->getMask() );
|
|
|
|
if ( !newLayer ) return;
|
|
_layer = newLayer;
|
|
}
|
|
|
|
|
|
void VirtualContacts::merge ( const Point& point, const Layer* layer )
|
|
{
|
|
VC vc ( point, layer );
|
|
|
|
ltrace(109) << "VirtualContacts::merge() " << point << " " << layer << endl;
|
|
|
|
vector<VC>::iterator it = _vcs.begin();
|
|
vector<VC>::iterator end = _vcs.end();
|
|
|
|
for ( ; it != end ; it++ ) {
|
|
if ( *it == vc ) { (*it).merge ( layer ); return; }
|
|
}
|
|
|
|
_vcs.push_back ( vc );
|
|
_boundingBox.merge ( Box(point).inflate(DbU::lambda(1.0)) );
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "Katabatic::AutoContact".
|
|
|
|
|
|
size_t AutoContact::_maxId = 0;
|
|
size_t AutoContact::_allocateds = 0;
|
|
const Name AutoContact::_goName = "Katabatic::AutoContact";
|
|
|
|
|
|
AutoContact* AutoContact::fromRp ( GCell* gcell
|
|
, RoutingPad* routingPad
|
|
, const Layer* layer
|
|
, Point point
|
|
, DbU::Unit width
|
|
, DbU::Unit height
|
|
, bool fixed
|
|
)
|
|
{
|
|
routingPad->getBodyHook()->detach ();
|
|
|
|
DbU::Unit x = 0;
|
|
DbU::Unit y = 0;
|
|
Entity* entity = routingPad->getOccurrence().getEntity();
|
|
|
|
// Assumes there is no rotation in the Transformation.
|
|
if ( dynamic_cast<Horizontal*>(entity) ) { x = point.getX(); }
|
|
else if ( dynamic_cast<Vertical* >(entity) ) { y = point.getY(); }
|
|
|
|
return AutoContact::create ( gcell
|
|
, routingPad
|
|
, layer
|
|
, x, y
|
|
, width, height
|
|
, false, false
|
|
, fixed
|
|
);
|
|
}
|
|
|
|
|
|
AutoContact::AutoContact ( GCell* gcell
|
|
, Contact* contact
|
|
, bool hAlignate
|
|
, bool vAlignate
|
|
)
|
|
: ExtensionGo (contact->getCell())
|
|
, _id (_maxId++)
|
|
, _contact (contact)
|
|
, _gcell (gcell)
|
|
, _invalid (false)
|
|
, _invalidTopology(true)
|
|
, _isTerminal (false)
|
|
, _fixed (false)
|
|
, _hAlignate (hAlignate)
|
|
, _vAlignate (vAlignate)
|
|
, _isCorner (false)
|
|
, _dxMin (0)
|
|
, _dxMax (_gcell->getXMax()-_gcell->getX())
|
|
, _dyMin (0)
|
|
, _dyMax (_gcell->getYMax()-_gcell->getY())
|
|
, _subContacts ()
|
|
{
|
|
_allocateds++;
|
|
_gcell->addContact ( this );
|
|
}
|
|
|
|
|
|
void AutoContact::_postCreate ()
|
|
{
|
|
ExtensionGo::_postCreate ();
|
|
|
|
restoreNativeConstraintBox ();
|
|
|
|
ltrace(90) << "Native CBox: " << this
|
|
<< " <" << DbU::getLambda(getCBXMin())
|
|
<< " " << DbU::getLambda(getCBYMin())
|
|
<< " " << DbU::getLambda(getCBXMax())
|
|
<< " " << DbU::getLambda(getCBYMax()) << ">" << endl;
|
|
|
|
Session::link ( this );
|
|
invalidate ();
|
|
|
|
ltrace(90) << "AutoContact::_postCreate() - " << this << " in " << _gcell << endl;
|
|
}
|
|
|
|
|
|
void AutoContact::_preDestroy ()
|
|
{
|
|
DebugSession::open ( _contact->getNet() );
|
|
|
|
ltrace(90) << "AutoContact::_preDestroy() - <AutoContact id:" << _id << ">" << endl;
|
|
|
|
if ( not _contact->getSlaveComponents().isEmpty() ) {
|
|
cerr << Error("Base contact still have slaves components, cancelled.\n"
|
|
" (%s)"
|
|
,_getString().c_str()) << endl;
|
|
DebugSession::close ();
|
|
return;
|
|
}
|
|
|
|
if ( not Session::doDestroyTool() ) {
|
|
_gcell->removeContact ( this );
|
|
Session::unlink ( this );
|
|
}
|
|
|
|
ExtensionGo::_preDestroy ();
|
|
if ( Session::doDestroyBaseContact() )
|
|
_contact->destroy ();
|
|
|
|
DebugSession::close ();
|
|
}
|
|
|
|
|
|
AutoContact::~AutoContact ()
|
|
{
|
|
_allocateds--;
|
|
}
|
|
|
|
|
|
AutoContact* AutoContact::create ( GCell* gcell
|
|
, Net* net
|
|
, const Layer* layer
|
|
, bool hAlignate
|
|
, bool vAlignate
|
|
)
|
|
{
|
|
Contact* contact = Contact::create ( net
|
|
, layer
|
|
, gcell->getCenter().getX()
|
|
, gcell->getCenter().getY()
|
|
, DbU::lambda(2.0)
|
|
, DbU::lambda(2.0)
|
|
);
|
|
AutoContact* autoContact = new AutoContact ( gcell, contact, hAlignate, vAlignate );
|
|
|
|
autoContact->_postCreate ();
|
|
|
|
ltrace(90) << "create(net*) " << autoContact << endl;
|
|
return autoContact;
|
|
}
|
|
|
|
|
|
AutoContact* AutoContact::create ( GCell* gcell
|
|
, RoutingPad* rp
|
|
, const Layer* layer
|
|
, const DbU::Unit dx
|
|
, const DbU::Unit dy
|
|
, const DbU::Unit width
|
|
, const DbU::Unit height
|
|
, bool hAlignate
|
|
, bool vAlignate
|
|
, bool fixed
|
|
)
|
|
{
|
|
Contact* contact = Contact::create ( rp
|
|
, layer
|
|
, dx /*- rp->getX()*/
|
|
, dy /*- rp->getY()*/
|
|
, width
|
|
, height
|
|
);
|
|
AutoContact* autoContact = new AutoContact ( gcell, contact, hAlignate, vAlignate );
|
|
|
|
autoContact->setFixed ( fixed );
|
|
autoContact->setTerminal ( true );
|
|
autoContact->_postCreate ();
|
|
|
|
ltrace(90) << "create(RoutingPad*) " << autoContact << endl;
|
|
return autoContact;
|
|
}
|
|
|
|
|
|
bool AutoContact::canDestroy ( bool error ) const
|
|
{
|
|
if ( not _contact->getSlaveComponents().isEmpty() ) {
|
|
if ( error ) {
|
|
cerr << Error("Base contact still have slaves components, cancelled.\n"
|
|
" (%s)"
|
|
,_getString().c_str()) << endl;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
size_t AutoContact::getSegmentEndAllocateds ()
|
|
{
|
|
return SegmentEnd::getAllocateds();
|
|
}
|
|
|
|
|
|
size_t AutoContact::getAllocateds ()
|
|
{
|
|
return _allocateds;
|
|
}
|
|
|
|
|
|
const Name& AutoContact::getStaticName ()
|
|
{
|
|
return _goName;
|
|
}
|
|
|
|
|
|
const Name& AutoContact::getName () const
|
|
{
|
|
return _goName;
|
|
}
|
|
|
|
|
|
unsigned int AutoContact::getMinDepth () const
|
|
{
|
|
size_t minDepth = (size_t)-1;
|
|
Component* anchor = getAnchor ();
|
|
if ( anchor ) {
|
|
minDepth = min ( minDepth, Session::getRoutingGauge()->getLayerDepth(anchor->getLayer()) );
|
|
//ltrace(200) << "Anchor:" << anchor << endl;
|
|
}
|
|
|
|
forEach ( Component*, icomponent, getSlaveComponents() ) {
|
|
minDepth = min ( minDepth, Session::getRoutingGauge()->getLayerDepth(icomponent->getLayer()) );
|
|
//ltrace(200) << "Slave:" << *icomponent << endl;
|
|
}
|
|
|
|
return (unsigned int)minDepth;
|
|
}
|
|
|
|
|
|
void AutoContact::getLengths ( DbU::Unit* lengths, set<AutoSegment*>& processeds )
|
|
{
|
|
forEach ( Hook*, ihook, getBodyHook()->getSlaveHooks() ) {
|
|
bool isSourceHook = (dynamic_cast<Segment::SourceHook*>(*ihook));
|
|
if ( !isSourceHook && ( dynamic_cast<Segment::TargetHook*>(*ihook) == NULL ) ) {
|
|
cerr << Error ( badHookType, getString(ihook->getComponent()).c_str() ) << endl;
|
|
return;
|
|
}
|
|
|
|
bool isHorizontal = true;
|
|
Segment* segment = dynamic_cast<Horizontal*>((*ihook)->getComponent());
|
|
if ( !segment ) {
|
|
isHorizontal = false;
|
|
segment = dynamic_cast<Vertical*>((*ihook)->getComponent());
|
|
if ( !segment )
|
|
continue;
|
|
}
|
|
|
|
AutoSegment* autoSegment = Session::lookup ( segment );
|
|
if ( not autoSegment or processeds.find(autoSegment) != processeds.end() )
|
|
continue;
|
|
processeds.insert ( autoSegment );
|
|
|
|
size_t depth = Session::getRoutingGauge()->getLayerDepth(segment->getLayer());
|
|
DbU::Unit length;
|
|
if ( autoSegment->isLocal() ) {
|
|
length = segment->getLength();
|
|
lengths[depth] += length;
|
|
if ( abs(length) >= DbU::lambda(50.0) )
|
|
cerr << Error("Supicious length:%.2f of %s."
|
|
,DbU::getLambda(length),getString(autoSegment).c_str()) << endl;
|
|
} else {
|
|
if ( isHorizontal ) {
|
|
if ( isSourceHook )
|
|
lengths[depth] += _gcell->getBoundingBox().getXMax() - segment->getSourceX();
|
|
else
|
|
lengths[depth] += segment->getTargetX() - _gcell->getBoundingBox().getXMin();
|
|
} else {
|
|
if ( isSourceHook )
|
|
lengths[depth] += _gcell->getBoundingBox().getYMax() - segment->getSourceY();
|
|
else
|
|
lengths[depth] += segment->getTargetY() - _gcell->getBoundingBox().getYMin();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Box AutoContact::getNativeConstraintBox () const
|
|
{
|
|
//if ( _fixed ) return Box(getCenter());
|
|
|
|
Component* component = getAnchor();
|
|
if ( component == NULL ) return _gcell->getBoundingBox ();
|
|
|
|
DbU::Unit xMin;
|
|
DbU::Unit xMax;
|
|
DbU::Unit yMin;
|
|
DbU::Unit yMax;
|
|
Vertical* vertical;
|
|
Horizontal* horizontal;
|
|
RoutingPad* routingPad;
|
|
|
|
if ( (horizontal = dynamic_cast<Horizontal*>(component))) {
|
|
xMin = horizontal->getSourcePosition().getX();
|
|
xMax = horizontal->getTargetPosition().getX();
|
|
yMin = yMax
|
|
= horizontal->getTargetPosition().getY();
|
|
} else if ( (vertical = dynamic_cast<Vertical*>(component)) ) {
|
|
yMin = vertical->getSourcePosition().getY();
|
|
yMax = vertical->getTargetPosition().getY();
|
|
xMin = xMax
|
|
= vertical->getTargetPosition().getX();
|
|
} else if ( (routingPad = dynamic_cast<RoutingPad*>(component)) ) {
|
|
Entity* entity = routingPad->getOccurrence().getEntity();
|
|
|
|
// Assumes there is no rotation in the Transformation.
|
|
if ( dynamic_cast<Horizontal*>(entity) ) {
|
|
xMin = routingPad->getSourcePosition().getX();
|
|
xMax = routingPad->getTargetPosition().getX();
|
|
yMin = yMax
|
|
= routingPad->getTargetPosition().getY();
|
|
} else if ( dynamic_cast<Vertical*>(entity) ) {
|
|
yMin = routingPad->getSourcePosition().getY();
|
|
yMax = routingPad->getTargetPosition().getY();
|
|
xMin = xMax
|
|
= routingPad->getTargetPosition().getX();
|
|
} else {
|
|
xMin = xMax = routingPad->getPosition().getX();
|
|
yMin = yMax = routingPad->getPosition().getY();
|
|
}
|
|
} else {
|
|
xMin = xMax = component->getPosition().getX();
|
|
yMin = yMax = component->getPosition().getY();
|
|
}
|
|
|
|
order ( xMin, xMax );
|
|
order ( yMin, yMax );
|
|
|
|
return Box ( xMin, yMin, xMax, yMax );
|
|
}
|
|
|
|
|
|
Interval AutoContact::getUConstraints ( unsigned int direction ) const
|
|
{
|
|
if ( direction == Constant::Horizontal ) {
|
|
return Interval ( getCBYMin(), getCBYMax() );
|
|
}
|
|
return Interval ( getCBXMin(), getCBXMax() );
|
|
}
|
|
|
|
|
|
AutoContacts AutoContact::getCollapseds ( unsigned int direction )
|
|
{
|
|
return AutoContacts_Collapsed ( this, direction );
|
|
}
|
|
|
|
|
|
void AutoContact::invalidate ()
|
|
{
|
|
if ( !isInvalidated() ) {
|
|
ltrace(110) << "AutoContact::invalidate() - " << this << endl;
|
|
setInvalidated ( true );
|
|
Session::invalidate ( this );
|
|
getGCell()->invalidate ();
|
|
}
|
|
}
|
|
|
|
|
|
void AutoContact::revalidate ()
|
|
{
|
|
updateGeometry ();
|
|
if ( _invalidTopology )
|
|
revalidateTopology ();
|
|
}
|
|
|
|
|
|
void AutoContact::updateGeometry ()
|
|
{
|
|
DebugSession::open ( getNet(), 80 );
|
|
|
|
ltrace(110) << "AutoContact::updateGeometry() " << this << endl;
|
|
ltracein(110);
|
|
|
|
_contact->invalidate ( false );
|
|
setInvalidated ( false );
|
|
|
|
if ( isFixed() ) {
|
|
FixedJunctionBox junctionBox ( this, false );
|
|
junctionBox.resize ();
|
|
} else {
|
|
JunctionBox junctionBox ( this, false );
|
|
junctionBox.resize ();
|
|
junctionBox.updateContacts ( _subContacts );
|
|
}
|
|
#if defined(CHECK_DATABASE)
|
|
checkTopology();
|
|
#endif
|
|
|
|
ltraceout(110);
|
|
|
|
DebugSession::close ();
|
|
}
|
|
|
|
|
|
void AutoContact::setGCell ( GCell* gcell )
|
|
{
|
|
invalidate ();
|
|
if ( _gcell ) _gcell->removeContact ( this );
|
|
|
|
_gcell = gcell;
|
|
if ( _gcell ) {
|
|
_gcell->addContact ( this );
|
|
_contact->setPosition ( _gcell->getCenter() );
|
|
_dxMin = 0;
|
|
_dyMin = 0;
|
|
_dxMax = _gcell->getXMax()-_gcell->getX();
|
|
_dyMax = _gcell->getYMax()-_gcell->getY();
|
|
} else {
|
|
cerr << Bug("NULL GCell for %p:%s.",_contact,_getString().c_str()) << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void AutoContact::breakUp ()
|
|
{
|
|
if ( isFixed() ) {
|
|
FixedJunctionBox(this,false).breakUp();
|
|
} else {
|
|
JunctionBox(this,false).breakUp();
|
|
}
|
|
ltrace(110) << "AutoContact::breakUp() succeded" << endl;
|
|
}
|
|
|
|
|
|
void AutoContact::split ()
|
|
{
|
|
DebugSession::open ( getNet() );
|
|
JunctionBox(this,false).split();
|
|
DebugSession::close ();
|
|
}
|
|
|
|
|
|
void AutoContact::checkTopology ()
|
|
{
|
|
ltrace(110) << "checkTopology() " << this << endl;
|
|
|
|
if ( isFixed() ) {
|
|
FixedJunctionBox(this,true).checkTopology();
|
|
} else {
|
|
JunctionBox(this,true).checkTopology();
|
|
}
|
|
}
|
|
|
|
|
|
void AutoContact::revalidateTopology ()
|
|
{
|
|
ltrace(110) << "revalidateTopology() " << this << endl;
|
|
|
|
JunctionBox(this,true).revalidateTopology();
|
|
}
|
|
|
|
|
|
bool AutoContact::isAlignate ( unsigned int direction ) const
|
|
{
|
|
return (_hAlignate && (direction == Constant::Horizontal))
|
|
|| (_vAlignate && (direction == Constant::Vertical ));
|
|
}
|
|
|
|
|
|
bool AutoContact::isHExtended ()
|
|
{ return JunctionBox(this,true).isHExtended(); }
|
|
|
|
|
|
bool AutoContact::isVExtended ()
|
|
{ return JunctionBox(this,true).isVExtended(); }
|
|
|
|
|
|
void AutoContact::computeAlignate ()
|
|
{
|
|
if ( !isFixed() )
|
|
JunctionBox(this,true).computeAlignate();
|
|
}
|
|
|
|
|
|
bool AutoContact::canGoOutsideGCell ( const AutoSegment* segment )
|
|
{ return JunctionBox(this,true).canGoOutside(segment); }
|
|
|
|
|
|
bool AutoContact::canHDesalignate ()
|
|
{ return JunctionBox(this,true).canHDesalignate(); }
|
|
|
|
|
|
bool AutoContact::canVDesalignate ()
|
|
{ return JunctionBox(this,true).canVDesalignate(); }
|
|
|
|
|
|
bool AutoContact::hDesalignate ()
|
|
{
|
|
bool desalignate = JunctionBox(this,true).canHDesalignate();
|
|
|
|
if ( desalignate ) setHAlignate ( false );
|
|
return desalignate;
|
|
}
|
|
|
|
|
|
bool AutoContact::vDesalignate ()
|
|
{
|
|
bool desalignate = JunctionBox(this,true).canVDesalignate();
|
|
|
|
if ( desalignate ) setVAlignate ( false );
|
|
return desalignate;
|
|
}
|
|
|
|
|
|
void AutoContact::restoreHConnexity ( DbU::Unit x, bool split )
|
|
{ JunctionBox(this,true).restoreHConnexity ( x, split ); }
|
|
|
|
|
|
void AutoContact::restoreVConnexity ( DbU::Unit y, bool split )
|
|
{ JunctionBox(this,true).restoreVConnexity ( y, split ); }
|
|
|
|
|
|
bool AutoContact::canMoveUp ( AutoSegment* moved ) const
|
|
{
|
|
ltrace(200) << "AutoContact::canMoveUp() " << this << endl;
|
|
size_t viaDepth = 100;
|
|
|
|
RoutingGauge* rg = Session::getRoutingGauge();
|
|
size_t movedDepth = rg->getLayerDepth(moved->getLayer());
|
|
|
|
Component* anchor = getAnchor ();
|
|
if ( anchor ) {
|
|
viaDepth = rg->getLayerDepth(anchor->getLayer());
|
|
ltrace(200) << "| Anchor depth: " << viaDepth << endl;
|
|
}
|
|
|
|
forEach ( Segment*, isegment, _contact->getSlaveComponents().getSubSet<Segment*>() ) {
|
|
if ( *isegment == moved->base() ) continue;
|
|
|
|
size_t depth = rg->getLayerDepth(isegment->getLayer());
|
|
if ( viaDepth == 100 ) viaDepth = depth;
|
|
else
|
|
if ( viaDepth != depth ) return false;
|
|
|
|
ltrace(200) << "| Segment depth: " << depth << endl;
|
|
}
|
|
|
|
return ( movedDepth+1 == viaDepth );
|
|
}
|
|
|
|
|
|
void AutoContact::setConstraintBox ( const Box& box )
|
|
{
|
|
setCBXMin ( box.getXMin() );
|
|
setCBXMax ( box.getXMax() );
|
|
setCBYMin ( box.getYMin() );
|
|
setCBYMax ( box.getYMax() );
|
|
ltrace(110) << "setConstraintBox() - " << this << " " << getConstraintBox() << endl;
|
|
ltrace(110) << "* " << _gcell << endl;
|
|
}
|
|
|
|
|
|
bool AutoContact::restrictConstraintBox ( DbU::Unit constraintMin
|
|
, DbU::Unit constraintMax
|
|
, unsigned int direction
|
|
, bool warnOnError )
|
|
{
|
|
if ( direction & Constant::Horizontal ) {
|
|
if ( (constraintMin > getCBYMax()) or (constraintMax < getCBYMin()) ) {
|
|
if ( Session::getDemoMode() or not warnOnError ) return false;
|
|
|
|
cerr << Error ( "Incompatible DY restriction on %s", _getString().c_str() ) << endl;
|
|
if ( constraintMin > getCBYMax() )
|
|
cerr << Error ( "(constraintMin > CBYMax : %.2lf > %.2lf)"
|
|
, DbU::getLambda(constraintMin)
|
|
, DbU::getLambda(getCBYMax()) )
|
|
<< endl;
|
|
if ( constraintMax < getCBYMin() )
|
|
cerr << Error ( "(constraintMax < CBYMin : %.2lf < %.2lf)"
|
|
, DbU::getLambda(constraintMax)
|
|
, DbU::getLambda(getCBYMin()) )
|
|
<< endl;
|
|
return false;
|
|
}
|
|
setCBYMin ( max(getCBYMin(),constraintMin) );
|
|
setCBYMax ( min(getCBYMax(),constraintMax) );
|
|
} else if ( direction & Constant::Vertical ) {
|
|
if ( (constraintMin > getCBXMax()) || (constraintMax < getCBXMin()) ) {
|
|
if ( Session::getDemoMode() or not warnOnError ) return false;
|
|
|
|
cerr << Error ( "Incompatible DX restriction on %s", _getString().c_str() ) << endl;
|
|
if ( constraintMin > getCBXMax() )
|
|
cerr << Error ( "(constraintMin > CBXMax : %.2lf > %.2lf)"
|
|
, DbU::getLambda(constraintMin)
|
|
, DbU::getLambda(getCBXMax()) )
|
|
<< endl;
|
|
if ( constraintMax < getCBXMin() )
|
|
cerr << Error ( "(constraintMax < CBXMin : %.2lf < %.2lf)"
|
|
, DbU::getLambda(constraintMax)
|
|
, DbU::getLambda(getCBXMin()) )
|
|
<< endl;
|
|
return false;
|
|
}
|
|
setCBXMin ( max(getCBXMin(),constraintMin) );
|
|
setCBXMax ( min(getCBXMax(),constraintMax) );
|
|
}
|
|
ltrace(110) << "restrictConstraintBox() - " << this << " " << getConstraintBox() << endl;
|
|
return true;
|
|
}
|
|
|
|
|
|
void AutoContact::restoreNativeConstraintBox ()
|
|
{
|
|
setConstraintBox ( getNativeConstraintBox() );
|
|
}
|
|
|
|
|
|
Box& AutoContact::intersectConstraintBox ( Box& box ) const
|
|
{
|
|
return box = box.getIntersection ( getConstraintBox() );
|
|
}
|
|
|
|
|
|
Box AutoContact::getBoundingBox () const
|
|
{
|
|
return _gcell->getBoundingBox ();
|
|
}
|
|
|
|
|
|
void AutoContact::translate ( const DbU::Unit& tx, const DbU::Unit& ty )
|
|
{
|
|
cerr << Warning("Calling AutoContact::translate() is likely a bug.") << endl;
|
|
_contact->translate ( tx, ty );
|
|
}
|
|
|
|
|
|
string AutoContact::_getString () const
|
|
{
|
|
string s = _contact->_getString();
|
|
s.insert ( 1, "id: " );
|
|
s.insert ( 4, getString(_id) );
|
|
s.insert ( s.size()-1, (_fixed )?" F":" -" );
|
|
s.insert ( s.size()-1, (_isTerminal)? "t": "-" );
|
|
s.insert ( s.size()-1, (_hAlignate) ? "h": "-" );
|
|
s.insert ( s.size()-1, (_vAlignate) ? "v": "-" );
|
|
s.insert ( s.size()-1, (_invalid) ? "i": "-" );
|
|
|
|
// Point p = _contact->getCenter();
|
|
// s.insert ( s.size()-1, " [" );
|
|
// s.insert ( s.size()-1, DbU::getValueString(p.getX()) );
|
|
// s.insert ( s.size()-1, ":" );
|
|
// s.insert ( s.size()-1, DbU::getValueString(p.getY()) );
|
|
// s.insert ( s.size()-1, "]" );
|
|
return s;
|
|
}
|
|
|
|
|
|
Record* AutoContact::_getRecord () const
|
|
{
|
|
Record* record = _contact->_getRecord ();
|
|
record->add ( getSlot ( "_gcell" , _gcell ) );
|
|
record->add ( getSlot ( "_constraintBox", getConstraintBox() ) );
|
|
record->add ( getSlot ( "_fixed" , _fixed ) );
|
|
record->add ( getSlot ( "_isTerminal" , _isTerminal ) );
|
|
record->add ( getSlot ( "_hAlignate" , _hAlignate ) );
|
|
record->add ( getSlot ( "_vAlignate" , _vAlignate ) );
|
|
record->add ( getSlot ( "_invalid" , _invalid ) );
|
|
return record;
|
|
}
|
|
|
|
|
|
} // End of Katabatic namespace.
|