// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2008-2013, 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 : "./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/UpdateSession.h" #include "hurricane/DebugSession.h" #include "crlcore/RoutingGauge.h" #include "katabatic/AutoContact.h" #include "katabatic/AutoVertical.h" #include "katabatic/AutoHorizontal.h" #include "katabatic/Session.h" namespace Katabatic { using std::ostringstream; using Hurricane::Bug; using Hurricane::Error; using Hurricane::Warning; using Hurricane::DebugSession; using Hurricane::ForEachIterator; // ------------------------------------------------------------------- // Class : "Katabatic::AutoContact". size_t AutoContact::_maxId = 0; size_t AutoContact::_allocateds = 0; const Name AutoContact::_goName = "Katabatic::AutoContact"; AutoContact::AutoContact ( GCell* gcell, Contact* contact ) : ExtensionGo(contact->getCell()) //, _id (_maxId++) , _id (contact->getId()) , _contact (contact) , _gcell (gcell) , _flags (CntInvalidatedCache|CntInCreationStage) , _dxMin (0) , _dxMax ((int)DbU::toLambda( _gcell->getXMax()-_gcell->getX() )) , _dyMin (0) , _dyMax ((int)DbU::toLambda( _gcell->getYMax()-_gcell->getY() )) { _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 () { ExtensionGo::_postCreate(); restoreNativeConstraintBox(); ltrace(90) << "Native CBox: " << this << " <" << DbU::getLambda(getCBXMin()) << " " << DbU::getLambda(getCBYMin()) << " " << DbU::getLambda(getCBXMax()) << " " << DbU::getLambda(getCBYMax()) << ">" << endl; Session::link( this ); invalidate( KbTopology ); ltrace(90) << "AutoContact::_postCreate() - " << this << " in " << _gcell << endl; } void AutoContact::_preDestroy () { DebugSession::open( _contact->getNet() ); ltrace(90) << "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; forEach ( Component*, icomponent, _contact->getSlaveComponents() ) { message << "\n | " << (*icomponent); } cerr << Error( message.str() ) << endl; canDestroyBase = false; } #endif if (not Session::doDestroyTool()) { _gcell->removeContact( this ); Session::unlink( this ); } ExtensionGo::_preDestroy(); #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 ( unsigned int flags ) const { if (not _contact->getSlaveComponents().isEmpty()) { if (flags & KbWarnOnError) { 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); } unsigned int AutoContact::getMinDepth () const { size_t minDepth = (size_t)-1; Component* anchor = getAnchor (); if (anchor) { minDepth = std::min( minDepth, Session::getRoutingGauge()->getLayerDepth(anchor->getLayer()) ); //ltrace(200) << "Anchor:" << anchor << endl; } forEach ( AutoSegment*, isegment, const_cast(this)->getAutoSegments() ) { minDepth = std::min( minDepth, Session::getRoutingGauge()->getLayerDepth(isegment->getLayer()) ); //ltrace(200) << "Slave:" << *icomponent << endl; } return (unsigned int)minDepth; } unsigned int AutoContact::getMaxDepth () const { size_t maxDepth = 0; Component* anchor = getAnchor (); if ( anchor ) { maxDepth = std::max ( maxDepth, Session::getRoutingGauge()->getLayerDepth(anchor->getLayer()) ); //ltrace(200) << "Anchor:" << anchor << endl; } forEach ( AutoSegment*, isegment, const_cast(this)->getAutoSegments() ) { maxDepth = std::max ( maxDepth, Session::getRoutingGauge()->getLayerDepth(isegment->getLayer()) ); //ltrace(200) << "Slave:" << *icomponent << endl; } return (unsigned int)maxDepth; } void AutoContact::getLengths ( DbU::Unit* lengths, AutoSegment::DepthLengthSet& processeds ) { forEach ( AutoSegment*, isegment, getAutoSegments() ) { bool isSourceHook = (isegment->getAutoSource() == this); if (processeds.find(*isegment) != processeds.end()) continue; processeds.insert( *isegment ); size_t depth = Session::getRoutingGauge()->getLayerDepth(isegment->getLayer()); DbU::Unit length; if (isegment->isLocal()) { length = isegment->getLength(); lengths[depth] += length; if ( not isegment->isUnbound() and (abs(length) > DbU::lambda(50.0)) ) cerr << Error("Suspicious length:%.2f of %s." ,DbU::getLambda(length),getString(*isegment).c_str()) << endl; } else { if ( isegment->isHorizontal() ) { if ( isSourceHook ) lengths[depth] += _gcell->getBoundingBox().getXMax() - isegment->getSourceX(); else lengths[depth] += isegment->getTargetX() - _gcell->getBoundingBox().getXMin(); } else { if ( isSourceHook ) lengths[depth] += _gcell->getBoundingBox().getYMax() - isegment->getSourceY(); else lengths[depth] += isegment->getTargetY() - _gcell->getBoundingBox().getYMin(); } } } } Box AutoContact::getNativeConstraintBox () const { return isFixed() ? Box(_contact->getPosition()) : _gcell->getBoundingBox(); } Interval AutoContact::getNativeUConstraints ( unsigned int direction ) const { Box nativeConstraints = getNativeConstraintBox(); if (direction & KbHorizontal) { return Interval( nativeConstraints.getXMin(), nativeConstraints.getXMax() ); } return Interval( nativeConstraints.getYMin(), nativeConstraints.getYMax() ); } Interval AutoContact::getUConstraints ( unsigned int direction ) const { if (direction & KbHorizontal) { return Interval( getCBXMin(), getCBXMax() ); } return Interval( getCBYMin(), getCBYMax() ); } void AutoContact::invalidate ( unsigned int flags ) { if (not isInvalidated()) { ltrace(110) << "AutoContact::invalidate() - " << this << endl; ltracein(110); setFlags( CntInvalidated ); if (flags & KbTopology ) setFlags( CntInvalidatedCache ); Session::invalidate( this ); _invalidate( flags ); //forEach( AutoSegment*, isegment, getAutoSegments() ) // isegment->invalidate(); getGCell()->invalidate(); ltraceout(110); } } void AutoContact::setGCell ( GCell* gcell ) { invalidate(); if (_gcell) _gcell->removeContact( this ); _gcell = gcell; if (_gcell) { ltrace(110) << "AutoContact::setGCell() " << gcell << endl; _gcell->addContact( this ); _contact->setPosition( _gcell->getCenter() ); _dxMin = 0; _dyMin = 0; _dxMax = (int)DbU::toLambda( _gcell->getXMax()-_gcell->getX() ); _dyMax = (int)DbU::toLambda( _gcell->getYMax()-_gcell->getY() ); ltrace(110) << "* deltas: [" << _dxMin << " " << _dyMin << " " << _dxMax << " " << _dyMax << "]" << endl; } else { cerr << Bug( "NULL GCell for %s.", _getString().c_str() ) << endl; } } void AutoContact::_getTopology ( Component*& anchor, Horizontal**& horizontals, Vertical**& verticals, size_t size ) { size_t hcount = 0; size_t vcount = 0; for ( size_t i=0 ; i(*icomponent); if (h != NULL) { if (hcount < size) horizontals[hcount++] = h; } else { Vertical* v = dynamic_cast(*icomponent); if ( (v != NULL) and (vcount < size) ) verticals[vcount++] = v; } } } void AutoContact::showTopologyError ( const std::string& message ) { Component* anchor = NULL; Horizontal** horizontals = new Horizontal* [10]; Vertical** verticals = new Vertical* [10]; _getTopology ( anchor, horizontals, verticals, 10 ); cerr << Error("In topology of %s",getString(this).c_str()) << endl; if (anchor) cerr << " A: " << anchor << endl; for ( size_t i=0 ; (i<10) and (horizontals[i] != NULL); ++i ) { AutoSegment* autoSegment = Session::lookup ( horizontals[i] ); if (autoSegment != NULL) cerr << " " << (autoSegment->isGlobal()?'G':'L') << ": " << autoSegment << endl; else cerr << " ?: " << horizontals[i] << endl; } for ( size_t i=0 ; (i<10) and (verticals[i] != NULL); ++i ) { AutoSegment* autoSegment = Session::lookup ( verticals[i] ); if (autoSegment != NULL) cerr << " " << (autoSegment->isGlobal()?'G':'L') << ": " << autoSegment << endl; else cerr << " ?: " << verticals[i] << endl; } cerr << " " << message << endl; delete [] horizontals; delete [] verticals; } void AutoContact::checkTopology () { //ltrace(110) << "checkTopology() NOT RE-IMPLEMENTED YET " << this << endl; } bool AutoContact::isTee ( unsigned int direction ) const { return (isHTee() and (direction & KbHorizontal)) or (isVTee() and (direction & KbVertical )); } bool AutoContact::canMoveUp ( const AutoSegment* moved ) const { ltrace(200) << "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() ); ltrace(200) << "| Anchor depth: " << viaDepth << endl; } forEach ( AutoSegment*, isegment, const_cast(this)->getAutoSegments() ) { if (*isegment == moved) continue; size_t depth = rg->getLayerDepth(isegment->getLayer()); if (viaDepth == 100) viaDepth = depth; else if (viaDepth != depth) return false; ltrace(200) << "| 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() ); ltrace(110) << "setConstraintBox() - " << this << " " << getConstraintBox() << endl; ltrace(110) << "* " << _gcell << endl; } bool AutoContact::restrictConstraintBox ( DbU::Unit constraintMin , DbU::Unit constraintMax , unsigned int flags ) { if (flags & KbHorizontal) { if ( (constraintMin > getCBYMax()) or (constraintMax < getCBYMin()) ) { if ( Session::isInDemoMode() or not (flags & KbWarnOnError) ) return false; cerr << Error ( "Incompatible DY restriction on %s", _getString().c_str() ) << endl; if ( constraintMin > getCBYMax() ) cerr << Error ( "(constraintMin > CBYMax : %.2lf > %.2lf)" , DbU::getLambda(constraintMin) , DbU::getLambda(getCBYMax()) ) << endl; if ( constraintMax < getCBYMin() ) cerr << Error ( "(constraintMax < CBYMin : %.2lf < %.2lf)" , DbU::getLambda(constraintMax) , DbU::getLambda(getCBYMin()) ) << endl; return false; } setCBYMin ( std::max(getCBYMin(),constraintMin) ); setCBYMax ( std::min(getCBYMax(),constraintMax) ); } else if (flags & KbVertical) { if ( (constraintMin > getCBXMax()) || (constraintMax < getCBXMin()) ) { if ( Session::isInDemoMode() or not (flags & KbWarnOnError) ) return false; cerr << Error ( "Incompatible DX restriction on %s", _getString().c_str() ) << endl; if ( constraintMin > getCBXMax() ) cerr << Error ( "(constraintMin > CBXMax : %.2lf > %.2lf)" , DbU::getLambda(constraintMin) , DbU::getLambda(getCBXMax()) ) << endl; if ( constraintMax < getCBXMin() ) cerr << Error ( "(constraintMax < CBXMin : %.2lf < %.2lf)" , DbU::getLambda(constraintMax) , DbU::getLambda(getCBXMin()) ) << endl; return false; } setCBXMin ( std::max(getCBXMin(),constraintMin) ); setCBXMax ( std::min(getCBXMax(),constraintMax) ); } ltrace(110) << "restrictConstraintBox() - " << this << " " << getConstraintBox() << endl; return true; } void AutoContact::restoreNativeConstraintBox () { setConstraintBox ( getNativeConstraintBox() ); } Box& AutoContact::intersectConstraintBox ( Box& box ) const { return box = box.getIntersection ( getConstraintBox() ); } 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 ); } 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, (isHTee ())? "h": "-" ); s.insert( s.size()-1, (isVTee ())? "v": "-" ); s.insert( s.size()-1, (isInvalidated ())? "i": "-" ); s.insert( s.size()-1, (isInvalidatedCache())? "c": "-" ); 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; } } // Katabatic namespace.