// -*- 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 | // | K a t a b a t i c - Routing Toolbox | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@lip6.fr | // | =============================================================== | // | C++ Module : "./AutoVertical.cpp" | // +-----------------------------------------------------------------+ #include #include "hurricane/Bug.h" #include "hurricane/Vertical.h" #include "crlcore/RoutingGauge.h" #include "katabatic/Configuration.h" #include "katabatic/AutoContactTurn.h" #include "katabatic/AutoVertical.h" #include "katabatic/AutoHorizontal.h" namespace Katabatic { using std::min; using std::max; using Hurricane::ltracein; using Hurricane::ltraceout; using Hurricane::Error; using Hurricane::Bug; // ------------------------------------------------------------------- // Class : "Katabatic::AutoVertical". Segment* AutoVertical::base () { return _vertical; } Segment* AutoVertical::base () const { return _vertical; } Vertical* AutoVertical::getVertical () { return _vertical; } DbU::Unit AutoVertical::getSourceU () const { return _vertical->getSourceY(); } DbU::Unit AutoVertical::getTargetU () const { return _vertical->getTargetY(); } DbU::Unit AutoVertical::getDuSource () const { return _vertical->getDySource(); } DbU::Unit AutoVertical::getDuTarget () const { return _vertical->getDyTarget(); } Interval AutoVertical::getSpanU () const { return Interval(_vertical->getSourceY(),_vertical->getTargetY()); } void AutoVertical::setDuSource ( DbU::Unit du ) { _vertical->setDySource(du); } void AutoVertical::setDuTarget ( DbU::Unit du ) { _vertical->setDyTarget(du); } string AutoVertical::_getTypeName () const { return "AutoVertical"; } AutoVertical::AutoVertical ( Vertical* vertical ) : AutoSegment(vertical) , _vertical(vertical) { ltrace(99) << "CTOR AutoVertical " << this << endl; ltrace(99) << " over " << vertical << endl; } void AutoVertical::_postCreate () { AutoSegment::_postCreate (); AutoContact* source = getAutoSource(); if (source->isTerminal()) source->setX( _vertical->getX() ); AutoContact* target = getAutoTarget(); if (target->isTerminal()) target->setX( _vertical->getX() ); if ( source->getGCell() != target->getGCell() ) { setFlags( SegGlobal ); GCell* gcell; GCell* end; if ( source->getGCell()->getY() < target->getGCell()->getY() ) { gcell = source->getGCell()->getUp(); end = target->getGCell(); } else { gcell = target->getGCell()->getUp(); end = source->getGCell(); } for ( ; gcell != end ; gcell = gcell->getUp() ) { if ( !gcell ) { cerr << Error("AutoSegment::create() : NULL GCell.") << endl; break; } gcell->addVSegment ( this ); } } } void AutoVertical::_preDestroy () { ltrace(200) << "AutoVertical::_preDestroy() - " << endl; ltrace(200) << " " << _getString() << endl; ltracein(90); if ( not Session::doDestroyTool() ) { AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); if ( source and target and (source->getGCell() != target->getGCell()) ) { GCell* gcell; GCell* end; if ( source->getGCell()->getY() < target->getGCell()->getY() ) { gcell = source->getGCell()->getUp(); end = target->getGCell(); } else { gcell = target->getGCell()->getUp(); end = source->getGCell(); } for ( ; gcell != end ; gcell = gcell->getUp() ) { if ( !gcell ) { cerr << Error("AutoSegment::_preDestroy() : NULL GCell.") << endl; break; } gcell->removeVSegment ( this ); } } } AutoSegment::_preDestroy (); ltraceout(90); } AutoVertical::~AutoVertical () { if ( Session::doDestroyBaseSegment() and not Session::doDestroyTool() ) { ltrace(200) << "~AutoVertical() - " << endl; _vertical->destroy (); } } Interval AutoVertical::getSourceConstraints ( unsigned int flags ) const { if (flags & KbNativeConstraints) { Box nativeBox ( getAutoSource()->getNativeConstraintBox() ); return Interval ( nativeBox.getXMin(), nativeBox.getXMax() ); } return Interval ( getAutoSource()->getCBXMin(), getAutoSource()->getCBXMax() ); } Interval AutoVertical::getTargetConstraints ( unsigned int flags ) const { if (flags & KbNativeConstraints) { Box nativeBox ( getAutoTarget()->getNativeConstraintBox() ); return Interval ( nativeBox.getXMin(), nativeBox.getXMax() ); } return Interval ( getAutoTarget()->getCBXMin(), getAutoTarget()->getCBXMax() ); } bool AutoVertical::getConstraints ( DbU::Unit& constraintMin, DbU::Unit& constraintMax ) const { AutoContact* contact = getAutoSource(); constraintMin = contact->getCBXMin(); constraintMax = contact->getCBXMax(); ltrace(148) << "Source constraints: " << contact << " [" << DbU::getValueString(constraintMin) << ":" << DbU::getValueString(constraintMax) << "]" << endl; contact = getAutoTarget(); constraintMin = max ( constraintMin, contact->getCBXMin() ); constraintMax = min ( constraintMax, contact->getCBXMax() ); ltrace(148) << "Merge with target constraints: " << contact << " [" << DbU::getValueString(constraintMin) << ":" << DbU::getValueString(constraintMax) << "]" << endl; constraintMin = max ( constraintMin, getUserConstraints().getVMin() ); constraintMax = min ( constraintMax, getUserConstraints().getVMax() ); ltrace(148) << "Merge with user constraints: " << getUserConstraints() << " [" << DbU::getValueString(constraintMin) << ":" << DbU::getValueString(constraintMax) << "]" << endl; return true; } unsigned int AutoVertical::getDirection () const { return KbVertical; } size_t AutoVertical::getGCells ( vector& gcells ) const { vector().swap ( gcells ); gcells.push_back ( getAutoSource()->getGCell() ); GCell* gcell = gcells.front(); GCell* end = getAutoTarget()->getGCell(); while ( gcell != end ) { gcell = gcell->getUp (); if ( !gcell ) break; gcells.push_back ( gcell ); } return gcells.size(); } bool AutoVertical::_canSlacken () const { ltraceout(200); Interval sourceSide = getAutoSource()->getGCell()->getSide( KbHorizontal ); Interval targetSide = getAutoTarget()->getGCell()->getSide( KbHorizontal ); Interval sourceConstraints = Interval(getAutoSource()->getCBXMin(),getAutoSource()->getCBXMax()); Interval targetConstraints = Interval(getAutoTarget()->getCBXMin(),getAutoTarget()->getCBXMax()); // Expand by a tiny amount for the "contains" to work for sure. sourceConstraints.inflate( 1 ); targetConstraints.inflate( 1 ); if (not sourceConstraints.contains(sourceSide)) { ltraceout(200); return true; } if (not targetConstraints.contains(targetSide)) { ltraceout(200); return true; } ltraceout(200); return false; } bool AutoVertical::_slacken ( unsigned int flags ) { ltrace(200) << "AutoVertical::_slacken() " << this << endl; ltracein(200); if ( not isStrongTerminal() or (not (_flags & (SegGlobal|SegWeakGlobal)) and (getLength() < getPitch()*5)) ) { ltraceout(200); return false; } ltrace(200) << "_flags:" << (_flags & (SegGlobal|SegWeakGlobal)) << endl; ltrace(200) << "test:" << (getLength() < getPitch()*5) << endl; ltrace(200) << "length:" << DbU::getValueString(getLength()) << endl; bool success = false; bool slackened = false; bool halfSlackened = false; int lowSlack = (flags & KbHalfSlacken) ? 3 : 10; AutoContact* source = getAutoSource(); AutoSegment* parallel = this; if (source->isTerminal()) { Interval constraints = source->getUConstraints (KbHorizontal|KbNoGCellShrink); Interval nativeConstraints = source->getNativeUConstraints(KbHorizontal|KbNoGCellShrink); int slack = constraints.getSize() / getPitch(); int nativeSlack = nativeConstraints.getSize() / getPitch(); // Ugly: GCell's track number is hardwired. if ((slack < lowSlack) or (nativeSlack - slack < 3)) { _makeDogleg( source->getGCell(), KbNoFlags ); slackened = true; } else if (slack < 10) { halfSlackened = true; } const vector& doglegs = Session::getDoglegs(); if (doglegs.size() >= 2) { ltrace(200) << "AutoSegment::_slaken(): Source @" << DbU::getValueString(getSourcePosition()) << endl; doglegs[doglegs.size()-2]->_setAxis( getSourcePosition() ); success = true; parallel = doglegs[ doglegs.size()-1 ]; } } AutoContact* target = NULL; if (parallel) { target = parallel->getAutoTarget(); } else { target = getAutoTarget(); } if (target->isTerminal()) { Interval constraints = target->getUConstraints (KbHorizontal|KbNoGCellShrink); Interval nativeConstraints = target->getNativeUConstraints(KbHorizontal|KbNoGCellShrink); int slack = constraints.getSize() / getPitch(); int nativeSlack = nativeConstraints.getSize() / getPitch(); // Ugly: GCell's track number is hardwired. if ((slack < lowSlack) or (nativeSlack - slack < 3)) { _makeDogleg( target->getGCell(), KbNoFlags ); slackened = true; } else if (slack < 10) { halfSlackened = true; } const vector& doglegs = Session::getDoglegs(); if (doglegs.size() >= 2) { ltrace(200) << "AutoSegment::_slaken(): Source @" << DbU::getValueString(getTargetPosition()) << endl; doglegs[doglegs.size()-2]->_setAxis( getTargetPosition() ); success = true; } } if (halfSlackened) { setFlags( SegHalfSlackened ); } else if (slackened) { setFlags ( SegSlackened ); unsetFlags( SegHalfSlackened ); } ltraceout(200); return success; } void AutoVertical::_setAxis ( DbU::Unit axis ) { setFlags( SegAxisSet ); if (_vertical->getX() == axis) return; ltrace(159) << "_setAxis() @X " << DbU::toLambda(axis) << " " << this << endl; _vertical->setX( axis ); invalidate(); AutoContact* anchor = getAutoSource(); anchor->invalidate(); if (anchor->isTerminal()) anchor->setX( axis ); anchor = getAutoTarget(); anchor->invalidate(); if (anchor->isTerminal()) anchor->setX( axis ); } void AutoVertical::updateOrient () { if (_vertical->getTargetY() < _vertical->getSourceY()) { ltrace(80) << "updateOrient() " << this << " (before S/T swap)" << endl; _vertical->invert(); unsigned int spinFlags = _flags & SegDepthSpin; unsetFlags( SegDepthSpin ); if (spinFlags & SegSourceTop ) setFlags( SegTargetTop ); if (spinFlags & SegSourceBottom) setFlags( SegTargetBottom ); if (spinFlags & SegTargetTop ) setFlags( SegSourceTop ); if (spinFlags & SegTargetBottom) setFlags( SegSourceBottom ); } } void AutoVertical::updatePositions () { _sourcePosition = _vertical->getSourceY() - Session::getExtensionCap(getLayer()); _targetPosition = _vertical->getTargetY() + Session::getExtensionCap(getLayer()); } bool AutoVertical::checkPositions () const { bool coherency = true; DbU::Unit sourcePosition = _vertical->getSourceY() - Session::getExtensionCap(getLayer()); DbU::Unit targetPosition = _vertical->getTargetY() + Session::getExtensionCap(getLayer()); if ( _sourcePosition != sourcePosition ) { cerr << Error ( "%s\n Source position incoherency: " "Shadow: %s, real: %s." , _getString().c_str() , DbU::getValueString(_sourcePosition).c_str() , DbU::getValueString( sourcePosition).c_str() ) << endl; coherency = false; } if ( _targetPosition != targetPosition ) { cerr << Error ( "%s\n Target position incoherency: " "Shadow: %s, real: %s." , _getString().c_str() , DbU::getValueString(_targetPosition).c_str() , DbU::getValueString( targetPosition).c_str() ) << endl; coherency = false; } return coherency; } bool AutoVertical::checkConstraints () const { Interval sourceConstraints = Interval(getAutoSource()->getCBXMin(),getAutoSource()->getCBXMax()); Interval targetConstraints = Interval(getAutoTarget()->getCBXMin(),getAutoTarget()->getCBXMax()); if (not sourceConstraints.intersect(targetConstraints)) { cerr << Error ( "%s\n Constraints incoherency:\n" " S:%s %s\n" " T:%s %s" , _getString().c_str() , getString(sourceConstraints).c_str() , getString(getAutoSource()).c_str() , getString(targetConstraints).c_str() , getString(getAutoTarget()).c_str() ) << endl; return false; } return true; } bool AutoVertical::canMoveULeft ( float reserve ) const { if (not isGlobal()) return false; if (not getAutoSource()->isTurn() or not getAutoTarget()->isTurn()) return false; if (not getAutoSource()->getGCell()->getLeft()) return false; AutoContact* autoSource = getAutoSource(); AutoContact* autoTarget = getAutoTarget(); AutoSegment* perpandiculars[2] = { autoSource->getSegment(0), autoTarget->getSegment(0) }; if ( ( (not perpandiculars[0]->isGlobal()) or (perpandiculars[0]->getAutoSource() == autoSource) ) and ( (not perpandiculars[1]->isGlobal()) or (perpandiculars[1]->getAutoSource() == autoTarget) ) ) return false; GCell* begin = autoSource->getGCell(); GCell* end = autoTarget->getGCell(); unsigned int depth = Session::getRoutingGauge()->getLayerDepth( getLayer() ); float currMaxDensity = 0.0; float leftMaxDensity = 0.0; for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getUp() ) { if (currMaxDensity < gcell->getWDensity(depth)) currMaxDensity = gcell->getWDensity( depth ); } begin = begin->getLeft(); end = end ->getLeft(); for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getUp() ) { if (leftMaxDensity < gcell->getWDensity(depth)) leftMaxDensity = gcell->getWDensity( depth ); } return (leftMaxDensity + reserve < currMaxDensity); } bool AutoVertical::canMoveURight ( float reserve ) const { if (not isGlobal()) return false; if (not getAutoSource()->isTurn() or not getAutoTarget()->isTurn()) return false; if (not getAutoSource()->getGCell()->getRight()) return false; AutoContact* autoSource = getAutoSource(); AutoContact* autoTarget = getAutoTarget(); AutoSegment* perpandiculars[2] = { autoSource->getSegment(0), autoTarget->getSegment(0) }; if ( ( (not perpandiculars[0]->isGlobal()) or (perpandiculars[0]->getAutoTarget() == autoSource) ) and ( (not perpandiculars[1]->isGlobal()) or (perpandiculars[1]->getAutoTarget() == autoTarget) ) ) return false; GCell* begin = autoSource->getGCell(); GCell* end = autoTarget->getGCell(); unsigned int depth = Session::getRoutingGauge()->getLayerDepth( getLayer() ); float currMaxDensity = 0.0; float leftMaxDensity = 0.0; for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getUp() ) { if (currMaxDensity < gcell->getWDensity(depth)) currMaxDensity = gcell->getWDensity( depth ); } begin = begin->getRight(); end = end ->getRight(); for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getUp() ) { if (leftMaxDensity < gcell->getWDensity(depth)) leftMaxDensity = gcell->getWDensity( depth ); } return (leftMaxDensity + reserve < currMaxDensity); } bool AutoVertical::moveULeft () { if (not getAutoSource()->isTurn() or not getAutoTarget()->isTurn()) return false; if (not getAutoSource()->getGCell()->getLeft()) return false; AutoContact* autoSource = getAutoSource(); AutoContact* autoTarget = getAutoTarget(); GCell* begin = autoSource->getGCell(); GCell* end = autoTarget->getGCell(); AutoSegment* perpandicular = autoSource->getSegment(0); if (perpandicular->isLocal()) { perpandicular->setFlags( Katabatic::SegGlobal ); } else { if (perpandicular->getAutoSource() == autoSource) { begin->addHSegment( perpandicular ); } else { if (begin->getLeft() == perpandicular->getAutoSource()->getGCell()) { perpandicular->unsetFlags( Katabatic::SegGlobal ); } else begin->getLeft()->removeHSegment( perpandicular ); } } perpandicular = autoTarget->getSegment(0); if (perpandicular->isLocal()) { perpandicular->setFlags( Katabatic::SegGlobal ); } else { if (perpandicular->getAutoSource() == autoTarget) { end->addHSegment( perpandicular ); } else { if (end->getLeft() == perpandicular->getAutoSource()->getGCell()) { perpandicular->unsetFlags( Katabatic::SegGlobal ); } else end->getLeft()->removeHSegment( perpandicular ); } } if (begin != end) { for ( GCell* gcell=begin->getUp() ; gcell and gcell!=end ; gcell=gcell->getUp() ) gcell->removeVSegment( this ); } begin = begin->getLeft(); end = end ->getLeft(); autoSource->setGCell( begin ); autoTarget->setGCell( end ); if (begin != end) { for ( GCell* gcell=begin->getUp() ; gcell and gcell!=end ; gcell=gcell->getUp() ) gcell->addVSegment( this ); } DbU::Unit x = begin->getSide( KbHorizontal ).getVMax(); setAxis( x ); return true; } bool AutoVertical::moveURight () { ltrace(200) << "AutoVertical::moveURight()" << endl; if (not getAutoSource()->isTurn() or not getAutoTarget()->isTurn()) return true; if (not getAutoSource()->getGCell()->getRight()) return true; AutoContact* autoSource = getAutoSource(); AutoContact* autoTarget = getAutoTarget(); GCell* begin = autoSource->getGCell(); GCell* end = autoTarget->getGCell(); AutoSegment* perpandicular = autoSource->getSegment(0); if (perpandicular->isLocal()) { perpandicular->setFlags( Katabatic::SegGlobal ); } else { if (perpandicular->getAutoTarget() == autoSource) { begin->addHSegment( perpandicular ); } else { if (begin->getRight() == perpandicular->getAutoTarget()->getGCell()) { perpandicular->unsetFlags( Katabatic::SegGlobal ); } else begin->getRight()->removeHSegment( perpandicular ); } } perpandicular = autoTarget->getSegment(0); if (perpandicular->isLocal()) { perpandicular->setFlags( Katabatic::SegGlobal ); } else { if (perpandicular->getAutoTarget() == autoTarget) { end->addHSegment( perpandicular ); } else { if (end->getRight() == perpandicular->getAutoTarget()->getGCell()) { perpandicular->unsetFlags( Katabatic::SegGlobal ); } else end->getRight()->removeHSegment( perpandicular ); } } if (begin != end) { for ( GCell* gcell=begin->getUp() ; gcell and gcell!=end ; gcell=gcell->getUp() ) gcell->removeVSegment( this ); } begin = begin->getRight(); end = end ->getRight(); autoSource->setGCell( begin ); autoTarget->setGCell( end ); if (begin != end) { for ( GCell* gcell=begin->getUp() ; gcell and gcell!=end ; gcell=gcell->getUp() ) gcell->addVSegment( this ); } DbU::Unit x = begin->getSide( KbHorizontal ).getVMin(); setAxis( x ); ltrace(200) << "Moved to axis: " << DbU::getValueString(x) << endl; return true; } unsigned int AutoVertical::_makeDogleg ( GCell* doglegGCell, unsigned int flags ) { ltrace(200) << "AutoVertical::_makeDogleg(GCell*)" << endl; AutoContact* autoSource = getAutoSource(); AutoContact* autoTarget = getAutoTarget(); GCell* begin = autoSource->getGCell(); GCell* end = autoTarget->getGCell(); //Session::doglegReset(); DbU::Unit doglegAxis = (doglegGCell->getYMax() + doglegGCell->getY()) / 2; if (isLocal()) doglegAxis = (getSourceY() + getTargetY()) / 2; if (doglegGCell == begin) unsetFlags( SegGlobal ); if (doglegGCell != end) { GCell* gcell = doglegGCell; do { if (gcell != begin) gcell->removeVSegment( this ); gcell = gcell->getUp(); } while ( gcell and (gcell != end) ); } size_t depth = Session::getRoutingGauge()->getLayerDepth ( _vertical->getLayer() ); bool upLayer = (depth+1 <= Session::getConfiguration()->getAllowedDepth()); Layer* contactLayer = Session::getRoutingGauge()->getContactLayer ( depth + ((upLayer)?0:-1) ); const Layer* doglegLayer = Session::getRoutingGauge()->getRoutingLayer ( depth + ((upLayer)?1:-1) ); Session::dogleg( this ); targetDetach(); invalidate( KbTopology ); autoTarget->invalidate( KbTopology ); AutoContact* dlContact1 = AutoContactTurn::create( doglegGCell, _vertical->getNet(), contactLayer ); ltrace(200) << dlContact1 << endl; AutoContact* dlContact2 = AutoContactTurn::create( doglegGCell, _vertical->getNet(), contactLayer ); ltrace(200) << dlContact2 << endl; AutoSegment* segment1 = AutoSegment::create( dlContact1 , dlContact2, KbHorizontal ); ltrace(200) << segment1 << endl; segment1->setLayer( doglegLayer ); segment1->_setAxis( doglegAxis ); segment1->setFlags( SegDogleg|SegSlackened|SegCanonical|SegNotAligned ); ltrace(200) << "New " << dlContact1->base() << "." << endl; ltrace(200) << "New " << dlContact2->base() << "." << endl; Session::dogleg( segment1 ); targetAttach( dlContact1 ); AutoSegment* segment2 = AutoVertical::create ( dlContact2, autoTarget, KbVertical ); autoTarget->cacheAttach( segment2 ); segment2->setLayer( getLayer() ); segment2->_setAxis( getX() ); segment2->setFlags( (isSlackened()?SegSlackened:0) ); Session::dogleg( segment2 ); if (isSourceTerminal()) { segment1->setFlags( SegWeakTerminal1 ); segment2->setFlags( SegWeakTerminal1 ); autoTarget->unsetFlags( CntWeakTerminal ); dlContact1->setFlags ( CntWeakTerminal ); if (autoTarget->getGCell() == doglegGCell) dlContact1->migrateConstraintBox( autoTarget ); } else if (isTargetTerminal()) { unsetFlags( SegTargetTerminal ); setFlags( SegWeakTerminal1 ); segment1->setFlags( SegWeakTerminal1 ); segment2->setFlags( SegTargetTerminal ); autoSource->unsetFlags( CntWeakTerminal ); dlContact2->setFlags ( CntWeakTerminal ); if (autoSource->getGCell() == doglegGCell) dlContact2->migrateConstraintBox( autoSource ); } else if (isWeakTerminal()) { segment1->setFlags( SegWeakTerminal1 ); segment2->setFlags( SegWeakTerminal1 ); } ltrace(200) << "Session::dogleg[x+1] perpand: " << segment1 << endl; ltrace(200) << "Session::dogleg[x+2] new paral: " << segment2 << endl; ltrace(200) << "Session::dogleg[x+0] original: " << this << endl; dlContact1->updateCache(); dlContact2->updateCache(); //autoTarget->updateCache(); segment2->canonize( flags ); if (not isCanonical()) canonize( flags ); return (upLayer) ? KbUseAboveLayer : KbUseBelowLayer; } string AutoVertical::_getString () const { string s = AutoSegment::_getString(); return s; } Record* AutoVertical::_getRecord () const { Record* record = AutoSegment::_getRecord (); record->add ( getSlot ( "_vertical", _vertical ) ); return record; } } // End of Katabatic namespace.