// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2008-2018, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | // | A n a b a t i c - Routing Toolbox | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@lip6.fr | // | =============================================================== | // | C++ Module : "./AutoSegments.cpp" | // +-----------------------------------------------------------------+ #include "hurricane/Error.h" #include "hurricane/RoutingPad.h" #include "anabatic/AutoContactTerminal.h" #include "anabatic/AutoSegment.h" namespace { using namespace Anabatic; AutoContact* isLocalDogleg ( AutoSegment* current, AutoContact* from, AutoSegment* master ) { if (not current->isLocal() or not from->isTurn()) return NULL; AutoContact* to = current->getOppositeAnchor( from ); if (not to->isTurn()) return NULL; AutoSegment* targetGlobal = to->getPerpandicular( current ); if (not targetGlobal->isGlobal() or (master->getLayer() != targetGlobal->getLayer())) return NULL; cdebug_log(144,0) << "Global aligned though dogleg:" << targetGlobal << endl; Interval masterConstraints; Interval targetConstraints; master ->getConstraints( masterConstraints ); targetGlobal->getConstraints( targetConstraints ); if (not targetConstraints.intersect(masterConstraints)) return NULL; return to; } } // Anonymous namespace. namespace Anabatic { using namespace std; using Hurricane::tab; using Hurricane::_TName; using Hurricane::Error; using Hurricane::ForEachIterator; using Hurricane::Hook; using Hurricane::RoutingPad; // ------------------------------------------------------------------- // Class : "Anabatic::AutoSegmentStack". void AutoSegmentStack::push ( AutoContact* contact, AutoSegment* segment ) { cdebug_log(144,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 () { while (_hook) { _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 : "Anabatic::AutoSegments_OnRoutingPad". AutoSegments_OnRoutingPad::Locator::Locator ( RoutingPad* rp, const AutoContactTerminal* contact ) : AutoSegmentHL() , _elements ({{NULL,NULL,NULL,NULL}}) , _index (0) { if (rp) { for ( Component* component : rp->getSlaveComponents() ) { AutoSegment* segment = Session::lookup( dynamic_cast(component) ); if (not segment) continue; size_t offset = 2; if (contact and (contact->getSegment() == segment)) offset = 0; if (segment->isHorizontal()) _elements[offset ] = segment; else _elements[offset+1] = segment; } } while ( (_index < 4) and not _elements[_index] ) ++_index; } AutoSegmentHL* AutoSegments_OnRoutingPad::Locator::getClone () const { return new Locator(*this); } AutoSegment* AutoSegments_OnRoutingPad::Locator::getElement () const { return (_index < 4) ? _elements[_index] : NULL; } bool AutoSegments_OnRoutingPad::Locator::isValid () const { return (_index < 4); } void AutoSegments_OnRoutingPad::Locator::progress () { cdebug_log(145,0) << "AutoSegments_OnRoutingPad::Locator::progress()" << endl; ++_index; while ( (_index < 4) and not _elements[_index] ) ++_index; } string AutoSegments_OnRoutingPad::Locator::_getString () const { string s = "<" + _TName("AutoSegments_OnRoutingPad::Locator") + getString(_index) + ">"; return s; } AutoSegments_OnRoutingPad::AutoSegments_OnRoutingPad ( const AutoContact* contact ) : AutoSegmentHC() , _routingPad(NULL) , _contact (dynamic_cast(contact)) { if (_contact) _routingPad = dynamic_cast(_contact->getAnchor()); } AutoSegmentHC* AutoSegments_OnRoutingPad::getClone () const { return new AutoSegments_OnRoutingPad(*this); } AutoSegmentHL* AutoSegments_OnRoutingPad::getLocator () const { return new Locator(_routingPad,_contact); } string AutoSegments_OnRoutingPad::_getString () const { string s = "<" + _TName("AutoSegments_OnRoutingPad") + " " + getString(_routingPad) + ">"; return s; } // ------------------------------------------------------------------- // Class : "AutoSegments_Connecteds". AutoSegments_Connecteds::Locator::Locator ( AutoSegment* segment, Flags flags ) : AutoSegmentHL() , _stack () { cdebug_log(145,0) << "AutoSegments_Connecteds::Locator::Locator()" << endl; if (flags & Flags::Source) { AutoContact* contact = segment->getAutoSource(); if (contact) _stack.push( contact, segment ); } if (flags & Flags::Target) { AutoContact* contact = segment->getAutoTarget(); if (contact) _stack.push( contact, segment ); } } AutoSegmentHL* AutoSegments_Connecteds::Locator::getClone () const { return new Locator(*this); } bool AutoSegments_Connecteds::Locator::isValid () const { return not _stack.isEmpty(); } void AutoSegments_Connecteds::Locator::progress () { cdebug_log(145,0) << "AutoSegments_Connecteds::Locator::progress()" << endl; while (not _stack.isEmpty()) { AutoContact* sourceContact = _stack.getAutoContact (); AutoSegment* sourceSegment = _stack.getAutoSegment (); _stack.pop (); AutoContactTerminal* sourceTerminal = dynamic_cast( sourceContact ); if (sourceTerminal) { for ( AutoSegment* currentSegment : sourceTerminal->getRpConnecteds() ) { cdebug_log(145,0) << "Looking at: " << currentSegment << endl; if (currentSegment == sourceSegment) continue; AutoContact* targetContact = currentSegment->getAutoSource(); if (not targetContact->isTerminal()) _stack.push( targetContact, currentSegment ); targetContact = currentSegment->getAutoTarget(); if (not targetContact->isTerminal()) _stack.push( targetContact, currentSegment ); } } else { LocatorHelper helper (sourceContact,Flags::WithPerpands); for ( ; helper.isValid() ; helper.progress() ) { AutoSegment* currentSegment = helper.getSegment(); cdebug_log(145,0) << "Looking at: " << currentSegment << endl; if (currentSegment == sourceSegment) continue; AutoContact* targetContact = currentSegment->getOppositeAnchor( sourceContact ); if (targetContact) _stack.push( targetContact, currentSegment ); } } break; } } string AutoSegments_Connecteds::Locator::_getString () const { string s = "<" + _TName("AutoSegments_Connecteds::Locator") + ">"; return s; } AutoSegmentHC* AutoSegments_Connecteds::getClone () const { return new AutoSegments_Connecteds(*this); } AutoSegmentHL* AutoSegments_Connecteds::getLocator () const { return new Locator(_segment,_flags); } AutoSegment* AutoSegments_Connecteds::Locator::getElement () const { return _stack.getAutoSegment(); } string AutoSegments_Connecteds::_getString () const { string s = "<" + _TName("AutoSegments_Connecteds") + " " + getString(_segment) + ">"; return s; } // ------------------------------------------------------------------- // Class : "AutoSegments_Aligneds". AutoSegments_Aligneds::Locator::Locator ( AutoSegment* segment, Flags flags ) : AutoSegmentHL() , _flags (flags) , _master(segment) , _stack () { if (not _master) return; if (not _flags.intersect(Flags::Source|Flags::Target)) _flags |= Flags::Source | Flags::Target; _flags |= (_master->isHorizontal()) ? Flags::Horizontal : Flags::Vertical; if (_flags & Flags::WithDoglegs) _flags |= Flags::WithPerpands; cdebug_log(144,0) << "AutoSegments_Aligneds::Locator::Locator() _flags:" << _flags.asString(FlagsFunction) << endl; if (_flags & Flags::Source) { AutoContact* contact = segment->getAutoSource(); if (contact) _stack.push( contact, segment ); } if (_flags & Flags::Target) { AutoContact* contact = segment->getAutoTarget(); if (contact) _stack.push( contact, segment ); } if (not (_flags & Flags::WithSelf)) 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(144,0) << "AutoSegments_Aligneds::Locator::progress()" << endl; while (not _stack.isEmpty()) { AutoContact* sourceContact = _stack.getAutoContact (); AutoSegment* sourceSegment = _stack.getAutoSegment (); _stack.pop (); cdebug_log(144,1) << "Iterate over: " << sourceContact << endl; LocatorHelper helper (sourceContact, _flags); for ( ; helper.isValid() ; helper.progress() ) { AutoSegment* currentSegment = helper.getSegment(); cdebug_log(144,0) << "| " << currentSegment << endl; if (currentSegment == sourceSegment) continue; if (AutoSegment::areAligneds(currentSegment,_master)) { 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 ); } else { if (_flags & Flags::WithDoglegs) { AutoContact* targetContact = isLocalDogleg( currentSegment, sourceContact, _master ); if (targetContact) { cdebug_log(144,0) << "Stacking dogleg global. " << endl; _stack.push( targetContact, currentSegment ); continue; } } } } cdebug_tabw(144,-1); if (_stack.getAutoSegment() == _master) continue; if (not AutoSegment::areAligneds(_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, Flags flags ) : AutoSegmentHL() //, _flags (Flags::WithPerpands|Flags::WithDoglegs) , _flags (Flags::WithPerpands|flags) , _master (master) , _stack () , _perpandiculars() { cdebug_log(144,0) << "AutoSegments_Perpandiculars::Locator::Locator(): _flags:" << _flags.asString(FlagsFunction) << endl; cdebug_log(144,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(144,1) << "AutoSegments_Perpandiculars::Locator::progress()" << endl; if (not _perpandiculars.empty()) _perpandiculars.pop_back(); if (not _perpandiculars.empty()) { cdebug_tabw(144,-1); return; } while ( not _stack.isEmpty() ) { AutoContact* sourceContact = _stack.getAutoContact(); AutoSegment* sourceSegment = _stack.getAutoSegment(); _stack.pop(); cdebug_log(144,0) << "Iterate over: " << sourceContact << endl; LocatorHelper helper (sourceContact, _flags); for ( ; helper.isValid() ; helper.progress() ) { AutoSegment* currentSegment = helper.getSegment(); if (currentSegment == sourceSegment) continue; cdebug_log(144,0) << "| " << currentSegment << endl; if (AutoSegment::areAligneds(currentSegment,_master)) { AutoContact* targetContact = currentSegment->getOppositeAnchor( sourceContact ); if (targetContact) { if (_master->getLayer() != currentSegment->getLayer()) { continue; } cdebug_log(144,0) << "Stacking target. " << endl; _stack.push( targetContact, currentSegment ); // 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(144,0) << "Stacking target. " << endl; // _stack.push( targetContact, currentSegment ); // } } else { cdebug_log(144,0) << "No opposite anchor to: " << sourceContact << endl; } } else { if ( (_flags & Flags::WithDoglegs) and currentSegment->isLocal() and sourceContact->isTurn() ) { AutoContact* targetContact = currentSegment->getOppositeAnchor( sourceContact ); if (targetContact->isTurn()) { AutoSegment* targetGlobal = targetContact->getPerpandicular( currentSegment ); if (targetGlobal->isGlobal() and (_master->getLayer() == targetGlobal->getLayer())) { cdebug_log(144,0) << "Global aligned though dogleg:" << targetGlobal << endl; Interval masterConstraints; Interval targetConstraints; _master ->getConstraints( masterConstraints ); targetGlobal->getConstraints( targetConstraints ); if (targetConstraints.intersect(masterConstraints)) { cdebug_log(144,0) << "Stacking dogleg global. " << endl; _stack.push( targetContact, currentSegment ); continue; } } } } _perpandiculars.push_back( currentSegment ); } } if (_stack.isEmpty()) break; if (_stack.getAutoSegment() == _master) continue; if (not _perpandiculars.empty()) break; } cdebug_tabw(144,-1); } 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(_master,_flags); } 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(_master) + ">"; return s; } // ------------------------------------------------------------------- // Class : "AutoSegments_AnchorOnGCell". AutoSegments_AnchorOnGCell::Locator::Locator ( GCell* fcell, Flags 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, Flags 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.