// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2008-2016, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | // | A n a b a t i c - Routing Toolbox | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@lip6.fr | // | =============================================================== | // | C++ Module : "./AutoSegment.cpp" | // +-----------------------------------------------------------------+ #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 "anabatic/Session.h" #include "anabatic/AutoContact.h" #include "anabatic/AutoSegment.h" #include "anabatic/AutoHorizontal.h" #include "anabatic/AutoVertical.h" #include "anabatic/GCell.h" #include "anabatic/AnabaticEngine.h" namespace { using namespace std; using namespace CRL; using namespace Hurricane; using namespace Anabatic; // --------------------------------------------------------------- // Local Variables. const char* badAutoSegmentAnchor = "AutoSegment::create() :\n\n" " Source and/or target anchor is NOT an (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 = "Anabatic::AutoSegment::create () :\n\n" " Segment between %s and %s\n" " is neither horizontal nor vertical .\n"; const char* badSegmentSource = "Anabatic::AutoSegment::create () :\n\n" " Source anchor of segment %s is not a Contact\n" " (%s)\n"; const char* badSegmentTarget = "Anabatic::AutoSegment::create () :\n\n" " Source anchor of segment %s is not a Contact\n" " (%s)\n"; const char* mismatchSegmentSource = "Anabatic::AutoSegment::create () :\n\n" " Source anchor of segment %s is already an AutoContact\n" " (%s)\n"; const char* mismatchSegmentTarget = "Anabatic::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; cdebug_log(145,0) << "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->base() ) continue; Segment* connex = dynamic_cast(*icomponent); if ( !connex ) continue; segment = Session::lookup ( connex ); if ( not segment or not segment->isWeakTerminal() ) continue; segmentCount++; } if ( segmentCount == 1 ) { return getTerminalInterval ( segment, terminalContact, isHorizontal, min, max ); return false; } } else { cdebug_log(145,0) << "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 _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++; cdebug_log(145,0) << "add Attractor @" << DbU::toLambda(position) << " [" << _attractors[position] << "]" << endl; } DbU::Unit AttractorsMap::getLowerMedian () const { size_t median = (_attractorsCount/2) + (_attractorsCount%2); size_t lower = 0; map::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::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 Anabatic { // ------------------------------------------------------------------- // Class : "Anabatic::AutoSegment::CompareByDepthLength". bool AutoSegment::CompareByDepthLength::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->getSourceU() - rhs->getSourceU(); if ( deltaUnit < 0 ) return true; // Smallest source first. if ( deltaUnit > 0 ) return false; deltaUnit = lhs->getLength() - rhs->getLength(); if ( deltaUnit > 0 ) return true; // Longest first. if ( deltaUnit < 0 ) return true; deltaUnit = lhs->getAxis() - rhs->getAxis(); if ( deltaUnit < 0 ) return true; // Smallest axis first. if ( deltaUnit > 0 ) return false; // 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(); // 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(); // if ( lhs->isFixed() xor rhs->isFixed() ) return lhs->isFixed(); return lhs->getId() < rhs->getId(); } // ------------------------------------------------------------------- // Class : "Anabatic::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. } // ------------------------------------------------------------------- // Class : "Anabatic::AutoSegment". size_t AutoSegment::_allocateds = 0; size_t AutoSegment::_globalsCount = 0; unsigned long AutoSegment::_maxId = 0; AutoSegment::AutoSegment ( Segment* segment ) : _id (segment->getId()) , _gcell (NULL) , _flags (SegCreated) , _depth (Session::getLayerDepth(segment->getLayer())) , _optimalMin (0) , _optimalMax (0) , _reduceds (0) , _sourcePosition (0) , _targetPosition (0) , _userConstraints (false) , _nativeConstraints(false) , _parent (NULL) , _observers () { AutoContact* source = Session::lookup(dynamic_cast(segment->getSource())); AutoContact* target = Session::lookup(dynamic_cast(segment->getTarget())); _allocateds++; if (dynamic_cast(segment)) setFlags( SegHorizontal ); if (source->isTerminal()) setFlags( SegSourceTerminal ); if (target->isTerminal()) setFlags( SegTargetTerminal ); _globalsCount += isGlobal() ? 1 : 0; source->invalidate( Flags::Topology ); } void AutoSegment::_preCreate ( AutoContact* source, AutoContact* target ) { if ( (source == NULL) or (target == NULL) ) 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 ); updateOrient(); updatePositions(); invalidate( Flags::Topology ); _observers.notify( Create ); } void AutoSegment::_preDestroy () { cdebug_log(149,0) << "AutoSegment::_preDestroy() - " << (void*)this << endl; cdebug_tabw(145,1); _observers.notify( Destroy ); Session::unlink( this ); cdebug_tabw(145,-1); } AutoSegment::~AutoSegment () { _allocateds--; if ( isGlobal() and (_globalsCount > 0) ) _globalsCount--; } DbU::Unit AutoSegment::getX () const { return base()->getX(); } DbU::Unit AutoSegment::getY () const { return base()->getY(); } AutoContact* AutoSegment::getOppositeAnchor ( AutoContact* anchor ) const { return Session::lookup(static_cast(getOppositeAnchor(anchor->base()))); } Interval& AutoSegment::getOptimal ( Interval& i ) const { i.getVMin() = getOptimalMin(); i.getVMax() = getOptimalMax(); return i; } bool AutoSegment::checkNotInvalidated () const { if (isInvalidated()) cerr << Error("%s is invalidated.",getString(this).c_str()) << endl; return not isInvalidated(); } void AutoSegment::invalidate ( unsigned int flags ) { if (Session::doDestroyTool()) return; if (flags & Flags::Source) setFlags( SegInvalidatedSource ); if (flags & Flags::Target) setFlags( SegInvalidatedTarget ); if (isInvalidated()) return; cdebug_log(149,0) << "AutoSegment::invalidate() " << flags << " " << this << endl; cdebug_tabw(149,1); _invalidate(); if ((flags & Flags::Propagate) and not isNotAligned()) { forEach( AutoSegment*, isegment, getAligneds() ) { isegment->_invalidate(); } } cdebug_tabw(149,-1); } void AutoSegment::_invalidate () { if (isInvalidated()) return; cdebug_log(145,0) << "AutoSegment::_invalidate() " << this << endl; setFlags( SegInvalidated ); Session::invalidate( this ); _observers.notify( Invalidate ); } void AutoSegment::invalidate ( AutoContact* contact ) { if (Session::doDestroyTool()) return; if (contact == getAutoSource()) setFlags( SegInvalidatedSource ); if (contact == getAutoTarget()) setFlags( SegInvalidatedTarget ); } void AutoSegment::revalidate () { cdebug_log(149,0) << "AutoSegment::revalidate() " << this << endl; if (not isInvalidated()) return; cdebug_tabw(149,1); updateOrient (); updatePositions(); unsigned int oldSpinFlags = _flags & SegDepthSpin; if (_flags & (SegInvalidatedSource|SegCreated)) { AutoContact* source = getAutoSource(); const Layer* contactLayer = source->getLayer(); const Layer* segmentLayer = getLayer(); cdebug_log(149,0) << "Changed source: " << source << endl; unsetFlags( SegSourceTop|SegSourceBottom ); if (contactLayer != segmentLayer) setFlags( (segmentLayer == contactLayer->getTop()) ? SegSourceBottom : SegSourceTop ); if (source->isTurn() and source->getPerpandicular(this)->isReduced()) incReduceds(); } if (_flags & (SegInvalidatedTarget|SegCreated)) { AutoContact* target = getAutoTarget(); const Layer* contactLayer = target->getLayer(); const Layer* segmentLayer = getLayer(); cdebug_log(149,0) << "Changed target: " << target << endl; unsetFlags( SegTargetTop|SegTargetBottom ); if (contactLayer != segmentLayer) setFlags( (segmentLayer == contactLayer->getTop()) ? SegTargetBottom : SegTargetTop ); if (target->isTurn() and target->getPerpandicular(this)->isReduced()) incReduceds(); } unsigned int observerFlags = Revalidate; if ( (_flags & SegCreated) or (oldSpinFlags != (_flags & SegDepthSpin)) ) observerFlags |= RevalidatePPitch; unsetFlags( SegInvalidated | SegInvalidatedSource | SegInvalidatedTarget | SegInvalidatedLayer | SegCreated ); _observers.notify( observerFlags ); cdebug_log(149,0) << "Updated: " << this << endl; cdebug_tabw(149,-1); } bool AutoSegment::isStrongTerminal ( unsigned int flags ) const { if (_flags & SegStrongTerminal) return true; if ((flags & Flags::Propagate) and not isNotAligned()) { forEach( AutoSegment*, isegment, const_cast(this)->getAligneds() ) { if (isegment->_flags & SegStrongTerminal) return true; } } return false; } DbU::Unit AutoSegment::getPPitch () const { unsigned int depth = getDepth(); DbU::Unit topPPitch = Session::getPitch( depth + ( ((_flags & SegSpinTop) and (depth+1 < Session::getDepth())) ? 1 : 0) ); DbU::Unit bottomPPitch = Session::getPitch( depth - ( ((_flags & SegSpinBottom) and (depth > 0))? 1 : 0) ); return std::max( topPPitch, bottomPPitch ); } 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 ) { cdebug_log(145,0) << "AutoSegment::getCanonical() - " << this << endl; min = getSourcePosition (); max = getTargetPosition (); if (max < min) swap( min, max ); //cdebug_log(145,0) << "[" << DbU::getValueString(min) << " " << DbU::getValueString(max) << "]" << endl; AutoSegment* canonical = this; size_t canonicals = isCanonical(); size_t aligneds = 1; DbU::Unit collapsedMin; DbU::Unit collapsedMax; if (not isNotAligned()) { forEach( AutoSegment*, isegment, getAligneds() ) { 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++; } //cdebug_log(145,0) << "[" << DbU::getValueString(min) << " " << DbU::getValueString(max) << "]" << endl; cdebug_log(145,0) << "Canonical: " << canonical << endl; if ( (canonicals > 1) or ( not canonicals and (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, getAligneds() ) 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::getCachedOnSourceContact ( unsigned int direction ) { return AutoSegments_CachedOnContact( getAutoSource(), direction ); } AutoSegments AutoSegment::getCachedOnTargetContact ( unsigned int direction ) { return AutoSegments_CachedOnContact( getAutoTarget(), direction ); } AutoSegments AutoSegment::getAligneds ( unsigned int flags ) { cdebug_log(145,0) << "AutoSegment::getAligneds() - flags:" << flags << endl; return AutoSegments_Aligneds( this, flags ); } AutoSegments AutoSegment::getPerpandiculars () { return AutoSegments_Perpandiculars( this ); } bool AutoSegment::checkDepthSpin () const { bool valid = true; const Layer* sourceLayer = getAutoSource()->getLayer(); const Layer* targetLayer = getAutoTarget()->getLayer(); if ( (_flags & SegSourceTop) and (sourceLayer->getBottom() != getLayer()) ) { cerr << Error("%s\n" " Source is not going above, connected to *top* of %s." , getString(this).c_str() , getString(getAutoSource()).c_str() ) << endl; valid = false; } if ( (_flags & SegSourceBottom) and (sourceLayer->getTop() != getLayer()) ) { cerr << Error("%s\n" " Source is not going below, connected to *bottom* of %s." , getString(this).c_str() , getString(getAutoSource()).c_str() ) << endl; valid = false; } if ( (_flags & SegTargetTop) and (targetLayer->getBottom() != getLayer()) ) { cerr << Error("%s\n" " Target is not going above connected to *top* of %s." , getString(this).c_str() , getString(getAutoTarget()).c_str() ) << endl; valid = false; } if ( (_flags & SegTargetBottom) and (targetLayer->getTop() != getLayer()) ) { cerr << Error("%s\n" " Target is not going below, connected to *bottom* of %s." , getString(this).c_str() , getString(getAutoTarget()).c_str() ) << endl; valid = false; } return valid; } void AutoSegment::setFlagsOnAligneds ( unsigned int flags ) { setFlags( flags ); if (not isNotAligned()) { for( AutoSegment* segment : getAligneds() ) segment->setFlags( flags ); } } void AutoSegment::sourceDetach () { AutoContact* source = getAutoSource(); if (source) { if (source->isTurn()) { AutoSegment* perpandicular = source->getPerpandicular(this); if (perpandicular and perpandicular->isReduced()) decReduceds(); } base()->getSourceHook()->detach(); source->cacheDetach( this ); unsetFlags( SegNotSourceAligned ); setFlags( SegInvalidatedSource ); } } void AutoSegment::targetDetach () { AutoContact* target = getAutoTarget(); if (target) { if (target->isTurn()) { AutoSegment* perpandicular = target->getPerpandicular(this); if (perpandicular and perpandicular->isReduced()) decReduceds(); } base()->getTargetHook()->detach(); target->cacheDetach( this ); unsetFlags( SegNotTargetAligned ); setFlags( SegInvalidatedTarget ); } } void AutoSegment::sourceAttach ( AutoContact* source ) { if (source) { if (not base()->getSourceHook()->isAttached()) base()->getSourceHook()->attach( source->base()->getBodyHook() ); source->cacheAttach( this ); // if (source->isHTee() and isHorizontal()) return; // else if (source->isVTee() and isVertical ()) return; // setFlags( SegNotSourceAligned ); } } void AutoSegment::targetAttach ( AutoContact* target ) { if (target) { if (not base()->getTargetHook()->isAttached()) base()->getTargetHook()->attach( target->base()->getBodyHook() ); target->cacheAttach( this ); // if (target->isHTee() and isHorizontal()) return; // else if (target->isVTee() and isVertical ()) return; // setFlags( SegNotTargetAligned ); } } void AutoSegment::mergeUserConstraints ( const Interval& constraints ) { cdebug_log(149,0) << "mergeUserConstraints() " << this << endl; cdebug_log(149,0) << "| " << constraints << " merged with " << _userConstraints << endl; _userConstraints.intersection(constraints); } bool AutoSegment::toConstraintAxis ( unsigned int flags ) { cdebug_log(149,1) << "toConstraintAxis() " << this << endl; if (not isCanonical()) { cdebug_tabw(149,-1); return false; } DbU::Unit constraintMin; DbU::Unit constraintMax; getConstraints( constraintMin, constraintMax ); // Empty constraint interval: ignore. if (constraintMin > constraintMax) { cdebug_tabw(149,-1); return false; } if (isDogleg()) { DbU::Unit halfSideLength = getAutoSource()->getGCell()->getSide ( isHorizontal() ? Flags::Vertical : Flags::Horizontal ).getHalfSize(); constraintMin -= halfSideLength; constraintMax += halfSideLength; } if (getAxis() < constraintMin) { setAxis( constraintMin, flags ); cdebug_tabw(149,-1); return true; } if (getAxis() > constraintMax) { setAxis( constraintMax, flags ); cdebug_tabw(149,-1); return true; } cdebug_tabw(149,-1); return false; } bool AutoSegment::toOptimalAxis ( unsigned int flags ) { cdebug_log(149,1) << "toOptimalAxis() " << this << endl; if (not isCanonical()) { cdebug_tabw(149,-1); 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) { setAxis( optimalMin, flags ); cdebug_tabw(149,-1); return true; } if (getAxis() > optimalMax) { setAxis( optimalMax, flags ); cdebug_tabw(149,-1); return true; } if (flags & Flags::Realignate) setAxis( getAxis(), flags ); cdebug_tabw(149,-1); return false; } void AutoSegment::setAxis ( DbU::Unit axis, unsigned int flags ) { if (not isCanonical()) return; if ( (axis == getAxis()) and not (flags & Flags::Realignate) ) return; cdebug_log(159,0) << "setAxis() @" << ((isHorizontal())?"Y ":"X ") << DbU::toLambda(getAxis()) << " to " << DbU::toLambda(axis) << " on " << this << endl; cdebug_tabw(145,1); _setAxis( axis ); if (not isNotAligned()) { for ( AutoSegment* segment : getAligneds() ) { segment->_setAxis( getAxis() ); } } else { cdebug_log(149,0) << "No need to process parallels." << endl; } cdebug_tabw(145,-1); } void AutoSegment::computeTerminal () { AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); cdebug_log(145,0) << "computeTerminal() S:" << source->isTerminal() << " T:" << target->isTerminal() << " " << this << endl; if (source->isTerminal()) { unsetFlags( SegWeakTerminal ); setFlags ( SegSourceTerminal ); if (not target->isTerminal()) target->setFlags( CntWeakTerminal ); } else if (target->isTerminal()) { unsetFlags( SegWeakTerminal ); setFlags ( SegTargetTerminal ); if (not source->isTerminal()) source->setFlags( CntWeakTerminal ); } else { unsigned int terminalFlag = 0; switch ( _getFlags() & SegWeakTerminal ) { case 0: break; case SegSourceTerminal|SegTargetTerminal: case SegSourceTerminal: case SegTargetTerminal: terminalFlag = SegWeakTerminal1; break; case SegWeakTerminal1: terminalFlag = SegWeakTerminal1; break; case SegWeakTerminal2: terminalFlag = SegWeakTerminal2; break; default: cerr << Warning("%s has multiple terminal flag sets:%s (%x)." ,getString(this).c_str() ,_getStringFlags().c_str() ,_flags ) << endl; terminalFlag = SegWeakTerminal2; break; } unsetFlags( SegWeakTerminal ); setFlags ( terminalFlag ); } } void AutoSegment::computeOptimal ( set& processeds ) { cdebug_log(145,1) << "computeOptimal() - " << this << endl; DbU::Unit optimalMin; DbU::Unit optimalMax; DbU::Unit constraintMin; DbU::Unit constraintMax; getConstraints( constraintMin, constraintMax ); if (isUserDefined()) { optimalMin = optimalMax = getAxis(); } else { 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, getPerpandiculars() ) { cdebug_log(145,1) << "Perpandicular " << *autoSegment << endl; if (autoSegment->isLocal()) { if (not autoSegment->isStrongTerminal()) { cdebug_tabw(145,-1); continue; } DbU::Unit terminalMin; DbU::Unit terminalMax; if (getTerminalInterval( *autoSegment , NULL , isHorizontal() , terminalMin , terminalMax )) { attractors.addAttractor( terminalMin ); if (terminalMin != terminalMax) attractors.addAttractor( terminalMax ); } } else { #if THIS_IS_DISABLED bool isMin = true; if ( isHorizontal() and (autoSegment->getAutoSource()->getGCell()->getRow() == _gcell->getRow()) ) isMin = false; if ( isVertical() and (autoSegment->getAutoSource()->getGCell()->getColumn() == _gcell->getColumn()) ) isMin = false; attractors.addAttractor( (isMin) ? minGCell : maxGCell ); #endif // Sloppy implentation. DbU::Unit perpandMin = autoSegment->getSourceU(); DbU::Unit perpandMax = autoSegment->getTargetU(); if (perpandMin < minGCell) attractors.addAttractor( minGCell ); if (perpandMax > maxGCell) attractors.addAttractor( maxGCell ); } cdebug_tabw(145,-1); } if (attractors.getAttractorsCount()) { cdebug_log(145,0) << "Lower Median " << DbU::toLambda(attractors.getLowerMedian()) << endl; cdebug_log(145,0) << "Upper Median " << DbU::toLambda(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 ); cdebug_log(145,0) << "Applying constraint on: " << this << endl; setOptimalMin( optimalMin ); setOptimalMax( optimalMax ); processeds.insert( this ); if (not isNotAligned()) { for ( AutoSegment* autoSegment : getAligneds() ) { cdebug_log(145,0) << "Applying constraint on: " << autoSegment << endl; autoSegment->setOptimalMin( optimalMin ); autoSegment->setOptimalMax( optimalMax ); processeds.insert( autoSegment ); } } cdebug_tabw(145,-1); } AutoSegment* AutoSegment::canonize ( unsigned int flags ) { cdebug_log(149,0) << "canonize() - " << this << endl; // if (isCanonical() and isGlobal()) { // cdebug_log(149,0) << "* " << this << " canonical" << endl; // return this; // } vector segments; AutoSegment* canonical = this; bool hasCanonical = isCanonical(); bool hasGlobal = isGlobal(); if (not isNotAligned()) { forEach( AutoSegment*, isegment, getAligneds(flags) ) { if (isegment->isFixed()) continue; hasGlobal = hasGlobal or isegment->isGlobal(); segments.push_back( *isegment ); if (not hasCanonical) { if (isegment->isCanonical()) { cdebug_log(149,0) << "* " << *isegment << " canonical already set" << endl; canonical = *isegment; hasCanonical = true; } if (CompareId()(*isegment,canonical)) canonical = *isegment; } } canonical->setFlags( SegCanonical ); if (hasGlobal) { for ( size_t i=0 ; iisGlobal()) segments[i]->setFlags( SegWeakGlobal ); } } else { for ( size_t i=0 ; iunsetFlags( SegWeakGlobal ); } if (segments.empty()) setFlags( SegNotAligned ); if (isCanonical()) { cdebug_log(149,0) << "* " << this << " canonical" << endl; } else { cdebug_log(149,0) << "* " << this << " not canonical" << endl; cdebug_log(149,0) << "* " << canonical << " *is* the canonical" << endl; } } else { setFlags ( SegCanonical ); unsetFlags( SegWeakGlobal ); } return canonical; } size_t AutoSegment::getAlignedContacts ( map& innerContacts ) const { map::iterator icontact; innerContacts.clear(); innerContacts.insert( make_pair(getAutoSource(),0x1) ); innerContacts.insert( make_pair(getAutoTarget(),0x4) ); if (not isNotAligned()) { forEach ( AutoSegment*, isegment, const_cast(this)->getAligneds() ) { 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(); } Interval AutoSegment::getMinSpanU () const { map contacts; map::iterator icontact; getAlignedContacts( contacts ); DbU::Unit spanMin = DbU::Min; DbU::Unit spanMax = DbU::Max; Interval constraints; unsigned int direction = 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); } size_t AutoSegment::getPerpandicularsBound ( set& bounds ) { map contacts; map::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() ) { AutoSegment* autoSegment = Session::lookup ( *isegment ); if (not autoSegment) continue; if (autoSegment->getDirection() == getDirection()) continue; bounds.insert( autoSegment ); } } } return bounds.size(); } bool AutoSegment::isUTurn () const { if (isGlobal()) return false; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); cerr << "AutoSegment::isUTurn():" << endl; if (not source->isTurn() or not target->isTurn()) return false; cerr << " Turn connected" << endl; AutoSegment* perpandicular = source->getPerpandicular( this ); bool onPSourceSource = (perpandicular->getAutoSource() == source); perpandicular = target->getPerpandicular( this ); bool onPTargetSource = (perpandicular->getAutoSource() == target); cerr << " PSource:" << onPSourceSource << " PTarget:" << onPTargetSource << endl; return not (onPSourceSource xor onPTargetSource); } bool AutoSegment::isReduceCandidate () const { if (isGlobal()) return false; if (not isSpinTopOrBottom()) return false; if (_reduceds) return false; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); if (not source->isTurn() or not target->isTurn()) return false; return true; } bool AutoSegment::canReduce () const { if (isGlobal()) return false; if (not isSpinTopOrBottom()) return false; if (_reduceds) return false; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); if (not source->isTurn() or not target->isTurn()) return false; unsigned int perpandicularDepth = getDepth(); if (isSpinBottom()) --perpandicularDepth; else if (isSpinTop()) { ++perpandicularDepth; if (perpandicularDepth >= Session::getDepth()) return false; } else return false; if (getLength() >= (Session::getPitch(perpandicularDepth) * 2)) return false; return true; } bool AutoSegment::reduce () { if (not canReduce()) return false; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); _flags |= SegIsReduced; source->getPerpandicular( this )->incReduceds(); target->getPerpandicular( this )->incReduceds(); return true; } bool AutoSegment::mustRaise () const { if (not (_flags & SegIsReduced)) return false; unsigned int perpandicularDepth = getDepth(); if (isSpinBottom()) --perpandicularDepth; else if (isSpinTop ()) ++perpandicularDepth; else return true; return (getLength() >= (Session::getPitch(perpandicularDepth) * 2)); } bool AutoSegment::raise () { if (not (_flags & SegIsReduced)) return false; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); _flags &= ~SegIsReduced; source->getPerpandicular( this )->decReduceds(); target->getPerpandicular( this )->decReduceds(); return true; } void AutoSegment::changeDepth ( unsigned int depth, unsigned int flags ) { cdebug_log(149,1) << "changeDepth() " << depth << " - " << this << endl; Session::invalidate( getNet() ); _changeDepth( depth, flags & ~Flags::Propagate ); if ((flags & Flags::Propagate) and not isNotAligned()) { forEach ( AutoSegment*, isegment, getAligneds(Flags::NoCheckLayer) ) { (*isegment)->_changeDepth( depth, flags & ~Flags::Propagate ); } } cdebug_tabw(149,-1); } void AutoSegment::_changeDepth ( unsigned int depth, unsigned int flags ) { cdebug_log(149,1) << "_changeDepth() - " << this << endl; invalidate( Flags::NoFlags ); setFlags( SegInvalidatedLayer|SegInvalidatedSource|SegInvalidatedTarget ); const Layer* newLayer = Session::getRoutingGauge()->getRoutingLayer(depth); if (getLayer() != newLayer) { setLayer( newLayer ); getAutoSource()->invalidate( Flags::Topology|Flags::NoCheckLayer ); getAutoTarget()->invalidate( Flags::Topology|Flags::NoCheckLayer ); } if (not (flags & Flags::WithNeighbors)) { cdebug_tabw(149,-1); return; } forEach ( AutoSegment*, isegment, getCachedOnSourceContact(Flags::DirectionMask) ) { if ((*isegment) == this) continue; if ((*isegment)->isGlobal ()) continue; if ((*isegment)->isTerminal()) continue; if (not ((*isegment)->isHorizontal() xor isHorizontal())) (*isegment)->_changeDepth( depth , Flags::NoFlags ); else (*isegment)->_changeDepth( depth-1, Flags::NoFlags ); } forEach ( AutoSegment*, isegment, getCachedOnTargetContact(Flags::DirectionMask) ) { if ((*isegment) == this) continue; if ((*isegment)->isGlobal ()) continue; if ((*isegment)->isTerminal()) continue; if (not ((*isegment)->isHorizontal() xor isHorizontal())) (*isegment)->_changeDepth( depth , Flags::NoFlags ); else (*isegment)->_changeDepth( depth-1, Flags::NoFlags ); } vector gcells; getGCells( gcells ); for ( size_t i=0 ; iinvalidate(); cdebug_tabw(149,-1); } bool AutoSegment::canSlacken ( unsigned int flags ) const { cdebug_log(149,0) << "AutoSegment::canSlacken()" << endl; if (not isGlobal() and not (flags & Flags::Propagate)) return false; if (_canSlacken()) return true; if ((flags & Flags::Propagate) and not isNotAligned()) { forEach ( AutoSegment*, isegment, const_cast(this)->getAligneds() ) { if (isegment->_canSlacken()) return true; } } return false; } bool AutoSegment::slacken ( unsigned int flags ) { bool success = false; success = success or _slacken( flags ); if ((flags & Flags::Propagate) and not isNotAligned()) { forEach ( AutoSegment*, isegment, getAligneds() ) { success = success or (*isegment)->_slacken( flags ); } } return success; } float AutoSegment::getMaxUnderDensity ( unsigned int flags ) { cdebug_log(149,0) << "AutoSegment::getMaxUnderDensity() " << endl; size_t depth = Session::getRoutingGauge()->getLayerDepth(getLayer()); vector gcells; getGCells( gcells ); float maxDensity = 0.0; for ( size_t i=0 ; igetFeedthroughs(depth) ); } if ((flags & Flags::Propagate) and not isNotAligned()) { forEach ( AutoSegment*, isegment, getAligneds() ) { isegment->getGCells( gcells ); for ( size_t i=0 ; igetFeedthroughs(depth) ); } } } return maxDensity; } bool AutoSegment::canPivotUp ( float reserve, unsigned int flags ) const { cdebug_log(149,0) << "AutoSegment::canPivotUp() - " << flags << " (reserve:" << reserve << ")" << endl; if ( isLayerChange() or isFixed() ) return false; if ( isStrongTerminal() or isLocal() ) return false; size_t depth = Session::getRoutingGauge()->getLayerDepth( getLayer() ); if (depth+2 >= Session::getRoutingGauge()->getDepth()) return false; vector gcells; getGCells( gcells ); for ( size_t i=0 ; ihasFreeTrack(depth+2,reserve)) return false; } if ( not (flags&Flags::IgnoreContacts) ) { cdebug_log(149,0) << getAutoSource() << endl; cdebug_log(149,0) << getAutoTarget() << endl; cdebug_log(149,0) << "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 & Flags::Propagate) and not isNotAligned()) { forEach ( AutoSegment*, isegment, const_cast(this)->getAligneds(flags) ) { isegment->getGCells( gcells ); for ( size_t i=0 ; ihasFreeTrack(depth+2,reserve)) return false; } if (isegment->getAutoSource()->getMinDepth() < depth) return false; if (isegment->getAutoTarget()->getMinDepth() < depth) return false; } } else { cdebug_log(149,0) << "AutoSegment::canPivotUp() - true [no propagate]" << endl; return true; } cdebug_log(149,0) << "AutoSegment::canPivotUp() - true [propagate]" << endl; return true; } bool AutoSegment::canPivotDown ( float reserve, unsigned int flags ) const { cdebug_log(149,0) << "AutoSegment::canPivotDown()" << " (reserve:" << reserve << ")" << endl; if ( isLayerChange() or isFixed() ) return false; if ( isStrongTerminal() or isLocal() ) return false; size_t depth = Session::getRoutingGauge()->getLayerDepth( getLayer() ); if (depth < 3) return false; vector gcells; getGCells( gcells ); for ( size_t i=0 ; ihasFreeTrack(depth-2,reserve)) return false; } cdebug_log(149,0) << getAutoSource() << endl; cdebug_log(149,0) << getAutoTarget() << endl; cdebug_log(149,0) << "max depths, Segment:" << depth << " S:" << getAutoSource()->getMaxDepth() << " T:" << getAutoTarget()->getMaxDepth() << endl; if (getAutoSource()->getMaxDepth() > depth) return false; if (getAutoTarget()->getMaxDepth() > depth) return false; if (not (flags & Flags::Propagate)) { cdebug_log(149,0) << "AutoSegment::canPivotDown() - true [no propagate]" << endl; return true; } if ((flags & Flags::Propagate) and not isNotAligned()) { forEach ( AutoSegment*, isegment, const_cast(this)->getAligneds() ) { isegment->getGCells( gcells ); for ( size_t i=0 ; ihasFreeTrack(depth-2,reserve)) return false; } if (isegment->getAutoSource()->getMaxDepth() < depth) return false; if (isegment->getAutoTarget()->getMaxDepth() < depth) return false; } } cdebug_log(149,0) << "AutoSegment::canPivotDown() - true [propagate]" << endl; return true; } bool AutoSegment::canMoveUp ( float reserve, unsigned int flags ) const { cdebug_log(149,0) << "AutoSegment::canMoveUp() " << flags << " (reserve:" << reserve << ")" << endl; bool lowDensity = true; GCell* begin = NULL; GCell* end = NULL; if ( isLayerChange() or isFixed() ) return false; if ( isStrongTerminal() and (not (flags & Flags::AllowTerminal)) ) return false; if ( isLocal() and (not (flags & Flags::AllowLocal )) ) return false; size_t depth = Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2; if (depth > Session::getConfiguration()->getAllowedDepth()) return false; vector gcells; getGCells( gcells ); begin = *gcells.begin (); end = *gcells.rbegin(); for ( size_t i=0 ; igetWDensity(depth-2) > 0.5) ) lowDensity = false; if (not gcells[i]->hasFreeTrack(depth,reserve)) { cdebug_log(149,0) << "Not enough free track in " << gcells[i] << endl; return false; } } cdebug_log(149,0) << "Enough free track under canonical segment." << endl; if ( isLocal() and not (flags & Flags::Propagate) ) { if (not getAutoSource()->canMoveUp(this)) return false; if (not getAutoTarget()->canMoveUp(this)) return false; return true; } //bool hasGlobalSegment = false; if ((flags & Flags::Propagate) and not isNotAligned()) { forEach ( AutoSegment*, isegment, const_cast(this)->getAligneds(flags) ) { if (isegment->isFixed ()) return false; //if (isegment->isGlobal()) hasGlobalSegment = true; 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 ; igetWDensity(depth-2) > 0.6) ) lowDensity = false; if (not gcells[i]->hasFreeTrack(depth,reserve)) { cdebug_log(149,0) << "Not enough free track in " << gcells[i] << endl; return false; } } } } if (lowDensity and (flags & Flags::CheckLowDensity)) return false; if ( (depth >= 4) and (flags & Flags::WithPerpands) ) { float fragmentation = begin->getFragmentation( depth-1 ); cdebug_log(149,0) << "Check begin GCell perpandicular fragmentation: " << fragmentation << endl; if (fragmentation < 0.5) { cdebug_log(149,0) << "Not enough free track for perpandicular in begin GCell " << "(frag:" << fragmentation << ")." << endl; return false; } fragmentation = end->getFragmentation( depth-1 ); cdebug_log(149,0) << "Check end GCell perpandicular fragmentation: " << fragmentation << endl; if (fragmentation < 0.5) { cdebug_log(149,0) << "Not enough free track for perpandicular in end GCell " << "(frag:" << fragmentation << ")." << endl; return false; } } return true; } bool AutoSegment::moveUp ( unsigned int flags ) { //if ( not canMoveUp(0.0,flags) ) return false; changeDepth( Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2, flags&Flags::Propagate ); return true; } bool AutoSegment::moveDown ( unsigned int flags ) { //if ( not canPivotDown(0.0,flags) ) return false; changeDepth( Session::getRoutingGauge()->getLayerDepth(getLayer()) - 2, flags&Flags::Propagate ); return true; } bool AutoSegment::reduceDoglegLayer () { if (not isReduced()) return true; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); unsigned int perpandicularDepth = getDepth(); if (isSpinBottom()) --perpandicularDepth; if (isSpinTop ()) ++perpandicularDepth; if (perpandicularDepth == getDepth()) { cerr << Bug( "AutoSegment::reduceDoglegLayer(): Reduced segment spin is neither top (TT) nor bottom (BB).\n" " %s" , getString(this).c_str() ) << endl; return false; } source->setLayer( Session::getRoutingLayer(perpandicularDepth) ); target->setLayer( Session::getRoutingLayer(perpandicularDepth) ); setLayer( Session::getRoutingLayer(perpandicularDepth) ); return true; } #if THIS_IS_DISABLED bool AutoSegment::shearUp ( GCell* upGCell, AutoSegment*& movedUp, float reserve, unsigned int flags ) { cdebug_log(149,0) << "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 gcells; getGCells ( gcells ); size_t iupGCell = 0; for ( ; iupGCellhasFreeTrack(upDepth,reserve) ) { cdebug_log(149,0) << "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) ) { cdebug_log(149,0) << "Left shearing @ " << gcells[i] << endl; leftShear = gcells[i]; } } while (i > 0); } AutoSegment* before = this; const vector& 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; } #endif unsigned int AutoSegment::canDogleg ( Interval interval ) { cdebug_log(149,0) << "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++; if (not isNotAligned()) { forEach ( AutoSegment*, isegment, getAligneds() ) { if (isegment->getSpanU().contains(interval.getVMin())) { if (isegment->isFixed()) return false; leftDogleg++; } if (isegment->getSpanU().contains(interval.getVMax())) { if (isegment->isFixed()) return 0; rightDogleg++; } } } if ( (leftDogleg == 1) and (rightDogleg <= 1) ) return Flags::DoglegOnLeft; if ( (leftDogleg <= 1) and (rightDogleg == 1) ) return Flags::DoglegOnRight; cdebug_log(149,0) << "leftCount:" << leftDogleg << " rightCount:" << rightDogleg << endl; return 0; } AutoSegment* AutoSegment::makeDogleg ( AutoContact* from ) { cdebug_log(149,1) << "AutoSegment::makeDogleg(AutoContact*) " << from << endl; cdebug_log(149,0) << this << endl; RoutingGauge* rg = Session::getRoutingGauge(); size_t segmentDepth = rg->getLayerDepth( getLayer() ); const vector& doglegs = Session::getDoglegs(); size_t index = doglegs.size(); bool isSource = (getAutoSource() == from); cdebug_log(149,0) << "isSource:" << isSource << endl; makeDogleg( from->getGCell(), Flags::NoCheckLayer ); if (doglegs.size() == index) { cdebug_tabw(149,-1); return NULL; } doglegs[ index+1 ]->setAxis( isHorizontal() ? from->getX() : from->getY() ); if (not from->getLayer()->contains(getLayer())) { cdebug_log(149,0) << "Contact layer do not contains Segment layer, adjust layers" << endl; if (getLayer()->above(from->getLayer())) { cdebug_log(149,0) << "Go Down from depth " << segmentDepth << endl; doglegs[ index + 1 ]->setLayer( rg->getRoutingLayer(segmentDepth-1) ); cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1] << endl; if (isSource) { doglegs[ index + 0 ]->setLayer( rg->getRoutingLayer(segmentDepth-2) ); doglegs[ index + 1 ]->getAutoSource()->setLayer( rg->getContactLayer(segmentDepth-2) ); doglegs[ index + 1 ]->getAutoTarget()->setLayer( rg->getContactLayer(segmentDepth-1) ); cdebug_log(149,0) << "doglegs[i+0]: " << doglegs[index+0] << endl; cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoSource() << endl; cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoTarget() << endl; } else { doglegs[ index + 2 ]->setLayer( rg->getRoutingLayer(segmentDepth-2) ); doglegs[ index + 1 ]->getAutoTarget()->setLayer( rg->getContactLayer(segmentDepth-2) ); doglegs[ index + 1 ]->getAutoSource()->setLayer( rg->getContactLayer(segmentDepth-1) ); cdebug_log(149,0) << "doglegs[i+2]: " << doglegs[index+2] << endl; cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoTarget() << endl; cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoSource() << endl; } } else { cdebug_log(149,0) << "Go Up from depth " << segmentDepth << endl; doglegs[ index + 1 ]->setLayer( rg->getRoutingLayer(segmentDepth+1) ); cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1] << endl; if (isSource) { doglegs[ index + 0 ]->setLayer( rg->getRoutingLayer(segmentDepth+2) ); doglegs[ index + 1 ]->getAutoSource()->setLayer( rg->getContactLayer(segmentDepth+1) ); doglegs[ index + 1 ]->getAutoTarget()->setLayer( rg->getContactLayer(segmentDepth ) ); cdebug_log(149,0) << "doglegs[i+0]: " << doglegs[index+0] << endl; cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoSource() << endl; cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoTarget() << endl; } else { doglegs[ index + 2 ]->setLayer( rg->getRoutingLayer(segmentDepth+2) ); doglegs[ index + 1 ]->getAutoTarget()->setLayer( rg->getContactLayer(segmentDepth+1) ); doglegs[ index + 1 ]->getAutoSource()->setLayer( rg->getContactLayer(segmentDepth ) ); cdebug_log(149,0) << "doglegs[i+2]: " << doglegs[index+2] << endl; cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoTarget() << endl; cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoSource() << endl; } } } cdebug_tabw(149,-1); return doglegs[ index + (isSource?0:2) ]; } unsigned int AutoSegment::makeDogleg ( Interval interval, unsigned int flags ) { cdebug_log(149,1) << "AutoSegment::makeDogleg(Interval) - " << interval << endl; bool leftDogleg = true; unsigned int rflags = 0; 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++; } if (not isNotAligned()) { forEach ( AutoSegment*, isegment, getAligneds(flags) ) { if (isegment->getSpanU().contains(interval.getVMin())) { leftCandidate = *isegment; leftDoglegCount++; } if (isegment->getSpanU().contains(interval.getVMax())) { rightCandidate = *isegment; rightDoglegCount++; } } } if ( (leftDoglegCount != 1) and (rightDoglegCount != 1) ) { cdebug_tabw(149,-1); return 0; } if (not leftDoglegCount) { leftDogleg = false; leftCandidate = rightCandidate; rightCandidate = NULL; } if (leftCandidate and rightCandidate) { cdebug_log(149,0) << "Left Constraint: " << leftCandidate->getSourceConstraints(Flags::NativeConstraints) << endl; cdebug_log(149,0) << "Right Constraint: " << rightCandidate->getTargetConstraints(Flags::NativeConstraints) << endl; if ( leftCandidate ->getTargetConstraints(Flags::NativeConstraints).getSize() < rightCandidate->getSourceConstraints(Flags::NativeConstraints).getSize() ) { leftCandidate = rightCandidate; leftDogleg = false; } } else { if (not leftCandidate) { leftCandidate = rightCandidate; leftDogleg = false; } } if (leftCandidate) { DbU::Unit axis; // Ugly: Hard-wired track spacing. if (leftDogleg) axis = interval.getVMin() - getPitch(); else axis = interval.getVMax() + getPitch(); cdebug_log(149,0) << "Break @" << DbU::getValueString(axis) << " " << leftCandidate << endl; unsigned int direction = getDirection(); GCell* gcell = leftCandidate->getAutoSource()->getGCell(); GCell* end = leftCandidate->getAutoTarget()->getGCell(); while ( gcell != end ) { if (gcell->getSide(direction).contains(axis)) break; gcell = (direction == Flags::Horizontal) ? gcell->getEast (getNativeMin()) : gcell->getNorth(getNativeMin()); } cdebug_log(149,0) << "In " << gcell << endl; rflags = leftCandidate->_makeDogleg( gcell, flags ); const vector& doglegs = Session::getDoglegs(); if (doglegs.size() >= 2) { cdebug_log(149,0) << "AutoSegment::makeDogleg(): @" << DbU::getValueString(axis) << endl; doglegs[1]->setAxis( axis ); } } cdebug_tabw(149,-1); return rflags | (leftDogleg ? Flags::DoglegOnLeft : Flags::DoglegOnRight); } unsigned int AutoSegment::makeDogleg ( GCell* doglegGCell, unsigned int flags ) { cdebug_log(9000,0) << "Deter| AutoSegment::makeDogleg(GCell*) " << doglegGCell << endl; cdebug_log(9000,0) << "Deter| in " << this << endl; cdebug_tabw(149,1); unsigned int rflags = 0; if ( doglegGCell->isIoPad() and (Session::getAnabatic()->getState() != EngineGlobalLoaded) ) { cerr << Bug( "Attempt to make a dogleg in a GCell under a Pad\n" " %s\n" " %s" , getString(this).c_str() , getString(doglegGCell).c_str() ) << endl; } if (isFixed()) { cerr << Error( "AutoSegment::makeDogleg(): Cannot make a dog leg on a fixed segment.\n" " (on: %s)", _getString().c_str() ) << endl; return 0; } if (doglegGCell->getSide(getDirection()).intersect(getSpanU())) { cdebug_log(149,0) << "Dogleg in " << this << " spanU:" << getSpanU() << endl; rflags = _makeDogleg( doglegGCell, flags ); } else { cdebug_log(149,0) << "Looking in aligneds." << endl; if (not isNotAligned()) { forEach ( AutoSegment*, aligned, getAligneds(flags) ) { cdebug_log(149,0) << "| Try in " << *aligned << endl; if (doglegGCell->getSide(getDirection()).intersect(aligned->getSpanU())) { cdebug_log(149,0) << "Dogleg in " << *aligned << endl; rflags = aligned->_makeDogleg( doglegGCell, flags ); cdebug_tabw(149,-1); return 0; } } } cerr << Bug("Cannot make a dogleg in %s at %s" ,_getString().c_str(), getString(doglegGCell).c_str()) << endl; } cdebug_tabw(149,-1); return rflags; } bool AutoSegment::_check () const { bool coherency = true; coherency = checkNotInvalidated() and coherency; coherency = checkPositions() and coherency; coherency = checkConstraints() and coherency; coherency = checkDepthSpin() and coherency; return coherency; } string AutoSegment::_getStringFlags () const { string state; state += isFixed () ?" F":" -"; state += isUnsetAxis () ? "u": "-"; state += isStrap () ? "S": "-"; state += isCanonical () ? "C": "-"; state += isGlobal () ? "G": "-"; state += isWeakGlobal () ? "g": "-"; state += isStrongTerminal() ? "T": "-"; state += isWeakTerminal1 () ? "W": "-"; state += isWeakTerminal2 () ? "w": "-"; state += isNotAligned () ? "A": "-"; state += isSlackened () ? "S": "-"; state += isReduced () ? "r": "-"; state += isInvalidated () ? "i": "-"; if (_flags & SegSourceTop) state += 'T'; else if (_flags & SegSourceBottom) state += 'B'; else state += '-'; if (_flags & SegTargetTop) state += 'T'; else if (_flags & SegTargetBottom) state += 'B'; else state += '-'; return state; } string AutoSegment::_getString () const { string s = base()->_getString(); //s.insert ( 1, "id: " ); //s.insert ( 4, getString(_id) ); s.insert ( s.size()-1, _getStringFlags() ); return s; } Record* AutoSegment::_getRecord () const { Record* record = base()->_getRecord (); record->add ( getSlot ( "_gcell" , _gcell ) ); record->add ( getSlot ( "_id" , &_id ) ); record->add ( getSlot ( "_flags" , &_flags ) ); record->add ( getSlot ( "_userContraints", &_userConstraints ) ); record->add ( getSlot ( "_sourcePosition", &_sourcePosition ) ); record->add ( getSlot ( "_targetPosition", &_targetPosition ) ); record->add ( getSlot ( "_parent" , _parent ) ); return record; } AutoSegment* AutoSegment::create ( AutoContact* source , AutoContact* target , Segment* hurricaneSegment ) { static const Layer* horizontalLayer = Session::getRoutingLayer( 1 ); static DbU::Unit horizontalWidth = Session::getWireWidth ( 1 ); static const Layer* verticalLayer = Session::getRoutingLayer( 2 ); static DbU::Unit verticalWidth = Session::getWireWidth ( 2 ); bool reattachSource = false; bool reattachTarget = false; AutoSegment* segment; Horizontal* horizontal = dynamic_cast( hurricaneSegment ); Vertical* vertical = dynamic_cast( hurricaneSegment ); AutoContact* reference = source; cdebug_log(149,0) << "Source:" << source << endl; cdebug_log(149,0) << "Target:" << target << endl; if (target->isFixed()) { if (source->isFixed()) { if ( (horizontal) and (source->getY() != target->getY())) cerr << Warning( "Straight AutoHorizontal connecting misaligned contacts:\n" " %s\n" " %s" , getString(source).c_str() , getString(target).c_str() ) << endl; if ( (vertical) and (source->getX() != target->getX())) cerr << Warning( "Straight AutoVertical connecting misaligned contacts:\n" " %s\n" " %s" , getString(source).c_str() , getString(target).c_str() ) << endl; } else reference = target; } Contact* contact = dynamic_cast( hurricaneSegment->getSource() ); AutoContact* autoContact = Session::lookup( contact ); if (contact == NULL) { throw Error( badSegmentSource, getString(hurricaneSegment).c_str() ); if ( autoContact and (autoContact != source) ) throw Error( mismatchSegmentSource , getString(hurricaneSegment).c_str() , getString(contact).c_str() ); } else { if (autoContact != source) reattachSource = true; } contact = dynamic_cast( hurricaneSegment->getTarget() ); autoContact = Session::lookup( contact ); if (contact == NULL) { throw Error( badSegmentTarget, getString(hurricaneSegment).c_str() ); if ( autoContact and (autoContact != target) ) throw Error ( mismatchSegmentTarget , getString(hurricaneSegment).c_str() , getString(contact).c_str() ); } else { if (autoContact != source) reattachTarget = true; } if (reattachSource) { Hook* hook = hurricaneSegment->getSourceHook(); hook->detach (); hook->attach ( source->getBodyHook() ); } if (reattachTarget) { Hook* hook = hurricaneSegment->getTargetHook(); hook->detach (); hook->attach ( target->getBodyHook() ); } if (horizontal) { if (horizontal->getLayer() != horizontalLayer) { if (Session::getAnabatic()->getConfiguration()->isGMetal(horizontal->getLayer())) { horizontal->setLayer( horizontalLayer ); horizontal->setWidth( horizontalWidth ); } else { if (horizontal->getWidth() != horizontalWidth) { cerr << Warning("Segment %s has non-default width %s." ,getString(horizontal).c_str() ,DbU::getValueString(horizontal->getWidth()).c_str()) << endl; } } } horizontal->setY( reference->getY() ); segment = new AutoHorizontal ( horizontal ); segment->_postCreate(); } else if (vertical) { if (vertical->getLayer() != verticalLayer) { if (Session::getAnabatic()->getConfiguration()->isGMetal(vertical->getLayer()) ) vertical->setLayer( verticalLayer ); vertical->setWidth( verticalWidth ); } else { if (vertical->getWidth() != verticalWidth) { cerr << Warning("Segment %s has non-default width %s." ,getString(vertical).c_str() ,DbU::getValueString(vertical->getWidth()).c_str()) << endl; } } vertical->setX( reference->getX() ); segment = new AutoVertical ( vertical ); segment->_postCreate(); } else { throw Error( badSegment, getString(source).c_str(), getString(target).c_str() ); } return segment; } AutoSegment* AutoSegment::create ( AutoContact* source , AutoContact* target , unsigned int dir , size_t depth ) { // Hardcoded: make the assumption that, // depth=0 is terminal reserved | METAL1 // depth=1 is horizontal | METAL2 // depth=2 is vertical | METAL3 // Should be based on gauge informations. static const Layer* hLayer = Session::getRoutingLayer( 1 ); static DbU::Unit hWidth = Session::getWireWidth ( 1 ); static const Layer* vLayer = Session::getRoutingLayer( 2 ); static DbU::Unit vWidth = Session::getWireWidth ( 2 ); const Layer* horizontalLayer = hLayer; DbU::Unit horizontalWidth = hWidth; const Layer* verticalLayer = vLayer; DbU::Unit verticalWidth = vWidth; if (depth != RoutingGauge::nlayerdepth) { horizontalLayer = verticalLayer = Session::getRoutingLayer( depth ); horizontalWidth = verticalWidth = Session::getWireWidth ( depth ); } AutoSegment* segment; AutoContact* reference = source; cdebug_log(149,0) << "Source:" << source << endl; cdebug_log(149,0) << "Target:" << target << endl; if (target->isFixed()) { if (source->isFixed()) { if ( (dir == Flags::Horizontal) and (source->getY() != target->getY())) cerr << Warning( "Straight AutoHorizontal connecting misaligned contacts:\n" " %s\n" " %s" , getString(source).c_str() , getString(target).c_str() ) << endl; if ( (dir == Flags::Vertical) and (source->getX() != target->getX())) cerr << Warning( "Straight AutoVertical connecting misaligned contacts:\n" " %s\n" " %s" , getString(source).c_str() , getString(target).c_str() ) << endl; } else reference = target; } if (dir & Flags::Horizontal) { segment = create( source , target , Horizontal::create( source->base() , target->base() , horizontalLayer , reference->getY() , horizontalWidth ) ); } else if (dir & Flags::Vertical) { segment = create( source , target , Vertical::create( source->base() , target->base() , verticalLayer , reference->getX() , verticalWidth ) ); } else throw Error( badSegment, getString(source).c_str(), getString(target).c_str() ); return segment; } void AutoSegment::destroy () { _preDestroy (); delete this; } bool AutoSegment::isTopologicalBound ( AutoSegment* seed, unsigned int flags ) { cdebug_log(145,1) << "isTopologicalBound() - " << seed << endl; set exploreds; vector stack; DbU::Unit axis; if (flags & Flags::Superior) axis = seed->getTargetU(); else axis = seed->getSourceU(); cdebug_log(145,0) << "check for bound " << DbU::getValueString(axis) << endl; exploreds.insert( seed->getAutoSource() ); exploreds.insert( seed->getAutoTarget() ); if (seed->getLength()) { if (flags & Flags::Superior) stack.push_back( seed->getAutoTarget() ); else stack.push_back( seed->getAutoSource() ); } else { stack.push_back( seed->getAutoTarget() ); stack.push_back( seed->getAutoSource() ); } while ( not stack.empty() ) { AutoContact* currentContact = stack.back(); stack.pop_back(); cdebug_log(145,0) << "Exploring: " << (void*)currentContact << " " << currentContact << endl; exploreds.insert( currentContact ); if (currentContact->getAnchor()) { cdebug_tabw(145,-1); return true; } forEach ( Component*, component, currentContact->getSlaveComponents() ) { Segment* segment = dynamic_cast( *component ); if (not segment) continue; AutoSegment* autoSegment = Session::lookup( segment ); if (not autoSegment) continue; if (not autoSegment->getLength()) { AutoContact* contact = autoSegment->getAutoSource(); if (contact and (contact != currentContact)) { if (exploreds.find(contact) == exploreds.end()) stack.push_back( contact ); } contact = autoSegment->getAutoTarget(); if (contact and (contact != currentContact)) { if (exploreds.find(contact) == exploreds.end()) stack.push_back( contact ); } continue; } if (autoSegment->isHorizontal() xor (flags & Flags::Horizontal)) continue; cdebug_log(145,0) << "| " << autoSegment << endl; if (flags & Flags::Superior) { if (autoSegment->getTargetU() > axis) { cdebug_tabw(145,-1); return true; } } else { if (autoSegment->getSourceU() < axis) { cdebug_tabw(145,-1); return true; } } } } cdebug_tabw(145,-1); return false; } #if THIS_IS_DISABLED 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; } #endif void AutoSegment::getTopologicalInfos ( AutoSegment* seed , vector& aligneds , vector& perpandiculars , DbU::Unit& leftBound , DbU::Unit& rightBound ) { cdebug_log(145,1) << "getTopologicalInfos() - " << seed << endl; leftBound = DbU::Max; rightBound = DbU::Min; AutoSegmentStack stack; stack.push( seed->getAutoSource(), seed ); stack.push( seed->getAutoTarget(), seed ); while ( not stack.isEmpty() ) { 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; cdebug_log(149,0) << "Segments of: " << sourceContact << endl; LocatorHelper helper (sourceContact, Flags::Horizontal|Flags::WithPerpands); for ( ; helper.isValid() ; helper.progress() ) { AutoSegment* currentSegment = helper.getSegment(); cdebug_log(149,0) << "Looking for: " << currentSegment << endl; if (currentSegment == sourceSegment) continue; if (AutoSegment::areAlignedsAndDiffLayer(currentSegment,seed)) { cerr << Error("Aligned segments not in same layer\n" " %s\n" " %s." ,getString(seed).c_str() ,getString(currentSegment).c_str()) << endl; continue; } if (AutoSegment::areAligneds(currentSegment,seed)) { aligneds.push_back( currentSegment ); AutoContact* targetContact = currentSegment->getOppositeAnchor( sourceContact ); cdebug_log(149,0) << "Target: " << targetContact << endl; if (targetContact) { if ( (seed->isHorizontal() and sourceContact->isHTee()) or (seed->isVertical () and sourceContact->isVTee()) ) { cdebug_log(149,0) << "Stacking target. " << endl; stack.push( targetContact, currentSegment ); } } } else { cdebug_log(149,0) << "| perpandicular " << currentSegment << endl; perpandiculars.push_back( currentSegment ); } } } cdebug_tabw(145,-1); } int AutoSegment::getTerminalCount ( AutoSegment* seed, vector& collapseds ) { cdebug_log(145,0) << "getTerminalCount() - " << seed << " (+collapseds)" << endl; int count = 0; for ( size_t i=0 ; i < collapseds.size() ; i++ ) { if (collapseds[i]->isStrongTerminal()) count++; } if (seed->getAutoSource()->isTerminal()) count++; if (seed->getAutoTarget()->isTerminal()) count++; return count; } } // End of Anabatic namespace.