// -*- 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 : "./AutoContact.cpp" | // +-----------------------------------------------------------------+ #include #include #include #include "hurricane/Bug.h" #include "hurricane/Error.h" #include "hurricane/Warning.h" #include "hurricane/Layer.h" #include "hurricane/ViaLayer.h" #include "hurricane/BasicLayer.h" #include "hurricane/Technology.h" #include "hurricane/Net.h" #include "hurricane/Plug.h" #include "hurricane/RoutingPad.h" #include "hurricane/Vertical.h" #include "hurricane/Horizontal.h" #include "hurricane/DebugSession.h" #include "crlcore/RoutingGauge.h" #include "anabatic/AutoContact.h" #include "anabatic/AutoContactTerminal.h" #include "anabatic/AutoContactTurn.h" #include "anabatic/AutoContactHTee.h" #include "anabatic/AutoContactVTee.h" #include "anabatic/AutoVertical.h" #include "anabatic/AutoHorizontal.h" #include "anabatic/AnabaticEngine.h" #include "anabatic/Session.h" namespace Anabatic { using std::ostringstream; using Hurricane::Bug; using Hurricane::Error; using Hurricane::Warning; using Hurricane::DebugSession; using Hurricane::ForEachIterator; // ------------------------------------------------------------------- // Class : "Anabatic::AutoContact". size_t AutoContact::_maxId = 0; size_t AutoContact::_allocateds = 0; const Name AutoContact::_goName = "Anabatic::AutoContact"; AutoContact::AutoContact ( GCell* gcell, Contact* contact ) : _id (contact->getId()) , _contact (contact) , _gcell (gcell) , _flags (CntInvalidatedCache|CntInCreationStage) , _xMin (_gcell->getXMin()) , _xMax (_gcell->getConstraintXMax()) , _yMin (_gcell->getYMin()) , _yMax (_gcell->getConstraintYMax()) { _allocateds++; _gcell->addContact ( this ); } void AutoContact::_preCreate ( GCell* gcell, Net* net, const Layer* layer ) { if (not gcell) throw Error("AutoContact::_preCreate(): GCell* parameter must not be NULL."); if (not net ) throw Error("AutoContact::_preCreate(): Net* parameter must not be NULL."); if (not layer) throw Error("AutoContact::_preCreate(): const Layer* parameter must not be NULL."); } void AutoContact::_postCreate () { restoreNativeConstraintBox(); cdebug_log(145,0) << "Native CBox: " << this << " <" << DbU::getValueString(getCBXMin()) << " " << DbU::getValueString(getCBYMin()) << " " << DbU::getValueString(getCBXMax()) << " " << DbU::getValueString(getCBYMax()) << ">" << endl; Session::link( this ); invalidate( Flags::Topology ); cdebug_log(145,0) << "AutoContact::_postCreate() - " << this << " in " << _gcell << endl; } void AutoContact::destroy () { _preDestroy (); delete this; } void AutoContact::_preDestroy () { DebugSession::open( _contact->getNet(), 145, 150 ); cdebug_log(145,0) << "AutoContact::_preDestroy() - " << endl; #if 0 bool canDestroyBase = true; if (not _contact->getSlaveComponents().isEmpty()) { ostringstream message; message << "Base contact still have slaves components, cancelled.\n" << " on: " << this; for ( Component* component : _contact->getSlaveComponents() ) { message << "\n | " << component; } cerr << Error( message.str() ) << endl; canDestroyBase = false; } #endif if (not Session::doDestroyTool()) { _gcell->removeContact( this ); Session::unlink( this ); } #if 0 if (Session::doDestroyBaseContact() and canDestroyBase) _contact->destroy(); #endif DebugSession::close(); } AutoContact::~AutoContact () { _allocateds--; } size_t AutoContact::getAllocateds () { return _allocateds; } const Name& AutoContact::getStaticName () { return _goName; } bool AutoContact::canDestroy ( Flags flags ) const { if (not _contact->getSlaveComponents().isEmpty()) { if (flags & Flags::WarnOnError) { cerr << Error("Base contact still have slaves components, cancelled.\n" " (%s)" ,_getString().c_str()) << endl; } return false; } return true; } const Name& AutoContact::getName () const { return _goName; } AutoSegments AutoContact::getAutoSegments () { return new AutoSegments_CachedOnContact(this); } AutoSegment* AutoContact::getPerpandicular ( const AutoSegment* ) const { return NULL; } AutoHorizontal* AutoContact::getHorizontal1 () const { return NULL; } AutoHorizontal* AutoContact::getHorizontal2 () const { return NULL; } AutoVertical* AutoContact::getVertical1 () const { return NULL; } AutoVertical* AutoContact::getVertical2 () const { return NULL; } bool AutoContact::isOnPin () const { return false; } void AutoContact::getDepthSpan ( size_t& minDepth, size_t& maxDepth ) const { minDepth = (size_t)-1; maxDepth = 0; Component* anchor = getAnchor (); if (anchor) { minDepth = std::min( minDepth, Session::getRoutingGauge()->getLayerDepth(anchor->getLayer()) ); maxDepth = std::max( maxDepth, Session::getRoutingGauge()->getLayerDepth(anchor->getLayer()) ); } for ( AutoSegment* segment : const_cast(this)->getAutoSegments() ) { minDepth = std::min( minDepth, Session::getRoutingGauge()->getLayerDepth(segment->getLayer()) ); maxDepth = std::max( maxDepth, Session::getRoutingGauge()->getLayerDepth(segment->getLayer()) ); } } void AutoContact::updateLayer () { size_t minDepth = (size_t)-1; size_t maxDepth = 0; getDepthSpan( minDepth, maxDepth ); setLayerAndWidth( maxDepth-minDepth, minDepth ); // if (minDepth == maxDepth) // setLayer( Session::getRoutingGauge()->getRoutingLayer(minDepth) ); // else // setLayer( Session::getRoutingGauge()->getContactLayer(minDepth) ); } void AutoContact::getLengths ( DbU::Unit* lengths, AutoSegment::DepthLengthSet& processeds ) { DbU::Unit hSideLength = getGCell()->getSide( Flags::Horizontal ).getSize(); DbU::Unit vSideLength = getGCell()->getSide( Flags::Vertical ).getSize(); for ( AutoSegment* segment : getAutoSegments() ) { bool isSourceHook = (segment->getAutoSource() == this); if (processeds.find(segment) != processeds.end()) continue; processeds.insert( segment ); size_t depth = Session::getRoutingGauge()->getLayerDepth(segment->getLayer()); DbU::Unit length; if (segment->isLocal()) { length = segment->getLength(); lengths[depth] += length; DbU::Unit sideLength = (segment->isHorizontal()) ? hSideLength : vSideLength; if ( not segment->isUnbound() and (abs(length) > sideLength) ) cerr << Error( "AutoContact::getLength(): Suspicious length %s (> %s) of %s.\n" " (on: %s)" , DbU::getValueString(length).c_str() , DbU::getValueString(sideLength).c_str() , getString(segment).c_str() , getString(this).c_str()) << endl; } else { if (segment->isHorizontal()) { if (isSourceHook) lengths[depth] += _gcell->getXMax() - segment->getSourceX(); else lengths[depth] += segment->getTargetX() - _gcell->getXMin(); } else { if (isSourceHook) lengths[depth] += _gcell->getYMax() - segment->getSourceY(); else lengths[depth] += segment->getTargetY() - _gcell->getYMin(); } } } } Box AutoContact::getNativeConstraintBox () const { if (isUserNativeConstraints()) return getConstraintBox(); if (isFixed()) return Box(_contact->getPosition()); return _gcell->getConstraintBox(); } Interval AutoContact::getNativeUConstraints ( Flags direction ) const { Box nativeConstraints = getNativeConstraintBox(); Interval constraint; if (direction & Flags::Horizontal) { constraint = Interval( nativeConstraints.getXMin(), nativeConstraints.getXMax() ); } else { constraint = Interval( nativeConstraints.getYMin(), nativeConstraints.getYMax() ); } //if (direction & Flags::NoGCellShrink) constraint.inflate( 0, GCell::getTopRightShrink() ); return constraint; } Interval AutoContact::getUConstraints ( Flags direction ) const { Interval constraint; if (direction & Flags::Horizontal) { constraint = Interval( getCBXMin(), getCBXMax() ); } else { constraint = Interval( getCBYMin(), getCBYMax() ); } //if (direction & Flags::NoGCellShrink) constraint.inflate( 0, GCell::getTopRightShrink() ); return constraint; } void AutoContact::invalidate ( Flags flags ) { if (flags & Flags::Topology ) setFlags( CntInvalidatedCache ); if (not isInvalidated()) { cdebug_log(145,1) << "AutoContact::invalidate() - " << this << endl; cdebug_log(145,0) << "flags:" << flags.asString(FlagsFunction) << endl; setFlags( CntInvalidated ); Session::invalidate( this ); _invalidate( flags ); getGCell()->invalidate(); cdebug_tabw(145,-1); } } void AutoContact::setGCell ( GCell* gcell ) { invalidate(); if (_gcell) _gcell->removeContact( this ); _gcell = gcell; if (_gcell) { cdebug_log(145,0) << "AutoContact::setGCell() " << gcell << endl; _gcell->addContact( this ); _contact->setPosition( _gcell->getCenter() ); _xMin = _gcell->getXMin(); _yMin = _gcell->getYMin(); _xMax = _gcell->getConstraintXMax(); _yMax = _gcell->getConstraintYMax(); if (cdebug.enabled()) { cdebug_log(145,0) << "* deltas: [" << DbU::getValueString(_xMin) << " " << DbU::getValueString(_yMin) << " " << DbU::getValueString(_xMax) << " " << DbU::getValueString(_yMax) << "]" << endl; } } else { cerr << Bug( "NULL GCell for %s.", _getString().c_str() ) << endl; } } void AutoContact::updateSize () { if (isInvalidatedWidth()) { size_t minDepth = 0; size_t maxDepth = 0; getDepthSpan( minDepth, maxDepth ); if (getVertical1() and getVertical1()->isWide()) { size_t vdepth = (Session::getLayerDepth(getVertical1()->getLayer()) == maxDepth) ? maxDepth : minDepth; DbU::Unit width = getVertical1()->getWidth(); width += Session::getViaWidth(vdepth) - Session::getWireWidth(vdepth); setWidth( width ); } if (getHorizontal1() and getHorizontal1()->isWide()) { size_t hdepth = (Session::getLayerDepth(getHorizontal1()->getLayer()) == maxDepth) ? maxDepth : minDepth; DbU::Unit width = getHorizontal1()->getWidth(); width += Session::getViaWidth(hdepth) - Session::getWireWidth(hdepth); setHeight( width ); } unsetFlags ( CntInvalidatedWidth ); } } void AutoContact::_getTopology ( Contact* support, Component*& anchor, Horizontal**& horizontals, Vertical**& verticals, size_t size ) { size_t hcount = 0; size_t vcount = 0; for ( size_t i=0 ; igetAnchor(); for ( Component* component : support->getSlaveComponents() ) { Horizontal* h = dynamic_cast(component); if (h != NULL) { if (hcount < size) horizontals[hcount++] = h; } else { Vertical* v = dynamic_cast(component); if ( (v != NULL) and (vcount < size) ) verticals[vcount++] = v; } } } void AutoContact::showTopologyError ( const std::string& message, Flags flags ) { Component* anchor = NULL; Horizontal** horizontals = new Horizontal* [10]; Vertical** verticals = new Vertical* [10]; if (not (flags & Flags::CParanoid)) cparanoid.setStreamMask( mstream::PassThrough ); _getTopology ( base(), anchor, horizontals, verticals, 10 ); cparanoid << Error("In topology of %s",getString(this).c_str()) << endl; if (anchor) cparanoid << " A: " << anchor << endl; for ( size_t i=0 ; (i<10) and (horizontals[i] != NULL); ++i ) { AutoSegment* autoSegment = Session::lookup ( horizontals[i] ); if (autoSegment != NULL) cparanoid << " " << (autoSegment->isGlobal()?'G':'L') << ": " << autoSegment << endl; else cparanoid << " ?: " << horizontals[i] << endl; } for ( size_t i=0 ; (i<10) and (verticals[i] != NULL); ++i ) { AutoSegment* autoSegment = Session::lookup ( verticals[i] ); if (autoSegment != NULL) cparanoid << " " << (autoSegment->isGlobal()?'G':'L') << ": " << autoSegment << endl; else cparanoid << " ?: " << verticals[i] << endl; } cparanoid << " " << message << endl; if (not (flags & Flags::CParanoid)) cparanoid.unsetStreamMask( mstream::PassThrough ); delete [] horizontals; delete [] verticals; } void AutoContact::checkTopology () { //cdebug_log(145,0) << "checkTopology() NOT RE-IMPLEMENTED YET " << this << endl; } void AutoContact::forceOnGrid ( Point ) { cerr << Warning( "AutoContact::forcedOnGrid() not implemented for this derived class.\n" " %s\n" , getString(this).c_str() ) << endl; } bool AutoContact::isTee ( Flags direction ) const { return (isHTee() and (direction & Flags::Horizontal)) or (isVTee() and (direction & Flags::Vertical )); } bool AutoContact::canMoveUp ( const AutoSegment* moved ) const { cdebug_log(149,0) << "AutoContact::canMoveUp() " << this << endl; size_t viaDepth = 100; RoutingGauge* rg = Session::getRoutingGauge(); size_t movedDepth = rg->getLayerDepth(moved->getLayer()); Component* anchor = getAnchor(); if (anchor) { viaDepth = rg->getLayerDepth( anchor->getLayer() ); cdebug_log(149,0) << "| Anchor depth: " << viaDepth << endl; } for ( AutoSegment* segment : const_cast(this)->getAutoSegments() ) { if (segment == moved) continue; size_t depth = rg->getLayerDepth(segment->getLayer()); if (viaDepth == 100) viaDepth = depth; else if (viaDepth != depth) return false; cdebug_log(149,0) << "| Segment depth: " << depth << endl; } return (movedDepth+1 == viaDepth); } void AutoContact::setConstraintBox ( const Box& box ) { setCBXMin ( box.getXMin() ); setCBXMax ( box.getXMax() ); setCBYMin ( box.getYMin() ); setCBYMax ( box.getYMax() ); cdebug_log(149,0) << "setConstraintBox() - " << this << " " << getConstraintBox() << " from:" << box << endl; cdebug_log(149,0) << "* " << _gcell << endl; } bool AutoContact::restrictConstraintBox ( DbU::Unit constraintMin , DbU::Unit constraintMax , Flags flags ) { cdebug_log(149,0) << "restrictConstraintBox() - " << this << " " << getConstraintBox() << endl; if (flags & Flags::Horizontal) { if ( (constraintMin > getCBYMax()) or (constraintMax < getCBYMin()) ) { if ( Session::isInDemoMode() or not (flags & Flags::WarnOnError) ) return false; cerr << Error ( "Incompatible DY restriction on %s", _getString().c_str() ) << endl; if ( constraintMin > getCBYMax() ) cerr << Error ( "(constraintMin > CBYMax : %s > %s)" , DbU::getValueString(constraintMin).c_str() , DbU::getValueString(getCBYMax()).c_str() ) << endl; if ( constraintMax < getCBYMin() ) cerr << Error ( "(constraintMax < CBYMin : %s < %s)" , DbU::getValueString(constraintMax).c_str() , DbU::getValueString(getCBYMin()).c_str() ) << endl; return false; } setCBYMin ( std::max(getCBYMin(),constraintMin) ); setCBYMax ( std::min(getCBYMax(),constraintMax) ); } else if (flags & Flags::Vertical) { if ( (constraintMin > getCBXMax()) || (constraintMax < getCBXMin()) ) { if ( Session::isInDemoMode() or not (flags & Flags::WarnOnError) ) return false; cerr << Error ( "Incompatible DX restriction on %s", _getString().c_str() ) << endl; if ( constraintMin > getCBXMax() ) cerr << Error ( "(constraintMin > CBXMax : %s > %s)" , DbU::getValueString(constraintMin).c_str() , DbU::getValueString(getCBXMax()).c_str() ) << endl; if ( constraintMax < getCBXMin() ) cerr << Error ( "(constraintMax < CBXMin : %s < %s)" , DbU::getValueString(constraintMax).c_str() , DbU::getValueString(getCBXMin()).c_str() ) << endl; return false; } setCBXMin ( std::max(getCBXMin(),constraintMin) ); setCBXMax ( std::min(getCBXMax(),constraintMax) ); } cdebug_log(149,0) << "restrictConstraintBox() - " << this << " " << getConstraintBox() << endl; return true; } void AutoContact::restoreNativeConstraintBox () { setConstraintBox ( getNativeConstraintBox() ); } Box& AutoContact::intersectConstraintBox ( Box& box ) const { return box = box.getIntersection ( getConstraintBox() ); } void AutoContact::migrateConstraintBox ( AutoContact* other ) { if (_gcell != other->_gcell) { cerr << Error( "AutoContact::migrateConstraintBox(): AutoContacts do not belongs to the same GCell:\n" " from: %s\n" " to: %s" , getString(other).c_str() , getString(this ).c_str() ) << endl; return; } setConstraintBox( other->getConstraintBox() ); other->restoreNativeConstraintBox(); } Box AutoContact::getBoundingBox () const { return _gcell->getBoundingBox (); } void AutoContact::translate ( const DbU::Unit& tx, const DbU::Unit& ty ) { cerr << Warning("Calling AutoContact::translate() is likely a bug.") << endl; _contact->translate ( tx, ty ); } void AutoContact::setLayerAndWidth ( size_t delta, size_t depth ) { cdebug_log(145,1) << "AutoContact::setLayerAndWidth() " << this << endl; cdebug_log(145,0) << "delta:" << delta << " depth:" << depth << endl; if (delta == 0) { setLayer( Session::getRoutingLayer(depth) ); if (Session::getDirection(depth) & Flags::Horizontal) { setSizes( Session::getPWireWidth(depth) , Session::getWireWidth (depth) ); } else { setSizes( Session::getWireWidth (depth) , Session::getPWireWidth(depth) ); } } else { setLayer( Session::getContactLayer(depth) ); setSizes( Session::getViaWidth (depth) , Session::getViaWidth (depth) ); } cdebug_tabw(145,-1); } AutoContact* AutoContact::createFrom ( Contact* hurricaneContact ) { AutoContact* autoContact = NULL; Component* anchor; size_t hSize = 0; size_t vSize = 0; Horizontal** horizontals = new Horizontal* [4]; Vertical** verticals = new Vertical* [4]; GCell* gcell = Session::getAnabatic()->getGCellUnder( hurricaneContact->getCenter() ); if (not gcell) { throw Error("AutoContact::createFrom( %s ):\n" " Contact is *not* under a GCell (outside routed area?)" , getString(hurricaneContact).c_str() ); } _getTopology ( hurricaneContact, anchor, horizontals, verticals, 4 ); for ( size_t i=0 ; i<4 ; ++i ) { hSize += (horizontals[i] != NULL) ? 1 : 0; vSize += (verticals [i] != NULL) ? 1 : 0; } if (anchor) { if (hSize+vSize == 1) { autoContact = new AutoContactTerminal( gcell, hurricaneContact ); autoContact->_postCreate(); autoContact->unsetFlags( CntInCreationStage ); } } else { if ((hSize == 1) and (vSize == 1)) { autoContact = new AutoContactTurn ( gcell, hurricaneContact ); autoContact->_postCreate(); autoContact->unsetFlags( CntInCreationStage ); } else if ((hSize == 2) and (vSize == 1)) { autoContact = new AutoContactHTee ( gcell, hurricaneContact ); autoContact->_postCreate(); autoContact->unsetFlags( CntInCreationStage ); } else if ((hSize == 1) and (vSize == 2)) { autoContact = new AutoContactVTee ( gcell, hurricaneContact ); } } if (not autoContact) { throw Error("AutoContact::createFrom( %s ):\n" " Contact do not have a manageable topology (a:%u, h:%u, v:%u)" , getString(hurricaneContact).c_str() , ((anchor) ? 1 : 0) , hSize , vSize ); } autoContact->_postCreate(); autoContact->unsetFlags( CntInCreationStage ); return autoContact; } string AutoContact::_getTypeName () const { return "AutoContact"; } string AutoContact::_getString () const { string s = _contact->_getString(); size_t i = s.find(' '); if (i != string::npos) { s.erase ( i+1, 7 ); s.insert( i+1, _getTypeName() ); } //s.insert( 1, "id: " ); //s.insert( 4, getString(_id) ); s.insert( s.size()-1, (isFixed ())?" F":" -" ); s.insert( s.size()-1, (isTerminal ())? "T": "-" ); s.insert( s.size()-1, (canDrag ())? "D": "-" ); s.insert( s.size()-1, (isHTee ())? "h": "-" ); s.insert( s.size()-1, (isVTee ())? "v": "-" ); s.insert( s.size()-1, (isInvalidated ())? "i": "-" ); s.insert( s.size()-1, (isInvalidatedCache())? "c": "-" ); //s.insert( s.size()-1, getString(getConstraintBox())); return s; } Record* AutoContact::_getRecord () const { Record* record = _contact->_getRecord (); record->add ( getSlot ( "_gcell" , _gcell ) ); record->add ( getSlot ( "_constraintBox", getConstraintBox() ) ); record->add ( getSlot ( "_flags" , _flags ) ); return record; } } // Anabatic namespace.