From 08d1db5dd6bdaa600a19235fdc87b416e9997a50 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Mon, 5 Apr 2021 00:01:54 +0200 Subject: [PATCH] Rewrite support for minimum area metal wires (stacked VIAs). We use the segments extensions (dxTarget & dyTarget) to enlarge if needed the segments. This new implementation is completely at Anabatic level and should not be seen (i.e. managed) at Katana level. * Change: In AutoHorizontal & AutoVertical, change the semantic of getSourceU() and getTargetU(). formerly they where the end position of the segment (with extension included), now they gives the position of the anchor contacts, that is the axis of the perpandiculars. * New: AutoSegment::getLength() is still a proxy toward the Segment::getLength() which returns the length of segment with dxSource & dxTarget. We introduce a getAnchoredlength() which returns the length between the centers of the S/T anchors. That is axis to axis. This is this length which is now used througout Anabatic. * New: In AutoSegment::_extentionCaps, add a fourth item to hold the segment minimal length (to respect minimal area given the wire width). * New: In AutoSegment::getExtensionCap(), if the segment has a non-zero S/T extension, returns it instead of the S/T contact extension *if it is greated*. The check of the extension can be disabled by the Flag::NoSegExt flag. * Change: In AutoSegment::isMiddleStack(), security check on the presence of source and targets. More accurate detection of perpandicular in "same layer" with a non-zero length, So the area is OK, even with a short segment. * New: AutoSegment::expandToMinLength(), check if a segment is under the minimal length and expand it if need be by playing with the dxTarget & dxSource. Tag minimal segments with the AutoSegment::SegAtMinArea flag. Also try to keep the segment *inside* it's former (supposedly wider) interval. * New: AutoSegment::unexpandToMinLength(), to be called on a formerly minimal sized segment which as grown up. Reset it's S/T extensions to zero and unset the flag SegAtMinArea. * Change: In AutoHorizontal::updateOrient(), when the extension are non-zero, also swap them if needed, to keep the exact footprint of the segment. * New: In AutoSegment::revalidate(), check that the segment respect the minimal length (area), and expand it if needed. Conversely, if the segment has grown up from a minimal length state, reset it's extensions to zero. * Change: In Anabatic::Session::revalidate(), invalidateds segments are now sorted in such a way that the "middle stack" ones are revalidateds last. Not recall 100% why... * New: In Katana::TrackCost, add a computation of the free interval length we are into (if any). Not used yet, keep it for future use. * Change: In KatanaEngine::finalizeLayout(), remove the call to segments minimum area protection. It is now obsoleted by the new implementation in Anabatic. * Change: In Track::check(), call the minimum size/area checker Track::checkMinArea(). --- anabatic/src/AnabaticEngine.cpp | 2 +- anabatic/src/AutoContact.cpp | 2 +- anabatic/src/AutoHorizontal.cpp | 31 ++++-- anabatic/src/AutoSegment.cpp | 166 ++++++++++++++++++++++++---- anabatic/src/AutoVertical.cpp | 22 ++-- anabatic/src/Constants.cpp | 2 + anabatic/src/LayerAssign.cpp | 2 +- anabatic/src/NetBuilderHV.cpp | 2 +- anabatic/src/NetBuilderM2.cpp | 2 +- anabatic/src/NetBuilderVH.cpp | 2 +- anabatic/src/Session.cpp | 2 + anabatic/src/anabatic/AutoSegment.h | 16 ++- anabatic/src/anabatic/Constants.h | 2 + katana/src/KatanaEngine.cpp | 14 +-- katana/src/Session.cpp | 19 ++++ katana/src/Track.cpp | 32 +++++- katana/src/TrackCost.cpp | 1 + katana/src/katana/Track.h | 1 + katana/src/katana/TrackCost.h | 5 + 19 files changed, 270 insertions(+), 55 deletions(-) diff --git a/anabatic/src/AnabaticEngine.cpp b/anabatic/src/AnabaticEngine.cpp index ab17e433..ed86a7c4 100644 --- a/anabatic/src/AnabaticEngine.cpp +++ b/anabatic/src/AnabaticEngine.cpp @@ -1355,7 +1355,7 @@ namespace Anabatic { set connectedLayers; forEach ( Segment*, segment, net->getSegments() ) { - if (segment->getLength()) { + if (segment->getAnchoredLength()) { if (net->isExternal()) { NetExternalComponents::setExternal( *segment ); } diff --git a/anabatic/src/AutoContact.cpp b/anabatic/src/AutoContact.cpp index 2978b941..10a17681 100644 --- a/anabatic/src/AutoContact.cpp +++ b/anabatic/src/AutoContact.cpp @@ -227,7 +227,7 @@ namespace Anabatic { size_t depth = Session::getRoutingGauge()->getLayerDepth(segment->getLayer()); DbU::Unit length; if (segment->isLocal()) { - length = segment->getLength(); + length = segment->getAnchoredLength(); lengths[depth] += length; DbU::Unit sideLength = (segment->isHorizontal()) ? hSideLength : vSideLength; diff --git a/anabatic/src/AutoHorizontal.cpp b/anabatic/src/AutoHorizontal.cpp index c91739f7..b9345f2a 100644 --- a/anabatic/src/AutoHorizontal.cpp +++ b/anabatic/src/AutoHorizontal.cpp @@ -47,8 +47,8 @@ namespace Anabatic { Segment* AutoHorizontal::base () { return _horizontal; } Segment* AutoHorizontal::base () const { return _horizontal; } Horizontal* AutoHorizontal::getHorizontal () { return _horizontal; } - DbU::Unit AutoHorizontal::getSourceU () const { return _horizontal->getSourceX(); } - DbU::Unit AutoHorizontal::getTargetU () const { return _horizontal->getTargetX(); } + DbU::Unit AutoHorizontal::getSourceU () const { return _horizontal->getSource()->getX(); } + DbU::Unit AutoHorizontal::getTargetU () const { return _horizontal->getTarget()->getX(); } DbU::Unit AutoHorizontal::getDuSource () const { return _horizontal->getDxSource(); } DbU::Unit AutoHorizontal::getDuTarget () const { return _horizontal->getDxTarget(); } Interval AutoHorizontal::getSpanU () const { return Interval(_horizontal->getSourceX(),_horizontal->getTargetX()); } @@ -335,11 +335,11 @@ namespace Anabatic { cdebug_tabw(149,1); cdebug_log(149,0) << "_flags:" << (_flags & (SegGlobal|SegWeakGlobal)) << endl; - cdebug_log(149,0) << "test:" << (getLength() < 5*getPitch()) << endl; - cdebug_log(149,0) << "length:" << DbU::getValueString(getLength()) << endl; + cdebug_log(149,0) << "test:" << (getAnchoredLength() < 5*getPitch()) << endl; + cdebug_log(149,0) << "length:" << DbU::getValueString(getAnchoredLength()) << endl; if (height >= 4*getPitch()) { - if (not (_flags & (SegGlobal|SegWeakGlobal)) and (getLength() < 5*getPitch())) { + if (not (_flags & (SegGlobal|SegWeakGlobal)) and (getAnchoredLength() < 5*getPitch())) { cdebug_log(149,0) << "Too short terminal segment to slacken." << endl; cdebug_tabw(149,-1); return false; @@ -486,9 +486,18 @@ namespace Anabatic { void AutoHorizontal::updateOrient () { - if (_horizontal->getTargetX() < _horizontal->getSourceX()) { + if (_horizontal->getTarget()->getX() < _horizontal->getSource()->getX()) { cdebug_log(145,0) << "updateOrient() " << this << " (before S/T swap)" << endl; - _horizontal->invert(); + if (isAtMinArea()) { + DbU::Unit sourceX = _horizontal->getSourceX(); + DbU::Unit targetX = _horizontal->getTargetX(); + _horizontal->invert(); + setDuSource( sourceX - getSourceU() ); + setDuTarget( targetX - getTargetU() ); + } else { + _horizontal->invert(); + } + cdebug_log(145,0) << "updateOrient() " << this << " (after S/T swap)" << endl; uint64_t spinFlags = _flags & SegDepthSpin; unsetFlags( SegDepthSpin ); @@ -512,8 +521,8 @@ namespace Anabatic { void AutoHorizontal::updatePositions () { - _sourcePosition = _horizontal->getSourceX() - getExtensionCap(Flags::Source); - _targetPosition = _horizontal->getTargetX() + getExtensionCap(Flags::Target); + _sourcePosition = getSourceU() - getExtensionCap(Flags::Source); + _targetPosition = getTargetU() + getExtensionCap(Flags::Target); } @@ -533,8 +542,8 @@ namespace Anabatic { bool AutoHorizontal::checkPositions () const { bool coherency = true; - DbU::Unit sourcePosition = _horizontal->getSourceX() - getExtensionCap(Flags::Source); - DbU::Unit targetPosition = _horizontal->getTargetX() + getExtensionCap(Flags::Target); + DbU::Unit sourcePosition = _horizontal->getSource()->getX() - getExtensionCap(Flags::Source); + DbU::Unit targetPosition = _horizontal->getTarget()->getX() + getExtensionCap(Flags::Target); if ( _sourcePosition != sourcePosition ) { cerr << "extensionCap: " << DbU::getValueString(getExtensionCap(Flags::Source)) << endl; diff --git a/anabatic/src/AutoSegment.cpp b/anabatic/src/AutoSegment.cpp index 2b57f510..1b6e421b 100644 --- a/anabatic/src/AutoSegment.cpp +++ b/anabatic/src/AutoSegment.cpp @@ -348,7 +348,7 @@ namespace Anabatic { if ( deltaUnit < 0 ) return true; // Smallest source first. if ( deltaUnit > 0 ) return false; - deltaUnit = lhs->getLength() - rhs->getLength(); + deltaUnit = lhs->getAnchoredLength() - rhs->getAnchoredLength(); if ( deltaUnit > 0 ) return true; // Longest first. if ( deltaUnit < 0 ) return false; @@ -409,6 +409,22 @@ namespace Anabatic { } +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoSegment::CompareByRevalidate". + + + bool AutoSegment::CompareByRevalidate::operator() ( AutoSegment* lhs, AutoSegment* rhs ) const + { + if (lhs->isNonPref() xor rhs->isNonPref() ) return lhs->isNonPref(); + + DbU::Unit deltaLength = lhs->getAnchoredLength() - rhs->getAnchoredLength(); + if (deltaLength > 0) return true; // Longest length first. + if (deltaLength < 0) return false; + + return lhs->getId() < rhs->getId(); // Smallest Id first. + } + + // ------------------------------------------------------------------- // Class : "Anabatic::AutoSegment". @@ -431,6 +447,7 @@ namespace Anabatic { //cerr << "AutoSegment::_initialize()" << endl; _initialized = true; + DbU::Unit twoGrid = DbU::fromGrid( 2 ); for ( size_t depth=0 ; depthgetMinimalArea(); if (minimalArea != 0.0) { *minimalLength = DbU::fromMicrons( minimalArea / DbU::toMicrons( Session::getWireWidth(depth) ) ); + DbU::Unit modulo = *minimalLength % twoGrid; + if (modulo) + *minimalLength += twoGrid - modulo; } //cerr << " viaToTop width: " << DbU::getValueString( Session::getViaWidth(depth) ) << endl; @@ -684,6 +704,10 @@ namespace Anabatic { incReduceds(); } + Interval oldSpan = Interval( _sourcePosition, _targetPosition ); + if (not expandToMinLength(oldSpan)) { + unexpandToMinLength(); + } updatePositions(); unsigned int observerFlags = Revalidate; @@ -736,25 +760,50 @@ namespace Anabatic { if (getFlags() & SegSourceTop ) cap = getViaToTopCap (depth); else if (getFlags() & SegSourceBottom) cap = getViaToBottomCap(depth); else cap = getViaToSameCap (depth); - cdebug_log(150,0) << "getExtensionCap(): flags:" << getFlags() + cdebug_log(150,0) << "getExtensionCap(): (source) flags:" << getFlags() << " VIA cap:" << DbU::getValueString(cap) << " t:" << (getFlags() & SegSourceBottom) << " b:" << (getFlags() & SegSourceTop) << endl; + if (not (flags & Flags::NoSegExt)) { + cdebug_log(150,0) << "duSource=" << DbU::getValueString(getDuSource()) << endl; + if (-getDuSource() > cap) { + cap = -getDuSource(); + cdebug_log(150,0) << "-> Custom cap (-duSource):" << DbU::getValueString(cap) << endl; + } + } } if (flags & Flags::Target) { if (getFlags() & SegTargetTop ) cap = getViaToTopCap (depth); else if (getFlags() & SegTargetBottom) cap = getViaToBottomCap(depth); else cap = getViaToSameCap (depth); - } - - if (not isCreated() and (getMinimalLength(depth) != 0.0) and isMiddleStack()) { - if (getLength() < getMinimalLength(depth)) { - cap = std::max( cap, getMinimalLength(depth)/2 ); + cdebug_log(150,0) << "getExtensionCap(): (target) flags:" << getFlags() + << " VIA cap:" << DbU::getValueString(cap) + << " t:" << (getFlags() & SegSourceBottom) + << " b:" << (getFlags() & SegSourceTop) + << endl; + if (not (flags & Flags::NoSegExt)) { + cdebug_log(150,0) << "duTarget=" << DbU::getValueString(getDuTarget()) << endl; + if (getDuTarget() > cap) { + cap = getDuTarget(); + cdebug_log(150,0) << "-> Custom cap (+duTarget):" << DbU::getValueString(cap) << endl; + } } } + // if ( not isCreated() + // and not (flags & Flags::NoMinLength) + // and (flags & Flags::Target) + // and (getMinimalLength(depth) != 0.0) + // and isMiddleStack() ) { + // DbU::Unit realLength = getExtensionCap( Flags::Source|Flags::LayerCapOnly|Flags::NoMinLength ) + // + getAnchoredLength(); + // if (realLength + cap < getMinimalLength(depth)) { + // cap = getMinimalLength(depth) - realLength; + // } + // } + if (getLayer()->isSymbolic() and (cap < getWidth()/2)) cap = getWidth()/2; if (not (flags & Flags::LayerCapOnly)) cap += getLayer()->getMinimalSpacing()/2; return cap; @@ -1329,7 +1378,7 @@ namespace Anabatic { if (terminalMin != terminalMax) attractors.addAttractor( terminalMax ); } - } else if (autoSegment->isLongLocal() or (autoSegment->getLength() > getPPitch()*20)) { + } else if (autoSegment->isLongLocal() or (autoSegment->getAnchoredLength() > getPPitch()*20)) { cdebug_log(145,0) << "Used as long global attractor." << endl; DbU::Unit perpandMin = autoSegment->getSourceU(); @@ -1555,16 +1604,95 @@ namespace Anabatic { bool AutoSegment::isMiddleStack () const { - if (isGlobal()) return false; - if (isSpinTopOrBottom()) return false; - + cdebug_log(149,0) << "AutoSegment::isMiddleStack() - " << this << endl; + if (isGlobal() or isNonPref()) return false; AutoContact* source = getAutoSource(); AutoContact* target = getAutoTarget(); + if (not source or not target) return false; + if (isSpinTopOrBottom()) return false; + if (not source->isTurn() and not source->isTerminal()) return false; + if (not target->isTurn() and not target->isTerminal()) return false; + if (source->isTurn()) { + AutoSegment* perpandicular = source->getPerpandicular( this ); + if (perpandicular->isNonPref() and (perpandicular->getAnchoredLength() != 0)) { + cdebug_log(149,0) << "| false, perpandicular is non-pref and non-zero. " << this << endl; + return false; + } + } + if (target->isTurn()) { + AutoSegment* perpandicular = target->getPerpandicular( this ); + if (perpandicular->isNonPref() and (perpandicular->getAnchoredLength() != 0)) { + cdebug_log(149,0) << "| false, perpandicular is non-pref and non-zero. " << this << endl; + return false; + } + } + cdebug_log(149,0) << " Middle stack or terminal bound." << endl; + return true; + } - if (not source->isTurn() or not target->isTurn()) return false; - if (source->getPerpandicular(this)->isNonPref()) return false; - if (target->getPerpandicular(this)->isNonPref()) return false; + bool AutoSegment::isUnderMinLength () const + { + return false; + // cdebug_log(149,0) << "AutoSegment::isUnderMinLength() - " << this << endl; + // if (not isMiddleStack()) return false; + // DbU::Unit spanLength = getSpanLength(); + // DbU::Unit minimalLength = getMinimalLength( Session::getLayerDepth( getLayer() )); + // cdebug_log(149,0) << " span=" << DbU::getValueString(spanLength) + // << " < min=" << DbU::getValueString(minimalLength)<< endl; + // return spanLength < minimalLength; + } + + + bool AutoSegment::expandToMinLength ( Interval span ) + { + if (not isMiddleStack()) return false; + cdebug_log(149,1) << "AutoSegment::expandToMinLength() " << this << endl; + cdebug_log(149,0) << "In span=" << span << endl; + cdebug_log(149,0) << "Before: [" << DbU::getValueString(getSourceU() - getExtensionCap( Flags::Source|Flags::LayerCapOnly )) + << " " << DbU::getValueString(getTargetU() + getExtensionCap( Flags::Target|Flags::LayerCapOnly )) + << "]" << endl; + + DbU::Unit sourceCap = getExtensionCap( Flags::Source|Flags::NoSegExt|Flags::LayerCapOnly ); + DbU::Unit targetCap = getExtensionCap( Flags::Target|Flags::NoSegExt|Flags::LayerCapOnly ); + DbU::Unit segMinLength = getAnchoredLength() + sourceCap + targetCap; + DbU::Unit techMinLength = getMinimalLength( Session::getLayerDepth( getLayer() )); + if (techMinLength <= segMinLength) { + cdebug_log(149,0) << "Above minimal length (" << DbU::getValueString(segMinLength) + << " >= " << DbU::getValueString(techMinLength) << ")" << endl; + cdebug_tabw(149,-1); + return false; + } + + DbU::Unit targetExpand = (techMinLength - segMinLength) / 2 + targetCap; + DbU::Unit sourceExpand = - (techMinLength - segMinLength) / 2 - sourceCap; + if (not span.isEmpty()) { + DbU::Unit shiftLeft = span.getVMax() - (getTargetU() + targetExpand); + if (shiftLeft < 0) { + targetExpand += shiftLeft; + sourceExpand += shiftLeft; + } + } + setDuSource( sourceExpand ); + setDuTarget( targetExpand ); + cdebug_log(149,0) << "sourceExpand=" << DbU::getValueString(sourceExpand) + << " targetExpand=" << DbU::getValueString(targetExpand) << endl; + cdebug_log(149,0) << "After: [" << DbU::getValueString(getSourceU() - getExtensionCap( Flags::Source|Flags::LayerCapOnly )) + << " " << DbU::getValueString(getTargetU() + getExtensionCap( Flags::Target|Flags::LayerCapOnly )) + << "] expand:" << DbU::getValueString(techMinLength - segMinLength)<< endl; + setFlags( SegAtMinArea ); + cdebug_tabw(149,-1); + return true; + } + + + bool AutoSegment::unexpandToMinLength () + { + if (not isAtMinArea()) return false; + cdebug_log(149,0) << "AutoSegment::unexpandToMinLength() " << this << endl; + setDuSource( 0 ); + setDuTarget( 0 ); + unsetFlags( SegAtMinArea ); return true; } @@ -1614,8 +1742,8 @@ namespace Anabatic { } else return false; - cdebug_log(159,0) << " length:" << DbU::getValueString(getLength()) << endl; - if (getLength() >= (Session::getPitch(perpandicularDepth) * 2)) return false; + cdebug_log(159,0) << " length:" << DbU::getValueString(getAnchoredLength()) << endl; + if (getAnchoredLength() >= (Session::getPitch(perpandicularDepth) * 2)) return false; return true; } @@ -1653,7 +1781,7 @@ namespace Anabatic { else if (isSpinTop ()) ++perpandicularDepth; else return true; - return (getLength() >= (Session::getPitch(perpandicularDepth) * 2)); + return (getAnchoredLength() >= (Session::getPitch(perpandicularDepth) * 2)); } @@ -2846,7 +2974,7 @@ namespace Anabatic { exploreds.insert( seed->getAutoSource() ); exploreds.insert( seed->getAutoTarget() ); - if (seed->getLength()) { + if (seed->getAnchoredLength()) { if (flags & Flags::Superior) stack.push_back( seed->getAutoTarget() ); else stack.push_back( seed->getAutoSource() ); } else { @@ -2871,7 +2999,7 @@ namespace Anabatic { AutoSegment* autoSegment = Session::lookup( segment ); if (not autoSegment) continue; - if (not autoSegment->getLength()) { + if (not autoSegment->getAnchoredLength()) { AutoContact* contact = autoSegment->getAutoSource(); if (contact and (contact != currentContact)) { if (exploreds.find(contact) == exploreds.end()) diff --git a/anabatic/src/AutoVertical.cpp b/anabatic/src/AutoVertical.cpp index bed3c094..2dfa47c3 100644 --- a/anabatic/src/AutoVertical.cpp +++ b/anabatic/src/AutoVertical.cpp @@ -41,8 +41,8 @@ namespace Anabatic { 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::getSourceU () const { return _vertical->getSource()->getY(); } + DbU::Unit AutoVertical::getTargetU () const { return _vertical->getTarget()->getY(); } 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()); } @@ -268,13 +268,13 @@ namespace Anabatic { if (not isDrag()) { if ( not isStrongTerminal() - or (not (_flags & (SegGlobal|SegWeakGlobal)) and (getLength() < getPitch()*5)) ) + or (not (_flags & (SegGlobal|SegWeakGlobal)) and (getAnchoredLength() < getPitch()*5)) ) { cdebug_tabw(149,-1); return false; } } cdebug_log(149,0) << "_flags:" << (_flags & (SegGlobal|SegWeakGlobal)) << endl; - cdebug_log(149,0) << "test:" << (getLength() < getPitch()*5) << endl; - cdebug_log(149,0) << "length:" << DbU::getValueString(getLength()) << endl; + cdebug_log(149,0) << "test:" << (getAnchoredLength() < getPitch()*5) << endl; + cdebug_log(149,0) << "length:" << DbU::getValueString(getAnchoredLength()) << endl; bool success = false; bool sourceSlackened = false; @@ -382,6 +382,10 @@ namespace Anabatic { if (_vertical->getTargetY() < _vertical->getSourceY()) { cdebug_log(145,0) << "updateOrient() " << this << " (before S/T swap)" << endl; _vertical->invert(); + DbU::Unit duSource = getDuSource(); + DbU::Unit duTarget = getDuTarget(); + setDuSource( -duTarget ); + setDuTarget( -duSource ); unsigned int spinFlags = _flags & SegDepthSpin; unsetFlags( SegDepthSpin ); @@ -405,8 +409,8 @@ namespace Anabatic { void AutoVertical::updatePositions () { - _sourcePosition = _vertical->getSourceY() - getExtensionCap(Flags::Source); - _targetPosition = _vertical->getTargetY() + getExtensionCap(Flags::Target); + _sourcePosition = getSourceU() - getExtensionCap(Flags::Source); + _targetPosition = getTargetU() + getExtensionCap(Flags::Target); } @@ -426,8 +430,8 @@ namespace Anabatic { bool AutoVertical::checkPositions () const { bool coherency = true; - DbU::Unit sourcePosition = _vertical->getSourceY() - getExtensionCap(Flags::Source); - DbU::Unit targetPosition = _vertical->getTargetY() + getExtensionCap(Flags::Target); + DbU::Unit sourcePosition = _vertical->getSource()->getY() - getExtensionCap(Flags::Source); + DbU::Unit targetPosition = _vertical->getTarget()->getY() + getExtensionCap(Flags::Target); if ( _sourcePosition != sourcePosition ) { cerr << Error ( "%s\n Source position incoherency: " diff --git a/anabatic/src/Constants.cpp b/anabatic/src/Constants.cpp index 9e7af137..d3a72004 100644 --- a/anabatic/src/Constants.cpp +++ b/anabatic/src/Constants.cpp @@ -122,6 +122,8 @@ namespace Anabatic { const BaseFlags Flags::UseNonPref = (1L << 34); const BaseFlags Flags::Force = (1L << 35); const BaseFlags Flags::LayerCapOnly = (1L << 36); + const BaseFlags Flags::NoMinLength = (1L << 37); + const BaseFlags Flags::NoSegExt = (1L << 38); Flags::~Flags () diff --git a/anabatic/src/LayerAssign.cpp b/anabatic/src/LayerAssign.cpp index 569c1e0d..fd5424d5 100644 --- a/anabatic/src/LayerAssign.cpp +++ b/anabatic/src/LayerAssign.cpp @@ -754,7 +754,7 @@ namespace Anabatic { if (not segment->isStrongTerminal()) locals.push_back( segment ); continue; } - if ( (segment->getLength() < 3*Session::getSliceHeight()) and (segment != seed) ) { + if ( (segment->getAnchoredLength() < 3*Session::getSliceHeight()) and (segment != seed) ) { locals.push_back( segment ); continue; } diff --git a/anabatic/src/NetBuilderHV.cpp b/anabatic/src/NetBuilderHV.cpp index bcc0d615..43ea958d 100644 --- a/anabatic/src/NetBuilderHV.cpp +++ b/anabatic/src/NetBuilderHV.cpp @@ -1737,7 +1737,7 @@ namespace Anabatic { cdebug_log(145,0) << "Create global segment: " << globalSegment << endl; // HARDCODED VALUE. - if ( (getTopology() & Global_Fixed) and (globalSegment->getLength() < 2*Session::getSliceHeight()) ) + if ( (getTopology() & Global_Fixed) and (globalSegment->getAnchoredLength() < 2*Session::getSliceHeight()) ) addToFixSegments( globalSegment ); if (getConnexity().fields.globals < 2) { diff --git a/anabatic/src/NetBuilderM2.cpp b/anabatic/src/NetBuilderM2.cpp index 42824e6e..242b007d 100644 --- a/anabatic/src/NetBuilderM2.cpp +++ b/anabatic/src/NetBuilderM2.cpp @@ -318,7 +318,7 @@ namespace Anabatic { cdebug_log(145,0) << "Create global segment: " << globalSegment << endl; // HARDCODED VALUE. - if ( (getTopology() & Global_Fixed) and (globalSegment->getLength() < 2*Session::getSliceHeight()) ) + if ( (getTopology() & Global_Fixed) and (globalSegment->getAnchoredLength() < 2*Session::getSliceHeight()) ) addToFixSegments( globalSegment ); if (getConnexity().fields.globals < 2) { diff --git a/anabatic/src/NetBuilderVH.cpp b/anabatic/src/NetBuilderVH.cpp index 51c92749..a7539618 100644 --- a/anabatic/src/NetBuilderVH.cpp +++ b/anabatic/src/NetBuilderVH.cpp @@ -577,7 +577,7 @@ namespace Anabatic { cdebug_log(145,0) << "Create global segment: " << globalSegment << endl; // HARDCODED VALUE. - if ( (getTopology() & Global_Fixed) and (globalSegment->getLength() < 2*Session::getSliceHeight()) ) + if ( (getTopology() & Global_Fixed) and (globalSegment->getAnchoredLength() < 2*Session::getSliceHeight()) ) addToFixSegments( globalSegment ); if (getConnexity().fields.globals < 2) { diff --git a/anabatic/src/Session.cpp b/anabatic/src/Session.cpp index 6bc4639b..66e56cc4 100644 --- a/anabatic/src/Session.cpp +++ b/anabatic/src/Session.cpp @@ -259,6 +259,8 @@ namespace Anabatic { cdebug_log(145,0) << "_segmentInvalidateds.size(): " << _segmentInvalidateds.size() << endl; _segmentRevalidateds.clear(); + std::sort( _segmentInvalidateds.begin(), _segmentInvalidateds.end() + , AutoSegment::CompareByRevalidate() ); for ( size_t i=0 ; i < _segmentInvalidateds.size() ; ++i, ++count ) { _segmentInvalidateds[i]->revalidate(); if ( not _destroyedSegments.empty() diff --git a/anabatic/src/anabatic/AutoSegment.h b/anabatic/src/anabatic/AutoSegment.h index 1721e8e2..c058dae4 100644 --- a/anabatic/src/anabatic/AutoSegment.h +++ b/anabatic/src/anabatic/AutoSegment.h @@ -107,6 +107,7 @@ namespace Anabatic { static const uint64_t SegShortNet = (1L<<35); static const uint64_t SegUnbreakable = (1L<<36); static const uint64_t SegNonPref = (1L<<37); + static const uint64_t SegAtMinArea = (1L<<38); // Masks. static const uint64_t SegWeakTerminal = SegStrongTerminal|SegWeakTerminal1|SegWeakTerminal2; static const uint64_t SegNotAligned = SegNotSourceAligned|SegNotTargetAligned; @@ -173,6 +174,7 @@ namespace Anabatic { inline DbU::Unit getContactWidth () const; inline DbU::Unit getLength () const; inline DbU::Unit getSpanLength () const; + inline DbU::Unit getAnchoredLength () const; inline DbU::Unit getSourcePosition () const; inline DbU::Unit getTargetPosition () const; inline DbU::Unit getSourceX () const; @@ -200,6 +202,7 @@ namespace Anabatic { inline bool isUnbreakable () const; inline bool isNonPref () const; inline bool isDrag () const; + inline bool isAtMinArea () const; inline bool isNotSourceAligned () const; inline bool isNotTargetAligned () const; inline bool isNotAligned () const; @@ -212,6 +215,7 @@ namespace Anabatic { inline bool isSpinBottom () const; inline bool isSpinTopOrBottom () const; inline bool isReduced () const; + bool isUnderMinLength () const; inline bool isStrap () const; inline bool isDogleg () const; inline bool isUnbound () const; @@ -332,6 +336,8 @@ namespace Anabatic { bool bloatStackedStrap (); bool reduce (); bool raise (); + bool expandToMinLength ( Interval ); + bool unexpandToMinLength (); // Canonical Modifiers. AutoSegment* canonize ( Flags flags=Flags::NoFlags ); virtual void invalidate ( Flags flags=Flags::Propagate ); @@ -425,6 +431,10 @@ namespace Anabatic { struct CompareBySourceU : public binary_function { bool operator() ( AutoSegment* lhs, AutoSegment* rhs ) const; }; + public: + struct CompareByRevalidate : public binary_function { + bool operator() ( AutoSegment* lhs, AutoSegment* rhs ) const; + }; public: typedef std::set DepthLengthSet; typedef std::set IdSet; @@ -526,6 +536,7 @@ namespace Anabatic { inline bool AutoSegment::isTargetTerminal () const { return _flags & SegTargetTerminal; } inline bool AutoSegment::isTerminal () const { return (_rpDistance == 0); } inline bool AutoSegment::isDrag () const { return _flags & SegDrag; } + inline bool AutoSegment::isAtMinArea () const { return _flags & SegAtMinArea; } inline bool AutoSegment::isNotSourceAligned () const { return _flags & SegNotSourceAligned; } inline bool AutoSegment::isNotTargetAligned () const { return _flags & SegNotTargetAligned; } inline bool AutoSegment::isNotAligned () const { return (_flags & SegNotAligned) == SegNotAligned; } @@ -564,6 +575,7 @@ namespace Anabatic { inline void AutoSegment::resetNativeConstraints ( DbU::Unit min, DbU::Unit max ) { _nativeConstraints = Interval( min, max ); } //inline void AutoSegment::mergeUserConstraints ( const Interval& constraints ) { _userConstraints.intersection(constraints); } inline void AutoSegment::resetUserConstraints () { _userConstraints = Interval(false); } + inline DbU::Unit AutoSegment::getAnchoredLength () const { return std::abs(getTargetU() - getSourceU()); } inline void AutoSegment::setLayer ( size_t depth ) { @@ -579,8 +591,8 @@ namespace Anabatic { { return getWidth() + Session::getViaWidth(getLayer()) - Session::getWireWidth(getLayer()); } inline DbU::Unit AutoSegment::getSpanLength () const - { return getLength() + getExtensionCap( Flags::Source|Flags::LayerCapOnly ) - + getExtensionCap( Flags::Target|Flags::LayerCapOnly ); + { return getAnchoredLength() + getExtensionCap( Flags::Source|Flags::LayerCapOnly|Flags::NoMinLength ) + + getExtensionCap( Flags::Target|Flags::LayerCapOnly|Flags::NoMinLength ); } inline void AutoSegment::setParent ( AutoSegment* parent ) diff --git a/anabatic/src/anabatic/Constants.h b/anabatic/src/anabatic/Constants.h index 35e631fe..6a9acdcd 100644 --- a/anabatic/src/anabatic/Constants.h +++ b/anabatic/src/anabatic/Constants.h @@ -103,6 +103,8 @@ namespace Anabatic { static const BaseFlags UseNonPref ; static const BaseFlags Force ; static const BaseFlags LayerCapOnly ; + static const BaseFlags NoMinLength ; + static const BaseFlags NoSegExt ; public: inline Flags ( uint64_t flags = NoFlags ); inline Flags ( const Hurricane::BaseFlags& ); diff --git a/katana/src/KatanaEngine.cpp b/katana/src/KatanaEngine.cpp index a2e9b2f0..0867f3a1 100644 --- a/katana/src/KatanaEngine.cpp +++ b/katana/src/KatanaEngine.cpp @@ -844,13 +844,13 @@ namespace Katana { cdebug_tabw(155,1); - openSession(); - for ( RoutingPlane* plane : _routingPlanes ) { - for ( Track* track : plane->getTracks() ) { - track->expandMinArea(); - } - } - Session::close(); + // openSession(); + // for ( RoutingPlane* plane : _routingPlanes ) { + // for ( Track* track : plane->getTracks() ) { + // track->expandMinArea(); + // } + // } + // Session::close(); setState( Anabatic::EngineDriving ); _gutKatana(); diff --git a/katana/src/Session.cpp b/katana/src/Session.cpp index 3e037011..25344b70 100644 --- a/katana/src/Session.cpp +++ b/katana/src/Session.cpp @@ -324,6 +324,25 @@ namespace Katana { TrackElement* trackSegment = lookup( revalidateds[i] ); if (trackSegment) trackSegment->reschedule( 0 ); } + // if (revalidateds[i]->isUnderMinLength()) { + // cdebug_log(159,0) << "Session: under min length:" << revalidateds[i] << endl; + // revalidateds[i]->expandToMinLength(); + // TrackElement* trackSegment = lookup( revalidateds[i] ); + // if (trackSegment) { + // trackSegment->invalidate(); + // trackSegment->reschedule( 0 ); + // } + // } else { + // if (revalidateds[i]->isAtMinArea()) { + // if (revalidateds[i]->unexpandToMinLength()) { + // TrackElement* trackSegment = lookup( revalidateds[i] ); + // if (trackSegment) { + // trackSegment->invalidate(); + // trackSegment->reschedule( 0 ); + // } + // } + // } + // } if (revalidateds[i]->canReduce()) { revalidateds[i]->reduce(); TrackElement* trackSegment = lookup( revalidateds[i] ); diff --git a/katana/src/Track.cpp b/katana/src/Track.cpp index 9ac92725..6252f9ac 100644 --- a/katana/src/Track.cpp +++ b/katana/src/Track.cpp @@ -373,8 +373,12 @@ namespace Katana { const Interval& interval = cost.getInterval(); Interval freeInterval = getFreeInterval( interval.getCenter(), cost.getNet() ); - if (not freeInterval.contains(interval)) + if (not freeInterval.contains(interval)) { getOverlapBounds( cost.getInterval(), begin, end ); + cost.setFreeLength( 0 ); + } else { + cost.setFreeLength( freeInterval.getSize() ); + } cost.setTrack( const_cast(this), begin, end ); cdebug_log(155,1) << "addOverlapCost() @" << DbU::getValueString(_axis) @@ -658,6 +662,8 @@ namespace Katana { if (not holes) coherency = (checkOverlap(overlaps) == 0) and coherency; + coherency = (checkMinArea() == 0) and coherency; + return coherency; } @@ -867,6 +873,30 @@ namespace Katana { } + uint32_t Track::checkMinArea () const + { + if (_segments.empty()) return 0; + + uint32_t nonMinArea = 0; + DbU::Unit techMinLength = AutoSegment::getMinimalLength( Session::getLayerDepth( getLayer() )); + for ( size_t j=0 ; j<_segments.size() ; ++j ) { + if (not _segments[j]->base() or not (_segments[j]->getDirection() & getDirection())) { + ++j; + continue; + } + if (not _segments[j]->base()->isMiddleStack()) continue; + if (_segments[j]->base()->getSpanLength() < techMinLength) { + cerr << Error( "Below minimal length/area for %s:\n length:%s, minimal length:%s" + , getString(_segments[j]).c_str() + , DbU::getValueString(_segments[j]->base()->getSpanLength()).c_str() + , DbU::getValueString(techMinLength).c_str() ) << endl; + ++nonMinArea; + } + } + return nonMinArea; + } + + void Track::expandMinArea () { if (_segments.empty()) return; diff --git a/katana/src/TrackCost.cpp b/katana/src/TrackCost.cpp index 56f775bf..ceb96596 100644 --- a/katana/src/TrackCost.cpp +++ b/katana/src/TrackCost.cpp @@ -57,6 +57,7 @@ namespace Katana { , _axisWeight (0) , _distanceToFixed (2*Session::getSliceHeight()) , _longuestOverlap (0) + , _freeLength (DbU::Max) , _dataState (0) , _ripupCount (0) , _selectFlags (NoFlags) diff --git a/katana/src/katana/Track.h b/katana/src/katana/Track.h index c9c5977f..8a59de55 100644 --- a/katana/src/katana/Track.h +++ b/katana/src/katana/Track.h @@ -99,6 +99,7 @@ namespace Katana { DbU::Unit getSourcePosition ( size_t index ) const; bool check ( uint32_t& overlaps, const char* message=NULL ) const; uint32_t checkOverlap ( uint32_t& overlaps ) const; + uint32_t checkMinArea () const; void expandMinArea (); inline void setLocalAssigned ( bool ); void invalidate (); diff --git a/katana/src/katana/TrackCost.h b/katana/src/katana/TrackCost.h index c2fc2bca..46092d1d 100644 --- a/katana/src/katana/TrackCost.h +++ b/katana/src/katana/TrackCost.h @@ -131,6 +131,7 @@ namespace Katana { inline DbU::Unit getDeltaPerpand () const; inline DbU::Unit getLongestOverlap () const; inline DbU::Unit getAxisWeight () const; + inline DbU::Unit getFreeLength () const; inline int getRipupCount () const; inline uint32_t getDataState () const; inline uint32_t setFlags ( uint32_t ); @@ -152,6 +153,7 @@ namespace Katana { inline void incDeltaShared ( DbU::Unit ); inline void incAxisWeight ( DbU::Unit ); inline void setLonguestOverlap ( DbU::Unit ); + inline void setFreeLength ( DbU::Unit ); inline void mergeRipupCount ( int ); inline void mergeDataState ( uint32_t ); inline bool selectNextTrack (); @@ -183,6 +185,7 @@ namespace Katana { DbU::Unit _axisWeight; DbU::Unit _distanceToFixed; DbU::Unit _longuestOverlap; + DbU::Unit _freeLength; uint32_t _dataState; int _ripupCount; uint32_t _selectFlags; @@ -223,6 +226,7 @@ namespace Katana { inline const Interval& TrackCost::getInterval2 () const { return _interval2; } inline uint32_t TrackCost::getTerminals () const { return _terminals; } inline DbU::Unit TrackCost::getLongestOverlap () const { return _longuestOverlap; } + inline DbU::Unit TrackCost::getFreeLength () const { return _freeLength; } inline DbU::Unit TrackCost::getDelta () const { return _delta; } inline DbU::Unit TrackCost::getAxisWeight () const { return _axisWeight; } inline int TrackCost::getRipupCount () const { return _ripupCount; } @@ -245,6 +249,7 @@ namespace Katana { inline void TrackCost::incDeltaShared ( DbU::Unit delta ) { _deltaShared += delta; } inline void TrackCost::incAxisWeight ( DbU::Unit weight ) { _axisWeight += weight; } inline void TrackCost::setLonguestOverlap ( DbU::Unit overlap ) { _longuestOverlap = std::max( overlap, _longuestOverlap ); } + inline void TrackCost::setFreeLength ( DbU::Unit length ) { _freeLength = std::min( length , _freeLength ); } inline void TrackCost::mergeRipupCount ( int count ) { _ripupCount = std::max( count , _ripupCount ); } inline void TrackCost::mergeDataState ( uint32_t state ) { _dataState = std::max( state , _dataState ); } inline string TrackCost::_getTypeName () const { return "TrackCost"; }