// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2008-2018, 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 #include "hurricane/DebugSession.h" #include "hurricane/Warning.h" #include "hurricane/Bug.h" #include "hurricane/DataBase.h" #include "hurricane/Technology.h" #include "hurricane/ViaLayer.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::getValueString(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; } // --------------------------------------------------------------- // Class : "SideStack". class SideStack { public: SideStack ( Flags direction, DbU::Unit pitch ); inline bool isHoled () const; const Interval& getSideAt ( DbU::Unit ) const; inline const Interval& getGSide () const; inline DbU::Unit getGSideMin () const; inline DbU::Unit getGSideMax () const; inline DbU::Unit getGSideCenter () const; void addGCell ( const GCell* ); inline bool intersect ( const Interval& ) const; inline void restrictGSide ( const Interval& ); void show () const; private: Flags _direction; bool _holed; DbU::Unit _pitch; Interval _full; Interval _gside; map _sides; }; SideStack::SideStack ( Flags direction, DbU::Unit pitch ) : _direction( (direction & Flags::Horizontal) ? Flags::Vertical : Flags::Horizontal ) , _holed (false) , _pitch (pitch) , _full (false) , _gside (false) , _sides () { } inline bool SideStack::isHoled () const { return _holed; } inline const Interval& SideStack::getGSide () const { return _gside; } inline DbU::Unit SideStack::getGSideMin () const { return _gside.getVMin(); } inline DbU::Unit SideStack::getGSideMax () const { return _gside.getVMax(); } inline DbU::Unit SideStack::getGSideCenter () const { return _gside.getVMax(); } inline bool SideStack::intersect ( const Interval& side ) const { return _gside.intersect(side); } inline void SideStack::restrictGSide ( const Interval& restrict ) { if (not _holed) _gside.intersection(restrict); } const Interval& SideStack::getSideAt ( DbU::Unit position ) const { if (_sides.empty()) return _full; if (_sides.size() == 1) return _sides.begin()->second; if (_sides.begin()->first > position) return _sides.begin()->second; for ( auto iside = ++_sides.begin() ; iside != _sides.end() ; ++iside ) { if (iside->first >= position) return (--iside)->second; } return _sides.rbegin()->second; } void SideStack::addGCell ( const GCell* gcell ) { Interval side = gcell->getSide( _direction, _pitch ); DbU::Unit position = (_direction & Flags::Vertical) ? gcell->getBoundingBox().getXMin() : gcell->getBoundingBox().getYMin(); if (not _holed and intersect(side)) _gside.intersection( side ); else { if (not _holed) { _holed = true; if (side.getVMin() > _gside.getVMax()) _gside = Interval( _gside.getVMax(), side.getVMin() ); else _gside = Interval( side.getVMax(), _gside.getVMin() ); } else { if (not intersect(side)) { if (side.getVMax() < _gside.getVMin()) _gside.merge( side.getVMax() ); else _gside.merge( side.getVMin() ); } } } _sides.insert( make_pair(position,side) ); } void SideStack::show () const { cdebug_log(145,0) << "SideStack::show()" << endl; for ( auto pside : _sides ) { cdebug_log(145,0) << "@ " << DbU::getValueString(pside.first) << " " << pside.second << endl; } } } // 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 false; deltaUnit = lhs->getAxis() - rhs->getAxis(); if ( deltaUnit < 0 ) return true; // Smallest axis first. if ( deltaUnit > 0 ) return false; #if THIS_IS_DISABLED 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(); #endif 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::CompareBySourceU". bool AutoSegment::CompareBySourceU::operator() ( AutoSegment* lhs, AutoSegment* rhs ) const { DbU::Unit 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; bool AutoSegment::_analogMode = false; bool AutoSegment::_shortNetMode = false; bool AutoSegment::_initialized = false; vector< array > AutoSegment::_extensionCaps; void AutoSegment::setAnalogMode ( bool state ) { _analogMode = state; } bool AutoSegment::getAnalogMode () { return _analogMode; } void AutoSegment::setShortNetMode ( bool state ) { _shortNetMode = state; } void AutoSegment::_initialize () { //cerr << "AutoSegment::_initialize()" << endl; _initialized = true; for ( size_t depth=0 ; depthisVertical()); uint32_t flags = (isVertical) ? Layer::EnclosureV : Layer::EnclosureH ; //cerr << depth << ":" << Session::getLayerGauge(depth)->getLayer()->getName() // << " isVertical:" << Session::getLayerGauge(depth)->isVertical() << endl; *viaToSameCap = Session::getPWireWidth(depth)/2; // Bottom metal of the VIA going *up*. const Layer* viaLayer = dynamic_cast( Session::getContactLayer(depth) ); if (viaLayer) *viaToTopCap = Session::getViaWidth(depth)/2 + viaLayer->getBottomEnclosure( flags ); // Top metal of the VIA going *down*. if (depth > 0) { viaLayer = dynamic_cast( Session::getContactLayer(depth-1) ); if (viaLayer) *viaToBottomCap = Session::getViaWidth(depth-1)/2 + viaLayer->getTopEnclosure( flags ); } //cerr << " viaToTop width: " << DbU::getValueString( Session::getViaWidth(depth) ) << endl; //cerr << " viaToTopCap: " << DbU::getValueString(*viaToTopCap ) << endl; //if (depth > 0) // cerr << " viaToBottom width:" << DbU::getValueString( Session::getViaWidth(depth-1)/2 ) << endl; //cerr << " viaToBottomCap: " << DbU::getValueString(*viaToBottomCap) << endl; //cerr << " viaToSameCap: " << DbU::getValueString(*viaToSameCap ) << endl; _extensionCaps.push_back( std::array( {{ viaToTopCap, viaToBottomCap, viaToSameCap }} ) ); } } AutoSegment::AutoSegment ( Segment* segment ) : _id (segment->getId()) , _gcell (NULL) , _flags (SegCreated) , _depth (Session::getLayerDepth(segment->getLayer())) , _optimalMin (0) , _optimalMax (0) , _reduceds (0) , _rpDistance (15) , _sourcePosition (0) , _targetPosition (0) , _userConstraints (false) , _nativeConstraints(false) , _parent (NULL) , _observers () { if (not _initialized) _initialize(); _allocateds++; if (dynamic_cast(segment)) setFlags( SegHorizontal ); _globalsCount += isGlobal() ? 1 : 0; AutoContact* source = Session::lookup(dynamic_cast(segment->getSource())); AutoContact* target = Session::lookup(dynamic_cast(segment->getTarget())); if (source->isTerminal()) setFlags( SegSourceTerminal ); if (target->isTerminal()) setFlags( SegTargetTerminal ); if (_analogMode) setFlags( SegAnalog ); if (_shortNetMode) setFlags( SegShortNet ); 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 ); AutoContact* contact = getAutoSource(); if (contact) contact->cacheDetach( this ); contact = getAutoTarget(); if (contact) contact->cacheDetach( this ); 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 ( Flags flags ) { if (Session::doDestroyTool()) return; cdebug_log(149,0) << "AutoSegment::invalidate() " << flags.asString(FlagsFunction) << " " << this << endl; cdebug_tabw(149,1); if (flags & Flags::Source) setFlags( SegInvalidatedSource ); if (flags & Flags::Target) setFlags( SegInvalidatedTarget ); if ( (getFlags() & SegSourceTerminal) and getAutoSource() and getAutoSource()->canDrag() and not getAutoSource()->isInvalidated() ) getAutoSource()->invalidate( flags ); if ( (getFlags() & SegTargetTerminal) and getAutoTarget() and getAutoTarget()->canDrag() and not getAutoTarget()->isInvalidated() ) getAutoTarget()->invalidate( flags ); if (isInvalidated()) { cdebug_tabw(149,-1); return; } _invalidate(); if ((flags & Flags::Propagate) and not isNotAligned()) { for ( AutoSegment* segment : getAligneds(flags & Flags::NoCheckLayer) ) { if (not segment->isInvalidated()) segment->_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(); uint64_t 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->getMask() != segmentLayer->getMask()) setFlags( (segmentLayer->getMask() == contactLayer->getTop()->getMask()) ? 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->getMask() != segmentLayer->getMask()) setFlags( (segmentLayer->getMask() == contactLayer->getTop()->getMask()) ? SegTargetBottom : SegTargetTop ); if (target->isTurn() and target->getPerpandicular(this)->isReduced()) incReduceds(); } updatePositions(); 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 ( Flags flags ) const { if (isTerminal()) return true; if ((flags & Flags::Propagate) and not isNotAligned()) { for ( AutoSegment* segment : const_cast(this)->getAligneds() ) { if (segment->isTerminal()) 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::getExtensionCap ( Flags flags ) const { size_t depth = Session::getLayerDepth( getLayer() ); DbU::Unit cap = 0; if (flags & Flags::Source) { if (getFlags() & SegSourceTop ) cap = getViaToTopCap (depth); else if (getFlags() & SegSourceBottom) cap = getViaToBottomCap(depth); else cap = getViaToSameCap (depth); cdebug_log(150,0) << "getExtensionCap(): flags:" << getFlags() << " VIA cap:" << DbU::getValueString(cap) << " t:" << (getFlags() & SegSourceBottom) << " b:" << (getFlags() & SegSourceTop) << endl; } if (flags & Flags::Target) { if (getFlags() & SegTargetTop ) cap = getViaToTopCap (depth); else if (getFlags() & SegTargetBottom) cap = getViaToBottomCap(depth); else cap = getViaToSameCap (depth); } if (getLayer()->isSymbolic() and (cap < getWidth()/2)) cap = getWidth()/2; if (not (flags & Flags::LayerCapOnly)) cap += getLayer()->getMinimalSpacing()/2; return cap; } 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()) { for ( AutoSegment* segment : getAligneds() ) { if (segment->isCanonical()) { canonical = segment; canonicals++; } collapsedMin = segment->getSourcePosition(); collapsedMax = segment->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; for ( AutoSegment* segment : getAligneds() ) cerr << " " << count++ << ": " << segment << endl; } } return canonical; } void AutoSegment::getEndAxes ( DbU::Unit& sourceAxis, DbU::Unit& targetAxis ) const { cdebug_log(145,0) << "AutoSegment::getEndAxes() - " << this << endl; sourceAxis = getSourceU(); targetAxis = getTargetU(); if (not isNotAligned()) { for( AutoSegment* aligned : const_cast(this)->getAligneds() ) { sourceAxis = std::min( sourceAxis, aligned->getSourceU() ); targetAxis = std::min( targetAxis, aligned->getTargetU() ); } } } AutoSegments AutoSegment::getOnSourceContact ( Flags direction ) { return AutoSegments_OnContact ( this, getSource() ).getSubSet( AutoSegments_InDirection(direction) ); } AutoSegments AutoSegment::getOnTargetContact ( Flags direction ) { return AutoSegments_OnContact ( this, getTarget() ).getSubSet( AutoSegments_InDirection(direction) ); } AutoSegments AutoSegment::getCachedOnSourceContact ( Flags direction ) { return AutoSegments_CachedOnContact( getAutoSource(), direction ); } AutoSegments AutoSegment::getCachedOnTargetContact ( Flags direction ) { return AutoSegments_CachedOnContact( getAutoTarget(), direction ); } AutoSegments AutoSegment::getAligneds ( Flags flags ) { return AutoSegments_Aligneds( this, flags ); } AutoSegments AutoSegment::getConnecteds ( Flags flags ) { return AutoSegments_Connecteds( this, flags ); } AutoSegments AutoSegment::getPerpandiculars ( Flags flags ) { return AutoSegments_Perpandiculars( this, flags ); } bool AutoSegment::checkDepthSpin () const { bool valid = true; const Layer* sourceLayer = getAutoSource()->getLayer(); const Layer* targetLayer = getAutoTarget()->getLayer(); if ( (_flags & SegSourceTop) and (sourceLayer->getBottom()->getMask() != getLayer()->getMask()) ) { cerr << Error( "%s\n" " Source is not going above, connected to *top* of %s.\n" " bottom:%s mask:%s\n" " layer:%s mask:%s\n" , getString(this).c_str() , getString(getAutoSource()).c_str() , getString(sourceLayer->getBottom()).c_str() , getString(sourceLayer->getBottom()->getMask()).c_str() , getString(getLayer()).c_str() , getString(getLayer()->getMask()).c_str() ) << endl; valid = false; } if ( (_flags & SegSourceBottom) and (sourceLayer->getTop()->getMask() != getLayer()->getMask()) ) { 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()->getMask() != getLayer()->getMask()) ) { 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()->getMask() != getLayer()->getMask()) ) { 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 ( uint64_t 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 ) { DebugSession::open( getNet(), 149, 160 ); cdebug_log(149,0) << "mergeUserConstraints() " << this << endl; cdebug_log(149,0) << "| " << constraints << " merged with " << _userConstraints << endl; _userConstraints.intersection(constraints); DebugSession::close(); } bool AutoSegment::toConstraintAxis ( Flags 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 ( Flags flags ) { cdebug_log(149,1) << "toOptimalAxis() " << this << endl; if (not isCanonical()) { cdebug_tabw(149,-1); return false; } if (not isUnsetAxis()) { cdebug_tabw(149,-1); return toConstraintAxis( flags ); } 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 ); cdebug_log(149,0) << "optimal:[" << DbU::getValueString(optimalMin) << " " << DbU::getValueString(optimalMax) << "]" << endl; 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 ); //setAxis( optimalMin, flags ); cdebug_tabw(149,-1); return false; } void AutoSegment::setAxis ( DbU::Unit axis, Flags flags ) { if (not isCanonical() and not (flags & Flags::Force)) return; if ( (axis == getAxis()) and not (flags & Flags::Realignate) ) return; cdebug_log(159,0) << "setAxis() @" << ((isHorizontal())?"Y ":"X ") << DbU::getValueString(getAxis()) << " to " << DbU::getValueString(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(); 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 { uint64_t 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 ); } cdebug_log(145,0) << "computeTerminal() S:" << source->isTerminal() << " T:" << target->isTerminal() << " " << this << endl; } void AutoSegment::computeOptimal ( set& processeds ) { cdebug_log(145,1) << "computeOptimal() - " << this << endl; DbU::Unit optimalMin; DbU::Unit optimalMax; DbU::Unit constraintMin; DbU::Unit constraintMax; vector aligneds; SideStack sideStack ( (isHorizontal() ? Flags::Horizontal : Flags::Vertical), getPitch() ); getConstraints( constraintMin, constraintMax ); cdebug_log(145,0) << "Constraints: [" << DbU::getValueString(constraintMin) << " " << DbU::getValueString(constraintMax) << "]" << endl; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); if (isLocal() and source->isTurn() and target->isTurn() and not isUserDefined()) { AutoSegment* sourcePerpand = source->getPerpandicular(this); AutoSegment* targetPerpand = target->getPerpandicular(this); sourcePerpand->updateOrient(); targetPerpand->updateOrient(); if (not ( (sourcePerpand->getAutoSource() == source) xor (targetPerpand->getAutoSource() == target) ) ) { // This is a U-Turn. cdebug_log(145,0) << "U-Turn special case." << endl; DbU::Unit optimal = 0; if (sourcePerpand->getAutoSource() == source) { optimal = std::min( sourcePerpand->getTargetU(), targetPerpand->getTargetU() ); optimal = std::min( optimal, constraintMax ); } else { optimal = std::max( sourcePerpand->getSourceU(), targetPerpand->getSourceU() ); optimal = std::max( optimal, constraintMin ); } cdebug_log(145,0) << "| Source perpandicular: " << sourcePerpand << endl; cdebug_log(145,0) << "| Target perpandicular: " << targetPerpand << endl; cdebug_log(145,0) << "Applying constraint (U-Turn) on: " << this << endl; cdebug_log(145,0) << "optimal: " << DbU::getValueString(optimal) << endl; setOptimalMin( optimal ); setOptimalMax( optimal ); processeds.insert( this ); cdebug_tabw(145,-1); return; } } if (isUserDefined()) { optimalMin = optimalMax = getAxis(); aligneds.push_back( this ); } else { DbU::Unit terminalMin; DbU::Unit terminalMax; AttractorsMap attractors; Flags flags = (isAnalog() ? Flags::WithDoglegs : Flags::NoFlags); getAligneds( Flags::WithSelf|flags ).fill( aligneds ); if (getGCell()->isMatrix()) { sideStack.addGCell( getGCell() ); } else { vector gcells; cdebug_log(145,0) << "Using pitch for L/T shrink:" << DbU::getValueString(getPitch()) << endl; for ( AutoSegment* aligned : aligneds ) { cdebug_log(145,0) << "@ " << aligned << endl; aligned->getGCells( gcells ); for ( GCell* gcell : gcells ) { sideStack.addGCell( gcell ); cdebug_log(145,0) << "| gcellSide:" << sideStack.getGSide() << " (from " << gcell << ")" << endl; } if (aligned->isStrongTerminal() and not sideStack.isHoled()) { cdebug_log(145,0) << "> Is strong terminal, restrict." << aligned << endl; Interval terminalConstraints; aligned->getConstraints( terminalConstraints ); sideStack.restrictGSide( terminalConstraints ); cdebug_log(145,0) << "| " << terminalConstraints.intersection(sideStack.getGSide()) << endl; cdebug_log(145,0) << "| gcellSide:" << sideStack.getGSide() << " (from " << aligned << ")" << endl; } } } sideStack.show(); cdebug_log(145,0) << "GCell interval " << sideStack.getGSide() << endl; 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 ); } for ( AutoSegment* autoSegment : getPerpandiculars(flags) ) { cdebug_log(145,1) << "| Perpandicular " << autoSegment << endl; if (autoSegment->isGlobal()) { cdebug_log(145,0) << "Used as global." << endl; const Interval& side = sideStack.getSideAt( autoSegment->getAxis() ); cdebug_log(145,0) << "Side @" << DbU::getValueString(autoSegment->getAxis()) << " " << side << endl; if (autoSegment->getSourceU() < side.getVMin()) attractors.addAttractor( sideStack.getGSideMin() ); if (autoSegment->getTargetU() > side.getVMax()) attractors.addAttractor( sideStack.getGSideMax() ); // // Sloppy implentation. // DbU::Unit perpandMin = autoSegment->getSourceU(); // DbU::Unit perpandMax = autoSegment->getTargetU(); // if (perpandMin < minGCell) attractors.addAttractor( minGCell ); // if (perpandMax > maxGCell) attractors.addAttractor( maxGCell ); } else if (autoSegment->isLocal()) { if (autoSegment->isStrongTerminal()) { cdebug_log(145,0) << "Used as strong terminal." << endl; DbU::Unit terminalMin; DbU::Unit terminalMax; if (getTerminalInterval( autoSegment , NULL , isHorizontal() , terminalMin , terminalMax )) { attractors.addAttractor( terminalMin ); if (terminalMin != terminalMax) attractors.addAttractor( terminalMax ); } } else if (autoSegment->isLongLocal() or (autoSegment->getLength() > getPPitch()*20)) { cdebug_log(145,0) << "Used as long global attractor." << endl; DbU::Unit perpandMin = autoSegment->getSourceU(); DbU::Unit perpandMax = autoSegment->getTargetU(); if (perpandMin != perpandMax) { if (perpandMin == getAxis()) attractors.addAttractor( perpandMax ); if (perpandMax == getAxis()) attractors.addAttractor( perpandMin ); } } } cdebug_tabw(145,-1); } if (sideStack.isHoled()) { optimalMin = optimalMax = sideStack.getGSideCenter(); } else { if (attractors.getAttractorsCount()) { optimalMin = attractors.getLowerMedian(); optimalMax = attractors.getUpperMedian(); } else { cdebug_log(145,0) << "No attractors, reverting to GCell bounding box" << endl; optimalMin = 0; optimalMax = (isHorizontal()) ? _gcell->getBoundingBox().getYMax() : _gcell->getBoundingBox().getXMax(); } setInBound( sideStack.getGSideMin(), sideStack.getGSideMax(), optimalMin ); setInBound( sideStack.getGSideMin(), sideStack.getGSideMax(), optimalMax ); } cdebug_log(145,0) << "optimalMin: " << DbU::getValueString(optimalMin) << endl; cdebug_log(145,0) << "optimalMax: " << DbU::getValueString(optimalMax) << endl; } setInBound( constraintMin, constraintMax, optimalMin ); setInBound( constraintMin, constraintMax, optimalMax ); for ( AutoSegment* aligned : aligneds ) { cdebug_log(145,0) << "Applying constraint on: " << aligned << endl; aligned->setOptimalMin( optimalMin ); aligned->setOptimalMax( optimalMax ); processeds.insert( aligned ); } // 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 ( Flags 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; Flags 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 { cdebug_log(159,0) << "AutoSegment::canReduce():" << this << endl; cdebug_log(159,0) << " _reduceds:" << _reduceds << endl; if (isGlobal() or isDrag() or isFixed()) return false; if (not isSpinTopOrBottom()) return false; if (_reduceds) return false; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); cdebug_log(159,0) << " source:" << source->isHTee() << "+" << source->isVTee() << endl; cdebug_log(159,0) << " target:" << target->isHTee() << "+" << target->isVTee() << endl; if ( ((source->isHTee() or target->isHTee()) and isHorizontal()) or ((source->isVTee() or target->isVTee()) and isVertical ()) ) return false; // if ( source->isHTee() or source->isVTee() // or target->isHTee() or target->isVTee() ) return false; unsigned int perpandicularDepth = getDepth(); if (isSpinBottom()) { if (perpandicularDepth > 0) --perpandicularDepth; } else if (isSpinTop()) { ++perpandicularDepth; if (perpandicularDepth >= Session::getDepth()) return false; } else return false; cdebug_log(159,0) << " length:" << DbU::getValueString(getLength()) << endl; if (getLength() >= (Session::getPitch(perpandicularDepth) * 2)) return false; return true; } bool AutoSegment::reduce () { if (isReduced()) return false; if (not canReduce()) return false; cdebug_log(159,0) << "AutoSegment::reduce():" << this << endl; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); _flags |= SegIsReduced; for ( AutoSegment* perpandicular : source->getAutoSegments() ) { if (perpandicular == this) continue; perpandicular->incReduceds(); } for ( AutoSegment* perpandicular : target->getAutoSegments() ) { if (perpandicular == this) continue; perpandicular->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; cdebug_log(159,0) << "AutoSegment::raise():" << this << endl; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); _flags &= ~SegIsReduced; for ( AutoSegment* perpandicular : source->getAutoSegments() ) { if (perpandicular == this) continue; cdebug_log(159,0) << "dec PP:" << perpandicular << endl; perpandicular->decReduceds(); } for ( AutoSegment* perpandicular : target->getAutoSegments() ) { if (perpandicular == this) continue; cdebug_log(159,0) << "dec PP:" << perpandicular << endl; perpandicular->decReduceds(); } return true; } void AutoSegment::changeDepth ( unsigned int depth, Flags flags ) { DebugSession::open( getNet(), 145, 150 ); cdebug_log(149,1) << "changeDepth() " << depth << " - " << this << endl; Session::invalidate( getNet() ); _changeDepth( depth, flags & ~Flags::Propagate ); if ((flags & Flags::Propagate) and not isNotAligned()) { cdebug_log(149,0) << "Propagate to aligneds." << endl; for ( AutoSegment* segment : getAligneds(Flags::NoCheckLayer) ) { segment->_changeDepth( depth, flags & ~Flags::Propagate ); } } cdebug_tabw(149,-1); DebugSession::close(); } void AutoSegment::_changeDepth ( unsigned int depth, Flags flags ) { cdebug_log(149,1) << "_changeDepth() - " << this << endl; invalidate( Flags::Topology|Flags::NoCheckLayer ); setFlags( SegInvalidatedLayer|SegInvalidatedSource|SegInvalidatedTarget ); const Layer* newLayer = Session::getRoutingGauge()->getRoutingLayer(depth); if (getLayer() != newLayer) { cdebug_log(149,0) << "Effective layer change to " << depth << "/" << newLayer << endl; setLayer( depth ); getAutoSource()->invalidate( Flags::Topology|Flags::NoCheckLayer ); getAutoTarget()->invalidate( Flags::Topology|Flags::NoCheckLayer ); } vector gcells; getGCells( gcells ); for ( size_t i=0 ; iflags() |= Flags::Invalidated; cdebug_log(149,0) << "changeDepth() " << gcells[i] << this << " " << endl; } if (not (flags & Flags::WithNeighbors)) { cdebug_tabw(149,-1); return; } for ( AutoSegment* segment : getCachedOnSourceContact(Flags::DirectionMask) ) { if (segment == this) continue; if (segment->isGlobal ()) continue; if (segment->isTerminal()) continue; if (not (segment->isHorizontal() xor isHorizontal())) segment->_changeDepth( depth , Flags::NoFlags ); else segment->_changeDepth( depth-1, Flags::NoFlags ); } for ( AutoSegment* segment : getCachedOnTargetContact(Flags::DirectionMask) ) { if (segment == this) continue; if (segment->isGlobal ()) continue; if (segment->isTerminal()) continue; if (not (segment->isHorizontal() xor isHorizontal())) segment->_changeDepth( depth , Flags::NoFlags ); else segment->_changeDepth( depth-1, Flags::NoFlags ); } cdebug_tabw(149,-1); } bool AutoSegment::canSlacken ( Flags 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()) { for ( AutoSegment* segment : const_cast(this)->getAligneds() ) { if (segment->_canSlacken()) return true; } } return false; } bool AutoSegment::slacken ( Flags flags ) { bool success = false; success = success or _slacken( flags ); if ((flags & Flags::Propagate) and not isNotAligned()) { for ( AutoSegment* segment : getAligneds() ) { success = success or segment->_slacken( flags ); } } return success; } float AutoSegment::getMaxUnderDensity ( Flags 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, Flags flags ) const { cdebug_log(149,0) << "AutoSegment::canPivotUp() - " << flags << " (reserve:" << reserve << ")" << endl; if ( isLayerChange() or isFixed() or isUnbreakable() ) 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() ); 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, Flags flags ) const { cdebug_log(149,0) << "AutoSegment::canPivotDown()" << " (reserve:" << reserve << ")" << endl; if ( isLayerChange() or isFixed() or isUnbreakable() ) 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, Flags flags ) const { cdebug_log(159,0) << "AutoSegment::canMoveUp() " << flags << " (reserve:" << reserve << ") " << this << endl; bool nLowDensity = true; bool nLowUpDensity = true; if ( isLayerChange() or isFixed() or isUnbreakable() ) 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 ); for ( size_t i=0 ; igetWDensity(depth-2) > 0.5) ) nLowDensity = false; if ( nLowUpDensity and (gcells[i]->getWDensity(depth) > 0.2) ) nLowUpDensity = false; if (not gcells[i]->hasFreeTrack(depth,reserve)) { cdebug_log(159,0) << "Not enough free track in " << gcells[i] << endl; return false; } } cdebug_log(159,0) << "Enough free track under canonical segment." << endl; if (not (flags & Flags::IgnoreContacts)) { if (getAutoSource()->getMinDepth() < depth-2) return false; if (getAutoTarget()->getMinDepth() < depth-2) return false; } if ( isLocal() and not (flags & Flags::Propagate) ) { if (not getAutoSource()->canMoveUp(this)) return false; if (not getAutoTarget()->canMoveUp(this)) return false; return true; } // if (getAutoSource()->isTurn() and (getAutoSource()->getPerpandicular(this)->getLayer() == getLayer())) return false; // if (getAutoTarget()->isTurn() and (getAutoTarget()->getPerpandicular(this)->getLayer() == getLayer())) return false; cdebug_log(159,0) << "Both source & target Contacts can move up." << endl; //bool hasGlobalSegment = false; if ((flags & Flags::Propagate) and not isNotAligned()) { for ( AutoSegment* segment : const_cast(this)->getAligneds(flags) ) { if (segment->isFixed ()) return false; //if (segment->isGlobal()) hasGlobalSegment = true; if (not (flags & Flags::IgnoreContacts)) { if (segment->getAutoSource()->getMinDepth() < depth-2) return false; if (segment->getAutoTarget()->getMinDepth() < depth-2) return false; } segment->getGCells( gcells ); for ( size_t i=0 ; igetWDensity(depth-2) > 0.6) ) nLowDensity = false; if ( nLowUpDensity and (gcells[i]->getWDensity(depth) > 0.2) ) { cdebug_log(159,0) << "lowUpDensity false in " << gcells[i] << "d:" << gcells[i]->getWDensity(depth) << endl; nLowUpDensity = false; } if (not gcells[i]->hasFreeTrack(depth,reserve)) { cdebug_log(159,0) << "Not enough free track in " << gcells[i] << endl; return false; } } } } if ( nLowDensity and (flags & Flags::CheckLowDensity )) return false; if (not nLowUpDensity and (flags & Flags::CheckLowUpDensity)) return false; if ( (depth >= 4) and (flags & Flags::WithPerpands) ) { float fragmentation = (*gcells.begin())->getFragmentation( depth-1 ); cdebug_log(159,0) << "Check begin GCell perpandicular fragmentation: " << fragmentation << endl; if (fragmentation < 0.5) { cdebug_log(159,0) << "Not enough free track for perpandicular in begin GCell " << "(frag:" << fragmentation << ")." << endl; return false; } fragmentation = (*gcells.rbegin())->getFragmentation( depth-1 ); cdebug_log(159,0) << "Check end GCell perpandicular fragmentation: " << fragmentation << endl; if (fragmentation < 0.5) { cdebug_log(159,0) << "Not enough free track for perpandicular in end GCell " << "(frag:" << fragmentation << ")." << endl; return false; } } return true; } bool AutoSegment::moveUp ( Flags flags ) { //if ( not canMoveUp(0.0,flags) ) return false; changeDepth( Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2, flags&Flags::Propagate ); return true; } bool AutoSegment::moveDown ( Flags 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 false; DebugSession::open( getNet(), 149, 160 ); cdebug_log(159,1) << "AutoSegment::reduceDoglegLayer(): " << this << endl; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); unsigned int minSourceDepth = Session::getAllowedDepth(); unsigned int maxSourceDepth = 0; unsigned int minTargetDepth = Session::getAllowedDepth(); unsigned int maxTargetDepth = 0; if (source->isTerminal()) { unsigned int anchorDepth = Session::getLayerDepth( source->base()->getAnchor()->getLayer() ); minSourceDepth = std::min( minSourceDepth, anchorDepth ); maxSourceDepth = std::max( maxSourceDepth, anchorDepth ); } else { for ( AutoSegment* perpandicular : source->getAutoSegments() ) { if (perpandicular == this) continue; minSourceDepth = std::min( minSourceDepth, perpandicular->getDepth() ); maxSourceDepth = std::max( maxSourceDepth, perpandicular->getDepth() ); } } if (target->isTerminal()) { unsigned int anchorDepth = Session::getLayerDepth( target->base()->getAnchor()->getLayer() ); minTargetDepth = std::min( minTargetDepth, anchorDepth ); maxTargetDepth = std::max( maxTargetDepth, anchorDepth ); } else { for ( AutoSegment* perpandicular : target->getAutoSegments() ) { if (perpandicular == this) continue; minTargetDepth = std::min( minTargetDepth, perpandicular->getDepth() ); maxTargetDepth = std::max( maxTargetDepth, perpandicular->getDepth() ); } } cdebug_log(159,0) << "Source span: [" << minSourceDepth << " " << maxSourceDepth << "]" << endl; cdebug_log(159,0) << "Target span: [" << minTargetDepth << " " << maxTargetDepth << "]" << endl; if ( (minSourceDepth == maxSourceDepth) and (minTargetDepth == maxTargetDepth) and (minSourceDepth == minTargetDepth) ) { const Layer* layer = Session::getRoutingLayer(minSourceDepth); DbU::Unit side = Session::getWireWidth (minSourceDepth); cdebug_log(159,0) << "Reducing to " << minSourceDepth << " " << layer << endl; source->setLayer( layer ); target->setLayer( layer ); setLayer( layer ); source->setSizes( side, side ); target->setSizes( side, side ); } cdebug_tabw(159,-1); DebugSession::close(); return true; // if (not source->isTurn() or not target->isTurn()) return true; // 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; // } // const Layer* layer = Session::getRoutingLayer(perpandicularDepth); // DbU::Unit side = Session::getWireWidth (perpandicularDepth); // source->setLayer( layer ); // target->setLayer( layer ); // setLayer( layer ); // source->setSizes( side, side ); // target->setSizes( side, side ); // return true; } bool AutoSegment::bloatStackedStrap () { DebugSession::open( getNet(), 145, 150 ); cdebug_log(149,1) << "AutoSegment::bloatStackedStrap() " << this << endl; double minArea = getLayer()->getMinimalArea(); if (minArea == 0.0) { cdebug_log(149,-1) << "False, NO minimal area." << endl; DebugSession::close(); return false; } DbU::Unit minLength = DbU::fromPhysical( minArea / DbU::toPhysical( getWidth(), DbU::UnitPower::Micro ) , DbU::UnitPower::Micro ); cdebug_log(149,0) << "Min length: " << DbU::getValueString(minLength) << " ." << endl; if ((getSpanLength() >= minLength) or isReduced()) { cdebug_log(149,-1) << "False, has length or is reduced." << endl; DebugSession::close(); return false; } if (isDrag()) { for ( AutoSegment* perpandicular : getPerpandiculars() ) { if (perpandicular->getSpanLength() > minLength) { cdebug_log(149,-1) << "False (drag), has length or PP has length." << endl; DebugSession::close(); return false; } } } else { if ( ((_flags & (SegSourceBottom|SegTargetTop)) != (SegSourceBottom|SegTargetTop)) and ((_flags & (SegTargetBottom|SegSourceTop)) != (SegTargetBottom|SegSourceTop)) ) { cdebug_log(149,-1) << "False, not part of a stacked VIA." << endl; DebugSession::close(); return false; } } DbU::Unit side = DbU::fromPhysical( std::sqrt(minArea) , DbU::UnitPower::Micro ); setWidth( side ); setDuSource( -side/2 ); setDuTarget( side/2 ); cdebug_log(149,-1) << "True, add area." << endl; DebugSession::close(); return true; } #if THIS_IS_DISABLED bool AutoSegment::shearUp ( GCell* upGCell, AutoSegment*& movedUp, float reserve, Flags 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 Flags 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()) { for ( AutoSegment* segment : getAligneds() ) { if (segment->getSpanU().contains(interval.getVMin())) { if (segment->isFixed()) return Flags::NoFlags; leftDogleg++; } if (segment->getSpanU().contains(interval.getVMax())) { if (segment->isFixed()) return Flags::NoFlags; 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 Flags::NoFlags; } 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( segmentDepth-1 ); cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1] << endl; if (isSource) { doglegs[ index + 0 ]->setLayer( std::max((size_t)1,segmentDepth-2) ); 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( std::max((size_t)1,segmentDepth-2) ); 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( segmentDepth+1 ); cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1] << endl; if (isSource) { doglegs[ index + 0 ]->setLayer( segmentDepth+2 ); 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( segmentDepth+2 ); 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; } } doglegs[ index + 1 ]->getAutoSource()->updateLayer(); doglegs[ index + 1 ]->getAutoTarget()->updateLayer(); } cdebug_tabw(149,-1); return doglegs[ index + (isSource?0:2) ]; } Flags AutoSegment::makeDogleg ( Interval interval, Flags flags ) { cdebug_log(149,1) << "AutoSegment::makeDogleg(Interval) - " << interval << endl; bool leftDogleg = true; Flags rflags = Flags::NoFlags; 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; Flags 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); } Flags AutoSegment::makeDogleg ( GCell* doglegGCell, Flags flags ) { cdebug_log(9000,0) << "Deter| AutoSegment::makeDogleg(GCell*) " << doglegGCell << endl; cdebug_log(9000,0) << "Deter| in " << this << endl; cdebug_tabw(149,1); Flags rflags = Flags::NoFlags; 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()) { for ( 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; if (isDrag() xor (getAutoSource()->canDrag() or getAutoTarget()->canDrag())) { cerr << Error( "%s\n" " Discrepency between segment \"drag\" state and it's contacts.\n" " source:%s\n" " target:%s" , getString(this).c_str() , getString(getAutoSource()).c_str() , getString(getAutoTarget()).c_str() ) << endl; coherency = false; } return coherency; } string AutoSegment::_getStringFlags () const { string state; state += isFixed () ?" F":" -"; state += isFixedAxis () ? "X": "-"; state += isUnsetAxis () ? "u": "-"; state += isStrap () ? "S": "-"; state += isUnbreakable () ? "U": "-"; state += isCanonical () ? "C": "-"; state += isGlobal () ? "G": "-"; state += isWeakGlobal () ? "g": "-"; state += isLongLocal () ? "L": "-"; state += isStrongTerminal () ? "T": "-"; state += isDrag () ? "D": "-"; state += isWeakTerminal1 () ? "W": "-"; state += isWeakTerminal2 () ? "w": "-"; state += isNotAligned () ? "A": "-"; state += isSlackened () ? "S": "-"; state += isReduced () ? "r": "-"; state += isInvalidated () ? "i": "-"; state += isInvalidatedLayer() ? "l": "-"; 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 += '-'; state += isShortNet () ? "s": "-"; return state; } string AutoSegment::_getString () const { string sdistance = " rpD:" + getString(_rpDistance); string s = base()->_getString(); s.insert ( s.size()-1, sdistance ); s.insert ( s.size()-1, _getStringFlags() ); return s; } Record* AutoSegment::_getRecord () const { Record* record = base()->_getRecord (); record->add ( getSlot ( "_extensionCaps" , &_extensionCaps ) ); 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 ) { const Layer* horizontalLayer = Session::getDHorizontalLayer(); DbU::Unit horizontalWidth = Session::getDHorizontalWidth(); const Layer* verticalLayer = Session::getDVerticalLayer(); DbU::Unit verticalWidth = Session::getDVerticalWidth(); uint32_t wPitch = NetRoutingExtension::getWPitch( source->getNet() ); if (wPitch > 1) { horizontalWidth += (wPitch-1) * Session::getDHorizontalPitch(); verticalWidth += (wPitch-1) * Session::getDVerticalPitch (); } cdebug_log(149,0) << "wPitch:" << wPitch << " hW:" << DbU::getValueString(horizontalWidth) << endl; if (wPitch > 2) { throw Error( "wPitch %d for \"%s\"", wPitch, getString(source->getNet()->getName()).c_str() ); } bool reattachSource = false; bool reattachTarget = false; AutoSegment* segment; Horizontal* horizontal = dynamic_cast( hurricaneSegment ); Vertical* vertical = dynamic_cast( hurricaneSegment ); AutoContact* reference = NULL; cdebug_log(149,0) << "Source:" << source << endl; cdebug_log(149,0) << "Target:" << target << endl; if (source->isFixed() and target->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; } if (target->isFixed() or target->isTerminal()) reference = target; if (source->isFixed() or source->isTerminal()) reference = source; 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; } } } if (reference) 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; } } if (reference) vertical->setX( reference->getX() ); segment = new AutoVertical ( vertical ); segment->_postCreate(); } else { throw Error( badSegment, getString(source).c_str(), getString(target).c_str() ); } if (wPitch > 1) segment->setFlags( SegWide ); if (source->canDrag() or target->canDrag()) segment->setFlags( SegDrag ); return segment; } AutoSegment* AutoSegment::create ( AutoContact* source , AutoContact* target , Flags 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. const Layer* hLayer = Session::getDHorizontalLayer(); DbU::Unit hWidth = Session::getDHorizontalWidth(); const Layer* vLayer = Session::getDVerticalLayer(); DbU::Unit vWidth = Session::getDVerticalWidth(); if (dir & Flags::UseNonPref) { if (dir & Flags::Vertical) { vLayer = hLayer; vWidth = Session::getDPHorizontalWidth(); cdebug_log(149,0) << "Make vertical in non-preferred direction (ppW:" << DbU::getValueString(vWidth).c_str() << ")." << endl; } if (dir & Flags::Horizontal) { hLayer = vLayer; hWidth = Session::getDPVerticalWidth(); cdebug_log(149,0) << "Make horizontal in non-preferred direction (ppW:" << DbU::getValueString(hWidth).c_str() << ")." << endl; } } const Layer* horizontalLayer = hLayer; DbU::Unit horizontalWidth = hWidth; const Layer* verticalLayer = vLayer; DbU::Unit verticalWidth = vWidth; cdebug_log(149,0) << "verticalWidth:" << DbU::getValueString(verticalWidth).c_str() << endl; uint32_t wPitch = NetRoutingExtension::getWPitch( source->getNet() ); if (wPitch > 1) { horizontalWidth = (wPitch-1) * Session::getDHorizontalPitch() + hWidth; verticalWidth = (wPitch-1) * Session::getDVerticalPitch () + vWidth; } cdebug_log(149,0) << "verticalWidth:" << DbU::getValueString(verticalWidth).c_str() << endl; if (depth != RoutingGauge::nlayerdepth) { horizontalLayer = verticalLayer = Session::getRoutingLayer( depth ); if (wPitch > 1) { horizontalWidth = verticalWidth = (wPitch-1) * Session::getPitch (depth) + Session::getWireWidth(depth); } else { if (dir & Flags::Horizontal) { horizontalWidth = Session::getWireWidth ( depth ); verticalWidth = Session::getPWireWidth( depth ); } else { verticalWidth = Session::getWireWidth ( depth ); horizontalWidth = Session::getPWireWidth( depth ); } cdebug_log(149,0) << "hW:" << DbU::getValueString(horizontalWidth).c_str() << "vW:" << DbU::getValueString( verticalWidth).c_str() << endl; if (dir & Flags::UseNonPref) { cdebug_log(149,0) << "swap H/W width." << endl; std::swap( horizontalWidth, verticalWidth ); } } } cdebug_log(149,0) << "verticalWidth:" << DbU::getValueString(verticalWidth).c_str() << endl; 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() ); if (wPitch > 1) segment->setFlags( SegWide ); if (source->canDrag() or target->canDrag()) segment->setFlags( SegDrag ); if (dir & Flags::UseNonPref) segment->setFlags( SegNonPref ); return segment; } void AutoSegment::destroy () { _preDestroy (); delete this; } AutoSegment* AutoSegment::getGlobalThroughDogleg ( AutoSegment* dogleg, AutoContact* from ) { AutoContact* source = dogleg->getAutoSource(); AutoContact* target = dogleg->getAutoTarget(); if (not source->isTurn() or not target->isTurn()) return NULL; AutoSegment* fromSegment = (source == from) ? source->getPerpandicular(dogleg) : target->getPerpandicular(dogleg); AutoSegment* toSegment = (source != from) ? source->getPerpandicular(dogleg) : target->getPerpandicular(dogleg); if (not toSegment->isGlobal() or (toSegment->getLayer() != fromSegment->getLayer())) return NULL; Interval fromConstraints; Interval toConstraints; fromSegment->getConstraints( fromConstraints ); toSegment ->getConstraints( toConstraints ); if (not fromConstraints.intersect(toConstraints)) return NULL; return toSegment; } bool AutoSegment::isTopologicalBound ( AutoSegment* seed, Flags 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 (bool)(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 Flags AutoSegment::getPerpandicularState ( AutoContact* contact , AutoSegment* source , AutoSegment* current , bool isHorizontalMaster , const Layer* masterLayer ) { Flags state = Flags::NoFlags; 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.