// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC/LIP6 2008-2010, All Rights Reserved // // =================================================================== // // $Id$ // // x-----------------------------------------------------------------x // | | // | C O R I O L I S | // | K i t e - D e t a i l e d R o u t e r | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@asim.lip6.fr | // | =============================================================== | // | C++ Module : "./TrackSegment.cpp" | // | *************************************************************** | // | U p d a t e s | // | | // x-----------------------------------------------------------------x #include #include #include "hurricane/Bug.h" #include "hurricane/Warning.h" #include "hurricane/Net.h" #include "hurricane/Name.h" #include "hurricane/RoutingPad.h" #include "katabatic/AutoContact.h" #include "katabatic/GCell.h" #include "crlcore/RoutingGauge.h" #include "kite/DataNegociate.h" #include "kite/TrackSegment.h" #include "kite/Track.h" #include "kite/Session.h" #include "kite/RoutingEvent.h" #include "kite/NegociateWindow.h" #include "kite/KiteEngine.h" namespace Kite { using namespace std; using Hurricane::inltrace; using Hurricane::ltracein; using Hurricane::ltraceout; using Hurricane::tab; using Hurricane::ForEachIterator; using Hurricane::Bug; using Hurricane::Error; using Hurricane::Net; using Hurricane::Name; using Hurricane::RoutingPad; // ------------------------------------------------------------------- // Class : "TrackSegment". TrackSegment::TrackSegment ( AutoSegment* segment, Track* track ) : TrackElement (track) , _base (segment) , _created (true) , _lock (true) , _revalidated (false) , _sourceDogLeg (false) , _targetDogLeg (false) , _canRipple (false) , _routed (false) , _area (0) , _data (NULL) , _dogLegLevel (0) { if (segment) { _data = new DataNegociate ( this ); _base->getCanonical ( _sourceU, _targetU ); setArea (); //update (); } } void TrackSegment::_postCreate () { TrackElement::_postCreate (); Session::link ( this ); } TrackSegment::~TrackSegment () { if ( _data ) delete _data; } void TrackSegment::_preDestroy () { ltrace(90) << "TrackSegment::_preDestroy() - " << (void*)this << " [" << (void*)_base << ", " << (void*)(_base?_base->base():NULL) << "]" << endl; Session::unlink ( this ); TrackElement::_preDestroy (); } TrackElement* TrackSegment::create ( AutoSegment* segment, Track* track, bool& created ) { created = false; TrackElement* trackElement = Session::lookup ( segment->base() ); if ( not trackElement ) { TrackSegment* trackSegment = new TrackSegment ( segment, track ); trackSegment->_postCreate (); created = true; trackSegment->invalidate (); ltrace(200) << "TrackSegment::create(): " << trackSegment << endl; trackElement = trackSegment; } return trackElement; } // Formerly Inline Functions. AutoSegment* TrackSegment::base () const { return _base; } bool TrackSegment::isBipoint () const { return _base->isBipoint(); } bool TrackSegment::isCreated () const { return _created; } bool TrackSegment::isFixed () const { return _base->isFixed(); } bool TrackSegment::isStrap () const { return _base->isCanonicalStrap(); } bool TrackSegment::isSlackenStrap () const { return _base->isSlackenStrap(); } bool TrackSegment::isLocal () const { return _base->isCanonicalLocal(); } bool TrackSegment::isGlobal () const { return !isLocal(); } bool TrackSegment::isLocked () const { return _lock; } bool TrackSegment::isTerminal () const { return _base->isTerminal(); } bool TrackSegment::isDogleg () const { return _base->isDogleg(); } bool TrackSegment::isRevalidated () const { return _revalidated; } bool TrackSegment::isRouted () const { return _routed; } bool TrackSegment::isSlackened () const { return _base->isSlackened(); } bool TrackSegment::isSlackenDogLeg () const { return isSlackened() and (_dogLegLevel > 0); } bool TrackSegment::hasSourceDogLeg () const { return _sourceDogLeg; } bool TrackSegment::hasTargetDogLeg () const { return _targetDogLeg; } bool TrackSegment::allowOutsideGCell () const { return _base->allowOutsideGCell(); } bool TrackSegment::canGoOutsideGCell () const { return _base->canGoOutsideGCell(); } bool TrackSegment::canRipple () const { return _canRipple; } unsigned long TrackSegment::getId () const { return _base->getId(); } DbU::Unit TrackSegment::getAxis () const { return _base->getAxis(); } unsigned long TrackSegment::getArea () const { return _area; } unsigned int TrackSegment::getDogLegLevel () const { return _dogLegLevel; } Interval TrackSegment::getSourceConstraints () const { return _base->getSourceConstraints(); } Interval TrackSegment::getTargetConstraints () const { return _base->getTargetConstraints(); } TrackElements TrackSegment::getCollapsedPerpandiculars () { return new TrackElements_CollapsedPerpandicular(this); } void TrackSegment::setAllowOutsideGCell ( bool state ) { _base->setAllowOutsideGCell(state,true); } void TrackSegment::setLock ( bool state ) { _lock = state; } void TrackSegment::setRevalidated ( bool state ) { _revalidated = state; } void TrackSegment::invalidate () { _base->invalidate(); } void TrackSegment::setCanRipple ( bool state ) { _canRipple = state; } void TrackSegment::setSourceDogLeg ( bool state ) { _sourceDogLeg = state; } void TrackSegment::setTargetDogLeg ( bool state ) { _targetDogLeg = state; } TrackElement* TrackSegment::getCanonical ( Interval& i ) { return Session::lookup ( _base->getCanonical(i)->base() ); } bool TrackSegment::canSlacken () const { return (not isSlackened())?(_base->canSlacken(true)):false; } bool TrackSegment::isHorizontal () const { return _base->isHorizontal(); } bool TrackSegment::isVertical () const { return _base->isVertical(); } unsigned int TrackSegment::getDirection () const { return _base->getDirection(); } Net* TrackSegment::getNet () const { return _base->getNet(); } const Layer* TrackSegment::getLayer () const { return _base->getLayer(); } DataNegociate* TrackSegment::getDataNegociate ( unsigned int flags ) const { if ( flags & TrackElement::DataSelf ) return _data; TrackElement* parent = getParent(); return (parent) ? parent->getDataNegociate() : NULL; } TrackElement* TrackSegment::getNext () const { size_t dummy = _index; return _track->getNext ( dummy, getNet() ); } TrackElement* TrackSegment::getPrevious () const { size_t dummy = _index; return _track->getPrevious ( dummy, getNet() ); } TrackElement* TrackSegment::getParent () const { AutoSegment* baseParent = base()->getParent(); if ( not baseParent ) return NULL; TrackElement* element = Session::lookup ( baseParent ); return element; } Interval TrackSegment::getFreeInterval () const { if ( not _track ) return Interval(false); size_t begin = _index; size_t end = _index; return _track->expandFreeInterval ( begin, end, Track::Inside, getNet() ); } size_t TrackSegment::getGCells ( vector& gcells ) const { vector().swap ( gcells ); Katabatic::GCell* sourceGCell = base()->getAutoSource()->getGCell(); Katabatic::GCell* targetGCell = base()->getAutoTarget()->getGCell(); ltrace(148) << "getGCells(): sourceGCell: " << sourceGCell << endl; ltrace(148) << "getGCells(): targetGCell: " << targetGCell << endl; forEach ( AutoSegment*, isegment, base()->getCollapseds() ) { Katabatic::GCell* gcell = isegment->getAutoSource()->getGCell(); if ( gcell->getIndex() < sourceGCell->getIndex() ) { sourceGCell = gcell; ltrace(148) << "getGCells(): new sourceGCell: " << sourceGCell << endl; } gcell = isegment->getAutoTarget()->getGCell(); if ( gcell->getIndex() > targetGCell->getIndex() ) { targetGCell = gcell; ltrace(148) << "getGCells(): new targetGCell: " << targetGCell << endl; } } if ( not sourceGCell or not targetGCell ) return 0; if ( not sourceGCell ) { gcells.push_back ( targetGCell ); return 1; } if ( not targetGCell ) { gcells.push_back ( sourceGCell ); return 1; } if ( isHorizontal() ) { gcells.push_back ( sourceGCell ); while ( sourceGCell != targetGCell ) { sourceGCell = sourceGCell->getRight(); if ( not sourceGCell ) break; //cerr << " Pushing: " << sourceGCell << endl; gcells.push_back ( sourceGCell ); } } else { gcells.push_back ( sourceGCell ); while ( sourceGCell != targetGCell ) { sourceGCell = sourceGCell->getUp(); if ( not sourceGCell ) break; gcells.push_back ( sourceGCell ); } } return gcells.size(); } size_t TrackSegment::getPerpandicularsBound ( set& bounds ) { bounds.clear (); set baseBounds; set::iterator ibase; _base->getPerpandicularsBound ( baseBounds ); for ( ibase = baseBounds.begin() ; ibase != baseBounds.end() ; ibase++ ) { TrackElement* segment = Session::lookup ( *ibase ); if ( segment ) bounds.insert ( segment ); } return bounds.size(); } void TrackSegment::setDogLegLevel ( unsigned int level ) { if ( level > 15 ) { cerr << Bug("%s has reached maximum dog leg count (15)." ,_getString().c_str()) << endl; level = 15; } _dogLegLevel = level; } void TrackSegment::dataInvalidate () { if (_data) _data->invalidate(); } void TrackSegment::eventInvalidate () { if ( !_data ) return; RoutingEvent* event = _data->getRoutingEvent(); if ( event ) event->invalidate ( true ); } void TrackSegment::setArea () { //float length = getValue ( getTargetU() - getSourceU() ); //float height = getValue ( getSlack() ); //_area = (unsigned long)( length * height ); _area = _base->getSlack(); } void TrackSegment::setRouted ( bool state ) { _routed = state; } void TrackSegment::setTrack ( Track* track ) { TrackElement::setTrack ( track ); } void TrackSegment::detach () { ltrace(200) << "TrackSegment::detach() - " << endl; setTrack ( NULL ); setIndex ( (size_t)-1 ); setLock ( true ); } void TrackSegment::revalidate ( bool invalidEvent ) { _created = false; ltrace(148) << "revalidate() - " << this << endl; _base->getCanonical ( _sourceU, _targetU ); _data->update (); if ( invalidEvent ) _data->invalidate ( true, true ); if ( _track ) Session::addSortEvent ( _track ); _revalidated = true; } void TrackSegment::setAxis ( DbU::Unit axis, unsigned int flags ) { _base->setAxis ( axis, flags ); invalidate (); } void TrackSegment::swapTrack ( TrackElement* other ) { if ( not other ) return; ltrace(200) << "TrackSegment::swapTrack()" << endl; size_t thisIndex = getIndex (); Track* thisTrack = getTrack (); size_t otherIndex = other->getIndex (); Track* otherTrack = other->getTrack (); if ( _track and otherTrack and (_track != otherTrack) ) { cerr << Error("TrackSegment::swapTrack() - swapping TrackSement from different tracks.") << endl; } // detach (); // other->detach (); // if ( thisTrack ) thisTrack ->insert ( other ); // if ( otherTrack ) otherTrack->insert ( this ); setTrack ( NULL ); other->setTrack ( NULL ); //other->setRouted ( thisRouted ); other->setTrack ( thisTrack ); other->setIndex ( thisIndex ); if ( thisTrack ) thisTrack->setSegment ( other, thisIndex ); //setRouted ( otherRouted ); setTrack ( otherTrack ); setIndex ( otherIndex ); if ( _track ) _track->setSegment ( this, _index ); #if defined(CHECK_DATABASE_DISABLED) if ( _track ) _track->_check(); else if ( other->getTrack() ) other->getTrack()->_check(); #endif RoutingEvent* thisEvent = getDataNegociate(TrackElement::DataSelf)->getRoutingEvent(); RoutingEvent* otherEvent = other->getDataNegociate()->getRoutingEvent(); if ( thisEvent ) thisEvent ->setSegment ( other ); if ( otherEvent ) otherEvent->setSegment ( this ); ltrace(200) << "| this: " << this << endl; ltrace(200) << "| other: " << other << endl; } void TrackSegment::reschedule ( unsigned int level ) { ltrace(200) << "TrackSegment::reschedule() - " << this << endl; ltracein(200); if ( not _data or not _data->hasRoutingEvent() ) Session::getNegociateWindow()->addInsertEvent ( this, level ); else { if ( _track != NULL ) Session::addRemoveEvent ( this ); Session::getNegociateWindow()->rescheduleEvent ( _data->getRoutingEvent(), level ); } ltraceout(200); } void TrackSegment::slacken () { if ( not isSlackened() ) { ltrace(200) << "TrackSegment::slacken()" << endl; ltracein(200); base()->slacken ( true ); _postModify (); ltraceout(200); } else throw Bug("TrackSegment::slacken(): NULL base or already slackened."); } float TrackSegment::getMaxUnderDensity ( unsigned int flags ) const { return _base->getMaxUnderDensity ( flags ); } bool TrackSegment::canPivotUp ( float reserve ) const { return _base->canPivotUp(reserve); } bool TrackSegment::canPivotDown ( float reserve ) const { return _base->canPivotDown(reserve); } bool TrackSegment::canMoveUp ( float reserve, unsigned int flags ) const { return _base->canMoveUp ( reserve, flags ); } bool TrackSegment::moveUp ( unsigned int flags ) { bool success = false; ltrace(200) << "TrackSegment::moveUp() " << flags << endl; ltracein(200); success = base()->moveUp ( flags ); const vector& invalidateds = Session::getInvalidateds(); if ( not invalidateds.empty() ) { vector segments; for ( size_t i=0 ; iaddTrackSegment(invalidateds[i],false); if ( segment != NULL ) { ltrace(200) << "moved up: " << invalidateds[i] << endl; segments.push_back ( segment ); // if ( (segment->getTrack() == NULL) // or (segment->getLayer() != segment->getTrack()->getLayer()) ) segment->reschedule ( 0 ); } } for ( size_t i=0 ; isetState ( DataNegociate::ConflictSolve1, true ); // _data->resetRipupCount (); // } ltraceout(200); return success; } bool TrackSegment::moveDown ( unsigned int flags ) { bool success = false; ltrace(200) << "TrackSegment::moveDown() " << flags << endl; ltracein(200); success = base()->moveDown ( flags ); const vector& invalidateds = Session::getInvalidateds(); if ( not invalidateds.empty() ) { vector segments; for ( size_t i=0 ; iaddTrackSegment(invalidateds[i],false); if ( segment != NULL ) { ltrace(200) << "moved down: " << invalidateds[i] << endl; segments.push_back ( segment ); // if ( (segment->getTrack() == NULL) // or (segment->getLayer() != segment->getTrack()->getLayer()) ) segment->reschedule ( 0 ); } } for ( size_t i=0 ; isetState ( DataNegociate::ConflictSolve1, true ); // _data->resetRipupCount (); // } ltraceout(200); return success; } bool TrackSegment::moveAside ( bool onLeft ) { bool success = true; ltrace(200) << "TrackSegment::moveAside() - " << (onLeft?"left":"right") << endl; ltracein(200); if ( onLeft ) base()->moveULeft (); else base()->moveURight (); const vector& invalidateds = Session::getInvalidateds(); if ( not invalidateds.empty() ) { vector segments; for ( size_t i=0 ; iaddTrackSegment(invalidateds[i],false) ); segments.back()->reschedule ( 0 ); } for ( size_t i=0 ; igetAutoSource()->getSlaveComponents().getSubSet() ) { dogleg = Session::lookup ( *isegment ); if ( dogleg and (dogleg->getDirection() == direction) ) { ltrace(200) << "Source dogleg: " << dogleg << endl; return dogleg; } } return NULL; } TrackElement* TrackSegment::getTargetDogLeg () { if ( not hasSourceDogLeg() ) return NULL; unsigned int direction = Constant::perpandicular ( getDirection() ); TrackElement* dogleg = NULL; forEach ( Segment*, isegment, base()->getAutoTarget()->getSlaveComponents().getSubSet() ) { dogleg = Session::lookup ( *isegment ); if ( dogleg and (dogleg->getDirection() == direction) ) { ltrace(200) << "Target dogleg: " << dogleg << endl; return dogleg; } } return NULL; } bool TrackSegment::canDogLeg ( Interval interval ) { ltrace(200) << "TrackSegment::canDogLeg(Interval) " << interval << endl; if ( isFixed() ) { ltrace(200) << "Failed: is fixed" << endl; return false; } if ( not isLocal() ) { ltrace(200) << "Failed: is not local" << endl; return false; } if ( hasSourceDogLeg() or hasTargetDogLeg() or isSlackened() ) { ltrace(200) << "Failed: already has source and/or target dogleg or slackened." << endl; return false; } return _base->canDogLeg(interval); } TrackElement* TrackSegment::makeDogLeg ( Interval interval, bool& leftDogleg ) { ltrace(200) << "TrackSegment::makeDogLeg(Interval)" << endl; bool upLayer = (Session::getRoutingGauge()->getLayerDepth(getLayer()) < 2); base()->makeDogLeg ( interval, upLayer, leftDogleg ); return _postDogLeg (); } bool TrackSegment::canDogLeg () { ltrace(200) << "TrackSegment::canDogLeg()" << endl; if ( not isLocal() ) { ltrace(200) << "Failed: is not local." << endl; return false; } if ( isFixed() ) { ltrace(200) << "Failed: is fixed." << endl; return false; } if ( isSlackened() ) { ltrace(200) << "Failed: is local & slackened." << endl; return false; } if ( hasSourceDogLeg() || hasTargetDogLeg() ) return false; return true; } TrackElement* TrackSegment::makeDogLeg () { Katabatic::AutoContact* source = _base->getAutoSource(); Katabatic::AutoContact* target = _base->getAutoTarget(); Katabatic::GCell* gcell = _base->getAutoSource()->getGCell(); TrackElement* dogleg = makeDogLeg ( gcell ); if ( dogleg ) { if ( source->isTerminal() xor target->isTerminal() ) { if ( target->isTerminal() ) source = target; DbU::Unit axis = (_base->isHorizontal()) ? source->getX() : source->getY(); ltrace(200) << "Setting dogleg axis @" << DbU::getValueString(axis) << endl; dogleg->setAxis ( axis ); } return _postDogLeg(); } return NULL; } bool TrackSegment::canDogLegAt ( Katabatic::GCell* dogLegGCell, unsigned int flags ) { ltrace(200) << "TrackSegment::canDogLegAt(GCell*) " << dogLegGCell << endl; if ( isFixed() ) { ltrace(200) << "Cannot dogleg a fixed segment." << endl; return false; } if ( isLocal() ) { if ( hasSourceDogLeg() or hasTargetDogLeg() ) { ltrace(200) << "Cannot dogleg again a local segment." << endl; return false; } if ( isSlackened() ) { ltrace(200) << "Cannot dogleg a local slackened segment." << endl; return false; } } vector gcells; getGCells ( gcells ); ltrace(190) << "Source: " << *gcells.begin () << endl; ltrace(190) << "Target: " << *gcells.rbegin() << endl; bool isGCellInside = false; for ( size_t igcell=0 ; igcellgetLayerDepth(getLayer()) < 2); base()->makeDogLeg ( dogLegGCell, upLayer ); return _postDogLeg (); } TrackElement* TrackSegment::_postDogLeg () { ltracein(200); TrackElement* perpandicular = NULL; const vector& dogLegs = Session::getDogLegs(); if ( not dogLegs.empty() ) { vector segments; for ( size_t i=0 ; iaddTrackSegment(dogLegs[i],false) ); switch ( i ) { case 0: segments[i]->setTargetDogLeg(); segments[i]->getDataNegociate()->resetRipupCount(); if ( segments[i] != this ) { cerr << Error ( "Incoherency in TrackSegment LUT, lookup of %p gives %p instead of %p (this)" , dogLegs[i], segments[i], this ) << endl; } break; case 1: perpandicular = segments[i]; segments[i]->setSourceDogLeg (); segments[i]->setTargetDogLeg (); segments[i]->setDogLegLevel ( getDogLegLevel()+1 ); break; case 2: segments[i]->setSourceDogLeg (); break; } } // TO CHECK // If the original TrackElement was inserted in a Track, must check // if the new bit takes it's place or not. //if ( getGCell() != originalGCell ) swapTrack ( segments[2] ); for ( size_t i=0 ; ireschedule ( ((i==1) ? 0 : 1) ); } ltrace(200) << "original: " << segments[0] << endl; ltrace(200) << "perpand: " << segments[1] << endl; ltrace(200) << "new paral: " << segments[2] << endl; } ltraceout(200); return perpandicular; } bool TrackSegment::canDesalignate () const { ltrace(200) << "TrackSegment::canDesalignate()" << endl; return _base->canDesalignate(); } void TrackSegment::desalignate () { ltrace(200) << "TrackSegment::desalignate()" << endl; ltracein(200); _base->desalignate (); _postModify (); ltraceout(200); } void TrackSegment::_postModify () { ltrace(200) << "TrackSegment::_postModify()" << endl; ltracein(200); unsigned int doglegLevel = getDogLegLevel() + 1; unsigned int parallelDir = getDirection (); unsigned int perpandicularDir = Constant::perpandicular ( parallelDir ); const vector& invalidateds = Session::getInvalidateds(); vector segments; if ( not invalidateds.empty() ) { for ( size_t i=0 ; iaddTrackSegment(invalidateds[i],false); if ( segment != NULL ) segments.push_back ( segment ); } } for ( size_t i=0 ; iisCreated() and (segment->getDirection() == perpandicularDir) ) { ltrace(200) << "Increasing dogleg level to: " << doglegLevel << endl; segment->setDogLegLevel ( doglegLevel ); } if ( segment->getDirection() == parallelDir ) { forEach ( TrackElement*, iperpandicular, segment->getCollapsedPerpandiculars() ) { ltrace(200) << "| pp: " << *iperpandicular << endl; iperpandicular->reschedule ( 0 ); } segment->reschedule ( 0 ); } } ltraceout(200); } bool TrackSegment::_check () const { if ( not base() ) return true; bool coherency = true; if ( not base()->isCanonical() ) { cerr << "[CHECK] " << this << " supporting AutoSegment is not canonical." << endl; coherency = false; } DbU::Unit min; DbU::Unit max; base()->getCanonical ( min, max ); if ( getSourceU() != min ) { cerr << "[CHECK] " << this << " has bad source position " << DbU::getValueString(min) << "." << endl; coherency = false; } if ( getTargetU() != max ) { cerr << "[CHECK] " << this << " has bad target position " << DbU::getValueString(max) << "." << endl; coherency = false; } return coherency; } string TrackSegment::_getTypeName () const { return "TrackSegment"; } string TrackSegment::_getString () const { string s1 = _base->_getString(); string s2 = " [" + DbU::getValueString(_sourceU) + ":" + DbU::getValueString(_targetU) + "]" + " " + DbU::getValueString(_targetU-_sourceU) + " " + getString(_dogLegLevel) + " [" + ((_track) ? getString(_index) : "npos") + "] " + ((isSlackened() ) ? "S" : "-") + ((_track ) ? "T" : "-") + ((_canRipple ) ? "r" : "-") + ((_sourceDogLeg ) ? "s" : "-") + ((_targetDogLeg ) ? "t" : "-"); s1.insert ( s1.size()-1, s2 ); return s1; } Record* TrackSegment::_getRecord () const { Record* record = TrackElement::_getRecord (); record->add ( getSlot ( "_base" , _base ) ); record->add ( getSlot ( "_lock" , _lock ) ); record->add ( getSlot ( "_revalidated", _revalidated ) ); return record; } } // End of Kite namespace.