diff --git a/anabatic/src/AnabaticEngine.cpp b/anabatic/src/AnabaticEngine.cpp index b36f1238..67e71f73 100644 --- a/anabatic/src/AnabaticEngine.cpp +++ b/anabatic/src/AnabaticEngine.cpp @@ -21,6 +21,7 @@ #include "hurricane/Horizontal.h" #include "hurricane/Vertical.h" #include "hurricane/Cell.h" +#include "hurricane/DebugSession.h" #include "hurricane/UpdateSession.h" #include "crlcore/RoutingGauge.h" #include "anabatic/GCell.h" @@ -39,11 +40,28 @@ namespace Anabatic { using Hurricane::Horizontal; using Hurricane::Vertical; using Hurricane::Cell; + using Hurricane::DebugSession; using Hurricane::UpdateSession; using CRL::RoutingGauge; using CRL::RoutingLayerGauge; +// ------------------------------------------------------------------- +// Error messages. + + const char* missingAnbt = + "%s :\n\n" + " Cell %s do not have any Anabatic (or not yet created).\n"; + + const char* badMethod = + "%s :\n\n" + " No method id %ud (Cell %s).\n"; + + const char* lookupFailed = + "Anabatic::Extension::getDatas(Segment*) :\n\n" + " Cannot find AutoSegment associated to %s (internal error).\n"; + + // ------------------------------------------------------------------- // Class : "Anabatic::AnabaticEngine". @@ -66,12 +84,16 @@ namespace Anabatic { : Super(cell) , _timer () , _configuration (new ConfigurationConcrete()) + , _state (EngineCreation) , _matrix () , _gcells () , _ovEdges () , _viewer (NULL) - , _flags (Flags::NoFlags) + , _flags (Flags::DestroyBaseContact) , _stamp (-1) + , _densityMode (MaxDensity) + , _autoSegmentLut() + , _autoContactLut() { _matrix.setCell( cell, _configuration->getSliceHeight() ); Edge::unity = _configuration->getSliceHeight(); @@ -108,19 +130,71 @@ namespace Anabatic { void AnabaticEngine::_preDestroy () { - _clear(); + cdebug_log(145,1) << "Anabatic::_preDestroy ()" << endl; + + if (getState() < EngineGutted) + setState( EnginePreDestroying ); + + _gutAnabatic(); + _state = EngineGutted; + + cdebug_log(145,0) << "About to delete base class ToolEngine." << endl; Super::_preDestroy(); + + //cmess2 << " - GCells := " << GCell::getAllocateds() << endl; + cmess2 << " - AutoContacts := " << AutoContact::getAllocateds() << endl; + cmess2 << " - AutoSegments := " << AutoSegment::getAllocateds() << endl; + + cdebug_log(145,0) << "Exiting Anabatic::_preDestroy()." << endl; + cdebug_tabw(145,-1); } - void AnabaticEngine::_clear () + void AnabaticEngine::_gutAnabatic () { - _flags |= Flags::Destroy; + Session::open( this ); - for ( GCell* gcell : _gcells ) gcell->_destroyEdges(); - for ( GCell* gcell : _gcells ) gcell->destroy(); - _gcells.clear(); - _ovEdges.clear(); + _flags.reset( Flags::DestroyBaseContact|Flags::DestroyBaseSegment ); + + if (_state == EngineDriving) { + cdebug_log(145,1) << "Saving AutoContacts/AutoSegments." << endl; + + size_t fixedSegments = 0; + size_t sameLayerDoglegs = 0; + for ( auto isegment : _autoSegmentLut ) { + if (isegment.second->isFixed()) ++fixedSegments; + if (isegment.second->reduceDoglegLayer()) ++sameLayerDoglegs; + } + + cmess1 << " o Driving Hurricane data-base." << endl; + cmess1 << Dots::asSizet(" - Active AutoSegments",AutoSegment::getAllocateds()-fixedSegments) << endl; + cmess1 << Dots::asSizet(" - Active AutoContacts",AutoContact::getAllocateds()-fixedSegments*2) << endl; + cmess1 << Dots::asSizet(" - AutoSegments" ,AutoSegment::getAllocateds()) << endl; + cmess1 << Dots::asSizet(" - AutoContacts" ,AutoContact::getAllocateds()) << endl; + cmess1 << Dots::asSizet(" - Same Layer doglegs" ,sameLayerDoglegs) << endl; + + //for ( Net* net : _cell->getNets() ) _saveNet( net ); + + cdebug_tabw(145,-1); + } + + if (_state < EngineGutted ) { + cdebug_log(145,0) << "Gutting Anabatic." << endl; + _state = EngineGutted; + _flags |= Flags::DestroyBaseContact; + + _destroyAutoSegments(); + _destroyAutoContacts(); + + _flags |= Flags::DestroyGCell; + + for ( GCell* gcell : _gcells ) gcell->_destroyEdges(); + for ( GCell* gcell : _gcells ) gcell->destroy(); + _gcells.clear(); + _ovEdges.clear(); + } + + Session::close(); } @@ -162,8 +236,9 @@ namespace Anabatic { void AnabaticEngine::reset () { - _clear(); - _flags.reset( Flags::Destroy ); + _gutAnabatic(); + _flags.reset( Flags::DestroyMask ); + _state = EngineCreation; UpdateSession::open(); GCell::create( this ); @@ -204,6 +279,257 @@ namespace Anabatic { } + void AnabaticEngine::cleanupGlobal () + { + UpdateSession::open(); + for ( GCell* gcell : _gcells ) gcell->cleanupGlobal(); + UpdateSession::close(); + } + + + void AnabaticEngine::loadGlobalRouting ( unsigned int method ) + { + if (_state < EngineGlobalLoaded) + throw Error ("AnabaticEngine::loadGlobalRouting() : global routing not present yet."); + + if (_state > EngineGlobalLoaded) + throw Error ("AnabaticEngine::loadGlobalRouting() : global routing already loaded."); + + switch ( method ) { + case EngineLoadGrByNet: _loadGrByNet(); break; + case EngineLoadGrByGCell: + default: + throw Error( badMethod + , "Anabatic::loadGlobalRouting()" + , method + , getString(_cell).c_str() + ); + } + cleanupGlobal(); + + _state = EngineActive; + } + + + void AnabaticEngine::updateNetTopology ( Net* net ) + { + DebugSession::open( net, 140, 150 ); + + cdebug_log(149,0) << "Anabatic::updateNetTopology( " << net << " )" << endl; + cdebug_tabw(145,1); + + vector contacts; + for ( Component* component : net->getComponents() ) { + Contact* contact = dynamic_cast( component ); + if (contact) { + AutoContact* autoContact = Session::lookup( contact ); + if (autoContact and autoContact->isInvalidatedCache()) + contacts.push_back( autoContact ); + } + } + + for ( size_t i=0 ; iupdateTopology(); + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + void AnabaticEngine::finalizeLayout () + { + cdebug_log(145,0) << "Anabatic::finalizeLayout()" << endl; + if (_state > EngineDriving) return; + + _state = EngineDriving; + + startMeasures(); + _gutAnabatic(); + stopMeasures (); + printMeasures( "fin" ); + + _state = EngineGutted; + } + + + void AnabaticEngine::_alignate ( Net* net ) + { + DebugSession::open( net, 140, 150 ); + + cdebug_log(149,0) << "Anabatic::_alignate( " << net << " )" << endl; + cdebug_tabw(145,1); + + //cmess2 << " - " << getString(net) << endl; + + set exploredSegments; + vector unexploreds; + vector aligneds; + + for ( Component* component : net->getComponents() ) { + Segment* segment = dynamic_cast(component); + if (segment) { + AutoSegment* seedSegment = Session::lookup( segment ); + if (seedSegment) unexploreds.push_back( seedSegment ); + } + } + sort( unexploreds.begin(), unexploreds.end(), AutoSegment::CompareId() ); + + for ( size_t i=0 ; ibase()) == exploredSegments.end()) { + cdebug_log(145,0) << "New chunk from: " << seedSegment << endl; + aligneds.push_back( seedSegment ); + + for ( AutoSegment* collapsed : seedSegment->getAligneds() ) { + cdebug_log(145,0) << "Aligned: " << collapsed << endl; + aligneds.push_back( collapsed ); + exploredSegments.insert( collapsed->base() ); + } + + cdebug_tabw(145,1); + sort( aligneds.begin(), aligneds.end(), AutoSegment::CompareId() ); + + cdebug_log(145,0) << "Seed: " << (void*)aligneds[0]->base() << " " << aligneds[0] << endl; + for ( size_t j=1 ; jbase()) << " " << aligneds[j] << endl; + } + + cdebug_log(149,0) << "Align on " << aligneds[0] + << " " << DbU::toLambda(aligneds[0]->getAxis()) << endl; + aligneds[0]->setAxis( aligneds[0]->getAxis(), Flags::Realignate ); + aligneds.clear(); + + cdebug_tabw(145,-1); + } + } + + cdebug_tabw(145,-1); + + DebugSession::close(); + } + + + void AnabaticEngine::_computeNetTerminals ( Net* net ) + { + DebugSession::open( net, 140, 150 ); + + cdebug_log(149,0) << "Anabatic::_computeNetTerminals( " << net << " )" << endl; + cdebug_tabw(145,1); + + for ( Segment* segment : net->getSegments() ) { + AutoSegment* autoSegment = Session::lookup( segment ); + if (autoSegment == NULL) continue; + if (autoSegment->isInvalidated()) autoSegment->computeTerminal(); + } + + cdebug_tabw(145,-1); + + DebugSession::close(); + } + + + void AnabaticEngine::_saveNet ( Net* net ) + { + DebugSession::open( net, 140, 150 ); + + cdebug_log(145,0) << "Anabatic::_saveNet() " << net << endl; + cdebug_tabw(145,1); + +#if 0 + cdebug_log(145,0) << "Deleting zero-length segments." << endl; + + vector nullSegments; + set connectedLayers; + + forEach ( Segment*, segment, net->getSegments() ) { + if (segment->getLength()) { + if (net->isExternal()) { + NetExternalComponents::setExternal( *segment ); + } + continue; + } + + if (Session::lookup(*segment) == NULL) { + cdebug_log(145,0) << "* Not associated to an AutoSegment: " << *segment << endl; + continue; + } + + if (not isTopAndBottomConnected(*segment,connectedLayers)) { + nullSegments.push_back( *segment ); + cdebug_log(145,0) << "* Null Length: " << *segment << endl; + } + } + + setFlags( EngineDestroyBaseSegment ); + for ( size_t i = 0 ; i < nullSegments.size() ; i++ ) { + Contact* source = dynamic_cast(nullSegments[i]->getSource()); + Contact* target = dynamic_cast(nullSegments[i]->getTarget()); + + if ( (source == NULL) or (target == NULL) ) { + cerr << Error("Unconnected source/target on %s.",getString(nullSegments[i]).c_str()) << endl; + continue; + } + + if (source->getAnchor()) { + if (target->getAnchor()) { + continue; + //cerr << Bug("Both source & target are anchored while deleting zero-length segment:\n" + // " %s.",getString(nullSegments[i]).c_str()) << endl; + } else + swap( source, target ); + } + + cdebug_log(145,0) << "Deleting: " << nullSegments[i] << endl; + if (isTopAndBottomConnected(nullSegments[i],connectedLayers)) { + cdebug_log(145,0) << "Deletion cancelled, no longer top or bottom connected." << endl; + continue; + } + + cdebug_log(145,0) << "* Source: " << (void*)source << " " << source << endl; + cdebug_log(145,0) << "* Target: " << (void*)target << " " << target << endl; + + const Layer* layer = DataBase::getDB()->getTechnology() + ->getViaBetween( *connectedLayers.begin(), *connectedLayers.rbegin() ); + + cdebug_log(145,0) << *connectedLayers.begin() << " + " << *connectedLayers.rbegin() << endl; + cdebug_log(145,0) << "* Shrink layer: " << layer << endl; + if ( !layer ) { + cerr << Error("NULL contact layer while deleting %s." + ,getString(nullSegments[i]).c_str()) << endl; + continue; + } + + Session::lookup( nullSegments[i] )->destroy (); + + vector slaveHooks; + Hook* masterHook = source->getBodyHook()->getPreviousMasterHook(); + + while ( masterHook->getNextHook() != source->getBodyHook() ) { + slaveHooks.push_back( masterHook->getNextHook() ); + cdebug_log(145,0) << "* detach: " + << (void*)masterHook->getNextHook()->getComponent() + << " " << masterHook->getNextHook()->getComponent() << endl; + masterHook->getNextHook()->detach(); + } + source->destroy(); + + masterHook = target->getBodyHook(); + for ( size_t j=0 ; j < slaveHooks.size() ; j++ ) { + slaveHooks[j]->attach( masterHook ); + } + + cdebug_log(145,0) << (void*)target << " " << target << " setLayer: " << layer << endl; + target->setLayer( layer ); + } + unsetFlags( EngineDestroyBaseSegment ); +#endif + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + void AnabaticEngine::startMeasures () { _timer.resetIncrease(); @@ -231,6 +557,88 @@ namespace Anabatic { } + void AnabaticEngine::updateDensity () + { for ( GCell* gcell : _gcells ) gcell->updateDensity(); } + + + AutoSegment* AnabaticEngine::_lookup ( Segment* segment ) const + { + AutoSegmentLut::const_iterator it = _autoSegmentLut.find( segment ); + if (it == _autoSegmentLut.end()) return NULL; + + return (*it).second; + } + + + void AnabaticEngine::_link ( AutoSegment* autoSegment ) + { + if (_state > EngineActive) return; + _autoSegmentLut[ autoSegment->base() ] = autoSegment; + } + + + void AnabaticEngine::_unlink ( AutoSegment* autoSegment ) + { + if (_state > EngineDriving) return; + + AutoSegmentLut::iterator it = _autoSegmentLut.find( autoSegment->base() ); + if (it != _autoSegmentLut.end()) + _autoSegmentLut.erase( it ); + } + + + AutoContact* AnabaticEngine::_lookup ( Contact* contact ) const + { + AutoContactLut::const_iterator it = _autoContactLut.find( contact ); + if (it == _autoContactLut.end()) { + return NULL; + } + return (*it).second; + } + + + void AnabaticEngine::_link ( AutoContact* autoContact ) + { + if (_state > EngineActive) return; + _autoContactLut [ autoContact->base() ] = autoContact; + } + + + void AnabaticEngine::_unlink ( AutoContact* autoContact ) + { + if ( _state > EngineActive ) return; + + AutoContactLut::iterator it = _autoContactLut.find( autoContact->base() ); + if (it != _autoContactLut.end()) + _autoContactLut.erase( it ); + } + + + void AnabaticEngine::_destroyAutoSegments () + { + cdebug_log(145,0) << "Anabatic::_destroyAutoSegments ()" << endl; + + size_t expandeds = 0; + for ( auto sasp : _autoSegmentLut ) { + expandeds++; + sasp.second->destroy(); + } + if (_state == EngineDriving) + cmess2 << " - Expandeds := " << expandeds << endl; + + _autoSegmentLut.clear(); + } + + + void AnabaticEngine::_destroyAutoContacts () + { + cdebug_log(145,0) << "Anabatic::_destroyAutoContacts ()" << endl; + + for ( auto cacp : _autoContactLut ) cacp.second->destroy(); + _autoContactLut.clear(); + } + + string AnabaticEngine::_getTypeName () const { return getString(_toolName); } diff --git a/anabatic/src/AutoContact.cpp b/anabatic/src/AutoContact.cpp new file mode 100644 index 00000000..4bdfcae7 --- /dev/null +++ b/anabatic/src/AutoContact.cpp @@ -0,0 +1,631 @@ +// -*- 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 | +// | 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) + , _dxMin (0) + , _dxMax ((int)DbU::toLambda( _gcell->getXMax()-_gcell->getXMin() )) + , _dyMin (0) + , _dyMax ((int)DbU::toLambda( _gcell->getYMax()-_gcell->getYMin() )) + { + _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::toLambda(getCBXMin()) + << " " << DbU::toLambda(getCBYMin()) + << " " << DbU::toLambda(getCBXMax()) + << " " << DbU::toLambda(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(), 140, 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; + + 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 ); + } + +#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 & 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; } + + + 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()) ); + //cdebug_log(149,0) << "Anchor:" << anchor << endl; + } + + forEach ( AutoSegment*, isegment, const_cast(this)->getAutoSegments() ) { + minDepth = std::min( minDepth, Session::getRoutingGauge()->getLayerDepth(isegment->getLayer()) ); + //cdebug_log(149,0) << "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()) ); + //cdebug_log(149,0) << "Anchor:" << anchor << endl; + } + + forEach ( AutoSegment*, isegment, const_cast(this)->getAutoSegments() ) { + maxDepth = std::max ( maxDepth, Session::getRoutingGauge()->getLayerDepth(isegment->getLayer()) ); + //cdebug_log(149,0) << "Slave:" << *icomponent << endl; + } + + return (unsigned int)maxDepth; + } + + + 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(); + + 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; + + DbU::Unit sideLength = (isegment->isHorizontal()) ? hSideLength : vSideLength; + if ( not isegment->isUnbound() and (abs(length) > sideLength) ) + cerr << Error("Suspicious length:%.2f of %s." + ,DbU::toLambda(length),getString(*isegment).c_str()) << endl; + } else { + if ( isegment->isHorizontal() ) { + if (isSourceHook) + lengths[depth] += _gcell->getXMax() - isegment->getSourceX(); + else + lengths[depth] += isegment->getTargetX() - _gcell->getXMin(); + } else { + if (isSourceHook) + lengths[depth] += _gcell->getYMax() - isegment->getSourceY(); + else + lengths[depth] += isegment->getTargetY() - _gcell->getYMin(); + } + } + } + } + + + Box AutoContact::getNativeConstraintBox () const + { + if (isUserNativeConstraints()) return getConstraintBox(); + if (isFixed()) return Box(_contact->getPosition()); + return _gcell->getBoundingBox(); + } + + + Interval AutoContact::getNativeUConstraints ( unsigned int 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 ( unsigned int 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 ( unsigned int flags ) + { + if (not isInvalidated()) { + cdebug_log(145,1) << "AutoContact::invalidate() - " << this << endl; + setFlags( CntInvalidated ); + if (flags & Flags::Topology ) setFlags( CntInvalidatedCache ); + Session::invalidate( this ); + + _invalidate( flags ); + //forEach( AutoSegment*, isegment, getAutoSegments() ) + // isegment->invalidate(); + + 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() ); + _dxMin = 0; + _dyMin = 0; + _dxMax = (int)DbU::toLambda( _gcell->getXMax()-_gcell->getXMin() ); + _dyMax = (int)DbU::toLambda( _gcell->getYMax()-_gcell->getYMin() ); + cdebug_log(145,0) << "* deltas: [" << _dxMin << " " << _dyMin << " " << _dxMax << " " << _dyMax << "]" << endl; + } else { + cerr << Bug( "NULL GCell for %s.", _getString().c_str() ) << endl; + } + } + + + 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(); + + forEach ( Component*, icomponent, support->getSlaveComponents() ) { + Horizontal* h = dynamic_cast(*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, unsigned int 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; + } + + + bool AutoContact::isTee ( unsigned int 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; + } + + 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; + + 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() << endl; + cdebug_log(149,0) << "* " << _gcell << endl; + } + + + bool AutoContact::restrictConstraintBox ( DbU::Unit constraintMin + , DbU::Unit constraintMax + , unsigned int 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 : %.2lf > %.2lf)" + , DbU::toLambda(constraintMin) + , DbU::toLambda(getCBYMax()) ) + << endl; + if ( constraintMax < getCBYMin() ) + cerr << Error ( "(constraintMax < CBYMin : %.2lf < %.2lf)" + , DbU::toLambda(constraintMax) + , DbU::toLambda(getCBYMin()) ) + << 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 : %.2lf > %.2lf)" + , DbU::toLambda(constraintMin) + , DbU::toLambda(getCBXMax()) ) + << endl; + if ( constraintMax < getCBXMin() ) + cerr << Error ( "(constraintMax < CBXMin : %.2lf < %.2lf)" + , DbU::toLambda(constraintMax) + , DbU::toLambda(getCBXMin()) ) + << 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 ); + } + + + 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, (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. diff --git a/anabatic/src/AutoContactHTee.cpp b/anabatic/src/AutoContactHTee.cpp new file mode 100644 index 00000000..31e455ed --- /dev/null +++ b/anabatic/src/AutoContactHTee.cpp @@ -0,0 +1,340 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2012-2016, 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 : "./AutoContactHTee.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/Vertical.h" +#include "hurricane/Horizontal.h" +#include "hurricane/DebugSession.h" +#include "crlcore/RoutingGauge.h" +#include "anabatic/AutoContactHTee.h" +#include "anabatic/AutoVertical.h" +#include "anabatic/AutoHorizontal.h" +#include "anabatic/Session.h" + + +namespace Anabatic { + + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::DebugSession; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoContactHTee". + + + AutoContactHTee* AutoContactHTee::create ( GCell* gcell, Net* net, const Layer* layer ) + { + DbU::Unit viaSide = Session::getViaWidth( layer ); + Contact* contact = Contact::create ( net + , layer + , gcell->getCenter().getX() + , gcell->getCenter().getY() + , viaSide + , viaSide + ); + AutoContactHTee* autoContact = new AutoContactHTee ( gcell, contact ); + + autoContact->_postCreate(); + autoContact->unsetFlags( CntInCreationStage ); + + cdebug_log(145,0) << "create(net*) " << autoContact << endl; + return autoContact; + } + + + AutoContactHTee::AutoContactHTee ( GCell* gcell, Contact* contact ) + : AutoContact (gcell,contact) + , _horizontal1(NULL) + , _horizontal2(NULL) + , _vertical1 (NULL) + { + setFlags( CntHTee ); + } + + + AutoContactHTee::~AutoContactHTee () + { } + + + AutoSegment* AutoContactHTee::getOpposite ( const AutoSegment* from ) const + { + if (from == _horizontal1) return _horizontal2; + if (from == _horizontal2) return _horizontal1; + return NULL; + } + + + AutoSegment* AutoContactHTee::getPerpandicular ( const AutoSegment* ) const + { return NULL; } + + + AutoSegment* AutoContactHTee::getSegment ( unsigned int index ) const + { + AutoSegment* segment = NULL; + switch ( index ) { + case 0: return _horizontal1; + case 1: return _horizontal2; + case 2: return _vertical1; + } + //if (not segment) + // cerr << Error( "In %s:\n No cached segment at index %d" + // , getString(this).c_str(), index ) << endl; + return segment; + } + + + void AutoContactHTee::_invalidate ( unsigned int ) + { + unsigned int flags = Flags::Propagate; + if (_horizontal1 and _horizontal2) { + if (_horizontal1->isInvalidated() xor _horizontal2->isInvalidated()) + flags = Flags::NoFlags; + } + + if (_horizontal1) _horizontal1->invalidate( flags ); + if (_horizontal2) _horizontal2->invalidate( flags ); + if (_vertical1 ) _vertical1 ->invalidate(); + } + + + void AutoContactHTee::cacheDetach ( AutoSegment* segment ) + { + cdebug_log(145,0) << _getTypeName() << "::cacheDetach() " << this << endl; + cdebug_log(145,0) << "| h1:" << _horizontal1 << endl; + cdebug_log(145,0) << "| h2:" << _horizontal2 << endl; + cdebug_log(145,0) << "| v1:" << _vertical1 << endl; + + if (segment == _horizontal1) _horizontal1 = NULL; + else if (segment == _horizontal2) _horizontal2 = NULL; + else if (segment == _vertical1) _vertical1 = NULL; + else { + if (_horizontal1 or _horizontal2 or _vertical1) + cerr << Bug( "%s::cacheDetach() On %s,\n" + " Cannot detach %s\n" + " because it *not* attached to this contact." + , _getTypeName().c_str() + , getString(this).c_str() + , getString(segment).c_str() + ) << endl; + return; + } + + setFlags( CntInvalidatedCache ); + } + + + void AutoContactHTee::cacheAttach ( AutoSegment* segment ) + { + cdebug_log(145,1) << _getTypeName() << "::cacheAttach() " << this << endl; + cdebug_log(145,0) << "Attaching: " << segment << endl; + + if (segment->getDirection() == Flags::Horizontal) { + if (not _horizontal1) _horizontal1 = static_cast(segment); + else if (not _horizontal2) _horizontal2 = static_cast(segment); + else { + cerr << Bug( "%s::cacheAttach() On %s,\n" + " h1 & h2 cache have not been cleared first, cancelled." + , _getTypeName().c_str(), getString(this).c_str() + ) << endl; + cdebug_tabw(145,-1); + return; + } + } else if (segment->getDirection() == Flags::Vertical) { + if (_vertical1) { + cerr << Bug( "%s::cacheAttach() On %s,\n" + " v1 cache has not been cleared first, cancelled." + , _getTypeName().c_str(), getString(this).c_str() + ) << endl; + cdebug_tabw(145,-1); + return; + } + _vertical1 = static_cast(segment); + } + + if (_horizontal1 and _horizontal2 and _vertical1) + unsetFlags( CntInvalidatedCache ); + + cdebug_log(145,0) << "| h1:" << _horizontal1 << endl; + cdebug_log(145,0) << "| h2:" << _horizontal2 << endl; + cdebug_log(145,0) << "| v1:" << _vertical1 << endl; + + cdebug_tabw(145,-1); + } + + + void AutoContactHTee::updateCache () + { + DebugSession::open( getNet(), 140, 150 ); + + cdebug_log(145,1) << _getTypeName() << "::updateCache() " << this << endl; + + Component* anchor; + Horizontal** horizontals = new Horizontal* [3]; + Vertical** verticals = new Vertical* [3]; + + _getTopology( base(), anchor, horizontals, verticals, 3 ); + + _horizontal1 = static_cast( Session::lookup(horizontals[0]) ); + _horizontal2 = static_cast( Session::lookup(horizontals[1]) ); + _vertical1 = static_cast( Session::lookup(verticals [0]) ); + + string message; + if (horizontals[0] == NULL) message = "HTee has less than two horizontal segments."; + else if (horizontals[1] == NULL) message = "HTee has less than two horizontal segments."; + else if (horizontals[2] != NULL) message = "HTee has more than two horizontal segments."; + else if (verticals [0] == NULL) message = "HTee is missing mandatory vertical segment."; + else if (verticals [1] != NULL) message = "HTee has more than one vertical segment."; + else if (_horizontal1 == NULL) message = "AutoSegment lookup failed on first horizontal segment."; + else if (_horizontal2 == NULL) message = "AutoSegment lookup failed on second horizontal segment."; + else if (_vertical1 == NULL) message = "AutoSegment lookup failed on vertical segment."; + else if ( (not _horizontal1->isCreated() and not _horizontal2->isCreated()) + and (_horizontal1->getY() != _horizontal2->getY()) ) { + message = "HTee has misaligned horizontal segments"; + message += " h1:" + getString(_horizontal1->getY()); + message += " h2:" + getString(_horizontal2->getY()); + } + if (not message.empty()) { + showTopologyError( message ); + setFlags( CntBadTopology ); + } + unsetFlags( CntInvalidatedCache ); + + cdebug_log(145,0) << "h1:" << _horizontal1 << endl; + cdebug_log(145,0) << "h2:" << _horizontal2 << endl; + cdebug_log(145,0) << "v1:" << _vertical1 << endl; + + delete [] horizontals; + delete [] verticals; + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + void AutoContactHTee::updateGeometry () + { + DebugSession::open( getNet(), 140, 150 ); + + cdebug_log(145,1) << _getTypeName() << "::updateGeometry() " << this << endl; + + if (isInvalidatedCache()) updateCache(); + if (isInvalidatedCache()) { + cerr << Error( "%s::updateGeometry() %s: Unable to restore cache." + , _getTypeName().c_str(), getString(this).c_str() ) << endl; + cdebug_tabw(145,-1); + return; + } + + base()->invalidate( false ); + unsetFlags( CntInvalidated ); + + if (not hasBadTopology()) { + setX( getVertical1 ()->getX() ); + setY( getHorizontal1()->getY() ); + } + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + void AutoContactHTee::updateTopology () + { + DebugSession::open( getNet(), 140, 150 ); + + cdebug_log(145,1) << _getTypeName() << "::updateTopology() " << this << endl; + + if (isInvalidatedCache()) updateCache(); + if (isInvalidatedCache()) { + cerr << Error( "%s::updateGeometry() %s: Unable to restore cache." + , _getTypeName().c_str(), getString(this).c_str() ) << endl; + cdebug_tabw(145,-1); + return; + } + + if (not hasBadTopology()) { + RoutingGauge* rg = Session::getRoutingGauge(); + size_t depthH1 = rg->getLayerDepth( getHorizontal1()->getLayer() ); + size_t depthH2 = rg->getLayerDepth( getHorizontal2()->getLayer() ); + size_t depthV1 = rg->getLayerDepth( getVertical1 ()->getLayer() ); + size_t minDepth = std::min( depthV1, std::min(depthH1,depthH2) ); + size_t maxDepth = std::max( depthV1, std::max(depthH1,depthH2) ); + size_t delta = maxDepth - minDepth; + + cdebug_log(145,0) << "delta:" << delta << endl; + + unsetFlags( CntWeakTerminal ); + + if (maxDepth - minDepth > 3) { + showTopologyError( "Sheared HTee, layer delta exceed 3." ); + setFlags( CntBadTopology ); + } else { + if (depthH1 == depthH2) { + // Dogleg on the vertical. + switch ( delta ) { + case 0: setLayer( rg->getRoutingLayer(minDepth) ); break; + case 1: setLayer( rg->getContactLayer(minDepth) ); break; + default: + setLayer( rg->getContactLayer( depthH1 + ((depthH1==minDepth)?0:-1) ) ); + _vertical1 = static_cast( _vertical1->makeDogleg(this) ); + break; + } + } else { + // Dogleg on the horizontal with the greater gap (should be equal to +/-2). + int deltaH1 = (int)depthH1 - (int)depthV1; + int deltaH2 = (int)depthH2 - (int)depthV1; + + if (std::abs(deltaH1) > std::abs(deltaH2)) { + setLayer( rg->getContactLayer( depthH2 + ((depthH2( _horizontal1->makeDogleg(this) ); + _horizontal1->makeDogleg(this); + cdebug_log(145,0) << "New h1:" << _horizontal1 << endl; + } else { + setLayer( rg->getContactLayer( depthH1 + ((depthH1( _horizontal2->makeDogleg(this) ); + _horizontal2->makeDogleg(this); + cdebug_log(145,0) << "New h2:" << _horizontal2 << endl; + } + } + } + + _horizontal1->invalidate( this ); + _horizontal2->invalidate( this ); + _vertical1 ->invalidate( this ); + } + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + string AutoContactHTee::_getTypeName () const + { return "ContactHTee"; } + + +} // Anabatic namespace. diff --git a/anabatic/src/AutoContactTerminal.cpp b/anabatic/src/AutoContactTerminal.cpp new file mode 100644 index 00000000..b7c47ee7 --- /dev/null +++ b/anabatic/src/AutoContactTerminal.cpp @@ -0,0 +1,406 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2012-2016, 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 : "./AutoContactTerminal.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/AutoContactTerminal.h" +#include "anabatic/AutoContactTurn.h" +#include "anabatic/AutoVertical.h" +#include "anabatic/AutoHorizontal.h" +#include "anabatic/Session.h" + + +namespace Anabatic { + + using std::ostringstream; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::DebugSession; + using Hurricane::Transformation; + using Hurricane::Entity; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoContactTerminal". + + + AutoContactTerminal* AutoContactTerminal::create ( GCell* gcell + , Component* anchor + , const Layer* layer + , Point point + , DbU::Unit width + , DbU::Unit height + ) + { + cdebug_log(145,1) << "AutoContactTerminal::create(... Point, ...)" << endl; + cdebug_log(145,0) << "@" << point << endl; + + anchor->getBodyHook()->detach(); + + AutoContactTerminal* autoContact = AutoContactTerminal::create( gcell + , anchor + , layer + , point.getX(), point.getY() + , width, height + ); + cdebug_tabw(145,-1); + return autoContact; + } + + + AutoContactTerminal* AutoContactTerminal::create ( GCell* gcell + , Component* anchor + , const Layer* layer + , const DbU::Unit x + , const DbU::Unit y + , const DbU::Unit width + , const DbU::Unit height + ) + { + cdebug_log(145,0) << "AutoContactTerminal::create(... x, y, ...)" << endl; + cdebug_log(145,0) << "@ x:" << DbU::getValueString(x) << " y:" << DbU::getValueString(y) << endl; + + Point anchorPosition = anchor->getPosition(); + + Contact* contact = Contact::create( anchor + , layer + , x - anchorPosition.getX() + , y - anchorPosition.getY() + , width + , height + ); + AutoContactTerminal* autoContact = new AutoContactTerminal( gcell, contact ); + + autoContact->_postCreate(); + autoContact->unsetFlags( CntInCreationStage ); + + cdebug_log(145,0) << "create(Component*) " << autoContact << endl; + return autoContact; + } + + + AutoContactTerminal::AutoContactTerminal ( GCell* gcell, Contact* contact ) + : AutoContact(gcell,contact) + , _segment (NULL) + { + setFlags( CntTerminal ); + } + + + AutoContactTerminal::~AutoContactTerminal () + { } + + + AutoSegment* AutoContactTerminal::getOpposite ( const AutoSegment* ) const + { return NULL; } + + + AutoSegment* AutoContactTerminal::getPerpandicular ( const AutoSegment* ) const + { return NULL; } + + + AutoSegment* AutoContactTerminal::getSegment ( unsigned int index ) const + { + if (_segment) { + switch ( index ) { + case 0: return (_segment->isHorizontal()) ? _segment : NULL; + case 2: return (_segment->isVertical ()) ? _segment : NULL; + } + } + return NULL; + } + + + Box AutoContactTerminal::getNativeConstraintBox () const + { + cdebug_log(145,1) << "AutoContactTerminal::getNativeConstraintBox()" << endl; + + Component* component = getAnchor(); + if (component == NULL) { + cerr << Error( "%s is not anchored.", getString(this).c_str() ) << endl; + cdebug_tabw(145,-1); + return _gcell->getBoundingBox (); + } + + DbU::Unit xMin; + DbU::Unit xMax; + DbU::Unit yMin; + DbU::Unit yMax; + Vertical* vertical; + Horizontal* horizontal; + RoutingPad* routingPad; + + if ( (horizontal = dynamic_cast(component)) ) { + cdebug_log(145,0) << "Anchor: " << horizontal << "@" << horizontal->getSourcePosition() << endl; + xMin = horizontal->getSourcePosition().getX(); + xMax = horizontal->getTargetPosition().getX(); + yMin = yMax + = horizontal->getTargetPosition().getY(); + } else if ( (vertical = dynamic_cast(component)) ) { + cdebug_log(145,0) << "Anchor: " << vertical << "@" << vertical->getSourcePosition() << endl; + yMin = vertical->getSourcePosition().getY(); + yMax = vertical->getTargetPosition().getY(); + xMin = xMax + = vertical->getTargetPosition().getX(); + } else if ( (routingPad = dynamic_cast(component)) ) { + Entity* entity = routingPad->getOccurrence().getEntity(); + Transformation transf = routingPad->getOccurrence().getPath().getTransformation(); + cdebug_log(145,0) << "Anchor: " << routingPad << endl; + + int rpOrient = 1; + switch ( transf.getOrientation() ) { + case Transformation::Orientation::R1: + case Transformation::Orientation::R3: + case Transformation::Orientation::XR: + case Transformation::Orientation::YR: + rpOrient = 2; + break; + default: + break; + } + + if (dynamic_cast(entity)) { + // rpOrient *is* the rotation. + } else if ( dynamic_cast(entity) ) { + // rpOrient is the inverse rotation. + rpOrient = (rpOrient == 1) ? 2 : 1; + } else { + rpOrient = 0; + } + + switch ( rpOrient ) { + case 1: + xMin = routingPad->getSourcePosition().getX(); + xMax = routingPad->getTargetPosition().getX(); + yMin = yMax + = routingPad->getTargetPosition().getY(); + break; + case 2: + yMin = routingPad->getSourcePosition().getY(); + yMax = routingPad->getTargetPosition().getY(); + xMin = xMax + = routingPad->getTargetPosition().getX(); + break; + default: + xMin = xMax = routingPad->getPosition().getX(); + yMin = yMax = routingPad->getPosition().getY(); + break; + } + } else { + xMin = xMax = component->getPosition().getX(); + yMin = yMax = component->getPosition().getY(); + } + + order( xMin, xMax ); + order( yMin, yMax ); + + cdebug_log(145,0) << "| Using (y): " << DbU::getValueString(yMin) << " " + << DbU::getValueString(yMax) << endl; + + cdebug_tabw(145,-1); + return Box( xMin, yMin, xMax, yMax ); + } + + + void AutoContactTerminal::_invalidate ( unsigned int flags ) + { + if (_segment) _segment->invalidate(); + } + + + void AutoContactTerminal::cacheDetach ( AutoSegment* segment ) + { + if (_segment == segment) { + _segment = NULL; + setFlags( CntInvalidatedCache ); + } + } + + + void AutoContactTerminal::cacheAttach ( AutoSegment* segment ) + { + if (_segment) { + cerr << Bug( "%s::cacheAttach() On %s,\n" + " cache has not been cleared first, cancelled." + , _getTypeName().c_str(), getString(this).c_str() + ) << endl; + return; + } + _segment = segment; + unsetFlags( CntInvalidatedCache ); + } + + + void AutoContactTerminal::updateCache () + { + DebugSession::open( getNet(), 140, 150 ); + + cdebug_log(145,1) << _getTypeName() << "::updateCache() " << this << endl; + + Component* anchor; + Horizontal** horizontals = new Horizontal* [2]; + Vertical** verticals = new Vertical* [2]; + + _getTopology( base(), anchor, horizontals, verticals, 2 ); + + if (anchor == NULL) + showTopologyError( "Terminal is missing an anchor (RoutingPad or Component)." ); + + size_t count = 0; + if (horizontals[0] != NULL) ++count; + if (horizontals[1] != NULL) ++count; + if (verticals [0] != NULL) ++count; + if (verticals [1] != NULL) ++count; + if (count > 1) { + showTopologyError( "Terminal has more than one segment." ); + } + if (horizontals[0] != NULL ) { + _segment = Session::lookup( horizontals[0] ); + } else { + _segment = Session::lookup( verticals[0] ); + } + if (_segment == NULL) { + ostringstream os; + os << this << ", AutoSegment lookup failed for:" + << "\n h1: " << horizontals[0] + << "\n v1: " << verticals[0]; + + delete [] horizontals; + delete [] verticals; + + showTopologyError( os.str() ); + throw Error( os.str() ); + } + unsetFlags( CntInvalidatedCache ); + cdebug_log(145,0) << "seg:" << _segment << endl; + + delete [] horizontals; + delete [] verticals; + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + void AutoContactTerminal::updateGeometry () + { + DebugSession::open( getNet(), 140, 150 ); + + cdebug_log(145,1) << _getTypeName() << "::updateGeometry() " << this << endl; + + if (isInvalidatedCache()) updateCache(); + if (isInvalidatedCache()) { + cerr << Error( "%s::updateGeometry() %s: Unable to restore cache." + , _getTypeName().c_str(), getString(this).c_str() ) << endl; + cdebug_tabw(145,-1); + return; + } + + base()->invalidate( false ); + unsetFlags( CntInvalidated ); + + ostringstream message; + if (not hasBadTopology()) { + if (_segment->isHorizontal()) { + if (not getUConstraints(Flags::Vertical).contains(_segment->getY())) { + cdebug_log(145,0) << "Cached: " << _segment << endl; + message << "Terminal horizontal segment Y " << DbU::getValueString(_segment->getY()) + << " axis is outside RoutingPad " << getUConstraints(Flags::Vertical) << "."; + + unsigned int flags = 0; + if (_segment->isCreated()) flags |= Flags::CParanoid; + showTopologyError( message.str(), flags ); + } else + setY( _segment->getY() ); + } else { + if (not getUConstraints(Flags::Horizontal).contains(_segment->getX())) { + cdebug_log(145,0) << "Cached: " << _segment << endl; + message << "Terminal vertical segment X" << DbU::getValueString(_segment->getX()) + << " axis is outside RoutingPad " << getUConstraints(Flags::Horizontal) << "."; + + unsigned int flags = 0; + if (_segment->isCreated()) flags |= Flags::CParanoid; + showTopologyError( message.str(), flags ); + } else + setX( _segment->getX() ); + } + } + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + void AutoContactTerminal::updateTopology () + { + DebugSession::open( getNet(), 140, 150 ); + + cdebug_log(145,1) << _getTypeName() << "::updateTopology() " << this << endl; + + if (isInvalidatedCache()) updateCache(); + if (isInvalidatedCache()) { + cerr << Error( "%s::updateGeometry() %s: Unable to restore cache." + , _getTypeName().c_str(), getString(this).c_str() ) << endl; + cdebug_tabw(145,-1); + return; + } + + RoutingGauge* rg = Session::getRoutingGauge(); + size_t anchorDepth = rg->getLayerDepth( (_flags & CntIgnoreAnchor) ? getLayer() + : getAnchor()->getLayer() ); + size_t segmentDepth = rg->getLayerDepth( _segment->getLayer() ); + size_t delta = abssub( anchorDepth, segmentDepth ); + + if (delta > 3) { + showTopologyError( "Sheared Terminal, layer delta exceed 3." ); + setFlags( CntBadTopology ); + } else { + if (delta > 1) { + //_segment = _segment->makeDogleg( this ); + _segment->makeDogleg( this ); + cdebug_log(145,0) << "Update seg: " << _segment << endl; + delta = abssub( anchorDepth, rg->getLayerDepth( _segment->getLayer() ) ); + } + else if (delta == 0) setLayer( rg->getRoutingLayer(anchorDepth) ); + else if (delta == 1) setLayer( rg->getContactLayer(std::min(anchorDepth,segmentDepth)) ); + } + _segment->invalidate( this ); + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + string AutoContactTerminal::_getTypeName () const + { return "ContactTerminal"; } + + +} // Anabatic namespace. diff --git a/anabatic/src/AutoContactTurn.cpp b/anabatic/src/AutoContactTurn.cpp new file mode 100644 index 00000000..540c7140 --- /dev/null +++ b/anabatic/src/AutoContactTurn.cpp @@ -0,0 +1,273 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2012-2016, 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 : "./AutoContactTurn.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/Vertical.h" +#include "hurricane/Horizontal.h" +#include "hurricane/DebugSession.h" +#include "crlcore/RoutingGauge.h" +#include "anabatic/AutoContactTurn.h" +#include "anabatic/AutoVertical.h" +#include "anabatic/AutoHorizontal.h" +#include "anabatic/Session.h" + + +namespace Anabatic { + + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::DebugSession; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoContactTurn". + + + AutoContactTurn* AutoContactTurn::create ( GCell* gcell, Net* net, const Layer* layer ) + { + _preCreate( gcell, net, layer ); + + DbU::Unit viaSide = Session::getViaWidth( layer ); + Contact* contact = Contact::create ( net + , layer + , gcell->getCenter().getX() + , gcell->getCenter().getY() + , viaSide + , viaSide + ); + AutoContactTurn* autoContact = new AutoContactTurn ( gcell, contact ); + + autoContact->_postCreate(); + autoContact->unsetFlags( CntInCreationStage ); + + cdebug_log(145,0) << "create(net*) " << autoContact << endl; + return autoContact; + } + + + AutoContactTurn::AutoContactTurn ( GCell* gcell, Contact* contact ) + : AutoContact (gcell,contact) + , _horizontal1(NULL) + , _vertical1 (NULL) + { + setFlags( CntTurn ); + } + + + AutoContactTurn::~AutoContactTurn () + { } + + + AutoSegment* AutoContactTurn::getOpposite ( const AutoSegment* ) const + { return NULL; } + + + AutoSegment* AutoContactTurn::getPerpandicular ( const AutoSegment* reference ) const + { + if (reference == _horizontal1) return _vertical1; + if (reference == _vertical1 ) return _horizontal1; + return NULL; + } + + + AutoSegment* AutoContactTurn::getSegment ( unsigned int index ) const + { + switch ( index ) { + case 0: return _horizontal1; + case 2: return _vertical1; + } + return NULL; + } + + + void AutoContactTurn::_invalidate ( unsigned int flags ) + { + if (_horizontal1) _horizontal1->invalidate(); + if (_vertical1 ) _vertical1 ->invalidate(); + } + + + void AutoContactTurn::cacheDetach ( AutoSegment* segment ) + { + if (segment == _horizontal1) _horizontal1 = NULL; + else if (segment == _vertical1) _vertical1 = NULL; + else return; + + setFlags( CntInvalidatedCache ); + } + + + void AutoContactTurn::cacheAttach ( AutoSegment* segment ) + { + if (segment->getDirection() == Flags::Horizontal) { + if (_horizontal1) { + cerr << Bug( "%s::cacheAttach() On %s,\n" + " h1 cache has not been cleared first, cancelled." + , _getTypeName().c_str(), getString(this).c_str() + ) << endl; + return; + } + _horizontal1 = static_cast(segment); + } else if (segment->getDirection() == Flags::Vertical) { + if (_vertical1) { + cerr << Bug( "%s::cacheAttach() On %s,\n" + " v1 cache has not been cleared first, cancelled." + , _getTypeName().c_str(), getString(this).c_str() + ) << endl; + return; + } + _vertical1 = static_cast(segment); + } + + if (_horizontal1 and _vertical1) unsetFlags( CntInvalidatedCache ); + } + + + void AutoContactTurn::updateCache () + { + DebugSession::open( getNet(), 140, 150 ); + + cdebug_log(145,1) << _getTypeName() << "::updateCache() " << this << endl; + + Component* anchor; + Horizontal** horizontals = new Horizontal* [2]; + Vertical** verticals = new Vertical* [2]; + + _getTopology ( base(), anchor, horizontals, verticals, 2 ); + + _horizontal1 = static_cast( Session::lookup(horizontals[0]) ); + _vertical1 = static_cast( Session::lookup(verticals [0]) ); + + string message; + if (horizontals[0] == NULL) message = "Turn is missing mandatory horizontal segment."; + else if (horizontals[1] != NULL) message = "Turn has more than one horizontal segment."; + else if (verticals [0] == NULL) message = "Turn is missing mandatory vertical segment."; + else if (verticals [1] != NULL) message = "Turn has more than one vertical segment."; + else if (_horizontal1 == NULL) message = "AutoSegment lookup failed on horizontal segment."; + else if (_vertical1 == NULL) message = "AutoSegment lookup failed on vertical segment."; + if (not message.empty()) { + showTopologyError( message ); + setFlags( CntBadTopology ); + } else + unsetFlags( CntInvalidatedCache ); + + cdebug_log(145,0) << "h1:" << _horizontal1 << endl; + cdebug_log(145,0) << "v1:" << _vertical1 << endl; + + delete [] horizontals; + delete [] verticals; + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + void AutoContactTurn::updateGeometry () + { + DebugSession::open( getNet(), 140, 150 ); + + cdebug_log(145,1) << _getTypeName() << "::updateGeometry() " << this << endl; + + if (isInvalidatedCache()) updateCache(); + if (isInvalidatedCache()) { + cerr << Error( "%s::updateGeometry() %s: Unable to restore cache." + , _getTypeName().c_str(), getString(this).c_str() ) << endl; + cdebug_tabw(145,-1); + return; + } + + base()->invalidate( false ); + unsetFlags ( CntInvalidated ); + + if (not hasBadTopology()) { + setX( getVertical1 ()->getX() ); + setY( getHorizontal1()->getY() ); + } + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + void AutoContactTurn::updateTopology () + { + DebugSession::open ( getNet(), 140, 150 ); + + cdebug_log(145,1) << _getTypeName() << "::updateTopology() " << this << endl; + + if (isInvalidatedCache()) updateCache(); + if (isInvalidatedCache()) { + cerr << Error( "%s::updateGeometry() %s: Unable to restore cache." + , _getTypeName().c_str(), getString(this).c_str() ) << endl; + cdebug_tabw(145,-1); + return; + } + + if (not hasBadTopology()) { + RoutingGauge* rg = Session::getRoutingGauge(); + size_t depthH1 = rg->getLayerDepth( getHorizontal1()->getLayer() ); + size_t depthV1 = rg->getLayerDepth( getVertical1 ()->getLayer() ); + size_t depthContact = (depthH1 < depthV1) ? depthH1 : depthH1-1; + size_t delta = abssub ( depthH1, depthV1 ); + + unsetFlags( CntWeakTerminal ); + if (delta > 3) { + showTopologyError( "Sheared Turn, layer delta exceed 3." ); + setFlags( CntBadTopology ); + } else { + if (delta == 3) { + if (_horizontal1->isInvalidatedLayer()) { + //_horizontal1 = static_cast( _horizontal1->makeDogleg(this) ); + _horizontal1->makeDogleg(this); + depthH1 = rg->getLayerDepth( _horizontal1->getLayer() ); + cdebug_log(145,0) << "Update h1: " << _horizontal1 << endl; + } else /*if (_vertical1->isInvalidatedLayer())*/ { + //_vertical1 = static_cast( _vertical1->makeDogleg(this) ); + _vertical1->makeDogleg(this); + depthV1 = rg->getLayerDepth( _vertical1->getLayer() ); + cdebug_log(145,0) << "Update v1: " << _vertical1 << endl; + } + delta = abssub ( depthH1, depthV1 ); + } + + setLayer ( (delta == 0) ? rg->getRoutingLayer(depthContact) : rg->getContactLayer(depthContact) ); + } + + _horizontal1->invalidate( this ); + _vertical1 ->invalidate( this ); + } + + cdebug_tabw(145,-1); + DebugSession::close (); + } + + + string AutoContactTurn::_getTypeName () const + { return "ContactTurn"; } + + +} // Anabatic namespace. diff --git a/anabatic/src/AutoContactVTee.cpp b/anabatic/src/AutoContactVTee.cpp new file mode 100644 index 00000000..28764a13 --- /dev/null +++ b/anabatic/src/AutoContactVTee.cpp @@ -0,0 +1,309 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2012-2016, 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 : "./AutoContactVTee.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/Vertical.h" +#include "hurricane/Horizontal.h" +#include "hurricane/DebugSession.h" +#include "crlcore/RoutingGauge.h" +#include "anabatic/AutoContactVTee.h" +#include "anabatic/AutoVertical.h" +#include "anabatic/AutoHorizontal.h" +#include "anabatic/Session.h" + + +namespace Anabatic { + + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::DebugSession; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoContactVTee". + + + AutoContactVTee* AutoContactVTee::create ( GCell* gcell, Net* net, const Layer* layer ) + { + DbU::Unit viaSide = Session::getViaWidth( layer ); + Contact* contact = Contact::create( net + , layer + , gcell->getCenter().getX() + , gcell->getCenter().getY() + , viaSide + , viaSide + ); + AutoContactVTee* autoContact = new AutoContactVTee( gcell, contact ); + + autoContact->_postCreate(); + autoContact->unsetFlags( CntInCreationStage ); + + cdebug_log(145,0) << "create(net*) " << autoContact << endl; + return autoContact; + } + + + AutoContactVTee::AutoContactVTee ( GCell* gcell, Contact* contact ) + : AutoContact(gcell,contact) + , _horizontal1(NULL) + , _vertical1 (NULL) + , _vertical2 (NULL) + { + setFlags( CntVTee ); + } + + + AutoContactVTee::~AutoContactVTee () + { } + + + AutoSegment* AutoContactVTee::getOpposite ( const AutoSegment* from ) const + { + if (from == _vertical1) return _vertical2; + if (from == _vertical2) return _vertical1; + return NULL; + } + + + AutoSegment* AutoContactVTee::getPerpandicular ( const AutoSegment* ) const + { return NULL; } + + + AutoSegment* AutoContactVTee::getSegment ( unsigned int index ) const + { + switch ( index ) { + case 0: return _horizontal1; + case 2: return _vertical1; + case 3: return _vertical2; + } + return NULL; + } + + + void AutoContactVTee::_invalidate ( unsigned int ) + { + unsigned int flags = Flags::Propagate; + if (_vertical1 and _vertical2) { + if (_vertical1->isInvalidated() xor _vertical2->isInvalidated()) + flags = Flags::NoFlags; + } + + if (_vertical1 ) _vertical1 ->invalidate( flags ); + if (_vertical2 ) _vertical2 ->invalidate( flags ); + if (_horizontal1) _horizontal1->invalidate(); + } + + + void AutoContactVTee::cacheDetach ( AutoSegment* segment ) + { + if (segment == _horizontal1) _horizontal1 = NULL; + else if (segment == _vertical1) _vertical1 = NULL; + else if (segment == _vertical2) _vertical2 = NULL; + else return; + + setFlags( CntInvalidatedCache ); + } + + + void AutoContactVTee::cacheAttach ( AutoSegment* segment ) + { + if (segment->getDirection() == Flags::Vertical) { + if (not _vertical1) _vertical1 = static_cast(segment); + else if (not _vertical2) _vertical2 = static_cast(segment); + else { + cerr << Bug( "%s::cacheAttach() On %s,\n" + " v1 & v2 cache have not been cleared first, cancelling." + , _getTypeName().c_str(), getString(this).c_str() + ) << endl; + return; + } + } else if (segment->getDirection() == Flags::Horizontal) { + if (_horizontal1) { + cerr << Bug( "%s::cacheAttach() On %s,\n" + " h1 cache has not been cleared first, cancelling." + , _getTypeName().c_str(), getString(this).c_str() + ) << endl; + return; + } + _horizontal1 = static_cast(segment); + } + + if (_vertical1 and _vertical2 and _horizontal1) + unsetFlags( CntInvalidatedCache ); + } + + + void AutoContactVTee::updateCache () + { + DebugSession::open( getNet(), 140, 150 ); + + cdebug_log(145,1) << "AutoContactVTee::updateCache() " << this << endl; + + Component* anchor; + Horizontal** horizontals = new Horizontal* [3]; + Vertical** verticals = new Vertical* [3]; + + _getTopology ( base(), anchor, horizontals, verticals, 3 ); + + _horizontal1 = static_cast( Session::lookup(horizontals[0]) ); + _vertical1 = static_cast( Session::lookup(verticals [0]) ); + _vertical2 = static_cast( Session::lookup(verticals [1]) ); + + string message; + if (verticals [0] == NULL) message = "VTee has less than two vertical segments."; + else if (verticals [1] == NULL) message = "VTee has less than two vertical segments."; + else if (verticals [2] != NULL) message = "VTee has more than two vertical segments."; + else if (horizontals[0] == NULL) message = "VTee is missing mandatory horizontal segment."; + else if (horizontals[1] != NULL) message = "VTee has more than one horizontal segment."; + else if (_horizontal1 == NULL) message = "AutoSegment lookup failed on horizontal segment."; + else if (_vertical1 == NULL) message = "AutoSegment lookup failed on first vertical segment."; + else if (_vertical2 == NULL) message = "AutoSegment lookup failed on second vertical segment."; + else if ( (not _vertical1->isCreated() and not _vertical2->isCreated()) + and (_vertical1->getY() != _vertical2->getY()) ) + message = "VTee has misaligned vertical segments"; + if (not message.empty() ) { + showTopologyError( message ); + setFlags( CntBadTopology ); + } + unsetFlags( CntInvalidatedCache ); + + cdebug_log(145,0) << "h1:" << _horizontal1 << endl; + cdebug_log(145,0) << "v1:" << _vertical1 << endl; + cdebug_log(145,0) << "v2:" << _vertical2 << endl; + + delete [] horizontals; + delete [] verticals; + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + void AutoContactVTee::updateGeometry () + { + DebugSession::open( getNet(), 140, 150 ); + + cdebug_log(145,1) << "AutoContactVTee::updateGeometry() " << this << endl; + + if (isInvalidatedCache()) updateCache(); + if (isInvalidatedCache()) { + cerr << Error( "%s::updateGeometry() %s: Unable to restore cache." + , _getTypeName().c_str(), getString(this).c_str() ) << endl; + cdebug_tabw(145,-1); + return; + } + + base()->invalidate( false ); + unsetFlags( CntInvalidated ); + + if (not hasBadTopology()) { + setX( getVertical1 ()->getX() ); + setY( getHorizontal1()->getY() ); + } + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + void AutoContactVTee::updateTopology () + { + DebugSession::open ( getNet(), 140, 150 ); + + cdebug_log(145,1) << "AutoContactVTee::updateTopology() " << this << endl; + + if (isInvalidatedCache()) updateCache(); + if (isInvalidatedCache()) { + cerr << Error( "%s::updateGeometry() %s: Unable to restore cache." + , _getTypeName().c_str(), getString(this).c_str() ) << endl; + cdebug_tabw(145,-1); + return; + } + + if (not hasBadTopology()) { + RoutingGauge* rg = Session::getRoutingGauge(); + size_t depthV1 = rg->getLayerDepth( getVertical1 ()->getLayer() ); + size_t depthV2 = rg->getLayerDepth( getVertical2 ()->getLayer() ); + size_t depthH1 = rg->getLayerDepth( getHorizontal1()->getLayer() ); + size_t minDepth = std::min( depthH1, std::min(depthV1,depthV2) ); + size_t maxDepth = std::max( depthH1, std::max(depthV1,depthV2) ); + size_t delta = maxDepth - minDepth; + + cdebug_log(145,0) << "minDepth:" << minDepth << endl; + cdebug_log(145,0) << "maxDepth:" << maxDepth << endl; + cdebug_log(145,0) << "delta:" << delta << endl; + + unsetFlags( CntWeakTerminal ); + + if ( maxDepth - minDepth > 3 ) { + showTopologyError( "Sheared VTee, layer delta exceed 3." ); + setFlags( CntBadTopology ); + } else { + if (depthV1 == depthV2) { + cdebug_log(145,0) << "depthV1 == depthV2 (" << depthV1 << ")" << endl; + // Dogleg on the horizontal. + switch ( delta ) { + case 0: setLayer( rg->getRoutingLayer(minDepth) ); break; + case 1: setLayer( rg->getContactLayer(minDepth) ); break; + default: + cdebug_log(145,0) << "Restore connectivity: dogleg on h1." << endl; + setLayer( rg->getContactLayer( depthV1 + ((depthV1==minDepth)?0:-1) ) ); + _horizontal1 = static_cast( _horizontal1->makeDogleg(this) ); + break; + } + } else { + // Dogleg on the vertical with the greater gap (should be equal to +/-2). + int deltaV1 = (int)depthV1 - (int)depthH1; + int deltaV2 = (int)depthV2 - (int)depthH1; + + if (std::abs(deltaV1) > std::abs(deltaV2)) { + setLayer( rg->getContactLayer( depthV2 + ((depthV2( _vertical1->makeDogleg(this) ); + _vertical1->makeDogleg(this); + } else { + setLayer( rg->getContactLayer( depthV1 + ((depthV1( _vertical2->makeDogleg(this) ); + _vertical2->makeDogleg(this); + } + } + } + + _horizontal1->invalidate( this ); + _vertical1 ->invalidate( this ); + _vertical2 ->invalidate( this ); + } + + cdebug_tabw(145,-1); + DebugSession::close (); + } + + + string AutoContactVTee::_getTypeName () const + { return "ContactVTee"; } + + +} // Anabatic namespace. diff --git a/anabatic/src/AutoHorizontal.cpp b/anabatic/src/AutoHorizontal.cpp new file mode 100644 index 00000000..77e8fc2d --- /dev/null +++ b/anabatic/src/AutoHorizontal.cpp @@ -0,0 +1,819 @@ +// -*- 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 | +// | A n a b a t i c - Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./AutoHorizontal.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "hurricane/Bug.h" +#include "hurricane/Error.h" +#include "hurricane/DebugSession.h" +#include "hurricane/RoutingPad.h" +#include "crlcore/RoutingGauge.h" +#include "anabatic/Configuration.h" +#include "anabatic/AutoContactTerminal.h" +#include "anabatic/AutoContactTurn.h" +#include "anabatic/AutoHorizontal.h" +#include "anabatic/AutoVertical.h" + + +namespace Anabatic { + + + using std::min; + using std::max; + using Hurricane::Error; + using Hurricane::Bug; + using Hurricane::DebugSession; + using Hurricane::RoutingPad; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoHorizontal". + + + 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::getDuSource () const { return _horizontal->getDxSource(); } + DbU::Unit AutoHorizontal::getDuTarget () const { return _horizontal->getDxTarget(); } + Interval AutoHorizontal::getSpanU () const { return Interval(_horizontal->getSourceX(),_horizontal->getTargetX()); } + void AutoHorizontal::setDuSource ( DbU::Unit du ) { _horizontal->setDxSource(du); } + void AutoHorizontal::setDuTarget ( DbU::Unit du ) { _horizontal->setDxTarget(du); } + string AutoHorizontal::_getTypeName () const { return "AutoHorizontal"; } + + + AutoHorizontal::AutoHorizontal ( Horizontal* horizontal ) + : AutoSegment(horizontal) + , _horizontal(horizontal) + { + cdebug_log(145,0) << "CTOR AutoHorizontal " << this << endl; + cdebug_log(145,0) << " over " << horizontal << endl; + } + + + void AutoHorizontal::_postCreate () + { + AutoSegment::_postCreate (); + + AutoContact* source = getAutoSource(); + if (source->isTerminal()) source->setY( _horizontal->getY() ); + + AutoContact* target = getAutoTarget(); + if (target->isTerminal()) target->setY( _horizontal->getY() ); + + _gcell = source->getGCell(); + + setOptimalMax( getGCell()->getYMax() ); + resetNativeConstraints( getGCell()->getYMin(), getGCell()->getYMax() ); + + if (getGCell() != target->getGCell()) { + setFlags( SegGlobal ); + + vector gcells; + getGCells( gcells ); + for ( GCell* gcell : gcells ) { + if ( (gcell != getGCell()) and (gcell != target->getGCell()) ) + gcell->addHSegment( this ); + mergeNativeMin( gcell->getYMin() ); + mergeNativeMax( gcell->getYMax() ); + } + } + } + + + void AutoHorizontal::_preDestroy () + { + cdebug_log(149,0) << "AutoHorizontal::_preDestroy() - " << endl; + cdebug_log(149,0) << " " << _getString() << endl; + cdebug_tabw(145,1); + + if (not Session::doDestroyTool()) { + vector gcells; + getGCells( gcells ); + for ( GCell* gcell : gcells ) gcell->removeHSegment( this ); + } + + AutoSegment::_preDestroy (); + cdebug_tabw(145,-1); + } + + + AutoHorizontal::~AutoHorizontal () + { + if ( Session::doDestroyBaseSegment() and not Session::doDestroyTool() ) { + cdebug_log(149,0) << "~AutoHorizontal() - " << endl; + _horizontal->destroy (); + } + } + + + Interval AutoHorizontal::getSourceConstraints ( unsigned int flags ) const + { + if (flags & Flags::NativeConstraints) { + Box nativeBox ( getAutoSource()->getNativeConstraintBox() ); + return Interval ( nativeBox.getYMin(), nativeBox.getYMax() ); + } + return Interval ( getAutoSource()->getCBYMin(), getAutoSource()->getCBYMax() ); + } + + + Interval AutoHorizontal::getTargetConstraints ( unsigned int flags ) const + { + if (flags & Flags::NativeConstraints) { + Box nativeBox ( getAutoTarget()->getNativeConstraintBox() ); + return Interval ( nativeBox.getYMin(), nativeBox.getYMax() ); + } + return Interval ( getAutoTarget()->getCBYMin(), getAutoTarget()->getCBYMax() ); + } + + + bool AutoHorizontal::getConstraints ( DbU::Unit& constraintMin, DbU::Unit& constraintMax ) const + { + constraintMin = getNativeMin(); + constraintMax = getNativeMax(); + + cdebug_log(149,0) << "Native constraints: [" + << DbU::getValueString(constraintMin) << ":" + << DbU::getValueString(constraintMax) << "]" + << endl; + + constraintMin = max ( constraintMin, getUserConstraints().getVMin() ); + constraintMax = min ( constraintMax, getUserConstraints().getVMax() ); + + cdebug_log(149,0) << "Merge with user constraints: " << getUserConstraints() << " [" + << DbU::getValueString(getUserConstraints().getVMin()) << ":" + << DbU::getValueString(getUserConstraints().getVMax()) << "]" + << endl; + + cdebug_log(149,0) << "Resulting constraints: " << " [" + << DbU::getValueString(constraintMin) << ":" + << DbU::getValueString(constraintMax) << "]" + << endl; + + return true; + } + + + unsigned int AutoHorizontal::getDirection () const + { return Flags::Horizontal; } + + + size_t AutoHorizontal::getGCells ( vector& gcells ) const + { + vector().swap( gcells ); + + DbU::Unit yprobe = getNativeMin(); + GCell* gcell = getAutoSource()->getGCell(); + GCell* end = getAutoTarget()->getGCell(); + + if (gcell->getXMin() > end->getXMin()) std::swap( gcell, end ); + + gcells.push_back( gcell ); + + while ( gcell != end ) { + gcell = gcell->getEast( yprobe ); + + if (not gcell) { + cerr << Error( "AutoHorizontal::getGCells() : NULL GCell under %s\n" + " begin:%s\n" + " end: %s" + , getString(this).c_str() + , getString(getAutoSource()->getGCell()).c_str() + , getString(getAutoTarget()->getGCell()).c_str() + ) << endl; + break; + } + + gcells.push_back( gcell ); + } + + return gcells.size(); + } + + + bool AutoHorizontal::_canSlacken () const + { + cdebug_tabw(149,1); + + Interval sourceSide = getAutoSource()->getGCell()->getSide( Flags::Vertical ); + Interval targetSide = getAutoTarget()->getGCell()->getSide( Flags::Vertical ); + Interval sourceConstraints = Interval(getAutoSource()->getCBYMin(),getAutoSource()->getCBYMax()); + Interval targetConstraints = Interval(getAutoTarget()->getCBYMin(),getAutoTarget()->getCBYMax()); + + // Expand by a tiny amount for the "contains" to work for sure. + sourceConstraints.inflate( 1 ); + targetConstraints.inflate( 1 ); + + cdebug_log(149,0) << "source " << getAutoSource() << endl; + cdebug_log(149,0) << "source constraints: " << sourceConstraints + << " " << DbU::getValueString(sourceConstraints.getSize()) << endl; + cdebug_log(149,0) << "target " << getAutoTarget() << endl; + cdebug_log(149,0) << "target constraints: " << targetConstraints + << " " << DbU::getValueString(targetConstraints.getSize()) << endl; + + if (not sourceConstraints.contains(sourceSide)) { cdebug_tabw(149,-1); return true; } + if (not targetConstraints.contains(targetSide)) { cdebug_tabw(149,-1); return true; } + + cdebug_tabw(149,-1); + return false; + } + + + bool AutoHorizontal::_slacken ( unsigned int flags ) + { + cdebug_log(149,0) << "AutoHorizontal::_slacken() " << this << endl; + + if (not isStrongTerminal()) return false; + + const Configuration* configuration = Session::getConfiguration(); + const Layer* metal2 = configuration->getRoutingLayer( 1 ); + + bool success = false; + bool isMetal2Source = false; + bool isMetal2Target = false; + DbU::Unit height = 0; + AutoContact* source = getAutoSource(); + AutoContact* target = getAutoTarget(); + if (source->isTerminal()) { + height = (static_cast(source->getAnchor()))->getBoundingBox().getHeight(); + isMetal2Source = (source->getLayer() == metal2); + } + if (target->isTerminal()) { + height = std::min( height, (static_cast(target->getAnchor()))->getBoundingBox().getHeight() ); + isMetal2Target = (target->getLayer() == metal2); + } + + if (height >= 4*getPitch()) { + if (not (_flags & (SegGlobal|SegWeakGlobal)) and (getLength() < 5*getPitch())) + return false; + } + + 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; + + int lowSlack = (flags & Flags::HalfSlacken) ? 3 : 10; + bool slackened = false; + bool halfSlackened = false; + DbU::Unit targetPosition = getTargetPosition(); + AutoSegment* parallel = this; + + if (source->isTerminal()) { + Interval perpandConstraints = getAutoTarget()->getUConstraints(Flags::Horizontal); + Interval constraints = source->getUConstraints (Flags::Vertical|Flags::NoGCellShrink); + Interval nativeConstraints = source->getNativeUConstraints(Flags::Vertical|Flags::NoGCellShrink); + int slack = constraints.getSize() / getPitch(); + int nativeSlack = nativeConstraints.getSize() / getPitch(); + + cdebug_log(149,0) << "Source constraint: " << constraints + << " slack:" << slack + << " native slack:" << nativeSlack << endl; + cdebug_log(149,0) << "Perpand constraints on target: " << perpandConstraints << endl; + // Ugly: GCell's track number is hardwired. + if ((nativeSlack < lowSlack) or (nativeSlack - slack < 3)) { + cdebug_log(149,0) << "Slackening from Source: " << source << endl; + _makeDogleg( source->getGCell(), Flags::NoFlags ); + slackened = true; + } else if (slack < 10) { + halfSlackened = true; + } + + const vector& doglegs = Session::getDoglegs(); + if (doglegs.size() >= 2) { + cdebug_log(149,0) << "AutoSegment::_slaken(): Source @" << DbU::getValueString(getSourcePosition()) << endl; + doglegs[doglegs.size()-2]->setAxis( getSourcePosition() ); + success = true; + + if (isMetal2Source) { + cdebug_log(149,0) << "Fixing on source terminal contact." + << doglegs[doglegs.size()-2]->getAutoSource() << endl; + //doglegs[doglegs.size()-2]->getAutoSource()->setFlags( CntFixed ); + doglegs[doglegs.size()-2]->getAutoSource()->setConstraintBox( source->getConstraintBox() ); + doglegs[doglegs.size()-2]->getAutoSource()->setFlags( CntUserNativeConstraints ); + } + + parallel = doglegs[ doglegs.size()-1 ]; + } + } + + if (parallel) target = parallel->getAutoTarget(); + + if (target->isTerminal()) { + Interval constraints = target->getUConstraints (Flags::Vertical|Flags::NoGCellShrink); + Interval nativeConstraints = target->getNativeUConstraints(Flags::Vertical|Flags::NoGCellShrink); + int slack = constraints.getSize() / getPitch(); + int nativeSlack = nativeConstraints.getSize() / getPitch(); + + // Ugly: GCell's track number is hardwired. + cdebug_log(149,0) << "Target constraint: " << constraints + << " slack:" << slack + << " native slack:" << nativeSlack << endl; + if ((nativeSlack < lowSlack) or (nativeSlack - slack < 3)) { + cdebug_log(149,0) << "Slackening from Target: " << target << endl; + parallel->_makeDogleg( target->getGCell(), Flags::NoFlags ); + slackened = true; + } else if (slack < 10) { + halfSlackened = true; + } + + if (halfSlackened) { + setFlags( SegHalfSlackened ); + } else if (slackened) { + setFlags ( SegSlackened ); + unsetFlags( SegHalfSlackened ); + } + + const vector& doglegs = Session::getDoglegs(); + if (doglegs.size() >= 2) { + cdebug_log(149,0) << "AutoSegment::_slaken(): Target @" << DbU::getValueString(targetPosition) << endl; + doglegs[doglegs.size()-2]->setAxis( targetPosition ); + success = true; + + if (isMetal2Target) { + cdebug_log(149,0) << "Fixing on target terminal contact: " + << doglegs[doglegs.size()-2]->getAutoTarget() << endl; + //doglegs[doglegs.size()-2]->getAutoTarget()->setFlags( CntFixed ); + doglegs[doglegs.size()-2]->getAutoTarget()->setConstraintBox( target->getConstraintBox() ); + doglegs[doglegs.size()-2]->getAutoTarget()->setFlags( CntUserNativeConstraints ); + } + } + } + cdebug_tabw(149,-1); + + return success; + } + + + void AutoHorizontal::_setAxis ( DbU::Unit axis ) + { + setFlags( SegAxisSet ); + + if ((axis != getAxis()) and isFixed()) { + cerr << Error( "AutoHorizontal::setAxis(): Cannot move fixed segment to %s.\n" + " (on: %s)" + , DbU::getValueString(axis).c_str() + , _getString().c_str() + ) << endl; + } + + if (_horizontal->getY() == axis) return; + + cdebug_log(145,0) << "_setAxis() @Y " << DbU::toLambda(axis) << " " << this << endl; + + _horizontal->setY( axis ); + invalidate(); + + AutoContact* anchor = getAutoSource(); + anchor->invalidate(); + if (anchor->isTerminal()) anchor->setY( axis ); + + anchor = getAutoTarget(); + anchor->invalidate(); + if (anchor->isTerminal()) anchor->setY( axis ); + } + + + void AutoHorizontal::updateOrient () + { + if (_horizontal->getTargetX() < _horizontal->getSourceX()) { + cdebug_log(145,0) << "updateOrient() " << this << " (before S/T swap)" << endl; + _horizontal->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 AutoHorizontal::updatePositions () + { + _sourcePosition = _horizontal->getSourceX() - Session::getExtensionCap(getLayer()); + _targetPosition = _horizontal->getTargetX() + Session::getExtensionCap(getLayer()); + } + + + void AutoHorizontal::updateNativeConstraints () + { + vector gcells; + getGCells( gcells ); + + resetNativeConstraints( gcells[0]->getYMin(), gcells[0]->getYMax() ); + for ( GCell* gcell : gcells ) { + mergeNativeMin( gcell->getYMin() ); + mergeNativeMax( gcell->getYMax() ); + } + } + + + bool AutoHorizontal::checkPositions () const + { + bool coherency = true; + DbU::Unit sourcePosition = _horizontal->getSourceX() - Session::getExtensionCap(getLayer()); + DbU::Unit targetPosition = _horizontal->getTargetX() + 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 AutoHorizontal::checkConstraints () const + { + Interval sourceConstraints = Interval(getAutoSource()->getCBYMin(),getAutoSource()->getCBYMax()); + Interval targetConstraints = Interval(getAutoTarget()->getCBYMin(),getAutoTarget()->getCBYMax()); + + 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 AutoHorizontal::canMoveULeft ( float reserve ) const + { +#if THIS_IS_DISABLED + //cerr << "canMoveULeft() " << this << endl; + + if (not isGlobal()) return false; + if (not getAutoSource()->isTurn() or not getAutoTarget()->isTurn()) return false; + if (not getAutoSource()->getGCell()->getDown()) 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; + + //cerr << "| begin:" << begin << endl; + //cerr << "| end: " << end << endl; + for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getRight() ) { + //cerr << "| gcell:" << gcell << endl; + if (currMaxDensity < gcell->getWDensity(depth)) currMaxDensity = gcell->getWDensity( depth ); + } + + begin = begin->getDown(); + end = end ->getDown(); + + for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getRight() ) { + if (leftMaxDensity < gcell->getWDensity(depth)) leftMaxDensity = gcell->getWDensity( depth ); + } + + return (leftMaxDensity + reserve < currMaxDensity); +#endif + + return false; + } + + + bool AutoHorizontal::canMoveURight ( float reserve ) const + { +#if THIS_IS_DISABLED + //cerr << "canMoveURight() " << this << endl; + + if (not isGlobal()) return false; + if (not getAutoSource()->isTurn() or not getAutoTarget()->isTurn()) return false; + if (not getAutoSource()->getGCell()->getUp()) 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; + + //cerr << "| begin:" << begin << endl; + //cerr << "| end: " << end << endl; + + for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getRight() ) { + //cerr << "| gcell: " << gcell << endl; + if (currMaxDensity < gcell->getWDensity(depth)) currMaxDensity = gcell->getWDensity( depth ); + } + + begin = begin->getUp(); + end = end ->getUp(); + + for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getRight() ) { + if (leftMaxDensity < gcell->getWDensity(depth)) leftMaxDensity = gcell->getWDensity( depth ); + } + + return (leftMaxDensity + reserve < currMaxDensity); +#endif + + return false; + } + + + bool AutoHorizontal::moveULeft () + { +#if THIS_IS_DISABLED + if (not getAutoSource()->isTurn() or not getAutoTarget()->isTurn()) return false; + if (not getAutoSource()->getGCell()->getDown()) return false; + + AutoContact* autoSource = getAutoSource(); + AutoContact* autoTarget = getAutoTarget(); + GCell* begin = autoSource->getGCell(); + GCell* end = autoTarget->getGCell(); + AutoSegment* perpandicular = autoSource->getSegment(2); + + if (perpandicular->isLocal()) { + perpandicular->setFlags( Anabatic::SegGlobal ); + } else { + if (perpandicular->getAutoSource() == autoSource) { + begin->addVSegment( perpandicular ); + } else { + if (begin->getDown() == perpandicular->getAutoSource()->getGCell()) { + perpandicular->unsetFlags( Anabatic::SegGlobal ); + } else + begin->getDown()->removeVSegment( perpandicular ); + } + } + + perpandicular = autoTarget->getSegment(2); + if (perpandicular->isLocal()) { + perpandicular->setFlags( Anabatic::SegGlobal ); + } else { + if (perpandicular->getAutoSource() == autoTarget) { + end->addVSegment( perpandicular ); + } else { + if (end->getDown() == perpandicular->getAutoSource()->getGCell()) { + perpandicular->unsetFlags( Anabatic::SegGlobal ); + } else + end->getDown()->removeVSegment( perpandicular ); + } + } + + if (begin != end) { + for ( GCell* gcell=begin->getRight() ; gcell and gcell!=end ; gcell=gcell->getRight() ) + gcell->removeHSegment( this ); + } + + begin = begin->getDown(); + end = end ->getDown(); + + autoSource->setGCell( begin ); + autoTarget->setGCell( end ); + if (begin != end) { + for ( GCell* gcell=begin->getRight() ; gcell and gcell!=end ; gcell=gcell->getRight() ) + gcell->addHSegment( this ); + } + + DbU::Unit y = begin->getSide(Flags::Vertical).getVMax(); + setAxis( y ); + + return true; +#endif + return false; + } + + + bool AutoHorizontal::moveURight () + { +#if THIS_IS_DISABLED + //cerr << "moveURight() " << this << endl; + + if (not getAutoSource()->isTurn() or not getAutoTarget()->isTurn()) return false; + if (not getAutoSource()->getGCell()->getUp()) return false; + + AutoContact* autoSource = getAutoSource(); + AutoContact* autoTarget = getAutoTarget(); + GCell* begin = autoSource->getGCell(); + GCell* end = autoTarget->getGCell(); + AutoSegment* perpandicular = autoSource->getSegment(2); + + if (perpandicular->isLocal()) { + perpandicular->setFlags( Anabatic::SegGlobal ); + } else { + if (perpandicular->getAutoTarget() == autoSource) { + begin->addVSegment( perpandicular ); + } else { + if (begin->getUp() == perpandicular->getAutoTarget()->getGCell()) { + perpandicular->unsetFlags( Anabatic::SegGlobal ); + } else + begin->getUp()->removeVSegment( perpandicular ); + } + } + + perpandicular = autoTarget->getSegment(2); + if (perpandicular->isLocal()) { + perpandicular->setFlags( Anabatic::SegGlobal ); + } else { + if (perpandicular->getAutoTarget() == autoTarget) { + end->addVSegment( perpandicular ); + } else { + if (end->getUp() == perpandicular->getAutoTarget()->getGCell()) { + perpandicular->unsetFlags( Anabatic::SegGlobal ); + } else + end->getUp()->removeVSegment( perpandicular ); + } + } + + //cerr << "| begin:" << begin << endl; + //cerr << "| end: " << end << endl; + + //cerr << "* remove" << endl; + if (begin != end) { + for ( GCell* gcell=begin->getRight() ; gcell and gcell!=end ; gcell=gcell->getRight() ) { + //cerr << "| gcell: " << end << endl; + gcell->removeHSegment( this ); + } + } + + begin = begin->getUp(); + end = end ->getUp(); + + autoSource->setGCell( begin ); + autoTarget->setGCell( end ); + //cerr << "* add" << endl; + if (begin != end) { + for ( GCell* gcell=begin->getRight() ; gcell and gcell!=end ; gcell=gcell->getRight() ) { + //cerr << "| gcell: " << end << endl; + gcell->addHSegment( this ); + } + } + + DbU::Unit y = begin->getSide( Flags::Vertical ).getVMin(); + setAxis( y ); + + return true; +#endif + return false; + } + + + unsigned int AutoHorizontal::_makeDogleg ( GCell* doglegGCell, unsigned int flags ) + { + DebugSession::open( getNet(), 140, 150 ); + cdebug_log(149,0) << "AutoHorizontal::_makeDogleg(GCell*)" << endl; + cdebug_tabw(149,1); + + //Session::doglegReset(); + + AutoContact* autoTarget = getAutoTarget(); + AutoContact* autoSource = getAutoSource(); + GCell* begin = autoSource->getGCell(); + GCell* end = autoTarget->getGCell(); + + DbU::Unit doglegAxis = (doglegGCell->getXMax() + doglegGCell->getXMin()) / 2; + if (isLocal()) + doglegAxis = (getSourceX() + getTargetX()) / 2; + + cdebug_log(149,0) << "Detaching from Target AutoContact " << autoTarget << "." << endl; + + if (doglegGCell == begin) unsetFlags( SegGlobal ); + if (doglegGCell != end) { + GCell* gcell = doglegGCell; + do { + if (gcell != begin) + gcell->removeHSegment( this ); + gcell = gcell->getEast( getNativeMin() ); + } while ( gcell and (gcell != end) ); + } + + size_t depth = Session::getRoutingGauge()->getLayerDepth( _horizontal->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( Flags::Topology ); + autoTarget->invalidate( Flags::Topology ); + AutoContact* dlContact1 = AutoContactTurn::create( doglegGCell, _horizontal->getNet(), contactLayer ); + AutoContact* dlContact2 = AutoContactTurn::create( doglegGCell, _horizontal->getNet(), contactLayer ); + AutoSegment* segment1 = AutoSegment::create( dlContact1 , dlContact2, Flags::Vertical ); + segment1->setLayer( doglegLayer ); + segment1->_setAxis( doglegAxis ); + segment1->setFlags( SegDogleg|SegSlackened|SegCanonical|SegNotAligned ); + + cdebug_log(149,0) << "New " << dlContact1 << endl; + cdebug_log(149,0) << "New " << dlContact2 << endl; + Session::dogleg( segment1 ); + + targetAttach( dlContact1 ); + AutoSegment* segment2 = AutoSegment::create( dlContact2 , autoTarget, Flags::Horizontal ); + autoTarget->cacheAttach( segment2 ); + segment2->setLayer( getLayer() ); + segment2->_setAxis( getY() ); + segment2->setFlags( (isSlackened()?SegSlackened:0) ); + Session::dogleg( segment2 ); + + if (autoSource->isTerminal()) { + segment1->setFlags( SegWeakTerminal1 ); + segment2->setFlags( SegWeakTerminal1 ); + autoTarget->unsetFlags( CntWeakTerminal ); + dlContact1->setFlags ( CntWeakTerminal ); + if (autoTarget->getGCell() == doglegGCell) + dlContact1->migrateConstraintBox( autoTarget ); + } else if (autoTarget->isTerminal()) { + 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 ); + } + + cdebug_log(149,0) << "Session::dogleg[x+1] perpand: " << segment1 << endl; + cdebug_log(149,0) << "Session::dogleg[x+2] new paral: " << segment2 << endl; + cdebug_log(149,0) << "Session::dogleg[x+0] original: " << this << endl; + + dlContact1->updateCache(); + dlContact2->updateCache(); + //autoTarget->updateCache(); + + segment2->canonize( flags ); + if (not isCanonical()) canonize( flags ); + + updateNativeConstraints(); + segment2->updateNativeConstraints(); + + cdebug_tabw(149,-1); + DebugSession::close(); + + return (upLayer) ? Flags::AboveLayer : Flags::BelowLayer; + } + + + string AutoHorizontal::_getString () const + { + string s = AutoSegment::_getString(); + return s; + } + + + Record* AutoHorizontal::_getRecord () const + { + Record* record = AutoSegment::_getRecord (); + record->add ( getSlot ( "_horizontal", _horizontal ) ); + + return record; + } + + +} // End of Anabatic namespace. diff --git a/anabatic/src/AutoSegment.cpp b/anabatic/src/AutoSegment.cpp new file mode 100644 index 00000000..dd15abe9 --- /dev/null +++ b/anabatic/src/AutoSegment.cpp @@ -0,0 +1,2387 @@ +// -*- 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 | +// | A n a b a t i c - Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./AutoSegment.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/Warning.h" +#include "hurricane/Bug.h" +#include "hurricane/DataBase.h" +#include "hurricane/Technology.h" +#include "hurricane/Horizontal.h" +#include "hurricane/Vertical.h" +#include "crlcore/RoutingGauge.h" +#include "anabatic/Session.h" +#include "anabatic/AutoContact.h" +#include "anabatic/AutoSegment.h" +#include "anabatic/AutoHorizontal.h" +#include "anabatic/AutoVertical.h" +#include "anabatic/GCell.h" +#include "anabatic/AnabaticEngine.h" + + +namespace { + + + using namespace std; + using namespace CRL; + using namespace Hurricane; + using namespace Anabatic; + + + // --------------------------------------------------------------- + // Local Variables. + + + const char* badAutoSegmentAnchor = + "AutoSegment::create() :\n\n" + " Source and/or target anchor is NOT an (internal error).\n" + " Source: %s, Target: %s"; + + const char* dupAutoSegmentAnchor = + "AutoSegment::create() :\n\n" + " Source and Target anchor are the same : %s (internal error)."; + + const char* badSegment = + "Anabatic::AutoSegment::create () :\n\n" + " Segment between %s and %s\n" + " is neither horizontal nor vertical .\n"; + + const char* badSegmentSource = + "Anabatic::AutoSegment::create () :\n\n" + " Source anchor of segment %s is not a Contact\n" + " (%s)\n"; + + const char* badSegmentTarget = + "Anabatic::AutoSegment::create () :\n\n" + " Source anchor of segment %s is not a Contact\n" + " (%s)\n"; + + const char* mismatchSegmentSource = + "Anabatic::AutoSegment::create () :\n\n" + " Source anchor of segment %s is already an AutoContact\n" + " (%s)\n"; + + const char* mismatchSegmentTarget = + "Anabatic::AutoSegment::create () :\n\n" + " Target anchor of segment %s is already an AutoContact\n" + " (%s)\n"; + + + // --------------------------------------------------------------- + // Local Functions. + + + bool getTerminalInterval ( AutoSegment* autoSegment + , AutoContact* fromContact + , bool isHorizontal + , DbU::Unit& min + , DbU::Unit& max + ) + { + AutoContact* terminalContact = NULL; + + if ( !fromContact ) { + bool found = getTerminalInterval ( autoSegment + , autoSegment->getAutoSource() + , autoSegment->isHorizontal() + , min + , max ); + if ( !found ) + found = getTerminalInterval ( autoSegment + , autoSegment->getAutoTarget() + , autoSegment->isHorizontal() + , min + , max ); + + //if ( !found ) + // cerr << "[ERROR] Cannot find terminal of " << autoSegment << "." << endl; + + return found; + } else { + if ( autoSegment->isGlobal() ) return false; + + cdebug_log(145,0) << "Examining " << autoSegment << " " << fromContact << endl; + + if ( autoSegment->getSource() == autoSegment->getTarget() ) { + cerr << Error("Source & Target are the same :\n" + " %s\n %s" + ,getString(autoSegment).c_str() + ,getString(autoSegment->getSource()).c_str()) << endl; + } + + terminalContact = autoSegment->getAutoSource(); + if ( terminalContact == fromContact ) { + terminalContact = autoSegment->getAutoTarget(); + } + + if ( !terminalContact->isTerminal() ) { + AutoSegment* segment = NULL; + size_t segmentCount = 0; + forEach ( Component*, icomponent, terminalContact->getSlaveComponents() ) { + if ( *icomponent == autoSegment->base() ) continue; + + Segment* connex = dynamic_cast(*icomponent); + if ( !connex ) continue; + + segment = Session::lookup ( connex ); + if ( not segment or not segment->isWeakTerminal() ) continue; + + segmentCount++; + } + + if ( segmentCount == 1 ) { + return getTerminalInterval ( segment, terminalContact, isHorizontal, min, max ); + + return false; + } + } else { + cdebug_log(145,0) << "Terminal is " << terminalContact << endl; + + Box constraintBox = terminalContact->getConstraintBox(); + if ( isHorizontal ) { + min = constraintBox.getXMin (); + max = constraintBox.getXMax (); + } else { + min = constraintBox.getYMin (); + max = constraintBox.getYMax (); + } + return true; + } + } + + return false; + } + + + // --------------------------------------------------------------- + // Class : "AttractorsMap". + + + class AttractorsMap { + // Constructor. + public: + inline AttractorsMap (); + inline size_t getAttractorsCount () const; + DbU::Unit getLowerMedian () const; + DbU::Unit getUpperMedian () const; + void addAttractor ( DbU::Unit position ); + protected: + map _attractors; + size_t _attractorsCount; + }; + + + inline AttractorsMap::AttractorsMap () + : _attractors(), _attractorsCount(0) + { } + + + inline size_t AttractorsMap::getAttractorsCount () const + { + return _attractorsCount; + } + + + void AttractorsMap::addAttractor ( DbU::Unit position ) + { + _attractors[position]++; + _attractorsCount++; + + cdebug_log(145,0) << "add Attractor @" << DbU::toLambda(position) + << " [" << _attractors[position] << "]" << endl; + } + + + DbU::Unit AttractorsMap::getLowerMedian () const + { + size_t median = (_attractorsCount/2) + (_attractorsCount%2); + size_t lower = 0; + + map::const_iterator it = _attractors.begin (); + for ( ; it != _attractors.end() ; it++ ) { + lower += it->second; + if ( lower >= median ) break; + } + + return it->first; + } + + + DbU::Unit AttractorsMap::getUpperMedian () const + { + size_t median = _attractorsCount / 2; + size_t upper = 0; + + map::const_iterator it = _attractors.begin (); + for ( ; it != _attractors.end() ; it++ ) { + upper += it->second; + if ( upper > median ) break; + } + + return it->first; + } + + +} // End of local namespace. + + +namespace Anabatic { + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoSegment::CompareByDepthLength". + + + bool AutoSegment::CompareByDepthLength::operator() ( AutoSegment* lhs, AutoSegment* rhs ) const + { + int deltaDepth = (int)(Session::getRoutingGauge()->getLayerDepth(lhs->getLayer())) + - (int)(Session::getRoutingGauge()->getLayerDepth(rhs->getLayer())); + if ( deltaDepth < 0 ) return true; // Lowest layer first. + if ( deltaDepth > 0 ) return false; + + DbU::Unit deltaUnit = lhs->getSourceU() - rhs->getSourceU(); + if ( deltaUnit < 0 ) return true; // Smallest source first. + if ( deltaUnit > 0 ) return false; + + deltaUnit = lhs->getLength() - rhs->getLength(); + if ( deltaUnit > 0 ) return true; // Longest first. + if ( deltaUnit < 0 ) return true; + + deltaUnit = lhs->getAxis() - rhs->getAxis(); + if ( deltaUnit < 0 ) return true; // Smallest axis first. + if ( deltaUnit > 0 ) return false; + + // if ( lhs->isCanonical () xor rhs->isCanonical () ) return lhs->isCanonical(); + // if ( lhs->isCollapsed () xor rhs->isCollapsed () ) return rhs->isCollapsed(); + // if ( lhs->isSlackenStrap() xor rhs->isSlackenStrap() ) return lhs->isSlackenStrap(); + + // if ( lhs->isGlobal () xor rhs->isGlobal () ) return lhs->isGlobal(); + // if ( lhs->isTerminal () xor rhs->isTerminal () ) return rhs->isTerminal(); + // if ( lhs->isHorizontal() xor rhs->isHorizontal() ) return lhs->isHorizontal(); + + // if ( lhs->isFixed() xor rhs->isFixed() ) return lhs->isFixed(); + + return lhs->getId() < rhs->getId(); + } + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoSegment::CompareByDepthAxis". + + + bool AutoSegment::CompareByDepthAxis::operator() ( AutoSegment* lhs, AutoSegment* rhs ) const + { + int deltaDepth = (int)(Session::getRoutingGauge()->getLayerDepth(lhs->getLayer())) + - (int)(Session::getRoutingGauge()->getLayerDepth(rhs->getLayer())); + if ( deltaDepth < 0 ) return true; // Lowest layer first. + if ( deltaDepth > 0 ) return false; + + DbU::Unit deltaUnit = lhs->getAxis() - rhs->getAxis(); + if ( deltaUnit < 0 ) return true; // Smallest axis first. + if ( deltaUnit > 0 ) return false; + + deltaUnit = lhs->getSourceU() - rhs->getSourceU(); + if ( deltaUnit < 0 ) return true; // Smallest source first. + if ( deltaUnit > 0 ) return false; + + return lhs->getId() < rhs->getId(); // Smallest Id first. + } + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoSegment". + + + size_t AutoSegment::_allocateds = 0; + size_t AutoSegment::_globalsCount = 0; + unsigned long AutoSegment::_maxId = 0; + + + AutoSegment::AutoSegment ( Segment* segment ) + : _id (segment->getId()) + , _gcell (NULL) + , _flags (SegCreated) + , _depth (Session::getLayerDepth(segment->getLayer())) + , _optimalMin (0) + , _optimalMax (0) + , _reduceds (0) + , _sourcePosition (0) + , _targetPosition (0) + , _userConstraints (false) + , _nativeConstraints(false) + , _parent (NULL) + , _observers () + { + AutoContact* source = Session::lookup(dynamic_cast(segment->getSource())); + AutoContact* target = Session::lookup(dynamic_cast(segment->getTarget())); + + _allocateds++; + + if (dynamic_cast(segment)) setFlags( SegHorizontal ); + if (source->isTerminal()) setFlags( SegSourceTerminal ); + if (target->isTerminal()) setFlags( SegTargetTerminal ); + + _globalsCount += isGlobal() ? 1 : 0; + + source->invalidate( Flags::Topology ); + } + + + void AutoSegment::_preCreate ( AutoContact* source, AutoContact* target ) + { + if ( (source == NULL) or (target == NULL) ) + throw Error( badAutoSegmentAnchor + , ((source)?getString(source).c_str():"NULL") + , ((target)?getString(target).c_str():"NULL") + ); + + if (source == target) + throw Error( dupAutoSegmentAnchor, getString(source).c_str() ); + } + + + void AutoSegment::_postCreate () + { + Session::invalidate( getNet() ); + Session::link( this ); + updateOrient(); + updatePositions(); + invalidate( Flags::Topology ); + + _observers.notify( Create ); + } + + + void AutoSegment::_preDestroy () + { + cdebug_log(149,0) << "AutoSegment::_preDestroy() - " << (void*)this << endl; + cdebug_tabw(145,1); + + _observers.notify( Destroy ); + + Session::unlink( this ); + cdebug_tabw(145,-1); + } + + + AutoSegment::~AutoSegment () + { + _allocateds--; + if ( isGlobal() and (_globalsCount > 0) ) _globalsCount--; + } + + + DbU::Unit AutoSegment::getX () const + { return base()->getX(); } + + + DbU::Unit AutoSegment::getY () const + { return base()->getY(); } + + + AutoContact* AutoSegment::getOppositeAnchor ( AutoContact* anchor ) const + { return Session::lookup(static_cast(getOppositeAnchor(anchor->base()))); } + + + Interval& AutoSegment::getOptimal ( Interval& i ) const + { + i.getVMin() = getOptimalMin(); + i.getVMax() = getOptimalMax(); + return i; + } + + + bool AutoSegment::checkNotInvalidated () const + { + if (isInvalidated()) + cerr << Error("%s is invalidated.",getString(this).c_str()) << endl; + + return not isInvalidated(); + } + + + void AutoSegment::invalidate ( unsigned int flags ) + { + if (Session::doDestroyTool()) return; + if (flags & Flags::Source) setFlags( SegInvalidatedSource ); + if (flags & Flags::Target) setFlags( SegInvalidatedTarget ); + if (isInvalidated()) return; + + cdebug_log(149,0) << "AutoSegment::invalidate() " << flags << " " << this << endl; + cdebug_tabw(149,1); + + _invalidate(); + + if ((flags & Flags::Propagate) and not isNotAligned()) { + forEach( AutoSegment*, isegment, getAligneds() ) { + isegment->_invalidate(); + } + } + cdebug_tabw(149,-1); + } + + + void AutoSegment::_invalidate () + { + if (isInvalidated()) return; + cdebug_log(145,0) << "AutoSegment::_invalidate() " << this << endl; + + setFlags( SegInvalidated ); + Session::invalidate( this ); + + _observers.notify( Invalidate ); + } + + + void AutoSegment::invalidate ( AutoContact* contact ) + { + if (Session::doDestroyTool()) return; + if (contact == getAutoSource()) setFlags( SegInvalidatedSource ); + if (contact == getAutoTarget()) setFlags( SegInvalidatedTarget ); + } + + + void AutoSegment::revalidate () + { + cdebug_log(149,0) << "AutoSegment::revalidate() " << this << endl; + if (not isInvalidated()) return; + + cdebug_tabw(149,1); + + updateOrient (); + updatePositions(); + + unsigned int oldSpinFlags = _flags & SegDepthSpin; + + if (_flags & (SegInvalidatedSource|SegCreated)) { + AutoContact* source = getAutoSource(); + const Layer* contactLayer = source->getLayer(); + const Layer* segmentLayer = getLayer(); + cdebug_log(149,0) << "Changed source: " << source << endl; + + unsetFlags( SegSourceTop|SegSourceBottom ); + if (contactLayer != segmentLayer) + setFlags( (segmentLayer == contactLayer->getTop()) ? SegSourceBottom : SegSourceTop ); + if (source->isTurn() and source->getPerpandicular(this)->isReduced()) + incReduceds(); + } + + if (_flags & (SegInvalidatedTarget|SegCreated)) { + AutoContact* target = getAutoTarget(); + const Layer* contactLayer = target->getLayer(); + const Layer* segmentLayer = getLayer(); + cdebug_log(149,0) << "Changed target: " << target << endl; + + unsetFlags( SegTargetTop|SegTargetBottom ); + if (contactLayer != segmentLayer) + setFlags( (segmentLayer == contactLayer->getTop()) ? SegTargetBottom : SegTargetTop ); + if (target->isTurn() and target->getPerpandicular(this)->isReduced()) + incReduceds(); + } + + unsigned int observerFlags = Revalidate; + if ( (_flags & SegCreated) or (oldSpinFlags != (_flags & SegDepthSpin)) ) + observerFlags |= RevalidatePPitch; + + unsetFlags( SegInvalidated + | SegInvalidatedSource + | SegInvalidatedTarget + | SegInvalidatedLayer + | SegCreated + ); + + _observers.notify( observerFlags ); + + cdebug_log(149,0) << "Updated: " << this << endl; + cdebug_tabw(149,-1); + } + + + bool AutoSegment::isStrongTerminal ( unsigned int flags ) const + { + if (_flags & SegStrongTerminal) return true; + + if ((flags & Flags::Propagate) and not isNotAligned()) { + forEach( AutoSegment*, isegment, const_cast(this)->getAligneds() ) { + if (isegment->_flags & SegStrongTerminal) return true; + } + } + return false; + } + + + DbU::Unit AutoSegment::getPPitch () const + { + unsigned int depth = getDepth(); + DbU::Unit topPPitch = Session::getPitch( depth + ( ((_flags & SegSpinTop) and (depth+1 < Session::getDepth())) ? 1 : 0) ); + DbU::Unit bottomPPitch = Session::getPitch( depth - ( ((_flags & SegSpinBottom) and (depth > 0))? 1 : 0) ); + + return std::max( topPPitch, bottomPPitch ); + } + + + DbU::Unit AutoSegment::getSlack () const + { + DbU::Unit constraintMin; + DbU::Unit constraintMax; + + getConstraints( constraintMin, constraintMax ); + + return constraintMax - constraintMin; + } + + + DbU::Unit AutoSegment::getCost ( DbU::Unit axis ) const + { + DbU::Unit optimal = getOptimalMin(); + if (axis < optimal) return optimal - axis; + + optimal = getOptimalMax(); + if (axis > optimal) return axis - optimal; + + return 0; + } + + + AutoSegment* AutoSegment::getCanonical ( DbU::Unit& min, DbU::Unit& max ) + { + cdebug_log(145,0) << "AutoSegment::getCanonical() - " << this << endl; + + min = getSourcePosition (); + max = getTargetPosition (); + + if (max < min) swap( min, max ); + + //cdebug_log(145,0) << "[" << DbU::getValueString(min) << " " << DbU::getValueString(max) << "]" << endl; + + AutoSegment* canonical = this; + size_t canonicals = isCanonical(); + size_t aligneds = 1; + DbU::Unit collapsedMin; + DbU::Unit collapsedMax; + + if (not isNotAligned()) { + forEach( AutoSegment*, isegment, getAligneds() ) { + if (isegment->isCanonical()) { + canonical = *isegment; + canonicals++; + } + + collapsedMin = isegment->getSourcePosition(); + collapsedMax = isegment->getTargetPosition(); + if (collapsedMax < collapsedMin) swap( collapsedMin, collapsedMax ); + if (collapsedMin < min) min = collapsedMin; + if (collapsedMax > max) max = collapsedMax; + + aligneds++; + } + //cdebug_log(145,0) << "[" << DbU::getValueString(min) << " " << DbU::getValueString(max) << "]" << endl; + cdebug_log(145,0) << "Canonical: " << canonical << endl; + + if ( (canonicals > 1) or ( not canonicals and (aligneds > 2) ) ) { + cerr << Bug("AutoSegment::getCanonical(): %p:%s" + "\n Bad canonization: %d canonicals out of %d collapseds." + , base(), _getString().c_str(), canonicals, aligneds ) << endl; + + int count = 0; + cerr << " " << count++ << ": " << this << endl; + forEach( AutoSegment*, isegment, getAligneds() ) + cerr << " " << count++ << ": " << *isegment << endl; + } + } + + return canonical; + } + + + AutoSegments AutoSegment::getOnSourceContact ( unsigned int direction ) + { + return AutoSegments_OnContact + ( this, getSource() ).getSubSet( AutoSegments_InDirection(direction) ); + } + + + AutoSegments AutoSegment::getOnTargetContact ( unsigned int direction ) + { + return AutoSegments_OnContact + ( this, getTarget() ).getSubSet( AutoSegments_InDirection(direction) ); + } + + + AutoSegments AutoSegment::getCachedOnSourceContact ( unsigned int direction ) + { return AutoSegments_CachedOnContact( getAutoSource(), direction ); } + + + AutoSegments AutoSegment::getCachedOnTargetContact ( unsigned int direction ) + { return AutoSegments_CachedOnContact( getAutoTarget(), direction ); } + + + AutoSegments AutoSegment::getAligneds ( unsigned int flags ) + { + cdebug_log(145,0) << "AutoSegment::getAligneds() - flags:" << flags << endl; + return AutoSegments_Aligneds( this, flags ); + } + + + AutoSegments AutoSegment::getPerpandiculars () + { return AutoSegments_Perpandiculars( this ); } + + + bool AutoSegment::checkDepthSpin () const + { + bool valid = true; + const Layer* sourceLayer = getAutoSource()->getLayer(); + const Layer* targetLayer = getAutoTarget()->getLayer(); + + if ( (_flags & SegSourceTop) and (sourceLayer->getBottom() != getLayer()) ) { + cerr << Error("%s\n" + " Source is not going above, connected to *top* of %s." + , getString(this).c_str() + , getString(getAutoSource()).c_str() + ) << endl; + valid = false; + } + if ( (_flags & SegSourceBottom) and (sourceLayer->getTop() != getLayer()) ) { + cerr << Error("%s\n" + " Source is not going below, connected to *bottom* of %s." + , getString(this).c_str() + , getString(getAutoSource()).c_str() + ) << endl; + valid = false; + } + if ( (_flags & SegTargetTop) and (targetLayer->getBottom() != getLayer()) ) { + cerr << Error("%s\n" + " Target is not going above connected to *top* of %s." + , getString(this).c_str() + , getString(getAutoTarget()).c_str() + ) << endl; + valid = false; + } + if ( (_flags & SegTargetBottom) and (targetLayer->getTop() != getLayer()) ) { + cerr << Error("%s\n" + " Target is not going below, connected to *bottom* of %s." + , getString(this).c_str() + , getString(getAutoTarget()).c_str() + ) << endl; + valid = false; + } + + return valid; + } + + + void AutoSegment::setFlagsOnAligneds ( unsigned int flags ) + { + setFlags( flags ); + if (not isNotAligned()) { + forEach( AutoSegment*, isegment, getAligneds() ) + isegment->setFlags( flags ); + } + } + + + void AutoSegment::sourceDetach () + { + AutoContact* source = getAutoSource(); + if (source) { + if (source->isTurn()) { + AutoSegment* perpandicular = source->getPerpandicular(this); + if (perpandicular and perpandicular->isReduced()) + decReduceds(); + } + base()->getSourceHook()->detach(); + source->cacheDetach( this ); + unsetFlags( SegNotSourceAligned ); + setFlags( SegInvalidatedSource ); + } + } + + + void AutoSegment::targetDetach () + { + AutoContact* target = getAutoTarget(); + if (target) { + if (target->isTurn()) { + AutoSegment* perpandicular = target->getPerpandicular(this); + if (perpandicular and perpandicular->isReduced()) + decReduceds(); + } + base()->getTargetHook()->detach(); + target->cacheDetach( this ); + unsetFlags( SegNotTargetAligned ); + setFlags( SegInvalidatedTarget ); + } + } + + + void AutoSegment::sourceAttach ( AutoContact* source ) + { + if (source) { + if (not base()->getSourceHook()->isAttached()) + base()->getSourceHook()->attach( source->base()->getBodyHook() ); + source->cacheAttach( this ); + + // if (source->isHTee() and isHorizontal()) return; + // else if (source->isVTee() and isVertical ()) return; + // setFlags( SegNotSourceAligned ); + } + } + + + void AutoSegment::targetAttach ( AutoContact* target ) + { + if (target) { + if (not base()->getTargetHook()->isAttached()) + base()->getTargetHook()->attach( target->base()->getBodyHook() ); + target->cacheAttach( this ); + + // if (target->isHTee() and isHorizontal()) return; + // else if (target->isVTee() and isVertical ()) return; + // setFlags( SegNotTargetAligned ); + } + } + + + void AutoSegment::mergeUserConstraints ( const Interval& constraints ) + { + cdebug_log(149,0) << "mergeUserConstraints() " << this << endl; + cdebug_log(149,0) << "| " << constraints << " merged with " << _userConstraints << endl; + _userConstraints.intersection(constraints); + } + + + bool AutoSegment::toConstraintAxis ( unsigned int flags ) + { + cdebug_log(149,1) << "toConstraintAxis() " << this << endl; + + if (not isCanonical()) { cdebug_tabw(149,-1); return false; } + + DbU::Unit constraintMin; + DbU::Unit constraintMax; + + getConstraints( constraintMin, constraintMax ); + + // Empty constraint interval: ignore. + if (constraintMin > constraintMax) { cdebug_tabw(149,-1); return false; } + + if (isDogleg()) { + DbU::Unit halfSideLength = getAutoSource()->getGCell()->getSide + ( isHorizontal() ? Flags::Vertical : Flags::Horizontal ).getHalfSize(); + constraintMin -= halfSideLength; + constraintMax += halfSideLength; + } + + if (getAxis() < constraintMin) { + setAxis( constraintMin, flags ); + cdebug_tabw(149,-1); + return true; + } + + if (getAxis() > constraintMax) { + setAxis( constraintMax, flags ); + cdebug_tabw(149,-1); + return true; + } + + cdebug_tabw(149,-1); + return false; + } + + + bool AutoSegment::toOptimalAxis ( unsigned int flags ) + { + cdebug_log(149,1) << "toOptimalAxis() " << this << endl; + + if (not isCanonical()) { cdebug_tabw(149,-1); return false; } + + DbU::Unit constraintMin; + DbU::Unit constraintMax; + + getConstraints( constraintMin, constraintMax ); + + DbU::Unit optimalMin = max( min(getOptimalMin(),constraintMax), constraintMin ); + DbU::Unit optimalMax = min( max(getOptimalMax(),constraintMin), constraintMax ); + + if (getAxis() < optimalMin) { + setAxis( optimalMin, flags ); + cdebug_tabw(149,-1); + return true; + } + + if (getAxis() > optimalMax) { + setAxis( optimalMax, flags ); + cdebug_tabw(149,-1); + return true; + } + + if (flags & Flags::Realignate) setAxis( getAxis(), flags ); + + cdebug_tabw(149,-1); + return false; + } + + + void AutoSegment::setAxis ( DbU::Unit axis, unsigned int flags ) + { + if (not isCanonical()) return; + + if ( (axis == getAxis()) and not (flags & Flags::Realignate) ) return; + + cdebug_log(149,0) << "setAxis() @" + << ((isHorizontal())?"Y ":"X ") << DbU::toLambda(getAxis()) + << " to " << DbU::toLambda(axis) << " on " << this << endl; + cdebug_tabw(145,1); + + _setAxis( axis ); + + if (not isNotAligned()) { + forEach( AutoSegment*, isegment, getAligneds() ) { + isegment->_setAxis( getAxis() ); + } + } else { + cdebug_log(149,0) << "No need to process parallels." << endl; + } + + cdebug_tabw(145,-1); + } + + + void AutoSegment::computeTerminal () + { + AutoContact* source = getAutoSource(); + AutoContact* target = getAutoTarget(); + + cdebug_log(145,0) << "computeTerminal() S:" << source->isTerminal() + << " T:" << target->isTerminal() + << " " << this << endl; + + if (source->isTerminal()) { + unsetFlags( SegWeakTerminal ); + setFlags ( SegSourceTerminal ); + if (not target->isTerminal()) + target->setFlags( CntWeakTerminal ); + } else if (target->isTerminal()) { + unsetFlags( SegWeakTerminal ); + setFlags ( SegTargetTerminal ); + if (not source->isTerminal()) + source->setFlags( CntWeakTerminal ); + } else { + unsigned int terminalFlag = 0; + switch ( _getFlags() & SegWeakTerminal ) { + case 0: break; + case SegSourceTerminal|SegTargetTerminal: + case SegSourceTerminal: + case SegTargetTerminal: terminalFlag = SegWeakTerminal1; break; + case SegWeakTerminal1: terminalFlag = SegWeakTerminal1; break; + case SegWeakTerminal2: terminalFlag = SegWeakTerminal2; break; + default: + cerr << Warning("%s has multiple terminal flag sets: %x." + ,getString(this).c_str() + ,_flags + ) << endl; + terminalFlag = SegWeakTerminal2; break; + } + unsetFlags( SegWeakTerminal ); + setFlags ( terminalFlag ); + } + } + + + void AutoSegment::computeOptimal ( set& processeds ) + { + cdebug_log(145,1) << "computeOptimal() - " << this << endl; + + DbU::Unit optimalMin; + DbU::Unit optimalMax; + DbU::Unit constraintMin; + DbU::Unit constraintMax; + + getConstraints( constraintMin, constraintMax ); + + if (isUserDefined()) { + optimalMin = optimalMax = getAxis(); + } else { + DbU::Unit minGCell = getOrigin(); + DbU::Unit maxGCell = getExtremity(); + DbU::Unit terminalMin; + DbU::Unit terminalMax; + AttractorsMap attractors; + + AutoContact* anchor = getAutoSource(); + if (anchor->isTerminal()) { + Box constraintBox = anchor->getConstraintBox(); + if ( isHorizontal() ) { + terminalMin = constraintBox.getYMin(); + terminalMax = constraintBox.getYMax(); + } else { + terminalMin = constraintBox.getXMin(); + terminalMax = constraintBox.getXMax(); + } + + attractors.addAttractor( terminalMin ); + if (terminalMin != terminalMax) + attractors.addAttractor( terminalMax ); + } + + anchor = getAutoTarget(); + if (anchor->isTerminal()) { + Box constraintBox = anchor->getConstraintBox(); + if (isHorizontal()) { + terminalMin = constraintBox.getYMin(); + terminalMax = constraintBox.getYMax(); + } else { + terminalMin = constraintBox.getXMin(); + terminalMax = constraintBox.getXMax(); + } + + attractors.addAttractor( terminalMin ); + if (terminalMin != terminalMax) + attractors.addAttractor( terminalMax ); + } + + forEach( AutoSegment*, autoSegment, getPerpandiculars() ) { + cdebug_log(145,1) << "Perpandicular " << *autoSegment << endl; + if (autoSegment->isLocal()) { + if (not autoSegment->isStrongTerminal()) { cdebug_tabw(145,-1); continue; } + + DbU::Unit terminalMin; + DbU::Unit terminalMax; + + if (getTerminalInterval( *autoSegment + , NULL + , isHorizontal() + , terminalMin + , terminalMax )) { + attractors.addAttractor( terminalMin ); + if (terminalMin != terminalMax) + attractors.addAttractor( terminalMax ); + } + } else { +#if THIS_IS_DISABLED + bool isMin = true; + if ( isHorizontal() + and (autoSegment->getAutoSource()->getGCell()->getRow() == _gcell->getRow()) ) + isMin = false; + if ( isVertical() + and (autoSegment->getAutoSource()->getGCell()->getColumn() == _gcell->getColumn()) ) + isMin = false; + attractors.addAttractor( (isMin) ? minGCell : maxGCell ); +#endif + // Sloppy implentation. + DbU::Unit perpandMin = autoSegment->getSourceU(); + DbU::Unit perpandMax = autoSegment->getTargetU(); + + if (perpandMin < minGCell) attractors.addAttractor( minGCell ); + if (perpandMax > maxGCell) attractors.addAttractor( maxGCell ); + } + cdebug_tabw(145,-1); + } + + if (attractors.getAttractorsCount()) { + cdebug_log(145,0) << "Lower Median " << DbU::toLambda(attractors.getLowerMedian()) << endl; + cdebug_log(145,0) << "Upper Median " << DbU::toLambda(attractors.getUpperMedian()) << endl; + + optimalMin = attractors.getLowerMedian(); + optimalMax = attractors.getUpperMedian(); + } else { + optimalMin = 0; + optimalMax = (isHorizontal()) ? _gcell->getBoundingBox().getYMax() + : _gcell->getBoundingBox().getXMax(); + } + } + + setInBound( constraintMin, constraintMax, optimalMin ); + setInBound( constraintMin, constraintMax, optimalMax ); + + cdebug_log(145,0) << "Applying constraint on: " << this << endl; + setOptimalMin( optimalMin ); + setOptimalMax( optimalMax ); + processeds.insert( this ); + if (not isNotAligned()) { + forEach ( AutoSegment*, autoSegment, getAligneds() ) { + cdebug_log(145,0) << "Applying constraint on: " << *autoSegment << endl; + autoSegment->setOptimalMin( optimalMin ); + autoSegment->setOptimalMax( optimalMax ); + processeds.insert( (*autoSegment) ); + } + } + + cdebug_tabw(145,-1); + } + + + AutoSegment* AutoSegment::canonize ( unsigned int flags ) + { + cdebug_log(149,0) << "canonize() - " << this << endl; + + // if (isCanonical() and isGlobal()) { + // cdebug_log(149,0) << "* " << this << " canonical" << endl; + // return this; + // } + + vector segments; + AutoSegment* canonical = this; + bool hasCanonical = isCanonical(); + bool hasGlobal = isGlobal(); + + if (not isNotAligned()) { + forEach( AutoSegment*, isegment, getAligneds(flags) ) { + if (isegment->isFixed()) continue; + + hasGlobal = hasGlobal or isegment->isGlobal(); + segments.push_back( *isegment ); + + if (not hasCanonical) { + if (isegment->isCanonical()) { + cdebug_log(149,0) << "* " << *isegment << " canonical already set" << endl; + canonical = *isegment; + hasCanonical = true; + } + + if (CompareId()(*isegment,canonical)) canonical = *isegment; + } + } + + canonical->setFlags( SegCanonical ); + if (hasGlobal) { + for ( size_t i=0 ; iisGlobal()) + segments[i]->setFlags( SegWeakGlobal ); + } + } else { + for ( size_t i=0 ; iunsetFlags( SegWeakGlobal ); + } + if (segments.empty()) setFlags( SegNotAligned ); + + if (isCanonical()) { cdebug_log(149,0) << "* " << this << " canonical" << endl; } + else { + cdebug_log(149,0) << "* " << this << " not canonical" << endl; + cdebug_log(149,0) << "* " << canonical << " *is* the canonical" << endl; + } + } else { + setFlags ( SegCanonical ); + unsetFlags( SegWeakGlobal ); + } + + return canonical; + } + + + size_t AutoSegment::getAlignedContacts ( map& innerContacts ) const + { + map::iterator icontact; + + innerContacts.clear(); + innerContacts.insert( make_pair(getAutoSource(),0x1) ); + innerContacts.insert( make_pair(getAutoTarget(),0x4) ); + + if (not isNotAligned()) { + forEach ( AutoSegment*, isegment, const_cast(this)->getAligneds() ) { + if ( (icontact = innerContacts.find(isegment->getAutoSource())) != innerContacts.end() ) { + if (icontact->second & 0x1) icontact->second |= 0x2; + else icontact->second |= 0x1; + } else + innerContacts.insert( make_pair(getAutoSource(),0x1) ); + + if ( (icontact = innerContacts.find(isegment->getAutoTarget())) != innerContacts.end() ) { + if (icontact->second & 0x4) icontact->second |= 0x8; + else icontact->second |= 0x4; + } else + innerContacts.insert( make_pair(getAutoTarget(),0x4) ); + } + } + + return innerContacts.size(); + } + + + Interval AutoSegment::getMinSpanU () const + { + map contacts; + map::iterator icontact; + + getAlignedContacts( contacts ); + + DbU::Unit spanMin = DbU::Min; + DbU::Unit spanMax = DbU::Max; + Interval constraints; + unsigned int direction = getDirection(); + + for ( icontact=contacts.begin() ; icontact != contacts.end() ; icontact++ ) { + constraints = icontact->first->getUConstraints( direction ); + if (icontact->second == 0x1) { + spanMin = max( spanMin, constraints.getVMax() ); + } + if (icontact->second == 0x4) { + spanMax = min( spanMax, constraints.getVMin() ); + } + } + + return Interval(spanMin,spanMax); + } + + + size_t AutoSegment::getPerpandicularsBound ( set& bounds ) + { + map contacts; + map::iterator icontact; + + getAlignedContacts( contacts ); + + for ( icontact=contacts.begin() ; icontact != contacts.end() ; icontact++ ) { + if ( (icontact->second == 0x1) or (icontact->second == 0x4) ) { + forEach ( Segment*, isegment, icontact->first->getSlaveComponents().getSubSet() ) { + AutoSegment* autoSegment = Session::lookup ( *isegment ); + if (not autoSegment) continue; + if (autoSegment->getDirection() == getDirection()) continue; + + bounds.insert( autoSegment ); + } + } + } + + return bounds.size(); + } + + + bool AutoSegment::isUTurn () const + { + if (isGlobal()) return false; + + AutoContact* source = getAutoSource(); + AutoContact* target = getAutoTarget(); + + cerr << "AutoSegment::isUTurn():" << endl; + + if (not source->isTurn() or not target->isTurn()) return false; + + cerr << " Turn connected" << endl; + + AutoSegment* perpandicular = source->getPerpandicular( this ); + bool onPSourceSource = (perpandicular->getAutoSource() == source); + + perpandicular = target->getPerpandicular( this ); + bool onPTargetSource = (perpandicular->getAutoSource() == target); + + cerr << " PSource:" << onPSourceSource << " PTarget:" << onPTargetSource << endl; + + return not (onPSourceSource xor onPTargetSource); + } + + + bool AutoSegment::isReduceCandidate () const + { + if (isGlobal()) return false; + if (not isSpinTopOrBottom()) return false; + if (_reduceds) return false; + + AutoContact* source = getAutoSource(); + AutoContact* target = getAutoTarget(); + + if (not source->isTurn() or not target->isTurn()) return false; + + return true; + } + + + bool AutoSegment::canReduce () const + { + if (isGlobal()) return false; + if (not isSpinTopOrBottom()) return false; + if (_reduceds) return false; + + AutoContact* source = getAutoSource(); + AutoContact* target = getAutoTarget(); + + if (not source->isTurn() or not target->isTurn()) return false; + + unsigned int perpandicularDepth = getDepth(); + if (isSpinBottom()) --perpandicularDepth; + else if (isSpinTop()) { + ++perpandicularDepth; + if (perpandicularDepth >= Session::getDepth()) return false; + } else + return false; + + if (getLength() >= (Session::getPitch(perpandicularDepth) * 2)) return false; + + return true; + } + + + bool AutoSegment::reduce () + { + if (not canReduce()) return false; + + AutoContact* source = getAutoSource(); + AutoContact* target = getAutoTarget(); + + _flags |= SegIsReduced; + source->getPerpandicular( this )->incReduceds(); + target->getPerpandicular( this )->incReduceds(); + + return true; + } + + + bool AutoSegment::mustRaise () const + { + if (not (_flags & SegIsReduced)) return false; + + unsigned int perpandicularDepth = getDepth(); + if (isSpinBottom()) --perpandicularDepth; + else if (isSpinTop ()) ++perpandicularDepth; + else return true; + + return (getLength() >= (Session::getPitch(perpandicularDepth) * 2)); + } + + + bool AutoSegment::raise () + { + if (not (_flags & SegIsReduced)) return false; + + AutoContact* source = getAutoSource(); + AutoContact* target = getAutoTarget(); + + _flags &= ~SegIsReduced; + source->getPerpandicular( this )->decReduceds(); + target->getPerpandicular( this )->decReduceds(); + + return true; + } + + + void AutoSegment::changeDepth ( unsigned int depth, unsigned int flags ) + { + cdebug_log(149,1) << "changeDepth() " << depth << " - " << this << endl; + Session::invalidate( getNet() ); + + _changeDepth( depth, flags & ~Flags::Propagate ); + + if ((flags & Flags::Propagate) and not isNotAligned()) { + forEach ( AutoSegment*, isegment, getAligneds(Flags::NoCheckLayer) ) { + (*isegment)->_changeDepth( depth, flags & ~Flags::Propagate ); + } + } + + cdebug_tabw(149,-1); + } + + + void AutoSegment::_changeDepth ( unsigned int depth, unsigned int flags ) + { + cdebug_log(149,1) << "_changeDepth() - " << this << endl; + + invalidate( Flags::NoFlags ); + setFlags( SegInvalidatedLayer|SegInvalidatedSource|SegInvalidatedTarget ); + + const Layer* newLayer = Session::getRoutingGauge()->getRoutingLayer(depth); + if (getLayer() != newLayer) { + setLayer( newLayer ); + + getAutoSource()->invalidate( Flags::Topology|Flags::NoCheckLayer ); + getAutoTarget()->invalidate( Flags::Topology|Flags::NoCheckLayer ); + } + + if (not (flags & Flags::WithNeighbors)) { + cdebug_tabw(149,-1); + return; + } + + forEach ( AutoSegment*, isegment, getCachedOnSourceContact(Flags::DirectionMask) ) { + if ((*isegment) == this) continue; + if ((*isegment)->isGlobal ()) continue; + if ((*isegment)->isTerminal()) continue; + + if (not ((*isegment)->isHorizontal() xor isHorizontal())) + (*isegment)->_changeDepth( depth , Flags::NoFlags ); + else + (*isegment)->_changeDepth( depth-1, Flags::NoFlags ); + } + + forEach ( AutoSegment*, isegment, getCachedOnTargetContact(Flags::DirectionMask) ) { + if ((*isegment) == this) continue; + if ((*isegment)->isGlobal ()) continue; + if ((*isegment)->isTerminal()) continue; + + if (not ((*isegment)->isHorizontal() xor isHorizontal())) + (*isegment)->_changeDepth( depth , Flags::NoFlags ); + else + (*isegment)->_changeDepth( depth-1, Flags::NoFlags ); + } + + vector gcells; + getGCells( gcells ); + for ( size_t i=0 ; iinvalidate(); + + cdebug_tabw(149,-1); + } + + + bool AutoSegment::canSlacken ( unsigned int flags ) const + { + cdebug_log(149,0) << "AutoSegment::canSlacken()" << endl; + + if (not isGlobal() and not (flags & Flags::Propagate)) return false; + + if (_canSlacken()) return true; + if ((flags & Flags::Propagate) and not isNotAligned()) { + forEach ( AutoSegment*, isegment, const_cast(this)->getAligneds() ) { + if (isegment->_canSlacken()) return true; + } + } + + return false; + } + + + bool AutoSegment::slacken ( unsigned int flags ) + { + bool success = false; + + success = success or _slacken( flags ); + + if ((flags & Flags::Propagate) and not isNotAligned()) { + forEach ( AutoSegment*, isegment, getAligneds() ) { + success = success or (*isegment)->_slacken( flags ); + } + } + + return success; + } + + + float AutoSegment::getMaxUnderDensity ( unsigned int flags ) + { + cdebug_log(149,0) << "AutoSegment::getMaxUnderDensity() " << endl; + + size_t depth = Session::getRoutingGauge()->getLayerDepth(getLayer()); + + vector gcells; + getGCells( gcells ); + + float maxDensity = 0.0; + + for ( size_t i=0 ; igetFeedthroughs(depth) ); + } + + if ((flags & Flags::Propagate) and not isNotAligned()) { + forEach ( AutoSegment*, isegment, getAligneds() ) { + isegment->getGCells( gcells ); + for ( size_t i=0 ; igetFeedthroughs(depth) ); + } + } + } + + return maxDensity; + } + + + bool AutoSegment::canPivotUp ( float reserve, unsigned int flags ) const + { + cdebug_log(149,0) << "AutoSegment::canPivotUp() - " << flags + << " (reserve:" << reserve << ")" << endl; + + if ( isLayerChange() or isFixed() ) return false; + if ( isStrongTerminal() or isLocal() ) return false; + + size_t depth = Session::getRoutingGauge()->getLayerDepth( getLayer() ); + if (depth+2 >= Session::getRoutingGauge()->getDepth()) return false; + + vector gcells; + getGCells( gcells ); + for ( size_t i=0 ; ihasFreeTrack(depth+2,reserve)) return false; + } + + if ( not (flags&Flags::IgnoreContacts) ) { + cdebug_log(149,0) << getAutoSource() << endl; + cdebug_log(149,0) << getAutoTarget() << endl; + cdebug_log(149,0) << "min depths, Segment:" << depth + << " S:" << getAutoSource()->getMinDepth() + << " T:" << getAutoTarget()->getMinDepth() << endl; + + if (getAutoSource()->getMinDepth() < depth) return false; + if (getAutoTarget()->getMinDepth() < depth) return false; + } + + if ((flags & Flags::Propagate) and not isNotAligned()) { + forEach ( AutoSegment*, isegment, const_cast(this)->getAligneds(flags) ) { + isegment->getGCells( gcells ); + for ( size_t i=0 ; ihasFreeTrack(depth+2,reserve)) return false; + } + if (isegment->getAutoSource()->getMinDepth() < depth) return false; + if (isegment->getAutoTarget()->getMinDepth() < depth) return false; + } + } else { + cdebug_log(149,0) << "AutoSegment::canPivotUp() - true [no propagate]" << endl; + return true; + } + + cdebug_log(149,0) << "AutoSegment::canPivotUp() - true [propagate]" << endl; + + return true; + } + + + bool AutoSegment::canPivotDown ( float reserve, unsigned int flags ) const + { + cdebug_log(149,0) << "AutoSegment::canPivotDown()" + << " (reserve:" << reserve << ")" << endl; + + if ( isLayerChange() or isFixed() ) return false; + if ( isStrongTerminal() or isLocal() ) return false; + + size_t depth = Session::getRoutingGauge()->getLayerDepth( getLayer() ); + if (depth < 3) return false; + + vector gcells; + getGCells( gcells ); + for ( size_t i=0 ; ihasFreeTrack(depth-2,reserve)) return false; + } + + cdebug_log(149,0) << getAutoSource() << endl; + cdebug_log(149,0) << getAutoTarget() << endl; + cdebug_log(149,0) << "max depths, Segment:" << depth + << " S:" << getAutoSource()->getMaxDepth() + << " T:" << getAutoTarget()->getMaxDepth() << endl; + + if (getAutoSource()->getMaxDepth() > depth) return false; + if (getAutoTarget()->getMaxDepth() > depth) return false; + if (not (flags & Flags::Propagate)) { + cdebug_log(149,0) << "AutoSegment::canPivotDown() - true [no propagate]" << endl; + return true; + } + + if ((flags & Flags::Propagate) and not isNotAligned()) { + forEach ( AutoSegment*, isegment, const_cast(this)->getAligneds() ) { + isegment->getGCells( gcells ); + for ( size_t i=0 ; ihasFreeTrack(depth-2,reserve)) return false; + } + if (isegment->getAutoSource()->getMaxDepth() < depth) return false; + if (isegment->getAutoTarget()->getMaxDepth() < depth) return false; + } + } + + cdebug_log(149,0) << "AutoSegment::canPivotDown() - true [propagate]" << endl; + + return true; + } + + + bool AutoSegment::canMoveUp ( float reserve, unsigned int flags ) const + { + cdebug_log(149,0) << "AutoSegment::canMoveUp() " << flags + << " (reserve:" << reserve << ")" << endl; + + bool lowDensity = true; + GCell* begin = NULL; + GCell* end = NULL; + + if ( isLayerChange() or isFixed() ) return false; + if ( isStrongTerminal() and (not (flags & Flags::AllowTerminal)) ) return false; + if ( isLocal() and (not (flags & Flags::AllowLocal )) ) return false; + + size_t depth = Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2; + if (depth > Session::getConfiguration()->getAllowedDepth()) return false; + + vector gcells; + getGCells( gcells ); + begin = *gcells.begin (); + end = *gcells.rbegin(); + + for ( size_t i=0 ; igetWDensity(depth-2) > 0.5) ) lowDensity = false; + if (not gcells[i]->hasFreeTrack(depth,reserve)) { + cdebug_log(149,0) << "Not enough free track in " << gcells[i] << endl; + return false; + } + } + + cdebug_log(149,0) << "Enough free track under canonical segment." << endl; + + if ( isLocal() and not (flags & Flags::Propagate) ) { + if (not getAutoSource()->canMoveUp(this)) return false; + if (not getAutoTarget()->canMoveUp(this)) return false; + return true; + } + + //bool hasGlobalSegment = false; + if ((flags & Flags::Propagate) and not isNotAligned()) { + forEach ( AutoSegment*, isegment, const_cast(this)->getAligneds(flags) ) { + if (isegment->isFixed ()) return false; + //if (isegment->isGlobal()) hasGlobalSegment = true; + + isegment->getGCells( gcells ); + //if ( (*gcells.begin ())->getIndex() < begin->getIndex() ) begin = *gcells.begin (); + //if ( (*gcells.rbegin())->getIndex() > end ->getIndex() ) end = *gcells.rbegin(); + + for ( size_t i=0 ; igetWDensity(depth-2) > 0.6) ) lowDensity = false; + if (not gcells[i]->hasFreeTrack(depth,reserve)) { + cdebug_log(149,0) << "Not enough free track in " << gcells[i] << endl; + return false; + } + } + } + } + + if (lowDensity and (flags & Flags::CheckLowDensity)) return false; + + if ( (depth >= 4) and (flags & Flags::WithPerpands) ) { + float fragmentation = begin->getFragmentation( depth-1 ); + cdebug_log(149,0) << "Check begin GCell perpandicular fragmentation: " << fragmentation << endl; + + if (fragmentation < 0.5) { + cdebug_log(149,0) << "Not enough free track for perpandicular in begin GCell " + << "(frag:" << fragmentation << ")." + << endl; + return false; + } + + fragmentation = end->getFragmentation( depth-1 ); + cdebug_log(149,0) << "Check end GCell perpandicular fragmentation: " << fragmentation << endl; + + if (fragmentation < 0.5) { + cdebug_log(149,0) << "Not enough free track for perpandicular in end GCell " + << "(frag:" << fragmentation << ")." + << endl; + return false; + } + } + + return true; + } + + + bool AutoSegment::moveUp ( unsigned int flags ) + { + //if ( not canMoveUp(0.0,flags) ) return false; + changeDepth( Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2, flags&Flags::Propagate ); + + return true; + } + + + bool AutoSegment::moveDown ( unsigned int flags ) + { + //if ( not canPivotDown(0.0,flags) ) return false; + changeDepth( Session::getRoutingGauge()->getLayerDepth(getLayer()) - 2, flags&Flags::Propagate ); + + return true; + } + + + bool AutoSegment::reduceDoglegLayer () + { + if (not isReduced()) return true; + + AutoContact* source = getAutoSource(); + AutoContact* target = getAutoTarget(); + + unsigned int perpandicularDepth = getDepth(); + if (isSpinBottom()) --perpandicularDepth; + if (isSpinTop ()) ++perpandicularDepth; + + if (perpandicularDepth == getDepth()) { + cerr << Bug( "AutoSegment::reduceDoglegLayer(): Reduced segment spin is neither top (TT) nor bottom (BB).\n" + " %s" + , getString(this).c_str() ) << endl; + return false; + } + + source->setLayer( Session::getRoutingLayer(perpandicularDepth) ); + target->setLayer( Session::getRoutingLayer(perpandicularDepth) ); + setLayer( Session::getRoutingLayer(perpandicularDepth) ); + + return true; + } + + +#if THIS_IS_DISABLED + + + bool AutoSegment::shearUp ( GCell* upGCell, AutoSegment*& movedUp, float reserve, unsigned int flags ) + { + cdebug_log(149,0) << "AutoSegment::shearUp() " << this << endl; + + movedUp = NULL; + + if ( isLayerChange() or isFixed() /*or isTerminal()*/ or isLocal() ) return false; + + size_t upDepth = Session::getRoutingGauge()->getLayerDepth(getLayer()) + 2; + if ( upDepth > Session::getConfiguration()->getAllowedDepth() ) return false; + + vector gcells; + getGCells ( gcells ); + + size_t iupGCell = 0; + for ( ; iupGCellhasFreeTrack(upDepth,reserve) ) { + cdebug_log(149,0) << "Right shearing @ " << gcells[i] << endl; + rightShear = gcells[i]; + } + } + + GCell* leftShear = NULL; + if ( iupGCell > 0 ) { + size_t i = iupGCell; + do { + --i; + if ( not gcells[i]->hasFreeTrack(upDepth,reserve) ) { + cdebug_log(149,0) << "Left shearing @ " << gcells[i] << endl; + leftShear = gcells[i]; + } + } while (i > 0); + } + + AutoSegment* before = this; + const vector& doglegs = Session::getDoglegs(); + + if ( leftShear ) { + makeDogleg ( leftShear, true ); + movedUp = doglegs[2]; + } else { + before = NULL; + movedUp = this; + } + + if ( rightShear ) makeDogleg(rightShear,true); + + if ( movedUp->moveUp(flags) ) { + if ( rightShear or leftShear ) + cinfo << "Shearing Up " << this << "." << endl; + return true; + } + + movedUp = NULL; + return false; + } +#endif + + + unsigned int AutoSegment::canDogleg ( Interval interval ) + { + cdebug_log(149,0) << "AutoSegment::canDogleg(Interval) " << interval << endl; + + size_t leftDogleg = 0; + size_t rightDogleg = 0; + if (getSpanU().contains(interval.getVMin())) leftDogleg++; + if (getSpanU().contains(interval.getVMax())) rightDogleg++; + + if (not isNotAligned()) { + forEach ( AutoSegment*, isegment, getAligneds() ) { + if (isegment->getSpanU().contains(interval.getVMin())) { + if (isegment->isFixed()) return false; + leftDogleg++; + } + if (isegment->getSpanU().contains(interval.getVMax())) { + if (isegment->isFixed()) return 0; + rightDogleg++; + } + } + } + + if ( (leftDogleg == 1) and (rightDogleg <= 1) ) return Flags::DoglegOnLeft; + if ( (leftDogleg <= 1) and (rightDogleg == 1) ) return Flags::DoglegOnRight; + + cdebug_log(149,0) << "leftCount:" << leftDogleg << " rightCount:" << rightDogleg << endl; + + return 0; + } + + + AutoSegment* AutoSegment::makeDogleg ( AutoContact* from ) + { + cdebug_log(149,1) << "AutoSegment::makeDogleg(AutoContact*) " << from << endl; + cdebug_log(149,0) << this << endl; + + RoutingGauge* rg = Session::getRoutingGauge(); + size_t segmentDepth = rg->getLayerDepth( getLayer() ); + const vector& doglegs = Session::getDoglegs(); + size_t index = doglegs.size(); + bool isSource = (getAutoSource() == from); + + cdebug_log(149,0) << "isSource:" << isSource << endl; + + makeDogleg( from->getGCell(), Flags::NoCheckLayer ); + if (doglegs.size() == index) { + cdebug_tabw(149,-1); + return NULL; + } + doglegs[ index+1 ]->setAxis( isHorizontal() ? from->getX() : from->getY() ); + + if (not from->getLayer()->contains(getLayer())) { + cdebug_log(149,0) << "Contact layer do not contains Segment layer, adjust layers" << endl; + + if (getLayer()->above(from->getLayer())) { + cdebug_log(149,0) << "Go Down from depth " << segmentDepth << endl; + + doglegs[ index + 1 ]->setLayer( rg->getRoutingLayer(segmentDepth-1) ); + cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1] << endl; + + if (isSource) { + doglegs[ index + 0 ]->setLayer( rg->getRoutingLayer(segmentDepth-2) ); + doglegs[ index + 1 ]->getAutoSource()->setLayer( rg->getContactLayer(segmentDepth-2) ); + doglegs[ index + 1 ]->getAutoTarget()->setLayer( rg->getContactLayer(segmentDepth-1) ); + cdebug_log(149,0) << "doglegs[i+0]: " << doglegs[index+0] << endl; + cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoSource() << endl; + cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoTarget() << endl; + } else { + doglegs[ index + 2 ]->setLayer( rg->getRoutingLayer(segmentDepth-2) ); + doglegs[ index + 1 ]->getAutoTarget()->setLayer( rg->getContactLayer(segmentDepth-2) ); + doglegs[ index + 1 ]->getAutoSource()->setLayer( rg->getContactLayer(segmentDepth-1) ); + cdebug_log(149,0) << "doglegs[i+2]: " << doglegs[index+2] << endl; + cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoTarget() << endl; + cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoSource() << endl; + } + } else { + cdebug_log(149,0) << "Go Up from depth " << segmentDepth << endl; + + doglegs[ index + 1 ]->setLayer( rg->getRoutingLayer(segmentDepth+1) ); + cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1] << endl; + + if (isSource) { + doglegs[ index + 0 ]->setLayer( rg->getRoutingLayer(segmentDepth+2) ); + doglegs[ index + 1 ]->getAutoSource()->setLayer( rg->getContactLayer(segmentDepth+1) ); + doglegs[ index + 1 ]->getAutoTarget()->setLayer( rg->getContactLayer(segmentDepth ) ); + cdebug_log(149,0) << "doglegs[i+0]: " << doglegs[index+0] << endl; + cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoSource() << endl; + cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoTarget() << endl; + } else { + doglegs[ index + 2 ]->setLayer( rg->getRoutingLayer(segmentDepth+2) ); + doglegs[ index + 1 ]->getAutoTarget()->setLayer( rg->getContactLayer(segmentDepth+1) ); + doglegs[ index + 1 ]->getAutoSource()->setLayer( rg->getContactLayer(segmentDepth ) ); + cdebug_log(149,0) << "doglegs[i+2]: " << doglegs[index+2] << endl; + cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoTarget() << endl; + cdebug_log(149,0) << "doglegs[i+1]: " << doglegs[index+1]->getAutoSource() << endl; + } + } + } + + cdebug_tabw(149,-1); + return doglegs[ index + (isSource?0:2) ]; + } + + + unsigned int AutoSegment::makeDogleg ( Interval interval, unsigned int flags ) + { + cdebug_log(149,1) << "AutoSegment::makeDogleg(Interval) - " << interval << endl; + + bool leftDogleg = true; + unsigned int rflags = 0; + size_t leftDoglegCount = 0; + size_t rightDoglegCount = 0; + AutoSegment* leftCandidate = NULL; + AutoSegment* rightCandidate = NULL; + + if (getSpanU().contains(interval.getVMin())) { leftCandidate = this; leftDoglegCount++; } + if (getSpanU().contains(interval.getVMax())) { rightCandidate = this; rightDoglegCount++; } + + if (not isNotAligned()) { + forEach ( AutoSegment*, isegment, getAligneds(flags) ) { + if (isegment->getSpanU().contains(interval.getVMin())) { leftCandidate = *isegment; leftDoglegCount++; } + if (isegment->getSpanU().contains(interval.getVMax())) { rightCandidate = *isegment; rightDoglegCount++; } + } + } + + if ( (leftDoglegCount != 1) and (rightDoglegCount != 1) ) { cdebug_tabw(149,-1); return 0; } + if (not leftDoglegCount) { + leftDogleg = false; + leftCandidate = rightCandidate; + rightCandidate = NULL; + } + + if (leftCandidate and rightCandidate) { + cdebug_log(149,0) << "Left Constraint: " << leftCandidate->getSourceConstraints(Flags::NativeConstraints) << endl; + cdebug_log(149,0) << "Right Constraint: " << rightCandidate->getTargetConstraints(Flags::NativeConstraints) << endl; + + if ( leftCandidate ->getTargetConstraints(Flags::NativeConstraints).getSize() + < rightCandidate->getSourceConstraints(Flags::NativeConstraints).getSize() ) { + leftCandidate = rightCandidate; + leftDogleg = false; + } + } else { + if (not leftCandidate) { + leftCandidate = rightCandidate; + leftDogleg = false; + } + } + + if (leftCandidate) { + DbU::Unit axis; + // Ugly: Hard-wired track spacing. + if (leftDogleg) axis = interval.getVMin() - getPitch(); + else axis = interval.getVMax() + getPitch(); + + cdebug_log(149,0) << "Break @" << DbU::getValueString(axis) << " " << leftCandidate << endl; + + unsigned int direction = getDirection(); + GCell* gcell = leftCandidate->getAutoSource()->getGCell(); + GCell* end = leftCandidate->getAutoTarget()->getGCell(); + while ( gcell != end ) { + if (gcell->getSide(direction).contains(axis)) break; + gcell = (direction == Flags::Horizontal) ? gcell->getEast (getNativeMin()) + : gcell->getNorth(getNativeMin()); + } + + cdebug_log(149,0) << "In " << gcell << endl; + rflags = leftCandidate->_makeDogleg( gcell, flags ); + + const vector& doglegs = Session::getDoglegs(); + if (doglegs.size() >= 2) { + cdebug_log(149,0) << "AutoSegment::makeDogleg(): @" << DbU::getValueString(axis) << endl; + doglegs[1]->setAxis( axis ); + } + } + + cdebug_tabw(149,-1); + return rflags | (leftDogleg ? Flags::DoglegOnLeft : Flags::DoglegOnRight); + } + + + unsigned int AutoSegment::makeDogleg ( GCell* doglegGCell, unsigned int flags ) + { + cdebug_log(9000,0) << "Deter| AutoSegment::makeDogleg(GCell*) " << doglegGCell << endl; + cdebug_log(9000,0) << "Deter| in " << this << endl; + cdebug_tabw(149,1); + + unsigned int rflags = 0; + + if ( doglegGCell->isIoPad() + and (Session::getAnabatic()->getState() != EngineGlobalLoaded) ) { + cerr << Bug( "Attempt to make a dogleg in a GCell under a Pad\n" + " %s\n" + " %s" + , getString(this).c_str() + , getString(doglegGCell).c_str() ) << endl; + } + + if (isFixed()) { + cerr << Error( "AutoSegment::makeDogleg(): Cannot make a dog leg on a fixed segment.\n" + " (on: %s)", _getString().c_str() ) << endl; + return 0; + } + + if (doglegGCell->getSide(getDirection()).intersect(getSpanU())) { + cdebug_log(149,0) << "Dogleg in " << this << endl; + rflags = _makeDogleg( doglegGCell, flags ); + } else { + cdebug_log(149,0) << "Looking in aligneds." << endl; + if (not isNotAligned()) { + forEach ( AutoSegment*, aligned, getAligneds(flags) ) { + cdebug_log(149,0) << "| Try in " << *aligned << endl; + if (doglegGCell->getSide(getDirection()).intersect(aligned->getSpanU())) { + cdebug_log(149,0) << "Dogleg in " << *aligned << endl; + rflags = aligned->_makeDogleg( doglegGCell, flags ); + cdebug_tabw(149,-1); + return 0; + } + } + } + cerr << Bug("Cannot make a dogleg in %s at %s" + ,_getString().c_str(), getString(doglegGCell).c_str()) << endl; + } + cdebug_tabw(149,-1); + + return rflags; + } + + + bool AutoSegment::_check () const + { + bool coherency = true; + + coherency = checkNotInvalidated() and coherency; + coherency = checkPositions() and coherency; + coherency = checkConstraints() and coherency; + coherency = checkDepthSpin() and coherency; + + return coherency; + } + + + string AutoSegment::_getStringFlags () const + { + string state; + state += isFixed () ?" F":" -"; + state += isUnsetAxis () ? "u": "-"; + state += isStrap () ? "S": "-"; + state += isCanonical () ? "C": "-"; + state += isGlobal () ? "G": "-"; + state += isWeakGlobal () ? "g": "-"; + state += isStrongTerminal() ? "T": "-"; + state += isWeakTerminal1 () ? "W": "-"; + state += isWeakTerminal2 () ? "w": "-"; + state += isNotAligned () ? "A": "-"; + state += isSlackened () ? "S": "-"; + state += isReduced () ? "r": "-"; + state += isInvalidated () ? "i": "-"; + + if (_flags & SegSourceTop) state += 'T'; + else if (_flags & SegSourceBottom) state += 'B'; + else state += '-'; + if (_flags & SegTargetTop) state += 'T'; + else if (_flags & SegTargetBottom) state += 'B'; + else state += '-'; + + return state; + } + + + string AutoSegment::_getString () const + { + string s = base()->_getString(); + //s.insert ( 1, "id: " ); + //s.insert ( 4, getString(_id) ); + s.insert ( s.size()-1, _getStringFlags() ); + return s; + } + + + Record* AutoSegment::_getRecord () const + { + Record* record = base()->_getRecord (); + record->add ( getSlot ( "_gcell" , _gcell ) ); + record->add ( getSlot ( "_id" , &_id ) ); + record->add ( getSlot ( "_flags" , &_flags ) ); + record->add ( getSlot ( "_userContraints", &_userConstraints ) ); + record->add ( getSlot ( "_sourcePosition", &_sourcePosition ) ); + record->add ( getSlot ( "_targetPosition", &_targetPosition ) ); + record->add ( getSlot ( "_parent" , _parent ) ); + return record; + } + + + AutoSegment* AutoSegment::create ( AutoContact* source + , AutoContact* target + , Segment* hurricaneSegment + ) + { + static const Layer* horizontalLayer = Session::getRoutingLayer( 1 ); + static DbU::Unit horizontalWidth = Session::getWireWidth ( 1 ); + static const Layer* verticalLayer = Session::getRoutingLayer( 2 ); + static DbU::Unit verticalWidth = Session::getWireWidth ( 2 ); + + bool reattachSource = false; + bool reattachTarget = false; + AutoSegment* segment; + Horizontal* horizontal = dynamic_cast( hurricaneSegment ); + Vertical* vertical = dynamic_cast( hurricaneSegment ); + AutoContact* reference = source; + + cdebug_log(149,0) << "Source:" << source << endl; + cdebug_log(149,0) << "Target:" << target << endl; + + if (target->isFixed()) { + if (source->isFixed()) { + if ( (horizontal) and (source->getY() != target->getY())) + cerr << Warning( "Straight AutoHorizontal connecting misaligned contacts:\n" + " %s\n" + " %s" + , getString(source).c_str() + , getString(target).c_str() + ) << endl; + if ( (vertical) and (source->getX() != target->getX())) + cerr << Warning( "Straight AutoVertical connecting misaligned contacts:\n" + " %s\n" + " %s" + , getString(source).c_str() + , getString(target).c_str() + ) << endl; + } else + reference = target; + } + + Contact* contact = dynamic_cast( hurricaneSegment->getSource() ); + AutoContact* autoContact = Session::lookup( contact ); + if (contact == NULL) { + throw Error( badSegmentSource, getString(hurricaneSegment).c_str() ); + if ( autoContact and (autoContact != source) ) + throw Error( mismatchSegmentSource + , getString(hurricaneSegment).c_str() + , getString(contact).c_str() ); + } else { + if (autoContact != source) reattachSource = true; + } + + contact = dynamic_cast( hurricaneSegment->getTarget() ); + autoContact = Session::lookup( contact ); + if (contact == NULL) { + throw Error( badSegmentTarget, getString(hurricaneSegment).c_str() ); + if ( autoContact and (autoContact != target) ) + throw Error ( mismatchSegmentTarget + , getString(hurricaneSegment).c_str() + , getString(contact).c_str() ); + } else { + if (autoContact != source) reattachTarget = true; + } + + if (reattachSource) { + Hook* hook = hurricaneSegment->getSourceHook(); + hook->detach (); + hook->attach ( source->getBodyHook() ); + } + + if (reattachTarget) { + Hook* hook = hurricaneSegment->getTargetHook(); + hook->detach (); + hook->attach ( target->getBodyHook() ); + } + + if (horizontal) { + if (horizontal->getLayer() != horizontalLayer) { + if (Session::getAnabatic()->getConfiguration()->isGMetal(horizontal->getLayer())) { + horizontal->setLayer( horizontalLayer ); + horizontal->setWidth( horizontalWidth ); + } else { + if (horizontal->getWidth() != horizontalWidth) { + cerr << Warning("Segment %s has non-default width %s." + ,getString(horizontal).c_str() + ,DbU::getValueString(horizontal->getWidth()).c_str()) << endl; + } + } + } + + horizontal->setY( reference->getY() ); + segment = new AutoHorizontal ( horizontal ); + segment->_postCreate(); + } else if (vertical) { + if (vertical->getLayer() != verticalLayer) { + if (Session::getAnabatic()->getConfiguration()->isGMetal(vertical->getLayer()) ) + vertical->setLayer( verticalLayer ); + vertical->setWidth( verticalWidth ); + } else { + if (vertical->getWidth() != verticalWidth) { + cerr << Warning("Segment %s has non-default width %s." + ,getString(vertical).c_str() + ,DbU::getValueString(vertical->getWidth()).c_str()) << endl; + } + } + + vertical->setX( reference->getX() ); + segment = new AutoVertical ( vertical ); + segment->_postCreate(); + } else { + throw Error( badSegment, getString(source).c_str(), getString(target).c_str() ); + } + + return segment; + } + + + AutoSegment* AutoSegment::create ( AutoContact* source + , AutoContact* target + , unsigned int dir + , size_t depth + ) + { + // Hardcoded: make the assumption that, + // depth=0 is terminal reserved | METAL1 + // depth=1 is horizontal | METAL2 + // depth=2 is vertical | METAL3 + // Should be based on gauge informations. + static const Layer* hLayer = Session::getRoutingLayer( 1 ); + static DbU::Unit hWidth = Session::getWireWidth ( 1 ); + static const Layer* vLayer = Session::getRoutingLayer( 2 ); + static DbU::Unit vWidth = Session::getWireWidth ( 2 ); + + const Layer* horizontalLayer = hLayer; + DbU::Unit horizontalWidth = hWidth; + const Layer* verticalLayer = vLayer; + DbU::Unit verticalWidth = vWidth; + + if (depth != RoutingGauge::nlayerdepth) { + horizontalLayer = verticalLayer = Session::getRoutingLayer( depth ); + horizontalWidth = verticalWidth = Session::getWireWidth ( depth ); + } + + AutoSegment* segment; + AutoContact* reference = source; + + cdebug_log(149,0) << "Source:" << source << endl; + cdebug_log(149,0) << "Target:" << target << endl; + + if (target->isFixed()) { + if (source->isFixed()) { + if ( (dir == Flags::Horizontal) and (source->getY() != target->getY())) + cerr << Warning( "Straight AutoHorizontal connecting misaligned contacts:\n" + " %s\n" + " %s" + , getString(source).c_str() + , getString(target).c_str() + ) << endl; + if ( (dir == Flags::Vertical) and (source->getX() != target->getX())) + cerr << Warning( "Straight AutoVertical connecting misaligned contacts:\n" + " %s\n" + " %s" + , getString(source).c_str() + , getString(target).c_str() + ) << endl; + } else + reference = target; + } + + if (dir & Flags::Horizontal) { + segment = create( source + , target + , Horizontal::create( source->base() + , target->base() + , horizontalLayer + , reference->getY() + , horizontalWidth ) ); + } else if (dir & Flags::Vertical) { + segment = create( source + , target + , Vertical::create( source->base() + , target->base() + , verticalLayer + , reference->getX() + , verticalWidth + ) ); + } else + throw Error( badSegment, getString(source).c_str(), getString(target).c_str() ); + + return segment; + } + + + void AutoSegment::destroy () + { + _preDestroy (); + delete this; + } + + + bool AutoSegment::isTopologicalBound ( AutoSegment* seed, unsigned int flags ) + { + cdebug_log(145,1) << "isTopologicalBound() - " << seed << endl; + + set exploreds; + vector stack; + DbU::Unit axis; + + if (flags & Flags::Superior) axis = seed->getTargetU(); + else axis = seed->getSourceU(); + + cdebug_log(145,0) << "check for bound " << DbU::getValueString(axis) << endl; + + exploreds.insert( seed->getAutoSource() ); + exploreds.insert( seed->getAutoTarget() ); + + if (seed->getLength()) { + if (flags & Flags::Superior) stack.push_back( seed->getAutoTarget() ); + else stack.push_back( seed->getAutoSource() ); + } else { + stack.push_back( seed->getAutoTarget() ); + stack.push_back( seed->getAutoSource() ); + } + + while ( not stack.empty() ) { + AutoContact* currentContact = stack.back(); + stack.pop_back(); + + cdebug_log(145,0) << "Exploring: " << (void*)currentContact << " " << currentContact << endl; + + exploreds.insert( currentContact ); + + if (currentContact->getAnchor()) { cdebug_tabw(145,-1); return true; } + + forEach ( Component*, component, currentContact->getSlaveComponents() ) { + Segment* segment = dynamic_cast( *component ); + if (not segment) continue; + + AutoSegment* autoSegment = Session::lookup( segment ); + if (not autoSegment) continue; + + if (not autoSegment->getLength()) { + AutoContact* contact = autoSegment->getAutoSource(); + if (contact and (contact != currentContact)) { + if (exploreds.find(contact) == exploreds.end()) + stack.push_back( contact ); + } + + contact = autoSegment->getAutoTarget(); + if (contact and (contact != currentContact)) { + if (exploreds.find(contact) == exploreds.end()) + stack.push_back( contact ); + } + + continue; + } + + if (autoSegment->isHorizontal() xor (flags & Flags::Horizontal)) continue; + + cdebug_log(145,0) << "| " << autoSegment << endl; + + if (flags & Flags::Superior) { + if (autoSegment->getTargetU() > axis) { cdebug_tabw(145,-1); return true; } + } else { + if (autoSegment->getSourceU() < axis) { cdebug_tabw(145,-1); return true; } + } + } + } + + cdebug_tabw(145,-1); + return false; + } + + +#if THIS_IS_DISABLED + unsigned int AutoSegment::getPerpandicularState ( AutoContact* contact + , AutoSegment* source + , AutoSegment* current + , bool isHorizontalMaster + , const Layer* masterLayer ) + { + unsigned int state = 0; + + bool sourcePerpandicular = arePerpandiculars ( isHorizontalMaster, source ); + bool currentPerpandicular = arePerpandiculars ( isHorizontalMaster, current ); + bool contactAlignate + = (contact->isHAlignate() and current->isHorizontal() and isHorizontalMaster) + or (contact->isVAlignate() and !current->isHorizontal() and !isHorizontalMaster); + + if ( not currentPerpandicular and masterLayer and (masterLayer != current->getLayer()) ) + state |= ParallelAndLayerChange; + + if ( currentPerpandicular and !current->isCollapsed() ) + state |= PerpandicularAny; + + if ( sourcePerpandicular ) { + // Source segment is perpandicular to master. + if ( currentPerpandicular and !current->isCollapsed() ) + state |= PerpandicularIndirect; + } else { + // Source segment is parallel to master. + if ( not (currentPerpandicular and current->isCollapsed()) and not contactAlignate ) { + // Current segment is parallel OR expanded. + state |= ParallelOrExpanded; + } + } + + return state; + } +#endif + + + void AutoSegment::getTopologicalInfos ( AutoSegment* seed + , vector& aligneds + , vector& perpandiculars + , DbU::Unit& leftBound + , DbU::Unit& rightBound + ) + { + cdebug_log(145,1) << "getTopologicalInfos() - " << seed << endl; + + leftBound = DbU::Max; + rightBound = DbU::Min; + + AutoSegmentStack stack; + + stack.push( seed->getAutoSource(), seed ); + stack.push( seed->getAutoTarget(), seed ); + + while ( not stack.isEmpty() ) { + AutoContact* sourceContact = stack.getAutoContact(); + AutoSegment* sourceSegment = stack.getAutoSegment(); + + stack.pop(); + + DbU::Unit constraint; + + if (seed->isHorizontal()) constraint = sourceContact->getCBXMax(); + else constraint = sourceContact->getCBYMax(); + if (constraint < leftBound) leftBound = constraint; + + if (seed->isHorizontal()) constraint = sourceContact->getCBXMin(); + else constraint = sourceContact->getCBYMin(); + if (constraint > rightBound) rightBound = constraint; + + cdebug_log(149,0) << "Segments of: " << sourceContact << endl; + LocatorHelper helper (sourceContact, Flags::Horizontal|Flags::WithPerpands); + for ( ; helper.isValid() ; helper.progress() ) { + AutoSegment* currentSegment = helper.getSegment(); + cdebug_log(149,0) << "Looking for: " << currentSegment << endl; + if (currentSegment == sourceSegment) continue; + + if (AutoSegment::areAlignedsAndDiffLayer(currentSegment,seed)) { + cerr << Error("Aligned segments not in same layer\n" + " %s\n" + " %s." + ,getString(seed).c_str() + ,getString(currentSegment).c_str()) << endl; + continue; + } + + if (AutoSegment::areAligneds(currentSegment,seed)) { + aligneds.push_back( currentSegment ); + + AutoContact* targetContact = currentSegment->getOppositeAnchor( sourceContact ); + cdebug_log(149,0) << "Target: " << targetContact << endl; + if (targetContact) { + if ( (seed->isHorizontal() and sourceContact->isHTee()) + or (seed->isVertical () and sourceContact->isVTee()) ) { + cdebug_log(149,0) << "Stacking target. " << endl; + stack.push( targetContact, currentSegment ); + } + } + } else { + cdebug_log(149,0) << "| perpandicular " << currentSegment << endl; + perpandiculars.push_back( currentSegment ); + } + } + } + + cdebug_tabw(145,-1); + } + + + int AutoSegment::getTerminalCount ( AutoSegment* seed, vector& collapseds ) + { + cdebug_log(145,0) << "getTerminalCount() - " << seed << " (+collapseds)" << endl; + + int count = 0; + for ( size_t i=0 ; i < collapseds.size() ; i++ ) { + if (collapseds[i]->isStrongTerminal()) + count++; + } + if (seed->getAutoSource()->isTerminal()) count++; + if (seed->getAutoTarget()->isTerminal()) count++; + + return count; + } + + +} // End of Anabatic namespace. diff --git a/anabatic/src/AutoSegments.cpp b/anabatic/src/AutoSegments.cpp new file mode 100644 index 00000000..304ac2bc --- /dev/null +++ b/anabatic/src/AutoSegments.cpp @@ -0,0 +1,512 @@ +// -*- 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 | +// | A n a b a t i c - Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./AutoSegments.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/Error.h" +#include "anabatic/AutoContact.h" +#include "anabatic/AutoSegment.h" + + +namespace Anabatic { + + using namespace std; + using Hurricane::tab; + using Hurricane::_TName; + using Hurricane::Error; + using Hurricane::ForEachIterator; + using Hurricane::Hook; + using Hurricane::Contact; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoSegmentStack". + + void AutoSegmentStack::push ( AutoContact* contact, AutoSegment* segment ) + { + cdebug_log(145,0) << "Stacking " << contact << " + " << segment << endl; + push_back( make_pair(contact,segment) ); + } + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoSegments_OnContact". + + AutoSegments_OnContact::Locator::Locator ( AutoSegment* master, Contact* contact ) + : AutoSegmentHL() + , _master (master) + , _element (NULL) + { + _hook = contact->getBodyHook()->getPreviousMasterHook(); + progress(); + } + + + AutoSegmentHL* AutoSegments_OnContact::Locator::getClone () const + { return new Locator(*this); } + + + AutoSegment* AutoSegments_OnContact::Locator::getElement () const + { return _element; } + + + bool AutoSegments_OnContact::Locator::isValid () const + { return !_hook; } + + + void AutoSegments_OnContact::Locator::progress () + { + cdebug_log(145,0) << "AutoSegments_OnContact::Locator::progress()" << endl; + + while (_hook and not _hook->isMaster()) { + _hook = _hook->getNextHook(); + _element = NULL; + + if ( _hook->isMaster() ) { _hook = NULL; break; } + + Segment* segment = dynamic_cast( _hook->getComponent() ); + if (segment) _element = Session::lookup( segment ); + + if (not _element or (_element == _master)) continue; + + break; + } + } + + + string AutoSegments_OnContact::Locator::_getString () const + { + string s = "<" + _TName("AutoSegments_OnContact::Locator") + + getString(_element) + + ">"; + return s; + } + + + AutoSegmentHC* AutoSegments_OnContact::getClone () const + { return new AutoSegments_OnContact(*this); } + + + AutoSegmentHL* AutoSegments_OnContact::getLocator () const + { return new Locator(_master,_contact); } + + + string AutoSegments_OnContact::_getString () const + { + string s = "<" + _TName("AutoSegments_OnContact") + " " + + getString(_master) + + ">"; + return s; + } + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_Aligneds". + + AutoSegments_Aligneds::Locator::Locator ( AutoSegment* segment, unsigned int flags ) + : AutoSegmentHL() + , _flags (flags) + , _master(segment) + , _stack () + { + if (not _master) return; + _flags |= (_master->isHorizontal()) ? Flags::Horizontal : Flags::Vertical; + + cdebug_log(145,0) << "AutoSegments_Aligneds::Locator::Locator() - _flags:" << _flags << endl; + + AutoContact* contact = segment->getAutoSource(); + if (contact) _stack.push( contact, segment ); + + contact = segment->getAutoTarget(); + if (contact) _stack.push( contact, segment ); + + progress(); + } + + + AutoSegmentHL* AutoSegments_Aligneds::Locator::getClone () const + { return new Locator(*this); } + + + bool AutoSegments_Aligneds::Locator::isValid () const + { return not _stack.isEmpty(); } + + + void AutoSegments_Aligneds::Locator::progress () + { + cdebug_log(145,0) << "AutoSegments_Aligneds::Locator::progress()" << endl; + + while (not _stack.isEmpty()) { + AutoContact* sourceContact = _stack.getAutoContact (); + AutoSegment* sourceSegment = _stack.getAutoSegment (); + + _stack.pop (); + + LocatorHelper helper (sourceContact, _flags); + for ( ; helper.isValid() ; helper.progress() ) { + AutoSegment* currentSegment = helper.getSegment(); + cdebug_log(145,0) << "Looking at: " << currentSegment << endl; + + if (currentSegment == sourceSegment) continue; + + if ( (not (_flags & Flags::NoCheckLayer)) + and AutoSegment::areAlignedsAndDiffLayer(currentSegment,_master)) { + cerr << Error("Aligned segments not in same layer (aligneds locator)\n" + " %s\n" + " %s." + ,getString(_master).c_str() + ,getString(currentSegment).c_str()) << endl; + continue; + } + + AutoContact* targetContact = currentSegment->getOppositeAnchor( sourceContact ); + if (targetContact) _stack.push( targetContact, currentSegment ); + } + + if (_stack.getAutoSegment() == _master) continue; + break; + } + } + + + string AutoSegments_Aligneds::Locator::_getString () const + { + string s = "<" + _TName("AutoSegments_Aligneds::Locator") + ">"; + return s; + } + + + AutoSegmentHC* AutoSegments_Aligneds::getClone () const + { return new AutoSegments_Aligneds(*this); } + + + AutoSegmentHL* AutoSegments_Aligneds::getLocator () const + { return new Locator(_segment,_flags); } + + + AutoSegment* AutoSegments_Aligneds::Locator::getElement () const + { return _stack.getAutoSegment(); } + + + string AutoSegments_Aligneds::_getString () const + { + string s = "<" + _TName("AutoSegments_Aligneds") + " " + + getString(_segment) + + ">"; + return s; + } + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_Perpandiculars". + + AutoSegments_Perpandiculars::Locator::Locator ( AutoSegment* master ) + : AutoSegmentHL() + , _flags (Flags::WithPerpands) + , _master (master) + , _stack () + , _perpandiculars() + { + cdebug_log(145,0) << "AutoSegments_Perpandiculars::Locator::Locator()" << endl; + cdebug_log(145,0) << " " << _master << endl; + + if (not _master) return; + if (_master->isHorizontal()) _flags |= Flags::Horizontal; + else _flags |= Flags::Vertical; + + AutoContact* contact = _master->getAutoSource(); + if ( contact ) _stack.push( contact, _master ); + + contact = _master->getAutoTarget(); + if ( contact ) _stack.push( contact, _master ); + + progress(); + } + + + AutoSegment* AutoSegments_Perpandiculars::Locator::getElement () const + { + if (_perpandiculars.empty()) return NULL; + return _perpandiculars.back(); + } + + + void AutoSegments_Perpandiculars::Locator::progress () + { + cdebug_log(145,0) << "AutoSegments_Perpandiculars::Locator::progress()" << endl; + + if (not _perpandiculars.empty()) _perpandiculars.pop_back(); + if (not _perpandiculars.empty()) return; + + while ( not _stack.isEmpty() ) { + AutoContact* sourceContact = _stack.getAutoContact(); + AutoSegment* sourceSegment = _stack.getAutoSegment(); + + _stack.pop(); + + LocatorHelper helper (sourceContact, _flags); + for ( ; helper.isValid() ; helper.progress() ) { + AutoSegment* currentSegment = helper.getSegment(); + if (currentSegment == sourceSegment) continue; + + if (AutoSegment::areAligneds(currentSegment,_master)) { + AutoContact* targetContact = currentSegment->getOppositeAnchor( sourceContact ); + if (targetContact) { + if ( (_master->isHorizontal() and sourceContact->isHTee()) + or (_master->isVertical () and sourceContact->isVTee()) ) { + if (AutoSegment::areAlignedsAndDiffLayer(currentSegment,_master)) { + cerr << Error("Aligned segments not in same layer (perpandicular locator)\n" + " %s\n" + " %s." + ,getString(_master).c_str() + ,getString(currentSegment).c_str()) << endl; + continue; + } + + cdebug_log(145,0) << "Stacking target. " << endl; + _stack.push( targetContact, currentSegment ); + } + } + } else { + _perpandiculars.push_back( currentSegment ); + } + } + + if (_stack.isEmpty()) break; + if (_stack.getAutoSegment() == _master) continue; + if (not _perpandiculars.empty()) break; + } + } + + + AutoSegmentHL* AutoSegments_Perpandiculars::Locator::getClone () const + { return new Locator(*this); } + + + bool AutoSegments_Perpandiculars::Locator::isValid () const + { return not _perpandiculars.empty(); } + + + AutoSegmentHC* AutoSegments_Perpandiculars::getClone () const + { return new AutoSegments_Perpandiculars(*this); } + + + AutoSegmentHL* AutoSegments_Perpandiculars::getLocator () const + { return new Locator(_segment); } + + + string AutoSegments_Perpandiculars::Locator::_getString () const + { + string s = "<" + _TName("AutoSegments_Perpandiculars::Locator") + ">"; + return s; + } + + + string AutoSegments_Perpandiculars::_getString () const + { + string s = "<" + _TName("AutoSegments_Perpandiculars") + " " + + getString(_segment) + + ">"; + return s; + } + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_AnchorOnGCell". + + AutoSegments_AnchorOnGCell::Locator::Locator ( GCell* fcell, unsigned int flags ) + : AutoSegmentHL() + , _flags (flags) + , _itContact (fcell->getContacts().begin()) + , _itEnd (fcell->getContacts().end()) + , _hookLocator(NULL) + , _element (NULL) + { progress(); } + + + AutoSegments_AnchorOnGCell::Locator::~Locator () + { if (_hookLocator) delete _hookLocator; } + + + AutoSegment* AutoSegments_AnchorOnGCell::Locator::getElement () const + { return _element; } + + + AutoSegmentHL* AutoSegments_AnchorOnGCell::Locator::getClone () const + { return new Locator(*this); } + + + bool AutoSegments_AnchorOnGCell::Locator::isValid () const + { return _element != NULL; } + + + void AutoSegments_AnchorOnGCell::Locator::progress () + { + cdebug_log(145,1) << "AutoSegments_AnchorOnGCell::Locator::progress()" << endl; + + while ( true ) { + if (_hookLocator == NULL) { + if (_itContact == _itEnd) { + cdebug_log(145,0) << "No more AutoContacts" << endl; + cdebug_tabw(145,-1); + return; + } + + cdebug_log(145,0) << *_itContact << endl; + + _hookLocator = (*_itContact)->getBodyHook()->getSlaveHooks().getLocator(); + _itContact++; + } else { + _hookLocator->progress(); + } + + while ( _hookLocator->isValid() ) { + cdebug_log(145,0) << _hookLocator->getElement() << endl; + Hook* hook = dynamic_cast(_hookLocator->getElement()); + if (hook) { + if ( ((_flags & Flags::Source) and (dynamic_cast(hook))) + or ((_flags & Flags::Target) and (dynamic_cast(hook))) ) { + _element = Session::lookup( static_cast(hook->getComponent()) ); + + if (_element->isHorizontal()) { + if (_flags & Flags::Horizontal) { cdebug_tabw(145,-1); return; } + } else + if (_flags & Flags::Vertical) { cdebug_tabw(145,-1); return; } + } + } + _hookLocator->progress(); + } + _hookLocator = NULL; + _element = NULL; + } + + cdebug_tabw(145,-1); + } + + + string AutoSegments_AnchorOnGCell::Locator::_getString () const + { + string s = "<" + _TName("AutoSegments_AnchorOnGCell::Locator") + ">"; + return s; + } + + + AutoSegmentHC* AutoSegments_AnchorOnGCell::getClone () const + { return new AutoSegments_AnchorOnGCell(*this); } + + + AutoSegmentHL* AutoSegments_AnchorOnGCell::getLocator () const + { return new Locator(_fcell,_flags); } + + + string AutoSegments_AnchorOnGCell::_getString () const + { + string s = "<" + _TName("AutoSegments_AnchorOnGCell") + " " + + getString(_fcell) + + ">"; + return s; + } + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoSegments_CachedOnContact". + + AutoSegments_CachedOnContact::Locator::Locator ( AutoContact* sourceContact, unsigned int direction ) + : AutoSegmentHL() + , _helper(new LocatorHelper(sourceContact,direction)) + { } + + + AutoSegments_CachedOnContact::Locator::~Locator () + { delete _helper; } + + + AutoSegment* AutoSegments_CachedOnContact::Locator::getElement () const + { return _helper->getSegment(); } + + + AutoSegmentHL* AutoSegments_CachedOnContact::Locator::getClone () const + { return new Locator(*this); } + + + bool AutoSegments_CachedOnContact::Locator::isValid () const + { return _helper->isValid(); } + + + void AutoSegments_CachedOnContact::Locator::progress () + { + cdebug_log(145,0) << "AutoSegments_CachedOnContact::Locator::progress()" << endl; + _helper->progress(); + } + + + AutoSegmentHL* AutoSegments_CachedOnContact::getLocator () const + { return new Locator(_sourceContact,_direction); } + + + AutoSegmentHC* AutoSegments_CachedOnContact::getClone () const + { return new AutoSegments_CachedOnContact(*this); } + + + string AutoSegments_CachedOnContact::Locator::_getString () const + { + string s = "<" + _TName("AutoSegments_CachedOnContact::Locator") + ">"; + return s; + } + + + string AutoSegments_CachedOnContact::_getString () const + { + string s = "<" + _TName("AutoSegments_CachedOnContact") + " " + + getString(_sourceContact) + + ">"; + return s; + } + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_IsAccountable". + + AutoSegmentHF* AutoSegments_IsAccountable::getClone () const + { return new AutoSegments_IsAccountable(); } + + + bool AutoSegments_IsAccountable::accept ( AutoSegment* segment ) const + { return segment->isCanonical(); } + + + string AutoSegments_IsAccountable::_getString () const + { return ""; } + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_InDirection". + + + AutoSegmentHF* AutoSegments_InDirection::getClone () const + { return new AutoSegments_InDirection(_direction); } + + + bool AutoSegments_InDirection::accept ( AutoSegment* segment ) const + { + return ( segment->isHorizontal() and (_direction & Flags::Horizontal) ) + or ( segment->isVertical () and (_direction & Flags::Vertical ) ); + } + + + string AutoSegments_InDirection::_getString () const + { return ""; } + + +} // Anabatic namespace. diff --git a/anabatic/src/AutoVertical.cpp b/anabatic/src/AutoVertical.cpp new file mode 100644 index 00000000..948520f4 --- /dev/null +++ b/anabatic/src/AutoVertical.cpp @@ -0,0 +1,728 @@ +// -*- 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 | +// | A n 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 "anabatic/Configuration.h" +#include "anabatic/AutoContactTurn.h" +#include "anabatic/AutoVertical.h" +#include "anabatic/AutoHorizontal.h" + + +namespace Anabatic { + + using std::min; + using std::max; + using Hurricane::Error; + using Hurricane::Bug; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::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) + { + cdebug_log(145,0) << "CTOR AutoVertical " << this << endl; + cdebug_log(145,0) << " 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() ); + + _gcell = source->getGCell(); + + setOptimalMax( getGCell()->getXMax() ); + resetNativeConstraints( getGCell()->getXMin(), getGCell()->getXMax() ); + + if (getGCell() != target->getGCell()) { + setFlags( SegGlobal ); + + vector gcells; + getGCells( gcells ); + for ( GCell* gcell : gcells ) { + if ( (gcell != getGCell()) and (gcell != target->getGCell()) ) + gcell->addVSegment( this ); + mergeNativeMin( gcell->getXMin() ); + mergeNativeMax( gcell->getXMax() ); + } + } + } + + + void AutoVertical::_preDestroy () + { + cdebug_log(149,1) << "AutoVertical::_preDestroy() - " << endl; + cdebug_log(149,0) << _getString() << endl; + + if ( not Session::doDestroyTool() ) { + vector gcells; + getGCells( gcells ); + for ( GCell* gcell : gcells ) gcell->removeVSegment( this ); + } + + AutoSegment::_preDestroy (); + cdebug_tabw(145,-1); + } + + + AutoVertical::~AutoVertical () + { + if ( Session::doDestroyBaseSegment() and not Session::doDestroyTool() ) { + cdebug_log(149,0) << "~AutoVertical() - " << endl; + _vertical->destroy (); + } + } + + + Interval AutoVertical::getSourceConstraints ( unsigned int flags ) const + { + if (flags & Flags::NativeConstraints) { + 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 & Flags::NativeConstraints) { + 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 + { + constraintMin = getNativeMin(); + constraintMax = getNativeMax(); + + cdebug_log(149,0) << "Native constraints: [" + << DbU::getValueString(constraintMin) << ":" + << DbU::getValueString(constraintMax) << "]" + << endl; + + constraintMin = max ( constraintMin, getUserConstraints().getVMin() ); + constraintMax = min ( constraintMax, getUserConstraints().getVMax() ); + + cdebug_log(149,0) << "Merge with user constraints: " << getUserConstraints() << " [" + << DbU::getValueString(getUserConstraints().getVMin()) << ":" + << DbU::getValueString(getUserConstraints().getVMax()) << "]" + << endl; + + cdebug_log(149,0) << "Resulting constraints: " << " [" + << DbU::getValueString(constraintMin) << ":" + << DbU::getValueString(constraintMax) << "]" + << endl; + + return true; + } + + + unsigned int AutoVertical::getDirection () const + { return Flags::Vertical; } + + + size_t AutoVertical::getGCells ( vector& gcells ) const + { + vector().swap( gcells ); + + DbU::Unit xprobe = getNativeMin(); + GCell* gcell = getAutoSource()->getGCell(); + GCell* end = getAutoTarget()->getGCell(); + + if (gcell->getYMin() > end->getYMin()) std::swap( gcell, end ); + + gcells.push_back( gcell ); + + while ( gcell != end ) { + gcell = gcell->getNorth( xprobe ); + + if (not gcell) { + cerr << Error( "AutoHorizontal::getGCells() : NULL GCell under %s\n" + " begin:%s\n" + " end: %s" + , getString(this).c_str() + , getString(getAutoSource()->getGCell()).c_str() + , getString(getAutoTarget()->getGCell()).c_str() + ) << endl; + break; + } + + gcells.push_back( gcell ); + } + + return gcells.size(); + } + + + bool AutoVertical::_canSlacken () const + { + cdebug_tabw(149,-1); + + Interval sourceSide = getAutoSource()->getGCell()->getSide( Flags::Horizontal ); + Interval targetSide = getAutoTarget()->getGCell()->getSide( Flags::Horizontal ); + 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)) { cdebug_tabw(149,-1); return true; } + if (not targetConstraints.contains(targetSide)) { cdebug_tabw(149,-1); return true; } + + cdebug_tabw(149,-1); + return false; + } + + + bool AutoVertical::_slacken ( unsigned int flags ) + { + cdebug_log(149,1) << "AutoVertical::_slacken() " << this << endl; + + if ( not isStrongTerminal() + or (not (_flags & (SegGlobal|SegWeakGlobal)) and (getLength() < 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; + + bool success = false; + bool slackened = false; + bool halfSlackened = false; + int lowSlack = (flags & Flags::HalfSlacken) ? 3 : 10; + AutoContact* source = getAutoSource(); + AutoSegment* parallel = this; + + if (source->isTerminal()) { + Interval constraints = source->getUConstraints (Flags::Horizontal|Flags::NoGCellShrink); + Interval nativeConstraints = source->getNativeUConstraints(Flags::Horizontal|Flags::NoGCellShrink); + 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(), Flags::NoFlags ); + slackened = true; + } else if (slack < 10) { + halfSlackened = true; + } + + const vector& doglegs = Session::getDoglegs(); + if (doglegs.size() >= 2) { + cdebug_log(149,0) << "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 (Flags::Horizontal|Flags::NoGCellShrink); + Interval nativeConstraints = target->getNativeUConstraints(Flags::Horizontal|Flags::NoGCellShrink); + 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(), Flags::NoFlags ); + slackened = true; + } else if (slack < 10) { + halfSlackened = true; + } + + const vector& doglegs = Session::getDoglegs(); + if (doglegs.size() >= 2) { + cdebug_log(149,0) << "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 ); + } + cdebug_tabw(149,-1); + + return success; + } + + + void AutoVertical::_setAxis ( DbU::Unit axis ) + { + setFlags( SegAxisSet ); + + if (_vertical->getX() == axis) return; + + cdebug_log(149,0) << "_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()) { + cdebug_log(145,0) << "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()); + } + + + void AutoVertical::updateNativeConstraints () + { + vector gcells; + getGCells( gcells ); + + resetNativeConstraints( gcells[0]->getXMin(), gcells[0]->getXMax() ); + for ( GCell* gcell : gcells ) { + mergeNativeMin( gcell->getXMin() ); + mergeNativeMax( gcell->getXMax() ); + } + } + + + 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 THIS_IS_DISABLED + 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); +#endif + return false; + } + + + bool AutoVertical::canMoveURight ( float reserve ) const + { +#if THIS_IS_DISABLED + 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); +#endif + return false; + } + + + bool AutoVertical::moveULeft () + { +#if THIS_IS_DISABLED + 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( Anabatic::SegGlobal ); + } else { + if (perpandicular->getAutoSource() == autoSource) { + begin->addHSegment( perpandicular ); + } else { + if (begin->getLeft() == perpandicular->getAutoSource()->getGCell()) { + perpandicular->unsetFlags( Anabatic::SegGlobal ); + } else + begin->getLeft()->removeHSegment( perpandicular ); + } + } + + perpandicular = autoTarget->getSegment(0); + if (perpandicular->isLocal()) { + perpandicular->setFlags( Anabatic::SegGlobal ); + } else { + if (perpandicular->getAutoSource() == autoTarget) { + end->addHSegment( perpandicular ); + } else { + if (end->getLeft() == perpandicular->getAutoSource()->getGCell()) { + perpandicular->unsetFlags( Anabatic::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( Flags::Horizontal ).getVMax(); + setAxis( x ); + + return true; +#endif + return false; + } + + + bool AutoVertical::moveURight () + { +#if THIS_IS_DISABLED + cdebug_log(149,0) << "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( Anabatic::SegGlobal ); + } else { + if (perpandicular->getAutoTarget() == autoSource) { + begin->addHSegment( perpandicular ); + } else { + if (begin->getRight() == perpandicular->getAutoTarget()->getGCell()) { + perpandicular->unsetFlags( Anabatic::SegGlobal ); + } else + begin->getRight()->removeHSegment( perpandicular ); + } + } + + perpandicular = autoTarget->getSegment(0); + if (perpandicular->isLocal()) { + perpandicular->setFlags( Anabatic::SegGlobal ); + } else { + if (perpandicular->getAutoTarget() == autoTarget) { + end->addHSegment( perpandicular ); + } else { + if (end->getRight() == perpandicular->getAutoTarget()->getGCell()) { + perpandicular->unsetFlags( Anabatic::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( Flags::Horizontal ).getVMin(); + setAxis( x ); + + cdebug_log(149,0) << "Moved to axis: " << DbU::getValueString(x) << endl; + + return true; +#endif + return false; + } + + + unsigned int AutoVertical::_makeDogleg ( GCell* doglegGCell, unsigned int flags ) + { + cdebug_log(149,0) << "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->getYMin()) / 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->getNorth( getNativeMin() ); + } 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( Flags::Topology ); + autoTarget->invalidate( Flags::Topology ); + AutoContact* dlContact1 = AutoContactTurn::create( doglegGCell, _vertical->getNet(), contactLayer ); + cdebug_log(149,0) << dlContact1 << endl; + AutoContact* dlContact2 = AutoContactTurn::create( doglegGCell, _vertical->getNet(), contactLayer ); + cdebug_log(149,0) << dlContact2 << endl; + AutoSegment* segment1 = AutoSegment::create( dlContact1 , dlContact2, Flags::Horizontal ); + cdebug_log(149,0) << segment1 << endl; + segment1->setLayer( doglegLayer ); + segment1->_setAxis( doglegAxis ); + segment1->setFlags( SegDogleg|SegSlackened|SegCanonical|SegNotAligned ); + cdebug_log(149,0) << "New " << dlContact1->base() << "." << endl; + cdebug_log(149,0) << "New " << dlContact2->base() << "." << endl; + Session::dogleg( segment1 ); + + targetAttach( dlContact1 ); + AutoSegment* segment2 = AutoVertical::create ( dlContact2, autoTarget, Flags::Vertical ); + 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 ); + } + + cdebug_log(149,0) << "Session::dogleg[x+1] perpand: " << segment1 << endl; + cdebug_log(149,0) << "Session::dogleg[x+2] new paral: " << segment2 << endl; + cdebug_log(149,0) << "Session::dogleg[x+0] original: " << this << endl; + + dlContact1->updateCache(); + dlContact2->updateCache(); + //autoTarget->updateCache(); + + segment2->canonize( flags ); + if (not isCanonical()) canonize( flags ); + + updateNativeConstraints(); + segment2->updateNativeConstraints(); + + return (upLayer) ? Flags::AboveLayer : Flags::BelowLayer; + } + + + 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 Anabatic namespace. diff --git a/anabatic/src/CMakeLists.txt b/anabatic/src/CMakeLists.txt index e7c0a20f..59757952 100644 --- a/anabatic/src/CMakeLists.txt +++ b/anabatic/src/CMakeLists.txt @@ -20,6 +20,16 @@ endif ( CHECK_DETERMINISM ) anabatic/AnabaticEngine.h anabatic/GraphicAnabaticEngine.h anabatic/Dijkstra.h + + anabatic/AutoContact.h + anabatic/AutoContactTerminal.h + anabatic/AutoContactTurn.h + anabatic/AutoContactHTee.h + anabatic/AutoContactVTee.h + anabatic/AutoSegment.h anabatic/AutoSegments.h + anabatic/AutoHorizontal.h + anabatic/AutoVertical.h + anabatic/Session.h ) set( mocIncludes anabatic/GraphicAnabaticEngine.h ) set( pyIncludes anabatic/PyAnabaticEngine.h @@ -35,6 +45,19 @@ endif ( CHECK_DETERMINISM ) GlobalRoute.cpp GraphicAnabaticEngine.cpp Dijkstra.cpp + + AutoContact.cpp + AutoContactTerminal.cpp + AutoContactTurn.cpp + AutoContactHTee.cpp + AutoContactVTee.cpp + AutoSegment.cpp AutoSegments.cpp + AutoHorizontal.cpp + AutoVertical.cpp + Session.cpp + NetConstraints.cpp + NetOptimals.cpp + LoadGlobalRouting.cpp ) set( pyCpps PyAnabaticEngine.cpp PyGraphicAnabaticEngine.cpp diff --git a/anabatic/src/Configuration.cpp b/anabatic/src/Configuration.cpp index cc2d61dc..e6df4f18 100644 --- a/anabatic/src/Configuration.cpp +++ b/anabatic/src/Configuration.cpp @@ -70,6 +70,9 @@ namespace Anabatic { , _cg (NULL) , _rg (NULL) , _extensionCaps () + , _saturateRatio (Cfg::getParamPercentage("katabatic.saturateRatio",80.0)->asDouble()) + , _saturateRp (Cfg::getParamInt ("katabatic.saturateRp" ,8 )->asInt()) + , _globalThreshold(0) , _allowedDepth (0) , _edgeLength (DbU::fromLambda(Cfg::getParamInt("anabatic.edgeLength",24)->asInt())) , _edgeWidth (DbU::fromLambda(Cfg::getParamInt("anabatic.edgeWidth" , 4)->asInt())) @@ -117,15 +120,17 @@ namespace Anabatic { ConfigurationConcrete::ConfigurationConcrete ( const ConfigurationConcrete& other ) : Configuration() - , _gmetalh (other._gmetalh) - , _gmetalv (other._gmetalv) - , _gcontact (other._gcontact) - , _cg (NULL) - , _rg (NULL) - , _extensionCaps(other._extensionCaps) - , _allowedDepth (other._allowedDepth) - , _edgeCostH (other._edgeCostH) - , _edgeCostK (other._edgeCostK) + , _gmetalh (other._gmetalh) + , _gmetalv (other._gmetalv) + , _gcontact (other._gcontact) + , _cg (NULL) + , _rg (NULL) + , _extensionCaps (other._extensionCaps) + , _saturateRatio (other._saturateRatio) + , _globalThreshold(other._globalThreshold) + , _allowedDepth (other._allowedDepth) + , _edgeCostH (other._edgeCostH) + , _edgeCostK (other._edgeCostK) { if (other._cg) _cg = other._cg->getClone(); if (other._rg) _rg = other._rg->getClone(); @@ -220,11 +225,23 @@ namespace Anabatic { { return getDirection( getLayerDepth(layer) ); } + float ConfigurationConcrete::getSaturateRatio () const + { return _saturateRatio; } + + + size_t ConfigurationConcrete::getSaturateRp () const + { return _saturateRp; } + + + DbU::Unit ConfigurationConcrete::getGlobalThreshold () const + { return _globalThreshold; } + + DbU::Unit ConfigurationConcrete::getPitch ( size_t depth, Flags flags ) const { if (flags == Flags::NoFlags) return _rg->getLayerPitch(depth); - if (flags & Flags::PitchAbove) { + if (flags & Flags::AboveLayer) { if (depth < getAllowedDepth()) return _rg->getLayerPitch( depth + 1 ); else { @@ -233,7 +250,7 @@ namespace Anabatic { } } - if (flags & Flags::PitchBelow) { + if (flags & Flags::BelowLayer) { if ( (depth > 0) and (_rg->getLayerType(depth-1) != Constant::PinOnly) ) return _rg->getLayerPitch( depth - 1 ); else { @@ -282,6 +299,18 @@ namespace Anabatic { } + void ConfigurationConcrete::setSaturateRatio ( float ratio ) + { _saturateRatio = ratio; } + + + void ConfigurationConcrete::setSaturateRp ( size_t threshold ) + { _saturateRp = threshold; } + + + void ConfigurationConcrete::setGlobalThreshold ( DbU::Unit threshold ) + { _globalThreshold = threshold; } + + DbU::Unit ConfigurationConcrete::getEdgeLength () const { return _edgeLength; } diff --git a/anabatic/src/Constants.cpp b/anabatic/src/Constants.cpp index 8e39a856..6b300503 100644 --- a/anabatic/src/Constants.cpp +++ b/anabatic/src/Constants.cpp @@ -1,4 +1,4 @@ -// -*- C++ -*- +// -*- mode: C++; explicit-buffer-name: "Constants.cpp" -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2016-2016, All Rights Reserved @@ -36,17 +36,17 @@ namespace Anabatic { string s = ""; s += (_flags & Horizontal ) ? 'h' : '-'; s += (_flags & Vertical ) ? 'v' : '-'; - s += (_flags & SourceGCell ) ? 'S' : '-'; - s += (_flags & TargetGCell ) ? 'T' : '-'; + s += (_flags & Source ) ? 'S' : '-'; + s += (_flags & Target ) ? 'T' : '-'; s += (_flags & DeviceGCell ) ? 'd' : '-'; s += (_flags & ChannelGCell) ? 'c' : '-'; s += (_flags & StrutGCell ) ? 's' : '-'; s += (_flags & MatrixGCell ) ? 'm' : '-'; s += ","; s += (_flags & Invalidated ) ? 'i' : '-'; - s += (_flags & Destroy ) ? 'D' : '-'; - s += (_flags & PitchAbove ) ? 'A' : '-'; - s += (_flags & PitchBelow ) ? 'B' : '-'; + s += (_flags & DestroyGCell) ? 'D' : '-'; + s += (_flags & AboveLayer ) ? 'A' : '-'; + s += (_flags & BelowLayer ) ? 'B' : '-'; return s; } diff --git a/anabatic/src/Edge.cpp b/anabatic/src/Edge.cpp index 114c89c7..1727c705 100644 --- a/anabatic/src/Edge.cpp +++ b/anabatic/src/Edge.cpp @@ -101,8 +101,8 @@ namespace Anabatic { void Edge::_preDestroy () { - _source->_remove( this, _flags|Flags::SourceGCell ); - _target->_remove( this, _flags|Flags::TargetGCell ); + _source->_remove( this, _flags|Flags::Source ); + _target->_remove( this, _flags|Flags::Target ); Super::_preDestroy(); } diff --git a/anabatic/src/GCell.cpp b/anabatic/src/GCell.cpp index 33c00627..849b9cc7 100644 --- a/anabatic/src/GCell.cpp +++ b/anabatic/src/GCell.cpp @@ -15,36 +15,302 @@ #include +#include "hurricane/Bug.h" +#include "hurricane/Warning.h" #include "hurricane/Contact.h" +#include "hurricane/RoutingPad.h" #include "hurricane/UpdateSession.h" #include "anabatic/GCell.h" #include "anabatic/AnabaticEngine.h" +namespace { + + using namespace std; + using namespace Hurricane; + using namespace Anabatic; + + +// ------------------------------------------------------------------- +// Class : "::UsedFragments". + + class UsedFragments { + private: + class Axiss; + + class Axis { + public: + Axis ( UsedFragments*, DbU::Unit axis ); + inline DbU::Unit getAxis () const; + inline UsedFragments* getUsedFragments () const; + void merge ( const Interval& mergeChunk ); + Interval getMaxFree () const; + private: + UsedFragments* _ufragments; + DbU::Unit _axis; + list _chunks; + }; + + private: + class AxisCompare { + public: + bool operator() ( const Axis* lhs, const Axis* rhs ); + }; + + class AxisMatch : public unary_function { + public: + inline AxisMatch ( DbU::Unit axis ); + inline bool operator() ( const Axis* ); + private: + DbU::Unit _axis; + }; + + public: + UsedFragments (); + ~UsedFragments (); + inline DbU::Unit getPitch () const; + inline DbU::Unit getMin () const; + inline DbU::Unit getMax () const; + Interval getMaxFree () const; + inline void setSpan ( DbU::Unit min, DbU::Unit max ); + inline void setCapacity ( size_t ); + inline void incGlobals ( size_t count=1 ); + inline void setPitch ( DbU::Unit ); + void merge ( DbU::Unit axis, const Interval& ); + private: + DbU::Unit _pitch; + vector _axiss; + Interval _span; + size_t _capacity; + size_t _globals; + }; + + + UsedFragments::Axis::Axis ( UsedFragments* ufragments, DbU::Unit axis ) + : _ufragments(ufragments) + , _axis (axis) + , _chunks () + { + merge( Interval( ufragments->getMin()-ufragments->getPitch(), ufragments->getMin() ) ); + merge( Interval( ufragments->getMax(), ufragments->getMax()+ufragments->getPitch() ) ); + } + + inline DbU::Unit UsedFragments::Axis::getAxis () const { return _axis; } + inline UsedFragments* UsedFragments::Axis::getUsedFragments () const { return _ufragments; } + + + void UsedFragments::Axis::merge ( const Interval& chunkMerge ) + { + // cerr << " Merge @" << DbU::getValueString(_axis) + // << " " << chunkMerge << endl; + + list::iterator imerge = _chunks.end(); + list::iterator ichunk = _chunks.begin(); + + while ( ichunk != _chunks.end() ) { + if (chunkMerge.getVMax() < (*ichunk).getVMin()) break; + + if (chunkMerge.intersect(*ichunk)) { + if (imerge == _chunks.end()) { + imerge = ichunk; + (*imerge).merge( chunkMerge ); + } else { + (*imerge).merge( *ichunk ); + ichunk = _chunks.erase( ichunk ); + continue; + } + } + ichunk++; + } + + if (imerge == _chunks.end()) { + _chunks.insert( ichunk, chunkMerge ); + } + } + + + Interval UsedFragments::Axis::getMaxFree () const + { + list::const_iterator ichunk = _chunks.begin(); + list::const_iterator iend = --_chunks.end(); + + Interval maxFree; + for ( ; ichunk != iend ; ++ichunk ) { + list::const_iterator inext = ichunk; + ++inext; + + if (inext == iend) break; + + Interval currentFree ( (*ichunk).getVMax(), (*inext).getVMin() ); + if (currentFree.getSize() > maxFree.getSize()) + maxFree = currentFree; + + // cerr << " @" << DbU::getValueString(_axis) + // << " before:" << *ichunk << " after:" << *inext + // << " size:" << DbU::getValueString(currentFree.getSize()) << endl; + } + + return maxFree; + } + + + inline bool UsedFragments::AxisCompare::operator() ( const Axis* lhs, const Axis* rhs ) + { + if (lhs->getAxis () < rhs->getAxis ()) return true; + return false; + } + + + inline UsedFragments::AxisMatch::AxisMatch ( DbU::Unit axis ) + : _axis(axis) + { } + + + inline bool UsedFragments::AxisMatch::operator() ( const Axis* axis ) + { return (axis->getAxis() == _axis); } + + + UsedFragments::UsedFragments () + : _pitch (0) + , _axiss () + , _span (false) + , _capacity(0) + , _globals (0) + { } + + + UsedFragments::~UsedFragments () + { + while ( not _axiss.empty() ) { + delete (*_axiss.begin()); + _axiss.erase( _axiss.begin() ); + } + } + + + inline DbU::Unit UsedFragments::getPitch () const { return _pitch; } + inline DbU::Unit UsedFragments::getMin () const { return _span.getVMin(); } + inline DbU::Unit UsedFragments::getMax () const { return _span.getVMax(); } + inline void UsedFragments::setPitch ( DbU::Unit pitch ) { _pitch=pitch; } + inline void UsedFragments::setSpan ( DbU::Unit min, DbU::Unit max ) { _span=Interval(min,max); } + inline void UsedFragments::setCapacity ( size_t capacity ) { _capacity=capacity; } + inline void UsedFragments::incGlobals ( size_t count ) { _globals+=count; } + + + void UsedFragments::merge ( DbU::Unit axis, const Interval& chunkMerge ) + { + Interval restrict = chunkMerge.getIntersection(_span); + if (restrict.isEmpty()) return; + + vector::iterator iaxis = find_if( _axiss.begin(), _axiss.end(), AxisMatch(axis) ); + + Axis* paxis = NULL; + if (iaxis == _axiss.end()) { + paxis = new Axis(this,axis); + _axiss.push_back ( paxis ); + stable_sort( _axiss.begin(), _axiss.end(), AxisCompare() ); + } else { + paxis = *iaxis; + } + + paxis->merge( restrict ); + } + + + Interval UsedFragments::getMaxFree () const + { + //cerr << "capacity:" << _capacity << " _globals:" << _globals << " _axiss:" << _axiss.size() << endl; + if (_capacity > _globals + _axiss.size() + 1) return _span; + + Interval maxFree; + vector::const_iterator iaxis = _axiss.begin(); + for ( ; iaxis != _axiss.end() ; ++iaxis ) { + Interval axisMaxFree = (*iaxis)->getMaxFree(); + if (axisMaxFree.getSize() > maxFree.getSize()) + maxFree = axisMaxFree; + } + + return maxFree; + } + + +} // End of anonymous namespace. + + namespace Anabatic { using std::cerr; using std::endl; + using Hurricane::Bug; using Hurricane::Error; + using Hurricane::Warning; using Hurricane::UpdateSession; + using Hurricane::Horizontal; + using Hurricane::Vertical; +// ------------------------------------------------------------------- +// Class : "Katabatic::GCell::CompareByDensity". + + + GCell::CompareByDensity::CompareByDensity ( size_t depth ) + : _depth(depth) + { } + + + bool GCell::CompareByDensity::operator() ( GCell* lhs, GCell* rhs ) + { + float difference = lhs->getDensity(_depth) - rhs->getDensity(_depth); + if (difference != 0.0) return (difference > 0.0); + + return lhs->getId() < rhs->getId(); + } + + +// ------------------------------------------------------------------- +// Class : "Anabatic::GCell". + Name GCell::_extensionName = "Anabatic::GCell"; GCell::GCell ( AnabaticEngine* anabatic, DbU::Unit xmin, DbU::Unit ymin ) : Super(anabatic->getCell()) - , _observable() - , _anabatic (anabatic) - , _flags (Flags::NoFlags) - , _westEdges () - , _eastEdges () - , _southEdges() - , _northEdges() - , _xmin (xmin) - , _ymin (ymin) - , _contacts () - { } + , _observable () + , _anabatic (anabatic) + , _flags (Flags::Invalidated) + , _westEdges () + , _eastEdges () + , _southEdges () + , _northEdges () + , _xmin (xmin) + , _ymin (ymin) + , _gcontacts () + , _vsegments () + , _hsegments () + , _contacts () + , _depth (Session::getRoutingGauge()->getDepth()) + , _pinDepth (0) + , _blockages (new DbU::Unit [_depth]) + , _cDensity (0.0) + , _densities (new float [_depth]) + , _feedthroughs (new float [_depth]) + , _fragmentations(new float [_depth]) + , _globalsCount (new float [_depth]) + , _key (this,1) + { + for ( size_t i=0 ; i<_depth ; i++ ) { + _blockages [i] = 0; + _densities [i] = 0.0; + _feedthroughs [i] = 0.0; + _fragmentations[i] = 0.0; + _globalsCount [i] = 0.0; + + if (Session::getRoutingGauge()->getLayerGauge(i)->getType() == Constant::PinOnly) + ++_pinDepth; + } + + updateKey( 1 ); + } void GCell::_postCreate () @@ -59,11 +325,14 @@ namespace Anabatic { if (not anabatic) throw Error( "GCell::create(): NULL anabatic argument." ); if (not anabatic->getCell()) throw Error( "GCell::create(): AnabaticEngine has no Cell loaded." ); + Session::open( anabatic ); GCell* gcell = new GCell ( anabatic , anabatic->getCell()->getAbutmentBox().getXMin() , anabatic->getCell()->getAbutmentBox().getYMin() ); gcell->_postCreate(); gcell->_revalidate(); + Session::close(); + return gcell; } @@ -77,7 +346,15 @@ namespace Anabatic { GCell::~GCell () - { } + { + cdebug_log(145,0) << "GCell::~GCell()" << endl; + + delete [] _blockages; + delete [] _densities; + delete [] _feedthroughs; + delete [] _fragmentations; + delete [] _globalsCount; + } void GCell::_destroyEdges () @@ -166,7 +443,7 @@ namespace Anabatic { bool GCell::hasGContact ( const Contact* owned ) const { - for ( Contact* contact : _contacts ) { + for ( Contact* contact : _gcontacts ) { if (contact == owned) return true; } return false; @@ -196,7 +473,6 @@ namespace Anabatic { { for ( Edge* edge : _eastEdges ) { GCell* side = edge->getOpposite(this); - cerr << "east @Y: " << DbU::getValueString(y) << " " << side << endl; if (y < side->getYMax()) return side; } return NULL; @@ -390,9 +666,11 @@ namespace Anabatic { bool GCell::doGrid () { + Session::open( getAnabatic() ); + const vector& gcells = getAnabatic()->getGCells(); size_t ibegin = gcells.size(); - DbU::Unit side = getAnabatic()->getConfiguration()->getSliceHeight(); + DbU::Unit side = Session::getSliceHeight(); Interval hspan = getSide( Flags::Horizontal ); Interval vspan = getSide( Flags::Vertical ); @@ -403,6 +681,7 @@ namespace Anabatic { , DbU::getValueString(hspan.getSize()).c_str() , getString(this).c_str() ) << endl; + Session::close(); return false; } @@ -415,8 +694,6 @@ namespace Anabatic { return false; } - //UpdateSession::open(); - GCell* row = this; GCell* column = NULL; DbU::Unit ycut = vspan.getVMin()+side; @@ -443,8 +720,7 @@ namespace Anabatic { } } - //UpdateSession::close(); - + Session::close(); return true; } @@ -563,7 +839,7 @@ namespace Anabatic { Contact* GCell::getGContact ( Net* net ) { - for ( Contact* contact : _contacts ) { + for ( Contact* contact : _gcontacts ) { if (contact->getNet() == net) { cdebug_log(111,0) << "GCell::getGContact(): " << contact << endl; return contact; @@ -578,7 +854,7 @@ namespace Anabatic { , DbU::fromLambda(2.0) , DbU::fromLambda(2.0) ); - _contacts.push_back( contact ); + _gcontacts.push_back( contact ); cdebug_log(111,0) << "GCell::getGContact(): " << contact << endl; return contact; } @@ -586,15 +862,15 @@ namespace Anabatic { bool GCell::unrefContact ( Contact* unref ) { - if (_contacts.empty()) return false; + if (_gcontacts.empty()) return false; - for ( size_t i=0 ; i< _contacts.size() ; ++i ) { - if (_contacts[i] == unref) { - if (_contacts[i]->getSlaveComponents().getLocator()->isValid()) return false; + for ( size_t i=0 ; i< _gcontacts.size() ; ++i ) { + if (_gcontacts[i] == unref) { + if (_gcontacts[i]->getSlaveComponents().getLocator()->isValid()) return false; - std::swap( _contacts[i], _contacts[_contacts.size()-1] ); - _contacts[ _contacts.size()-1 ]->destroy(); - _contacts.pop_back(); + std::swap( _gcontacts[i], _gcontacts[_gcontacts.size()-1] ); + _gcontacts[ _gcontacts.size()-1 ]->destroy(); + _gcontacts.pop_back(); return true; } @@ -604,6 +880,19 @@ namespace Anabatic { } + void GCell::cleanupGlobal () + { + for ( size_t i=0 ; i<_gcontacts.size() ; ) { + if (not _gcontacts[i]->getSlaveComponents().getLocator()->isValid()) { + std::swap( _gcontacts[i], _gcontacts[_gcontacts.size()-1] ); + _gcontacts[ _gcontacts.size()-1 ]->destroy(); + _gcontacts.pop_back(); + } else + ++i; + } + } + + const Name& GCell::getName () const { return _extensionName; } @@ -675,6 +964,601 @@ namespace Anabatic { } + bool GCell::isSaturated ( size_t depth ) const + { return getDensity(depth) > Session::getSaturateRatio(); } + + + Interval GCell::getSide ( unsigned int direction ) const + { + Interval side; + switch ( direction ) { + default: + case Flags::Horizontal: side = Interval(getXMin(),getXMax()); break; + case Flags::Vertical: side = Interval(getYMin(),getYMax()); break; + } + return side; + } + + + AutoSegments GCell::getHStartSegments () + { return new AutoSegments_AnchorOnGCell (this,Flags::EastSide); } + + + AutoSegments GCell::getVStartSegments () + { return new AutoSegments_AnchorOnGCell (this,Flags::NorthSide); } + + + AutoSegments GCell::getHStopSegments () + { return new AutoSegments_AnchorOnGCell (this,Flags::WestSide); } + + + AutoSegments GCell::getVStopSegments () + { return new AutoSegments_AnchorOnGCell (this,Flags::SouthSide); } + + + size_t GCell::getRoutingPads ( set& rps ) + { + for ( size_t i=0 ; i<_contacts.size() ; ++i ) { + RoutingPad* rp = dynamic_cast(_contacts[i]->getAnchor()); + if ( rp ) { + rps.insert ( rp ); + } + } + return rps.size(); + } + + + float GCell::getHCapacity () const + { + int capacity = 0; + if (not _eastEdges.empty()) { + for ( Edge* edge : _eastEdges ) capacity += edge->getCapacity(); + } else { + for ( Edge* edge : _westEdges ) capacity += edge->getCapacity(); + } + return (float)capacity; + } + + + float GCell::getVCapacity () const + { + int capacity = 0; + if (not _northEdges.empty()) { + for ( Edge* edge : _northEdges ) capacity += edge->getCapacity(); + } else { + for ( Edge* edge : _southEdges ) capacity += edge->getCapacity(); + } + return (float)capacity; + } + + + float GCell::getAverageHVDensity () const + { + // Average density of all layers mixeds together. + float density = 0.0; + for ( size_t i=0 ; i<_depth ; i++ ) + density += _densities[i]; + return density / ((float)(_depth-_pinDepth)); + } + + + float GCell::getMaxHVDensity () const + { + // Maximum density between all horizontal vs. all vertical layers. + size_t hplanes = 0; + size_t vplanes = 0; + float hdensity = 0.0; + float vdensity = 0.0; + + for ( size_t i=_pinDepth ; i<_depth ; i++ ) { + if ( i%2 ) { hdensity += _densities[i]; ++hplanes; } + else { vdensity += _densities[i]; ++vplanes; } + } + + if (hplanes) hdensity /= hplanes; + if (vplanes) vdensity /= vplanes; + + return std::max(hdensity, vdensity); + } + + + float GCell::getDensity ( unsigned int flags ) const + { + if (isInvalidated() and not(flags & Flags::NoUpdate)) const_cast(this)->updateDensity(); + + float density = 0.0; + + if (getAnabatic()->getDensityMode() == AverageHVDensity) { + density = getAverageHVDensity(); + } else if (getAnabatic()->getDensityMode() == MaxHVDensity) { + density = getMaxHVDensity(); + } else if (getAnabatic()->getDensityMode() == AverageHDensity) { + size_t hplanes = 0; + float hdensity = 0.0; + + for ( size_t i=_pinDepth ; i<_depth ; i++ ) { + if (i%2) { hdensity += _densities[i]; ++hplanes; } + } + if (hplanes) hdensity /= hplanes; + + density = hdensity; + } else if (getAnabatic()->getDensityMode() == AverageVDensity) { + size_t vplanes = 0; + float vdensity = 0.0; + + for ( size_t i=_pinDepth ; i<_depth ; i++ ) { + if (i%2 == 0) { vdensity += _densities[i]; ++vplanes; } + } + + if (vplanes) vdensity /= vplanes; + + density = vdensity; + } else if (getAnabatic()->getDensityMode() == MaxDensity) { + for ( size_t i=_pinDepth ; i<_depth ; i++ ) { + if (_densities[i] > density) density = _densities[i]; + } + } else if (getAnabatic()->getDensityMode() == MaxHDensity) { + for ( size_t i=_pinDepth ; i<_depth ; i++ ) { + if ((i%2) and (_densities[i] > density)) density = _densities[i]; + } + } else if (getAnabatic()->getDensityMode() == MaxVDensity) { + for ( size_t i=_pinDepth ; i<_depth ; i++ ) { + if ((i%2 == 0) and (_densities[i] > density)) density = _densities[i]; + } + } + + return density; + } + + + void GCell::addBlockage ( size_t depth, DbU::Unit length ) + { + if (depth >= _depth) return; + + _blockages[depth] += length; + _flags |= Flags::Invalidated; + + cdebug_log(149,0) << "GCell:addBlockage() " << this << " " + << depth << ":" << DbU::getValueString(_blockages[depth]) << endl; + } + + + void GCell::removeContact ( AutoContact* ac ) + { + size_t begin = 0; + size_t end = _contacts.size(); + bool found = false; + + for ( ; not found and (begin < end) ; begin++ ) { + if ( _contacts[begin] == ac ) { + _contacts[begin] = _contacts[end-1]; + found = true; + } + } + + if (found) { + cdebug_log(149,0) << "remove " << ac << " from " << this << endl; + _contacts.pop_back(); + } else { + cerr << Bug("%p:%s do not belong to %s." + ,ac->base(),getString(ac).c_str(),_getString().c_str()) << endl; + } + } + + + void GCell::removeHSegment ( AutoSegment* segment ) + { + size_t end = _hsegments.size(); + size_t begin = 0; + + for ( ; begin < end ; begin++ ) { + if (_hsegments[begin] == segment) std::swap( _hsegments[begin], _hsegments[--end] ); + } + + if (_hsegments.size() == end) { + cerr << Bug( "%s do not go through %s." + , getString(segment).c_str() + , _getString().c_str() ) << endl; + return; + } + + if (_hsegments.size() - end > 1) + cerr << Bug( "%s has multiple occurrences of %s." + , _getString().c_str() + , getString(segment).c_str() ) << endl; + + _hsegments.erase( _hsegments.begin() + end, _hsegments.end() ); + } + + + void GCell::removeVSegment ( AutoSegment* segment ) + { + size_t end = _vsegments.size(); + size_t begin = 0; + + for ( ; begin < end ; begin++ ) { + if (_vsegments[begin] == segment) std::swap( _vsegments[begin], _vsegments[--end] ); + } + + if (_vsegments.size() == end) { + cerr << Bug( "%s do not go through %s." + , getString(segment).c_str() + , _getString().c_str() ) << endl; + return; + } + + if (_vsegments.size() - end > 1) + cerr << Bug( "%s has multiple occurrences of %s." + , _getString().c_str() + , getString(segment).c_str() ) << endl; + + _vsegments.erase( _vsegments.begin() + end, _vsegments.end() ); + } + + + void GCell::updateContacts () + { for ( AutoContact* contact : _contacts ) contact->updateGeometry(); } + + + size_t GCell::updateDensity () + { + if (not isInvalidated()) return (isSaturated()) ? 1 : 0; + + _flags.reset( Flags::Saturated ); + + for ( size_t i=0 ; i<_vsegments.size() ; i++ ) { + if ( _vsegments[i] == NULL ) + cerr << "NULL Autosegment at index " << i << endl; + } + + sort( _hsegments.begin(), _hsegments.end(), AutoSegment::CompareByDepthLength() ); + sort( _vsegments.begin(), _vsegments.end(), AutoSegment::CompareByDepthLength() ); + + float hcapacity = getHCapacity (); + float vcapacity = getVCapacity (); + float ccapacity = hcapacity * vcapacity * 4; + DbU::Unit width = getXMax() - getXMin(); + DbU::Unit height = getYMax() - getYMin(); + DbU::Unit hpenalty = 0 /*_box.getWidth () / 3*/; + DbU::Unit vpenalty = 0 /*_box.getHeight() / 3*/; + DbU::Unit uLengths1 [ _depth ]; + DbU::Unit uLengths2 [ _depth ]; + float localCounts [ _depth ]; + vector ufragments ( _depth ); + + for ( size_t i=0 ; i<_depth ; i++ ) { + ufragments[i].setPitch ( Session::getPitch(i) ); + _feedthroughs[i] = 0.0; + uLengths2 [i] = 0; + localCounts [i] = 0.0; + _globalsCount[i] = 0.0; + + switch ( Session::getDirection(i) ) { + case Flags::Horizontal: + ufragments[i].setSpan ( getXMin(), getXMax() ); + ufragments[i].setCapacity( (size_t)hcapacity ); + break; + case Flags::Vertical: + ufragments[i].setSpan ( getYMin(), getYMax() ); + ufragments[i].setCapacity( (size_t)vcapacity ); + break; + } + } + + // Compute wirelength associated to contacts (in DbU::Unit converted to float). + AutoSegment::DepthLengthSet processeds; + for ( AutoContact* contact : _contacts ) { + for ( size_t i=0 ; i<_depth ; i++ ) uLengths1[i] = 0; + contact->getLengths ( uLengths1, processeds ); + for ( size_t i=0 ; i<_depth ; i++ ) { + switch ( Session::getDirection(i) ) { + case Flags::Horizontal: uLengths2[i] += uLengths1[i]+hpenalty; break; + case Flags::Vertical: uLengths2[i] += uLengths1[i]+vpenalty; break; + } + } + } + + // Add the "pass through" horizontal segments. + if ( _hsegments.size() ) { + const Layer* layer = _hsegments[0]->getLayer(); + size_t depth = Session::getRoutingGauge()->getLayerDepth(layer); + size_t count = 0; + for ( size_t i=0 ; i<_hsegments.size() ; i++ ) { + _globalsCount[depth] += 1.0; + ufragments[depth].incGlobals(); + + if ( layer != _hsegments[i]->getLayer() ) { + uLengths2[depth] += count * width; + + count = 0; + layer = _hsegments[i]->getLayer(); + depth = Session::getRoutingGauge()->getLayerDepth(layer); + } + count++; + _feedthroughs[depth] += 1.0; + } + if ( count ) { + uLengths2[depth] += count * width; + } + } + + // Add the "pass through" vertical segments. + if ( _vsegments.size() ) { + const Layer* layer = _vsegments[0]->getLayer(); + size_t depth = Session::getRoutingGauge()->getLayerDepth(layer); + size_t count = 0; + for ( size_t i=0 ; i<_vsegments.size() ; i++ ) { + _globalsCount[depth] += 1.0; + ufragments[depth].incGlobals(); + + if ( layer != _vsegments[i]->getLayer() ) { + uLengths2[depth] += count * height; + + count = 0; + layer = _vsegments[i]->getLayer(); + depth = Session::getRoutingGauge()->getLayerDepth(layer); + } + count++; + _feedthroughs[depth] += 1.0; + } + if ( count ) { + uLengths2[depth] += count * height; + } + } + + // Add the blockages. + for ( size_t i=0 ; i<_depth ; i++ ) { + uLengths2[i] += _blockages[i]; + } + + // Compute the number of non pass-through tracks. + if (processeds.size()) { + AutoSegment::DepthLengthSet::iterator isegment = processeds.begin(); + const Layer* layer = (*isegment)->getLayer(); + DbU::Unit axis = (*isegment)->getAxis(); + size_t depth = Session::getRoutingGauge()->getLayerDepth(layer); + size_t count = 0; + for ( ; isegment != processeds.end(); ++isegment ) { + _feedthroughs[depth] += ((*isegment)->isGlobal()) ? 0.50 : 0.33; + localCounts [depth] += 1.0; + if ( (*isegment)->isGlobal() ) _globalsCount[depth] += 1.0; + + ufragments[depth].merge( (*isegment)->getAxis(), (*isegment)->getSpanU() ); + if ( (axis != (*isegment)->getAxis()) or (layer != (*isegment)->getLayer()) ) { + count = 0; + axis = (*isegment)->getAxis(); + layer = (*isegment)->getLayer(); + depth = Session::getRoutingGauge()->getLayerDepth(layer); + } + ++count; + } + } + + // Normalize: 0 < d < 1.0 (divide by H/V capacity). + for ( size_t i=0 ; i<_depth ; i++ ) { + switch ( Session::getDirection(i) ) { + case Flags::Horizontal: + _densities [i] = ((float)uLengths2[i]) / ( hcapacity * (float)width ); + _feedthroughs [i] += (float)(_blockages[i] / width); + _fragmentations[i] = (float)ufragments[i].getMaxFree().getSize() / (float)width; + break; + case Flags::Vertical: + _densities [i] = ((float)uLengths2[i]) / ( vcapacity * (float)height ); + _feedthroughs [i] += (float)(_blockages[i] / height); + _fragmentations[i] = (float)ufragments[i].getMaxFree().getSize() / (float)height; + break; + } + + if (_densities[i] >= 1.0) _flags |= Flags::Saturated; + } + + _cDensity = ( (float)_contacts.size() ) / ccapacity; + _flags.reset( Flags::Invalidated ); + + checkDensity(); + + return isSaturated() ? 1 : 0 ; + } + + + size_t GCell::checkDensity () const + { + if (isInvalidated()) const_cast(this)->updateDensity(); + + if ( not Session::isInDemoMode() and Session::doWarnGCellOverload() ) { + for ( size_t i=0 ; i<_depth ; i++ ) { + if (_densities[i] > 1.0) { + cparanoid << Warning( "%s overloaded in %s (M2:%.2f M3:%.2f M4:%.2f M5:%.2f)" + , _getString().c_str() + , getString(Session::getRoutingGauge()->getRoutingLayer(i)->getName()).c_str() + , _densities[1] // M2 + , _densities[2] // M3 + //, _blockages[2] // M4 + , _densities[3] // M5 + , _densities[4] // M6 + ) + << endl; + } + } + } + + return isSaturated() ? 1 : 0 ; + } + + + bool GCell::hasFreeTrack ( size_t depth, float reserve ) const + { + if (isInvalidated()) const_cast(this)->updateDensity(); + + float capacity = 0.0; + switch ( Session::getDirection(depth) ) { + case Flags::Horizontal: capacity = getHCapacity(); break; + case Flags::Vertical: capacity = getVCapacity(); break; + } + + cdebug_log(149,0) << " | hasFreeTrack [" << getId() << "] depth:" << depth << " " + << Session::getRoutingGauge()->getRoutingLayer(depth)->getName() + //<< " " << (_densities[depth]*capacity) << " vs. " << capacity + << " " << _feedthroughs[depth] << " vs. " << capacity + << " " << this << endl; + + return (_feedthroughs[depth] + 0.99 + reserve <= capacity); + } + + + void GCell::rpDesaturate ( set& globalNets ) + { + set rps; + getRoutingPads( rps ); + + set rpNets; + set::iterator irp = rps.begin(); + for ( RoutingPad* rp : rps ) { + if (rp->getLayer() != Session::getRoutingLayer(0)) continue; + rpNets.insert( rp->getNet() ); + } + + if (rpNets.size() < Session::getSaturateRp()) return; + + cerr << Warning("%s has %zd terminals (h:%zd, v:%zd)" + ,getString(this).c_str() + ,rps.size() + ,_hsegments.size() + ,_vsegments.size() + ) << endl; + + AutoSegment* segment; + while ( (_densities[1] > 0.5) and stepDesaturate(1,globalNets,segment,Flags::ForceMove) ) { + cdebug_log(149,0) << "Moved up: " << segment << endl; + } + } + + + bool GCell::stepDesaturate ( size_t depth + , set& globalNets + , AutoSegment*& moved + , unsigned int flags + ) + { + cdebug_log(9000,0) << "Deter| GCell::stepDesaturate() [" << getId() << "] depth:" << depth << endl; + + updateDensity(); + moved = NULL; + + if (not (flags & Flags::ForceMove) and not isSaturated(depth)) return false; + + vector::iterator isegment; + vector::iterator iend; + + switch ( Session::getDirection(depth) ) { + case Flags::Horizontal: + iend = _hsegments.end (); + isegment = _hsegments.begin(); + break; + case Flags::Vertical: + iend = _vsegments.end (); + isegment = _vsegments.begin(); + break; + } + + for ( ; (isegment != iend) ; isegment++ ) { + unsigned int segmentDepth = Session::getRoutingGauge()->getLayerDepth((*isegment)->getLayer()); + + if (segmentDepth < depth) continue; + if (segmentDepth > depth) break; + + globalNets.insert( (*isegment)->getNet() ); + cdebug_log(9000,0) << "Deter| Move up " << (*isegment) << endl; + + moved = (*isegment); + + if (moved) return true; + } + + return false; + } + + + bool GCell::stepBalance ( size_t depth, GCell::Set& invalidateds ) + { + cdebug_log(149,0) << "stepBalance() - " << this << endl; + + updateDensity(); + + vector::iterator isegment; + vector::iterator iend; + set globalNets; + + switch ( Session::getDirection(depth) ) { + case Flags::Horizontal: + iend = _hsegments.end (); + isegment = _hsegments.begin(); + break; + case Flags::Vertical: + iend = _vsegments.end (); + isegment = _vsegments.begin(); + break; + } + + for ( ; (isegment != iend) ; isegment++ ) { + unsigned int segmentDepth = Session::getRoutingGauge()->getLayerDepth((*isegment)->getLayer()); + + if (segmentDepth < depth) continue; + if (segmentDepth > depth) break; + +#if THIS_IS_DISABLED + // Hard-coded: reserve 3 tracks (1/20 * 3). + if ((*isegment)->canMoveULeft(0.05)) { + getAnabatic()->moveULeft(*isegment,globalNets,invalidateds); + return true; + } + if ((*isegment)->canMoveURight(0.05)) { + getAnabatic()->moveURight(*isegment,globalNets,invalidateds); + return true; + } +#endif + } + + return false; + } + + + bool GCell::stepNetDesaturate ( size_t depth, set& globalNets, GCell::Set& invalidateds ) + { + cdebug_log(9000,0) << "Deter| GCell::stepNetDesaturate() depth:" << depth << endl; + cdebug_log(9000,0) << "Deter| " << this << endl; + + updateDensity(); + + vector::iterator isegment; + vector::iterator iend; + + switch ( Session::getDirection(depth) ) { + case Flags::Horizontal: + iend = _hsegments.end (); + isegment = _hsegments.begin (); + break; + case Flags::Vertical: + iend = _vsegments.end (); + isegment = _vsegments.begin (); + break; + } + + for ( ; (isegment != iend) ; isegment++ ) { + unsigned int segmentDepth = Session::getRoutingGauge()->getLayerDepth((*isegment)->getLayer()); + + if (segmentDepth < depth) continue; + if (segmentDepth > depth) break; + + cdebug_log(9000,0) << "Deter| Move up " << (*isegment) << endl; + + // if (getAnabatic()->moveUpNetTrunk2(*isegment,globalNets,invalidateds)) + // return true; + } + + return false; + } + string GCell::_getTypeName () const { return getString(_extensionName); } @@ -691,16 +1575,111 @@ namespace Anabatic { Record* GCell::_getRecord () const { Record* record = Super::_getRecord(); - record->add( getSlot("_flags" , &_flags ) ); - record->add( getSlot("_westEdges" , &_westEdges ) ); - record->add( getSlot("_eastEdges" , &_eastEdges ) ); - record->add( getSlot("_southEdges", &_southEdges) ); - record->add( getSlot("_northEdges", &_northEdges) ); + record->add( getSlot("_flags" , &_flags ) ); + record->add( getSlot("_westEdges" , &_westEdges ) ); + record->add( getSlot("_eastEdges" , &_eastEdges ) ); + record->add( getSlot("_southEdges" , &_southEdges) ); + record->add( getSlot("_northEdges" , &_northEdges) ); record->add( DbU::getValueSlot("_xmin", &_xmin) ); record->add( DbU::getValueSlot("_ymin", &_ymin) ); + record->add( getSlot ( "_vsegments", &_vsegments ) ); + record->add( getSlot ( "_hsegments", &_hsegments ) ); + record->add( getSlot ( "_contacts" , &_contacts ) ); + record->add( getSlot ( "_depth" , &_depth ) ); + + RoutingGauge* rg = getAnabatic()->getConfiguration()->getRoutingGauge(); + + for ( size_t depth=0 ; depth<_depth ; ++depth ) { + ostringstream s; + const Layer* layer = rg->getRoutingLayer(depth)->getBlockageLayer(); + s << "_blockages[" << depth << ":" << ((layer) ? layer->getName() : "None") << "]"; + record->add( getSlot ( s.str(), &_blockages[depth] ) ); + } + + for ( size_t depth=0 ; depth<_depth ; ++depth ) { + ostringstream s; + const Layer* layer = rg->getRoutingLayer(depth); + s << "_densities[" << depth << ":" << ((layer) ? layer->getName() : "None") << "]"; + record->add( getSlot ( s.str(), &_densities[depth] ) ); + } return record; } +// ------------------------------------------------------------------- +// Class : "Anabatic::GCellDensitySet". + + + GCellDensitySet::GCellDensitySet ( size_t depth ) + : _depth (depth) + , _set () + , _requests() + { } + + + GCellDensitySet::GCellDensitySet ( size_t depth, const GCell::Vector& gcells ) + : _depth (depth) + , _set () + , _requests() + { + for ( size_t i=0 ; i::iterator iinserted; + GCell::Set::iterator igcell = _requests.begin(); + + // Remove invalidateds GCell from the queue. + for ( ; igcell != _requests.end() ; ++igcell ) { + iinserted = _set.find(*igcell); + if (iinserted != _set.end()) { + _set.erase( iinserted ); + } + } + + // Re-insert invalidateds GCell in the queue *after* updating the key. + for ( igcell = _requests.begin() ; igcell != _requests.end() ; ++igcell ) { + (*igcell)->updateKey( _depth ); + _set.insert( *igcell ); + } + + _requests.clear(); + } + + +// ------------------------------------------------------------------- +// Utilities. + + + string getVectorString ( float* v, size_t size ) + { + ostringstream s; + + s << setprecision(3); + for ( size_t i=0 ; iloadGlobalRouting( EngineLoadGrByNet ); + } + + void GraphicAnabaticEngine::addToMenu ( CellViewer* viewer ) { assert( _viewer == NULL ); @@ -453,6 +460,11 @@ namespace Anabatic { , "Global Route" , std::bind(&GraphicAnabaticEngine::_globalRoute,this) ); + _viewer->addToMenu( "placeAndRoute.anabatic.detailedRoute" + , "Anabatic - &Detailed Route" + , "Run the Anabatic detailed router" + , std::bind(&GraphicAnabaticEngine::_detailRoute,this) + ); } diff --git a/anabatic/src/LoadGlobalRouting.cpp b/anabatic/src/LoadGlobalRouting.cpp new file mode 100644 index 00000000..1111ad3c --- /dev/null +++ b/anabatic/src/LoadGlobalRouting.cpp @@ -0,0 +1,2203 @@ +// -*- 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 | +// | A n a b a t i c - Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./LoadGlobalRouting.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/Bug.h" +#include "hurricane/Error.h" +#include "hurricane/Warning.h" +#include "hurricane/DebugSession.h" +#include "hurricane/Layer.h" +#include "hurricane/BasicLayer.h" +#include "hurricane/RegularLayer.h" +#include "hurricane/Technology.h" +#include "hurricane/DataBase.h" +#include "hurricane/Net.h" +#include "hurricane/NetExternalComponents.h" +#include "hurricane/NetRoutingProperty.h" +#include "hurricane/RoutingPad.h" +#include "hurricane/RoutingPads.h" +#include "hurricane/Pad.h" +#include "hurricane/Plug.h" +#include "hurricane/Cell.h" +#include "hurricane/Instance.h" +#include "hurricane/Vertical.h" +#include "hurricane/Horizontal.h" +#include "crlcore/AllianceFramework.h" +#include "crlcore/RoutingGauge.h" +#include "crlcore/Measures.h" +#include "anabatic/AutoContactTerminal.h" +#include "anabatic/AutoContactTurn.h" +#include "anabatic/AutoContactHTee.h" +#include "anabatic/AutoContactVTee.h" +#include "anabatic/AutoSegment.h" +#include "anabatic/AnabaticEngine.h" + + +namespace { + + using Anabatic::AutoContactTerminal; + + +/*! \defgroup LoadGlobalRouting Global Routing Loading + * \brief Translation rules to build detailed routing from global + * + * This module documents how the global routing built by \c Knik is + * loaded into the \c Anabatic data-base. It is intented for developpers + * only. + */ + +//! \addtogroup LoadGlobalRouting +//! \{ + +//! \enum LocalFunctionFlag +//! A set of flags for all functions of the LoadGlobalRouting module. +//! They can be combined to form the \e flags argument of functions. +//! the functions will ignore flags that are not intended to them. +//! +//! For \c HSmall, \c VSmall & \c Punctual see checkRoutingPadSize(). + +//! \var LocalFunctionFlag::NoFlags +//! A simple alias over zero to explicitly tell that no flag at all is +//! passed to the function. + +//! \var LocalFunctionFlag::HAccess +//! The constructed topology will be accessed through an horizontal +//! segment. The absence of this flag tell that the access will be done +//! trough a vertical. + +//! \var LocalFunctionFlag::VSmall +//! The RoutingPad vertically covers a very small number of access points, +//! so it is likely overconstrained for direct horizontal connexion. + +//! \var LocalFunctionFlag::HSmall +//! The RoutingPad horizontally covers a very small number of access points, +//! so it is likely overconstrained for direct vertical connexion. + +//! \var LocalFunctionFlag::Punctual +//! The RoutingPad covers only an access point in either direction. + +//! \var LocalFunctionFlag::DoSourceContact +//! When creating Anabatic::AutoContactTerminal on non-punctual RoutingPad, this flag +//! request the creation of a contact on the source point. + +//! \var LocalFunctionFlag::DoTargetContact +//! When creating Anabatic::AutoContactTerminal on non-punctual RoutingPad, this flag +//! request the creation of a contact on the target point. + + +//! \function unsigned int checkRoutingPadSize ( Component* rp ); +//! +//! Look at the geometrical size of the Component and assess if +//! it's span is too narrow either horizontally or vertically. +//! Return a combination of flags indicating it's state: +//! - HSmall : less than 3 pitches in horizontal direction. +//! - VSmall : less than 3 pitches in vertical direction. +//! - Punctual : one pitch in either directions. +//! +//! The component can be a RoutingPad, a Vertical or an Horizontal. +//! +//! \image html checkRoutingPadSize.png "checkRoutingPadSize()" + +/*! \class GCellTopology + * + * \brief Build the wiring for a Net inside a GCell (\b internal). + * + * As this class is called to initially construct the Anabatic wiring, + * it must build a \b connex wiring. That is without gaps in layer depth, + * because the topology restauration mechanism (AutoContact::updateTopology()) + * of the AutoContact cannot work until all AutoSegments are revalidated at + * least once. The topology restauration work by creating doglegs which in turn, + * call the canonization, which needs all the caches to be up to date. + */ + +//! \function void GCellTopology::doRp_AutoContacts ( GCell* gcell, Component* rp, AutoContact*& source, AutoContact*& target, unsigned int flags ); +//! \param gcell The GCell into which create the AutoContact. +//! \param rp The Component we want to access. +//! \param source The AutoContact created on the \c source (\e returned). +//! \param target The AutoContact created on the \c target (\e returned). +//! \param flags Managed by this function: +//! - LocalFunctionFlag::DoSourceContact +//! - LocalFunctionFlag::DoTargetContact +//! +//! Create the AutoContact directly anchored on the Component (terminal). +//! Three cases are manageds: +//! -# Ordinary (non-punctual) \c METAL1 terminal: an AutoContactTerminal +//! is anchored on the RoutingPad. +//! -# Punctual \c METAL1 terminal, the access must never be blocked +//! by other routing. To ensure it, we create a fixed AutoSegment (anchored +//! on two AutoContactTerminal) to cover it. The \e normal AutoContactTerminal +//! is also created. +//! -# non \c METAL1 terminal, as for the punctual \c METAL1, a +//! fixed protection is added over the RoutingPad. If we access +//! horizontally a vertical RoutingPad or vertically an horizontal +//! one, an extra AutoContactTerminal is added (to allow is displacement +//! along the RoutingPad). +//! +//! To avoid creating a fixed protection over a RoutingPad multiple times, +//! the RoutingPad and it's associated protection is stored in a static +//! \c map : \c __routingPadAutoSegments. +//! +//! Conversely, because an AutoContactTerminal can only be connected to one +//! segment, each time this function is called a new terminal will be created +//! (or maybe two in case of non-punctual terminals). If only one AutoContact +//! is requested, it is created centered on the RoutingPad. The initial +//! position of AutoContact do not prevent them to move afterwards, +//! even those created on source/target on a non-punctual RoutingPad. +//! +//! \remark For clarity we describe the layer management of this function in term +//! of \c METAL, but it is the RoutingGauge depth which is actually used. +//! +//! \image html doRp_AutoContacts.png "doRp_AutoContacts()" + +//! \function AutoContact* GCellTopology::doRp_Access ( GCell* gcell, Component* rp, unsigned int flags ); +//! \param gcell The GCell into which create the AutoContact. +//! \param rp The Component onto which anchor the access contact. +//! \param flags Relevant flags are: +//! - HAccess, the terminal is to be accessed through an horizontal +//! segment. +//! - VSmall, force the terminal to be considered as small in the +//! vertical direction. +//! +//! If \c HAccess is set, the Component is to be accessed trough an horizontal +//! segment. If unset, the access is done vertically. +//! +//! Create an AutoContact to access a Component (terminal). If the Component +//! is not to be accessed through an horizontal segment, and do not cover a +//! large span in the horizontal direction (flag \c VSmall), a local horizontal +//! AutoSegment is added to slacken the vertical constraints. +//! +//! \image html doRp_Access.png "doRp_Access()" + +//! \function AutoContact* GCellTopology::doRp_AccessPad ( RoutingPad* rp, unsigned int flags ); +//! \param rp The Component onto which anchor the access contact. +//! \param flags Relevant flags are: +//! - HAccess, the terminal is to be accessed through an horizontal +//! segment. +//! - VSmall, force the terminal to be considered as small in the +//! vertical direction. +//! \return A Anabatic::AutoContactTerminal . +//! +//! The Component \c rp is a RoutingPad which belongs to a pad cell. This case +//! occurs when we are routing a complete chip. This method build, from the +//! \c rp a stack of articulated punctual segments and contacts to reach the +//! default H/V routing layers (usually \c METAL2 & \c METAL3). This may be +//! needed when the pad terminal is in \c METAL5, for instance. +//! +//! The returned AutoContactTerminal is anchored on the last punctual segment +//! build. +//! +//! The GCell into which the AutoContactTerminal is created may be under the +//! pads area. However, it will be right on the border of the GCell. +//! The global router vertexes of GCell under the pad area are marked as +//! blocked so will never be used for routing. +//! +//! \remark The segments and contacts added to ensure the layer connexity are not +//! put into the Anabatic database. They are plain Hurricane objects, invisibles +//! from it. + +//! \function void GCellTopology::doRp_StairCaseH ( GCell* gcell, Component* rp1, Component* rp2 ); +//! +//! Build the wiring to connect to horizontal Component. Two cases: +//! - The Component are aligneds, then only a straight wire is created. +//! - They are \e not aligned, then a complete dogleg is created. +//! +//! \image html doRp_StairCaseH.png "doRp_StairCaseH()" + +//! \function void GCellTopology::doRp_StairCaseV ( GCell* gcell, Component* rp1, Component* rp2 ); +//! +//! Build the wiring to connect to vertical Components. Two cases: +//! - The Components are aligneds, then only a straight wire is created. +//! - They are \e not aligned, then a complete dogleg is created. +//! +//! \image html doRp_StairCaseV.png "doRp_StairCaseV()" + +//! \function void GCellTopology::_do_xG_1Pad (); +//! +//! Construct the topology, when there is only global wires and one local +//! terminal, but coming from a Pad. As thoses connectors will always be +//! on one border of the GCell they can be considered as a kind of global. +//! +//! So this method mostly calls GCellTopology::doRp_AccessPad() to create +//! the AutoContactTerminal, then calls GCellTopology::_do_xG(), except +//! for straight lines which are managed directly. + +//! \function void GCellTopology::_do_xG (); +//! +//! Construct the topology, when there is only global wires (no local terminals). +//! +//! Some topology are not handled because they must not be managed by this +//! function: +//!
    +//!
  • One global: nonsensical because there also must be a terminal. +//!
  • Two aligned globals: in that case we do a straight wire whithout +//! any AutoContact (handled by the source/target of the wire). +//!
+//! +//! \image html _do_xG.png "_do_xG()" + +//! \function void GCellTopology::_do_1G_1M1 (); +//! +//! Construct a topology where there is \e one global and one RoutingPad +//! in \c METAL1. The \c METAL1 is assumed to be vertical. +//! +//! \remark When accessing the RoutingPad through an horizontal global segment +//! and the vertical extension of the segment is small, the global is +//! still directly attached to the terminal, inducing a high constraint +//! on it. We left to job of slackening it to the router. +//! +//! \image html _do_1G_1M1.png "_do_1G_1M1()" + +//! \function void GCellTopology::_do_1G_xM1 (); +//! +//! Construct a topology where there is \e one global and any number of +//! RoutingPad in \c METAL1. The \c METAL1 is assumed to be vertical. +//! +//! The RoutingPads are linked together two by two. If the horizontal +//! segments are not aligned by the router, part of the routage will be +//! done through the RoutingPad itself. The global incoming segment will +//! connected to the leftmost, rightmost or centermost RoutingPad according +//! from wich side it comes from. +//! +//! \image html _do_1G_xM1.png "_do_1G_xM1()" + +//! \function void GCellTopology::_do_xG_1M1_1M2 (); +//! +//! Construct a topology where there is at least one global (and up to 4), +//! one \c METAL1 RoutingPad (assumed V) and one \c METAL2 RoutingPad (assumed H). +//! +//! In this topology, we want to try to reuse the \c METAL2 RoutingPad as a +//! feedtrough in the horizontal routage. Thus: +//! - The \c METAL1 and \c METAL2 RoutingPad are connected through a separate wiring. +//! - The south & west global wiring is attached to the leftmost contact of +//! the \c METAL2. +//! - The north & east global wiring is attached to the rightmost contact of +//! the \c METAL2. +//! +//! South/west and north/south can be build independantly. Depending on the number +//! of globals, they can consist of: +//! - Nothing (no south nor west). +//! - An AutoContact (west present). +//! - An horizontal plus a turn (south present). +//! - An horizontal plus a HTee (south & west present). +//! +//! \remark Not all configurations are represented below. +//! +//! \image html _do_xG_1M1_1M2.png "_do_xG_1M1_1M2()" + +//! \function void GCellTopology::_do_xG_xM1_xM3 (); +//! +//! Construct a topology where there is at least one global (and up to 4), +//! at least one \c METAL1 RoutingPad (assumed V) and at least one \c METAL3 +//! RoutingPad (assumed V). +//! +//! In this topology, we want to try to reuse the \c METAL3 RoutingPad as a +//! feedtrough in the vertical routage. Thus: +//! - The \c METAL1 and \c METAL3 RoutingPad are connected through a separate +//! wiring made of separate horizontals. +//! - The south-west global wiring is attached to the leftmost RoutingPad +//! if there isn't south or to the first \c METAL3 otherwise. +//! - The north-east global wiring is attached to the rightmost RoutingPad +//! if there isn't north or to the first \c METAL3 otherwise. +//! +//! South/west and north/south can be build independantly. Depending on the number +//! of globals, they can consist of: +//! - Nothing (no south nor west). +//! - An AutoContact on the leftmost RoutingPad (west present). +//! - An AutoContact on the first \c METAL3 (only south present). +//! - An AutoContact plus a vertical plus a VTee (south & west present). +//! +//! \image html _do_xG_xM1_xM3.png "_do_xG_xM1_xM3()" + +//! \function void GCellTopology::_do_xG_xM2 (); +//! +//! Construct a topology where there is at least one global (and up to 4), +//! and any number of \c METAL2 RoutingPads (assumeds H). +//! +//! In this topology, we want to try to reuse the \c METAL2 RoutingPad as a +//! feedtrough in the horizontal routage. Thus: +//! - The RoutingPad are connecteds trough a separate staircase (or +//! straight wire if aligneds). +//! - The south-west global wiring is attached to the leftmost RoutingPad +//! if there isn't south or to the biggest horizontal RoutingPad otherwise. +//! - The north-east global wiring is attached to the rightmost RoutingPad +//! if there isn't south or to the biggest horizontal RoutingPad otherwise. +//! +//! \image html _do_xG_xM2.png "_do_xG_xM2()" + +//! \function void GCellTopology::_do_1G_1M3 (); +//! +//! Construct a topology where there is one global and one \c METAL3 RoutingPad +//! (assumeds V). +//! +//! In this topology, we reuse the \c METAL3 RoutingPad as a feedtrough in the +//! vertical routage. Thus: +//! - If the global is either north or south, we directly connect to the +//! north end or south end of the RoutingPad. \red{The vertical global will} +//! \red{have no slack at all we assume that METAL3 terminals are only from} +//! \red{blocks and are aligneds vertically.} +//! - If the global is east or west \e and the RoutingPad is sufficiently +//! extended in the vertical direction, we connect an horizontal in the +//! normal way. +//! - If the global is not sufficiently extended, we add a turn to give some +//! slack to the global. +//! +//! +//! \image html _do_1G_1M3.png "_do_1G_1M3()" + +//! \function void GCellTopology::_do_xG_xM3 (); +//! +//! Construct a topology where there at least one global and two \c METAL3 RoutingPad +//! (assumed V). +//! +//! In this topology, we reuse the \c METAL3 RoutingPad as a feedtrough in the +//! vertical routage. \red{We assume that the most likely relative position} +//! \red{of the RoutingPads is to be aligned vertically}. +//! Thus: +//! - All RoutingPads are linked two by two trough vertical staircases. +//! - The south-west global wiring is attached to the bottommost RoutingPad +//! (without vertical slack). If a misalignment is detected, then a +//! dogleg is added. +//! - The north-east global wiring is attached to the topmost RoutingPad +//! (without vertical slack). +//! +//! South/west and north/south can be build independantly. Depending on the number +//! of globals, they can consist of: +//! - Nothing (no south nor west). +//! - An sliding AutoContact on the bottommost RoutingPad (west present). +//! - An fixed AutoContact on the bottommost RoutingPad (only south present). +//! - An fixed AutoContact plus a vertical plus a VTee (south & west present). +//! +//! \image html _do_xG_xM3.png "_do_xG_xM3()" + +//! \function void singleGCell ( AnabaticEngine* anbt, Net* net ); +//! +//! All the RoutingPads of the net are concentrated under a single +//! GCell. This function assumes that all the terminals are in +//! \c METAL1 (vertical), and link them two by two by horizontal +//! wires. + +//! \} + + + using namespace std; + using namespace CRL; + using namespace Hurricane; + using namespace Anabatic; + + + // --------------------------------------------------------------- + // Local Enum/Types. + + enum LocalFunctionFlag { NoFlags = 0x00000000 + , SortDecreasing = 0x00000001 + , HAccess = 0x00000002 + , VSmall = 0x00000004 + , HSmall = 0x00000008 + , Punctual = 0x00000010 + , HCollapse = 0x00000020 + , VCollapse = 0x00000040 + , Terminal = 0x00000080 + , DoSourceContact = 0x00000100 + , DoTargetContact = 0x00000200 + , SouthBound = 0x00010000 + , NorthBound = 0x00020000 + , WestBound = 0x00040000 + , EastBound = 0x00080000 + }; + + + // --------------------------------------------------------------- + // Local Variables. + + const char* invalidGCell = + "Anabatic::GCellTopology () :\n\n" + " No GCell under point.\n"; + + const char* mismatchGCell = + "Anabatic::GCellTopology () :\n\n" + " Contacts under two different GCells.\n"; + + const char* missingGCell = + "Anabatic::GCellTopology () :\n\n" + " No Contact in GCell.\n"; + + + map __routingPadAutoSegments; + + + // --------------------------------------------------------------- + // LoadGlobalRouting Local Classes. + + + struct NetCompareByName { + inline bool operator() ( const Net* lhs, const Net* rhs ) const; + }; + + inline bool NetCompareByName::operator() ( const Net* lhs, const Net* rhs ) const + { return lhs->getName() < rhs->getName(); } + + + // --------------------------------------------------------------- + // LoadGlobalRouting Local Functions. + + + void lookupClear () + { __routingPadAutoSegments.clear (); } + + + void getPositions ( Component* anchor, Point& source, Point& target ) + { + Segment* segment = dynamic_cast( anchor ); + if (segment) { + source = segment->getSourcePosition(); + target = segment->getTargetPosition(); + return; + } + + RoutingPad* rp = dynamic_cast( anchor ); + if (rp) { + source = rp->getSourcePosition(); + target = rp->getTargetPosition(); + return; + } + + source = anchor->getPosition(); + target = anchor->getPosition(); + } + + + unsigned int checkRoutingPadSize ( Component* anchor ) + { + Point source; + Point target; + + size_t anchorDepth = Session::getLayerDepth( anchor->getLayer() ); + if (anchorDepth == 0) ++anchorDepth; + + getPositions( anchor, source, target ); + + DbU::Unit width = abs( target.getX() - source.getX() ); + DbU::Unit height = abs( target.getY() - source.getY() ); + + unsigned int flags = 0; + flags |= (width < 3*Session::getPitch(anchorDepth)) ? HSmall : 0; + flags |= (height < 3*Session::getPitch(anchorDepth)) ? VSmall : 0; + flags |= ((width == 0) && (height == 0)) ? Punctual : 0; + + cdebug_log(145,0) << "::checkRoutingPadSize(): pitch[" << anchorDepth << "]:" + << DbU::toLambda(Session::getPitch(anchorDepth)) << " " + << ((flags & HSmall) ? "HSmall " : " ") + << ((flags & VSmall) ? "VSmall " : " ") + << endl; + + return flags; + } + + + Hook* getSegmentOppositeHook ( Hook* hook ) + { + Segment* segment = static_cast( hook->getComponent() ); + return segment->getOppositeHook( hook ); + } + + + unsigned int getSegmentHookType ( Hook* hook ) + { + Horizontal* horizontal = dynamic_cast( hook->getComponent() ); + if (horizontal) { + if (horizontal->getSourceX() > horizontal->getTargetX()) + cerr << Warning("Bad orientation of %s",getString(horizontal).c_str()) << endl; + + if (dynamic_cast(hook)) + return EastBound; + return WestBound; + } else { + Vertical* vertical = dynamic_cast( hook->getComponent() ); + if (vertical) { + if (vertical->getSourceY() > vertical->getTargetY()) + cerr << Warning("Bad orientation of %s",getString(vertical).c_str()) << endl; + + if (dynamic_cast(hook)) + return NorthBound; + } else { + cerr << Warning("Unmanaged Hook %s",getString(hook).c_str()) << endl; + } + } + return SouthBound; + } + + + // --------------------------------------------------------------- + // Class : "SortRpByX". + + class SortRpByX { + public: + inline SortRpByX ( unsigned int flags ); + inline bool operator() ( Component* rp1, Component* rp2 ); + protected: + unsigned int _flags; + }; + + + inline SortRpByX::SortRpByX ( unsigned int flags ) + : _flags(flags) + { } + + + inline bool SortRpByX::operator() ( Component* rp1, Component* rp2 ) + { + DbU::Unit x1 = rp1->getCenter().getX(); + DbU::Unit x2 = rp2->getCenter().getX(); + + if (x1 == x2) return false; + return (_flags & SortDecreasing) xor (x1 < x2); + } + + + // --------------------------------------------------------------- + // Class : "SortRpByY". + + class SortRpByY { + public: + inline SortRpByY ( unsigned int flags ); + inline bool operator() ( Component* rp1, Component* rp2 ); + protected: + unsigned int _flags; + }; + + + inline SortRpByY::SortRpByY ( unsigned int flags ) + : _flags(flags) + { } + + + inline bool SortRpByY::operator() ( Component* rp1, Component* rp2 ) + { + DbU::Unit y1 = rp1->getCenter().getY(); + DbU::Unit y2 = rp2->getCenter().getY(); + + if (y1 == y2) return false; + return (_flags & SortDecreasing) xor (y1 < y2); + } + + + // --------------------------------------------------------------- + // Class : "ForkStack". + + class ForkStack { + public: + inline void push ( Hook* from, AutoContact* contact ); + inline void pop (); + inline Hook* getFrom () const; + inline AutoContact* getContact () const; + private: + struct Element { + Hook* _from; + AutoContact* _contact; + inline Element ( Hook* from, AutoContact* contact ); + }; + private: + list _stack; + }; + + + inline ForkStack::Element::Element ( Hook* from, AutoContact* contact ) : _from(from), _contact(contact) {} + inline void ForkStack::pop () { if (not _stack.empty()) _stack.pop_back(); } + inline Hook* ForkStack::getFrom () const { return _stack.empty() ? NULL : _stack.back()._from; } + inline AutoContact* ForkStack::getContact () const { return _stack.empty() ? NULL : _stack.back()._contact; } + + + inline void ForkStack::push ( Hook* from, AutoContact* contact ) + { + cdebug_log(145,0) << " Stacking " << from << " + " << contact << endl; + _stack.push_back( Element(from,contact) ); + } + + + // --------------------------------------------------------------- + // Class : "GGellTopology". + + class GCellTopology { + + public: + static void init ( unsigned int degree ); + static void fixSegments (); + GCellTopology ( AnabaticEngine*, Hook* fromHook, AutoContact* sourceContact=NULL ); + void construct ( ForkStack& forks ); + inline unsigned int getStateG () const; + inline GCell* getGCell () const; + static void doRp_AutoContacts ( GCell*, Component*, AutoContact*& source, AutoContact*& target, unsigned int flags ); + static AutoContact* doRp_Access ( GCell*, Component*, unsigned int flags ); + static AutoContact* doRp_AccessPad ( RoutingPad*, unsigned int flags ); + static void doRp_StairCaseH ( GCell*, Component* rp1, Component* rp2 ); + static void doRp_StairCaseV ( GCell*, Component* rp1, Component* rp2 ); + private: + void _do_xG (); + void _do_xG_1Pad (); + void _do_1G_1PinM2 (); + void _do_1G_1M1 (); + void _do_1G_xM1 (); + void _do_xG_xM1_xM3 (); + void _do_xG_1M1_1M2 (); + void _do_4G_1M2 (); + void _do_xG_xM2 (); + void _do_1G_1M3 (); + void _do_xG_xM3 (); + + private: + enum ConnexityBits { GlobalBSize = 4 + , Metal1BSize = 4 + , Metal2BSize = 4 + , Metal3BSize = 4 + , PadsBSize = 4 + , PinsBSize = 4 + }; + +#define CONNEXITY_VALUE( Gs, M1s, M2s, M3s, pads, pins ) \ + Gs + ((M1s ) << GlobalBSize) \ + + ((M2s ) << (GlobalBSize+Metal1BSize)) \ + + ((M3s ) << (GlobalBSize+Metal1BSize+Metal2BSize)) \ + + ((pads) << (GlobalBSize+Metal1BSize+Metal2BSize+Metal3BSize)) \ + + ((pins) << (GlobalBSize+Metal1BSize+Metal2BSize+Metal3BSize+PadsBSize)) + + // Connexity Name | G|M1|M2|M2|Pad|Pin| + enum ConnexityFlag { Conn_0G = CONNEXITY_VALUE( 0, 0, 0, 0, 0 , 0 ) + , Conn_2G = CONNEXITY_VALUE( 2, 0, 0, 0, 0 , 0 ) + , Conn_3G = CONNEXITY_VALUE( 3, 0, 0, 0, 0 , 0 ) + , Conn_4G = CONNEXITY_VALUE( 4, 0, 0, 0, 0 , 0 ) + , Conn_0G_2M1 = CONNEXITY_VALUE( 0, 2, 0, 0, 0 , 0 ) + , Conn_1G_1M1 = CONNEXITY_VALUE( 1, 1, 0, 0, 0 , 0 ) + , Conn_1G_2M1 = CONNEXITY_VALUE( 1, 2, 0, 0, 0 , 0 ) + , Conn_1G_3M1 = CONNEXITY_VALUE( 1, 3, 0, 0, 0 , 0 ) + , Conn_1G_4M1 = CONNEXITY_VALUE( 1, 4, 0, 0, 0 , 0 ) + , Conn_1G_5M1 = CONNEXITY_VALUE( 1, 5, 0, 0, 0 , 0 ) + , Conn_1G_1M2 = CONNEXITY_VALUE( 1, 0, 1, 0, 0 , 0 ) + , Conn_1G_2M2 = CONNEXITY_VALUE( 1, 0, 2, 0, 0 , 0 ) + , Conn_1G_3M2 = CONNEXITY_VALUE( 1, 0, 3, 0, 0 , 0 ) + , Conn_1G_4M2 = CONNEXITY_VALUE( 1, 0, 4, 0, 0 , 0 ) + , Conn_1G_1M3 = CONNEXITY_VALUE( 1, 0, 0, 1, 0 , 0 ) + , Conn_1G_2M3 = CONNEXITY_VALUE( 1, 0, 0, 2, 0 , 0 ) + , Conn_1G_3M3 = CONNEXITY_VALUE( 1, 0, 0, 3, 0 , 0 ) + , Conn_1G_4M3 = CONNEXITY_VALUE( 1, 0, 0, 4, 0 , 0 ) + , Conn_1G_1M1_1M2 = CONNEXITY_VALUE( 1, 1, 1, 0, 0 , 0 ) + , Conn_1G_1M1_1M3 = CONNEXITY_VALUE( 1, 1, 0, 1, 0 , 0 ) + // Connexity Name | G|M1|M2|M2|Pad|Pin| + , Conn_2G_1M1 = CONNEXITY_VALUE( 2, 1, 0, 0, 0 , 0 ) + , Conn_2G_2M1 = CONNEXITY_VALUE( 2, 2, 0, 0, 0 , 0 ) + , Conn_2G_3M1 = CONNEXITY_VALUE( 2, 3, 0, 0, 0 , 0 ) + , Conn_2G_4M1 = CONNEXITY_VALUE( 2, 4, 0, 0, 0 , 0 ) + , Conn_2G_5M1 = CONNEXITY_VALUE( 2, 5, 0, 0, 0 , 0 ) + , Conn_2G_1M2 = CONNEXITY_VALUE( 2, 0, 1, 0, 0 , 0 ) + , Conn_2G_2M2 = CONNEXITY_VALUE( 2, 0, 2, 0, 0 , 0 ) + , Conn_2G_3M2 = CONNEXITY_VALUE( 2, 0, 3, 0, 0 , 0 ) + , Conn_2G_4M2 = CONNEXITY_VALUE( 2, 0, 4, 0, 0 , 0 ) + , Conn_2G_1M3 = CONNEXITY_VALUE( 2, 0, 0, 1, 0 , 0 ) + , Conn_2G_2M3 = CONNEXITY_VALUE( 2, 0, 0, 2, 0 , 0 ) + , Conn_2G_3M3 = CONNEXITY_VALUE( 2, 0, 0, 3, 0 , 0 ) + , Conn_2G_4M3 = CONNEXITY_VALUE( 2, 0, 0, 4, 0 , 0 ) + , Conn_2G_1M1_1M2 = CONNEXITY_VALUE( 2, 1, 1, 0, 0 , 0 ) + // Connexity Name | G|M1|M2|M2|Pad|Pin| + , Conn_3G_1M1 = CONNEXITY_VALUE( 3, 1, 0, 0, 0 , 0 ) + , Conn_3G_2M1 = CONNEXITY_VALUE( 3, 2, 0, 0, 0 , 0 ) + , Conn_3G_3M1 = CONNEXITY_VALUE( 3, 3, 0, 0, 0 , 0 ) + , Conn_3G_4M1 = CONNEXITY_VALUE( 3, 4, 0, 0, 0 , 0 ) + , Conn_3G_1M2 = CONNEXITY_VALUE( 3, 0, 1, 0, 0 , 0 ) + , Conn_3G_2M2 = CONNEXITY_VALUE( 3, 0, 2, 0, 0 , 0 ) + , Conn_3G_1M3 = CONNEXITY_VALUE( 3, 0, 0, 1, 0 , 0 ) + , Conn_3G_2M3 = CONNEXITY_VALUE( 3, 0, 0, 2, 0 , 0 ) + , Conn_3G_3M3 = CONNEXITY_VALUE( 3, 0, 0, 3, 0 , 0 ) + , Conn_3G_4M3 = CONNEXITY_VALUE( 3, 0, 0, 4, 0 , 0 ) + // Connexity Name | G|M1|M2|M2|Pad|Pin| + , Conn_4G_1M1 = CONNEXITY_VALUE( 4, 1, 0, 0, 0 , 0 ) + , Conn_4G_2M1 = CONNEXITY_VALUE( 4, 2, 0, 0, 0 , 0 ) + , Conn_4G_3M1 = CONNEXITY_VALUE( 4, 3, 0, 0, 0 , 0 ) + , Conn_4G_4M1 = CONNEXITY_VALUE( 4, 4, 0, 0, 0 , 0 ) + , Conn_4G_1M2 = CONNEXITY_VALUE( 4, 0, 1, 0, 0 , 0 ) + , Conn_4G_1M3 = CONNEXITY_VALUE( 4, 0, 0, 1, 0 , 0 ) + , Conn_1G_1Pad = CONNEXITY_VALUE( 1, 0, 0, 0, 1 , 0 ) + , Conn_2G_1Pad = CONNEXITY_VALUE( 2, 0, 0, 0, 1 , 0 ) + , Conn_3G_1Pad = CONNEXITY_VALUE( 3, 0, 0, 0, 1 , 0 ) + , Conn_1G_1PinM2 = CONNEXITY_VALUE( 1, 0, 1, 0, 0 , 1 ) + }; + + // Connexity Union Type. + union UConnexity { + unsigned int connexity; + struct { + unsigned int globals : GlobalBSize; + unsigned int M1 : Metal1BSize; + unsigned int M2 : Metal2BSize; + unsigned int M3 : Metal3BSize; + unsigned int Pad : PadsBSize; + unsigned int Pin : PinsBSize; + } fields; + }; + + enum TopologyFlag { Global_Vertical_End = 0x00000001 + , Global_Horizontal_End = 0x00000002 + , Global_Horizontal = 0x00000004 + , Global_Vertical = 0x00000008 + , Global_Turn = 0x00000010 + , Global_Fork = 0x00000020 + , Global_Fixed = 0x00000040 + , Global_End = Global_Vertical_End | Global_Horizontal_End + , Global_Split = Global_Horizontal | Global_Vertical | Global_Fork + }; + + // Attributes. + private: + static vector _toFixSegments; + static unsigned int _degree; + UConnexity _connexity; + unsigned int _topology; + Net* _net; + GCell* _gcell; + AutoContact* _sourceContact; + AutoContact* _southWestContact; + AutoContact* _northEastContact; + Hook* _fromHook; + Hook* _east; + Hook* _west; + Hook* _north; + Hook* _south; + vector _routingPads; + }; + + + inline unsigned int GCellTopology::getStateG () const { return _connexity.fields.globals; } + inline GCell* GCellTopology::getGCell () const { return _gcell; } + + + vector GCellTopology::_toFixSegments; + unsigned int GCellTopology::_degree = 0; + + + void GCellTopology::fixSegments () + { + for ( size_t i=0 ; i<_toFixSegments.size() ; ++i ) + _toFixSegments[i]->setFlags( SegFixed ); + _toFixSegments.clear(); + } + + + void GCellTopology::init ( unsigned int degree ) + { + _degree = degree; + _toFixSegments.clear(); + } + + + GCellTopology::GCellTopology ( AnabaticEngine* anbt + , Hook* fromHook + , AutoContact* sourceContact ) + : _connexity () + , _topology (0) + , _gcell (NULL) + , _sourceContact (sourceContact) + , _southWestContact(NULL) + , _northEastContact(NULL) + , _fromHook (fromHook) + , _east (NULL) + , _west (NULL) + , _north (NULL) + , _south (NULL) + , _routingPads () + { + _connexity.connexity = 0; + + cdebug_log(145,1) << "GCellTopology::GCellTopology()" << endl; + cdebug_log(145,0) << getString(fromHook) << endl; + cdebug_log(145,0) << sourceContact << endl; + + Segment* fromSegment = static_cast( _fromHook->getComponent() ); + _net = fromSegment->getNet(); + + for ( Hook* hook : fromHook->getHooks() ) { + cdebug_log(145,0) << "Topology [" << _connexity.connexity << "] = " + << "[" << _connexity.fields.globals + << "+" << _connexity.fields.M1 + << "+" << _connexity.fields.M2 + << "+" << _connexity.fields.M3 + << "+" << _connexity.fields.Pin + << "+" << _connexity.fields.Pad + << "] " << _gcell + << endl; + + Segment* toSegment = dynamic_cast( hook->getComponent() ); + if (toSegment) { + switch ( getSegmentHookType(hook) ) { + case WestBound: _west = hook; break; + case EastBound: _east = hook; break; + case SouthBound: _south = hook; break; + case NorthBound: _north = hook; break; + } + + _connexity.fields.globals++; + } else { + Component* anchor = hook->getComponent(); + RoutingPad* rp = dynamic_cast( anchor ); + + cdebug_log(145,0) << "| Looking for Anchor:" << anchor << " rp:" << rp << endl; + + if (anchor) { + Contact* contact = dynamic_cast( anchor ); + if (contact + and ( Session::getAnabatic()->getConfiguration()->isGContact( anchor->getLayer() ) + or Session::getAnabatic()->getConfiguration()->isGMetal ( anchor->getLayer() )) ) { + // Global routing articulation contact are in not ? + GCell* gcell = anbt->getGCellUnder( contact->getCenter() ); + cdebug_log(145,0) << "* Global Routing Articulation: " << contact << endl; + cdebug_log(145,0) << "| " << gcell << endl; + if (gcell == NULL) + throw Error( invalidGCell ); + if (_gcell == NULL) _gcell = gcell; + else if (_gcell != gcell) { + throw Error( mismatchGCell ); + } + } else { + if (rp and AllianceFramework::get()->isPad(rp->_getEntityAsComponent()->getCell())) { + _connexity.fields.Pad++; + } else { + const Layer* layer = anchor->getLayer(); + + if (layer == Session::getRoutingLayer(0)) _connexity.fields.M1++; // M1 V + else if (layer == Session::getRoutingLayer(1)) _connexity.fields.M2++; // M2 H + else if (layer == Session::getRoutingLayer(2)) _connexity.fields.M3++; // M3 V + else if (layer == Session::getRoutingLayer(3)) _connexity.fields.M2++; // M4 H + else if (layer == Session::getRoutingLayer(4)) _connexity.fields.M3++; // M5 V + else { + cerr << Warning( "Terminal layer \"%s\" of %s is not managed yet (ignored)." + , getString(layer->getName()).c_str() + , getString(anchor).c_str() ) + << endl; + continue; + } + + if (dynamic_cast(rp->getOccurrence().getEntity())) _connexity.fields.Pin++; + } + + cdebug_log(145,0) << "| Component to connect: " << anchor << endl; + _routingPads.push_back( rp ); + } + } + } + } + cdebug_log(145,0) << "east: " << _east << endl; + cdebug_log(145,0) << "west: " << _west << endl; + cdebug_log(145,0) << "north:" << _north << endl; + cdebug_log(145,0) << "south:" << _south << endl; + + if (_connexity.fields.globals == 1) { + if ( _north or _south ) _topology |= Global_Vertical_End; + else _topology |= Global_Horizontal_End; + } else if (_connexity.fields.globals == 2) { + if ( _east && _west ) _topology |= Global_Horizontal; + else if ( _north && _south ) _topology |= Global_Vertical; + else _topology |= Global_Turn; + } else { + _topology |= Global_Fork; + } + + cdebug_tabw(145,-1); + + if (_gcell == NULL) throw Error( missingGCell ); + } + + + void GCellTopology::construct ( ForkStack& forks ) + { + cdebug_log(145,1) << "GCellTopology::construct() [" << _connexity.connexity << "] in " << _gcell << endl; + + _southWestContact = NULL; + _northEastContact = NULL; + + bool straightLine = false; + + switch ( _connexity.connexity ) { + case Conn_1G_1Pad: + case Conn_2G_1Pad: + case Conn_3G_1Pad: _do_xG_1Pad(); break; + case Conn_1G_1PinM2: _do_1G_1PinM2(); break; + case Conn_1G_1M1: _do_1G_1M1(); break; + case Conn_1G_2M1: + case Conn_1G_3M1: + case Conn_1G_4M1: + case Conn_1G_5M1: _do_1G_xM1(); break; + case Conn_1G_1M2: + case Conn_1G_2M2: + case Conn_1G_3M2: + case Conn_1G_4M2: _do_xG_xM2(); break; + case Conn_1G_1M3: _do_1G_1M3(); break; + case Conn_1G_2M3: + case Conn_1G_3M3: + case Conn_1G_4M3: _do_xG_xM3 (); break; + case Conn_1G_1M1_1M2: _do_xG_1M1_1M2(); break; + case Conn_1G_1M1_1M3: _do_1G_xM1 (); break; + case Conn_2G_1M1: + case Conn_2G_2M1: + case Conn_2G_3M1: + case Conn_2G_4M1: + case Conn_2G_5M1: + case Conn_3G_1M1: + case Conn_3G_2M1: + case Conn_3G_3M1: + case Conn_3G_4M1: + case Conn_3G_2M3: + case Conn_3G_3M3: + case Conn_3G_4M3: + case Conn_4G_1M1: + case Conn_4G_2M1: + case Conn_4G_3M1: + case Conn_4G_4M1: _do_xG_xM1_xM3(); break; + case Conn_4G_1M2: _do_4G_1M2(); break; + case Conn_2G_1M2: + case Conn_2G_2M2: + case Conn_2G_3M2: + case Conn_2G_4M2: + case Conn_3G_1M2: + case Conn_3G_2M2: _do_xG_xM2(); break; + case Conn_2G_1M3: + case Conn_2G_2M3: + case Conn_2G_3M3: + case Conn_2G_4M3: + case Conn_3G_1M3: _do_xG_xM3 (); break; + case Conn_2G_1M1_1M2: _do_xG_1M1_1M2(); break; + case Conn_2G: + if ( (_east and _west) or (_north and _south) ) { + straightLine = true; + break; + } + case Conn_3G: + case Conn_4G: + _do_xG(); + break; + default: + throw Bug( "Unmanaged Configuration [%d] = [%d+%d+%d+%d,%d+%d] %s in %s\n" + " The global routing seems to be defective." + , _connexity.connexity + , _connexity.fields.globals + , _connexity.fields.M1 + , _connexity.fields.M2 + , _connexity.fields.M3 + , _connexity.fields.Pin + , _connexity.fields.Pad + , _net->_getString().c_str() + , getString(_gcell).c_str() + ); + _do_xG(); + } + + if (straightLine) { + _northEastContact = _southWestContact = _sourceContact; + // This a global router problem. + // cerr << Bug( "Unmanaged configuration: straight line in %s,\n" + // " The global routing seems to be defective." + // , _net->_getString().c_str() + // ) << endl; + // return; + } else { + if (_sourceContact) { + AutoContact* targetContact + = ( getSegmentHookType(_fromHook) & (NorthBound|EastBound) ) + ? _northEastContact : _southWestContact ; + AutoSegment* globalSegment = AutoSegment::create( _sourceContact + , targetContact + , static_cast( _fromHook->getComponent() ) + ); + globalSegment->setFlags( (_degree == 2) ? SegBipoint : 0 ); + cdebug_log(145,0) << "Create global segment: " << globalSegment << endl; + +#if THIS_IS_DEPRECATED + if ( globalSegment->isHorizontal() + and ( (Session::getRoutingGauge()->getLayerDepth(_sourceContact->getLayer()->getBottom()) > 1) + or (Session::getRoutingGauge()->getLayerDepth(targetContact ->getLayer()->getBottom()) > 1)) ) { + globalSegment->setLayer ( Session::getRoutingLayer(3) ); + cdebug_log(145,0) << "Source:" << _sourceContact << endl; + cdebug_log(145,0) << "Target:" << targetContact << endl; + cdebug_log(145,0) << "Moving up global:" << globalSegment << endl; + } +#endif + // HARDCODED VALUE. + if ( (_topology & Global_Fixed) and (globalSegment->getLength() < 2*Session::getSliceHeight()) ) + _toFixSegments.push_back( globalSegment ); + + if (_connexity.fields.globals < 2) { + cdebug_tabw(145,-1); + return; + } + } else + _fromHook = NULL; + } + + Hook* toHook = NULL; + Hook* toHookOpposite = NULL; + if ( _east and (_fromHook != _east) ) { + toHook = _east; + toHookOpposite = getSegmentOppositeHook( _east ); + cdebug_log(145,0) << "Pushing East (to) " << getString(toHook) << endl; + cdebug_log(145,0) << "Pushing East (from) " << _northEastContact << endl; + forks.push( toHookOpposite, _northEastContact ); + } + if ( _west and (_fromHook != _west) ) { + toHook = _west; + toHookOpposite = getSegmentOppositeHook( _west ); + cdebug_log(145,0) << "Pushing West (to) " << getString(toHook) << endl; + cdebug_log(145,0) << "Pushing West (from) " << _southWestContact << endl; + forks.push( toHookOpposite, _southWestContact ); + } + if ( _north and (_fromHook != _north) ) { + toHook = _north; + toHookOpposite = getSegmentOppositeHook( _north ); + cdebug_log(145,0) << "Pushing North (to) " << getString(toHook) << endl; + cdebug_log(145,0) << "Pushing North (from) " << _northEastContact << endl; + forks.push( toHookOpposite, _northEastContact ); + } + if ( _south and (_fromHook != _south) ) { + toHook = _south; + toHookOpposite = getSegmentOppositeHook( _south ); + cdebug_log(145,0) << "Pushing South (to) " << getString(toHook) << endl; + cdebug_log(145,0) << "Pushing South (from) " << _southWestContact << endl; + forks.push( toHookOpposite, _southWestContact ); + } + + if (straightLine and toHook) { + Hook* prevSource = getSegmentOppositeHook( _fromHook ); + Hook* master = prevSource->getMasterHook(); + + prevSource->getComponent()->destroy(); + + toHook->detach(); + toHook->attach( master ); + } + + cdebug_tabw(145,-1); + } + + + void GCellTopology::doRp_AutoContacts ( GCell* gcell + , Component* rp + , AutoContact*& source + , AutoContact*& target + , unsigned int flags + ) + { + cdebug_log(145,1) << "doRp_AutoContacts()" << endl; + cdebug_log(145,0) << rp << endl; + + source = target = NULL; + + Point sourcePosition; + Point targetPosition; + const Layer* rpLayer = rp->getLayer(); + size_t rpDepth = Session::getLayerDepth( rp->getLayer() ); + unsigned int direction = Session::getDirection ( rpDepth ); + DbU::Unit viaSide = Session::getWireWidth ( rpDepth ); + + getPositions( rp, sourcePosition, targetPosition ); + + if (sourcePosition.getX() > targetPosition.getX()) swap( sourcePosition, targetPosition ); + if (sourcePosition.getY() > targetPosition.getY()) swap( sourcePosition, targetPosition ); + + GCell* sourceGCell = Session::getAnabatic()->getGCellUnder( sourcePosition ); + GCell* targetGCell = Session::getAnabatic()->getGCellUnder( targetPosition ); + + if (rpDepth == 0) { + rpLayer = Session::getContactLayer(0); + direction = Flags::Horizontal; + viaSide = Session::getViaWidth( rpDepth ); + } + + // Non-M1 terminal or punctual M1 protections. + if ((rpDepth != 0) or (sourcePosition == targetPosition)) { + map::iterator irp = __routingPadAutoSegments.find( rp ); + if (irp == __routingPadAutoSegments.end()) { + AutoContact* sourceProtect = AutoContactTerminal::create( sourceGCell + , rp + , rpLayer + , sourcePosition + , viaSide, viaSide + ); + AutoContact* targetProtect = AutoContactTerminal::create( targetGCell + , rp + , rpLayer + , targetPosition + , viaSide, viaSide + ); + sourceProtect->setFlags( CntFixed ); + targetProtect->setFlags( CntFixed ); + + AutoSegment* segment = AutoSegment::create( sourceProtect, targetProtect, direction ); + segment->setFlags( SegFixed ); + + __routingPadAutoSegments.insert( make_pair(rp,segment) ); + } + } + + if (sourcePosition != targetPosition) { + if (flags & DoSourceContact) + source = AutoContactTerminal::create( sourceGCell + , rp + , rpLayer + , sourcePosition + , viaSide, viaSide + ); + if (flags & DoTargetContact) + target = AutoContactTerminal::create( targetGCell + , rp + , rpLayer + , targetPosition + , viaSide, viaSide + ); + } + + if (not source and not target) { + source = target = AutoContactTerminal::create( gcell + , rp + , rpLayer + , rp->getCenter() + , viaSide, viaSide + ); + } + + cdebug_tabw(145,-1); + return; + } + + + AutoContact* GCellTopology::doRp_Access ( GCell* gcell, Component* rp, unsigned int flags ) + { + cdebug_log(145,1) << "doRp_Access() - flags:" << flags << endl; + + AutoContact* rpContactSource; + AutoContact* rpContactTarget; + + flags |= checkRoutingPadSize( rp ); + + doRp_AutoContacts( gcell, rp, rpContactSource, rpContactTarget, flags ); + + if (flags & HAccess) { + if (flags & VSmall) { + AutoContact* subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) ); + AutoContact* subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) ); + AutoSegment::create( rpContactSource, subContact1, Flags::Horizontal ); + AutoSegment::create( subContact1, subContact2, Flags::Vertical ); + rpContactSource = subContact2; + } + } else { + if (flags & HSmall) { + AutoContact* subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) ); + AutoSegment::create( rpContactSource, subContact1, Flags::Horizontal ); + rpContactSource = subContact1; + } + } + + cdebug_tabw(145,-1); + + return rpContactSource; + } + + + AutoContact* GCellTopology::doRp_AccessPad ( RoutingPad* rp, unsigned int flags ) + { + cdebug_log(145,1) << "doRp_AccessPad()" << endl; + cdebug_log(145,0) << rp << endl; + + // Hardcoded: H access is METAL2 (depth=1), V access is METAL3 (depth=2). + size_t accessDepth = (flags & HAccess) ? 1 : 2 ; + size_t padDepth = Session::getLayerDepth(rp->getLayer()); + if (padDepth > Session::getAllowedDepth()) { + cerr << Error( "GCellTopology::doRp_AccessPad(): Pad RoutingPad %s\n" + " has a layer unreachable by the router (top layer is: %s)" + , getString(rp).c_str() + , getString(Session::getRoutingLayer(Session::getAllowedDepth())).c_str() + ) << endl; + padDepth = Session::getAllowedDepth(); + } + + rp->getBodyHook()->detach(); + + Point rpPosition = rp->getCenter(); + Point position = rp->getCenter(); + Box rpbb = rp->getBoundingBox(); + if ( (rpbb.getWidth () > 2*Session::getWireWidth(padDepth)) + or (rpbb.getHeight() > 2*Session::getWireWidth(padDepth)) ) { + //cerr << "doRp_AccessPad(): connecting to non-punctual connector (RoutingPad).\n" + // << " " << rp->getNet() << "pad:" << rp->getOccurrence().getMasterCell() << endl; + + Transformation transf = rp->getOccurrence().getPath().getTransformation(); + switch ( transf.getOrientation() ) { + case Transformation::Orientation::ID: position.setY( rpbb.getYMin() ); break; + case Transformation::Orientation::MY: position.setY( rpbb.getYMax() ); break; + case Transformation::Orientation::YR: + case Transformation::Orientation::R3: position.setX( rpbb.getXMin() ); break; + case Transformation::Orientation::R1: position.setX( rpbb.getXMax() ); break; + default: + break; + } + } + + GCell* gcell = Session::getAnabatic()->getGCellUnder(position); + Component* anchor = rp; + + if (padDepth != accessDepth) { + if (padDepth > accessDepth) { + // Go *down* from the pad's RoutingPad. + --padDepth; + + Contact* target = NULL; + Contact* source = Contact::create ( rp + , Session::getContactLayer(padDepth) + , position.getX() - rpPosition.getX() + , position.getY() - rpPosition.getY() + , Session::getViaWidth(padDepth) + , Session::getViaWidth(padDepth) + ); + + for ( size_t depth = padDepth ; depth >= accessDepth ; --depth ) { + const Layer* segmentLayer = Session::getRoutingLayer(depth); + const Layer* targetLayer = (depth == accessDepth) ? segmentLayer + : Session::getContactLayer(depth-1); + DbU::Unit targetSide = (depth == accessDepth) ? Session::getWireWidth(depth) + : Session::getViaWidth (depth-1); + + target = Contact::create( rp->getNet() + , targetLayer + , position.getX() + , position.getY() + , targetSide + , targetSide + ); + if (Session::getDirection(depth) == Flags::Horizontal) { + anchor = Horizontal::create( source + , target + , segmentLayer + , position.getY() + , Session::getWireWidth(depth) + ); + } else { + anchor = Vertical::create( source + , target + , segmentLayer + , position.getX() + , Session::getWireWidth(depth) + ); + } + cdebug_log(145,0) << "Pad strap: " << anchor << endl; + source = target; + } + } else { + // Go *up* from the pad's RoutingPad. + Contact* target = NULL; + Contact* source = Contact::create ( rp + , Session::getContactLayer(padDepth) + , 0 + , 0 + , Session::getViaWidth(padDepth) + , Session::getViaWidth(padDepth) + ); + + for ( size_t depth = padDepth ; depth <= accessDepth ; ++depth ) { + const Layer* segmentLayer = Session::getRoutingLayer(depth); + const Layer* targetLayer = (depth == accessDepth) ? segmentLayer + : Session::getContactLayer(depth); + DbU::Unit targetSide = (depth == accessDepth) ? Session::getWireWidth(depth) + : Session::getViaWidth (depth); + + target = Contact::create( rp->getNet() + , targetLayer + , position.getX() + , position.getY() + , targetSide + , targetSide + ); + if (Session::getDirection(depth) == Flags::Horizontal) { + anchor = Horizontal::create( source + , target + , segmentLayer + , position.getY() + , Session::getWireWidth(depth) + ); + } else { + anchor = Vertical::create( source + , target + , segmentLayer + , position.getX() + , Session::getWireWidth(depth) + ); + } + cdebug_log(145,0) << "Pad strap: " << anchor << endl; + source = target; + } + } + } + + AutoContact* autoSource + = AutoContactTerminal::create ( gcell + , anchor + , Session::getRoutingLayer(accessDepth) + , position + , Session::getWireWidth(accessDepth) + , Session::getWireWidth(accessDepth) + ); + cdebug_tabw(145,-1); + return autoSource; + } + + + void GCellTopology::doRp_StairCaseH ( GCell* gcell, Component* rp1, Component* rp2 ) + { + cdebug_log(145,0) << "doRp_StairCaseH()" << endl; + + if (rp1->getCenter().getX() > rp2->getCenter().getX()) swap( rp1, rp2 ); + + AutoContact* rp1ContactSource = NULL; + AutoContact* rp1ContactTarget = NULL; + AutoContact* rp2ContactSource = NULL; + AutoContact* rp2ContactTarget = NULL; + const Layer* viaLayer = NULL; + + doRp_AutoContacts( gcell, rp1, rp1ContactSource, rp1ContactTarget, DoTargetContact ); + doRp_AutoContacts( gcell, rp2, rp2ContactSource, rp2ContactTarget, DoSourceContact ); + + if (rp1ContactTarget->getY() == rp2ContactSource->getY()) { + cdebug_log(145,0) << "Aligned horizontal routing pads : straight wire" << endl; + + viaLayer = rp1->getLayer(); + AutoSegment::create( rp1ContactTarget, rp2ContactSource, Flags::Horizontal ); + return; + } + + viaLayer = Session::getContactLayer(1); + + AutoContact* subContact1 = AutoContactTurn::create( gcell, rp1->getNet(), viaLayer ); + AutoContact* subContact2 = AutoContactTurn::create( gcell, rp1->getNet(), viaLayer ); + + AutoSegment::create( rp1ContactTarget, subContact1 , Flags::Horizontal ); + AutoSegment::create( subContact1 , subContact2 , Flags::Vertical ); + AutoSegment::create( subContact1 , rp2ContactSource, Flags::Horizontal ); + } + + + void GCellTopology::doRp_StairCaseV ( GCell* gcell, Component* rp1, Component* rp2 ) + { + cdebug_log(145,0) << "doRp_StairCaseV()" << endl; + + if (rp1->getCenter().getY() > rp2->getCenter().getY()) swap( rp1, rp2 ); + + AutoContact* rp1ContactSource = NULL; + AutoContact* rp1ContactTarget = NULL; + AutoContact* rp2ContactSource = NULL; + AutoContact* rp2ContactTarget = NULL; + const Layer* viaLayer = NULL; + + doRp_AutoContacts( gcell, rp1, rp1ContactSource, rp1ContactTarget, DoTargetContact ); + doRp_AutoContacts( gcell, rp2, rp2ContactSource, rp2ContactTarget, DoSourceContact ); + + if (rp1ContactTarget->getX() == rp2ContactSource->getX()) { + cdebug_log(145,0) << "Aligned vertical routing pads : straight wire" << endl; + + viaLayer = rp1->getLayer(); + AutoSegment::create( rp1ContactTarget, rp2ContactSource, Flags::Vertical ); + return; + } + + viaLayer = Session::getContactLayer(1); + + AutoContact* subContact1 = AutoContactTurn::create( gcell, rp1->getNet(), viaLayer ); + AutoContact* subContact2 = AutoContactTurn::create( gcell, rp1->getNet(), viaLayer ); + + AutoSegment::create( rp1ContactTarget, subContact1 , Flags::Vertical ); + AutoSegment::create( subContact1 , subContact2 , Flags::Horizontal ); + AutoSegment::create( subContact1 , rp2ContactSource, Flags::Vertical ); + } + + + void GCellTopology::_do_xG () + { + cdebug_log(145,1) << "_do_xG()" << endl; + + if (_connexity.fields.globals == 2) { + _southWestContact + = _northEastContact + = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + } else if (_connexity.fields.globals == 3) { + if (_east and _west) { + _southWestContact = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + _northEastContact = AutoContactVTee::create( _gcell, _net, Session::getContactLayer(1) ); + if (_south) swap( _southWestContact, _northEastContact ); + + AutoSegment::create( _southWestContact, _northEastContact, Flags::Vertical ); + } else { + _southWestContact = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + _northEastContact = AutoContactHTee::create( _gcell, _net, Session::getContactLayer(1) ); + if (_west) swap( _southWestContact, _northEastContact ); + + AutoSegment::create( _southWestContact, _northEastContact, Flags::Horizontal ); + } + } else { // fields.globals == 4. + AutoContact* turn = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + _southWestContact = AutoContactHTee::create( _gcell, _net, Session::getContactLayer(1) ); + _northEastContact = AutoContactVTee::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( _southWestContact, turn, Flags::Horizontal ); + AutoSegment::create( turn, _northEastContact, Flags::Vertical ); + } + cdebug_tabw(145,-1); + } + + + void GCellTopology::_do_xG_1Pad () + { + cdebug_log(145,1) << "_do_xG_1Pad() [Managed Configuration - Optimized] " << _topology << endl; + cdebug_log(145,0) << "_connexity.globals:" << _connexity.fields.globals << endl; + + unsigned int flags = NoFlags; + bool eastPad = false; + bool westPad = false; + bool northPad = false; + bool southPad = false; + Instance* padInstance = _routingPads[0]->getOccurrence().getPath().getHeadInstance(); + + switch ( padInstance->getTransformation().getOrientation() ) { + case Transformation::Orientation::ID: northPad = true; break; + case Transformation::Orientation::MY: southPad = true; break; + case Transformation::Orientation::YR: + case Transformation::Orientation::R3: eastPad = true; flags |= HAccess; break; + case Transformation::Orientation::R1: westPad = true; flags |= HAccess; break; + default: + cerr << Warning( "Unmanaged orientation %s for pad <%s>." + , getString(padInstance->getTransformation().getOrientation()).c_str() + , getString(padInstance).c_str() ) << endl; + break; + } + cdebug_log(145,0) << "eastPad:" << eastPad << ", " + << "westPad:" << westPad << ", " + << "northPad:" << northPad << ", " + << "southPad:" << southPad + << endl; + + AutoContact* source = doRp_AccessPad( _routingPads[0], flags ); + // Point position = _routingPads[0]->getCenter(); + // AutoContact* source = NULL; + // GCell* gcell = Session::getAnabatic()->getGCellGrid()->getGCell(position); + + // source = AutoContactTerminal::create ( gcell + // , _routingPads[0] + // , Session::getContactLayer(3) + // , position + // , Session::getViaWidth(3), Session::getViaWidth(3) + // ); + // source->setFlags( CntFixed ); + + // if (northPad or eastPad) { + // _southWestContact = _northEastContact = source; + // cdebug_tabw(145,-1); + // return; + // } + + // Check for straight lines, which are not managed by _do_xG(). + if (_connexity.fields.globals == 1) { + if ( (westPad and (_east != NULL)) + or (eastPad and (_west != NULL)) ) { + AutoContact* turn = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + _northEastContact = _southWestContact + = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( source, turn, Flags::Horizontal ); + AutoSegment::create( turn, _northEastContact, Flags::Vertical ); + cdebug_tabw(145,-1); + return; + } else if ( (southPad and (_north != NULL)) + or (northPad and (_south != NULL)) ) { + AutoContact* turn = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + _northEastContact = _southWestContact + = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( source, turn, Flags::Vertical ); + AutoSegment::create( turn, _northEastContact, Flags::Horizontal ); + cdebug_tabw(145,-1); + return; + } + } + + ++_connexity.fields.globals; + --_connexity.fields.Pad; + + if (westPad ) _west = source->getBodyHook(); + if (eastPad ) _east = source->getBodyHook(); + if (southPad) _south = source->getBodyHook(); + if (northPad) _north = source->getBodyHook(); + + _do_xG(); + + if (westPad) { + AutoSegment::create( source, _southWestContact, Flags::Horizontal ); + _west = NULL; + } + if (eastPad) { + AutoSegment::create( source, _northEastContact, Flags::Horizontal ); + _east = NULL; + } + if (southPad) { + AutoSegment::create( source, _southWestContact, Flags::Vertical ); + _south = NULL; + } + if (northPad) { + AutoSegment::create( source, _northEastContact, Flags::Vertical ); + _north = NULL; + } + --_connexity.fields.globals; + + cdebug_tabw(145,-1); + } + + + void GCellTopology::_do_1G_1PinM2 () + { + cdebug_log(145,1) << "_do_1G_1PinM2() [Managed Configuration - Optimized] " << _topology << endl; + + AutoContact* rpContact = doRp_Access( _gcell, _routingPads[0], NoFlags ); + AutoContact* turn1 = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, turn1, Flags::Vertical ); + + if (_north or _south) { + AutoContact* turn2 = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( turn1, turn2, Flags::Horizontal ); + turn1 = turn2; + } + _southWestContact = _northEastContact = turn1; + + cdebug_tabw(145,-1); + } + + + void GCellTopology::_do_1G_1M1 () + { + cdebug_log(145,1) << "_do_1G_1M1() [Managed Configuration - Optimized] " << _topology << endl; + + unsigned int flags = NoFlags; + if (_east ) { flags |= HAccess; } + else if (_west ) { flags |= HAccess; } + else if (_north) { flags |= VSmall; } + else if (_south) { flags |= VSmall; } + + _southWestContact = _northEastContact = doRp_Access( _gcell, _routingPads[0], flags ); + + cdebug_tabw(145,-1); + } + + + void GCellTopology::_do_1G_xM1 () + { + cdebug_log(145,1) << "_do_1G_" << _connexity.fields.M1 << "M1() [Managed Configuration]" << endl; + + sort( _routingPads.begin(), _routingPads.end(), SortRpByX(NoFlags) ); // increasing X. + for ( unsigned int i=1 ; i<_routingPads.size() ; ++i ) { + AutoContact* leftContact = doRp_Access( _gcell, _routingPads[i-1], HAccess ); + AutoContact* rightContact = doRp_Access( _gcell, _routingPads[i ], HAccess ); + AutoSegment::create( leftContact, rightContact, Flags::Horizontal ); + } + + Component* globalRp = NULL; + if (_east) globalRp = _routingPads[_routingPads.size()-1]; + else if (_west) globalRp = _routingPads[0]; + else { + globalRp = _routingPads[0]; + + cdebug_log(145,0) << "| Initial N/S Global RP: " << globalRp << endl; + for ( unsigned int i=1 ; i<_routingPads.size() ; ++i ) { + if (_routingPads[i]->getBoundingBox().getHeight() > globalRp->getBoundingBox().getHeight()) { + cdebug_log(145,0) << "| Better RP: " << globalRp << endl; + globalRp = _routingPads[i]; + } + } + } + + AutoContact* globalContact = doRp_Access( _gcell, globalRp, HAccess ); + + if (_north or _south) { + AutoContact* turn = globalContact; + globalContact = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( globalContact, turn, Flags::Horizontal ); + } + + _northEastContact = _southWestContact = globalContact; + + cdebug_tabw(145,-1); + } + + + void GCellTopology::_do_xG_1M1_1M2 () + { + cdebug_log(145,1) << "_do_xG_1M1_1M2() [Managed Configuration]" << endl; + + Component* rpL1; + Component* rpL2; + if (_routingPads[0]->getLayer() == Session::getRoutingLayer(0)) { + rpL1 = _routingPads[0]; + rpL2 = _routingPads[1]; + } else { + rpL1 = _routingPads[1]; + rpL2 = _routingPads[0]; + } + cdebug_log(145,0) << "rpL1 := " << rpL1 << endl; + cdebug_log(145,0) << "rpL2 := " << rpL2 << endl; + + AutoContact* rpL1ContactSource = NULL; + AutoContact* rpL1ContactTarget = NULL; + AutoContact* rpL2ContactSource = NULL; + AutoContact* rpL2ContactTarget = NULL; + + doRp_AutoContacts( _gcell, rpL1, rpL1ContactSource, rpL1ContactTarget, NoFlags ); + doRp_AutoContacts( _gcell, rpL2, rpL2ContactSource, rpL2ContactTarget, NoFlags ); + + AutoContact* subContact = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpL1ContactSource, subContact, Flags::Horizontal ); + AutoSegment::create( rpL2ContactSource, subContact, Flags::Vertical ); + + if (_south or _west) { + doRp_AutoContacts( _gcell, rpL2, rpL2ContactSource, rpL2ContactTarget, DoSourceContact ); + if (_south and _west) { + _southWestContact = AutoContactHTee::create( _gcell, _net, Session::getContactLayer(2) ); + AutoSegment::create( rpL2ContactSource, _southWestContact, Flags::Horizontal ); + } else { + if (_south) { + _southWestContact = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(2) ); + AutoSegment::create( rpL2ContactSource, _southWestContact, Flags::Horizontal ); + } else { + _southWestContact = rpL2ContactSource; + } + } + } + + if (_north or _east) { + doRp_AutoContacts( _gcell, rpL2, rpL2ContactSource, rpL2ContactTarget, DoTargetContact ); + if (_north and _east) { + _northEastContact = AutoContactHTee::create( _gcell, _net, Session::getContactLayer(2) ); + AutoSegment::create( rpL2ContactTarget, _northEastContact, Flags::Horizontal ); + } else { + if (_north) { + _northEastContact = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(2) ); + AutoSegment::create( rpL2ContactTarget, _northEastContact, Flags::Horizontal ); + } else { + _northEastContact = rpL2ContactTarget; + } + } + } + + cdebug_tabw(145,-1); + } + + + void GCellTopology::_do_xG_xM1_xM3 () + { + cdebug_log(145,1) << "_do_xG_" << _connexity.fields.M1 + << "M1_" << _connexity.fields.M3 + << "M3() [G:" << _connexity.fields.globals << " Managed Configuration]" << endl; + cdebug_log(145,0) << "_connexity: " << _connexity.connexity << endl; + cdebug_log(145,0) << "_north: " << _north << endl; + cdebug_log(145,0) << "_south: " << _south << endl; + cdebug_log(145,0) << "_east: " << _east << endl; + cdebug_log(145,0) << "_west: " << _west << endl; + + Component* rpM3 = NULL; + if (_routingPads[0]->getLayer() == Session::getRoutingLayer(2)) + rpM3 = _routingPads[0]; + + sort( _routingPads.begin(), _routingPads.end(), SortRpByX(NoFlags) ); // increasing X. + for ( unsigned int i=1 ; i<_routingPads.size() ; ++i ) { + AutoContact* leftContact = doRp_Access( _gcell, _routingPads[i-1], HAccess ); + AutoContact* rightContact = doRp_Access( _gcell, _routingPads[i ], HAccess ); + AutoSegment::create( leftContact, rightContact, Flags::Horizontal ); + + if (not rpM3 and (_routingPads[i]->getLayer() == Session::getRoutingLayer(2))) + rpM3 = _routingPads[i]; + } + + AutoContact* unusedContact = NULL; + + if (rpM3) { + // At least one M3 RoutingPad is present: use it. + if (_west and not _south) { + _southWestContact = doRp_Access( _gcell, _routingPads[0], HAccess ); + } else if (not _west and _south) { + doRp_AutoContacts( _gcell, rpM3, _southWestContact, unusedContact, DoSourceContact ); + } else if (_west and _south) { + AutoContact* rpContact = NULL; + doRp_AutoContacts( _gcell, rpM3, rpContact, unusedContact, DoSourceContact ); + _southWestContact = AutoContactVTee::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, _southWestContact, Flags::Vertical ); + } + + if (_east and not _north) { + _northEastContact = doRp_Access( _gcell, _routingPads[_routingPads.size()-1], HAccess ); + } else if (not _east and _north) { + doRp_AutoContacts( _gcell, rpM3, unusedContact, _northEastContact, DoTargetContact ); + } else if (_east and _north) { + AutoContact* rpContact = NULL; + doRp_AutoContacts( _gcell, rpM3, unusedContact, rpContact, DoTargetContact ); + _northEastContact = AutoContactVTee::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, _northEastContact, Flags::Vertical ); + } + } else { + // All RoutingPad are M1. + Component* southWestRp = _routingPads[0]; + cdebug_log(145,0) << "| Initial S-W Global RP: " << southWestRp << endl; + for ( unsigned int i=1 ; i<_routingPads.size() ; ++i ) { + if (southWestRp->getBoundingBox().getHeight() >= 4*Session::getPitch(1)) break; + if (_routingPads[i]->getBoundingBox().getHeight() > southWestRp->getBoundingBox().getHeight()) { + cdebug_log(145,0) << "| Better RP: " << southWestRp << endl; + southWestRp = _routingPads[i]; + } + } + + if (_west and not _south) { + _southWestContact = doRp_Access( _gcell, southWestRp, HAccess ); + } else if (not _west and _south) { + AutoContact* rpContact = doRp_Access( _gcell, southWestRp, HAccess ); + _southWestContact = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, _southWestContact, Flags::Horizontal ); + } else if (_west and _south) { + AutoContact* rpContact = doRp_Access( _gcell, southWestRp, HAccess ); + _southWestContact = AutoContactHTee::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, _southWestContact, Flags::Horizontal ); + } + + Component* northEastRp = _routingPads[_routingPads.size()-1]; + cdebug_log(145,0) << "| Initial N-E Global RP: " << northEastRp << endl; + + if (_routingPads.size() > 1) { + for ( unsigned int i=_routingPads.size()-1; i != 0 ; ) { + i -= 1; + if (northEastRp->getBoundingBox().getHeight() >= 4*Session::getPitch(1)) break; + if (_routingPads[i]->getBoundingBox().getHeight() > northEastRp->getBoundingBox().getHeight()) { + cdebug_log(145,0) << "| Better RP: " << northEastRp << endl; + northEastRp = _routingPads[i]; + } + } + } + + if (_east and not _north) { + _northEastContact = doRp_Access( _gcell, northEastRp, HAccess ); + } else if (not _east and _north) { + AutoContact* rpContact = doRp_Access( _gcell, northEastRp, HAccess ); + _northEastContact = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, _northEastContact, Flags::Horizontal ); + } else if (_east and _north) { + AutoContact* rpContact = doRp_Access( _gcell, northEastRp, HAccess ); + _northEastContact = AutoContactHTee::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, _northEastContact, Flags::Horizontal ); + } + } + + cdebug_tabw(145,-1); + } + + + void GCellTopology::_do_4G_1M2 () + { + cdebug_log(145,1) << "_do_4G_1M2() [Managed Configuration]" << endl; + + Component* rpL2 = _routingPads[0]; + cdebug_log(145,0) << "rpL2 := " << rpL2 << endl; + + AutoContact* rpL2ContactSource = NULL; + AutoContact* rpL2ContactTarget = NULL; + + doRp_AutoContacts( _gcell, rpL2, rpL2ContactSource, rpL2ContactTarget, DoSourceContact|DoTargetContact ); + + _southWestContact = AutoContactHTee::create( _gcell, _net, Session::getContactLayer(2) ); + _northEastContact = AutoContactHTee::create( _gcell, _net, Session::getContactLayer(2) ); + + AutoSegment::create( _southWestContact, rpL2ContactSource, Flags::Horizontal ); + AutoSegment::create( rpL2ContactTarget, _northEastContact, Flags::Horizontal ); + + cdebug_tabw(145,-1); + } + + void GCellTopology::_do_xG_xM2 () + { + cdebug_log(145,1) << "_do_" + << _connexity.fields.globals << "G_" + << _connexity.fields.M2 << "M2() [Managed Configuration - x]" << endl; + + Component* biggestRp = _routingPads[0]; + for ( unsigned int i=1 ; i<_routingPads.size() ; ++i ) { + doRp_StairCaseH( _gcell, _routingPads[i-1], _routingPads[i] ); + if (_routingPads[i]->getBoundingBox().getWidth() > biggestRp->getBoundingBox().getWidth()) + biggestRp = _routingPads[i]; + } + + AutoContact* unusedContact = NULL; + + if (_west and not _south) { + doRp_AutoContacts( _gcell, _routingPads[0], _southWestContact, unusedContact, DoSourceContact ); + } else if (not _west and _south) { + _southWestContact = doRp_Access( _gcell, biggestRp, NoFlags ); + } else if (_west and _south) { + AutoContact* rpContact = doRp_Access( _gcell, biggestRp, NoFlags ); + _southWestContact = AutoContactVTee::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, _southWestContact, Flags::Vertical ); + } + + if (_east and not _north) { + doRp_AutoContacts( _gcell, _routingPads[_routingPads.size()-1], _northEastContact, unusedContact, DoSourceContact ); + } else if (not _east and _north) { + _northEastContact = doRp_Access( _gcell, biggestRp, NoFlags ); + } else if (_east and _north) { + AutoContact* rpContact = doRp_Access( _gcell, biggestRp, NoFlags ); + _northEastContact = AutoContactVTee::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, _northEastContact, Flags::Vertical ); + } + + cdebug_tabw(145,-1); + } + + + void GCellTopology::_do_1G_1M3 () + { + cdebug_log(145,1) << "_do_1G_1M3() [Optimised Configuration]" << endl; + + unsigned int flags = (_east or _west) ? HAccess : NoFlags; + flags |= (_north) ? DoTargetContact : NoFlags; + flags |= (_south) ? DoSourceContact : NoFlags; + + doRp_AutoContacts( _gcell + , _routingPads[0] + , _southWestContact + , _northEastContact + , flags + ); + if (not _southWestContact) _southWestContact = _northEastContact; + if (not _northEastContact) _northEastContact = _southWestContact; + + cdebug_log(145,0) << "_southWest: " << _southWestContact << endl; + cdebug_log(145,0) << "_northEast: " << _northEastContact << endl; + + if (flags & HAccess) { + // HARDCODED VALUE. + if (_routingPads[0]->getBoundingBox().getHeight() < 3*Session::getPitch(1)) { + AutoContact* subContact = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( _southWestContact, subContact, Flags::Vertical ); + + _southWestContact = _northEastContact = subContact; + } + } else { + if (_sourceContact) { + if (_sourceContact->getX() != _southWestContact->getX()) { + AutoContactTurn* turn1 = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoContactTurn* turn2 = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( _southWestContact, turn1, Flags::Vertical ); + AutoSegment::create( turn1 , turn2, Flags::Horizontal ); + _southWestContact = _northEastContact = turn2; + } + } + } + cdebug_tabw(145,-1); + } + + + void GCellTopology::_do_xG_xM3 () + { + cdebug_log(145,1) << "_do_xG_" << _connexity.fields.M3 + << "M3() [Managed Configuration]" << endl; + cdebug_log(145,0) << "_west:" << _west << endl; + cdebug_log(145,0) << "_east:" << _east << endl; + cdebug_log(145,0) << "_south:" << _south << endl; + cdebug_log(145,0) << "_north:" << _north << endl; + + sort( _routingPads.begin(), _routingPads.end(), SortRpByY(NoFlags) ); // increasing Y. + for ( unsigned int i=1 ; i<_routingPads.size() ; i++ ) { + doRp_StairCaseV( _gcell, _routingPads[i-1], _routingPads[i] ); + } + + AutoContact* unusedContact = NULL; + Component* rp = _routingPads[0]; + + if (_west and not _south) { + _southWestContact = doRp_Access( _gcell, rp, HAccess ); + } else if (not _west and _south) { + doRp_AutoContacts( _gcell, rp, _southWestContact, unusedContact, DoSourceContact ); + if (_sourceContact) { + if (_sourceContact->getX() != _southWestContact->getX()) { + cdebug_log(149,0) << "Misaligned South: _source:" << DbU::getValueString(_sourceContact->getX()) + << "_southWest:" << DbU::getValueString(_southWestContact->getX()) << endl; + + AutoContactTurn* turn1 = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoContactTurn* turn2 = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( _southWestContact, turn1, Flags::Vertical ); + AutoSegment::create( turn1 , turn2, Flags::Horizontal ); + _southWestContact = turn2; + } + } + } else if (_west and _south) { + AutoContact* rpContact = NULL; + doRp_AutoContacts( _gcell, rp, rpContact, unusedContact, DoSourceContact ); + _southWestContact = AutoContactVTee::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, _southWestContact, Flags::Vertical ); + } + + rp = _routingPads[_routingPads.size()-1]; + if (_east and not _north) { + _northEastContact = doRp_Access( _gcell, rp, HAccess ); + } else if (not _east and _north) { + doRp_AutoContacts( _gcell, rp, unusedContact, _northEastContact, DoTargetContact ); + if (_sourceContact) { + if (_sourceContact->getX() != _northEastContact->getX()) { + cdebug_log(149,0) << "Misaligned North: _source:" << DbU::getValueString(_sourceContact->getX()) + << "_southWest:" << DbU::getValueString(_northEastContact->getX()) << endl; + + AutoContactTurn* turn1 = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoContactTurn* turn2 = AutoContactTurn::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( _northEastContact, turn1, Flags::Vertical ); + AutoSegment::create( turn1 , turn2, Flags::Horizontal ); + _northEastContact = turn2; + } + } + } else if (_east and _north) { + AutoContact* rpContact = NULL; + doRp_AutoContacts( _gcell, rp, unusedContact, rpContact, DoTargetContact ); + _northEastContact = AutoContactVTee::create( _gcell, _net, Session::getContactLayer(1) ); + AutoSegment::create( rpContact, _northEastContact, Flags::Vertical ); + } + + cdebug_tabw(145,-1); + } + + + void singleGCell ( AnabaticEngine* anbt, Net* net ) + { + cdebug_log(145,1) << "singleGCell() " << net << endl; + + vector rpM1s; + Component* rpM2 = NULL; + + forEach ( RoutingPad*, irp, net->getRoutingPads() ) { + if (Session::getRoutingGauge()->getLayerDepth(irp->getLayer()) == 1) + rpM2 = *irp; + else + rpM1s.push_back( *irp ); + } + + if ((rpM1s.size() < 2) and not rpM2) { + cerr << Error( "For %s, less than two Plugs/Pins (%d)." + , getString(net).c_str() + , rpM1s.size() ) << endl; + cdebug_tabw(145,-1); + return; + } + + sort( rpM1s.begin(), rpM1s.end(), SortRpByX(NoFlags) ); // increasing X. + + GCell* gcell1 = anbt->getGCellUnder( (*rpM1s.begin ())->getCenter() ); + GCell* gcell2 = anbt->getGCellUnder( (*rpM1s.rbegin())->getCenter() ); + + if (not gcell1) { + cerr << Error( "No GCell under %s.", getString(rpM1s[0]).c_str() ) << endl; + cdebug_tabw(145,-1); + return; + } + if (gcell1 != gcell2) { + cerr << Error( "Not under a single GCell %s.", getString(rpM1s[0]).c_str() ) << endl; + cdebug_tabw(145,-1); + return; + } + + cdebug_log(145,0) << "singleGCell " << gcell1 << endl; + + AutoContact* turn = NULL; + AutoContact* source = NULL; + AutoContact* target = NULL; + + for ( size_t irp=1 ; irpgetNet(), Session::getContactLayer(1) ); + AutoSegment::create( source, turn , Flags::Horizontal ); + AutoSegment::create( turn , target, Flags::Vertical ); + } + + cdebug_tabw(145,-1); + } + + +} // Anonymous namespace. + + + + +namespace Anabatic { + + using Hurricane::Name; + using Hurricane::DebugSession; + using Hurricane::Error; + using Hurricane::Warning; + using Hurricane::Bug; + using CRL::addMeasure; + using CRL::getMeasure; + + + void AnabaticEngine::_loadGrByNet () + { + cmess1 << " o Loading Nets global routing from Knik." << endl; + //cmess1 << Dots::asDouble(" - Saturation",getMeasure(getCell(),"Sat.")->getData()) << endl; + + startMeasures(); + Session::open( this ); + + forEach ( Net*, inet, getCell()->getNets() ) { + if (NetRoutingExtension::isAutomaticGlobalRoute(*inet)) { + DebugSession::open( *inet, 140, 150 ); + _loadNetGlobalRouting( *inet ); + Session::revalidate(); + DebugSession::close(); + } + } // forEach(Net*) + +#if defined(CHECK_DATABASE) + _check ( "after Anabatic loading" ); +#endif + + Session::close(); + + stopMeasures(); + printMeasures( "load" ); + + addMeasure( getCell(), "Globals", AutoSegment::getGlobalsCount() ); + addMeasure( getCell(), "Edges" , AutoSegment::getAllocateds() ); + } + + + void AnabaticEngine::_loadNetGlobalRouting ( Net* net ) + { + cdebug_log(149,0) << "Anabatic::_loadNetGlobalRouting( " << net << " )" << endl; + cdebug_tabw(145,1); + + ForkStack forks; + Hook* sourceHook = NULL; + AutoContact* sourceContact = NULL; + + lookupClear(); + + RoutingPads routingPads = net->getRoutingPads(); + size_t degree = routingPads.getSize(); + + if (degree == 0) { + cmess2 << Warning("Net \"%s\" do not have any RoutingPad (ignored)." + ,getString(net->getName()).c_str()) << endl; + cdebug_tabw(145,-1); + return; + } + if (degree < 2) { +#if 0 + if (not getDemoMode()) + cmess2 << Warning("Net \"%s\" have less than 2 plugs/pins (ignored)." + ,getString(net->getName()).c_str()) << endl; +#endif + cdebug_tabw(145,-1); + return; + } + + cdebug_tabw(145,1); + Hook* startHook = NULL; + GCell* lowestGCell = NULL; + size_t unconnecteds = 0; + size_t connecteds = 0; + + GCellTopology::init( degree ); + + cdebug_log(145,0) << "Start RoutingPad Ring" << endl; + forEach ( RoutingPad*, startRp, routingPads ) { + bool segmentFound = false; + + forEach ( Hook*, ihook, startRp->getBodyHook()->getHooks() ) { + cdebug_log(145,0) << "Component " << ihook->getComponent() << endl; + Segment* segment = dynamic_cast( ihook->getComponent() ); + + if (segment) { + ++connecteds; + segmentFound = true; + + GCellTopology gcellConf ( this, *ihook, NULL ); + if (gcellConf.getStateG() == 1) { + if ( (lowestGCell == NULL) or (*gcellConf.getGCell() < *lowestGCell) ) { + cdebug_log(145,0) << "Starting from GCell " << gcellConf.getGCell() << endl; + lowestGCell = gcellConf.getGCell(); + startHook = *ihook; + } + break; + } + } + } + + unconnecteds += (segmentFound) ? 0 : 1; + if ( (unconnecteds > 10) and (connecteds == 0) ) { + cerr << Warning("More than 10 unconnected RoutingPads (%u) on %s, missing global routing?" + ,unconnecteds, getString(net->getName()).c_str() ) << endl; + + NetRoutingExtension::create( net )->setFlags ( NetRoutingState::Excluded ); + NetRoutingExtension::create( net )->unsetFlags( NetRoutingState::AutomaticGlobalRoute ); + cdebug_tabw(145,-1); + return; + } + // Uncomment the next line to disable the lowest GCell search. + // (takes first GCell with exactly one global). + //if (startHook) break; + } + cdebug_tabw(145,-1); + + if (startHook == NULL) { singleGCell( this, net ); cdebug_tabw(145,-1); return; } + + GCellTopology startGCellConf ( this, startHook, NULL ); + startGCellConf.construct( forks ); + + sourceHook = forks.getFrom (); + sourceContact = forks.getContact(); + forks.pop(); + + while ( sourceHook ) { + GCellTopology gcellConf ( this, sourceHook, sourceContact ); + gcellConf.construct( forks ); + + sourceHook = forks.getFrom(); + sourceContact = forks.getContact(); + forks.pop(); + + cdebug_log(145,0) << "Popping (from) " << sourceHook << endl; + cdebug_log(145,0) << "Popping (to) " << sourceContact << endl; + } + + lookupClear(); + Session::revalidate(); + +#if THIS_IS_DISABLED + set::iterator iover = overconstraineds.begin(); + for ( ; iover != overconstraineds.end() ; ++iover ) { + (*iover)->makeDogLeg( (*iover)->getAutoSource()->getGCell(), true ); + } +#endif + + Session::revalidate(); + GCellTopology::fixSegments(); + cdebug_tabw(145,-1); + } + + +} // Anabatic namespace. diff --git a/anabatic/src/NetConstraints.cpp b/anabatic/src/NetConstraints.cpp new file mode 100644 index 00000000..5100dfc2 --- /dev/null +++ b/anabatic/src/NetConstraints.cpp @@ -0,0 +1,192 @@ + +// -*- 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 | +// | A n a b a t i c - Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./NetConstraints.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/DebugSession.h" +#include "hurricane/BasicLayer.h" +#include "hurricane/Net.h" +#include "hurricane/NetExternalComponents.h" +#include "hurricane/RoutingPad.h" +#include "hurricane/Pad.h" +#include "hurricane/Plug.h" +#include "hurricane/Instance.h" +#include "hurricane/Vertical.h" +#include "hurricane/Horizontal.h" +#include "hurricane/Cell.h" +#include "anabatic/AutoContact.h" +#include "anabatic/AutoSegment.h" +#include "anabatic/Session.h" +#include "anabatic/AnabaticEngine.h" + + +namespace { + + + // \addtogroup NetConstraints + // \{ + + /* \function void propagateConstraintFromRp ( RoutingPad* rp ) + * \param rp The \c RoutingPad starting point. + * + * Do a full constraint propagation starting from this \c RoutingPad. + */ + + // \} + + + using namespace std; + using namespace CRL; + using namespace Hurricane; + using namespace Anabatic; + + +// ----------------------------------------------------------------- +// Local Functions. + + + void propagateConstraintFromRp ( RoutingPad* rp ) + { + cdebug_log(145,1) << "propagateConstraintFromRp() - " << rp << endl; + + forEach ( Component*, icomponent, rp->getSlaveComponents() ) { + cdebug_log(145,0) << "slave component: " << *icomponent << endl; + AutoContact* sourceContact = Session::lookup( dynamic_cast(*icomponent) ); + if (sourceContact) { + cdebug_log(145,0) << "Start slave: " << sourceContact << endl; + + set verticalSegments; + set horizontalSegments; + + forEach ( AutoSegment*, isegment, sourceContact->getAutoSegments() ) { + cdebug_log(145,0) << "Examining: " << (*isegment) << endl; + AutoContact* targetContact = isegment->getOppositeAnchor(sourceContact); + + if (targetContact) { + if (isegment->isHorizontal()) { + cdebug_log(145,0) << "On horizontal stack " << (*isegment) << endl; + horizontalSegments.insert( (*isegment) ); + } else { + cdebug_log(145,0) << "On vertical stack " << (*isegment) << endl; + verticalSegments.insert( (*isegment) ); + } + } + } + + Box constraintBox = sourceContact->getConstraintBox(); + + // Propagate constraint through horizontally aligned segments. + cdebug_log(145,0) << "Propagate constraint on horizontal segments" << endl; + + set::iterator ihorizontal = horizontalSegments.begin(); + for ( ; ihorizontal != horizontalSegments.end() ; ++ihorizontal ) { + AutoContact* contact = NULL; + forEach ( AutoSegment*, ialigned, (*ihorizontal)->getAligneds() ) { + contact = ialigned->getAutoTarget(); + cdebug_log(145,0) << "contact: " << contact << endl; + if (contact) { + cdebug_log(145,0) << "Apply to (target): " << contact << endl; + contact->restrictConstraintBox( constraintBox.getYMin() + , constraintBox.getYMax() + , Flags::Horizontal|Flags::WarnOnError ); + } + contact = ialigned->getAutoSource(); + cdebug_log(145,0) << "contact: " << contact << endl; + if (contact) { + cdebug_log(145,0) << "Apply to (source): " << contact << endl; + contact->restrictConstraintBox( constraintBox.getYMin() + , constraintBox.getYMax() + , Flags::Horizontal|Flags::WarnOnError ); + } + } + } + + // Propagate constraint through vertically aligned segments. + cdebug_log(145,0) << "Propagate constraint on vertical segments" << endl; + + set::iterator ivertical = verticalSegments.begin(); + for ( ; ivertical != verticalSegments.end() ; ++ivertical ) { + AutoContact* contact = NULL; + forEach ( AutoSegment*, ialigned, (*ivertical)->getAligneds() ) { + contact = ialigned->getAutoTarget(); + if (contact) { + cdebug_log(145,0) << "Apply to (target): " << contact << endl; + contact->restrictConstraintBox( constraintBox.getXMin() + , constraintBox.getXMax() + , Flags::Vertical|Flags::WarnOnError ); + } + contact = ialigned->getAutoSource(); + if (contact) { + cdebug_log(145,0) << "Apply to (source): " << contact << endl; + contact->restrictConstraintBox( constraintBox.getXMin() + , constraintBox.getXMax() + , Flags::Vertical|Flags::WarnOnError ); + } + } + } + } + } + + cdebug_log(145,0) << "propagateConstraintFromRp() - Exit" << endl; + cdebug_tabw(145,-1); + } + + +} // Anonymous namespace. + + + +namespace Anabatic { + + + using Hurricane::Cell; + + + void AnabaticEngine::computeNetConstraints ( Net* net ) + { + DebugSession::open( net, 140, 150); + + cdebug_log(149,0) << "Anabatic::computeNetConstraints( " << net << " )" << endl; + cdebug_tabw(145,1); + + vector routingPads; + forEach ( Component*, icomponent, net->getComponents() ) { + Contact* contact = dynamic_cast( *icomponent ); + if (contact) { + AutoContact* autoContact = Session::lookup( contact ); + if (autoContact) + autoContact->restoreNativeConstraintBox(); + } else { + RoutingPad* routingPad = dynamic_cast( *icomponent ); + if (routingPad) routingPads.push_back( routingPad ); + } + } + + for ( size_t i=0 ; igetSegments() ) { + // AutoSegment* autoSegment = Session::lookup( *isegment ); + // if (autoSegment) autoSegment->toConstraintAxis(); + // } + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + +} // Anabatic namespace. diff --git a/anabatic/src/NetOptimals.cpp b/anabatic/src/NetOptimals.cpp new file mode 100644 index 00000000..90470f59 --- /dev/null +++ b/anabatic/src/NetOptimals.cpp @@ -0,0 +1,82 @@ + +// -*- 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 | +// | A n a b a t i c - Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./NetOptimals.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/DebugSession.h" +#include "hurricane/Net.h" +#include "hurricane/Segment.h" +#include "anabatic/Session.h" +#include "anabatic/AutoSegment.h" +#include "anabatic/AnabaticEngine.h" + + +namespace Anabatic { + + using namespace std; + using Hurricane::tab; + using Hurricane::ForEachIterator; + using Hurricane::Net; + using Hurricane::Segment; + using Hurricane::DebugSession; + + + void AnabaticEngine::_computeNetOptimals ( Net* net ) + { + DebugSession::open( net, 140, 150 ); + cdebug_log(149,0) << "Anabatic::_computeNetOptimals( " << net << " )" << endl; + cdebug_tabw(145,1); + + vector segments; + forEach ( Segment*, segment, net->getSegments() ) { + AutoSegment* autoSegment = Session::lookup( *segment ); + if (autoSegment) segments.push_back( autoSegment ); + } + sort( segments.begin(), segments.end(), AutoSegment::CompareId() ); + + set processeds; + for ( size_t i=0 ; icomputeOptimal( processeds ); + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + + void AnabaticEngine::toOptimals ( Net* net ) + { + DebugSession::open( net, 140, 150 ); + cdebug_log(149,0) << "Anabatic::_toOptimals( " << net << " )" << endl; + cdebug_tabw(145,1); + + vector segments; + forEach ( Segment*, segment, net->getSegments() ) { + AutoSegment* autoSegment = Session::lookup( *segment ); + if (autoSegment) segments.push_back( autoSegment ); + } + sort( segments.begin(), segments.end(), AutoSegment::CompareId() ); + + for ( size_t i=0 ; iisCanonical()) segments[i]->toOptimalAxis(); + } + + cdebug_tabw(145,-1); + DebugSession::close(); + } + + +} // Anabatic namespace. diff --git a/anabatic/src/Session.cpp b/anabatic/src/Session.cpp new file mode 100644 index 00000000..bdb7657d --- /dev/null +++ b/anabatic/src/Session.cpp @@ -0,0 +1,407 @@ +// -*- mode: C++; explicit-buffer-name: "Session.cpp" -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2016, 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 : "./Session.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/Error.h" +#include "hurricane/Horizontal.h" +#include "hurricane/Vertical.h" +#include "hurricane/Cell.h" +#include "hurricane/UpdateSession.h" +#include "crlcore/RoutingGauge.h" +#include "anabatic/Configuration.h" +#include "anabatic/Session.h" +#include "anabatic/AutoContact.h" +#include "anabatic/AutoSegment.h" +#include "anabatic/AnabaticEngine.h" + + +namespace { + + + const char* reopenSession = + "Session::open() :\n\n" + " Session already open for %s (internal error)."; + + const char* openSessionError = + "%s :\n\n" + " Session has not been opened (internal error)."; + + +} // End of local namespace. + + + + +namespace Anabatic { + + using namespace std; + using Hurricane::tab; + using Hurricane::Error; + using Hurricane::ForEachIterator; + using Hurricane::UpdateSession; + using Hurricane::Horizontal; + using Hurricane::Vertical; + using Hurricane::Cell; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::Session". + + Session* Session::_session = NULL; + + + Session* Session::get ( const char* message ) + { + if (not _session and message) + throw Error( openSessionError, message ); + return _session; + } + + + Session::Session ( AnabaticEngine* anbt ) + : _anabatic (anbt) + , _technology (anbt->getConfiguration()->getRoutingGauge()->getTechnology()) + , _cellGauge (anbt->getConfiguration()->getCellGauge()) + , _routingGauge (anbt->getConfiguration()->getRoutingGauge()) + , _autoContacts () + , _doglegs () + , _segmentInvalidateds() + , _segmentRevalidateds() + , _netInvalidateds () + , _netRevalidateds () + { } + + + void Session::_postCreate () + { + UpdateSession::open(); + _session = this; + } + + + Session::~Session () + { } + + + void Session::_preDestroy () + { + if (_anabatic->getState() <= EngineActive) { + _revalidate (); + + _anabatic->updateDensity(); + } + UpdateSession::close(); + } + + + bool Session::_doDestroyBaseContact () { return _anabatic->doDestroyBaseContact(); } + bool Session::_doDestroyBaseSegment () { return _anabatic->doDestroyBaseSegment(); } + bool Session::_doDestroyTool () { return _anabatic->doDestroyTool(); } + Configuration* Session::_getConfiguration () { return _anabatic->getConfiguration(); } + + + void Session::_invalidate ( Net* net ) + { + cdebug_log(149,0) << "Session::invalidate(Net*) - " << net << endl; + _netInvalidateds.insert(net); + } + + + void Session::_canonize () + { + cdebug_log(145,1) << "Anabatic::Session::_canonize()" << endl; + + if (_segmentInvalidateds.empty()) { + cdebug_log(145,0) << "Invalidated AutoSegment collection <_segmentInvalidateds> is empty." << endl; + cdebug_tabw(145,-1); + return; + } + + set exploredSegments; + vector aligneds; + + // Should no longer be necessary to ensure determinism. + //sort( _segmentInvalidateds.begin(), _segmentInvalidateds.end(), AutoSegment::CompareId() ); + + for ( size_t i=0 ; i<_segmentInvalidateds.size() ; i++ ) { + AutoSegment* seedSegment = _segmentInvalidateds[i]; + AutoSegment* canonical = seedSegment; + + if (exploredSegments.find(seedSegment->base()) == exploredSegments.end()) { + cdebug_log(145,0) << "New chunk from: " << seedSegment << endl; + aligneds.push_back( seedSegment ); + + bool isWeakGlobal = seedSegment->isGlobal(); + if (not seedSegment->isNotAligned()) { + forEach ( AutoSegment*, aligned, seedSegment->getAligneds() ) { + cdebug_log(145,0) << "Aligned: " << *aligned << endl; + aligneds.push_back ( *aligned ); + exploredSegments.insert ( aligned->base() ); + + isWeakGlobal = isWeakGlobal or aligned->isGlobal(); + if (AutoSegment::CompareId()( *aligned, canonical )) + canonical = *aligned; + } + } + + cdebug_tabw(145,1); + + canonical->setFlags( SegCanonical ); + cdebug_log(145,0) << "Canonical: " << canonical << endl; + + for ( size_t j=0 ; jisGlobal()) aligneds[j]->setFlags ( SegWeakGlobal ); + else aligneds[j]->unsetFlags( SegWeakGlobal ); + + if (aligneds[j] == canonical) continue; + if (aligneds[j]->isCanonical()) { + cerr << Error("Session::_canonize(): On %s\n" + " Segment is no longer the canonical one, this must not happens." + ,getString(aligneds[j]).c_str()) << endl; + } + aligneds[j]->unsetFlags( SegCanonical ); + cdebug_log(145,0) << "Secondary: " << aligneds[j] << endl; + } + if (aligneds.empty()) canonical->setFlags( SegNotAligned ); + + cdebug_log(149,0) << "Align @" << DbU::toLambda(canonical->getAxis()) + << " on " << canonical << endl; + + //canonical->setAxis( canonical->getAxis(), Flags::Realignate ); + if (canonical->isUnsetAxis()) canonical->toOptimalAxis( Flags::Realignate|Flags::Propagate ); + else canonical->setAxis( canonical->getAxis(), Flags::Realignate|Flags::Propagate ); + aligneds.clear(); + cdebug_tabw(145,-1); + } + } + + cdebug_tabw(145,-1); + } + + + void Session::_revalidateTopology () + { + cdebug_log(145,1) << "Anabatic::Session::_revalidateTopology()" << endl; + + set::iterator inet = _netInvalidateds.begin(); + + for ( ; inet != _netInvalidateds.end() ; inet++ ) { + cdebug_log(145,0) << "Anabatic::Session::_revalidateTopology(Net*)" << *inet << endl; + _anabatic->updateNetTopology ( *inet ); + _anabatic->computeNetConstraints( *inet ); + _anabatic->_computeNetOptimals ( *inet ); + _anabatic->_computeNetTerminals ( *inet ); + } + _canonize (); + + for ( size_t i=0 ; i<_segmentInvalidateds.size() ; ++i ) { + if (_segmentInvalidateds[i]->isCanonical()) { + if (_segmentInvalidateds[i]->isUnsetAxis()) _segmentInvalidateds[i]->toOptimalAxis(); + else _segmentInvalidateds[i]->toConstraintAxis(); + } + } + + _netRevalidateds.clear(); + _netRevalidateds.swap( _netInvalidateds ); + + cdebug_tabw(145,-1); + } + + + size_t Session::_revalidate () + { + cdebug_log(145,1) << "Anabatic::Session::revalidate()" << endl; + cdebug_log(145,0) << "_segmentInvalidateds.size(): " << _segmentInvalidateds.size() << endl; + cdebug_log(145,0) << "_autoContacts.size(): " << _autoContacts.size() << endl; + + size_t count = 0; + + if (not _netInvalidateds.empty()) _revalidateTopology(); + + cdebug_log(145,0) << "AutoContacts Revalidate (after _revalidateTopology())." << endl; + for ( size_t i=0 ; i < _autoContacts.size() ; i++, count++ ) + _autoContacts[i]->updateGeometry(); + _autoContacts.clear(); + + cdebug_log(145,0) << "AutoSegments Revalidate (after AutoContact::updateGeometry())." << endl; + cdebug_log(145,0) << "_segmentInvalidateds.size(): " << _segmentInvalidateds.size() << endl; + + _segmentRevalidateds.clear(); + for ( size_t i=0 ; i < _segmentInvalidateds.size() ; ++i, ++count ) { + _segmentInvalidateds[i]->revalidate(); + if ( not _destroyedSegments.empty() + and (_destroyedSegments.find(_segmentInvalidateds[i]) != _destroyedSegments.end()) ) + continue; + + _segmentRevalidateds.push_back( _segmentInvalidateds[i] ); + } + _segmentInvalidateds.clear(); + + cdebug_log(145,0) << "AutoSegments/AutoContacts queued deletion." << endl; + unsigned int flags = _anabatic->flags() & Flags::DestroyMask; + _anabatic->flags() = Flags::DestroyMask; + set::iterator isegment = _destroyedSegments.begin(); + for ( ; isegment != _destroyedSegments.end() ; isegment++ ) { + AutoContact* source = (*isegment)->getAutoSource(); + AutoContact* target = (*isegment)->getAutoTarget(); + (*isegment)->destroy(); + if (source and source->canDestroy(true)) source->destroy(); + if (target and target->canDestroy(true)) target->destroy(); + } + _anabatic->flags() = flags; + set().swap( _destroyedSegments ); + + cdebug_tabw(145,-1); + + return count; + } + + + Session* Session::open ( AnabaticEngine* anbt ) + { + cdebug_log(145,0) << "Session::open()" << endl; + + if (_session) { + if (_session->_anabatic != anbt) + throw Error( reopenSession, getString(_session->getAnabatic()).c_str() ); + + return _session; + } + + Session* session = new Session ( anbt ); + session->_postCreate(); + + return session; + } + + + void Session::close () + { + cdebug_log(145,1) << "Session::close()" << endl; + + if (not _session) throw Error( openSessionError, "Session::Close()" ); + + _session->_preDestroy(); + + delete _session; + _session = NULL; + + cdebug_tabw(145,-1); + } + + + unsigned int Session::getDirection ( size_t depth ) + { + RoutingGauge* rg = get("getDirection()")->_routingGauge; + switch ( rg->getLayerDirection(depth) ) { + case Constant::Horizontal: return Flags::Horizontal; + case Constant::Vertical: return Flags::Vertical; + } + return 0; + } + + + DbU::Unit Session::_getPitch ( size_t depth, unsigned int flags ) const + { + if (flags == Flags::NoFlags) return _routingGauge->getLayerPitch(depth); + + if (flags & Flags::AboveLayer) { + if (depth < getAllowedDepth()) + return _routingGauge->getLayerPitch( depth + 1 ); + else { + if ( (depth > 0) and (_routingGauge->getLayerType(depth-1) != Constant::PinOnly) ) + return _routingGauge->getLayerPitch( depth - 1 ); + } + } + + if (flags & Flags::BelowLayer) { + if ( (depth > 0) and (_routingGauge->getLayerType(depth-1) != Constant::PinOnly) ) + return _routingGauge->getLayerPitch( depth - 1 ); + else { + if (depth < getAllowedDepth()) + return _routingGauge->getLayerPitch( depth + 1 ); + } + } + + // Should issue at least a warning here. + return _routingGauge->getLayerPitch(depth); + } + + + bool Session::isInDemoMode () + { return get("isInDemoMode()")->_anabatic->isInDemoMode(); } + + + float Session::getSaturateRatio () + { return get("getSaturateRatio()")->_anabatic->getSaturateRatio(); } + + + size_t Session::getSaturateRp () + { return get("getSaturateRp()")->_anabatic->getSaturateRp(); } + + + bool Session::doWarnGCellOverload () + { return get("doWarnGCellOverload()")->_anabatic->doWarnOnGCellOverload(); } + + + void Session::setAnabaticFlags ( unsigned int flags ) + { get("setKabaticFlags()")->_anabatic->flags() = flags; } + + + void Session::link ( AutoContact* autoContact ) + { return get("link(AutoContact*)")->_anabatic->_link( autoContact ); } + + + void Session::link ( AutoSegment* autoSegment ) + { return get("link(AutoSegment*)")->_anabatic->_link( autoSegment ); } + + + void Session::unlink ( AutoContact* autoContact ) + { return get("unlink(AutoContact*)")->_anabatic->_unlink( autoContact ); } + + + void Session::unlink ( AutoSegment* autoSegment ) + { return get("unlink(AutoSegment*)")->_anabatic->_unlink( autoSegment ); } + + + AutoContact* Session::lookup ( Contact* contact ) + { return get("lookup(Contact*)")->_anabatic->_lookup( contact ); } + + + AutoSegment* Session::lookup ( Segment* segment ) + { return get("lookup(Segment*)")->_anabatic->_lookup( segment ); } + + + string Session::_getString () const + { + return "<" + _getTypeName() + " " + + getString(_anabatic->getCell()->getName()) + + ">"; + } + + + Record* Session::_getRecord () const + { + Record* record = new Record ( _getString() ); + record->add ( getSlot ( "_anabatic" , _anabatic ) ); + record->add ( getSlot ( "_autoContacts", &_autoContacts ) ); + //record->add ( getSlot ( "_autoSegments", &_autoSegments ) ); + return record; + } + + +} // End of Anabatic namespace. diff --git a/anabatic/src/anabatic/AnabaticEngine.h b/anabatic/src/anabatic/AnabaticEngine.h index 01d12638..468accfc 100644 --- a/anabatic/src/anabatic/AnabaticEngine.h +++ b/anabatic/src/anabatic/AnabaticEngine.h @@ -34,6 +34,8 @@ namespace Hurricane { #include "anabatic/Configuration.h" #include "anabatic/Matrix.h" #include "anabatic/GCell.h" +#include "anabatic/AutoContact.h" +#include "anabatic/AutoSegments.h" namespace Anabatic { @@ -53,80 +55,150 @@ namespace Anabatic { class AnabaticEngine : public ToolEngine { + public: + enum DensityMode { AverageHVDensity=1 // Average between all densities. + , AverageHDensity =2 // Average between all H densities. + , AverageVDensity =3 // Average between all V densities. + , MaxHVDensity =4 // Maximum between average H and average V. + , MaxVDensity =5 // Maximum of V densities. + , MaxHDensity =6 // Maximum of H densities. + , MaxDensity =7 // Maximum of H & V densities. + }; public: typedef ToolEngine Super; public: - static AnabaticEngine* create ( Cell* ); - static AnabaticEngine* get ( const Cell* ); - static const Name& staticGetName (); - virtual const Name& getName () const; - virtual Configuration* getConfiguration (); - inline CellViewer* getViewer () const; - inline void setViewer ( CellViewer* ); - inline const Matrix* getMatrix () const; - inline const vector& getGCells () const; - inline const vector& getOvEdges () const; - inline GCell* getSouthWestGCell () const; - inline GCell* getGCellUnder ( DbU::Unit x, DbU::Unit y ) const; - inline GCell* getGCellUnder ( Point ) const; - int getCapacity ( Interval, Flags ) const; - size_t getNetsFromEdge ( const Edge*, NetSet& ); - inline void addOv ( Edge* ); - inline void removeOv ( Edge* ); - // Dijkstra related functions. - inline int getStamp () const; - inline int incStamp (); - // Global routing related functions. - void globalRoute (); - // Misc. functions. - inline const Flags& flags () const; - inline Flags& flags (); - void reset (); - void startMeasures (); - void stopMeasures (); - void printMeasures ( const string& ) const; - inline void _add ( GCell* ); - inline void _remove ( GCell* ); - inline void _updateLookup ( GCell* ); - inline bool _inDestroy () const; - // Inspector support. - virtual Record* _getRecord () const; - virtual string _getString () const; - virtual string _getTypeName () const; - protected: - AnabaticEngine ( Cell* ); - virtual ~AnabaticEngine (); - virtual void _postCreate (); - virtual void _preDestroy (); - void _clear (); - private: - AnabaticEngine ( const AnabaticEngine& ); - AnabaticEngine& operator= ( const AnabaticEngine& ); + static AnabaticEngine* create ( Cell* ); + static AnabaticEngine* get ( const Cell* ); + static const Name& staticGetName (); + virtual const Name& getName () const; + virtual Configuration* getConfiguration (); + inline unsigned int getDensityMode () const; + inline CellViewer* getViewer () const; + inline void setViewer ( CellViewer* ); + inline EngineState getState () const; + inline const Matrix* getMatrix () const; + inline const vector& getGCells () const; + inline const vector& getOvEdges () const; + inline GCell* getSouthWestGCell () const; + inline GCell* getGCellUnder ( DbU::Unit x, DbU::Unit y ) const; + inline GCell* getGCellUnder ( Point ) const; + int getCapacity ( Interval, Flags ) const; + size_t getNetsFromEdge ( const Edge*, NetSet& ); + inline void setState ( EngineState state ); + inline void setDensityMode ( unsigned int ); + inline void addOv ( Edge* ); + inline void removeOv ( Edge* ); + // Dijkstra related functions. + inline int getStamp () const; + inline int incStamp (); + // Global routing related functions. + void globalRoute (); + void cleanupGlobal (); + // Detailed routing related functions. + inline bool isInDemoMode () const; + inline bool doWarnOnGCellOverload () const; + inline bool doDestroyBaseContact () const; + inline bool doDestroyBaseSegment () const; + inline bool doDestroyTool () const; + inline DbU::Unit getGlobalThreshold () const; + inline float getSaturateRatio () const; + inline size_t getSaturateRp () const; + inline DbU::Unit getExtensionCap () const; + void updateDensity (); + inline void setGlobalThreshold ( DbU::Unit ); + inline void setSaturateRatio ( float ); + inline void setSaturateRp ( size_t ); + void loadGlobalRouting ( unsigned int method ); + void computeNetConstraints ( Net* ); + void toOptimals ( Net* ); + void updateNetTopology ( Net* ); + void finalizeLayout (); + inline const AutoContactLut& _getAutoContactLut () const; + inline const AutoSegmentLut& _getAutoSegmentLut () const; + void _link ( AutoContact* ); + void _link ( AutoSegment* ); + void _unlink ( AutoContact* ); + void _unlink ( AutoSegment* ); + AutoContact* _lookup ( Contact* ) const; + AutoSegment* _lookup ( Segment* ) const; + void _loadGrByNet (); + void _loadNetGlobalRouting ( Net* ); + void _computeNetOptimals ( Net* ); + void _computeNetTerminals ( Net* ); + void _alignate ( Net* ); + void _saveNet ( Net* ); + void _destroyAutoContacts (); + void _destroyAutoSegments (); + // Misc. functions. + inline const Flags& flags () const; + inline Flags& flags (); + void reset (); + void startMeasures (); + void stopMeasures (); + void printMeasures ( const string& ) const; + inline void _add ( GCell* ); + inline void _remove ( GCell* ); + inline void _updateLookup ( GCell* ); + inline bool _inDestroy () const; + // Inspector support. + virtual Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const; + protected: + AnabaticEngine ( Cell* ); + virtual ~AnabaticEngine (); + virtual void _postCreate (); + virtual void _preDestroy (); + void _gutAnabatic (); + private: + AnabaticEngine ( const AnabaticEngine& ); + AnabaticEngine& operator= ( const AnabaticEngine& ); private: - static Name _toolName; - Timer _timer; - Configuration* _configuration; - Matrix _matrix; - vector _gcells; - vector _ovEdges; - CellViewer* _viewer; - Flags _flags; - int _stamp; + static Name _toolName; + Timer _timer; + Configuration* _configuration; + EngineState _state; + Matrix _matrix; + vector _gcells; + vector _ovEdges; + CellViewer* _viewer; + Flags _flags; + int _stamp; + unsigned int _densityMode; + AutoSegmentLut _autoSegmentLut; + AutoContactLut _autoContactLut; }; - inline CellViewer* AnabaticEngine::getViewer () const { return _viewer; } - inline void AnabaticEngine::setViewer ( CellViewer* viewer ) { _viewer=viewer; } - inline const Matrix* AnabaticEngine::getMatrix () const { return &_matrix; } - inline const vector& AnabaticEngine::getGCells () const { return _gcells; } - inline const vector& AnabaticEngine::getOvEdges () const { return _ovEdges; } - inline GCell* AnabaticEngine::getSouthWestGCell () const { return _gcells[0]; } - inline GCell* AnabaticEngine::getGCellUnder ( DbU::Unit x, DbU::Unit y ) const { return _matrix.getUnder(x,y); } - inline GCell* AnabaticEngine::getGCellUnder ( Point p ) const { return _matrix.getUnder(p); } - inline const Flags& AnabaticEngine::flags () const { return _flags; } - inline Flags& AnabaticEngine::flags () { return _flags; } - inline void AnabaticEngine::_updateLookup ( GCell* gcell ) { _matrix.updateLookup(gcell); } - inline bool AnabaticEngine::_inDestroy () const { return _flags & Flags::Destroy; } + inline EngineState AnabaticEngine::getState () const { return _state; } + inline void AnabaticEngine::setState ( EngineState state ) { _state = state; } + inline CellViewer* AnabaticEngine::getViewer () const { return _viewer; } + inline void AnabaticEngine::setViewer ( CellViewer* viewer ) { _viewer=viewer; } + inline const Matrix* AnabaticEngine::getMatrix () const { return &_matrix; } + inline const vector& AnabaticEngine::getGCells () const { return _gcells; } + inline const vector& AnabaticEngine::getOvEdges () const { return _ovEdges; } + inline GCell* AnabaticEngine::getSouthWestGCell () const { return _gcells[0]; } + inline GCell* AnabaticEngine::getGCellUnder ( DbU::Unit x, DbU::Unit y ) const { return _matrix.getUnder(x,y); } + inline GCell* AnabaticEngine::getGCellUnder ( Point p ) const { return _matrix.getUnder(p); } + inline unsigned int AnabaticEngine::getDensityMode () const { return _densityMode; } + inline void AnabaticEngine::setDensityMode ( unsigned int mode ) { _densityMode=mode; } + inline const AutoContactLut& AnabaticEngine::_getAutoContactLut () const { return _autoContactLut; } + inline const AutoSegmentLut& AnabaticEngine::_getAutoSegmentLut () const { return _autoSegmentLut; } + inline const Flags& AnabaticEngine::flags () const { return _flags; } + inline Flags& AnabaticEngine::flags () { return _flags; } + inline bool AnabaticEngine::doDestroyBaseContact () const { return _flags & Flags::DestroyBaseContact; } + inline bool AnabaticEngine::doDestroyBaseSegment () const { return _flags & Flags::DestroyBaseSegment; } + inline bool AnabaticEngine::doDestroyTool () const { return _state >= EngineGutted; } + inline bool AnabaticEngine::doWarnOnGCellOverload () const { return _flags & Flags::WarnOnGCellOverload; } + inline bool AnabaticEngine::isInDemoMode () const { return _flags & Flags::DemoMode; } + inline DbU::Unit AnabaticEngine::getGlobalThreshold () const { return _configuration->getGlobalThreshold(); } + inline float AnabaticEngine::getSaturateRatio () const { return _configuration->getSaturateRatio(); } + inline size_t AnabaticEngine::getSaturateRp () const { return _configuration->getSaturateRp(); } + inline void AnabaticEngine::setSaturateRatio ( float ratio ) { _configuration->setSaturateRatio(ratio); } + inline void AnabaticEngine::setSaturateRp ( size_t threshold ) { _configuration->setSaturateRp(threshold); } + inline void AnabaticEngine::setGlobalThreshold ( DbU::Unit threshold ) { _configuration->setGlobalThreshold(threshold); } + inline void AnabaticEngine::_updateLookup ( GCell* gcell ) { _matrix.updateLookup(gcell); } + inline bool AnabaticEngine::_inDestroy () const { return _flags & Flags::DestroyMask; } inline void AnabaticEngine::_add ( GCell* gcell ) { diff --git a/anabatic/src/anabatic/AutoContact.h b/anabatic/src/anabatic/AutoContact.h new file mode 100644 index 00000000..b8027399 --- /dev/null +++ b/anabatic/src/anabatic/AutoContact.h @@ -0,0 +1,351 @@ +// -*- 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 | +// | A n a b a t i c - Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./anabatic/AutoContact.h" | +// +-----------------------------------------------------------------+ + + +#ifndef ANABATIC_AUTOCONTACT_H +#define ANABATIC_AUTOCONTACT_H + +#include +#include +#include "hurricane/Contact.h" +#include "hurricane/ExtensionGo.h" +#include "anabatic/Constants.h" +#include "anabatic/AutoSegment.h" +#include "anabatic/GCell.h" + + +namespace Anabatic { + + + using std::cerr; + using std::endl; + using Hurricane::tab; + using Hurricane::Name; + using Hurricane::Net; + using Hurricane::Component; + using Hurricane::Components; + using Hurricane::Layer; + using Hurricane::Contact; + using Hurricane::ExtensionGo; + + class AnabaticEngine; + class AutoHorizontal; + class AutoVertical; + class AutoContact; + + + typedef std::map AutoContactLut; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoContact". + + enum AutoContactFlag { CntFixed = 0x00000001 + , CntTerminal = 0x00000002 + , CntTurn = 0x00000004 + , CntHTee = 0x00000008 + , CntVTee = 0x00000010 + , CntInvalidated = 0x00000020 + , CntInvalidatedCache = 0x00000040 + , CntInCreationStage = 0x00000080 + , CntBadTopology = 0x00000100 + , CntIgnoreAnchor = 0x00000200 + , CntWeakTerminal = 0x00000400 + , CntUserNativeConstraints = 0x00000800 + }; + + class AutoContact { + public: + static AutoContact* createFrom ( Contact* ); + public: + // Wrapped Contact Accessors. + inline Hook* getBodyHook (); + inline Hook* getAnchorHook (); + inline Component* getAnchor () const; + inline Net* getNet () const; + inline const Layer* getLayer () const; + inline DbU::Unit getX () const; + inline DbU::Unit getY () const; + inline DbU::Unit getDx () const; + inline DbU::Unit getDy () const; + inline Point getCenter () const; + inline Point getPosition () const; + inline DbU::Unit getWidth () const; + inline DbU::Unit getHalfWidth () const; + inline DbU::Unit getHeight () const; + inline DbU::Unit getHalfHeight () const; + inline Components getSlaveComponents () const; + // Wrapped Contact Modifiers. + inline void setLayer ( const Layer* ); + inline void setWidth ( DbU::Unit ); + inline void setHeight ( DbU::Unit ); + inline void setSizes ( DbU::Unit width, DbU::Unit height ); + inline void setX ( DbU::Unit ); + inline void setY ( DbU::Unit ); + inline void setPosition ( DbU::Unit width, DbU::Unit height ); + inline void setPosition ( const Point& ); + inline void setDx ( DbU::Unit ); + inline void setDy ( DbU::Unit ); + inline void setOffset ( DbU::Unit dx, DbU::Unit dy ); + virtual void translate ( const DbU::Unit& tx, const DbU::Unit& ty ); + // Predicates. + inline bool isInCreationStage () const; + inline bool isInvalidated () const; + inline bool isInvalidatedCache () const; + inline bool isTerminal () const; + inline bool isTurn () const; + bool isTee ( unsigned int direction ) const; + inline bool isHTee () const; + inline bool isVTee () const; + inline bool isFixed () const; + inline bool isUserNativeConstraints () const; + inline bool hasBadTopology () const; + bool canDestroy ( unsigned int flags=0 ) const; + bool canMoveUp ( const AutoSegment* moved ) const; + // Accessors. + inline Contact* base () const; + static size_t getAllocateds (); + static const Name& getStaticName (); + virtual const Name& getName () const; + inline size_t getId () const; + virtual Box getBoundingBox () const; + inline GCell* getGCell () const; + virtual AutoSegment* getOpposite ( const AutoSegment* ) const = 0; + virtual AutoSegment* getPerpandicular ( const AutoSegment* ) const = 0; + virtual AutoSegment* getSegment ( unsigned int ) const = 0; + unsigned int getMinDepth () const; + unsigned int getMaxDepth () const; + void getLengths ( DbU::Unit* lengths, AutoSegment::DepthLengthSet& ); + virtual Box getNativeConstraintBox () const; + Interval getNativeUConstraints ( unsigned int direction ) const; + Interval getUConstraints ( unsigned int direction ) const; + inline DbU::Unit getCBXMin () const; + inline DbU::Unit getCBXMax () const; + inline DbU::Unit getCBYMin () const; + inline DbU::Unit getCBYMax () const; + inline Box getConstraintBox () const; + Box& intersectConstraintBox ( Box& box ) const; + // Collections. + AutoSegments getAutoSegments (); + // Modifiers. + void invalidate ( unsigned int flags=0 ); + virtual void cacheDetach ( AutoSegment* ) = 0; + virtual void cacheAttach ( AutoSegment* ) = 0; + virtual void updateCache () = 0; + virtual void updateGeometry () = 0; + virtual void updateTopology () = 0; + void showTopologyError ( const std::string&, unsigned int flags=0 ); + virtual void checkTopology (); + inline void setFlags ( unsigned int ); + inline void unsetFlags ( unsigned int ); + void setGCell ( GCell* ); + inline void setCBXMin ( DbU::Unit xMin ); + inline void setCBXMax ( DbU::Unit xMax ); + inline void setCBYMin ( DbU::Unit yMin ); + inline void setCBYMax ( DbU::Unit yMax ); + void setConstraintBox ( const Box& box ); + bool restrictConstraintBox ( DbU::Unit constraintMin + , DbU::Unit constraintMax + , unsigned int flags=Flags::WarnOnError ); + void restoreNativeConstraintBox (); + void migrateConstraintBox ( AutoContact* other ); + void destroy (); + // Inspector Management. + Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const; + + private: + // Internal: Attributes. + static size_t _maxId; + static size_t _allocateds; + static const Name _goName; + + protected: + size_t _id; + Contact* _contact; + GCell* _gcell; + unsigned int _flags; + int _dxMin:8; + int _dxMax:8; + int _dyMin:8; + int _dyMax:8; + + protected: + // Constructors & Destructors. + AutoContact ( GCell*, Contact* ); + virtual ~AutoContact (); + static void _preCreate ( GCell*, Net*, const Layer* ); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + AutoContact ( const AutoContact& ); + AutoContact& operator= ( const AutoContact& ); + + protected: + inline int _getDeltaMin ( DbU::Unit x, DbU::Unit xMin ); + inline int _getDeltaMax ( DbU::Unit x, DbU::Unit xMin, DbU::Unit xMax ); + static void _getTopology ( Contact*, Component*& anchor, Horizontal**&, Vertical**&, size_t ); + virtual void _invalidate ( unsigned int flags ) = 0; + }; + + +// Wrapped Contact Inline Functions. + inline Hook* AutoContact::getBodyHook () { return _contact->getBodyHook(); } + inline Hook* AutoContact::getAnchorHook () { return _contact->getAnchorHook(); } + inline Component* AutoContact::getAnchor () const { return _contact->getAnchor(); } + inline Net* AutoContact::getNet () const { return _contact->getNet(); } + inline const Layer* AutoContact::getLayer () const { return _contact->getLayer(); } + inline DbU::Unit AutoContact::getX () const { return _contact->getX(); } + inline DbU::Unit AutoContact::getY () const { return _contact->getY(); } + inline DbU::Unit AutoContact::getDx () const { return _contact->getDx(); } + inline DbU::Unit AutoContact::getDy () const { return _contact->getDy(); } + inline Point AutoContact::getCenter () const { return _contact->getCenter(); } + inline Point AutoContact::getPosition () const { return _contact->getPosition(); } + inline DbU::Unit AutoContact::getWidth () const { return _contact->getWidth(); } + inline DbU::Unit AutoContact::getHalfWidth () const { return _contact->getHalfWidth(); } + inline DbU::Unit AutoContact::getHeight () const { return _contact->getHeight(); } + inline DbU::Unit AutoContact::getHalfHeight () const { return _contact->getHalfHeight(); } + inline Components AutoContact::getSlaveComponents () const { return _contact->getSlaveComponents(); } + inline void AutoContact::setLayer ( const Layer* layer ) { _contact->setLayer(layer); } + inline void AutoContact::setWidth ( DbU::Unit w ) { _contact->setWidth(w); } + inline void AutoContact::setHeight ( DbU::Unit h ) { _contact->setHeight(h); } + inline void AutoContact::setSizes ( DbU::Unit w, DbU::Unit h ) { _contact->setSizes(w,h); } + inline void AutoContact::setX ( DbU::Unit x ) { _contact->setX(x); } + inline void AutoContact::setY ( DbU::Unit y ) { _contact->setY(y); } + inline void AutoContact::setPosition ( DbU::Unit x, DbU::Unit y ) { _contact->setPosition(x,y); } + inline void AutoContact::setPosition ( const Point& p ) { _contact->setPosition(p); } + inline void AutoContact::setDx ( DbU::Unit dx ) { _contact->setDx(dx); } + inline void AutoContact::setDy ( DbU::Unit dy ) { _contact->setDy(dy); } + inline void AutoContact::setOffset ( DbU::Unit dx, DbU::Unit dy ) { _contact->setOffset(dx,dy); } +// AutoContact Inline Functions. + inline bool AutoContact::isInCreationStage () const { return _flags&CntInCreationStage; } + inline bool AutoContact::isInvalidated () const { return _flags&CntInvalidated; } + inline bool AutoContact::isInvalidatedCache () const { return _flags&CntInvalidatedCache; } + inline bool AutoContact::isTurn () const { return _flags&CntTurn; } + inline bool AutoContact::isFixed () const { return _flags&CntFixed; } + inline bool AutoContact::isUserNativeConstraints () const { return _flags&CntUserNativeConstraints; } + inline bool AutoContact::isTerminal () const { return _flags&CntTerminal; } + inline bool AutoContact::isHTee () const { return _flags&CntHTee; } + inline bool AutoContact::isVTee () const { return _flags&CntVTee; } + inline bool AutoContact::hasBadTopology () const { return _flags&CntBadTopology; } + inline size_t AutoContact::getId () const { return _id; } + inline Contact* AutoContact::base () const { return _contact; } + inline GCell* AutoContact::getGCell () const { return _gcell; } + inline Box AutoContact::getConstraintBox () const { return Box(getCBXMin(),getCBYMin(),getCBXMax(),getCBYMax()); } + inline void AutoContact::setCBXMin ( DbU::Unit xMin ) { _dxMin = _getDeltaMin(xMin,_gcell->getXMin()); } + inline void AutoContact::setCBXMax ( DbU::Unit xMax ) { _dxMax = _getDeltaMax(xMax,_gcell->getXMin(),_gcell->getXMax()); } + inline void AutoContact::setCBYMin ( DbU::Unit yMin ) { _dyMin = _getDeltaMin(yMin,_gcell->getYMin()); } + inline void AutoContact::setCBYMax ( DbU::Unit yMax ) { _dyMax = _getDeltaMax(yMax,_gcell->getYMin(),_gcell->getYMax()); } + inline void AutoContact::setFlags ( unsigned int flags ) { _flags|= flags; } + inline void AutoContact::unsetFlags ( unsigned int flags ) { _flags&=~flags; } + inline int AutoContact::_getDeltaMin ( DbU::Unit x, DbU::Unit xMin ) { if (xxMax) x=xMax; return (int)DbU::toLambda(x-xMin); } + + inline DbU::Unit AutoContact::getCBXMin () const + { return isFixed() ? _contact->getX() : DbU::fromLambda(_dxMin) + _gcell->getXMin(); } + + inline DbU::Unit AutoContact::getCBXMax () const + { return isFixed() ? _contact->getX() : DbU::fromLambda(_dxMax) + _gcell->getXMin(); } + + inline DbU::Unit AutoContact::getCBYMin () const + { return isFixed() ? _contact->getY() : DbU::fromLambda(_dyMin) + _gcell->getYMin(); } + + inline DbU::Unit AutoContact::getCBYMax () const + { return isFixed() ? _contact->getY() : DbU::fromLambda(_dyMax) + _gcell->getYMin(); } + +// ------------------------------------------------------------------- +// Class : "Anabatic::LocatorHelper". + + class LocatorHelper { + public: + inline LocatorHelper ( AutoContact*, unsigned int flags=0 ); + inline bool isValid () const; + inline AutoSegment* getSegment () const; + inline void progress (); + private: + inline unsigned int _min () const; + inline unsigned int _max () const; + private: + unsigned int _flags; + unsigned int _index; + AutoContact* _contact; + }; + + + inline LocatorHelper::LocatorHelper ( AutoContact* contact, unsigned int flags ) + : _flags(flags), _index(_min()), _contact(contact) + { + cdebug_tabw(145,1); + cdebug_log(145,0) << "CTOR LocatorHelper " << contact->_getString() << endl; + cdebug_log(145,0) << "+ _min():" << _min() << endl; + cdebug_log(145,0) << "+ _max():" << _max() << endl; + cdebug_log(145,0) << "+ getSegment(_min()):" << _contact->getSegment(_min()) << endl; + if (not _contact->getSegment(_index)) progress(); + cdebug_tabw(145,-1); + } + + inline bool LocatorHelper::isValid () const + { return _index < _max(); } + + inline unsigned int LocatorHelper::_min () const + { return (_flags & (Flags::Horizontal|Flags::WithPerpands)) ? 0 : 2; } + + inline unsigned int LocatorHelper::_max () const + { return ((_flags & Flags::Horizontal) and not (_flags & Flags::WithPerpands)) ? 2 : 4; } + + inline AutoSegment* LocatorHelper::getSegment () const + { + cdebug_log(145,0) << "LocatorHelper::getSegment(" << _index << ") - " << _contact->getSegment(_index) << endl; + return (_index < _max()) ? _contact->getSegment(_index) : NULL; + } + + inline void LocatorHelper::progress () + { + cdebug_tabw(145,1); + ++_index; + cdebug_log(145,0) << "LocatorHelper::progress() [" << _index << "] " << _contact->getSegment(_index) << endl; + while ((_index < _max()) and (_contact->getSegment(_index) == NULL)) { + ++_index; + cdebug_log(145,0) << "LocatorHelper::progress() [" << _index << "] " << _contact->getSegment(_index) << endl; + } + cdebug_tabw(145,-1); + } + + +// ------------------------------------------------------------------- +// Helper Functions. + + + templateinline void order ( Type& a, Type& b ) { if (a>b) std::swap(a,b); } + + inline DbU::Unit setInBound ( DbU::Unit lower, DbU::Unit upper, DbU::Unit& value ) + { + if ( lower > value ) value = lower; + if ( upper < value ) value = upper; + + return value; + } + + inline size_t abssub ( size_t a, size_t b ) { return (a>b) ? a-b : b-a; } + + +} // Anabatic namespace. + + +INSPECTOR_P_SUPPORT(Anabatic::AutoContact); + + +#endif // ANABATIC_AUTOCONTACT_H diff --git a/anabatic/src/anabatic/AutoContactHTee.h b/anabatic/src/anabatic/AutoContactHTee.h new file mode 100644 index 00000000..2181f38c --- /dev/null +++ b/anabatic/src/anabatic/AutoContactHTee.h @@ -0,0 +1,76 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2012-2016, 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++ Header : "./anabatic/AutoContactHTee.h" | +// +-----------------------------------------------------------------+ + + +#ifndef ANABATIC_AUTOCONTACT_HTEE_H +#define ANABATIC_AUTOCONTACT_HTEE_H + +#include "anabatic/AutoContact.h" + + +namespace Anabatic { + + class AutoHorizontal; + class AutoVertical; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoContactHTee". + + + class AutoContactHTee : public AutoContact { + friend class AutoContact; + public: + static AutoContactHTee* create ( GCell*, Net*, const Layer* ); + protected: + // Constructors & Destructors. + AutoContactHTee ( GCell*, Contact* ); + virtual ~AutoContactHTee (); + virtual void _invalidate ( unsigned int flags ); + public: + inline AutoHorizontal* getHorizontal1 () const; + inline AutoHorizontal* getHorizontal2 () const; + inline AutoVertical* getVertical1 () const; + virtual AutoSegment* getOpposite ( const AutoSegment* ) const; + virtual AutoSegment* getPerpandicular ( const AutoSegment* ) const; + virtual AutoSegment* getSegment ( unsigned int ) const; + virtual void updateGeometry (); + virtual void updateTopology (); + virtual void cacheDetach ( AutoSegment* ); + virtual void cacheAttach ( AutoSegment* ); + virtual void updateCache (); + virtual string _getTypeName () const; + private: + AutoContactHTee ( const AutoContactHTee& ); + AutoContactHTee& operator= ( const AutoContactHTee& ); + private: + AutoHorizontal* _horizontal1; + AutoHorizontal* _horizontal2; + AutoVertical* _vertical1; + }; + + + inline AutoHorizontal* AutoContactHTee::getHorizontal1 () const { return _horizontal1; }; + inline AutoHorizontal* AutoContactHTee::getHorizontal2 () const { return _horizontal2; }; + inline AutoVertical* AutoContactHTee::getVertical1 () const { return _vertical1; }; + + +} // Anabatic namespace. + + +INSPECTOR_P_SUPPORT(Anabatic::AutoContactHTee); + + +#endif // ANABATIC_AUTOCONTACT_HTEE_H diff --git a/anabatic/src/anabatic/AutoContactTerminal.h b/anabatic/src/anabatic/AutoContactTerminal.h new file mode 100644 index 00000000..6da7dde2 --- /dev/null +++ b/anabatic/src/anabatic/AutoContactTerminal.h @@ -0,0 +1,82 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC/LIP6 2012-2016, 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++ Header : "./anabatic/AutoContactTerminal.h" | +// +-----------------------------------------------------------------+ + + +#ifndef ANABATIC_AUTOCONTACT_TERMINAL_H +#define ANABATIC_AUTOCONTACT_TERMINAL_H + +#include "anabatic/AutoContact.h" + + +namespace Anabatic { + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoContactTerminal". + + + class AutoContactTerminal : public AutoContact { + friend class AutoContact; + public: + static AutoContactTerminal* create ( GCell* gcell + , Component* anchor + , const Layer* layer + , Point point + , DbU::Unit width + , DbU::Unit height + ); + static AutoContactTerminal* create ( GCell* gcell + , Component* anchor + , const Layer* layer + , const DbU::Unit dx + , const DbU::Unit dy + , const DbU::Unit width + , const DbU::Unit height + ); + protected: + // Constructors & Destructors. + AutoContactTerminal ( GCell*, Contact* ); + virtual ~AutoContactTerminal (); + virtual void _invalidate ( unsigned int flags ); + public: + virtual Box getNativeConstraintBox () const; + inline AutoSegment* getSegment () const; + virtual AutoSegment* getSegment ( unsigned int ) const; + virtual AutoSegment* getOpposite ( const AutoSegment* ) const; + virtual AutoSegment* getPerpandicular ( const AutoSegment* ) const; + virtual void updateGeometry (); + virtual void updateTopology (); + virtual void cacheDetach ( AutoSegment* ); + virtual void cacheAttach ( AutoSegment* ); + virtual void updateCache (); + virtual string _getTypeName () const; + private: + AutoContactTerminal ( const AutoContactTerminal& ); + AutoContactTerminal& operator= ( const AutoContactTerminal& ); + protected: + AutoSegment* _segment; + }; + + + inline AutoSegment* AutoContactTerminal::getSegment () const { return _segment; } + + +} // Anabatic namespace. + + +INSPECTOR_P_SUPPORT(Anabatic::AutoContactTerminal); + + +#endif // ANABATIC_AUTOCONTACT_TERMINAL_H diff --git a/anabatic/src/anabatic/AutoContactTurn.h b/anabatic/src/anabatic/AutoContactTurn.h new file mode 100644 index 00000000..3c3f87df --- /dev/null +++ b/anabatic/src/anabatic/AutoContactTurn.h @@ -0,0 +1,74 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2012-2016, 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++ Header : "./anabatic/AutoContactTurn.h" | +// +-----------------------------------------------------------------+ + + +#ifndef ANABATIC_AUTOCONTACT_TURN_H +#define ANABATIC_AUTOCONTACT_TURN_H + +#include "anabatic/AutoContact.h" + + +namespace Anabatic { + + class AutoContactTerminal; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoContactTurn". + + + class AutoContactTurn : public AutoContact { + friend class AutoContact; + public: + static AutoContactTurn* create ( GCell*, Net*, const Layer* ); + static void insert ( AutoContactTerminal* ); + protected: + // Constructors & Destructors. + AutoContactTurn ( GCell*, Contact* ); + virtual ~AutoContactTurn (); + virtual void _invalidate ( unsigned int flags ); + public: + inline AutoHorizontal* getHorizontal1 () const; + inline AutoVertical* getVertical1 () const; + virtual AutoSegment* getOpposite ( const AutoSegment* ) const; + virtual AutoSegment* getPerpandicular ( const AutoSegment* ) const; + virtual AutoSegment* getSegment ( unsigned int ) const; + virtual void updateGeometry (); + virtual void updateTopology (); + virtual void cacheDetach ( AutoSegment* ); + virtual void cacheAttach ( AutoSegment* ); + virtual void updateCache (); + virtual string _getTypeName () const; + private: + AutoContactTurn ( const AutoContactTurn& ); + AutoContactTurn& operator= ( const AutoContactTurn& ); + private: + AutoHorizontal* _horizontal1; + AutoVertical* _vertical1; + }; + + + inline AutoHorizontal* AutoContactTurn::getHorizontal1 () const { return _horizontal1; }; + inline AutoVertical* AutoContactTurn::getVertical1 () const { return _vertical1; }; + + + +} // Anabatic namespace. + + +INSPECTOR_P_SUPPORT(Anabatic::AutoContactTurn); + + +#endif // ANABATIC_AUTOCONTACT_TURN_H diff --git a/anabatic/src/anabatic/AutoContactVTee.h b/anabatic/src/anabatic/AutoContactVTee.h new file mode 100644 index 00000000..e682fbe9 --- /dev/null +++ b/anabatic/src/anabatic/AutoContactVTee.h @@ -0,0 +1,73 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2012-2016, 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++ Header : "./anabatic/AutoContactVTee.h" | +// +-----------------------------------------------------------------+ + + +#ifndef ANABATIC_AUTOCONTACT_VTEE_H +#define ANABATIC_AUTOCONTACT_VTEE_H + +#include "anabatic/AutoContact.h" + + +namespace Anabatic { + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoContactVTee". + + + class AutoContactVTee : public AutoContact { + friend class AutoContact; + public: + static AutoContactVTee* create ( GCell*, Net*, const Layer* ); + protected: + // Constructors & Destructors. + AutoContactVTee ( GCell*, Contact* ); + virtual ~AutoContactVTee (); + virtual void _invalidate ( unsigned int flags ); + public: + inline AutoHorizontal* getHorizontal1 () const; + inline AutoVertical* getVertical1 () const; + inline AutoVertical* getVertical2 () const; + virtual AutoSegment* getOpposite ( const AutoSegment* ) const; + virtual AutoSegment* getPerpandicular ( const AutoSegment* ) const; + virtual AutoSegment* getSegment ( unsigned int ) const; + virtual void updateGeometry (); + virtual void updateTopology (); + virtual void cacheDetach ( AutoSegment* ); + virtual void cacheAttach ( AutoSegment* ); + virtual void updateCache (); + virtual string _getTypeName () const; + private: + AutoContactVTee ( const AutoContactVTee& ); + AutoContactVTee& operator= ( const AutoContactVTee& ); + private: + AutoHorizontal* _horizontal1; + AutoVertical* _vertical1; + AutoVertical* _vertical2; + }; + + + inline AutoHorizontal* AutoContactVTee::getHorizontal1 () const { return _horizontal1; }; + inline AutoVertical* AutoContactVTee::getVertical1 () const { return _vertical1; }; + inline AutoVertical* AutoContactVTee::getVertical2 () const { return _vertical2; }; + + +} // Anabatic namespace. + + +INSPECTOR_P_SUPPORT(Anabatic::AutoContactVTee); + + +#endif // ANABATIC_AUTOCONTACT_VTEE_H diff --git a/anabatic/src/anabatic/AutoHorizontal.h b/anabatic/src/anabatic/AutoHorizontal.h new file mode 100644 index 00000000..762017a7 --- /dev/null +++ b/anabatic/src/anabatic/AutoHorizontal.h @@ -0,0 +1,96 @@ +// -*- 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 | +// | A n a b a t i c - Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./anabatic/AutoHorizontal.h" | +// +-----------------------------------------------------------------+ + + +#ifndef ANABATIC_AUTOHORIZONTAL_H +#define ANABATIC_AUTOHORIZONTAL_H + +#include "hurricane/Horizontal.h" +#include "anabatic/AutoSegment.h" + + +namespace Anabatic { + + +// ------------------------------------------------------------------- +// Class : "AutoHorizontal". + + + class AutoHorizontal : public AutoSegment { + friend class AutoSegment; + + public: + // Predicates. + virtual bool _canSlacken () const; + virtual bool canMoveULeft ( float reserve=0.0 ) const; + virtual bool canMoveURight ( float reserve=0.0 ) const; + // Accessors. + virtual Segment* base (); + virtual Segment* base () const; + virtual Horizontal* getHorizontal (); + virtual DbU::Unit getSourceU () const; + virtual DbU::Unit getTargetU () const; + virtual DbU::Unit getDuSource () const; + virtual DbU::Unit getDuTarget () const; + virtual Interval getSpanU () const; + virtual bool getConstraints ( DbU::Unit& min , DbU::Unit& max ) const; + virtual Interval getSourceConstraints ( unsigned int flags=0 ) const; + virtual Interval getTargetConstraints ( unsigned int flags=0 ) const; + virtual unsigned int getDirection () const; + virtual size_t getGCells ( vector& ) const; + // Modifiers. + virtual void setDuSource ( DbU::Unit ); + virtual void setDuTarget ( DbU::Unit ); + virtual void _setAxis ( DbU::Unit ); + virtual void updateOrient (); + virtual void updatePositions (); + virtual void updateNativeConstraints (); + virtual bool checkPositions () const; + virtual bool checkConstraints () const; + virtual unsigned int _makeDogleg ( GCell*, unsigned int flags ); + virtual bool moveULeft (); + virtual bool moveURight (); + virtual bool _slacken ( unsigned int flags ); +#if THIS_IS_DISABLED + virtual void desalignate ( AutoContact* ); +#endif + // Inspector Management. + virtual Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const; + + // Internal: Attributes. + protected: + Horizontal* _horizontal; + + // Internal: Constructors. + protected: + AutoHorizontal ( Horizontal* ); + virtual ~AutoHorizontal (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + AutoHorizontal ( const AutoHorizontal& ); + AutoHorizontal& operator= ( const AutoHorizontal& ); + }; + + +} // End of Anabatic namespace. + + +INSPECTOR_P_SUPPORT(Anabatic::AutoHorizontal); + + +#endif // ANABATIC_AUTOHORIZONTAL_H diff --git a/anabatic/src/anabatic/AutoSegment.h b/anabatic/src/anabatic/AutoSegment.h new file mode 100644 index 00000000..8e93ecdc --- /dev/null +++ b/anabatic/src/anabatic/AutoSegment.h @@ -0,0 +1,586 @@ +// -*- 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 | +// | A n a b a t i c - Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./anabatic/AutoSegment.h" | +// +-----------------------------------------------------------------+ + + +#ifndef ANABATIC_AUTOSEGMENT_H +#define ANABATIC_AUTOSEGMENT_H + +#include +#include +#include +#include "hurricane/Interval.h" +#include "hurricane/Segment.h" +#include "hurricane/Components.h" +#include "hurricane/Contact.h" +namespace Hurricane { + class Layer; + class Horizontal; + class Vertical; + class Cell; +} +#include "crlcore/RoutingGauge.h" +#include "anabatic/Constants.h" +#include "anabatic/GCell.h" +#include "anabatic/AutoSegments.h" +#include "anabatic/Session.h" + + +namespace Anabatic { + + using std::set; + using std::cerr; + using std::endl; + using std::binary_function; + using Hurricane::StaticObservable; + using Hurricane::BaseObserver; + using Hurricane::tab; + using Hurricane::Interval; + using Hurricane::Layer; + using Hurricane::Components; + using Hurricane::Horizontal; + using Hurricane::Vertical; + using Hurricane::Cell; + using CRL::RoutingGauge; + + class AutoHorizontal; + class AutoVertical; + +// ------------------------------------------------------------------- +// Class : "AutoSegment". + + enum AutoSegmentFlag { SegNoFlags = 0x0 + , SegHorizontal = (1<< 0) + , SegFixed = (1<< 1) + , SegGlobal = (1<< 2) + , SegWeakGlobal = (1<< 3) + , SegCanonical = (1<< 4) + , SegBipoint = (1<< 5) + , SegDogleg = (1<< 6) + , SegStrap = (1<< 7) + , SegSourceTop = (1<< 8) + , SegSourceBottom = (1<< 9) + , SegTargetTop = (1<<10) + , SegTargetBottom = (1<<11) + , SegIsReduced = (1<<12) + , SegLayerChange = (1<<13) + , SegSourceTerminal = (1<<14) // Replace Terminal. + , SegTargetTerminal = (1<<15) // Replace Terminal. + , SegStrongTerminal = SegSourceTerminal|SegTargetTerminal + , SegWeakTerminal1 = (1<<16) // Replace TopologicalEnd. + , SegWeakTerminal2 = (1<<17) // Replace TopologicalEnd. + , SegNotSourceAligned = (1<<18) + , SegNotTargetAligned = (1<<19) + , SegUnbound = (1<<20) + , SegHalfSlackened = (1<<21) + , SegSlackened = (1<<22) + , SegAxisSet = (1<<23) + , SegInvalidated = (1<<24) + , SegInvalidatedSource = (1<<25) + , SegInvalidatedTarget = (1<<26) + , SegInvalidatedLayer = (1<<27) + , SegCreated = (1<<28) + , SegUserDefined = (1<<29) + // Masks. + , SegWeakTerminal = SegStrongTerminal|SegWeakTerminal1|SegWeakTerminal2 + , SegNotAligned = SegNotSourceAligned|SegNotTargetAligned + , SegSpinTop = SegSourceTop |SegTargetTop + , SegSpinBottom = SegSourceBottom |SegTargetBottom + , SegDepthSpin = SegSpinTop |SegSpinBottom + }; + + + class AutoSegment { + friend class AutoHorizontal; + friend class AutoVertical; + + public: + class Observable : public StaticObservable<1> { + public: + enum Indexes { TrackSegment = 0 + }; + public: + inline Observable (); + private: + Observable ( const StaticObservable& ); + Observable& operator= ( const StaticObservable& ); + }; + public: + enum ObserverFlag { Create = 0x000000001 + , Destroy = 0x000000002 + , Invalidate = 0x000000004 + , Revalidate = 0x000000008 + , RevalidatePPitch = 0x000000010 + }; + public: + typedef std::function< void(AutoSegment*) > RevalidateCb_t; + public: + static void setDestroyMode ( bool ); + static AutoSegment* create ( AutoContact* source + , AutoContact* target + , Segment* hurricaneSegment + ); + static AutoSegment* create ( AutoContact* source + , AutoContact* target + , unsigned int dir + , size_t depth=RoutingGauge::nlayerdepth + ); + void destroy (); + // Wrapped Segment Functions. + virtual Segment* base () const = 0; + virtual Segment* base () = 0; + virtual Horizontal* getHorizontal () { return NULL; }; + virtual Vertical* getVertical () { return NULL; }; + inline Cell* getCell () const; + inline Net* getNet () const; + inline const Layer* getLayer () const; + inline Box getBoundingBox () const; + inline Hook* getSourceHook (); + inline Hook* getTargetHook (); + inline Contact* getSource () const; + inline Contact* getTarget () const; + inline Component* getOppositeAnchor ( Component* ) const; + inline Components getAnchors () const; + virtual DbU::Unit getX () const; + virtual DbU::Unit getY () const; + inline DbU::Unit getWidth () const; + inline DbU::Unit getLength () const; + inline DbU::Unit getSourcePosition () const; + inline DbU::Unit getTargetPosition () const; + inline DbU::Unit getSourceX () const; + inline DbU::Unit getSourceY () const; + inline DbU::Unit getTargetX () const; + inline DbU::Unit getTargetY () const; + inline void invert (); + inline void setLayer ( const Layer* ); + // Predicates. + inline bool isHorizontal () const; + inline bool isVertical () const; + inline bool isGlobal () const; + inline bool isWeakGlobal () const; + inline bool isLocal () const; + inline bool isFixed () const; + inline bool isBipoint () const; + inline bool isWeakTerminal () const; + inline bool isWeakTerminal1 () const; + inline bool isWeakTerminal2 () const; + inline bool isTerminal () const; + inline bool isNotSourceAligned () const; + inline bool isNotTargetAligned () const; + inline bool isNotAligned () const; + bool isStrongTerminal ( unsigned int flags=0 ) const; + inline bool isSourceTerminal () const; + inline bool isTargetTerminal () const; + inline bool isLayerChange () const; + inline bool isSpinTop () const; + inline bool isSpinBottom () const; + inline bool isSpinTopOrBottom () const; + inline bool isReduced () const; + inline bool isStrap () const; + inline bool isDogleg () const; + inline bool isUnbound () const; + inline bool isInvalidated () const; + inline bool isInvalidatedLayer () const; + inline bool isCreated () const; + inline bool isCanonical () const; + inline bool isUnsetAxis () const; + inline bool isSlackened () const; + inline bool isUserDefined () const; + bool isReduceCandidate () const; + bool isUTurn () const; + virtual bool _canSlacken () const = 0; + bool canReduce () const; + bool mustRaise () const; + unsigned int canDogleg ( Interval ); + virtual bool canMoveULeft ( float reserve=0.0 ) const = 0; + virtual bool canMoveURight ( float reserve=0.0 ) const = 0; + bool canMoveUp ( float reserve=0.0, unsigned int flags=0 ) const; + bool canPivotUp ( float reserve=0.0, unsigned int flags=0 ) const; + bool canPivotDown ( float reserve=0.0, unsigned int flags=0 ) const; + bool canSlacken ( unsigned int flags=0 ) const; + virtual bool checkPositions () const = 0; + virtual bool checkConstraints () const = 0; + bool checkDepthSpin () const; + // Accessors. + inline unsigned long getId () const; + inline unsigned int getFlags () const; + virtual unsigned int getDirection () const = 0; + inline GCell* getGCell () const; + virtual size_t getGCells ( vector& ) const = 0; + inline AutoContact* getAutoSource () const; + inline AutoContact* getAutoTarget () const; + AutoContact* getOppositeAnchor ( AutoContact* ) const; + size_t getPerpandicularsBound ( set& ); + inline AutoSegment* getParent () const; + inline unsigned int getDepth () const; + inline DbU::Unit getPitch () const; + DbU::Unit getPPitch () const; + inline DbU::Unit getAxis () const; + virtual DbU::Unit getSourceU () const = 0; + virtual DbU::Unit getTargetU () const = 0; + virtual DbU::Unit getDuSource () const = 0; + virtual DbU::Unit getDuTarget () const = 0; + inline DbU::Unit getOrigin () const; + inline DbU::Unit getExtremity () const; + virtual Interval getSpanU () const = 0; + Interval getMinSpanU () const; + virtual Interval getSourceConstraints ( unsigned int flags=0 ) const = 0; + virtual Interval getTargetConstraints ( unsigned int flags=0 ) const = 0; + virtual bool getConstraints ( DbU::Unit& min, DbU::Unit& max ) const = 0; + inline bool getConstraints ( Interval& i ) const; + inline const Interval& getUserConstraints () const; + inline const Interval& getNativeConstraints () const; + virtual DbU::Unit getSlack () const; + inline DbU::Unit getOptimalMin () const; + inline DbU::Unit getOptimalMax () const; + inline DbU::Unit getNativeMin () const; + inline DbU::Unit getNativeMax () const; + Interval& getOptimal ( Interval& i ) const; + virtual DbU::Unit getCost ( DbU::Unit axis ) const; + virtual AutoSegment* getCanonical ( DbU::Unit& min , DbU::Unit& max ); + inline AutoSegment* getCanonical ( Interval& i ); + float getMaxUnderDensity ( unsigned int flags ); + // Modifiers. + inline void unsetFlags ( unsigned int ); + inline void setFlags ( unsigned int ); + void setFlagsOnAligneds ( unsigned int ); + inline void incReduceds (); + inline void decReduceds (); + virtual void setDuSource ( DbU::Unit du ) = 0; + virtual void setDuTarget ( DbU::Unit du ) = 0; + void computeTerminal (); + virtual void updateOrient () = 0; + virtual void updatePositions () = 0; + virtual void updateNativeConstraints () = 0; + void updateSourceSpin (); + void updateTargetSpin (); + void sourceDetach (); + void targetDetach (); + void sourceAttach ( AutoContact* ); + void targetAttach ( AutoContact* ); + //inline void mergeUserConstraints ( const Interval& ); + void mergeUserConstraints ( const Interval& ); + inline void resetUserConstraints (); + inline void setOptimalMin ( DbU::Unit min ); + inline void setOptimalMax ( DbU::Unit max ); + inline void mergeNativeMin ( DbU::Unit min ); + inline void mergeNativeMax ( DbU::Unit max ); + inline void resetNativeConstraints ( DbU::Unit min, DbU::Unit max ); + bool checkNotInvalidated () const; + inline void setParent ( AutoSegment* ); + void revalidate (); + AutoSegment* makeDogleg ( AutoContact* ); + unsigned int makeDogleg ( Interval, unsigned int flags=Flags::NoFlags ); + unsigned int makeDogleg ( GCell*, unsigned int flags=Flags::NoFlags ); + virtual unsigned int _makeDogleg ( GCell*, unsigned int flags ) = 0; + virtual bool moveULeft () = 0; + virtual bool moveURight () = 0; + bool slacken ( unsigned int flags ); + virtual bool _slacken ( unsigned int flags ) = 0; + void _changeDepth ( unsigned int depth, unsigned int flags ); + void changeDepth ( unsigned int depth, unsigned int flags ); + bool moveUp ( unsigned int flags=Flags::NoFlags ); + bool moveDown ( unsigned int flags=Flags::NoFlags ); + bool reduceDoglegLayer (); + bool reduce (); + bool raise (); + // Canonical Modifiers. + AutoSegment* canonize ( unsigned int flags=Flags::NoFlags ); + virtual void invalidate ( unsigned int flags=Flags::Propagate ); + void invalidate ( AutoContact* ); + void computeOptimal ( set& processeds ); + void setAxis ( DbU::Unit, unsigned int flags=Flags::NoFlags ); + bool toConstraintAxis ( unsigned int flags=Flags::Realignate ); + bool toOptimalAxis ( unsigned int flags=Flags::Realignate ); + // Collections & Filters. + AutoSegments getOnSourceContact ( unsigned int direction ); + AutoSegments getOnTargetContact ( unsigned int direction ); + AutoSegments getCachedOnSourceContact ( unsigned int direction ); + AutoSegments getCachedOnTargetContact ( unsigned int direction ); + AutoSegments getAligneds ( unsigned int flags=Flags::NoFlags ); + AutoSegments getPerpandiculars (); + size_t getAlignedContacts ( map& ) const ; + // Observers. + template< typename OwnerT > + inline OwnerT* getObserver ( size_t slot ); + inline void setObserver ( size_t slot, BaseObserver* ); + inline void notify ( unsigned int flags ); + // Inspector Management. + virtual Record* _getRecord () const = 0; + virtual string _getString () const = 0; + virtual string _getTypeName () const = 0; + // Non-reviewed atomic modifiers. + bool _check () const; +#if THIS_IS_DISABLED + virtual void desalignate ( AutoContact* ) = 0; + bool shearUp ( GCell* + , AutoSegment*& movedUp + , float reserve + , unsigned int flags ); +#endif + + protected: + // Internal: Static Attributes. + static size_t _allocateds; + static size_t _globalsCount; + static bool _destroyBase; + static bool _destroyTool; + static unsigned long _maxId; + // Internal: Attributes. + const unsigned long _id; + GCell* _gcell; + unsigned int _flags; + unsigned int _depth : 8; + unsigned int _optimalMin : 8; + unsigned int _optimalMax : 8; + unsigned int _reduceds : 2; + DbU::Unit _sourcePosition; + DbU::Unit _targetPosition; + Interval _userConstraints; + Interval _nativeConstraints; + AutoSegment* _parent; + Observable _observers; + + // Internal: Constructors & Destructors. + protected: + AutoSegment ( Segment* segment ); + virtual ~AutoSegment (); + static void _preCreate ( AutoContact* source, AutoContact* target ); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + AutoSegment ( const AutoSegment& ); + AutoSegment& operator= ( const AutoSegment& ); + protected: + void _invalidate (); + inline unsigned int _getFlags () const; + std::string _getStringFlags () const; + virtual void _setAxis ( DbU::Unit ) = 0; + + public: + struct CompareId : public binary_function { + inline bool operator() ( const AutoSegment* lhs, const AutoSegment* rhs ) const; + }; + public: + struct CompareByDepthLength : public binary_function { + bool operator() ( AutoSegment* lhs, AutoSegment* rhs ) const; + }; + public: + struct CompareByDepthAxis : public binary_function { + bool operator() ( AutoSegment* lhs, AutoSegment* rhs ) const; + }; + public: + typedef std::set DepthLengthSet; + + // Static Utilities. + public: + static inline bool areAlignedsAndDiffLayer ( AutoSegment*, AutoSegment* ); + static bool isTopologicalBound ( AutoSegment* seed, unsigned int flags ); + static inline bool arePerpandiculars ( AutoSegment* a, AutoSegment* b ); + static inline bool arePerpandiculars ( bool isHorizontalA, AutoSegment* b ); + static inline bool areAligneds ( AutoSegment* a, AutoSegment* b ); + static unsigned int getPerpandicularState ( AutoContact* contact + , AutoSegment* source + , AutoSegment* current + , bool isHorizontalMaster + , const Layer* masterLayer=NULL + ); + static inline unsigned int getPerpandicularState ( AutoContact* contact + , AutoSegment* source + , AutoSegment* current + , AutoSegment* master + ); + static void getTopologicalInfos ( AutoSegment* seed + , vector& collapseds + , vector& perpandiculars + , DbU::Unit& leftBound + , DbU::Unit& rightBound + ); + static int getTerminalCount ( AutoSegment* seed + , vector& collapseds + ); + static inline int getTerminalCount ( AutoSegment* seed ); + static inline size_t getGlobalsCount (); + static inline size_t getAllocateds (); + static inline unsigned long getMaxId (); + }; + + +// Inline Functions. + inline unsigned long AutoSegment::getId () const { return _id; } + inline Cell* AutoSegment::getCell () const { return base()->getCell(); } + inline Net* AutoSegment::getNet () const { return base()->getNet(); } + inline const Layer* AutoSegment::getLayer () const { return base()->getLayer(); } + inline Box AutoSegment::getBoundingBox () const { return base()->getBoundingBox(); } + inline Hook* AutoSegment::getSourceHook () { return base()->getSourceHook(); } + inline Hook* AutoSegment::getTargetHook () { return base()->getTargetHook(); } + inline Contact* AutoSegment::getSource () const { return static_cast(base()->getSource()); } + inline Contact* AutoSegment::getTarget () const { return static_cast(base()->getTarget()); } + inline Component* AutoSegment::getOppositeAnchor ( Component* anchor ) const { return base()->getOppositeAnchor(anchor); }; + inline AutoSegment* AutoSegment::getParent () const { return _parent; } + inline DbU::Unit AutoSegment::getSourcePosition () const { return _sourcePosition; } + inline DbU::Unit AutoSegment::getTargetPosition () const { return _targetPosition; } + inline DbU::Unit AutoSegment::getSourceX () const { return base()->getSourceX(); } + inline DbU::Unit AutoSegment::getSourceY () const { return base()->getSourceY(); } + inline DbU::Unit AutoSegment::getTargetX () const { return base()->getTargetX(); } + inline DbU::Unit AutoSegment::getTargetY () const { return base()->getTargetY(); } + inline DbU::Unit AutoSegment::getWidth () const { return base()->getWidth(); } + inline DbU::Unit AutoSegment::getLength () const { return base()->getLength(); } + inline void AutoSegment::invert () { base()->invert(); } + inline GCell* AutoSegment::getGCell () const { return _gcell; } + inline AutoContact* AutoSegment::getAutoSource () const { return Session::lookup(getSource()); } + inline AutoContact* AutoSegment::getAutoTarget () const { return Session::lookup(getTarget()); } + inline bool AutoSegment::getConstraints ( Interval& i ) const { return getConstraints(i.getVMin(),i.getVMax()); } + inline AutoSegment* AutoSegment::getCanonical ( Interval& i ) { return getCanonical(i.getVMin(),i.getVMax()); } + inline unsigned int AutoSegment::getDepth () const { return _depth; } + inline DbU::Unit AutoSegment::getPitch () const { return Session::getPitch(getDepth(),Flags::NoFlags); } + inline DbU::Unit AutoSegment::getAxis () const { return isHorizontal()?base()->getY():base()->getX(); } + inline DbU::Unit AutoSegment::getOrigin () const { return isHorizontal()?_gcell->getYMin():_gcell->getXMin(); } + inline DbU::Unit AutoSegment::getExtremity () const { return isHorizontal()?_gcell->getYMax():_gcell->getXMax(); } + inline DbU::Unit AutoSegment::getOptimalMin () const { return DbU::lambda(_optimalMin) + getOrigin(); } + inline DbU::Unit AutoSegment::getOptimalMax () const { return DbU::lambda(_optimalMax) + getOrigin(); } + inline DbU::Unit AutoSegment::getNativeMin () const { return _nativeConstraints.getVMin(); } + inline DbU::Unit AutoSegment::getNativeMax () const { return _nativeConstraints.getVMax(); } + inline const Interval& AutoSegment::getUserConstraints () const { return _userConstraints; } + inline const Interval& AutoSegment::getNativeConstraints () const { return _nativeConstraints; } + + inline bool AutoSegment::isHorizontal () const { return _flags & SegHorizontal; } + inline bool AutoSegment::isVertical () const { return not (_flags & SegHorizontal); } + inline bool AutoSegment::isFixed () const { return _flags & SegFixed; } + inline bool AutoSegment::isGlobal () const { return _flags & SegGlobal; } + inline bool AutoSegment::isWeakGlobal () const { return _flags & SegWeakGlobal; } + inline bool AutoSegment::isLocal () const { return not (_flags & SegGlobal); } + inline bool AutoSegment::isBipoint () const { return _flags & SegBipoint; } + inline bool AutoSegment::isWeakTerminal () const { return _flags & SegWeakTerminal; } + inline bool AutoSegment::isWeakTerminal1 () const { return _flags & SegWeakTerminal1; } + inline bool AutoSegment::isWeakTerminal2 () const { return _flags & SegWeakTerminal2; } + inline bool AutoSegment::isSourceTerminal () const { return _flags & SegSourceTerminal; } + inline bool AutoSegment::isTargetTerminal () const { return _flags & SegTargetTerminal; } + inline bool AutoSegment::isTerminal () const { return _flags & SegStrongTerminal; } + 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; } + inline bool AutoSegment::isDogleg () const { return _flags & SegDogleg ; } + inline bool AutoSegment::isUnbound () const { return _flags & SegUnbound ; } + inline bool AutoSegment::isStrap () const { return _flags & SegStrap; } + inline bool AutoSegment::isLayerChange () const { return _flags & SegLayerChange; } + inline bool AutoSegment::isSpinTop () const { return ((_flags & SegSpinTop ) == SegSpinTop); } + inline bool AutoSegment::isSpinBottom () const { return ((_flags & SegSpinBottom) == SegSpinBottom); } + inline bool AutoSegment::isSpinTopOrBottom () const { return isSpinTop() or isSpinBottom(); } + inline bool AutoSegment::isReduced () const { return _flags & SegIsReduced; } + inline bool AutoSegment::isSlackened () const { return _flags & SegSlackened; } + inline bool AutoSegment::isCanonical () const { return _flags & SegCanonical; } + inline bool AutoSegment::isUnsetAxis () const { return not (_flags & SegAxisSet); } + inline bool AutoSegment::isInvalidated () const { return _flags & SegInvalidated; } + inline bool AutoSegment::isInvalidatedLayer () const { return _flags & SegInvalidatedLayer; } + inline bool AutoSegment::isCreated () const { return _flags & SegCreated; } + inline bool AutoSegment::isUserDefined () const { return _flags & SegUserDefined; } + inline void AutoSegment::setFlags ( unsigned int flags ) { _flags |= flags; } + inline void AutoSegment::unsetFlags ( unsigned int flags ) { _flags &= ~flags; } + + inline unsigned int AutoSegment::getFlags () const { return _flags; } + inline unsigned int AutoSegment::_getFlags () const { return _flags; } + inline void AutoSegment::incReduceds () { if (_reduceds<3) ++_reduceds; } + inline void AutoSegment::decReduceds () { if (_reduceds>0) --_reduceds; } + inline void AutoSegment::setLayer ( const Layer* layer ) { base()->setLayer(layer); _depth=Session::getLayerDepth(layer); } + inline void AutoSegment::setOptimalMin ( DbU::Unit min ) { _optimalMin = (unsigned int)DbU::getLambda(min-getOrigin()); } + inline void AutoSegment::setOptimalMax ( DbU::Unit max ) { _optimalMax = (unsigned int)DbU::getLambda(max-getOrigin()); } + inline void AutoSegment::mergeNativeMin ( DbU::Unit min ) { _nativeConstraints.getVMin() = std::max( min, _nativeConstraints.getVMin() ); } + inline void AutoSegment::mergeNativeMax ( DbU::Unit max ) { _nativeConstraints.getVMax() = std::min( max, _nativeConstraints.getVMax() ); } + 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 void AutoSegment::setParent ( AutoSegment* parent ) + { + if ( parent == this ) { + cerr << "Parentage Looping: " << parent->_getString() << endl; + } + _parent = parent; + } + + + inline bool AutoSegment::CompareId::operator() ( const AutoSegment* lhs, const AutoSegment* rhs ) const + { return lhs->getId() < rhs->getId(); } + + inline unsigned long AutoSegment::getMaxId () + { return _maxId; } + + inline bool AutoSegment::areAlignedsAndDiffLayer ( AutoSegment* s1, AutoSegment* s2 ) + { return s1 and s2 + and (s1->isHorizontal() == s2->isHorizontal()) + and (s1->getLayer() != s2->getLayer()); } + + inline bool AutoSegment::arePerpandiculars ( AutoSegment* a, AutoSegment* b ) + { return a and b and (a->isHorizontal() != b->isHorizontal()); } + + inline bool AutoSegment::arePerpandiculars ( bool isHorizontalA, AutoSegment* b ) + { return b and (isHorizontalA != b->isHorizontal()); } + + inline bool AutoSegment::areAligneds ( AutoSegment* a, AutoSegment* b ) + { return a and b and (a->isHorizontal() == b->isHorizontal()); } + + inline unsigned int AutoSegment::getPerpandicularState ( AutoContact* contact + , AutoSegment* source + , AutoSegment* current + , AutoSegment* master ) + { + return getPerpandicularState ( contact, source, current, master->isHorizontal(), master->getLayer() ); + } + + + inline int AutoSegment::getTerminalCount ( AutoSegment* seed ) + { + cdebug_log(145,0) << "getTerminalCount() - " << seed << endl; + + vector collapseds; + vector perpandiculars; + DbU::Unit leftBound; + DbU::Unit rightBound; + + getTopologicalInfos ( seed + , collapseds + , perpandiculars + , leftBound + , rightBound + ); + + return getTerminalCount ( seed, collapseds ); + } + + + inline size_t AutoSegment::getGlobalsCount () { return _globalsCount; } + inline size_t AutoSegment::getAllocateds () { return _allocateds; } + + + inline void AutoSegment::setObserver ( size_t slot, BaseObserver* observer ) + { _observers.setObserver( slot, observer ); } + + template + inline OwnerT* AutoSegment::getObserver ( size_t slot ) + { return _observers.getObserver(slot); } + + inline void AutoSegment::notify ( unsigned int flags ) + { _observers.notify( flags ); } + + inline AutoSegment::Observable::Observable () : StaticObservable<1>() { } + + +} // End of Anabatic namespace. + + +INSPECTOR_P_SUPPORT(Anabatic::AutoSegment); + + +# endif // ANABATIC_AUTOSEGMENT_H diff --git a/anabatic/src/anabatic/AutoSegments.h b/anabatic/src/anabatic/AutoSegments.h new file mode 100644 index 00000000..d8f135c4 --- /dev/null +++ b/anabatic/src/anabatic/AutoSegments.h @@ -0,0 +1,446 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC/LIP6 2008-2016, 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++ Header : "./anabatic/AutoSegments.h" | +// +-----------------------------------------------------------------+ + + +#ifndef ANABATIC_AUTOSEGMENTS_H +#define ANABATIC_AUTOSEGMENTS_H + +#include +#include +#include +#include +#include "hurricane/Collection.h" +#include "hurricane/DbU.h" +#include "hurricane/Box.h" + +namespace Hurricane { + class Hook; + class Component; + class Contact; + class Segment; + class Net; +} + + +namespace Anabatic { + + using std::string; + using std::pair; + using std::list; + using std::vector; + using std::map; + + using Hurricane::Record; + using Hurricane::DbU; + using Hurricane::Box; + using Hurricane::Hook; + using Hurricane::Component; + using Hurricane::Contact; + using Hurricane::Segment; + using Hurricane::Net; + using Hurricane::Filter; + using Hurricane::Locator; + using Hurricane::Collection; + using Hurricane::GenericFilter; + using Hurricane::GenericLocator; + using Hurricane::GenericCollection; + + class LocatorHelper; + class AutoContact; + class AutoSegment; + class GCell; + + +// ------------------------------------------------------------------- +// Collections. + + typedef Hurricane::Filter AutoSegmentHF; + typedef Hurricane::Locator AutoSegmentHL; + typedef Hurricane::Collection AutoSegmentHC; + typedef GenericCollection AutoSegments; + typedef GenericLocator AutoSegmentLocator; + typedef GenericFilter AutoSegmentFilter; + typedef map AutoSegmentLut; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoSegmentStack". + + class AutoSegmentStack : protected list > { + public: + inline bool isEmpty () const; + inline size_t getSize () const; + void push ( AutoContact*, AutoSegment* ); + inline void pop (); + inline AutoContact* getAutoContact () const; + inline AutoSegment* getAutoSegment () const; + }; + + + inline bool AutoSegmentStack::isEmpty () const { return empty(); }; + inline size_t AutoSegmentStack::getSize () const { return size(); }; + inline void AutoSegmentStack::pop () { if ( !empty() ) pop_back(); }; + inline AutoContact* AutoSegmentStack::getAutoContact () const { return empty() ? NULL : back().first; }; + inline AutoSegment* AutoSegmentStack::getAutoSegment () const { return empty() ? NULL : back().second; }; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::AutoSegments_OnContact". + + class AutoSegments_OnContact : public AutoSegmentHC { + + public: + // Sub-Class: Locator. + class Locator : public AutoSegmentHL { + public: + Locator ( AutoSegment* master, Contact* contact ); + inline Locator ( const Locator& ); + virtual AutoSegment* getElement () const; + virtual AutoSegmentHL* getClone () const; + virtual bool isValid () const; + virtual void progress (); + virtual string _getString () const; + protected: + AutoSegment* _master; + Hook* _hook; + AutoSegment* _element; + }; + + public: + // AutoSegments_OnContact Methods. + inline AutoSegments_OnContact ( AutoSegment* master, Contact* contact ); + inline AutoSegments_OnContact ( const AutoSegments_OnContact& ); + virtual AutoSegmentHC* getClone () const; + virtual AutoSegmentHL* getLocator () const; + virtual string _getString () const; + + protected: + // AutoSegments_OnContact Attributes. + AutoSegment* _master; + Contact* _contact; + }; + + + inline AutoSegments_OnContact::Locator::Locator ( const Locator &locator ) + : AutoSegmentHL() + , _master(locator._master) + , _hook(locator._hook) + , _element(locator._element) + { } + + + inline AutoSegments_OnContact::AutoSegments_OnContact ( AutoSegment* master, Contact* contact ) + : AutoSegmentHC() + , _master(master) + , _contact(contact) + { } + + + inline AutoSegments_OnContact::AutoSegments_OnContact ( const AutoSegments_OnContact& segments ) + : AutoSegmentHC() + , _master(segments._master) + , _contact(segments._contact) + { } + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_Aligneds". + + class AutoSegments_Aligneds : public AutoSegmentHC { + + public: + // Sub-Class: Locator. + class Locator : public AutoSegmentHL { + public: + inline Locator ( AutoSegment* segment , unsigned int flags ); + inline Locator ( const Locator &locator ); + virtual AutoSegment* getElement () const; + virtual AutoSegmentHL* getClone () const; + virtual bool isValid () const; + virtual void progress (); + virtual string _getString () const; + protected: + unsigned int _flags; + AutoSegment* _master; + AutoSegmentStack _stack; + }; + + public: + // AutoSegments_Aligneds Methods. + AutoSegments_Aligneds ( AutoSegment*, unsigned int flags=Flags::NoFlags ); + AutoSegments_Aligneds ( const AutoSegments_Aligneds& ); + virtual AutoSegmentHC* getClone () const; + virtual AutoSegmentHL* getLocator () const; + virtual string _getString () const; + + protected: + // AutoSegments_Aligneds Attributes. + unsigned int _flags; + AutoSegment* _segment; + }; + + + inline AutoSegments_Aligneds::Locator::Locator ( const Locator &locator ) + : AutoSegmentHL() + , _flags (locator._flags) + , _master(locator._master) + , _stack (locator._stack) + { } + + + inline AutoSegments_Aligneds::AutoSegments_Aligneds ( AutoSegment* segment, unsigned int flags ) + : AutoSegmentHC() + , _flags (flags) + , _segment(segment) + { } + + + inline AutoSegments_Aligneds::AutoSegments_Aligneds ( const AutoSegments_Aligneds& autosegments ) + : AutoSegmentHC() + , _flags (autosegments._flags) + , _segment(autosegments._segment) + { } + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_Perpandiculars". + + class AutoSegments_Perpandiculars : public AutoSegmentHC { + + public: + // Sub-Class: Locator. + class Locator : public AutoSegmentHL { + public: + Locator ( AutoSegment* master ); + inline Locator ( const Locator& ); + virtual AutoSegment* getElement () const; + virtual AutoSegmentHL* getClone () const; + virtual bool isValid () const; + virtual void progress (); + virtual string _getString () const; + protected: + unsigned int _flags; + AutoSegment* _master; + AutoSegmentStack _stack; + vector _perpandiculars; + }; + + public: + // AutoSegments_Perpandiculars Methods. + inline AutoSegments_Perpandiculars ( AutoSegment* master ); + inline AutoSegments_Perpandiculars ( const AutoSegments_Perpandiculars& ); + virtual AutoSegmentHC* getClone () const; + virtual AutoSegmentHL* getLocator () const; + virtual string _getString () const; + + protected: + // AutoSegments_Perpandiculars Attributes. + AutoSegment* _segment; + }; + + + inline AutoSegments_Perpandiculars::Locator::Locator ( const Locator& locator ) + : AutoSegmentHL() + , _flags (locator._flags) + , _master (locator._master) + , _stack (locator._stack) + , _perpandiculars() + { } + + + inline AutoSegments_Perpandiculars::AutoSegments_Perpandiculars + ( AutoSegment* segment ) + : AutoSegmentHC() + , _segment(segment) + { } + + + inline AutoSegments_Perpandiculars::AutoSegments_Perpandiculars + ( const AutoSegments_Perpandiculars& autosegments ) + : AutoSegmentHC() + , _segment(autosegments._segment) + { } + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_AnchorOnGCell". + + class AutoSegments_AnchorOnGCell : public AutoSegmentHC { + + public: + // Sub-Class: Locator. + class Locator : public AutoSegmentHL { + public: + Locator ( GCell* fcell, unsigned int flags ); + inline Locator ( const Locator& ); + virtual ~Locator (); + virtual AutoSegment* getElement () const; + virtual AutoSegmentHL* getClone () const; + virtual bool isValid () const; + virtual void progress (); + virtual string _getString () const; + protected: + unsigned int _flags; + vector::const_iterator _itContact; + vector::const_iterator _itEnd; + Hurricane::Locator* _hookLocator; + AutoSegment* _element; + }; + + public: + // AutoSegments_Perpandiculars Methods. + inline AutoSegments_AnchorOnGCell ( GCell* fcell, unsigned int flags ); + inline AutoSegments_AnchorOnGCell ( const AutoSegments_AnchorOnGCell& ); + virtual AutoSegmentHC* getClone () const; + virtual AutoSegmentHL* getLocator () const; + virtual string _getString () const; + + public: + // AutoSegments_Perpandiculars Attributes. + GCell* _fcell; + unsigned int _flags; + }; + + + inline AutoSegments_AnchorOnGCell::Locator::Locator ( const Locator &locator ) + : AutoSegmentHL() + , _flags (locator._flags) + , _itContact (locator._itContact) + , _itEnd (locator._itEnd) + , _hookLocator (locator._hookLocator->getClone()) + , _element (locator._element) + { } + + + inline AutoSegments_AnchorOnGCell::AutoSegments_AnchorOnGCell ( GCell* fcell, unsigned int flags ) + : AutoSegmentHC() + , _fcell(fcell) + , _flags(flags) + { } + + + inline AutoSegments_AnchorOnGCell::AutoSegments_AnchorOnGCell + ( const AutoSegments_AnchorOnGCell& autosegments ) + : AutoSegmentHC() + , _fcell(autosegments._fcell) + , _flags(autosegments._flags) + { } + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_CachedOnContact". + + class AutoSegments_CachedOnContact : public AutoSegmentHC { + + public: + // Sub-Class: Locator. + class Locator : public AutoSegmentHL { + public: + Locator ( AutoContact* sourceAnchor, unsigned int direction ); + inline Locator ( const Locator& ); + virtual ~Locator (); + virtual AutoSegment* getElement () const; + virtual AutoSegmentHL* getClone () const; + virtual bool isValid () const; + virtual void progress (); + virtual string _getString () const; + protected: + LocatorHelper* _helper; + }; + + // Constructors. + public: + // AutoSegments_CachedOnContact Methods. + inline AutoSegments_CachedOnContact ( AutoContact* sourceContact + , unsigned int direction=Flags::Horizontal|Flags::Vertical ); + inline AutoSegments_CachedOnContact ( const AutoSegments_CachedOnContact& ); + virtual AutoSegmentHC* getClone () const; + virtual AutoSegmentHL* getLocator () const; + virtual string _getString () const; + + protected: + // AutoSegments_CachedOnContact Attributes. + unsigned int _direction; + AutoContact* _sourceContact; + + }; + + + inline AutoSegments_CachedOnContact::Locator::Locator ( const Locator &locator ) + : AutoSegmentHL() + , _helper(locator._helper) + { } + + + inline AutoSegments_CachedOnContact::AutoSegments_CachedOnContact + ( AutoContact* sourceContact, unsigned int direction ) + : AutoSegmentHC() + , _direction (direction) + , _sourceContact(sourceContact) + { + if (_direction & Flags::Vertical) _direction |= Flags::WithPerpands; + } + + + inline AutoSegments_CachedOnContact::AutoSegments_CachedOnContact + ( const AutoSegments_CachedOnContact& autosegments ) + : AutoSegmentHC() + , _direction (autosegments._direction) + , _sourceContact(autosegments._sourceContact) + { } + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_IsAccountable". + + class AutoSegments_IsAccountable : public AutoSegmentHF { + public: + virtual AutoSegmentHF* getClone () const; + virtual bool accept ( AutoSegment* ) const; + virtual string _getString () const; + }; + + +// ------------------------------------------------------------------- +// Class : "AutoSegments_InDirection". + + class AutoSegments_InDirection : public AutoSegmentHF { + public: + inline AutoSegments_InDirection ( unsigned int direction ); + inline AutoSegments_InDirection ( const AutoSegments_InDirection& ); + virtual AutoSegmentHF* getClone () const; + virtual bool accept ( AutoSegment* segment ) const; + virtual string _getString () const; + protected: + unsigned int _direction; + }; + + + inline AutoSegments_InDirection::AutoSegments_InDirection ( unsigned int direction ) + : AutoSegmentHF() + , _direction(direction) + {} + + + inline AutoSegments_InDirection::AutoSegments_InDirection ( const AutoSegments_InDirection& filter ) + : AutoSegmentHF() + , _direction(filter._direction) + {} + + +} // End of Anabatic namespace. + + +# endif diff --git a/anabatic/src/anabatic/AutoVertical.h b/anabatic/src/anabatic/AutoVertical.h new file mode 100644 index 00000000..ac263f20 --- /dev/null +++ b/anabatic/src/anabatic/AutoVertical.h @@ -0,0 +1,97 @@ + +// -*- 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 | +// | A n a b a t i c - Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./anabatic/AutoVertical.h" | +// +-----------------------------------------------------------------+ + + +#ifndef ANABATIC_AUTOVERTICAL_H +#define ANABATIC_AUTOVERTICAL_H + +#include "hurricane/Vertical.h" +#include "anabatic/AutoSegment.h" + + +namespace Anabatic { + + +// ------------------------------------------------------------------- +// Class : "AutoVertical". + + + class AutoVertical : public AutoSegment { + friend class AutoSegment; + + public: + // Predicates. + virtual bool _canSlacken () const; + virtual bool canMoveULeft ( float reserve=0.0 ) const; + virtual bool canMoveURight ( float reserve=0.0 ) const; + // Accessors. + virtual Segment* base (); + virtual Segment* base () const; + virtual Vertical* getVertical (); + virtual DbU::Unit getSourceU () const; + virtual DbU::Unit getTargetU () const; + virtual DbU::Unit getDuSource () const; + virtual DbU::Unit getDuTarget () const; + virtual Interval getSpanU () const; + virtual bool getConstraints ( DbU::Unit& min, DbU::Unit& max ) const; + virtual Interval getSourceConstraints ( unsigned int flags=0 ) const; + virtual Interval getTargetConstraints ( unsigned int flags=0 ) const; + virtual unsigned int getDirection () const; + virtual size_t getGCells ( vector& ) const; + // Modifiers. + virtual void setDuSource ( DbU::Unit ); + virtual void setDuTarget ( DbU::Unit ); + virtual void _setAxis ( DbU::Unit ); + virtual void updateOrient (); + virtual void updatePositions (); + virtual void updateNativeConstraints (); + virtual bool checkPositions () const; + virtual bool checkConstraints () const; + virtual unsigned int _makeDogleg ( GCell*, unsigned int flags ); + virtual bool moveULeft (); + virtual bool moveURight (); + virtual bool _slacken ( unsigned int flags ); +#if THIS_IS_DISABLED + virtual void desalignate ( AutoContact* ); +#endif + // Inspector Management. + virtual Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const; + + protected: + // Internal: Attributes. + Vertical* _vertical; + + // Constructors. + protected: + AutoVertical ( Vertical* ); + virtual ~AutoVertical (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + AutoVertical ( const AutoVertical& ); + AutoVertical& operator= ( const AutoVertical& ); + }; + + +} // End of Anabatic namespace. + + +INSPECTOR_P_SUPPORT(Anabatic::AutoVertical); + + +#endif // ANABATIC_AUTOHORIZONTAL_H diff --git a/anabatic/src/anabatic/Configuration.h b/anabatic/src/anabatic/Configuration.h index d122d310..20339aeb 100644 --- a/anabatic/src/anabatic/Configuration.h +++ b/anabatic/src/anabatic/Configuration.h @@ -83,7 +83,13 @@ namespace Anabatic { virtual DbU::Unit getWireWidth ( const Layer* ) const = 0; virtual DbU::Unit getExtensionCap ( const Layer* ) const = 0; virtual Flags getDirection ( const Layer* ) const = 0; + virtual float getSaturateRatio () const = 0; + virtual size_t getSaturateRp () const = 0; + virtual DbU::Unit getGlobalThreshold () const = 0; virtual void setAllowedDepth ( size_t ) = 0; + virtual void setSaturateRatio ( float ) = 0; + virtual void setSaturateRp ( size_t ) = 0; + virtual void setGlobalThreshold ( DbU::Unit ) = 0; virtual DbU::Unit getEdgeLength () const = 0; virtual DbU::Unit getEdgeWidth () const = 0; virtual float getEdgeCostH () const = 0; @@ -140,7 +146,13 @@ namespace Anabatic { virtual DbU::Unit getWireWidth ( const Layer* ) const; virtual DbU::Unit getExtensionCap ( const Layer* ) const; virtual Flags getDirection ( const Layer* ) const; + virtual float getSaturateRatio () const; + virtual size_t getSaturateRp () const; + virtual DbU::Unit getGlobalThreshold () const; virtual void setAllowedDepth ( size_t ); + virtual void setSaturateRatio ( float ); + virtual void setSaturateRp ( size_t ); + virtual void setGlobalThreshold ( DbU::Unit ); virtual DbU::Unit getEdgeLength () const; virtual DbU::Unit getEdgeWidth () const; virtual float getEdgeCostH () const; @@ -159,6 +171,9 @@ namespace Anabatic { CellGauge* _cg; RoutingGauge* _rg; std::vector _extensionCaps; + float _saturateRatio; + size_t _saturateRp; + DbU::Unit _globalThreshold; size_t _allowedDepth; DbU::Unit _edgeLength; DbU::Unit _edgeWidth; diff --git a/anabatic/src/anabatic/Constants.h b/anabatic/src/anabatic/Constants.h index 28686899..534dbe6e 100644 --- a/anabatic/src/anabatic/Constants.h +++ b/anabatic/src/anabatic/Constants.h @@ -1,4 +1,4 @@ -// -*- C++ -*- +// -*- mode: C++; explicit-buffer-name: "Constants.h" -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2016-2016, All Rights Reserved @@ -24,25 +24,60 @@ namespace Anabatic { class Flags : public Hurricane::BaseFlags { public: - enum Flag { NoFlags = 0 - , Horizontal = (1<<0) - , Vertical = (1<<1) - , SourceGCell = (1<<2) - , TargetGCell = (1<<3) - , DeviceGCell = (1<<4) - , ChannelGCell = (1<<5) - , StrutGCell = (1<<6) - , MatrixGCell = (1<<7) - , Invalidated = (1<<8) - , Destroy = (1<<9) - , WestSide = Horizontal|TargetGCell - , EastSide = Horizontal|SourceGCell - , SouthSide = Vertical |TargetGCell - , NorthSide = Vertical |SourceGCell - , AllSides = WestSide|EastSide|SouthSide|NorthSide - , PitchAbove = (1<<10) - , PitchBelow = (1<<11) - }; + static const unsigned int NoFlags = 0; + // Flags used for both objects states & functions arguments. + static const unsigned int Horizontal = (1 << 0); + static const unsigned int Vertical = (1 << 1); + static const unsigned int Source = (1 << 2); + static const unsigned int Target = (1 << 3); + static const unsigned int Invalidated = (1 << 4); + // Flags for GCell objects states only. + static const unsigned int DeviceGCell = (1 << 5); + static const unsigned int ChannelGCell = (1 << 6); + static const unsigned int StrutGCell = (1 << 7); + static const unsigned int MatrixGCell = (1 << 8); + static const unsigned int IoPadGCell = (1 << 9); + static const unsigned int Saturated = (1 << 10); + // Flags for Anabatic objects states only. + static const unsigned int DemoMode = (1 << 5); + static const unsigned int WarnOnGCellOverload = (1 << 6); + static const unsigned int DestroyGCell = (1 << 7); + static const unsigned int DestroyBaseContact = (1 << 8); + static const unsigned int DestroyBaseSegment = (1 << 9); + // Masks. + static const unsigned int WestSide = Horizontal|Target; + static const unsigned int EastSide = Horizontal|Source; + static const unsigned int SouthSide = Vertical |Target; + static const unsigned int NorthSide = Vertical |Source; + static const unsigned int AllSides = WestSide|EastSide|SouthSide|NorthSide ; + static const unsigned int DirectionMask = Horizontal|Vertical; + static const unsigned int DestroyMask = DestroyGCell|DestroyBaseContact|DestroyBaseSegment; + // Flags for functions arguments only. + static const unsigned int AboveLayer = (1 << 5); + static const unsigned int BelowLayer = (1 << 6); + static const unsigned int OpenSession = (1 << 7); + static const unsigned int Realignate = (1 << 8); + static const unsigned int NativeConstraints = (1 << 9); + static const unsigned int ForceMove = (1 << 10); + static const unsigned int WithPerpands = (1 << 11); + static const unsigned int WarnOnError = (1 << 12); + static const unsigned int Topology = (1 << 13); + static const unsigned int GlobalSegment = (1 << 14); + static const unsigned int AllowTerminal = (1 << 15); + static const unsigned int AllowLocal = (1 << 16); + static const unsigned int IgnoreContacts = (1 << 17); + static const unsigned int Propagate = (1 << 18); + static const unsigned int Superior = (1 << 19); + static const unsigned int DoglegOnLeft = (1 << 20); + static const unsigned int DoglegOnRight = (1 << 21); + static const unsigned int WithNeighbors = (1 << 22); + static const unsigned int NoCheckLayer = (1 << 23); + static const unsigned int HalfSlacken = (1 << 24); + static const unsigned int NoGCellShrink = (1 << 25); + static const unsigned int CParanoid = (1 << 26); + static const unsigned int Create = (1 << 27); + static const unsigned int CheckLowDensity = (1 << 28); + static const unsigned int NoUpdate = (1 << 29); public: inline Flags ( unsigned int flags = NoFlags ); inline Flags ( BaseFlags ); @@ -56,6 +91,23 @@ namespace Anabatic { Flags::Flags ( BaseFlags base ) : BaseFlags(base) { } + enum EngineState { EngineCreation = 1 + , EngineGlobalLoaded = 2 + , EngineActive = 3 + , EngineDriving = 4 + , EnginePreDestroying = 5 + , EngineGutted = 6 + }; + + enum EngineAlgorithm { EngineLoadGrByNet = (1 << 0) + , EngineLoadGrByGCell = (1 << 1) + , EngineLayerAssignByLength = (1 << 2) + , EngineLayerAssignByTrunk = (1 << 3) + , EngineNoNetLayerAssign = (1 << 4) + }; + + + } // Anabatic namespace. diff --git a/anabatic/src/anabatic/GCell.h b/anabatic/src/anabatic/GCell.h index eb91fcc2..f27bfe99 100644 --- a/anabatic/src/anabatic/GCell.h +++ b/anabatic/src/anabatic/GCell.h @@ -20,20 +20,25 @@ #include #include #include +#include #include "hurricane/Name.h" #include "hurricane/Box.h" #include "hurricane/Cell.h" #include "hurricane/ExtensionGo.h" namespace Hurricane { class Contact; + class RoutingPad; } #include "anabatic/Edge.h" +#include "anabatic/AutoSegments.h" namespace Anabatic { using std::string; using std::vector; + using std::set; + using std::binary_function; using Hurricane::StaticObservable; using Hurricane::BaseObserver; using Hurricane::Name; @@ -45,9 +50,11 @@ namespace Anabatic { using Hurricane::Net; using Hurricane::Entity; using Hurricane::Contact; + using Hurricane::RoutingPad; using Hurricane::Cell; class AnabaticEngine; + class GCell; // ------------------------------------------------------------------- @@ -56,6 +63,18 @@ namespace Anabatic { class GCell : public ExtensionGo { public: typedef ExtensionGo Super; + typedef std::set< GCell*, Entity::CompareById > Set; + typedef std::vector Vector; + public: + enum DensityMode { AverageHVDensity = 1 // Average between all densities. + , AverageHDensity = 2 // Average between all H densities. + , AverageVDensity = 3 // Average between all V densities. + , MaxHVDensity = 4 // Maximum between average H and average V. + , MaxVDensity = 5 // Maximum of V densities. + , MaxHDensity = 6 // Maximum of H densities. + , MaxDensity = 7 // Maximum of H & V densities. + }; + public: class Observable : public StaticObservable<1> { public: @@ -68,123 +87,219 @@ namespace Anabatic { Observable& operator= ( const StaticObservable& ); }; public: - static Box getBorder ( const GCell*, const GCell* ); + class CompareByDensity : public binary_function { + public: + CompareByDensity ( size_t depth ); + inline bool operator() ( GCell* lhs, GCell* rhs ); + private: + size_t _depth; + }; + class CompareByKey : public binary_function { + public: + inline bool operator() ( const GCell* lhs, const GCell* rhs ); + }; + public: + class Key { + public: + inline Key ( GCell*, size_t depth ); + inline float getDensity () const; + inline GCell* getGCell () const; + inline void update ( size_t depth ); + friend bool operator< ( const Key&, const Key& ); + private: + GCell* _gcell; + float _density; + }; + public: + static Box getBorder ( const GCell*, const GCell* ); public: - static GCell* create ( AnabaticEngine* ); + static GCell* create ( AnabaticEngine* ); public: - inline bool isHFlat () const; - inline bool isVFlat () const; - inline bool isFlat () const; - inline bool isDevice () const; - inline bool isChannel () const; - inline bool isStrut () const; - inline bool isMatrix () const; - bool isWest ( GCell* ) const; - bool isEast ( GCell* ) const; - bool isNorth ( GCell* ) const; - bool isSouth ( GCell* ) const; - bool hasGContact ( const Contact* ) const; - inline AnabaticEngine* getAnabatic () const; - inline DbU::Unit getXMin () const; - inline DbU::Unit getYMin () const; - inline DbU::Unit getXMax ( int shrink=0 ) const; - inline DbU::Unit getYMax ( int shrink=0 ) const; - inline Interval getSide ( Flags direction ) const; - inline Point getCenter () const; - inline const vector& getWestEdges () const; - inline const vector& getEastEdges () const; - inline const vector& getNorthEdges () const; - inline const vector& getSouthEdges () const; - Edge* getEdgeTo ( GCell*, Flags sideHint=Flags::AllSides ) const; - inline Edges getEdges ( Flags sides=Flags::AllSides ) const; - inline GCell* getWest () const; - inline GCell* getEast () const; - inline GCell* getSouth () const; - inline GCell* getNorth () const; - GCell* getWest ( DbU::Unit y ) const; - GCell* getEast ( DbU::Unit y ) const; - GCell* getSouth ( DbU::Unit x ) const; - GCell* getNorth ( DbU::Unit x ) const; - GCell* getUnder ( DbU::Unit x, DbU::Unit y ) const; - inline GCell* getUnder ( Point p ) const; - GCell* hcut ( DbU::Unit y ); - GCell* vcut ( DbU::Unit x ); - bool doGrid (); - Contact* getGContact ( Net* ); - inline const vector& getGContacts () const; - bool unrefContact ( Contact* ); + inline bool isSaturated () const; + bool isSaturated ( size_t depth ) const; + inline bool isInvalidated () const; + inline bool isHFlat () const; + inline bool isVFlat () const; + inline bool isFlat () const; + inline bool isDevice () const; + inline bool isChannel () const; + inline bool isStrut () const; + inline bool isMatrix () const; + inline bool isIoPad () const; + bool isWest ( GCell* ) const; + bool isEast ( GCell* ) const; + bool isNorth ( GCell* ) const; + bool isSouth ( GCell* ) const; + bool hasGContact ( const Contact* ) const; + inline AnabaticEngine* getAnabatic () const; + inline DbU::Unit getXMin () const; + inline DbU::Unit getYMin () const; + inline DbU::Unit getXMax ( int shrink=0 ) const; + inline DbU::Unit getYMax ( int shrink=0 ) const; + inline Interval getSide ( Flags direction ) const; + inline Point getCenter () const; + inline const vector& getWestEdges () const; + inline const vector& getEastEdges () const; + inline const vector& getNorthEdges () const; + inline const vector& getSouthEdges () const; + Edge* getEdgeTo ( GCell*, Flags sideHint=Flags::AllSides ) const; + inline Edges getEdges ( Flags sides=Flags::AllSides ) const; + inline GCell* getWest () const; + inline GCell* getEast () const; + inline GCell* getSouth () const; + inline GCell* getNorth () const; + GCell* getWest ( DbU::Unit y ) const; + GCell* getEast ( DbU::Unit y ) const; + GCell* getSouth ( DbU::Unit x ) const; + GCell* getNorth ( DbU::Unit x ) const; + GCell* getUnder ( DbU::Unit x, DbU::Unit y ) const; + inline GCell* getUnder ( Point p ) const; + GCell* hcut ( DbU::Unit y ); + GCell* vcut ( DbU::Unit x ); + bool doGrid (); + Contact* getGContact ( Net* ); + inline const vector& getGContacts () const; + bool unrefContact ( Contact* ); + void cleanupGlobal (); + // Detailed routing functions. + bool hasFreeTrack ( size_t depth, float reserve ) const; + inline size_t getDepth () const; + Interval getSide ( unsigned int ) const; + float getHCapacity () const; + float getVCapacity () const; + float getDensity ( unsigned int flags=Flags::NoFlags ) const; + float getAverageHVDensity () const; + float getMaxHVDensity () const; + inline float getCDensity ( unsigned int flags=Flags::NoFlags ) const; + inline float getWDensity ( size_t depth, unsigned int flags=Flags::NoFlags ) const; + inline DbU::Unit getBlockage ( size_t depth ) const; + inline float getFragmentation ( size_t depth ) const; + inline float getFeedthroughs ( size_t depth ) const; + inline float getGlobalsCount ( size_t depth ) const; + inline const vector& getHSegments () const; + inline const vector& getVSegments () const; + inline const vector& getContacts () const; + AutoSegments getHStartSegments (); + AutoSegments getVStartSegments (); + AutoSegments getHStopSegments (); + AutoSegments getVStopSegments (); + inline AutoSegments getStartSegments ( unsigned int direction ); + inline AutoSegments getStopSegments ( unsigned int direction ); + size_t getRoutingPads ( set& ); + inline const Key& getKey () const; + size_t checkDensity () const; + bool checkEdgeSaturation ( size_t hreserved, size_t vreserved) const; + void addBlockage ( size_t depth, DbU::Unit ); + inline void addHSegment ( AutoSegment* ); + inline void addVSegment ( AutoSegment* ); + inline void addContact ( AutoContact* ); + void removeVSegment ( AutoSegment* ); + void removeHSegment ( AutoSegment* ); + void removeContact ( AutoContact* ); + void updateContacts (); + size_t updateDensity (); + inline void updateKey ( size_t depth ); + bool stepBalance ( size_t depth, Set& invalidateds ); + void rpDesaturate ( set& ); + bool stepDesaturate ( size_t depth + , set&, AutoSegment*& moved + , unsigned int flags=Flags::NoFlags ); + bool stepNetDesaturate ( size_t depth + , set& globalNets + , Set& invalidateds ); // Misc. functions. - inline const Flags& flags () const; - inline Flags& flags (); - void _add ( Edge* edge, Flags side ); - void _remove ( Edge* edge, Flags side=Flags::AllSides ); - void _destroyEdges (); - private: - void _revalidate (); - void _moveEdges ( GCell* dest, size_t ibegin, Flags flags ); - public: - // Observers. - inline void setObserver ( size_t slot, BaseObserver* ); - template - inline OwnerT* getObserver ( size_t slot ); - inline void notify ( unsigned int flags ); - // ExtensionGo support. - inline const Name& staticGetName (); - virtual const Name& getName () const; - virtual void translate ( const DbU::Unit&, const DbU::Unit& ); - virtual Box getBoundingBox () const; + inline const Flags& flags () const; + inline Flags& flags (); + void _add ( Edge* edge, Flags side ); + void _remove ( Edge* edge, Flags side=Flags::AllSides ); + void _destroyEdges (); + private: + void _revalidate (); + void _moveEdges ( GCell* dest, size_t ibegin, Flags flags ); + public: + // Observers. + template + inline OwnerT* getObserver ( size_t slot ); + inline void setObserver ( size_t slot, BaseObserver* ); + inline void notify ( unsigned int flags ); + // ExtensionGo support. + inline const Name& staticGetName (); + virtual const Name& getName () const; + virtual void translate ( const DbU::Unit&, const DbU::Unit& ); + virtual Box getBoundingBox () const; public: // Inspector support. - virtual string _getTypeName () const; - virtual string _getString () const; - virtual Record* _getRecord () const; - protected: - GCell ( AnabaticEngine*, DbU::Unit xmin, DbU::Unit ymin ); - virtual ~GCell (); - GCell* _create ( DbU::Unit xmin, DbU::Unit ymin ); - virtual void _postCreate (); - virtual void _preDestroy (); + virtual string _getTypeName () const; + virtual string _getString () const; + virtual Record* _getRecord () const; + protected: + GCell ( AnabaticEngine*, DbU::Unit xmin, DbU::Unit ymin ); + virtual ~GCell (); + GCell* _create ( DbU::Unit xmin, DbU::Unit ymin ); + virtual void _postCreate (); + virtual void _preDestroy (); private: - GCell ( const GCell& ); - GCell& operator= ( const GCell& ); + GCell ( const GCell& ); + GCell& operator= ( const GCell& ); private: - static Name _extensionName; - Observable _observable; - AnabaticEngine* _anabatic; - Flags _flags; - vector _westEdges; - vector _eastEdges; - vector _southEdges; - vector _northEdges; - DbU::Unit _xmin; - DbU::Unit _ymin; - vector _contacts; + static Name _extensionName; + Observable _observable; + AnabaticEngine* _anabatic; + Flags _flags; + vector _westEdges; + vector _eastEdges; + vector _southEdges; + vector _northEdges; + DbU::Unit _xmin; + DbU::Unit _ymin; + vector _gcontacts; + vector _vsegments; + vector _hsegments; + vector _contacts; + size_t _depth; + size_t _pinDepth; + DbU::Unit* _blockages; + float _cDensity; + float* _densities; + float* _feedthroughs; + float* _fragmentations; + float* _globalsCount; + Key _key; }; - inline bool GCell::isHFlat () const { return getYMin() == getYMax(); } - inline bool GCell::isVFlat () const { return getXMin() == getXMax(); } - inline bool GCell::isFlat () const { return isHFlat() or isVFlat(); } - inline bool GCell::isDevice () const { return _flags & Flags::DeviceGCell; } - inline bool GCell::isChannel () const { return _flags & Flags::ChannelGCell; } - inline bool GCell::isStrut () const { return _flags & Flags::StrutGCell; } - inline bool GCell::isMatrix () const { return _flags & Flags::MatrixGCell; } - inline AnabaticEngine* GCell::getAnabatic () const { return _anabatic; } - inline DbU::Unit GCell::getXMin () const { return _xmin; } - inline DbU::Unit GCell::getYMin () const { return _ymin; } - inline Edges GCell::getEdges ( Flags sides ) const { return new GCell_Edges(this,sides); } - inline const vector& GCell::getWestEdges () const { return _westEdges; } - inline const vector& GCell::getEastEdges () const { return _eastEdges; } - inline const vector& GCell::getNorthEdges () const { return _northEdges; } - inline const vector& GCell::getSouthEdges () const { return _southEdges; } - inline GCell* GCell::getWest () const { return _westEdges.empty() ? NULL : _westEdges[0]->getOpposite(this); } - inline GCell* GCell::getEast () const { return _eastEdges.empty() ? NULL : _eastEdges[0]->getOpposite(this); } - inline GCell* GCell::getSouth () const { return _southEdges.empty() ? NULL : _southEdges[0]->getOpposite(this); } - inline GCell* GCell::getNorth () const { return _northEdges.empty() ? NULL : _northEdges[0]->getOpposite(this); } - inline GCell* GCell::getUnder ( Point p ) const { return getUnder(p.getX(),p.getY()); } - inline const vector& GCell::getGContacts () const { return _contacts; } - inline const Flags& GCell::flags () const { return _flags; } - inline Flags& GCell::flags () { return _flags; } + inline bool GCell::isHFlat () const { return getYMin() == getYMax(); } + inline bool GCell::isVFlat () const { return getXMin() == getXMax(); } + inline bool GCell::isFlat () const { return isHFlat() or isVFlat(); } + inline bool GCell::isDevice () const { return _flags & Flags::DeviceGCell; } + inline bool GCell::isChannel () const { return _flags & Flags::ChannelGCell; } + inline bool GCell::isStrut () const { return _flags & Flags::StrutGCell; } + inline bool GCell::isMatrix () const { return _flags & Flags::MatrixGCell; } + inline bool GCell::isIoPad () const { return _flags & Flags::IoPadGCell; } + inline bool GCell::isSaturated () const { return _flags & Flags::Saturated; } + inline bool GCell::isInvalidated () const { return _flags & Flags::Invalidated; } + inline AnabaticEngine* GCell::getAnabatic () const { return _anabatic; } + inline DbU::Unit GCell::getXMin () const { return _xmin; } + inline DbU::Unit GCell::getYMin () const { return _ymin; } + inline Edges GCell::getEdges ( Flags sides ) const { return new GCell_Edges(this,sides); } + inline const vector& GCell::getWestEdges () const { return _westEdges; } + inline const vector& GCell::getEastEdges () const { return _eastEdges; } + inline const vector& GCell::getNorthEdges () const { return _northEdges; } + inline const vector& GCell::getSouthEdges () const { return _southEdges; } + inline GCell* GCell::getWest () const { return _westEdges.empty() ? NULL : _westEdges[0]->getOpposite(this); } + inline GCell* GCell::getEast () const { return _eastEdges.empty() ? NULL : _eastEdges[0]->getOpposite(this); } + inline GCell* GCell::getSouth () const { return _southEdges.empty() ? NULL : _southEdges[0]->getOpposite(this); } + inline GCell* GCell::getNorth () const { return _northEdges.empty() ? NULL : _northEdges[0]->getOpposite(this); } + inline GCell* GCell::getUnder ( Point p ) const { return getUnder(p.getX(),p.getY()); } + inline const vector& GCell::getGContacts () const { return _gcontacts; } + inline size_t GCell::getDepth () const { return _depth; } + inline const vector& GCell::getVSegments () const { return _vsegments; } + inline const vector& GCell::getHSegments () const { return _hsegments; } + inline const vector& GCell::getContacts () const { return _contacts; } + inline const GCell::Key& GCell::getKey () const { return _key; } + inline void GCell::updateKey ( size_t depth ) { _key.update(depth); } + inline const Flags& GCell::flags () const { return _flags; } + inline Flags& GCell::flags () { return _flags; } inline DbU::Unit GCell::getXMax ( int shrink ) const { return _eastEdges.empty() ? getCell()->getAbutmentBox().getXMax() - shrink @@ -215,11 +330,103 @@ namespace Anabatic { inline GCell::Observable::Observable () : StaticObservable<1>() { } + inline AutoSegments GCell::getStartSegments ( unsigned int direction ) + { return (direction&Flags::Horizontal) ? getHStartSegments() : getVStartSegments(); } + + inline AutoSegments GCell::getStopSegments ( unsigned int direction ) + { return (direction&Flags::Horizontal) ? getHStopSegments() : getVStopSegments(); } + + inline float GCell::getCDensity ( unsigned int flags ) const + { if (isInvalidated() and not(flags & Flags::NoUpdate)) const_cast(this)->updateDensity(); return _cDensity; } + + inline float GCell::getWDensity ( size_t depth, unsigned int flags ) const + { if (isInvalidated() and not(flags & Flags::NoUpdate)) const_cast(this)->updateDensity(); return _densities[depth]; } + + inline float GCell::getFragmentation ( size_t depth ) const + { if (isInvalidated()) const_cast(this)->updateDensity(); return _fragmentations[depth]; } + + inline float GCell::getFeedthroughs ( size_t depth ) const + { if (isInvalidated()) const_cast(this)->updateDensity(); return _feedthroughs[depth]; } + + inline float GCell::getGlobalsCount ( size_t depth ) const + { if (isInvalidated()) const_cast(this)->updateDensity(); return _globalsCount[depth]; } + + inline DbU::Unit GCell::getBlockage ( size_t depth ) const + { return (depth<_depth) ? _blockages[depth] : 0; } + + inline void GCell::addVSegment ( AutoSegment* segment ) + { _flags |= Flags::Invalidated; _vsegments.push_back(segment); } + + inline void GCell::addHSegment ( AutoSegment* segment ) + { _flags |= Flags::Invalidated; _hsegments.push_back(segment); } + + inline void GCell::addContact ( AutoContact* contact ) + { _flags |= Flags::Invalidated; _contacts.push_back(contact); } + + + inline bool operator< ( const GCell& lhs, const GCell& rhs ) + { + if (lhs.getYMin() != rhs.getYMin()) return lhs.getYMin() < rhs.getYMin(); + if (lhs.getXMin() != rhs.getXMin()) return lhs.getXMin() < rhs.getXMin(); + return lhs.getId() < rhs.getId(); + } + + +// GCell::CompareByKey Inline Functions. + inline bool GCell::CompareByKey::operator() ( const GCell* lhs, const GCell* rhs ) + { return lhs->getKey() < rhs->getKey(); } + + +// GCell::Key Inline Functions. + inline GCell::Key::Key ( GCell* owner, size_t depth ) : _gcell(owner), _density(owner->getWDensity(depth,Flags::NoUpdate)) {} + inline float GCell::Key::getDensity () const { return _density; } + inline GCell* GCell::Key::getGCell () const { return _gcell; } + inline void GCell::Key::update ( size_t depth ) { _density=_gcell->getWDensity(depth); } + + inline bool operator< ( const GCell::Key& lhs, const GCell::Key& rhs ) + { + float difference = lhs._density - rhs._density; + if (difference != 0.0) return (difference > 0.0); + + return lhs._gcell->getId() < rhs._gcell->getId(); + } + // ------------------------------------------------------------------- -// Class : "GCellSet". +// Class : "GCellDensitySet". + + class GCellDensitySet { + public: + GCellDensitySet ( size_t depth ); + GCellDensitySet ( size_t depth, const std::vector& ); + ~GCellDensitySet (); + inline bool empty () const; + inline size_t size () const; + inline const std::set& + getGCells () const; + inline void insert ( GCell* ); + inline void erase ( GCell* ); + inline void unqueue ( GCell* ); + void requeue (); + private: + size_t _depth; + std::set _set; + GCell::Set _requests; + }; - typedef std::set< GCell*, Entity::CompareById > GCellSet; + + inline bool GCellDensitySet::empty () const { return _set.empty(); } + inline size_t GCellDensitySet::size () const { return _set.size(); } + inline void GCellDensitySet::insert ( GCell* gcell ) { _requests.insert( gcell ); } + inline void GCellDensitySet::erase ( GCell* gcell ) { if (not _set.empty()) _set.erase( gcell ); } + inline void GCellDensitySet::unqueue ( GCell* gcell ) { insert( gcell ); } + inline const std::set& GCellDensitySet::getGCells () const { return _set; } + + +// ------------------------------------------------------------------- +// Utilities. + + string getVectorString ( float*, size_t ); } // Anabatic namespace. diff --git a/anabatic/src/anabatic/GraphicAnabaticEngine.h b/anabatic/src/anabatic/GraphicAnabaticEngine.h index 7a8ecf78..e2a81e72 100644 --- a/anabatic/src/anabatic/GraphicAnabaticEngine.h +++ b/anabatic/src/anabatic/GraphicAnabaticEngine.h @@ -83,6 +83,7 @@ namespace Anabatic { virtual ~GraphicAnabaticEngine (); void _runTest (); void _globalRoute (); + void _detailRoute (); }; diff --git a/anabatic/src/anabatic/Session.h b/anabatic/src/anabatic/Session.h new file mode 100644 index 00000000..33ec8549 --- /dev/null +++ b/anabatic/src/anabatic/Session.h @@ -0,0 +1,236 @@ +// -*- mode: C++; explicit-buffer-name: "Session.h" -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2016, 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++ Header : "./anabatic/Session.h" | +// +-----------------------------------------------------------------+ + + +#ifndef ANABATIC_SESSION_H +#define ANABATIC_SESSION_H + +#include +#include +#include +#include +#include +#include "hurricane/Commons.h" +#include "hurricane/DbU.h" +#include "crlcore/CellGauge.h" +#include "crlcore/RoutingGauge.h" +#include "anabatic/Constants.h" +#include "anabatic/Configuration.h" + +namespace Hurricane { + class Layer; + class Technology; + class Net; + class Contact; + class Segment; +} + + +namespace Anabatic { + + using std::cerr; + using std::endl; + using std::string; + using std::vector; + using std::set; + using std::map; + using std::make_pair; + using Hurricane::tab; + using Hurricane::_TName; + using Hurricane::Record; + using Hurricane::Layer; + using Hurricane::Technology; + using Hurricane::DbU; + using Hurricane::Net; + using Hurricane::Contact; + using Hurricane::Segment; + using CRL::RoutingGauge; + + class AutoContact; + class AutoSegment; + class AnabaticEngine; + + +// ------------------------------------------------------------------- +// Class : "Anabatic::Session". + + class Session { + public: + // Static Methods. + static inline bool doDestroyBaseContact (); + static inline bool doDestroyBaseSegment (); + static inline bool doDestroyTool (); + static bool isInDemoMode (); + static bool doWarnGCellOverload (); + static Session* get ( const char* message=NULL ); + static inline Technology* getTechnology (); + static inline AnabaticEngine* getAnabatic (); + static inline const Configuration* getConfiguration (); + static float getSaturateRatio (); + static size_t getSaturateRp (); + static inline size_t getAllowedDepth (); + static DbU::Unit getExtensionCap (); + static inline CellGauge* getCellGauge (); + static inline DbU::Unit getSliceHeight (); + static inline DbU::Unit getSliceStep (); + static inline RoutingGauge* getRoutingGauge (); + static inline RoutingLayerGauge* getLayerGauge ( size_t depth ); + static inline size_t getDepth (); + static inline size_t getViaDepth ( const Layer* layer ); + static inline size_t getLayerDepth ( const Layer* layer ); + static inline const Layer* getRoutingLayer ( size_t ); + static inline const Layer* getContactLayer ( size_t ); + static unsigned int getDirection ( size_t depth ); + static inline DbU::Unit getPitch ( size_t depth, unsigned int flags ); + static inline DbU::Unit getOffset ( size_t depth ); + static inline DbU::Unit getWireWidth ( size_t depth ); + static inline DbU::Unit getViaWidth ( size_t depth ); + static inline unsigned int getDirection ( const Layer* ); + static inline DbU::Unit getPitch ( const Layer*, unsigned int flags ); + static inline DbU::Unit getOffset ( const Layer* ); + static inline DbU::Unit getWireWidth ( const Layer* ); + static inline DbU::Unit getViaWidth ( const Layer* ); + static inline DbU::Unit getExtensionCap ( const Layer* ); + static inline size_t getSegmentStackSize (); + static inline size_t getContactStackSize (); + static inline const vector& getInvalidateds (); + static inline const vector& getRevalidateds (); + static inline const set& getDestroyeds (); + static inline const vector& getDoglegs (); + static inline const set& getNetsModificateds (); + static Session* open ( AnabaticEngine* ); + static void close (); + static void setAnabaticFlags ( unsigned int ); + static inline void dogleg ( AutoSegment* ); + static inline void doglegReset (); + static inline void revalidateTopology (); + static inline void setInvalidateMask ( unsigned int ); + static inline void invalidate ( Net* ); + static inline void invalidate ( AutoContact* ); + static inline void invalidate ( AutoSegment* ); + static inline size_t revalidate (); + static void link ( AutoContact* ); + static void link ( AutoSegment* ); + static void unlink ( AutoContact* ); + static void unlink ( AutoSegment* ); + static AutoContact* lookup ( Contact* ); + static AutoSegment* lookup ( Segment* ); + static inline void destroyRequest ( AutoSegment* ); + // Methods. + bool _doDestroyBaseContact (); + bool _doDestroyBaseSegment (); + bool _doDestroyTool (); + virtual Configuration* _getConfiguration (); + inline void _dogleg ( AutoSegment* ); + inline void _doglegReset (); + void _invalidate ( Net* ); + inline void _invalidate ( AutoContact* ); + inline void _invalidate ( AutoSegment* ); + inline void _destroyRequest ( AutoSegment* ); + void _canonize (); + void _revalidateTopology (); + size_t _revalidate (); + DbU::Unit _getPitch ( size_t depth, unsigned int flags ) const; + Record* _getRecord () const; + string _getString () const; + inline string _getTypeName () const; + + protected: + static Session* _session; + AnabaticEngine* _anabatic; + Technology* _technology; + CellGauge* _cellGauge; + RoutingGauge* _routingGauge; + vector _autoContacts; + vector _doglegs; + vector _segmentInvalidateds; + vector _segmentRevalidateds; + set _netInvalidateds; + set _netRevalidateds; + set _destroyedSegments; + + // Constructors. + protected: + Session ( AnabaticEngine* ); + virtual ~Session (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + Session ( const Session& ); + Session& operator= ( const Session& ); + }; + + +// Inline Functions. + inline Technology* Session::getTechnology () { return get("getTechnology()")->_technology; } + inline CellGauge* Session::getCellGauge () { return get("getCellGauge()")->_cellGauge; } + inline RoutingGauge* Session::getRoutingGauge () { return get("getRoutingGauge()")->_routingGauge; } + inline bool Session::doDestroyBaseContact () { return get("doDestroyBaseContact()")->_doDestroyBaseContact(); } + inline bool Session::doDestroyBaseSegment () { return get("doDestroyBaseSegment()")->_doDestroyBaseSegment(); } + inline bool Session::doDestroyTool () { return get("doDestroyTool()")->_doDestroyTool(); } + inline const Configuration* Session::getConfiguration () { return get("getConfiguration()")->_getConfiguration(); } + inline AnabaticEngine* Session::getAnabatic () { return get("getAnabatic()")->_anabatic; } + inline void Session::revalidateTopology () { return get("revalidateTopology()")->_revalidateTopology(); } + inline size_t Session::revalidate () { return get("revalidate()")->_revalidate(); } + inline size_t Session::getSegmentStackSize () { return get("getSegmentStackSize()")->_segmentInvalidateds.size(); } + inline size_t Session::getContactStackSize () { return get("getContactStackSize()")->_autoContacts.size(); } + inline const vector& Session::getInvalidateds () { return get("getInvalidateds()")->_segmentInvalidateds; } + inline const vector& Session::getRevalidateds () { return get("getRevalidateds()")->_segmentRevalidateds; } + inline const set& Session::getDestroyeds () { return get("getDestroyeds()")->_destroyedSegments; } + inline const vector& Session::getDoglegs () { return get("getDoglegs()")->_doglegs; } + inline const set& Session::getNetsModificateds () { return get("getNetsModificateds()")->_netRevalidateds; } + inline void Session::doglegReset () { return get("doglegReset()")->_doglegReset (); } + inline void Session::invalidate ( Net* net ) { return get("invalidate(Net*)")->_invalidate(net); } + inline void Session::invalidate ( AutoContact* autoContact ) { return get("invalidate(AutoContact*)")->_invalidate(autoContact); } + inline void Session::invalidate ( AutoSegment* autoSegment ) { return get("invalidate(AutoSegment*)")->_invalidate(autoSegment); } + inline void Session::dogleg ( AutoSegment* autoSegment ) { return get("dogleg(AutoSegment*)")->_dogleg(autoSegment); } + inline void Session::destroyRequest ( AutoSegment* autoSegment ) { return get("destroyRequest(AutoSegment*)")->_destroyRequest(autoSegment); } + + inline size_t Session::getAllowedDepth () { return getConfiguration()->getAllowedDepth(); } + + inline DbU::Unit Session::getSliceHeight () { return getCellGauge()->getSliceHeight(); } + inline DbU::Unit Session::getSliceStep () { return getCellGauge()->getSliceStep(); } + inline RoutingLayerGauge* Session::getLayerGauge ( size_t depth ) { return getRoutingGauge()->getLayerGauge(depth); } + inline size_t Session::getDepth () { return getRoutingGauge()->getDepth(); } + inline size_t Session::getViaDepth ( const Layer* layer ) { return getRoutingGauge()->getViaDepth(layer); } + inline size_t Session::getLayerDepth ( const Layer* layer ) { return getRoutingGauge()->getLayerDepth(layer); } + inline const Layer* Session::getRoutingLayer ( size_t depth ) { return getRoutingGauge()->getRoutingLayer(depth); } + inline const Layer* Session::getContactLayer ( size_t depth ) { return getRoutingGauge()->getContactLayer(depth); } + inline DbU::Unit Session::getPitch ( size_t depth, unsigned int flags=Flags::NoFlags ) { return get("getPitch(depth,flags)")->_getPitch( depth, flags ); } + inline DbU::Unit Session::getOffset ( size_t depth ) { return getRoutingGauge()->getLayerOffset(depth); } + inline DbU::Unit Session::getWireWidth ( size_t depth ) { return getRoutingGauge()->getLayerWireWidth(depth); } + inline DbU::Unit Session::getViaWidth ( size_t depth ) { return getRoutingGauge()->getViaWidth(depth); } + inline DbU::Unit Session::getPitch ( const Layer* layer, unsigned int flags=Flags::NoFlags ) { return getPitch( getLayerDepth(layer), flags ); } + inline DbU::Unit Session::getOffset ( const Layer* layer ) { return getOffset ( getLayerDepth(layer) ); } + inline DbU::Unit Session::getWireWidth ( const Layer* layer ) { return getWireWidth( getLayerDepth(layer) ); } + inline DbU::Unit Session::getViaWidth ( const Layer* layer ) { return getViaWidth ( getViaDepth(layer) ); } + inline DbU::Unit Session::getExtensionCap ( const Layer* layer ) { return getConfiguration()->getExtensionCap(layer); } + inline unsigned int Session::getDirection ( const Layer* layer ) { return getDirection( getLayerDepth(layer) ); } + + inline void Session::_dogleg ( AutoSegment* segment ) { _doglegs.push_back(segment); } + inline void Session::_doglegReset () { _doglegs.clear(); } + inline void Session::_invalidate ( AutoContact* contact ) { _autoContacts.push_back(contact); } + inline void Session::_invalidate ( AutoSegment* segment ) { _segmentInvalidateds.push_back(segment); } + inline void Session::_destroyRequest ( AutoSegment* segment ) { _destroyedSegments.insert(segment); } + inline string Session::_getTypeName () const { return _TName("Session"); } + + +} // Anabatic namespace. + + +INSPECTOR_P_SUPPORT(Anabatic::Session); + + +#endif // ANABATIC_SESSION_H