coriolis/kite/src/RoutingEvent.cpp

3751 lines
136 KiB
C++

// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC/LIP6 2008-2010, All Rights Reserved
//
// ===================================================================
//
// $Id$
//
// x-----------------------------------------------------------------x
// | |
// | C O R I O L I S |
// | K i t e - D e t a i l e d R o u t e r |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@asim.lip6.fr |
// | =============================================================== |
// | C++ Module : "./RoutingEvent.cpp" |
// | *************************************************************** |
// | U p d a t e s |
// | |
// x-----------------------------------------------------------------x
#include <cstdlib>
#include <iomanip>
#include <algorithm>
#include "hurricane/Bug.h"
#include "hurricane/DebugSession.h"
#include "hurricane/Net.h"
#include "hurricane/Layer.h"
#include "katabatic/AutoContact.h"
#include "kite/DataNegociate.h"
#include "kite/TrackElement.h"
#include "kite/Track.h"
#include "kite/Tracks.h"
#include "kite/GCell.h"
#include "kite/RoutingPlane.h"
#include "kite/RoutingEvent.h"
#include "kite/RoutingEventHistory.h"
#include "kite/RoutingEventQueue.h"
#include "kite/NegociateWindow.h"
#include "kite/Session.h"
#include "kite/KiteEngine.h"
namespace {
/*! \defgroup ClassManipulator Manipulator Class
*/
//! \addtogroup ClassManipulator
//! \{
/*! \class Manipulator
* \brief Handle \TrackElement ripup &amp; topological modifications.
*
* Handles all \TrackElement modifications.
*/
/*! \function Manipulator::Manipulator ( TrackElement* segment, State& state );
* \param segment The \TrackElement to manipulate.
* \param state The \RoutingEvent state.
*/
/*! \function TrackElement* Manipulator::getSegment () const;
* \Return The working \TrackElement.
*/
/*! \function DataNegociate* Manipulator::getData () const;
* \Return The DataNegociate of the \TrackElement.
*/
/*! \function RoutingEvent* Manipulator::getEvent () const;
* \Return The \RoutingEvent associated to the \TrackElement. May be
* \NULL if it belongs to a more prioritary GCell RoutingSet.
*/
/*! \function bool Manipulator::canRipup () const;
* \return \true if the maximum ripup &amp; reset count has not been reached.
*/
/*! \function bool Manipulator::ripup ( Interval overlap, unsigned int type, DbU::Unit axisHint );
* \param overlap The Interval that should be cleared.
* \param type The type of ripup action.
* \param axisHint An indication as where to move the riped up segment.
* \return \True if the operation has succedeed.
*
* If the \TrackElement cannot be riped up (it cames from a more
* prioritary GCell RoutingSet), then it tries to relax it.
*/
/*! \function bool Manipulator::ripup ( DbU::Unit point, unsigned int type, DbU::Unit axisHint );
* \param point The point around which the \Track should be cleared.
* \param type The type of ripup action.
* \param axisHint An indication as where to move the riped up segment.
* \return \True if the operation has succedeed.
*
* \see The other ripup method.
*/
/*! \function bool Manipulator::relax ( Interval overlap );
* \param overlap The overlaping interval to free.
* \return \true if the operation has succeeded.
*
* Finds the appropriate dogleg GCells to break the \TrackElement.
* There could be one or two breaks whether the overlap is fully
* enclosed or not.
*/
/*! \function bool Manipulator::modifyTopology ();
* \return \true if the operation has succeeded.
*
* Try to changes the \TrackElement topology.
*/
/*! \function bool Manipulator::insertInTrack ( size_t i );
* \param i The index of \Track into which insert.
* \return \true if the operation has succeeded.
*
* Try to insert the \TrackElement into the \Track <i>i</i>.
* The index is relative to the State's \Track vector.
*/
/*! \function bool Manipulator::desalignate ();
* \return \true if the operation has succeeded.
*
* Try to desalignate the \TrackElement.
*/
/*! \function bool Manipulator::slacken ();
* \return \true if the operation has succeeded.
*
* Try to slacken the \TrackElement.
*/
/*! \function bool Manipulator::moveUp ();
* \return \true if the operation has succeeded.
*
* Try to move up the \TrackElement.
*/
/*! \function bool Manipulator::makeDogLeg ();
* \return \true if the operation has succeeded.
*
* Try to make a dog leg on the \TrackElement.
* This method is restricted to local \TrackElement only.
*/
/*! \function bool Manipulator::minimize ();
* \return \true if the operation has succeeded.
*
* Try to mimize the wirelength of the \TrackElement.
* This operation can only be done once.
*/
/*! \function bool Manipulator::relax ( size_t i );
* \param i The index of the selected \Track.
* \return \true if the operation has succeeded.
*
* Try to make a dog leg on the \TrackElement.
* This method is restricted to local \TrackElement only.
*/
//! \}
using namespace std;
using namespace Hurricane;
using namespace Kite;
// -------------------------------------------------------------------
// Class : "LvGCandidate".
class LvGCandidate {
public:
struct Compare : public binary_function<LvGCandidate&,LvGCandidate&,bool> {
inline bool operator() ( const LvGCandidate& lhs, const LvGCandidate& rhs ) const;
};
public:
inline LvGCandidate ( TrackElement* segment=NULL, Interval overlap=Interval(), size_t terminals=0 );
inline TrackElement* getSegment () const;
inline const Interval& getOverlap () const;
inline size_t getTerminals () const;
private:
TrackElement* _segment;
Interval _overlap;
size_t _terminals;
};
inline LvGCandidate::LvGCandidate ( TrackElement* segment, Interval overlap, size_t terminals )
: _segment (segment)
, _overlap (overlap)
, _terminals(terminals)
{ }
inline TrackElement* LvGCandidate::getSegment () const { return _segment; }
inline const Interval& LvGCandidate::getOverlap () const { return _overlap; }
inline size_t LvGCandidate::getTerminals () const { return _terminals; }
inline bool LvGCandidate::Compare::operator() ( const LvGCandidate& lhs, const LvGCandidate& rhs ) const
{
if ( lhs.getTerminals() != rhs.getTerminals() )
return lhs.getTerminals() < rhs.getTerminals();
if ( lhs.getOverlap() != rhs.getOverlap() )
return lhs.getOverlap().getSize() > rhs.getOverlap().getSize();
return lhs.getSegment()->getAxis() < rhs.getSegment()->getAxis();
}
// -------------------------------------------------------------------
// Class : "Cs1Candidate".
class Cs1Candidate {
public:
inline Cs1Candidate ( Track* track=NULL );
inline Track* getTrack () const;
inline size_t getBegin () const;
inline size_t getEnd () const;
inline size_t getLength () const;
inline Interval getConflict ( size_t );
inline void setBegin ( size_t );
inline void setEnd ( size_t );
inline void addConflict ( const Interval& );
public:
friend inline bool operator< ( const Cs1Candidate&, const Cs1Candidate& );
private:
Track* _track;
size_t _begin;
size_t _end;
vector<Interval> _conflicts;
};
inline Cs1Candidate::Cs1Candidate ( Track* track )
: _track (track)
, _begin (0)
, _end (0)
, _conflicts()
{ }
inline Track* Cs1Candidate::getTrack () const { return _track; }
inline size_t Cs1Candidate::getBegin () const { return _begin; }
inline size_t Cs1Candidate::getEnd () const { return _end; }
inline size_t Cs1Candidate::getLength () const { return _conflicts.size(); }
inline void Cs1Candidate::setBegin ( size_t i ) { _begin=i; }
inline void Cs1Candidate::setEnd ( size_t i ) { _end=i; }
inline void Cs1Candidate::addConflict ( const Interval& conflict ) { _conflicts.push_back(conflict); }
inline Interval Cs1Candidate::getConflict ( size_t i )
{
if (i >= _conflicts.size()) return Interval();
return _conflicts[i];
}
inline bool operator< ( const Cs1Candidate& lhs, const Cs1Candidate& rhs )
{ return lhs._conflicts.size() < rhs._conflicts.size(); }
// -------------------------------------------------------------------
// Class : "ShearAnalyze".
class ShearAnalyze {
public:
ShearAnalyze ( TrackElement* );
void addPerpandicular ( DbU::Unit axis, Interval constraint );
GCell* getShearGCell ();
private:
GCell* _compute ();
private:
TrackElement* _segment;
vector<GCell*> _gcells;
vector<Interval> _constraints;
GCell* _shearGCell;
bool _computed;
};
ShearAnalyze::ShearAnalyze ( TrackElement* segment )
: _segment (segment)
, _gcells ()
, _constraints()
, _shearGCell (NULL)
, _computed (false)
{
segment->getGCells ( _gcells );
for ( size_t igcell=0 ; igcell<_gcells.size() ; igcell++ ) {
_constraints.push_back ( Interval() );
}
}
GCell* ShearAnalyze::getShearGCell ()
{
if ( not _computed ) _compute ();
return _shearGCell;
}
void ShearAnalyze::addPerpandicular ( DbU::Unit axis, Interval constraint )
{
Interval uside;
for ( size_t igcell=0 ; igcell<_gcells.size() ; igcell++ ) {
uside = _gcells[igcell]->getUSide(_segment->getDirection(),true);
if ( uside.contains(axis) ) {
_constraints[igcell].merge ( constraint );
}
}
}
GCell* ShearAnalyze::_compute ()
{
_shearGCell = NULL;
Interval trunk ( false );
for ( size_t igcell=0 ; igcell<_gcells.size() ; igcell++ ) {
if ( not _constraints[igcell].isEmpty() ) {
trunk.intersection ( _constraints[igcell] );
}
}
// Ugly: explicit pitch.
trunk.inflate ( DbU::lambda(5.0) );
// 0: intialisation, 1: left constrained, 2: right constrained.
unsigned int previousConstraint = 0;
size_t ishearBegin = 0;
size_t ishearEnd = 0;
for ( size_t igcell=0 ; igcell<_gcells.size() ; igcell++ ) {
if ( _constraints[igcell].isEmpty() ) continue;
bool leftConstrained = (_constraints[igcell].getVMin() >= trunk.getVMin());
bool rightConstrained = (_constraints[igcell].getVMax() <= trunk.getVMax());
if ( not leftConstrained and not rightConstrained ) continue;
if ( leftConstrained and rightConstrained ) {
ishearBegin = ishearEnd = 0;
break;
}
if ( not previousConstraint ) {
previousConstraint = (leftConstrained) ? 1 : 2;
continue;
}
if ( leftConstrained xor (previousConstraint == 1) ) {
if ( not ishearBegin ) {
ishearBegin = igcell;
continue;
}
ishearBegin = ishearEnd = 0;
break;
}
}
if ( ishearBegin ) {
if ( _constraints[ishearBegin-1].isEmpty() ) {
_shearGCell = _gcells[ishearBegin-1];
}
}
return _shearGCell;
}
// -------------------------------------------------------------------
// Class : "UnionItervals".
class UnionIntervals {
public:
inline UnionIntervals ();
void addInterval ( Interval& );
inline size_t size () const;
inline bool empty () const;
inline list<Interval>::const_iterator begin () const;
inline list<Interval>::const_iterator end () const;
inline DbU::Unit getVMin () const;
inline DbU::Unit getVMax () const;
string _getString ();
private:
list<Interval> _intervals;
};
inline UnionIntervals::UnionIntervals () : _intervals() { }
inline list<Interval>::const_iterator UnionIntervals::begin () const { return _intervals.begin(); }
inline list<Interval>::const_iterator UnionIntervals::end () const { return _intervals.end(); }
inline size_t UnionIntervals::size () const { return _intervals.size(); }
inline bool UnionIntervals::empty () const { return _intervals.empty(); }
inline DbU::Unit UnionIntervals::getVMin () const { return (empty()) ? DbU::Max : (*begin()).getVMin(); }
inline DbU::Unit UnionIntervals::getVMax () const { return (empty()) ? DbU::Min : (*begin()).getVMax(); }
void UnionIntervals::addInterval ( Interval& interval )
{
ltrace(200) << "UnionInterval::addInterval() - " << interval << endl;
list<Interval>::iterator iintv = _intervals.begin ();
bool merged = false;
while ( iintv != _intervals.end() ) {
if ( !merged ) {
if ( interval.getVMax() < (*iintv).getVMin() ) { _intervals.insert ( iintv, interval ); return; }
if ( interval.getVMin() > (*iintv).getVMax() ) { iintv++; continue; }
merged = true;
interval = (*iintv).merge ( interval );
iintv++;
} else {
if ( (*iintv).intersect ( interval ) ) {
interval = (*iintv).merge ( interval );
iintv = _intervals.erase ( iintv );
continue;
} else
break;
}
}
if ( !merged ) _intervals.push_back ( interval );
}
string UnionIntervals::_getString ()
{
ostringstream s;
list<Interval>::iterator iintv = _intervals.begin();
for ( ; iintv != _intervals.end() ; iintv++ ) {
s << " [" << DbU::getValueString((*iintv).getVMin())
<< ":" << DbU::getValueString((*iintv).getVMax()) << "]";
}
return s.str();
}
// -------------------------------------------------------------------
// Class : "RipupHistory".
class RipupHistory {
public:
RipupHistory ( RoutingEvent* );
inline bool isDislodger ( RoutingEvent* ) const;
inline size_t size () const;
inline size_t getDislodgersCount () const;
void addAxis ( DbU::Unit );
void addAxis ( RoutingEvent* );
bool hasAxis ( DbU::Unit ) const;
UnionIntervals* getUnionIntervals ( DbU::Unit );
void addDislodger ( RoutingEvent* );
void addDislodger ( TrackElement* );
void print ( ostream& );
private:
RoutingEvent* _masterEvent;
map<DbU::Unit,UnionIntervals> _dislodgers;
size_t _dislodgersCount;
};
RipupHistory::RipupHistory ( RoutingEvent* event )
: _masterEvent(event)
, _dislodgers()
, _dislodgersCount(0)
{
const Interval& perpandicular = _masterEvent->getPerpandicular();
RoutingPlane* plane = Session::getKiteEngine()->getRoutingPlaneByLayer(_masterEvent->getSegment()->getLayer());
Track* track;
if ( !perpandicular.isEmpty() ) {
track = plane->getTrackByPosition(perpandicular.getVMin());
if ( track && (track->getAxis() < perpandicular.getVMin()) ) track = track->getNext();
for ( ; track && (track->getAxis() <= perpandicular.getVMax())
; track = track->getNext() )
addAxis ( track->getAxis() );
}
track = plane->getTrackByPosition(_masterEvent->getSegment()->getAxis());
if ( track ) {
size_t begin;
size_t end;
Interval interval = _masterEvent->getSegment()->getCanonicalInterval();
track->getOverlapBounds ( interval, begin, end );
if ( begin != Track::NPOS ) {
for ( ; begin < end ; begin++ ) {
TrackElement* other = track->getSegment(begin);
if ( other->getNet() == _masterEvent->getSegment()->getNet() ) continue;
if ( !interval.intersect(other->getCanonicalInterval()) ) continue;
addDislodger ( other );
}
}
}
}
inline bool RipupHistory::isDislodger ( RoutingEvent* event ) const { return hasAxis(event->getSegment()->getAxis()); }
inline size_t RipupHistory::size () const { return _dislodgers.size(); }
inline size_t RipupHistory::getDislodgersCount () const { return _dislodgersCount; }
void RipupHistory::addAxis ( DbU::Unit axis )
{
if ( hasAxis(axis) ) return;
_dislodgers.insert ( make_pair(axis,UnionIntervals()) );
}
void RipupHistory::addAxis ( RoutingEvent* event )
{
addAxis ( event->getAxisHistory() );
}
bool RipupHistory::hasAxis ( DbU::Unit axis ) const
{
return _dislodgers.find(axis) != _dislodgers.end();
}
UnionIntervals* RipupHistory::getUnionIntervals ( DbU::Unit axis )
{
map<DbU::Unit,UnionIntervals>::iterator iunion = _dislodgers.find ( axis );
if ( iunion == _dislodgers.end() ) return NULL;
return &(iunion->second);
}
void RipupHistory::addDislodger ( RoutingEvent* event )
{
if ( event->getSegment() == _masterEvent->getSegment() ) return;
if ( event->getSegment()->getLayer() != _masterEvent->getSegment()->getLayer() ) return;
UnionIntervals* intervals = getUnionIntervals ( event->getAxisHistory() );
if ( !intervals ) return;
Interval canonical = event->getSegment()->getCanonicalInterval();
intervals->addInterval ( canonical );
_dislodgersCount++;
}
void RipupHistory::addDislodger ( TrackElement* segment )
{
if ( _masterEvent->getSegment()->getNet() == segment->getNet() ) return;
UnionIntervals* intervals = getUnionIntervals ( segment->getAxis() );
if ( !intervals ) return;
Interval canonical = segment->getCanonicalInterval();
intervals->addInterval ( canonical );
_dislodgersCount++;
}
void RipupHistory::print ( ostream& o )
{
o << "[HISTORY] " << _masterEvent << endl;
map<DbU::Unit,UnionIntervals>::iterator iunion = _dislodgers.begin();
for ( ; iunion != _dislodgers.end() ; iunion++ )
o << " @" << DbU::getValueString(iunion->first)
<< " " << (iunion->second)._getString() << endl;
}
// -------------------------------------------------------------------
// Class : "::SegmentAction".
class SegmentAction {
public:
enum Type { Self = (1<< 0)
, Other = (1<< 1)
, Ripup = (1<< 2)
, Insert = (1<< 3)
, ResetRipup = (1<< 4)
, AxisHint = (1<< 5)
, Perpandicular = (1<< 6)
, EventLevel1 = (1<< 7)
, EventLevel2 = (1<< 8)
, EventLevel3 = (1<< 9)
, EventLevel4 = (1<<10)
, EventLevel5 = (1<<11)
, PackingMode = (1<<12)
, ToState = (1<<13)
, ToRipupLimit = (1<<14)
, SelfInsert = Self |Insert
, SelfRipup = Self |Ripup
, SelfRipupPerpand = Self |Ripup | Perpandicular
, SelfRipupAndReset = Self |Ripup | Perpandicular
, SelfShrinkPerpand = Self |Ripup | Perpandicular|EventLevel4
, SelfRipupAndAxisHint = Self |Ripup | Perpandicular|EventLevel4| AxisHint
, OtherRipup = Other|Ripup
, OtherPushAside = Other|Ripup | Perpandicular|EventLevel3
, OtherPacking = Other|Ripup | Perpandicular|PackingMode
};
public:
SegmentAction ( TrackElement*
, unsigned int type
, DbU::Unit axisHint=0
, unsigned int toState =0
);
inline TrackElement* getSegment () const;
inline unsigned int getType () const;
inline void setAxisHint ( DbU::Unit );
inline unsigned int setFlag ( unsigned int );
bool doAction ( RoutingEventQueue& );
private:
TrackElement* _segment;
unsigned int _type;
DbU::Unit _axisHint;
unsigned int _toState;
};
inline TrackElement* SegmentAction::getSegment () const { return _segment; }
inline unsigned int SegmentAction::getType () const { return _type; }
inline void SegmentAction::setAxisHint ( DbU::Unit axis ) { _axisHint = axis; }
inline unsigned int SegmentAction::setFlag ( unsigned int flag ) { _type |= flag; return _type; }
SegmentAction::SegmentAction ( TrackElement* segment
, unsigned int type
, DbU::Unit axisHint
, unsigned int toState
)
: _segment (segment)
, _type (type)
, _axisHint(axisHint)
, _toState (toState)
{ }
bool SegmentAction::doAction ( RoutingEventQueue& queue )
{
// Note:
// "_immediate" ripup flags was associated with "perpandicular", as they
// must be re-inserted *before* any parallel. Must look to solve the redundancy.
if ( _type & Perpandicular ) {
ltrace(200) << "* Riping Pp " << _segment << endl;
} else {
ltrace(200) << "* Riping // " << _segment << endl;
}
if ( _segment->isFixed() ) return true;
DataNegociate* data = _segment->getDataNegociate();
if ( data == NULL ) return true;
if ( _type & ResetRipup ) data->resetRipupCount ();
if ( _type & ToState ) {
data->setState ( _toState );
data->setRipupCount ( Session::getKiteEngine()->getRipupLimit(_segment) );
}
if ( data->getGCellOrder() == Session::getOrder() ) {
// Current order, default behavior: ripup.
if ( _segment->getTrack() )
Session::addRemoveEvent ( _segment );
} else if ( data->getGCellOrder() < Session::getOrder() ) {
// Order is lower: no longer able to displace it.
return false;
} else {
// Order is greater, do not route now. Ripup if needed.
if ( _segment->getTrack() )
Session::addRemoveEvent ( _segment );
return true;
}
RoutingEvent* event = data->getRoutingEvent();
if ( event == NULL ) {
if ( data->getGCellOrder() == Session::getOrder() ) {
cerr << Bug("Missing Event on %p:%s"
,_segment->base()->base(),getString(_segment).c_str()) << endl;
}
ltrace(200) << "Not in current GCellRoutingSet, cancelled." << endl;
return true;
}
if ( (_type & AxisHint) /*and not _segment->isSlackenDogLeg()*/ ) {
ltrace(200) << "Setting Axis Hint: @" << DbU::getValueString(_axisHint) << endl;
event->setAxisHint ( _axisHint );
}
if ( _type & ToRipupLimit ) {
unsigned int limit = Session::getKiteEngine()->getRipupLimit(_segment);
if ( limit > data->getRipupCount() )
data->setRipupCount ( limit );
}
unsigned int eventLevel = 0;
if ( _type & EventLevel1 ) eventLevel = 1;
if ( _type & EventLevel2 ) eventLevel = 2;
if ( _type & EventLevel3 ) eventLevel = 3;
if ( _type & EventLevel4 ) eventLevel = 4;
if ( _type & EventLevel5 ) eventLevel = 5;
RoutingEvent* fork = event->reschedule ( queue, eventLevel );
if ( fork )
fork->setMode ( (_type&PackingMode) ? RoutingEvent::Pack : RoutingEvent::Negociate );
return true;
}
// -------------------------------------------------------------------
// Class Declaration : "::State".
class State {
public:
enum StateValues { MissingData = (1<<0)
, EmptyTrackList = (1<<1)
, Inserted = (1<<2)
, Self = (1<<3)
, Other = (1<<4)
, Ripup = (1<<5)
, MaximumRipup = (1<<6)
, TopologyModificated = (1<<7)
, SelfInserted = Self | Inserted
, SelfMaximumRipup = Self | MaximumRipup
, OtherRipup = Other | Ripup
, OtherTopologyModificated = Other | TopologyModificated
, SelfTopologyModificated = Self | TopologyModificated
};
enum SlackenFlags { NoRecursive = (1<<0)
, NoTransition = (1<<1)
};
public:
State ( RoutingEvent*
, RoutingEventQueue&
, RoutingEventHistory&
);
inline RoutingEvent* getEvent ();
inline RoutingEventQueue& getQueue ();
inline RoutingEventHistory& getHistory ();
inline unsigned int getState ();
inline DataNegociate* getData ();
inline Interval& getConstraint ();
inline Interval& getOptimal ();
inline vector<TrackCost>& getCosts ();
inline TrackCost& getCost ( size_t );
inline Track* getTrack ( size_t );
inline size_t getBegin ( size_t );
inline size_t getEnd ( size_t );
inline void setState ( unsigned int );
inline void addAction ( TrackElement*
, unsigned int type
, DbU::Unit axisHint=0
, unsigned int toState =0
);
inline vector<SegmentAction>& getActions ();
bool doActions ();
inline void clearActions ();
bool insertInTrack ( size_t );
bool conflictSolve1 ();
bool conflictSolve2 ();
bool localVsGlobal ();
bool slackenTopology ( TrackElement*, unsigned int flags=0 );
private:
RoutingEvent* _event;
RoutingEventQueue& _queue;
RoutingEventHistory& _history;
unsigned int _state;
DataNegociate* _data;
Interval _constraint;
Interval _optimal;
vector<TrackCost> _costs;
vector<SegmentAction> _actions;
};
// -------------------------------------------------------------------
// Class Declaration : "::Manipulator".
class Manipulator {
public:
enum { ToRipupLimit=1, AllowExpand =2, NoExpand=4, PerpandicularsFirst=8, ToMoveUp=16 };
enum { LeftAxisHint=1, RightAxisHint=2 };
enum { NoRingLimit=1 };
public:
Manipulator ( TrackElement*, State& );
~Manipulator ();
inline TrackElement* getSegment () const;
inline DataNegociate* getData () const;
inline RoutingEvent* getEvent () const;
bool canRipup ( unsigned int flags=0 ) const;
bool isCaged ( DbU::Unit ) const;
bool ripup ( Interval overlap
, unsigned int type
, DbU::Unit axisHint=0
, unsigned int toState =0
);
bool ripup ( DbU::Unit point
, unsigned int type
, DbU::Unit axisHint=0
);
bool ripupPerpandiculars ( unsigned int flags=0 );
bool ripple ();
bool goOutsideGCell ();
bool minimize ();
bool desalignate ();
bool slacken ();
bool pivotUp ();
bool moveUp ();
bool makeDogLeg ();
bool makeDogLeg ( DbU::Unit );
bool makeDogLeg ( Interval );
bool relax ( Interval, unsigned int flags=AllowExpand );
bool relax ( size_t );
bool insertInTrack ( size_t );
bool shrinkToTrack ( size_t
, unsigned int flags=0
, DbU::Unit leftAxisHint=0
, DbU::Unit rightAxisHint=0
);
bool forceToTrack ( size_t );
void reprocessPerpandiculars ();
private:
TrackElement* _segment;
DataNegociate* _data;
RoutingEvent* _event;
State& _S;
};
// -------------------------------------------------------------------
// Class Definition : "::State".
State::State ( RoutingEvent* event, RoutingEventQueue& queue, RoutingEventHistory& history )
: _event (event)
, _queue (queue)
, _history (history)
, _state (0)
, _data (NULL)
, _constraint ()
, _optimal ()
, _costs ()
, _actions ()
{
TrackElement* segment = _event->getSegment();
_event->setTracksFree ( 0 );
_data = segment->getDataNegociate();
if ( !_data ) {
_state = MissingData;
return;
}
#if defined(CHECK_DETERMINISM)
cerr << "Order: " << _data->getGCellOrder() << " - " << _data->getCost() << endl;
#endif
_data->update ();
_event->invalidate ( true ); // Optimizable.
_event->revalidate ( true );
_constraint = _event->getConstraints();
_optimal = _event->getOptimal();
const Interval& perpandicular = _event->getPerpandicular ();
ltrace(148) << "Katabatic intervals:" << endl;
ltrace(148) << "* Optimal: " << _optimal << endl;
ltrace(148) << "* Constraints: " << _constraint << endl;
ltrace(148) << "* Perpandicular: " << perpandicular << endl;
ltrace(148) << "* OptimalAxis: " << _event->getOptimalAxis() << endl;
ltrace(148) << "* AxisHint: " << DbU::getValueString(_event->getAxisHint()) << endl;
if ( _event->getTracksNb() ) {
if ( _constraint.getIntersection(perpandicular).isEmpty() ) {
ltrace(200) << "Perpandicular free is too tight." << endl;
_state = EmptyTrackList;
} else
_constraint.intersection ( perpandicular );
} else {
ltrace(200) << "No Track in perpandicular free." << endl;
_state = EmptyTrackList;
}
if ( _state == EmptyTrackList ) return;
ltrace(148) << "Negociate intervals:" << endl;
ltrace(148) << "* Optimal: " << _optimal << endl;
ltrace(148) << "* Constraints: " << _constraint << endl;
ltracein(148);
bool inLocalDepth = (Session::getRoutingGauge()->getLayerDepth(segment->getLayer()) < 3);
RoutingPlane* plane = Session::getKiteEngine()->getRoutingPlaneByLayer(segment->getLayer());
forEach ( Track*, itrack, Tracks_Range::get(plane,_constraint)) {
_costs.push_back ( itrack->getOverlapCost(segment) );
_costs.back().setAxisWeight ( _event->getAxisWeight(itrack->getAxis()) );
_costs.back().incDeltaPerpand ( _data->getCost().getWiringDelta(itrack->getAxis()) );
if ( inLocalDepth and (_costs.back().getDataState() == DataNegociate::MaximumSlack) )
_costs.back().setInfinite ();
_costs.back().consolidate ();
ltrace(149) << "| " << (*itrack) << " - " << _costs.back() << endl;
}
ltraceout(148);
if ( _data->isBorder() and (_costs.size() == 1) and _costs[0].isInfinite() ) {
Interval span;
if ( _data->isLeftBorder() ) {
span = Interval ( segment->getCanonicalInterval().getVMin()
, segment->getCanonicalInterval().getVMin()+DbU::lambda(5.0) );
} else {
span = Interval ( segment->getCanonicalInterval().getVMax()-DbU::lambda(5.0)
, segment->getCanonicalInterval().getVMax() );
}
Track* track = _costs[0].getTrack();
_costs[0] = track->getOverlapCost ( span, segment->getNet() );
_costs[0].setAxisWeight ( _event->getAxisWeight(track->getAxis()) );
_costs[0].incDeltaPerpand ( _data->getCost().getWiringDelta(track->getAxis()) );
if ( segment->isGlobal() and (_costs[0].getDataState() == DataNegociate::MaximumSlack) )
_costs[0].setInfinite ();
_costs[0].consolidate ();
ltrace(200) << "Replace: " << _costs[0] << endl;
}
if ( _costs.empty() ) {
Track* nearest = plane->getTrackByPosition(_constraint.getCenter());
if ( (nearest->getAxis() < _constraint.getVMin())
|| (nearest->getAxis() > _constraint.getVMax()) ) {
//setUnimplemented ();
//cerr << "[UNIMPLEMENTED] " << segment << " no Track in constraint interval "
// << _constraint << " " << "." << endl;
} else {
cerr << Bug(" %s Track_Range() failed to find Tracks in %s (they exists)."
,getString(segment).c_str()
,getString(_constraint).c_str()
) << endl;
}
_state = EmptyTrackList;
}
sort ( _costs.begin(), _costs.end() );
size_t i=0;
for ( ; (i<_costs.size()) and _costs[i].isFree() ; i++ );
_event->setTracksFree ( i );
}
inline RoutingEvent* State::getEvent () { return _event; }
inline RoutingEventQueue& State::getQueue () { return _queue; }
inline RoutingEventHistory& State::getHistory () { return _history; }
inline unsigned int State::getState () { return _state; }
inline DataNegociate* State::getData () { return _data; }
inline Interval& State::getConstraint () { return _constraint; }
inline Interval& State::getOptimal () { return _optimal; }
inline vector<TrackCost>& State::getCosts () { return _costs; }
inline TrackCost& State::getCost ( size_t i ) { return _costs[i]; }
inline Track* State::getTrack ( size_t i ) { return _costs[i].getTrack(); }
inline size_t State::getBegin ( size_t i ) { return _costs[i].getBegin(); }
inline size_t State::getEnd ( size_t i ) { return _costs[i].getEnd(); }
inline vector<SegmentAction>& State::getActions () { return _actions; }
inline void State::setState ( unsigned int state ) { _state = state; }
inline void State::clearActions () { _actions.clear(); }
void State::addAction ( TrackElement* segment
, unsigned int type
, DbU::Unit axisHint
, unsigned int toState )
{
if ( not segment->isFixed() ) {
_actions.push_back ( SegmentAction(segment,type,axisHint,toState) );
ltrace(200) << "State::addAction(): " << segment << endl;
}
}
bool State::doActions ()
{
ltrace(200) << "State::doActions() - " << _actions.size() << endl;
bool ripupOthersParallel = false;
for ( size_t i=0 ; i<_actions.size() ; i++ ) {
if ( _actions[i].getType() & SegmentAction::OtherRipup ) {
ripupOthersParallel = true;
}
}
for ( size_t i=0 ; i<_actions.size() ; i++ ) {
if ( (_actions[i].getType() & SegmentAction::SelfInsert) and ripupOthersParallel )
_actions[i].setFlag ( SegmentAction::EventLevel3 );
if ( not _actions[i].doAction(_queue) ) {
cinfo << "[INFO] Failed action on " << _actions[i].getSegment() << endl;
}
}
_actions.clear ();
return true;
}
bool State::insertInTrack ( size_t i )
{
ltrace(200) << "State::insertInTrack() istate:" << _event->getInsertState()
<< " track:" << i << endl;
_event->incInsertState();
switch ( _event->getInsertState() ) {
case 1:
if ( Manipulator(_event->getSegment(),*this).insertInTrack(i) ) return true;
_event->incInsertState();
case 2:
if ( Manipulator(_event->getSegment(),*this).shrinkToTrack(i) ) return true;
_event->incInsertState();
case 3:
if ( Manipulator(_event->getSegment(),*this).forceToTrack(i) ) return true;
_event->incInsertState();
}
return false;
}
bool State::conflictSolve2 ()
{
bool success = false;
RipupHistory ripupHistory ( _event );
RoutingEvent* event;
TrackElement* segment = _event->getSegment();
ltrace(200) << "State::conflictSolve2()" << endl;
size_t maxDepth = min ( getHistory().size(), (size_t)300 );
size_t depth = 0;
while ( (ripupHistory.getDislodgersCount() < 3) and (depth < maxDepth) ) {
event = getHistory().getRNth(depth++);
if ( !event ) continue;
if ( (event->getSegment() != segment) and ripupHistory.isDislodger(event) )
ripupHistory.addDislodger ( event );
}
//ripupHistory.print ( cout );
UnionIntervals* intervals = ripupHistory.getUnionIntervals ( segment->getAxis() );
if ( intervals && !intervals->empty() ) {
DbU::Unit minConflict = intervals->getVMin();
DbU::Unit maxConflict = intervals->getVMax();
Interval canonical = segment->getCanonicalInterval();
bool sourceDogLeg = canonical.contains(minConflict);
bool targetDogLeg = canonical.contains(maxConflict);
if ( sourceDogLeg || targetDogLeg ) {
Point breakPoint;
if ( segment->isHorizontal() )
breakPoint = Point ( (sourceDogLeg)?minConflict:maxConflict ,segment->getAxis() );
else
breakPoint = Point ( segment->getAxis(), (sourceDogLeg)?minConflict:maxConflict );
GCell* dogLegGCell = Session::getGCellUnder ( breakPoint.getX(), breakPoint.getY() );
if ( dogLegGCell ) {
if ( segment->canDogLegAt(dogLegGCell) ) {
if ( segment->makeDogLeg(dogLegGCell) )
success = true;
}
} else {
cerr << Bug("No GCell under %s.",getString(breakPoint).c_str()) << endl;
}
if ( !success ) {
if ( segment->isHorizontal() )
breakPoint = Point ( (targetDogLeg)?maxConflict:minConflict ,segment->getAxis() );
else
breakPoint = Point ( segment->getAxis(), (targetDogLeg)?maxConflict:minConflict );
GCell* dogLegGCell = Session::getGCellUnder ( breakPoint.getX(), breakPoint.getY() );
if ( dogLegGCell ) {
if ( segment->canDogLegAt(dogLegGCell) ) {
if ( segment->makeDogLeg(dogLegGCell) )
success = true;
}
} else {
cerr << Bug("No GCell under %s.",getString(breakPoint).c_str()) << endl;
}
}
}
} else {
ltrace(200) << "No disloggers found @" << DbU::getValueString(segment->getAxis()) << endl;
Interval freeSpan = Session::getKiteEngine()->
getTrackByPosition(segment->getLayer(),segment->getAxis())->
getFreeInterval(segment->getSourceU(),segment->getNet());
if ( freeSpan.contains(segment->getCanonicalInterval()) ) {
ltrace(200) << "Disloggers vanished, Segment can be re-inserted." << endl;
success = true;
}
}
return success;
}
bool State::conflictSolve1 ()
{
bool success = false;
Interval constraints;
vector<Cs1Candidate> candidates;
TrackElement* segment = _event->getSegment();
bool canMoveUp = (segment->isLocal()) ? segment->canPivotUp(0.5) : segment->canMoveUp(0.5);
unsigned int relaxFlags
= (_data and (_data->getStateCount() < 2)) ? Manipulator::AllowExpand : Manipulator::NoExpand;
ltrace(200) << "State::conflictSolve1()" << endl;
ltrace(200) << "| Candidates Tracks: " << endl;
segment->base()->getConstraints ( constraints );
Interval overlap = segment->getCanonicalInterval();
RoutingPlane* plane = Session::getKiteEngine()->getRoutingPlaneByLayer(segment->getLayer());
Track* track = plane->getTrackByPosition(constraints.getVMin(),Constant::Superior);
for ( ; track->getAxis() <= constraints.getVMax() ; track = track->getNext() ) {
ltrace(200) << "* " << track << endl;
candidates.push_back ( Cs1Candidate(track) );
size_t begin;
size_t end;
TrackElement* other;
Net* otherNet = NULL;
Interval otherOverlap;
track->getOverlapBounds ( overlap, begin, end );
candidates.back().setBegin ( begin );
candidates.back().setEnd ( end );
for ( ; (begin < end) ; begin++ ) {
other = track->getSegment(begin);
if ( other->getNet() == segment->getNet() ) continue;
if ( !other->getCanonicalInterval().intersect(overlap) ) continue;
ltrace(200) << " | Conflict: " << begin << " " << other << endl;
if ( otherNet != other->getNet() ) {
if ( otherNet != NULL ) {
candidates.back().addConflict ( otherOverlap );
}
otherNet = other->getNet();
otherOverlap = other->getCanonicalInterval();
} else {
otherOverlap.merge(other->getCanonicalInterval());
}
}
if ( not otherOverlap.isEmpty() )
candidates.back().addConflict ( otherOverlap );
}
sort ( candidates.begin(), candidates.end() );
for ( size_t icandidate=0 ; icandidate<candidates.size() ; icandidate++ ) {
ltrace(200) << "Trying l:" << candidates[icandidate].getLength()
<< " " << candidates[icandidate].getTrack() << endl;
if ( candidates[icandidate].getLength() > 2 ) break;
Interval overlap0 = candidates[icandidate].getConflict(0);
if ( candidates[icandidate].getLength() == 1 ) {
Track* track = candidates[icandidate].getTrack();
TrackElement* other = track->getSegment(candidates[icandidate].getBegin());
if ( other->isGlobal()
and (other->getDataNegociate()->getGCellOrder() == Session::getOrder())
and other->canMoveUp(0.5) ) {
ltrace(200) << "conflictSolve1() - One conflict, other move up" << endl;
if ( (success = other->moveUp()) ) break;
}
ltrace(200) << "conflictSolve1() - One conflict, relaxing self" << endl;
if ( Manipulator(segment,*this).relax(overlap0,relaxFlags) ) {
success = true;
break;
} else {
if ( not canMoveUp
and (relaxFlags != Manipulator::NoExpand)
and Manipulator(segment,*this).relax(overlap0,Manipulator::NoExpand) ) {
ltrace(200) << "Cannot move up but successful narrow breaking." << endl;
success = true;
break;
}
}
}
if ( candidates[icandidate].getLength() == 2 ) {
ltrace(200) << "conflictSolve1() - Two conflict, relaxing self" << endl;
Interval overlap1 = candidates[icandidate].getConflict(1);
// Ugly: hard-coded half GCell side.
if ( overlap1.getVMin() - overlap0.getVMax() < DbU::lambda(5.0) ) {
ltrace(200) << "conflictSolve1() - Too narrow spacing: "
<< DbU::getValueString(overlap1.getVMin() - overlap0.getVMax()) << endl;
continue;
}
if ( Manipulator(segment,*this).relax(overlap0,relaxFlags) ) {
success = true;
break;
} else {
if ( not canMoveUp
and (relaxFlags != Manipulator::NoExpand)
and Manipulator(segment,*this).relax(overlap0,Manipulator::NoExpand) ) {
ltrace(200) << "Cannot move up but successful narrow breaking." << endl;
success = true;
break;
}
}
}
}
//if ( track && (track->getAxis() < constraints.getVMin()) ) track = track->getNext();
//for ( ; !success && track && (track->getAxis() <= constraints.getVMax()) ; track = track->getNext() )
if ( not success and (segment->getLength() >= Session::getConfiguration()->getGlobalThreshold()) ) {
ltrace(200) << "Long global wire, break in the middle." << endl;
Interval span;
segment->getCanonical ( span );
success = Manipulator(segment,*this).makeDogLeg ( span.getCenter() );
}
if ( not success and segment->isGlobal() and (_costs.size() <= 1) ) {
ltrace(200) << "Overconstrained perpandiculars, rip them up. On track:" << endl;
ltrace(200) << " " << track << endl;
Manipulator(segment,*this).ripupPerpandiculars ();
success = true;
}
return success;
}
bool State::localVsGlobal ()
{
ltrace(200) << "State::localVsGlobal()" << endl;
ltracein(200);
bool success = false;
Interval constraint = _event->getConstraints();
TrackElement* segment = _event->getSegment();
Interval overlap = segment->getCanonicalInterval();
vector<LvGCandidate> candidates;
//Interval uside = segment->getGCell()->getUSide(segment->getDirection(),true);
Interval uside = overlap;
// Ugly: Hard-wired pitch usage.
uside.inflate ( DbU::lambda(10.0) );
ltrace(200) << "uside: " << uside << endl;
RoutingPlane* plane = Session::getKiteEngine()->getRoutingPlaneByLayer(segment->getLayer());
forEach ( Track*, itrack, Tracks_Range::get(plane,constraint)) {
ltrace(200) << "| " << (*itrack) << " - " << endl;
size_t begin;
size_t end;
TrackElement* candidate = NULL;
Net* otherNet = NULL;
Interval otherOverlap;
unsigned int weight = 0;
size_t terminals = 0;
itrack->getOverlapBounds ( overlap, begin, end );
for ( ; (begin < end) ; begin++ ) {
TrackElement* other = itrack->getSegment(begin);
if ( other->getNet() == segment->getNet() ) continue;
if ( not other->getCanonicalInterval().intersect(overlap) ) continue;
if ( not other->isGlobal() ) { candidate = NULL; break; }
ltrace(200) << "| Conflict: " << begin << " " << other << endl;
if ( otherNet == NULL ) {
otherNet = other->getNet();
otherOverlap = other->getCanonicalInterval();
candidate = other;
itrack->getTerminalWeight ( uside, otherNet, terminals, weight );
// if ( (other->base()->getAutoSource()->getAnchor() != NULL)
// and (overlap.contains(otherOverlap.getVMin())) )
// ++terminals;
// if ( (other->base()->getAutoTarget()->getAnchor() != NULL)
// and (overlap.contains(otherOverlap.getVMax())) )
// ++terminals;
ltrace(200) << "> Candidate " << candidate << endl;
} else {
if ( other->getNet() == otherNet ) {
Interval otherCanonical = other->getCanonicalInterval();
if ( otherOverlap.intersect(otherCanonical) ) {
otherOverlap.merge(otherCanonical);
// if ( (other->base()->getAutoSource()->getAnchor() != NULL)
// and (overlap.contains(otherCanonical.getVMin())) )
// ++terminals;
// if ( (other->base()->getAutoTarget()->getAnchor() != NULL)
// and (overlap.contains(otherCanonical.getVMax())) )
// ++terminals;
continue;
}
} else {
ltrace(200) << "> Reject candidate " << candidate << endl;
candidate = NULL;
break;
}
}
}
if ( candidate ) {
ltrace(200) << "> Accept candidate " << candidate << endl;
candidates.push_back ( LvGCandidate(candidate,otherOverlap,terminals) );
}
}
if ( candidates.empty() ) {
ltraceout(200);
return false;
}
sort ( candidates.begin(), candidates.end(), LvGCandidate::Compare() );
for ( size_t i=0 ; i<candidates.size() ; ++i ) {
ltrace(200) << i << "| " << DbU::getValueString(candidates[i].getOverlap().getSize())
<< "+" << candidates[i].getTerminals()
<< " " << candidates[i].getSegment() << endl;
}
for ( size_t i=0 ; (not success) and (i<candidates.size()) ; ++i ) {
if ( Manipulator(candidates[i].getSegment(),*this).ripup
(overlap,SegmentAction::OtherRipup/*|SegmentAction::ToState
,DataNegociate::MoveUp*/) ) {
ltrace(200) << "localVsGlobal() - Successful relaxing of Other Global" << endl;
success = true;
}
}
ltraceout(200);
return success;
}
bool State::slackenTopology ( TrackElement* segment, unsigned int flags )
{
DebugSession::open ( segment->getNet(), 200 );
bool success = false;
bool blocked = false;
bool repush = true;
DataNegociate* data = segment->getDataNegociate ();
unsigned int nextState = data->getState();
unsigned int actionFlags = SegmentAction::SelfInsert|SegmentAction::EventLevel5;
ltrace(200) << "Slacken Topology for " << segment->getNet()
<< " " << segment << endl;
ltracein(200);
if ( (not segment) or (not data) ) { ltraceout(200); DebugSession::close(); return false; }
if ( segment == _event->getSegment() ) _event->resetInsertState();
if ( not (data->isBorder() or data->isRing()) ) {
data->resetRipupCount ();
} else {
if ( not Manipulator(segment,*this).canRipup(Manipulator::NoRingLimit) ) {
cerr << "[UNSOLVED] " << segment << " slacken topology not allowed for border/ring." << endl;
ltraceout(200);
DebugSession::close ();
return false;
}
}
// Ring cases.
if ( data->isBorder() ) {
ltrace(200) << "Segment is Ripup only (border), bypass to Unimplemented." << endl;
if ( not Manipulator(segment,*this).canRipup (Manipulator::NoRingLimit) ) {
ltrace(200) << "Cannot ripup, bypass to Unimplemented." << endl;
data->setState ( DataNegociate::Unimplemented );
} else {
ltrace(200) << "Refusing to slacken border segment." << endl;
ltraceout(200);
DebugSession::close ();
return false;
}
}
if ( data->isRing() ) {
ltrace(200) << "Segment is Ripup only (ring), back-propagate to perpandiculars." << endl;
// Do not change the state.
//data->setState ( DataNegociate::Unimplemented );
success = Manipulator(segment,*this).ripupPerpandiculars(Manipulator::ToRipupLimit
|Manipulator::PerpandicularsFirst
|Manipulator::ToMoveUp);
repush = false;
if ( not success ) {
data->setState ( DataNegociate::Unimplemented );
}
}
// Normal cases.
if ( not blocked and not success ) {
if ( segment->isStrap() ) {
ltrace(200) << "Strap segment FSM." << endl;
switch ( data->getState() ) {
case DataNegociate::RipupPerpandiculars:
nextState = DataNegociate::Desalignate;
success = Manipulator(segment,*this).ripupPerpandiculars();
if ( success ) break;
case DataNegociate::Desalignate:
case DataNegociate::Minimize:
nextState = DataNegociate::LocalVsGlobal;
success = Manipulator(segment,*this).minimize();
if ( success ) break;
case DataNegociate::DogLeg:
case DataNegociate::Slacken:
case DataNegociate::ConflictSolve1:
case DataNegociate::ConflictSolve2:
case DataNegociate::MoveUp:
case DataNegociate::LocalVsGlobal:
if ( not (flags & NoRecursive) ) {
if ( (success = localVsGlobal()) ) {
nextState = DataNegociate::LocalVsGlobal;
if ( data->getStateCount() >= 1 )
nextState = DataNegociate::MaximumSlack;
break;
}
}
case DataNegociate::MaximumSlack:
case DataNegociate::Unimplemented:
nextState = DataNegociate::Unimplemented;
break;
}
if ( not success and (nextState != DataNegociate::Unimplemented) ) {
success = Manipulator(segment,*this).ripupPerpandiculars(Manipulator::ToRipupLimit);
}
} else if ( segment->isLocal() ) {
// Local TrackElement State Machine.
ltrace(200) << "Local segment FSM." << endl;
switch ( data->getState() ) {
case DataNegociate::RipupPerpandiculars:
nextState = DataNegociate::Desalignate;
success = Manipulator(segment,*this).ripupPerpandiculars();
if ( success ) break;
case DataNegociate::Desalignate:
nextState = DataNegociate::Minimize;
success = Manipulator(segment,*this).desalignate();
break;
case DataNegociate::Minimize:
nextState = DataNegociate::DogLeg;
success = Manipulator(segment,*this).minimize();
if ( success ) break;
case DataNegociate::DogLeg:
nextState = DataNegociate::Slacken;
success = Manipulator(segment,*this).makeDogLeg();
if ( success ) break;
case DataNegociate::Slacken:
nextState = DataNegociate::ConflictSolve2;
success = Manipulator(segment,*this).slacken();
if ( success ) break;
case DataNegociate::ConflictSolve1:
case DataNegociate::ConflictSolve2:
if ( not (flags & NoRecursive) ) {
nextState = DataNegociate::MoveUp;
success = conflictSolve2 ();
break;
}
case DataNegociate::MoveUp:
nextState = DataNegociate::LocalVsGlobal;
success = Manipulator(segment,*this).moveUp();
if ( success ) break;
case DataNegociate::LocalVsGlobal:
if ( not (flags & NoRecursive) ) {
if ( (success = localVsGlobal()) ) {
nextState = DataNegociate::LocalVsGlobal;
if ( data->getStateCount() >= 1 )
nextState = DataNegociate::MaximumSlack;
break;
}
}
case DataNegociate::MaximumSlack:
if ( segment->isSlackenStrap() ) {
if ( (nextState < DataNegociate::MaximumSlack) or (data->getStateCount() < 2) ) {
nextState = DataNegociate::MaximumSlack;
success = conflictSolve1 ();
if ( success ) break;
}
}
case DataNegociate::Unimplemented:
nextState = DataNegociate::Unimplemented;
break;
}
if ( not success and (nextState != DataNegociate::Unimplemented) ) {
if ( data->getStateCount() < 6 )
success = Manipulator(segment,*this).ripupPerpandiculars(Manipulator::ToRipupLimit);
}
// Special case: all tracks are overlaping a blockage.
if ( not success
and (nextState == DataNegociate::Unimplemented)
and segment->isSlackened() ) {
blocked = (getCosts().size() > 0);
for ( size_t itrack=0 ; itrack<getCosts().size() ; ++itrack ) {
if ( (not getCost(itrack).isBlockage() and not getCost(itrack).isFixed()) ) {
blocked = false;
break;
}
}
if ( blocked ) {
//Interval nativeConstraints;
//_event->getSegment()->base()->getConstraints ( nativeConstraints );
//if ( nativeConstraints.getSize() < DbU::lambda(5.0) ) {
// blocked = true;
success = Manipulator(segment,*this).pivotUp();
if ( not success ) {
cerr << "[ERROR] Tighly constrained segment overlapping a blockage." << endl;
ltrace(200) << "Segment is hard blocked, bypass to Unimplemented." << endl;
nextState = DataNegociate::Unimplemented;
}
//}
}
}
// LOOPING.
// if ( not success
// and (nextState == DataNegociate::Unimplemented)
// and segment->isSlackened() ) {
// ltrace(200) << "Last chance on slackened" << endl;
// segment->base()->setSlackened ( false );
// success = Manipulator(segment,*this).makeDogLeg();
// nextState = DataNegociate::MaximumSlack;
// }
} else {
// Global TrackElement State Machine.
switch ( data->getState() ) {
ltrace(200) << "Global segment FSM." << endl;
case DataNegociate::RipupPerpandiculars:
ltrace(200) << "Global, State: RipupPerpandiculars." << endl;
nextState = DataNegociate::Desalignate;
break;
case DataNegociate::Minimize:
case DataNegociate::DogLeg:
case DataNegociate::Desalignate:
ltrace(200) << "Global, State: Minimize, DogLeg or Desalignate." << endl;
if ( (success = Manipulator(segment,*this).desalignate()) ) {
nextState = DataNegociate::Slacken;
break;
}
case DataNegociate::Slacken:
ltrace(200) << "Global, State: Slacken." << endl;
if ( (success = Manipulator(segment,*this).slacken()) ) {
nextState = DataNegociate::ConflictSolve1;
break;
}
case DataNegociate::ConflictSolve1:
case DataNegociate::ConflictSolve2:
ltrace(200) << "Global, State: ConflictSolve1 or ConflictSolve2." << endl;
if ( not (flags & NoRecursive) ) {
if ( (success = conflictSolve1 ()) ) {
nextState = DataNegociate::ConflictSolve1;
if ( data->getStateCount() > 3 )
nextState = DataNegociate::MoveUp;
break;
}
}
case DataNegociate::MoveUp:
ltrace(200) << "Global, State: MoveUp." << endl;
if ( (success = Manipulator(segment,*this).moveUp()) ) {
nextState = DataNegociate::ConflictSolve1;
break;
}
nextState = DataNegociate::MaximumSlack;
break;
case DataNegociate::MaximumSlack:
case DataNegociate::Unimplemented:
ltrace(200) << "Global, State: MaximumSlack or Unimplemented." << endl;
nextState = DataNegociate::Unimplemented;
break;
}
if ( not success and (nextState != DataNegociate::Unimplemented) ) {
if ( data->getStateCount() < 6 )
success = Manipulator(segment,*this).ripupPerpandiculars(Manipulator::ToRipupLimit);
}
}
}
if ( not (flags&NoTransition) ) data->setState ( nextState );
if ( success ) {
if ( repush ) {
if ( not (data->isRing() or data->isBorder()) )
actionFlags |= SegmentAction::ResetRipup;
addAction ( segment, actionFlags );
}
} else {
clearActions ();
if ( data->getState() == DataNegociate::Unimplemented ) {
cerr << "[UNSOLVED] " << segment << " unable to slacken topology." << endl;
}
}
ltraceout(200);
DebugSession::close ();
return success;
}
// -------------------------------------------------------------------
// Class Definition : "::Manipulator".
inline TrackElement* Manipulator::getSegment () const { return _segment; }
inline DataNegociate* Manipulator::getData () const { return _data; }
inline RoutingEvent* Manipulator::getEvent () const { return _event; }
Manipulator::Manipulator ( TrackElement* segment, State& S )
: _segment(segment)
, _data (NULL)
, _event (NULL)
, _S (S)
{
if ( !_segment )
throw Error("Manipulator::Manipulator(): cannot build upon a NULL TrackElement.");
DebugSession::open ( _segment->getNet(), 200 );
_data = _segment->getDataNegociate();
if ( _data )
_event = _data->getRoutingEvent();
}
Manipulator::~Manipulator ()
{
DebugSession::close ();
}
bool Manipulator::canRipup ( unsigned int flags ) const
{
if ( _data ) {
if ( not _event or _event->isUnimplemented() ) return false;
unsigned int limit = Session::getKiteEngine()->getRipupLimit(_segment);
if ( not ( flags & NoRingLimit )
and (_data->isRing() or _data->isBorder())
and not (_data->getRipupCount() < limit) )
return false;
return (_data->getRipupCount() < limit);
}
return false;
}
bool Manipulator::isCaged ( DbU::Unit axis ) const
{
Track* track = _segment->getTrack();
if ( not track ) return false;
TrackElement* neighbor = _segment->getPrevious();
if ( neighbor and (neighbor->isFixed() or neighbor->isBlockage()) ) {
if ( abs(axis - neighbor->getTargetU()) < DbU::lambda(10.0) )
return true;
}
neighbor = _segment->getNext();
if ( neighbor and (neighbor->isFixed() or neighbor->isBlockage()) ) {
if ( abs(axis - neighbor->getSourceU()) < DbU::lambda(10.0) )
return true;
}
return false;
}
bool Manipulator::ripup ( DbU::Unit point , unsigned int type, DbU::Unit axisHint )
{
ltrace(200) << "Manipulator::ripup(DbU::Unit) " << DbU::getValueString(point) << endl;
Interval overlap = Interval(point);
overlap.inflate ( Session::getExtensionCap() ); // Ugly.
return ripup ( overlap, type, axisHint );
}
bool Manipulator::ripup ( Interval overlap , unsigned int type, DbU::Unit axisHint, unsigned int toState )
{
ltrace(200) << "Manipulator::ripup(Interval) " << overlap << endl;
ltrace(200) << "TrackElement:" << _data->getGCellOrder()
<< " < Session:" << Session::getOrder() << endl;
if ( not canRipup() ) return false;
if ( _segment->isFixed() ) return false;
if ( _data == NULL ) return true;
if ( _segment->getTrack() ) {
if ( _data->getGCellOrder() < Session::getOrder() ) {
return relax(overlap);
}
}
_S.addAction ( _segment, type, axisHint, toState );
return true;
}
bool Manipulator::ripupPerpandiculars ( unsigned int flags )
{
ltrace(200) << "Manipulator::ripupPerpandiculars() - " << flags << endl;
bool success = true;
bool cagedPerpandiculars = false;
Interval constraints ( _event->getConstraints() );
Interval perpandicularConstraints ( constraints );
size_t placedPerpandiculars = 0;
unsigned int parallelActionFlags = SegmentAction::SelfRipup|SegmentAction::EventLevel4;
unsigned int perpandicularActionFlags = SegmentAction::SelfRipupPerpand;
if ( flags & Manipulator::PerpandicularsFirst ) {
parallelActionFlags &= ~SegmentAction::EventLevel4;
perpandicularActionFlags |= SegmentAction::EventLevel4;
if ( flags & Manipulator::ToRipupLimit )
perpandicularActionFlags |= SegmentAction::ToRipupLimit;
} else {
if ( flags & Manipulator::ToRipupLimit )
parallelActionFlags |= SegmentAction::ToRipupLimit;
}
ltrace(200) << "Pure constraints: " << constraints << endl;
Track* track = NULL;
const vector<TrackElement*>& perpandiculars = _event->getPerpandiculars();
for ( size_t i=0 ; i < perpandiculars.size() ; i++ ) {
track = perpandiculars[i]->getTrack();
if ( not track ) continue;
if ( Manipulator(perpandiculars[i],_S).isCaged(_event->getSegment()->getAxis()) ) {
cagedPerpandiculars = true;
break;
}
placedPerpandiculars++;
// Try to ripup the perpandicular itself.
DataNegociate* data2 = perpandiculars[i]->getDataNegociate();
if ( data2->getGCellOrder() == Session::getOrder() ) {
ltrace(200) << "| " << perpandiculars[i] << endl;
if ( (flags & Manipulator::ToMoveUp)
and (data2->getState() < DataNegociate::MoveUp) )
data2->setState ( DataNegociate::MoveUp );
if ( Manipulator(perpandiculars[i],_S).ripup(_event->getSegment()->getAxis()
,perpandicularActionFlags) )
continue;
}
// Cannot ripup the perpandicular, try to ripup it's neigbors.
size_t begin;
size_t end;
track->getOverlapBounds ( constraints, begin, end );
for ( ; (begin < end) ; begin++ ) {
TrackElement* other = track->getSegment(begin);
if ( other->getNet() == _event->getSegment()->getNet() ) continue;
Interval otherCanonical ( other->getCanonicalInterval() );
if ( not otherCanonical.intersect(constraints) ) continue;
if ( other->getDataNegociate()
and (other->getDataNegociate()->getGCellOrder() < Session::getOrder()) ) {
if ( otherCanonical.getVMin() < constraints.getVMin() )
constraints.shrinkVMin ( otherCanonical.getVMax() );
else
constraints.shrinkVMax ( otherCanonical.getVMin() );
continue;
}
// Try to ripup conflicting neighbor.
if ( Manipulator(other,_S).canRipup() ) {
ltrace(200) << " | Ripup: " << begin << " " << other << endl;
_S.addAction ( other, SegmentAction::OtherRipup );
} else {
ltrace(200) << "Aborted ripup of perpandiculars, blocked by border/ring." << endl;
return false;
}
}
}
if ( cagedPerpandiculars ) {
ltrace(200) << "Aborted ripup of perpandiculars, constraints are due to fixed/blockage." << endl;
_S.addAction ( _segment, SegmentAction::SelfRipup );
return true;
}
if ( _segment->isLocal() and not placedPerpandiculars ) {
ltrace(200) << "No placed perpandiculars, tight native constraints, place perpandiculars FIRST." << endl;
for ( size_t i=0 ; i < perpandiculars.size() ; i++ ) {
_S.addAction ( perpandiculars[i], perpandicularActionFlags|SegmentAction::EventLevel4 );
}
_S.addAction ( _segment, parallelActionFlags );
return true;
}
RoutingPlane* plane = Session::getKiteEngine()->getRoutingPlaneByLayer(_segment->getLayer());
size_t tracksNb = 0;
track = plane->getTrackByPosition(constraints.getVMin());
if ( track && (track->getAxis() < constraints.getVMin()) ) track = track->getNext();
for ( ; track && (track->getAxis() <= constraints.getVMax())
; track = track->getNext(), tracksNb++ );
if ( _segment->isLocal() and (tracksNb < 2) ) success = ripple();
_S.addAction ( _segment, parallelActionFlags );
return success;
}
bool Manipulator::relax ( Interval interval, unsigned int flags )
{
interval.inflate ( - Session::getExtensionCap() /*+ DbU::lambda(5.0)*/ ); // Ugly.
ltrace(200) << "Manipulator::relax() of: " << _segment << " " << interval << endl;
if ( _segment->isFixed() ) return false;
if ( not interval.intersect(_segment->getCanonicalInterval()) ) return false;
if ( not _data ) return false;
//if ( _data->isBorder() or _data->isRing() ) return false;
if ( _segment->isTerminal()
and (_segment->getLayer() == Session::getRoutingGauge()->getRoutingLayer(1)) ) {
if ( interval.contains(_segment->base()->getAutoSource()->getX()) ) return false;
if ( interval.contains(_segment->base()->getAutoTarget()->getX()) ) return false;
}
bool success = true;
unsigned int currentOrder = Session::getOrder ();
ltracein(200);
ltrace(200) << "Current o:" << currentOrder << " vs. Segment o:" << _data->getGCellOrder() << endl;
//bool expand = (_data->getGCellOrder() < currentOrder);
bool expand = _segment->isGlobal() and (flags&AllowExpand);
ltrace(200) << "Expand:" << expand << endl;
// Temp: <= replace < equal order can be relaxeds.
if ( _data->getGCellOrder() <= currentOrder ) {
vector<GCell*> gcells;
_segment->getGCells ( gcells );
if ( gcells.size() < 2 ) {
cerr << Bug("relax() Cannot break %p:%s,\n"
" only in %s (current order %d)."
,_segment->base()->base()
,getString(_segment).c_str()
,getString(gcells[0]).c_str()
,currentOrder
) << endl;
ltraceout(200);
return false;
}
unsigned int depth = Session::getRoutingGauge()->getLayerDepth(_segment->getLayer());
Interval uside;
size_t dogLegCount = 0;
size_t iminconflict = gcells.size();
size_t imaxconflict = gcells.size();
size_t igcell;
// Look for closest enclosing min & max GCells indexes.
for ( igcell=0 ; igcell<gcells.size() ; igcell++ ) {
uside = gcells[igcell]->getUSide(_segment->getDirection(),true);
ltrace(200) << "| " << gcells[igcell] << " uside: " << uside << endl;
if ( uside.contains(interval.getVMin()) ) {
iminconflict = igcell;
ltrace(200) << "> Min conflict: " << iminconflict << endl;
}
if ( uside.contains(interval.getVMax()) ) {
imaxconflict = igcell;
ltrace(200) << "> Max conflict: " << imaxconflict << endl;
}
}
// Expand min & max to enclose GCells of greatest or equal order
// (i.e. less saturateds)
bool minExpanded = false;
bool maxExpanded = false;
if ( expand ) {
size_t iexpand = iminconflict;
if ( iminconflict < gcells.size() ) {
for ( igcell=iminconflict ; true ; igcell-- ) {
if ( gcells[igcell]->getOrder() >= currentOrder ) iexpand = igcell;
else break;
if ( igcell == 0 ) break;
}
if ( iexpand > 0 ) {
size_t imindepth = iexpand;
for ( ; iexpand < iminconflict ; iexpand++ ) {
if ( not _segment->canDogLegAt(gcells[iexpand],true) ) continue;
ltrace(200) << "Density " << Session::getRoutingGauge()->getRoutingLayer(depth)->getName()
<< " " << gcells[iexpand]->getDensity(depth) << endl;
if ( gcells[imindepth]->getDensity(depth) > gcells[iexpand]->getDensity(depth) )
imindepth = iexpand;
}
iexpand = imindepth;
}
if ( iminconflict != iexpand ) minExpanded = true;
iminconflict = (iexpand>0) ? iexpand : gcells.size();
}
iexpand = imaxconflict;
for ( igcell=imaxconflict ; igcell < gcells.size() ; igcell++ ) {
if ( gcells[igcell]->getOrder() >= currentOrder ) iexpand = igcell;
else break;
}
if ( iexpand < gcells.size()-1 ) {
size_t imindepth = iexpand;
for ( ; iexpand > imaxconflict ; iexpand-- ) {
if ( not _segment->canDogLegAt(gcells[iexpand],true) ) continue;
ltrace(200) << "Density " << Session::getRoutingGauge()->getRoutingLayer(depth)->getName()
<< " " << gcells[iexpand]->getDensity(depth) << endl;
if ( gcells[imindepth]->getDensity(depth) > gcells[iexpand]->getDensity(depth) )
imindepth = iexpand;
}
iexpand = imindepth;
}
if ( imaxconflict != iexpand ) maxExpanded = true;
imaxconflict = (iexpand < gcells.size()) ? iexpand : gcells.size();
}
ltrace(200) << "minExpanded:" << minExpanded << " (" << iminconflict
<< ") maxExpanded:" << maxExpanded << " (" << imaxconflict << ")" << endl;
// Check for full enclosure.
if ( ( (iminconflict == gcells.size()) and (imaxconflict == gcells.size() ) )
or ( (iminconflict == 0) and (imaxconflict == gcells.size()-1) )) {
cinfo << "[INFO] Manipulator::relax(): Segment fully enclosed in interval." << endl;
ltraceout(200);
return false;
}
// Check order validity under the relaxed interval.
// Should be implicitely satisfied.
// Suppress min/max if it's the first/last.
if ( (iminconflict < gcells.size()) and (imaxconflict == gcells.size()-1) ) imaxconflict = gcells.size();
if ( (imaxconflict < gcells.size()) and (iminconflict == 0) ) iminconflict = gcells.size();
// Compute number of doglegs and nature of the *first* dogleg.
// (first can be min or max, second can only be max)
bool firstDogLegIsMin = false;
if ( iminconflict < gcells.size() ) { dogLegCount++; firstDogLegIsMin = true; }
if ( imaxconflict < gcells.size() ) dogLegCount++;
switch ( dogLegCount ) {
case 2:
// Compact only if the double dogleg is at beginning or end.
if ( iminconflict == imaxconflict ) {
if ( iminconflict == 0 ) {
// First dogleg is max.
dogLegCount--;
} else if ( iminconflict == gcells.size()-1 ) {
dogLegCount--;
firstDogLegIsMin = true;
}
}
break;
case 1: break;
case 0:
cerr << Bug("Manipulator::relax() Can't find a GCell suitable for making dogleg.\n"
" Cannot move either left or right of %s. Current order %d."
,getString(interval).c_str()
,currentOrder
) << endl;
ltraceout(200);
return false;
}
ltrace(200) << "| Has to do " << dogLegCount << " doglegs." << endl;
// Check for conflict occuring outside the current RoutingSet.
// Ugly: 2 track pitch.
#ifdef DISABLE_NARROW_DOGLEG
if ( (iminconflict != gcells.size())
and ( (gcells[iminconflict]->getOrder() > currentOrder)
or (_data->getGCellOrder() < currentOrder) ) ) {
uside = gcells[iminconflict]->getUSide(_segment->getDirection(),true);
if ( interval.getVMin() - uside.getVMin() < DbU::lambda(10.0) ) {
ltrace(200) << "Min conflict dogleg space is too narrow (<2 tracks)." << endl;
ltraceout(200);
return false;
} else {
ltrace(200) << "Min conflict has sufficent slack min:"
<< DbU::getValueString(interval.getVMin()) << " uside:"
<< DbU::getValueString(uside.getVMin())
<< endl;
}
}
#endif
#ifdef DISABLE_NARROW_DOGLEG
if ( (imaxconflict != gcells.size())
and ( (gcells[imaxconflict]->getOrder() > currentOrder)
or (_data->getGCellOrder() < currentOrder) ) ) {
uside = gcells[imaxconflict]->getUSide(_segment->getDirection(),true);
if ( uside.getVMax() - interval.getVMax() < DbU::lambda(10.0) ) {
ltrace(200) << "Max conflict dogleg space is too narrow (<2 tracks)." << endl;
ltraceout(200);
return false;
} else {
ltrace(200) << "Max conflict has sufficent slack max:"
<< DbU::getValueString(interval.getVMax()) << " uside:"
<< DbU::getValueString(uside.getVMax())
<< endl;
}
}
#endif
// Check of "min is less than one track close the edge" (while not expanded).
// AND we are on the first GCell AND there's one dogleg only.
if ( not minExpanded and (iminconflict == 0) and (imaxconflict == gcells.size()) ) {
ltrace(200) << "Cannot break in first GCell only." << endl;
ltraceout(200);
return false;
}
// Check of "min is less than one track close the edge" (while not expanded).
if ( /*not minExpanded and*/ (iminconflict > 0) and (iminconflict < gcells.size()) ) {
uside = gcells[iminconflict-1]->getUSide(_segment->getDirection(),true);
ltrace(200) << "GCell Edge Comparison (min): " << uside
<< " vs. " << DbU::getValueString(interval.getVMin()) << endl;
// Ugly: One lambda shrink.
if ( interval.getVMin()-DbU::lambda(1.0) <= uside.getVMax() ) {
if ( gcells[iminconflict-1]->getOrder() >= currentOrder ) {
ltrace(200) << "Using previous GCell." << endl;
iminconflict--;
} else {
ltrace(200) << "Cannot break in previous GCell." << endl;
ltraceout(200);
return false;
}
}
}
// Check if there is only one dogleg AND it's the last one.
if ( not maxExpanded and (iminconflict == gcells.size()) and (imaxconflict == gcells.size()-1) ) {
ltrace(200) << "Cannot break in last GCell only." << endl;
ltraceout(200);
return false;
}
// Check of "max is less than one track close the edge" (while not expanded).
// AND we are on the last GCell AND there's one dogleg only.
// if ( not maxExpanded and (iminconflict == gcells.size()) and (imaxconflict == gcells.size()-1) ) {
// uside = gcells[imaxconflict]->getUSide(_segment->getDirection(),true);
// ltrace(200) << "GCell Edge Comparison (max): " << uside
// << " vs. " << DbU::getValueString(interval.getVMax()) << endl;
// // Ugly: Direct uses of routing pitch.
// if ( interval.getVMax()+DbU::lambda(10.0) >= uside.getVMax() ) {
// ltrace(200) << "Cannot break in last GCell only, less than 2 pitches." << endl;
// ltraceout(200);
// return false;
// }
// }
// Check of "max is less than one track close the edge" (while not expanded).
if ( /*not maxExpanded and*/ (imaxconflict < gcells.size()-1) ) {
uside = gcells[imaxconflict+1]->getUSide(_segment->getDirection(),true);
ltrace(200) << "GCell Edge Comparison (max): " << uside
<< " vs. " << DbU::getValueString(interval.getVMax()) << endl;
// Ugly: Direct uses of routing pitch.
if ( interval.getVMax()+DbU::lambda(5.0) >= uside.getVMin() ) {
if ( gcells[imaxconflict+1]->getOrder() >= currentOrder ) {
ltrace(200) << "Using next GCell." << endl;
imaxconflict++;
} else {
ltrace(200) << "Cannot break in next GCell." << endl;
ltraceout(200);
return false;
}
}
}
size_t ifirstDogleg = gcells.size();
size_t isecondDogleg = gcells.size();
if ( not firstDogLegIsMin ) {
ifirstDogleg = imaxconflict;
} else {
ifirstDogleg = iminconflict;
isecondDogleg = imaxconflict;
}
// Making first dogleg.
ltrace(200) << "Making FIRST dogleg at " << ifirstDogleg << endl;
TrackElement* segment1 = NULL;
TrackElement* segment2 = NULL;
Track* track = _segment->getTrack();
GCell* dogLegGCell = gcells[ifirstDogleg];
TrackElement* dogleg = NULL;
DbU::Unit doglegAxis;
bool doglegReuse1 = false;
bool doglegReuse2 = false;
// Try to reuse existing dogleg if broken at either end.
if ( ifirstDogleg == 0 ) dogleg = _segment->getSourceDogLeg();
if ( ifirstDogleg == gcells.size()-1 ) dogleg = _segment->getTargetDogLeg();
if ( dogleg ) {
ltrace(200) << "Reusing dogleg." << endl;
doglegReuse1 = true;
segment1 = _segment;
} else {
// Try to create a new dogleg.
if ( not _segment->canDogLegAt(dogLegGCell) ) {
ltrace(200) << "Cannot create FIRST dogleg." << endl;
ltraceout(200);
return false;
}
dogleg = _segment->makeDogLeg ( dogLegGCell );
segment1 = Session::lookup ( Session::getDogLegs()[2] );
}
if ( firstDogLegIsMin ) {
if ( minExpanded ) {
//doglegAxis = dogLegGCell->getUSide(_segment->getDirection(),false).getVMax() - DbU::lambda(1.0);
doglegAxis = dogLegGCell->getUSide(_segment->getDirection(),false).getCenter();
} else {
// Ugly: hardcoded pitch.
doglegAxis = interval.getVMin() - DbU::lambda(5.0);
}
} else {
if ( maxExpanded ) {
doglegAxis = dogLegGCell->getUSide(_segment->getDirection(),false).getVMin();
} else {
// Ugly: hardcoded pitch (5.0 - 1.0).
doglegAxis = interval.getVMax() + DbU::lambda(4.0);
}
}
if ( doglegReuse1 ) _S.addAction ( dogleg, SegmentAction::OtherRipup );
else dogleg->setAxis ( doglegAxis );
// If event is present, the dogleg is in the current RoutingSet.
RoutingEvent* event = dogleg->getDataNegociate()->getRoutingEvent();
if ( event ) {
ltrace(200) << "Set Axis Hint: @" << DbU::getValueString(doglegAxis) << " " << dogleg << endl;
event->setAxisHint ( doglegAxis );
} else {
ltrace(200) << "Dogleg has no RoutingEvent yet." << endl;
}
if ( (dogLegCount == 2)
and not _segment->getTrack()
and (_segment->getGCell()->getOrder() < Session::getOrder()) ) {
Session::addInsertEvent ( _segment, track );
}
// Making second dogleg.
if ( dogLegCount > 1 ) {
ltrace(200) << "Making SECOND dogleg at " << isecondDogleg
<< " on " << segment1 << endl;
dogleg = NULL;
dogLegGCell = gcells[isecondDogleg];
if ( ifirstDogleg == isecondDogleg ) {
ltrace(200) << "Double break in same GCell." << endl;
segment1->setSourceDogLeg(false);
}
if ( isecondDogleg == gcells.size()-1 ) dogleg = segment1->getTargetDogLeg();
if ( dogleg ) {
ltrace(200) << "Reusing dogleg." << endl;
doglegReuse2 = true;
segment2 = segment1;
} else {
// Try to create a new dogleg.
if ( not segment1->canDogLegAt(dogLegGCell) ) {
ltrace(200) << "Cannot create SECOND dogleg." << endl;
ltraceout(200);
return false;
}
dogleg = segment1->makeDogLeg ( dogLegGCell );
segment2 = Session::lookup ( Session::getDogLegs()[2] );
}
if ( maxExpanded ) {
//doglegAxis = dogLegGCell->getUSide(segment1->getDirection(),false).getVMin();
doglegAxis = dogLegGCell->getUSide(segment1->getDirection(),false).getCenter();
} else {
// Ugly: hardcoded pitch.
doglegAxis = interval.getVMax() + DbU::lambda(5.0);
}
if ( doglegReuse2 ) _S.addAction ( dogleg, SegmentAction::OtherRipup );
else dogleg->setAxis ( doglegAxis );
// If event is present, the dogleg is in the current RoutingSet.
RoutingEvent* event = dogleg->getDataNegociate()->getRoutingEvent();
if ( event ) {
ltrace(200) << "Set Axis Hint: @" << DbU::getValueString(doglegAxis) << " " << dogleg << endl;
event->setAxisHint ( doglegAxis );
} else {
ltrace(200) << "Dogleg has no RoutingEvent yet." << endl;
}
const vector<AutoSegment*>& doglegs = Session::getDogLegs();
for ( size_t i=0 ; i<doglegs.size() ; i++ ) {
TrackElement* segment = Session::lookup(doglegs[i]);
if ( ( segment->getGCell()->getOrder() < Session::getOrder() ) and not segment->getTrack() ) {
Session::addInsertEvent ( segment, track );
}
}
}
switch ( dogLegCount ) {
case 1:
if ( not doglegReuse1 ) {
if ( firstDogLegIsMin )
_segment->getDataNegociate()->setState ( DataNegociate::RipupPerpandiculars, true );
else
segment1->getDataNegociate()->setState ( DataNegociate::RipupPerpandiculars, true );
}
break;
case 2:
if ( not doglegReuse1 )
_segment->getDataNegociate()->setState ( DataNegociate::RipupPerpandiculars, true );
if ( not doglegReuse2 )
segment2->getDataNegociate()->setState ( DataNegociate::RipupPerpandiculars, true );
break;
}
} else if ( _data->getGCellOrder() > currentOrder ) {
cerr << Bug("relax() Routing order problem for %s."
,getString(_segment).c_str()) << endl;
success = false;
} else {
// The TrackElement has an order equal to the Session, it's in the
// RoutingSet.
if ( !Manipulator(_segment,_S).makeDogLeg(interval) ) success = false;
}
ltraceout(200);
return success;
}
bool Manipulator::insertInTrack ( size_t itrack )
{
Track* track = _S.getTrack(itrack);
size_t begin = _S.getBegin(itrack);
size_t end = _S.getEnd (itrack);
Net* ownerNet = _segment->getNet();
Interval toFree (_segment->getCanonicalInterval());
Net* ripupNet = NULL;
set<TrackElement*> canonicals;
DbU::Unit rightAxisHint = 0;
DbU::Unit leftAxisHint = 0;
bool leftIntrication = false;
bool rightIntrication = false;
bool success = true;
unsigned long maxId = AutoSegment::getMaxId();
ltrace(200) << "Manipulator::insertInTrack() - " << toFree << endl;
for ( size_t i = begin ; success && (i < end) ; i++ ) {
TrackElement* segment2 = track->getSegment(i);
ltrace(200) << "* Looking // " << segment2 << endl;
if ( segment2->getNet() == ownerNet ) continue;
if ( not toFree.intersect(segment2->getCanonicalInterval()) ) continue;
if ( segment2->getId() >= maxId ) continue;
if ( segment2->isBlockage() or segment2->base()->isFixed() ) {
success = false;
continue;
}
//if ( (segment2->getNet() != ripupNet )
// && !toFree.intersect(segment2->getCanonicalInterval()) ) continue;
ripupNet = segment2->getNet();
DataNegociate* data2 = segment2->getDataNegociate();
if ( !data2 ) {
ltrace(200) << "No DataNegociate, ignoring." << endl;
continue;
}
if ( data2->getGCellOrder() < Session::getOrder() ) {
// Interval relax.
success = Manipulator(segment2,_S).relax ( toFree );
} else {
if ( data2->getState() == DataNegociate::MaximumSlack ) {
ltrace(200) << "At " << DataNegociate::getStateString(data2)
<< " for " << segment2 << endl;
success = false;
continue;
}
bool shrinkLeft = false;
bool shrinkRight = false;
if ( data2->getCost().getRightMinExtend() < toFree.getVMin() ) {
ltrace(200) << "- Shrink right edge (push left) " << segment2 << endl;
shrinkRight = true;
TrackElement* rightNeighbor2 = track->getSegment(i+1);
if ( rightNeighbor2 && (rightNeighbor2->getNet() == segment2->getNet()) ) {
Interval interval1 = segment2->getCanonicalInterval();
Interval interval2 = rightNeighbor2->getCanonicalInterval();
if ( interval1.intersect(interval2) && (interval2.getVMax() > interval1.getVMax()) )
shrinkLeft = true;
}
}
if ( data2->getCost().getLeftMinExtend() > toFree.getVMax() ) {
ltrace(200) << "- Shrink left edge (push right) " << segment2 << endl;
shrinkLeft = true;
if ( i > 0 ) {
TrackElement* leftNeighbor2 = track->getSegment(i-1);
if ( leftNeighbor2 && (leftNeighbor2->getNet() == segment2->getNet()) ) {
Interval interval1 = segment2->getCanonicalInterval();
Interval interval2 = leftNeighbor2->getCanonicalInterval();
if ( interval1.intersect(interval2) && (interval2.getVMin() < interval1.getVMin()) )
shrinkRight = true;
}
}
}
if ( not (shrinkLeft xor shrinkRight) ) {
ltrace(200) << "- Hard overlap/enclosure/shrink " << segment2 << endl;
if ( not (success = Manipulator(segment2,_S).ripup(toFree,SegmentAction::OtherRipup)) )
continue;
}
canonicals.clear ();
forEach ( TrackElement*, isegment3
, segment2->getCollapsedPerpandiculars().getSubSet(TrackElements_UniqCanonical(canonicals)) ) {
DataNegociate* data3 = isegment3->getDataNegociate();
if ( not data3 ) continue;
RoutingEvent* event3 = data3->getRoutingEvent();
if ( not event3 ) continue;
if ( not toFree.intersect(event3->getConstraints()) ) {
ltrace(200) << " . " << *isegment3 << endl;
continue;
}
ltrace(200) << " | " << *isegment3 << endl;
if ( shrinkRight xor shrinkLeft ) {
if ( shrinkRight ) {
if ( not (success=Manipulator(*isegment3,_S).ripup ( track->getAxis()
, SegmentAction::OtherPushAside
| SegmentAction::AxisHint
, toFree.getVMin() - DbU::lambda(1.0)
)) )
break;
if ( event3->getTracksFree() == 1 ) {
ltrace(200) << "Potential left intrication with other perpandicular." << endl;
if ( isegment3->getAxis() == segment2->getTargetU() - Session::getExtensionCap() ) {
leftIntrication = true;
leftAxisHint = isegment3->getAxis();
}
}
}
if ( shrinkLeft ) {
if ( not (success=Manipulator(*isegment3,_S).ripup ( track->getAxis()
, SegmentAction::OtherPushAside
| SegmentAction::AxisHint
, toFree.getVMax() + DbU::lambda(1.0)
)) )
break;
if ( event3->getTracksFree() == 1 ) {
ltrace(200) << "Potential right intrication with other perpandicular." << endl;
if ( isegment3->getAxis() == segment2->getSourceU() + Session::getExtensionCap() ) {
rightIntrication = true;
rightAxisHint = isegment3->getAxis();
}
}
}
} else {
// DbU::Unit axisHint
// = (event3->getAxisHint() - toFree.getVMin() < toFree.getVMax() - event3->getAxisHint())
// ? (toFree.getVMin() - DbU::lambda(1.0)) : (toFree.getVMax() + DbU::lambda(1.0));
if ( not (success=Manipulator(*isegment3,_S).ripup ( track->getAxis()
, SegmentAction::OtherRipup
| SegmentAction::EventLevel3
//| SegmentAction::AxisHint, axisHint
)) )
break;
}
}
if ( not success ) break;
}
}
if ( success ) {
_S.setState ( State::OtherRipup );
_S.addAction ( _segment, SegmentAction::SelfInsert /*| SegmentAction::EventLevel3*/ );
_segment->setAxis ( _S.getCost(itrack).getTrack()->getAxis() );
unsigned int flags = 0;
if ( rightIntrication ) flags |= RightAxisHint;
if ( leftIntrication ) flags |= LeftAxisHint;
if ( flags )
Manipulator(_segment,_S).shrinkToTrack(itrack,flags,leftAxisHint,rightAxisHint);
} else
_S.clearActions ();
return success;
}
bool Manipulator::forceToTrack ( size_t itrack )
{
Track* track = _S.getTrack(itrack);
size_t begin = _S.getBegin(itrack);
size_t end = _S.getEnd (itrack);
Net* ownerNet = _segment->getNet();
Interval toFree (_segment->getCanonicalInterval());
Net* ripupNet = NULL;
set<TrackElement*> canonicals;
bool success = true;
ltrace(200) << "Manipulator::forceToTrack() - " << toFree << endl;
for ( size_t i = begin ; success && (i < end) ; i++ ) {
TrackElement* segment2 = track->getSegment(i);
ltrace(200) << "* Looking // " << segment2 << endl;
if ( segment2->getNet() == ownerNet ) continue;
if ( !toFree.intersect(segment2->getCanonicalInterval()) ) continue;
if ( segment2->base()->isFixed() ) {
success = false;
continue;
}
//if ( (segment2->getNet() != ripupNet )
// && !toFree.intersect(segment2->getCanonicalInterval()) ) continue;
ripupNet = segment2->getNet();
DataNegociate* data2 = segment2->getDataNegociate();
if ( !data2 ) {
ltrace(200) << "No DataNegociate, ignoring." << endl;
continue;
}
if ( data2->getGCellOrder() < Session::getOrder() ) {
// Interval relax.
success = Manipulator(segment2,_S).relax ( toFree );
} else {
ltrace(200) << "- Forced ripup " << segment2 << endl;
if ( not (success=Manipulator(segment2,_S).ripup(toFree,SegmentAction::OtherRipup)) )
continue;
canonicals.clear ();
forEach ( TrackElement*, isegment3
, segment2->getCollapsedPerpandiculars().getSubSet(TrackElements_UniqCanonical(canonicals)) ) {
DataNegociate* data3 = isegment3->getDataNegociate();
if ( !data3 ) continue;
RoutingEvent* event3 = data3->getRoutingEvent();
if ( !event3 ) continue;
if ( Manipulator(*isegment3,_S).canRipup() )
_S.addAction ( *isegment3, SegmentAction::OtherRipup );
}
}
}
if ( success ) {
_S.setState ( State::OtherRipup );
_S.addAction ( _segment, SegmentAction::SelfInsert );
_segment->setAxis ( _S.getCost(itrack).getTrack()->getAxis() );
}
return success;
}
bool Manipulator::shrinkToTrack ( size_t i, unsigned int flags, DbU::Unit leftAxisHint, DbU::Unit rightAxisHint )
{
Track* track = _S.getTrack(i);
size_t begin = _S.getBegin(i);
size_t end = _S.getEnd (i);
Net* ownerNet = _segment->getNet();
set<TrackElement*> canonicals;
bool success = true;
DbU::Unit leftExtend = _segment->getSourceU() + Session::getExtensionCap();
DbU::Unit rightExtend = _segment->getSourceU() - Session::getExtensionCap();
ltrace(200) << "Manipulator::shrinkToTrack()" << endl;
if ( _segment->isLocal() ) return false;
//Interval shrunkFree ( _segment->getSourceConstraints().getVMax()
// , _segment->getTargetConstraints().getVMin() );
Interval shrunkFree = _segment->base()->getMinSpanU();
ltrace(200) << "* " << shrunkFree << endl;
for ( size_t i = begin ; success && (i < end) ; i++ ) {
TrackElement* segment2 = track->getSegment(i);
ltrace(200) << "* Looking // " << segment2 << endl;
if ( segment2->getNet() == ownerNet ) continue;
if ( segment2->isFixed() ) { success = false; continue; }
if ( !shrunkFree.intersect(segment2->getCanonicalInterval()) ) continue;
success = false;
}
if ( success ) {
set<TrackElement*> perpandiculars;
set<TrackElement*>::iterator iperpand;
DbU::Unit axisHint;
if ( not (flags & LeftAxisHint ) ) leftAxisHint = shrunkFree.getCenter();
if ( not (flags & RightAxisHint) ) rightAxisHint = shrunkFree.getCenter();
_segment->getPerpandicularsBound ( perpandiculars );
for ( iperpand = perpandiculars.begin() ; iperpand != perpandiculars.end() ; iperpand++ ) {
DataNegociate* data2 = (*iperpand)->getDataNegociate();
if ( data2 && (data2->getGCellOrder() >= Session::getOrder()) ) {
ltrace(200) << "| perpandicular bound:" << *iperpand << endl;
success = Manipulator(*iperpand,_S).ripup ( track->getAxis(), SegmentAction::SelfRipupAndAxisHint );
if ( success ) {
if ( (*iperpand)->getAxis() == leftExtend ) axisHint = leftAxisHint;
else if ( (*iperpand)->getAxis() == rightExtend ) axisHint = rightAxisHint;
else {
cinfo << "[INFO] Bound Axis is neither left nor right\n "
<< (*iperpand) << endl;
axisHint = shrunkFree.getCenter();
}
_S.getActions()[_S.getActions().size()-1].setAxisHint ( axisHint );
}
}
}
_S.addAction ( _segment, SegmentAction::SelfInsert );
_S.setState ( State::OtherRipup );
ltrace(200) << "Successful shrinkToTrack." << endl;
return true;
}
return false;
}
bool Manipulator::desalignate ()
{
ltrace(200) << "Manipulator::desalignate() " << _segment << endl;
if ( _segment->isFixed () ) return false;
if ( !_segment->canDesalignate() ) return false;
_segment->desalignate ();
return true;
}
bool Manipulator::slacken ()
{
ltrace(200) << "Manipulator::slacken() " << _segment << endl;
if ( _segment->isFixed () ) return false;
if ( !_segment->canSlacken() ) return false;
_segment->slacken ();
return true;
}
bool Manipulator::goOutsideGCell ()
{
ltrace(200) << "Manipulator::goOutsideGCell() " << _segment << endl;
return false;
#if 0
if ( _segment->isFixed () ) return false;
if ( !_segment->canGoOutsideGCell() ) return false;
GCell* sourceGCell = _segment->getGCell();
GCell* leftGCell = NULL;
GCell* rightGCell = NULL;
Interval uside;
bool goLeft = false;
bool goRight = false;
if ( _segment->isHorizontal() ) {
uside = sourceGCell->getUSide ( Constant::Vertical, false );
leftGCell = sourceGCell->getDown();
rightGCell = sourceGCell->getUp ();
} else {
uside = sourceGCell->getUSide ( Constant::Horizontal, false );
leftGCell = sourceGCell->getLeft ();
rightGCell = sourceGCell->getRight();
}
Interval constraints;
_segment->base()->getConstraints ( constraints );
// Ugly: Must use the right compensator for VMax.
if ( rightGCell and (uside.getVMax() <= constraints.getVMax())+DbU::lambda(1.0) ) goRight = true;
if ( leftGCell and (uside.getVMin() >= constraints.getVMin()) ) goLeft = true;
if ( goRight and goLeft ) {
DbU::Unit distanceToLeft = _segment->getAxis() - uside.getVMin();
DbU::Unit distanceToRight = uside.getVMax() - _segment->getAxis();
if ( distanceToLeft < distanceToRight ) goRight = false;
else goLeft = false;
}
_segment->moveAside ( goLeft );
return true;
#endif
}
bool Manipulator::ripple ()
{
ltrace(200) << "Manipulator::ripple() from " << _segment << endl;
//if ( not _segment->canRipple() ) return false;
if ( not _segment->isLocal() ) return false;
Net* net = _segment->getNet();
Interval uside = _segment->getGCell()->getUSide
( Constant::perpandicular(_segment->getDirection()), false );
RoutingPlane* plane = Session::getKiteEngine()->getRoutingPlaneByLayer(_segment->getLayer());
ltracein(200);
forEach ( Track*, itrack, Tracks_Range::get(plane,uside)) {
size_t begin;
size_t end;
itrack->getOverlapBounds ( _segment->getCanonicalInterval(), begin, end );
for ( ; begin < end ; begin++ ) {
TrackElement* other = itrack->getSegment(begin);
ltrace(200) << "| " << other << endl;
if ( other->getNet() == net ) continue;
if ( not other->canRipple() ) continue;
DataNegociate* otherData = other->getDataNegociate();
if ( not otherData ) continue;
if ( otherData->getGCellOrder() < Session::getOrder() ) continue;
DbU::Unit shiftedAxisHint;
RoutingEvent* otherEvent = otherData->getRoutingEvent();
if ( other->getAxis() < _segment->getAxis() ) {
// Ugly: routing pitch.
shiftedAxisHint = otherEvent->getAxisHint() - DbU::lambda(5.0);
if ( shiftedAxisHint < uside.getVMin() )
shiftedAxisHint = uside.getVMin();
} else {
// Ugly: routing pitch.
shiftedAxisHint = otherEvent->getAxisHint() + DbU::lambda(5.0);
if ( shiftedAxisHint > uside.getVMax() )
shiftedAxisHint = uside.getVMax();
}
otherEvent->setAxisHint ( shiftedAxisHint );
_S.addAction ( other, SegmentAction::OtherRipup );
}
}
ltraceout(200);
return true;
}
bool Manipulator::pivotUp ()
{
ltrace(200) << "Manipulator::pivotUp() " << _segment << endl;
if ( _segment->isFixed () ) return false;
if ( not _segment->canMoveUp(0.0) ) return false;
_segment->moveUp ();
return true;
}
bool Manipulator::moveUp ()
{
ltrace(200) << "Manipulator::moveUp() " << _segment << endl;
if ( _segment->isFixed () ) return false;
if ( _segment->isLocal() and not _segment->canPivotUp(0.0) ) return false;
if ( not _segment->canMoveUp(0.5) ) return false;
#if DISABLED
ltrace(200) << "| Repack Tracks: " << endl;
Interval constraints;
Interval overlap = _segment->getCanonicalInterval();
RoutingPlane* plane = Session::getKiteEngine()->getRoutingPlaneByLayer(_segment->getLayer());
size_t begin;
size_t end;
TrackElement* other;
constraints = _segment->getGCell()->getUSide(Constant::perpandicular(_segment->getDirection()),true);
forEach ( Track*, itrack, Tracks_Range::get(plane,constraints)) {
itrack->getOverlapBounds ( overlap, begin, end );
for ( ; (begin < end) ; begin++ ) {
other = itrack->getSegment(begin);
if ( other->isGlobal() ) continue;
if ( other->getDataNegociate()
and (other->getDataNegociate()->getGCellOrder() != Session::getOrder()) ) continue;
ltrace(200) << " | Ripup for repack: " << begin << " " << other << endl;
_S.addAction ( other, SegmentAction::OtherRipup );
}
}
#endif
_segment->moveUp ();
return true;
}
bool Manipulator::makeDogLeg ()
{
ltrace(200) << "Manipulator::makeDogLeg() " << _segment << endl;
if ( _segment->isFixed() ) return false;
if ( !_segment->isLocal() ) return false;
if ( _S.getCosts().size() ) {
Track* track = _S.getTrack(0);
size_t begin = _S.getBegin(0);
size_t end = _S.getEnd (0);
Net* ownerNet = _segment->getNet();
Interval toFree (_segment->getCanonicalInterval());
Interval overlap;
for ( size_t i = begin ; i < end ; i++ ) {
TrackElement* segment2 = track->getSegment(i);
ltrace(200) << "* Looking // " << segment2 << endl;
if ( segment2->getNet() == ownerNet ) continue;
if ( !toFree.intersect(segment2->getCanonicalInterval()) ) continue;
if ( overlap.isEmpty() )
overlap = segment2->getCanonicalInterval();
else
overlap.merge ( segment2->getCanonicalInterval() );
}
if ( !overlap.isEmpty() && makeDogLeg(overlap) ) return true;
}
if ( !_segment->canDogLeg() ) return false;
_segment->makeDogLeg ();
return true;
}
bool Manipulator::makeDogLeg ( Interval overlap )
{
ltrace(200) << "Manipulator::makeDogLeg(Interval) " << _segment << endl;
ltrace(200) << overlap << endl;
//if ( !_segment->isLocal() || !_segment->canDogLeg() ) return false;
if ( _segment->isFixed () ) return false;
if ( !_segment->canDogLeg(overlap) ) return false;
bool pushLeft;
bool isTerminal = _segment->isTerminal();
TrackElement* dogleg = _segment->makeDogLeg(overlap,pushLeft);
if ( dogleg ) {
ltrace(200) << "Manipulator::makeDogLeg(Interval) - Push dogleg to the "
<< ((pushLeft)?"left":"right") << endl;
if ( isTerminal ) {
AutoContact* contact = (pushLeft) ? _segment->base()->getAutoSource()
: _segment->base()->getAutoTarget();
DbU::Unit axisHint = (_segment->isHorizontal()) ? contact->getX() : contact->getY();
RoutingEvent* event = dogleg->getDataNegociate()->getRoutingEvent();
if ( event ) {
event->setAxisHint ( axisHint );
event->setForcedToHint ( true );
ltrace(200) << "Forced to axis hint @" << DbU::getValueString(axisHint) << endl;
}
}
return true;
}
return false;
}
bool Manipulator::makeDogLeg ( DbU::Unit position )
{
ltrace(200) << "Manipulator::makeDogLeg(position) " << _segment << endl;
ltrace(200) << "Breaking position: " << DbU::getValueString(position) << endl;
if ( _segment->isFixed() ) return false;
vector<GCell*> gcells;
_segment->getGCells ( gcells );
size_t igcell = 0;
for ( ; igcell<gcells.size() ; igcell++ ) {
if ( gcells[igcell]->getUSide(_segment->getDirection(),true).contains(position) )
break;
}
if ( igcell == gcells.size() ) return false;
if ( not _segment->canDogLegAt(gcells[igcell]) ) return false;
TrackElement* dogleg = _segment->makeDogLeg(gcells[igcell]);
return ( dogleg != NULL );
}
bool Manipulator::minimize ()
{
ltrace(200) << "Manipulator::minimize() " << _segment << endl;
if ( _segment->isFixed() ) return false;
if ( !_event->canMinimize() ) return false;
DbU::Unit minSpan = DbU::Max;
DbU::Unit maxSpan = DbU::Min;
Interval punctualSpan ( false );
if ( _segment->base()->getAutoSource()->getAnchor() ) {
ltrace(200) << " | " << _segment->base()->getAutoSource() << endl;
Interval constraints ( _segment->base()->getAutoSource()->getUConstraints
(Constant::perpandicular(_segment->getDirection())) );
ltrace(200) << " | Constraints: " << constraints << endl;
minSpan = min ( minSpan, constraints.getVMax() );
maxSpan = max ( maxSpan, constraints.getVMin() );
punctualSpan.intersection ( constraints );
}
if ( _segment->base()->getAutoTarget()->getAnchor() ) {
ltrace(200) << " | " << _segment->base()->getAutoTarget() << endl;
Interval constraints ( _segment->base()->getAutoTarget()->getUConstraints
(Constant::perpandicular(_segment->getDirection())) );
ltrace(200) << " | Constraints: " << constraints << endl;
minSpan = min ( minSpan, constraints.getVMax() );
maxSpan = max ( maxSpan, constraints.getVMin() );
punctualSpan.intersection ( constraints );
}
const vector<TrackElement*>& perpandiculars = _event->getPerpandiculars();
for ( size_t i=0 ; i<perpandiculars.size() ; i++ ) {
DataNegociate* data2 = perpandiculars[i]->getDataNegociate();
if ( !data2 ) continue;
ltrace(200) << " | " << perpandiculars[i] << endl;
if ( data2->getGCellOrder() < Session::getOrder() ) {
ltrace(200) << "Reject: bad order." << endl;
continue;
}
RoutingEvent* event2 = data2->getRoutingEvent();
if ( !event2 ) continue;
ltrace(200) << " | Constraints: " << event2->getConstraints() << endl;
minSpan = min ( minSpan, event2->getConstraints().getVMax() );
maxSpan = max ( maxSpan, event2->getConstraints().getVMin() );
punctualSpan.intersection ( event2->getConstraints() );
}
if ( minSpan > maxSpan ) swap ( minSpan, maxSpan );
ltrace(200) << "punctualSpan: " << punctualSpan
<< " min/max span: [" << DbU::getValueString(minSpan)
<< ":" << DbU::getValueString(minSpan) << "]" << endl;
vector<Interval> holes;
for ( size_t itrack=0 ; itrack<_S.getCosts().size() ; itrack++ ) {
size_t begin = _S.getBegin(itrack);
size_t end = _S.getEnd (itrack);
Track* track = _S.getTrack(itrack);
if ( end < track->getSize() ) end++;
ltrace(200) << "Looking for holes in " << _S.getCost(itrack) << endl;
TrackElement* otherPrevious = NULL;
// ToDo: Manage disjoint but subsequent segment of a Net.
// (currently, that hole will not be found).
for ( ; begin < end ; begin++ ) {
TrackElement* otherSegment = track->getSegment(begin);
if ( otherSegment->getNet() == _segment->getNet() ) continue;
if ( !otherPrevious ) {
holes.push_back ( Interval(track->getMin()
,otherSegment->getSourceU()) );
ltrace(200) << "| First hole: " << holes.back() << " " << otherSegment << endl;
} else {
if ( otherSegment->getNet() == otherPrevious->getNet() ) continue;
holes.push_back ( Interval(otherPrevious->getTargetU()
,otherSegment ->getSourceU()) );
ltrace(200) << "| Found hole: " << holes.back()
<< " " << otherPrevious << " <-> " << " " << otherSegment << endl;
}
otherPrevious = otherSegment;
}
}
if ( holes.empty() ) {
ltrace(200) << "No holes found to minimize into." << endl;
return false;
}
Interval currentSpan = _segment->getCanonicalInterval();
Interval biggestHole;
for ( size_t i=0 ; i<holes.size() ; i++ ) {
if ( currentSpan.getIntersection(holes[i] ).getSize()
> currentSpan.getIntersection(biggestHole).getSize() )
biggestHole = holes[i];
}
if ( !punctualSpan.isEmpty() ) {
bool success = false;
if ( biggestHole.intersect(punctualSpan) ) {
ltrace(200) << "Go as punctual into biggest hole: " << biggestHole << endl;
success = true;
} else {
for ( size_t i=0 ; i<holes.size() ; i++ ) {
ltrace(200) << "Trying secondary hole: " << holes[i] << endl;
if ( holes[i].intersect(punctualSpan) ) {
biggestHole = holes[i];
ltrace(200) << "Go as punctual into secondary hole: " << biggestHole << endl;
success = true;
}
}
}
if ( !success ) {
ltrace(200) << "No suitable hole found." << endl;
return false;
}
} else {
biggestHole.intersection ( Interval(minSpan,maxSpan) );
if ( biggestHole.isEmpty() ) {
ltrace(200) << "Biggest hole is empty (under span ["
<< DbU::getValueString(minSpan) << " "
<< DbU::getValueString(maxSpan) << "])" << endl;
return false;
} else {
ltrace(200) << "Go into biggest hole: " << biggestHole << endl;
}
}
DbU::Unit axisHint = biggestHole.intersection(punctualSpan).getCenter();
ltrace(200) << "Axis Hint: " << DbU::getValueString(axisHint) << endl;
for ( size_t i=0 ; i<perpandiculars.size() ; i++ ) {
DataNegociate* data2 = perpandiculars[i]->getDataNegociate();
if ( !data2 ) continue;
ltrace(200) << " | " << perpandiculars[i] << endl;
if ( data2->getGCellOrder() < Session::getOrder() ) continue;
RoutingEvent* event2 = data2->getRoutingEvent();
if ( !event2 ) continue;
_S.addAction ( perpandiculars[i], SegmentAction::SelfRipupAndAxisHint, axisHint );
}
_event->setMinimized ();
return true;
}
bool Manipulator::relax ( size_t i )
{
ltrace(200) << "Manipulator::relax() " << _segment << endl;
if ( /* _segment->base()->isGlobal()
||*/ _segment->isFixed()
|| ( _segment->getDogLegLevel() > 0 )
|| ( _segment->getLength() < DbU::lambda(10.0) )
|| !_segment->canDogLegAt(_segment->getGCell()) )
return false;
TrackElement* perpandicular
= _segment->makeDogLeg ( Session::lookup(_segment->base()->getAutoSource()->getGCell()) );
if ( perpandicular ) {
RoutingEvent* event = perpandicular->getDataNegociate()->getRoutingEvent();
if ( event ) {
TrackCost& cost = _S.getCost(i);
Interval optimal = cost.getInterval();
event->setOptimalAxis ( optimal.inflate( - Session::getExtensionCap() ) );
} else {
cerr << Bug("New dog leg without active RoutingEvent.\n "
"%s",getString(perpandicular).c_str()) << endl;
}
}
return true;
}
void Manipulator::reprocessPerpandiculars ()
{
if ( _event->getAxisHistory() == _event->getAxisHint() ) return;
bool moveLeft = (_event->getAxisHistory() > _event->getAxisHint());
const vector<TrackElement*>& perpandiculars = _event->getPerpandiculars();
for ( size_t iperpand=0 ; iperpand<perpandiculars.size() ; iperpand++ ) {
TrackElement* perpandicular = perpandiculars[iperpand];
DataNegociate* data = perpandicular->getDataNegociate();
if ( perpandicular->isFixed() ) continue;
if ( not data or (data->getGCellOrder() != Session::getOrder()) ) continue;
if ( not perpandicular->getTrack() ) continue;
if ( not Manipulator(perpandicular,_S).canRipup()
or (data->getState() >= DataNegociate::MaximumSlack) ) continue;
// Ugly: ExtensionCap usage.
if ( moveLeft ) {
if ( perpandicular->getTargetU()-Session::getExtensionCap() == _event->getAxisHistory() )
_S.addAction ( perpandicular, SegmentAction::OtherPacking );
} else {
if ( perpandicular->getSourceU()+Session::getExtensionCap() == _event->getAxisHistory() )
_S.addAction ( perpandicular, SegmentAction::OtherPacking );
}
}
}
// -------------------------------------------------------------------
// Local Functions.
} // End of anonymous namespace.
namespace Kite {
using std::cerr;
using std::endl;
using std::setw;
using std::min;
using Hurricane::tab;
using Hurricane::inltrace;
using Hurricane::ltracein;
using Hurricane::ltraceout;
using Hurricane::DebugSession;
using Hurricane::Bug;
using Hurricane::ForEachIterator;
using Hurricane::Net;
using Hurricane::Layer;
// -------------------------------------------------------------------
// Class : "RoutingEvent::Compare".
bool RoutingEvent::Compare::operator() ( const RoutingEvent* lhs, const RoutingEvent* rhs ) const
{
//if ( !lhs->isValid() ) const_cast<RoutingEvent*>(lhs)->revalidate ();
//if ( !rhs->isValid() ) const_cast<RoutingEvent*>(rhs)->revalidate ();
//unsigned int lhsDepth = Session::getRoutingGauge()->getLayerDepth(lhs->getSegment()->getLayer());
//unsigned int rhsDepth = Session::getRoutingGauge()->getLayerDepth(rhs->getSegment()->getLayer());
//if ( lhsDepth > rhsDepth ) return true;
//if ( lhsDepth < rhsDepth ) return false;
if ( lhs == rhs ) return false;
return RoutingEvent::Key::Compare() ( lhs->getKey(), rhs->getKey() );
// if ( lhs->getEventLevel() < rhs->getEventLevel() ) return true;
// if ( lhs->getEventLevel() > rhs->getEventLevel() ) return false;
// // Uses static ordering.
// if ( lhs->getTracksNb() < rhs->getTracksNb() ) return false;
// if ( lhs->getTracksNb() > rhs->getTracksNb() ) return true;
// if ( lhs->getPriority() < rhs->getPriority() ) return false;
// if ( lhs->getPriority() > rhs->getPriority() ) return true;
// //return false;
// // For debugging purpose only: ensure a reproductible sort. Could be removed.
// //bool segmentCompare = TrackElement::CompareByPosition() ( lhs->getSegment(), rhs->getSegment() );
// //return (segmentCompare or ((void*)lhs < (void*)rhs));
// return ((void*)lhs < (void*)rhs);
}
// -------------------------------------------------------------------
// Class : "RoutingEvent::Key".
bool RoutingEvent::Key::Compare::operator() ( const RoutingEvent::Key& lhs, const RoutingEvent::Key& rhs ) const
{
//if ( lhs._ring xor rhs._ring ) return lhs._ring;
if ( lhs._eventLevel < rhs._eventLevel ) return true;
if ( lhs._eventLevel > rhs._eventLevel ) return false;
if ( lhs._canRipple xor rhs._canRipple ) return rhs._canRipple;
//if ( lhs._slackenStrap xor rhs._slackenStrap ) return lhs._slackenStrap;
// Uses static ordering.
//if ( lhs._tracksNb < rhs._tracksNb ) return false;
//if ( lhs._tracksNb > rhs._tracksNb ) return true;
if ( lhs._priority < rhs._priority ) return false;
if ( lhs._priority > rhs._priority ) return true;
if ( lhs._length < rhs._length ) return true;
if ( lhs._length > rhs._length ) return false;
if ( lhs._isHorizontal xor rhs._isHorizontal ) return rhs._isHorizontal;
if ( lhs._axis > rhs._axis ) return true;
if ( lhs._axis < rhs._axis ) return false;
if ( lhs._sourceU > rhs._sourceU ) return true;
if ( lhs._sourceU < rhs._sourceU ) return false;
if ( lhs._net->getName() != rhs._net->getName() )
return lhs._net->getName() < rhs._net->getName();
return lhs._id < rhs._id;
}
RoutingEvent::Key::Key ( const RoutingEvent* event )
: _slackenStrap(event->getSegment()->isSlackenStrap())
, _isHorizontal(event->getSegment()->isHorizontal())
, _canRipple (event->getSegment()->canRipple())
, _tracksNb (event->getTracksNb())
, _priority (event->getPriority())
, _eventLevel (event->getEventLevel())
, _length (event->getSegment()->getLength())
, _axis (event->getSegment()->getAxis())
, _sourceU (event->getSegment()->getSourceU())
, _net (event->getSegment()->getNet())
, _id (event->getSegment()->getId())
{ }
void RoutingEvent::Key::update ( const RoutingEvent* event )
{
if ( !event ) return;
_slackenStrap = event->getSegment()->isSlackenStrap();
_canRipple = event->getSegment()->canRipple();
_tracksNb = event->getTracksNb();
_priority = event->getPriority();
_eventLevel = event->getEventLevel();
_length = event->getSegment()->getLength();
_axis = event->getSegment()->getAxis();
_sourceU = event->getSegment()->getSourceU();
_id = event->getSegment()->getId();
}
// -------------------------------------------------------------------
// Class : "RoutingEvent".
size_t RoutingEvent::_allocateds = 0;
size_t RoutingEvent::_processeds = 0;
size_t RoutingEvent::_cloneds = 0;
size_t RoutingEvent::getAllocateds () { return _allocateds; }
size_t RoutingEvent::getProcesseds () { return _processeds; }
size_t RoutingEvent::getCloneds () { return _cloneds; }
void RoutingEvent::resetProcesseds () { _processeds = 0; }
RoutingEvent::RoutingEvent ( TrackElement* segment, unsigned int mode )
: _cloned (false)
, _processed (false)
, _disabled (false)
, _valid (false)
, _validConstraints (false)
, _validPerpandiculars (false)
, _canHandleConstraints(false)
, _minimized (false)
, _forceToHint (false)
, _segment (segment)
, _axisHistory (segment->getAxis())
, _axisHint (segment->getAxis())
, _optimalAxis (false)
, _constraints ()
, _optimal ()
, _perpandicular (false)
, _shearGCell (NULL)
, _tracksNb (0)
, _tracksFree (0)
, _insertState (0)
, _mode (mode)
, _rippleState (0)
, _eventLevel (0)
, _priority (0.0)
, _perpandiculars ()
, _key (this)
{
DataNegociate* data = _segment->getDataNegociate();
if ( data )
data->setRoutingEvent ( this );
// Interval optimal;
// _segment->base()->getOptimal ( optimal );
// _axisHint = optimal.getCenter();
invalidate ( true );
ltrace(180) << "create: " << (void*)this << ":" << this << endl;
ltrace(200) << "Initial setAxisHint @" << DbU::getValueString(_axisHint) << endl;
if ( _segment->getTrack() ) {
cerr << Bug("RoutingEvent::create() - TrackElement is already inserted in a Track."
"\n %s."
,getString(_segment).c_str()
) << endl;
}
}
RoutingEvent* RoutingEvent::create ( TrackElement* segment, unsigned int mode )
{
RoutingEvent* event = new RoutingEvent ( segment, mode );
++_allocateds;
return event;
}
RoutingEvent* RoutingEvent::clone () const
{
_cloned = true;
RoutingEvent* clone = new RoutingEvent ( *this );
++_allocateds;
++_cloneds;
clone->_cloned = false;
clone->_disabled = false;
clone->_eventLevel = 0;
ltrace(200) << "RoutingEvent::clone() " << (void*)clone << ":" << clone
<< " (from: " << (void*)this << ")" << endl;
return clone;
}
RoutingEvent::~RoutingEvent ()
{
ltrace(180) << "~RoutingEvent() " << (void*)this << endl;
DataNegociate* data = _segment->getDataNegociate();
if ( data and ( data->getRoutingEvent() == this ) )
data->setRoutingEvent ( NULL );
}
void RoutingEvent::destroy ()
{
ltrace(180) << "RoutingEvent::destroy() " << (void*)this << ":" << this << endl;
if ( _allocateds > 0 ) --_allocateds;
delete this;
}
bool RoutingEvent::isUnimplemented () const
{ return getState() == DataNegociate::Unimplemented; }
unsigned int RoutingEvent::getState () const
{
DataNegociate* data = _segment->getDataNegociate();
if ( not data ) return 0;
return data->getState();
}
void RoutingEvent::setState ( unsigned int state )
{
DataNegociate* data = _segment->getDataNegociate();
if ( not data ) return;
data->setState ( state );
}
void RoutingEvent::setEventLevel ( unsigned int level )
{ _eventLevel = level; }
void RoutingEvent::setAxisHint ( DbU::Unit axis )
{
ltrace(200) << "setAxisHint @" << DbU::getValueString(axis) << " " << _segment << endl;
_axisHint = axis;
}
long RoutingEvent::getAxisWeight ( DbU::Unit axis ) const
{ return abs(axis - _axisHint); }
RoutingEvent* RoutingEvent::reschedule ( RoutingEventQueue& queue, unsigned int eventLevel )
{
RoutingEvent* active = _segment->getDataNegociate()->getRoutingEvent();
if ( active != this )
return active->reschedule ( queue, eventLevel );
RoutingEvent* fork = NULL;
if ( isUnimplemented() ) {
ltrace(200) << "Reschedule: cancelled (Unimplemented) "
<< (void*)this << " -> " << (void*)fork << ":" << fork << endl;
return NULL;
}
if ( not isProcessed() ) {
fork = this;
ltrace(200) << "Reschedule/Self: "
<< (void*)this << " -> "
<< (void*)fork << ":" << eventLevel << ":" << fork << endl;
} else {
fork = clone();
fork->_processed = false;
_segment->getDataNegociate()->setRoutingEvent ( fork );
ltrace(200) << "Reschedule/Fork: "
<< (void*)this << " -> " << (void*)fork << ":" << fork << endl;
}
if ( fork->_eventLevel < eventLevel )
fork->_eventLevel = eventLevel;
queue.repush ( fork );
return fork;
}
void RoutingEvent::setSegment ( TrackElement* segment )
{
if ( _segment )
_segment->getDataNegociate()->setRoutingEvent ( NULL );
_segment = segment;
_segment->getDataNegociate()->setRoutingEvent ( this );
invalidate ( true, true );
}
void RoutingEvent::process ( RoutingEventQueue& queue, RoutingEventHistory& history )
{
DebugSession::open ( _segment->getNet(), 200 );
#if defined(CHECK_DETERMINISM)
cerr << "Order: "
<< getProcesseds()
<< "," << getEventLevel()
<< "," << setw(6) << getPriority()
<< " " << setw(6) << DbU::getValueString(_segment->getLength())
<< " " << _segment->isHorizontal()
<< " " << setw(6) << DbU::getValueString(_segment->getAxis())
<< " " << setw(6) << DbU::getValueString(_segment->getSourceU())
<< ": " << _segment << endl;
#endif
_processeds++;
ltrace(210) << "Event:" << _processeds << " " << this << endl;
ltracein(200);
ltrace(200) << "State: *before* "
<< DataNegociate::getStateString(_segment->getDataNegociate())
<< " ripup:" << _segment->getDataNegociate()->getRipupCount()
<< endl;
ltrace(149) << "Level: " << getEventLevel()
<< ", area: " << _segment->getArea() << endl;
_preCheck(_segment);
_eventLevel = 0;
if ( _mode < PostPack ) history.push ( this );
if ( isProcessed() || isDisabled() ) {
ltrace(200) << "Already processed or disabled." << endl;
} else {
setProcessed ();
switch ( _mode ) {
case Negociate: _processNegociate ( queue, history ); break;
case Pack:
case PostPack: _processPacking ( queue, history ); break;
default:
cerr << Bug("RoutingEvent::process() - Unknown mode value:%d.",_mode) << endl;
break;
}
}
#if defined(CHECK_DATABASE)
Session::getKiteEngine()->_check ( _segment->getNet() );
#endif
ltraceout(200);
queue.repushInvalidateds ();
Session::revalidate ();
queue.commit ();
_postCheck(_segment);
DebugSession::close ();
if ( Session::getKiteEngine()->getPostEventCb() != NULL )
Session::getKiteEngine()->getPostEventCb() ();
}
void RoutingEvent::_processNegociate ( RoutingEventQueue& queue, RoutingEventHistory& history )
{
ltrace(200) << "* Mode:Negociation." << endl;
State S ( this, queue, history );
if ( S.getHistory().looping() ) {
cerr << Error("RoutingEvent::process() - Simple Loop detection triggered.") << endl;
setState ( DataNegociate::Unimplemented );
S.getHistory().dump ( cerr, 40 );
return;
}
if ( S.getState() == State::MissingData ) {
cerr << Error("RoutingEvent::process() - Missing datas.") << endl;
return;
}
ltracein(200);
S.getData()->incRipupCount ();
size_t itrack = 0;
for ( itrack = 0 ; itrack < S.getCosts().size() ; itrack++ )
ltrace(200) << "| " << S.getCost(itrack) << endl;
itrack = 0;
if ( isForcedToHint() ) {
// Try to honor the forced axis hint.
bool hintFound = false;
for ( ; itrack < S.getCosts().size() ; itrack++ ) {
if ( S.getCost(itrack).getTrack()->getAxis() == _axisHint ) {
hintFound = true;
break;
}
}
if ( !hintFound ) itrack = 0;
ltrace(200) << "Forcing to hint Track: " << itrack << endl;
}
if ( Manipulator(_segment,S).canRipup() ) {
if ( S.getCosts().size() and S.getCost(itrack).isFree() ) {
// Track is free: insertion.
ltrace(200) << "Insert in free space " << this << endl;
resetInsertState ();
_axisHistory = _segment->getAxis();
_eventLevel = 0;
Session::addInsertEvent ( _segment, S.getCost(itrack).getTrack() );
Manipulator(_segment,S).reprocessPerpandiculars ();
S.setState ( State::SelfInserted );
} else {
// Do ripup.
if ( S.getState() == State::EmptyTrackList ) {
Manipulator(_segment,S).ripupPerpandiculars ();
} else {
for ( itrack=0 ; itrack<S.getCosts().size() ; itrack++ ) {
if ( S.getCost(itrack).isInfinite() ) break;
if ( S.insertInTrack(itrack) ) break;
resetInsertState ();
}
//if ( S.getCosts().size() and not S.getCost(itrack).isInfinite() )
// S.insertInTrack ( itrack );
if ( S.getState() != State::OtherRipup ) {
S.slackenTopology ( _segment );
}
}
}
} else {
// Ripup limit has been reached.
if ( not S.slackenTopology ( _segment ) ) {
S.setState ( State::SelfMaximumRipup );
}
}
S.doActions ();
if ( itrack < S.getCosts().size() ) {
ltrace(200) << "Placed: @" << DbU::getValueString(S.getCost(itrack).getTrack()->getAxis())
<< " " << (void*)this << ":" << this << endl;
}
ltraceout(200);
}
void RoutingEvent::_processPacking ( RoutingEventQueue& queue, RoutingEventHistory& history )
{
ltrace(200) << "* Mode:Packing." << endl;
if ( _segment->getTrack() != NULL ) {
ltrace(200) << "* Cancel: already in Track." << endl;
return;
}
// if ( !_canHandleConstraints ) {
// ltrace(200) << "* Cancel: cannot handle constraints." << endl;
// return;
// }
State S ( this, queue, history );
if ( S.getState() == State::MissingData ) return;
if ( S.getState() == State::EmptyTrackList ) return;
ltracein(200);
for ( size_t i = 0 ; i < S.getCosts().size() ; i++ )
ltrace(200) << "| " << S.getCost(i) << endl;
ltraceout(200);
if ( S.getCosts().size() and S.getCost(0).isFree() ) {
ltrace(200) << "Insert in free space." << endl;
Session::addInsertEvent ( _segment, S.getCost(0).getTrack() );
S.setState ( State::SelfInserted );
} else {
ltrace(200) << "Packing failed." << endl;
if ( _mode == Pack ) {
_mode = Negociate;
S.addAction ( _segment, SegmentAction::SelfInsert );
S.doActions ();
}
}
}
void RoutingEvent::revalidate ( bool force )
{
if ( _valid and not force ) return;
DebugSession::open ( _segment->getNet(), 148 );
ltrace(200) << "RoutingEvent::revalidate() - " << (void*)this << ":" << this << endl;
ltracein(200);
ltrace(200) << "axisHint:" << DbU::getValueString(_axisHint) << endl;
_canHandleConstraints = true;
if ( /*!_validConstraints*/ true ) {
_segment->base()->getConstraints ( _constraints );
_segment->base()->getOptimal ( _optimal );
ltrace(200) << "| Raw Track Constraint: " << _constraints << endl;
_validConstraints = true;
}
if ( !_validPerpandiculars ) {
TrackElement* perpandicular;
Interval canonical;
_perpandiculars.clear ();
forEach ( AutoSegment*, isegment, _segment->base()->getCollapsedPerpandiculars() ) {
ltrace(200) << "| perpandicular " << *isegment << endl;
perpandicular = Session::lookup ( isegment->getCanonical(canonical)->base() );
if ( !perpandicular ) continue;
_perpandiculars.push_back ( perpandicular );
}
_validPerpandiculars = true;
if ( not _segment->isTerminal() and (_perpandiculars.size() < 2) )
cerr << Bug("Less than two perpandiculars on %s.",getString(_segment).c_str()) << endl;
}
ltrace(200) << "| Track Constraint: " << _constraints << endl;
_perpandicular = _constraints;
DataNegociate* dataPerpandicular;
for ( size_t i=0 ; i<_perpandiculars.size() ; i++ ) {
dataPerpandicular = _perpandiculars[i]->getDataNegociate();
if ( !dataPerpandicular ) {
ltrace(200) << "| No data " << _perpandiculars[i] << endl;
continue;
}
if ( _perpandiculars[i]->getTrack() ) {
Interval trackFree = _perpandiculars[i]->getFreeInterval( false );
ltrace(200) << "| From " << _perpandiculars[i] << endl;
ltrace(200) << "| Track Perpandicular Free: " << trackFree << endl;
_perpandicular.intersection ( trackFree );
if ( dataPerpandicular->getGCellOrder() < Session::getOrder() )
_constraints.intersection ( trackFree );
} else {
ltrace(200) << "| Not in any track " << _perpandiculars[i] << endl;
}
}
_tracksNb = 0;
ltrace(200) << "| Perpandicular Free: " << _perpandicular << endl;
if ( !_perpandicular.isEmpty() ) {
RoutingPlane* plane = Session::getKiteEngine()->getRoutingPlaneByLayer(_segment->getLayer());
Track* track = plane->getTrackByPosition(_perpandicular.getVMin());
if ( track && (track->getAxis() < _perpandicular.getVMin()) ) track = track->getNext();
for ( ; track && (track->getAxis() <= _perpandicular.getVMax())
; track = track->getNext(), _tracksNb++ );
}
if ( not _tracksNb ) {
ltrace(200) << "| Reverting to pure constraints." << endl;
RoutingPlane* plane = Session::getKiteEngine()->getRoutingPlaneByLayer(_segment->getLayer());
Track* track = plane->getTrackByPosition(_constraints.getVMin());
if ( track && (track->getAxis() < _constraints.getVMin()) ) track = track->getNext();
for ( ; track && (track->getAxis() <= _constraints.getVMax())
; track = track->getNext(), _tracksNb++ );
_canHandleConstraints = false;
}
if ( not _tracksNb ) {
ltrace(200) << "| Pure constraints are too tight." << endl;
//_segment->base()->getConstraints ( _constraints );
_canHandleConstraints = false;
}
_priority
= (DbU::getLambda(_segment->getLength()) + 1.0)
* (DbU::getLambda(_segment->base()->getSlack()) + 1.0);
//_priority = (DbU::getLambda(_segment->getLength()) + 1.0) * (float)(_tracksNb+1);
//_priority = (float)_segment->getArea();
_valid = true;
ltrace(200) << _segment << " has " << _tracksNb << " choices " << _perpandicular << endl;
ltraceout(200);
DebugSession::close();
}
string RoutingEvent::_getTypeName () const
{ return "RoutingEvent"; }
string RoutingEvent::_getString () const
{
string s = "<" + _getTypeName();
s += " " + getString(_eventLevel);
s += "," + getString((long)getPriority());
s += " @" + DbU::getValueString(getAxisHistory());
s += ":" + getString(_segment);
s += " " + getString(_segment->getDataNegociate()->getRipupCount());
s += " ";
s += (isCloned ()?"C":"-");
s += (isDisabled ()?"d":"-");
s += (isUnimplemented()?"u":"-");
s += ">";
return s;
}
Record* RoutingEvent::_getRecord () const
{
Record* record = new Record ( getString(this) );
record->add ( getSlot ( "_segment" , _segment ) );
record->add ( getSlot ( "_processed" , _processed ) );
return record;
}
} // End of Kite namespace.