2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
// -*- C++ -*-
|
|
|
|
//
|
|
|
|
// This file is part of the Coriolis Software.
|
2010-04-23 08:14:17 -05:00
|
|
|
// Copyright (c) UPMC/LIP6 2008-2010, All Rights Reserved
|
2010-03-09 09:24:55 -06:00
|
|
|
//
|
|
|
|
// ===================================================================
|
|
|
|
//
|
|
|
|
// $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 & 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 & 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 )
|
|
|
|
{
|
2010-06-01 16:35:20 -05:00
|
|
|
if (i >= _conflicts.size()) return Interval();
|
2010-03-09 09:24:55 -06:00
|
|
|
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 };
|
2010-04-23 08:14:17 -05:00
|
|
|
enum { NoRingLimit=1 };
|
2010-03-09 09:24:55 -06:00
|
|
|
public:
|
|
|
|
Manipulator ( TrackElement*, State& );
|
|
|
|
~Manipulator ();
|
|
|
|
inline TrackElement* getSegment () const;
|
|
|
|
inline DataNegociate* getData () const;
|
|
|
|
inline RoutingEvent* getEvent () const;
|
2010-04-23 08:14:17 -05:00
|
|
|
bool canRipup ( unsigned int flags=0 ) const;
|
2010-03-09 09:24:55 -06:00
|
|
|
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 ();
|
2010-05-03 04:16:50 -05:00
|
|
|
bool makeDogLeg ( DbU::Unit );
|
2010-03-09 09:24:55 -06:00
|
|
|
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();
|
2010-04-28 10:44:07 -05:00
|
|
|
bool canMoveUp = (segment->isLocal()) ? segment->canPivotUp(0.5) : segment->canMoveUp(0.5);
|
2010-03-09 09:24:55 -06:00
|
|
|
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 ) {
|
2010-04-12 06:24:57 -05:00
|
|
|
Track* track = candidates[icandidate].getTrack();
|
|
|
|
TrackElement* other = track->getSegment(candidates[icandidate].getBegin());
|
|
|
|
|
|
|
|
if ( other->isGlobal()
|
|
|
|
and (other->getDataNegociate()->getGCellOrder() == Session::getOrder())
|
2010-04-28 10:44:07 -05:00
|
|
|
and other->canMoveUp(0.5) ) {
|
2010-04-12 06:24:57 -05:00
|
|
|
ltrace(200) << "conflictSolve1() - One conflict, other move up" << endl;
|
|
|
|
if ( (success = other->moveUp()) ) break;
|
|
|
|
}
|
|
|
|
|
2010-03-09 09:24:55 -06:00
|
|
|
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() )
|
|
|
|
|
2010-05-03 04:16:50 -05:00
|
|
|
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) ) {
|
2010-03-09 09:24:55 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-03 04:16:50 -05:00
|
|
|
if ( candidate ) {
|
|
|
|
ltrace(200) << "> Accept candidate " << candidate << endl;
|
2010-03-09 09:24:55 -06:00
|
|
|
candidates.push_back ( LvGCandidate(candidate,otherOverlap,terminals) );
|
2010-05-03 04:16:50 -05:00
|
|
|
}
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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 )
|
|
|
|
{
|
2010-04-17 05:14:46 -05:00
|
|
|
DebugSession::open ( segment->getNet(), 200 );
|
2010-04-12 06:24:57 -05:00
|
|
|
|
2010-04-23 08:14:17 -05:00
|
|
|
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;
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
ltrace(200) << "Slacken Topology for " << segment->getNet()
|
|
|
|
<< " " << segment << endl;
|
|
|
|
ltracein(200);
|
|
|
|
|
2010-04-12 06:24:57 -05:00
|
|
|
if ( (not segment) or (not data) ) { ltraceout(200); DebugSession::close(); return false; }
|
2010-03-09 09:24:55 -06:00
|
|
|
if ( segment == _event->getSegment() ) _event->resetInsertState();
|
|
|
|
|
|
|
|
if ( not (data->isBorder() or data->isRing()) ) {
|
|
|
|
data->resetRipupCount ();
|
|
|
|
} else {
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not Manipulator(segment,*this).canRipup(Manipulator::NoRingLimit) ) {
|
2010-03-09 09:24:55 -06:00
|
|
|
cerr << "[UNSOLVED] " << segment << " slacken topology not allowed for border/ring." << endl;
|
|
|
|
ltraceout(200);
|
2010-04-12 06:24:57 -05:00
|
|
|
DebugSession::close ();
|
2010-03-09 09:24:55 -06:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ring cases.
|
|
|
|
if ( data->isBorder() ) {
|
|
|
|
ltrace(200) << "Segment is Ripup only (border), bypass to Unimplemented." << endl;
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not Manipulator(segment,*this).canRipup (Manipulator::NoRingLimit) ) {
|
2010-03-09 09:24:55 -06:00
|
|
|
ltrace(200) << "Cannot ripup, bypass to Unimplemented." << endl;
|
|
|
|
data->setState ( DataNegociate::Unimplemented );
|
|
|
|
} else {
|
|
|
|
ltrace(200) << "Refusing to slacken border segment." << endl;
|
|
|
|
ltraceout(200);
|
2010-04-12 06:24:57 -05:00
|
|
|
DebugSession::close ();
|
2010-03-09 09:24:55 -06:00
|
|
|
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() ) {
|
2010-04-23 08:14:17 -05:00
|
|
|
ltrace(200) << "Strap segment FSM." << endl;
|
2010-03-09 09:24:55 -06:00
|
|
|
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.
|
2010-04-23 08:14:17 -05:00
|
|
|
ltrace(200) << "Local segment FSM." << endl;
|
2010-03-09 09:24:55 -06:00
|
|
|
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() ) {
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( (nextState < DataNegociate::MaximumSlack) or (data->getStateCount() < 2) ) {
|
2010-03-09 09:24:55 -06:00
|
|
|
nextState = DataNegociate::MaximumSlack;
|
|
|
|
success = conflictSolve1 ();
|
|
|
|
if ( success ) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case DataNegociate::Unimplemented:
|
|
|
|
nextState = DataNegociate::Unimplemented;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( not success and (nextState != DataNegociate::Unimplemented) ) {
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( data->getStateCount() < 6 )
|
|
|
|
success = Manipulator(segment,*this).ripupPerpandiculars(Manipulator::ToRipupLimit);
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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() ) {
|
2010-04-23 08:14:17 -05:00
|
|
|
ltrace(200) << "Global segment FSM." << endl;
|
2010-03-09 09:24:55 -06:00
|
|
|
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;
|
|
|
|
}
|
2010-05-03 04:16:50 -05:00
|
|
|
nextState = DataNegociate::MaximumSlack;
|
|
|
|
break;
|
2010-03-09 09:24:55 -06:00
|
|
|
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) ) {
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( data->getStateCount() < 6 )
|
|
|
|
success = Manipulator(segment,*this).ripupPerpandiculars(Manipulator::ToRipupLimit);
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( not (flags&NoTransition) ) data->setState ( nextState );
|
|
|
|
|
|
|
|
if ( success ) {
|
|
|
|
if ( repush ) {
|
|
|
|
if ( not (data->isRing() or data->isBorder()) )
|
2010-04-23 08:14:17 -05:00
|
|
|
actionFlags |= SegmentAction::ResetRipup;
|
2010-03-09 09:24:55 -06:00
|
|
|
|
2010-04-23 08:14:17 -05:00
|
|
|
addAction ( segment, actionFlags );
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
clearActions ();
|
|
|
|
if ( data->getState() == DataNegociate::Unimplemented ) {
|
|
|
|
cerr << "[UNSOLVED] " << segment << " unable to slacken topology." << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ltraceout(200);
|
2010-04-12 06:24:57 -05:00
|
|
|
DebugSession::close ();
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
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.");
|
|
|
|
|
2010-04-17 05:14:46 -05:00
|
|
|
DebugSession::open ( _segment->getNet(), 200 );
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
_data = _segment->getDataNegociate();
|
|
|
|
if ( _data )
|
|
|
|
_event = _data->getRoutingEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Manipulator::~Manipulator ()
|
|
|
|
{
|
|
|
|
DebugSession::close ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-23 08:14:17 -05:00
|
|
|
bool Manipulator::canRipup ( unsigned int flags ) const
|
2010-03-09 09:24:55 -06:00
|
|
|
{
|
|
|
|
if ( _data ) {
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not _event or _event->isUnimplemented() ) return false;
|
|
|
|
|
2010-03-09 09:24:55 -06:00
|
|
|
unsigned int limit = Session::getKiteEngine()->getRipupLimit(_segment);
|
2010-04-23 08:14:17 -05:00
|
|
|
|
|
|
|
if ( not ( flags & NoRingLimit )
|
|
|
|
and (_data->isRing() or _data->isBorder())
|
|
|
|
and not (_data->getRipupCount() < limit) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return (_data->getRipupCount() < limit);
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not canRipup() ) return false;
|
|
|
|
|
2010-03-09 09:24:55 -06:00
|
|
|
if ( _segment->isFixed() ) return false;
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( _data == NULL ) return true;
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
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++;
|
2010-04-23 08:14:17 -05:00
|
|
|
|
|
|
|
// Try to ripup the perpandicular itself.
|
2010-03-09 09:24:55 -06:00
|
|
|
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 );
|
2010-04-23 08:14:17 -05:00
|
|
|
|
|
|
|
if ( Manipulator(perpandiculars[i],_S).ripup(_event->getSegment()->getAxis()
|
|
|
|
,perpandicularActionFlags) )
|
|
|
|
continue;
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
2010-04-23 08:14:17 -05:00
|
|
|
// Cannot ripup the perpandicular, try to ripup it's neigbors.
|
2010-03-09 09:24:55 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-04-23 08:14:17 -05:00
|
|
|
// 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;
|
|
|
|
}
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 ) {
|
2010-04-23 08:14:17 -05:00
|
|
|
ltrace(200) << "No placed perpandiculars, tight native constraints, place perpandiculars FIRST." << endl;
|
2010-03-09 09:24:55 -06:00
|
|
|
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;
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not interval.intersect(_segment->getCanonicalInterval()) ) return false;
|
|
|
|
if ( not _data ) return false;
|
|
|
|
//if ( _data->isBorder() or _data->isRing() ) return false;
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
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;
|
2010-05-03 04:16:50 -05:00
|
|
|
TrackElement* segment1 = NULL;
|
|
|
|
TrackElement* segment2 = NULL;
|
|
|
|
Track* track = _segment->getTrack();
|
|
|
|
GCell* dogLegGCell = gcells[ifirstDogleg];
|
|
|
|
TrackElement* dogleg = NULL;
|
2010-03-09 09:24:55 -06:00
|
|
|
DbU::Unit doglegAxis;
|
2010-05-03 04:16:50 -05:00
|
|
|
bool doglegReuse1 = false;
|
|
|
|
bool doglegReuse2 = false;
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
// Try to reuse existing dogleg if broken at either end.
|
2010-05-03 04:16:50 -05:00
|
|
|
if ( ifirstDogleg == 0 ) dogleg = _segment->getSourceDogLeg();
|
|
|
|
if ( ifirstDogleg == gcells.size()-1 ) dogleg = _segment->getTargetDogLeg();
|
2010-03-09 09:24:55 -06:00
|
|
|
if ( dogleg ) {
|
|
|
|
ltrace(200) << "Reusing dogleg." << endl;
|
2010-05-03 04:16:50 -05:00
|
|
|
doglegReuse1 = true;
|
|
|
|
segment1 = _segment;
|
2010-03-09 09:24:55 -06:00
|
|
|
} else {
|
|
|
|
// Try to create a new dogleg.
|
2010-05-03 04:16:50 -05:00
|
|
|
if ( not _segment->canDogLegAt(dogLegGCell) ) {
|
2010-03-09 09:24:55 -06:00
|
|
|
ltrace(200) << "Cannot create FIRST dogleg." << endl;
|
|
|
|
ltraceout(200);
|
|
|
|
return false;
|
|
|
|
}
|
2010-05-03 04:16:50 -05:00
|
|
|
dogleg = _segment->makeDogLeg ( dogLegGCell );
|
|
|
|
segment1 = Session::lookup ( Session::getDogLegs()[2] );
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( firstDogLegIsMin ) {
|
|
|
|
if ( minExpanded ) {
|
2010-05-03 04:16:50 -05:00
|
|
|
//doglegAxis = dogLegGCell->getUSide(_segment->getDirection(),false).getVMax() - DbU::lambda(1.0);
|
|
|
|
doglegAxis = dogLegGCell->getUSide(_segment->getDirection(),false).getCenter();
|
2010-03-09 09:24:55 -06:00
|
|
|
} else {
|
|
|
|
// Ugly: hardcoded pitch.
|
|
|
|
doglegAxis = interval.getVMin() - DbU::lambda(5.0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( maxExpanded ) {
|
2010-05-03 04:16:50 -05:00
|
|
|
doglegAxis = dogLegGCell->getUSide(_segment->getDirection(),false).getVMin();
|
2010-03-09 09:24:55 -06:00
|
|
|
} else {
|
|
|
|
// Ugly: hardcoded pitch (5.0 - 1.0).
|
|
|
|
doglegAxis = interval.getVMax() + DbU::lambda(4.0);
|
|
|
|
}
|
|
|
|
}
|
2010-05-03 04:16:50 -05:00
|
|
|
if ( doglegReuse1 ) _S.addAction ( dogleg, SegmentAction::OtherRipup );
|
|
|
|
else dogleg->setAxis ( doglegAxis );
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
// 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)
|
2010-05-03 04:16:50 -05:00
|
|
|
and not _segment->getTrack()
|
|
|
|
and (_segment->getGCell()->getOrder() < Session::getOrder()) ) {
|
|
|
|
Session::addInsertEvent ( _segment, track );
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Making second dogleg.
|
|
|
|
if ( dogLegCount > 1 ) {
|
|
|
|
ltrace(200) << "Making SECOND dogleg at " << isecondDogleg
|
2010-05-03 04:16:50 -05:00
|
|
|
<< " on " << segment1 << endl;
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
dogleg = NULL;
|
|
|
|
dogLegGCell = gcells[isecondDogleg];
|
|
|
|
|
|
|
|
if ( ifirstDogleg == isecondDogleg ) {
|
|
|
|
ltrace(200) << "Double break in same GCell." << endl;
|
2010-05-03 04:16:50 -05:00
|
|
|
segment1->setSourceDogLeg(false);
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
2010-05-03 04:16:50 -05:00
|
|
|
if ( isecondDogleg == gcells.size()-1 ) dogleg = segment1->getTargetDogLeg();
|
2010-03-09 09:24:55 -06:00
|
|
|
if ( dogleg ) {
|
|
|
|
ltrace(200) << "Reusing dogleg." << endl;
|
2010-05-03 04:16:50 -05:00
|
|
|
doglegReuse2 = true;
|
|
|
|
segment2 = segment1;
|
2010-03-09 09:24:55 -06:00
|
|
|
} else {
|
|
|
|
// Try to create a new dogleg.
|
2010-05-03 04:16:50 -05:00
|
|
|
if ( not segment1->canDogLegAt(dogLegGCell) ) {
|
2010-03-09 09:24:55 -06:00
|
|
|
ltrace(200) << "Cannot create SECOND dogleg." << endl;
|
|
|
|
ltraceout(200);
|
|
|
|
return false;
|
|
|
|
}
|
2010-05-03 04:16:50 -05:00
|
|
|
dogleg = segment1->makeDogLeg ( dogLegGCell );
|
|
|
|
segment2 = Session::lookup ( Session::getDogLegs()[2] );
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( maxExpanded ) {
|
2010-05-03 04:16:50 -05:00
|
|
|
//doglegAxis = dogLegGCell->getUSide(segment1->getDirection(),false).getVMin();
|
|
|
|
doglegAxis = dogLegGCell->getUSide(segment1->getDirection(),false).getCenter();
|
2010-03-09 09:24:55 -06:00
|
|
|
} else {
|
|
|
|
// Ugly: hardcoded pitch.
|
|
|
|
doglegAxis = interval.getVMax() + DbU::lambda(5.0);
|
|
|
|
}
|
2010-05-03 04:16:50 -05:00
|
|
|
if ( doglegReuse2 ) _S.addAction ( dogleg, SegmentAction::OtherRipup );
|
|
|
|
else dogleg->setAxis ( doglegAxis );
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
// 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++ ) {
|
2010-05-03 04:16:50 -05:00
|
|
|
TrackElement* segment = Session::lookup(doglegs[i]);
|
2010-03-09 09:24:55 -06:00
|
|
|
if ( ( segment->getGCell()->getOrder() < Session::getOrder() ) and not segment->getTrack() ) {
|
|
|
|
Session::addInsertEvent ( segment, track );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-05-03 04:16:50 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-03-09 09:24:55 -06:00
|
|
|
} 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;
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not (success = Manipulator(segment2,_S).ripup(toFree,SegmentAction::OtherRipup)) )
|
|
|
|
continue;
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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 ) {
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not (success=Manipulator(*isegment3,_S).ripup ( track->getAxis()
|
|
|
|
, SegmentAction::OtherPushAside
|
|
|
|
| SegmentAction::AxisHint
|
|
|
|
, toFree.getVMin() - DbU::lambda(1.0)
|
|
|
|
)) )
|
|
|
|
break;
|
|
|
|
|
2010-03-09 09:24:55 -06:00
|
|
|
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 ) {
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not (success=Manipulator(*isegment3,_S).ripup ( track->getAxis()
|
|
|
|
, SegmentAction::OtherPushAside
|
|
|
|
| SegmentAction::AxisHint
|
|
|
|
, toFree.getVMax() + DbU::lambda(1.0)
|
|
|
|
)) )
|
|
|
|
break;
|
2010-03-09 09:24:55 -06:00
|
|
|
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));
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not (success=Manipulator(*isegment3,_S).ripup ( track->getAxis()
|
|
|
|
, SegmentAction::OtherRipup
|
|
|
|
| SegmentAction::EventLevel3
|
|
|
|
//| SegmentAction::AxisHint, axisHint
|
|
|
|
)) )
|
|
|
|
break;
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
}
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not success ) break;
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( not (success=Manipulator(segment2,_S).ripup(toFree,SegmentAction::OtherRipup)) )
|
|
|
|
continue;
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( Manipulator(*isegment3,_S).canRipup() )
|
|
|
|
_S.addAction ( *isegment3, SegmentAction::OtherRipup );
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( success ) {
|
|
|
|
_S.setState ( State::OtherRipup );
|
|
|
|
_S.addAction ( _segment, SegmentAction::SelfInsert );
|
|
|
|
_segment->setAxis ( _S.getCost(itrack).getTrack()->getAxis() );
|
|
|
|
}
|
|
|
|
|
2010-04-17 05:14:46 -05:00
|
|
|
return success;
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( _segment->isFixed () ) return false;
|
|
|
|
if ( not _segment->canMoveUp(0.0) ) return false;
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
_segment->moveUp ();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Manipulator::moveUp ()
|
|
|
|
{
|
|
|
|
ltrace(200) << "Manipulator::moveUp() " << _segment << endl;
|
|
|
|
|
|
|
|
if ( _segment->isFixed () ) return false;
|
2010-04-23 08:14:17 -05:00
|
|
|
if ( _segment->isLocal() and not _segment->canPivotUp(0.0) ) return false;
|
|
|
|
if ( not _segment->canMoveUp(0.5) ) return false;
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-03 04:16:50 -05:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-09 09:24:55 -06:00
|
|
|
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: "
|
2010-04-23 08:14:17 -05:00
|
|
|
<< (void*)this << " -> "
|
|
|
|
<< (void*)fork << ":" << eventLevel << ":" << fork << endl;
|
2010-03-09 09:24:55 -06:00
|
|
|
} 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;
|
2010-04-17 05:14:46 -05:00
|
|
|
resetInsertState ();
|
2010-03-09 09:24:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//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;
|
|
|
|
|
2010-05-11 06:04:47 -05:00
|
|
|
DebugSession::open ( _segment->getNet(), 148 );
|
2010-03-09 09:24:55 -06:00
|
|
|
|
|
|
|
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.
|