1558 lines
56 KiB
C++
1558 lines
56 KiB
C++
// -*- C++ -*-
|
|
//
|
|
// This file is part of the Coriolis Software.
|
|
// Copyright (c) UPMC 2008-2018, All Rights Reserved
|
|
//
|
|
// +-----------------------------------------------------------------+
|
|
// | C O R I O L I S |
|
|
// | 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@lip6.fr |
|
|
// | =============================================================== |
|
|
// | C++ Module : "./SegmentFsm.cpp" |
|
|
// +-----------------------------------------------------------------+
|
|
|
|
|
|
#include <algorithm>
|
|
#include "hurricane/Bug.h"
|
|
#include "hurricane/DebugSession.h"
|
|
#include "katana/TrackElement.h"
|
|
#include "katana/Tracks.h"
|
|
#include "katana/RoutingPlane.h"
|
|
#include "katana/DataNegociate.h"
|
|
#include "katana/RoutingEvent.h"
|
|
#include "katana/RoutingEventQueue.h"
|
|
#include "katana/RoutingEventHistory.h"
|
|
#include "katana/Manipulator.h"
|
|
#include "katana/SegmentFsm.h"
|
|
#include "katana/KatanaEngine.h"
|
|
|
|
|
|
namespace {
|
|
|
|
using namespace std;
|
|
using namespace Hurricane;
|
|
using namespace Katana;
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "Cs1Candidate".
|
|
|
|
class Cs1Candidate {
|
|
public:
|
|
inline Cs1Candidate ( Track* track=NULL, DbU::Unit ppitch=0 );
|
|
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 Interval getLongestConflict () const;
|
|
inline DbU::Unit getBreakPos () const;
|
|
inline DbU::Unit getConflictLength () const;
|
|
inline void setBegin ( size_t );
|
|
inline void setEnd ( size_t );
|
|
inline void addConflict ( const Interval& );
|
|
void consolidate ();
|
|
public:
|
|
friend inline bool operator< ( const Cs1Candidate&, const Cs1Candidate& );
|
|
private:
|
|
Track* _track;
|
|
DbU::Unit _ppitch;
|
|
size_t _begin;
|
|
size_t _end;
|
|
vector<Interval> _conflicts;
|
|
Interval _longestConflict;
|
|
DbU::Unit _breakPos;
|
|
DbU::Unit _conflictLength;
|
|
};
|
|
|
|
|
|
inline Cs1Candidate::Cs1Candidate ( Track* track, DbU::Unit ppitch )
|
|
: _track (track)
|
|
, _ppitch (ppitch)
|
|
, _begin (0)
|
|
, _end (0)
|
|
, _conflicts ()
|
|
, _longestConflict()
|
|
, _breakPos (0)
|
|
, _conflictLength (0)
|
|
{ }
|
|
|
|
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 Interval Cs1Candidate::getLongestConflict () const { return _longestConflict; }
|
|
inline DbU::Unit Cs1Candidate::getBreakPos () const { return _breakPos; }
|
|
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);
|
|
_conflictLength += conflict.getSize();
|
|
|
|
if (conflict.getSize() > _longestConflict.getSize())
|
|
_longestConflict = conflict;
|
|
}
|
|
|
|
inline Interval Cs1Candidate::getConflict ( size_t i )
|
|
{
|
|
if (i >= _conflicts.size()) return Interval();
|
|
return _conflicts[i];
|
|
}
|
|
|
|
inline bool operator< ( const Cs1Candidate& lhs, const Cs1Candidate& rhs )
|
|
{
|
|
DbU::Unit delta = lhs._longestConflict.getSize() - rhs._longestConflict.getSize();
|
|
if (delta < 0) return true;
|
|
if (delta > 0) return false;
|
|
|
|
return lhs._conflictLength < rhs._conflictLength;
|
|
}
|
|
|
|
|
|
void Cs1Candidate::consolidate ()
|
|
{
|
|
if (_conflicts.size() > 0) {
|
|
DbU::Unit halfConflict = 0;
|
|
size_t i = 0;
|
|
for ( ; i<_conflicts.size()-1 ; ++i ) {
|
|
halfConflict += _conflicts[i].getSize();
|
|
if (halfConflict > _conflictLength/2)
|
|
break;
|
|
}
|
|
|
|
// Ugly: hard-coded pitch.
|
|
_breakPos = _conflicts[i].getVMin() - _ppitch;
|
|
}
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// 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 )
|
|
{
|
|
cdebug_log(159,0) << "UnionInterval::addInterval() - " << interval << endl;
|
|
|
|
list<Interval>::iterator iintv = _intervals.begin ();
|
|
|
|
bool merged = false;
|
|
while ( iintv != _intervals.end() ) {
|
|
if (not 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 (not 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->getPerpandicularFree();
|
|
RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(_masterEvent->getSegment()->getLayer());
|
|
Track* track;
|
|
|
|
if (not perpandicular.isEmpty()) {
|
|
track = plane->getTrackByPosition(perpandicular.getVMin());
|
|
|
|
if (track and (track->getAxis() < perpandicular.getVMin())) track = track->getNextTrack();
|
|
for ( ; track && (track->getAxis() <= perpandicular.getVMax())
|
|
; track = track->getNextTrack() )
|
|
addAxis( track->getAxis() );
|
|
}
|
|
|
|
track = plane->getTrackByPosition(_masterEvent->getSegment()->getAxis());
|
|
if (track) {
|
|
size_t begin = Track::npos;
|
|
size_t end = Track::npos;
|
|
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 (not 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 (not 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 (not 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;
|
|
}
|
|
|
|
|
|
} // Anonymous namespace.
|
|
|
|
|
|
namespace Katana {
|
|
|
|
using std::sort;
|
|
using Hurricane::tab;
|
|
using Hurricane::DebugSession;
|
|
using Hurricane::Bug;
|
|
using Hurricane::ForEachIterator;
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "SegmentAction".
|
|
|
|
SegmentAction::SegmentAction ( TrackElement* segment
|
|
, uint32_t type
|
|
, DbU::Unit axisHint
|
|
, uint32_t 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.
|
|
|
|
DebugSession::open( _segment->getNet(), 156, 160 );
|
|
|
|
if (_type & Lock) {
|
|
cdebug_log(159,1) << "* Lock // " << _segment << endl;
|
|
} else if (_type & Perpandicular) {
|
|
cdebug_log(159,1) << "* Riping Pp " << _segment << endl;
|
|
} else if (_type & OtherRipup) {
|
|
cdebug_log(159,1) << "* Riping Other " << _segment << endl;
|
|
} else {
|
|
cdebug_log(159,1) << "* Riping // " << _segment << endl;
|
|
}
|
|
|
|
if (_segment->isFixed ()) { DebugSession::close(); return true; }
|
|
//if (_segment->isReduced()) { DebugSession::close(); return true; }
|
|
|
|
DataNegociate* data = _segment->getDataNegociate();
|
|
if (data == NULL) {
|
|
cdebug_tabw(159,-1);
|
|
DebugSession::close();
|
|
return true;
|
|
}
|
|
|
|
if (_type & ResetRipup ) data->resetRipupCount();
|
|
if (_type & DecreaseRipup) data->decRipupCount ();
|
|
|
|
if (_type & ToState) {
|
|
data->setState ( _toState );
|
|
data->setRipupCount( Session::getKatanaEngine()->getRipupLimit(_segment) );
|
|
}
|
|
|
|
if (_segment->getTrack()) Session::addRemoveEvent( _segment );
|
|
|
|
RoutingEvent* event = data->getRoutingEvent();
|
|
if (event == NULL) {
|
|
cerr << Bug( "Missing Event on %p:%s"
|
|
, _segment->base()->base(),getString(_segment).c_str() ) << endl;
|
|
DebugSession::close();
|
|
return true;
|
|
}
|
|
|
|
if (_type&Lock) Session::addLockEvent( _segment );
|
|
|
|
if ( (_type & AxisHint) /*and not _segment->isSlackenDogleg()*/ ) {
|
|
cdebug_log(159,0) << "Setting Axis Hint: @" << DbU::getValueString(_axisHint) << endl;
|
|
event->setAxisHint( _axisHint );
|
|
}
|
|
|
|
// It is possible that this code could be disabled.
|
|
// There should be no need to move the axis of the segment to be inserted,
|
|
// it will automatically slot into the empty track, if any.
|
|
if (_type & MoveToAxis) {
|
|
cdebug_log(159,0) << "Moving Axis To: @" << DbU::getValueString(_axisHint) << endl;
|
|
_segment->setAxis( _axisHint );
|
|
}
|
|
|
|
if (_type & ToRipupLimit) {
|
|
uint32_t limit = Session::getKatanaEngine()->getRipupLimit(_segment);
|
|
if (limit > data->getRipupCount())
|
|
data->setRipupCount( limit );
|
|
}
|
|
|
|
uint32_t 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;
|
|
event->setRipedByLocal( _type&RipedByLocal );
|
|
|
|
//RoutingEvent* fork =
|
|
event->reschedule( queue, eventLevel );
|
|
|
|
cdebug_tabw(159,-1);
|
|
DebugSession::close();
|
|
return true;
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "SegmentFsm".
|
|
|
|
|
|
SegmentFsm::SegmentFsm ( RoutingEvent* event1
|
|
, RoutingEventQueue& queue
|
|
, RoutingEventHistory& history )
|
|
: _event1 (event1)
|
|
, _event2 (NULL)
|
|
, _queue (queue)
|
|
, _history (history)
|
|
, _state (0)
|
|
, _data1 (NULL)
|
|
, _data2 (NULL)
|
|
, _constraint ()
|
|
, _optimal ()
|
|
, _costs ()
|
|
, _actions ()
|
|
, _fullBlocked (true)
|
|
, _sameAxis (false)
|
|
, _useEvent2 (false)
|
|
, _minimizeDrag(false)
|
|
{
|
|
DataSymmetric* symData = NULL;
|
|
TrackElement* segment1 = _event1->getSegment();
|
|
TrackElement* segment2 = segment1->getSymmetric();
|
|
_event1->setTracksFree( 0 );
|
|
|
|
_data1 = segment1->getDataNegociate();
|
|
if (not _data1) {
|
|
_state = MissingData;
|
|
return;
|
|
}
|
|
|
|
_data1->update();
|
|
_event1->revalidate();
|
|
|
|
if (segment2) {
|
|
symData = Session::getKatanaEngine()->getDataSymmetric( segment1->getNet() );
|
|
|
|
_data2 = segment2->getDataNegociate();
|
|
if (not _data2 or not symData) {
|
|
_state = MissingData;
|
|
return;
|
|
}
|
|
|
|
_event2 = _data2->getRoutingEvent();
|
|
_event2->setTracksFree( 0 );
|
|
|
|
cdebug_log(159,1) << "Coupled:" << _event2 << endl;
|
|
_data2->update();
|
|
_event2->revalidate();
|
|
cdebug_tabw(159,-1);
|
|
|
|
_sameAxis = (segment1->isVertical() xor symData->isSymVertical());
|
|
}
|
|
|
|
Interval perpandicular = _event1->getPerpandicularFree();
|
|
cdebug_log(159,0) << "* Perpandicular (master): " << perpandicular << endl;
|
|
|
|
_constraint = _event1->getConstraints();
|
|
cdebug_log(159,0) << "* Constraints: " << _constraint << " (" << _constraint.getVMin() << " " << _constraint.getVMax() << ")" << endl;
|
|
|
|
_optimal = _event1->getOptimal();
|
|
if (_event2) {
|
|
if (_sameAxis) {
|
|
_constraint .intersection( _event2->getConstraints() );
|
|
perpandicular.intersection( _event2->getPerpandicularFree() );
|
|
|
|
cdebug_log(159,0) << "* Perpandicular (slave): same axis "
|
|
<< _event2->getPerpandicularFree() << endl;
|
|
} else {
|
|
_constraint .intersection( symData->getSymmetrical( _event2->getConstraints() ) );
|
|
perpandicular.intersection( symData->getSymmetrical( _event2->getPerpandicularFree() ) );
|
|
|
|
cdebug_log(159,0) << "* Perpandicular (slave): PP axis "
|
|
<< symData->getSymmetrical(_event2->getPerpandicularFree()) << endl;
|
|
cdebug_log(159,0) << "* Constraints: " << _constraint << " (" << _constraint.getVMin() << " " << _constraint.getVMax() << ")" << endl;
|
|
}
|
|
}
|
|
|
|
cdebug_log(159,0) << "Anabatic intervals:" << endl;
|
|
cdebug_log(159,0) << "* Optimal: " << _optimal << " (" << _optimal.getVMin() << " " << _optimal.getVMax() << ")" << endl;
|
|
cdebug_log(159,0) << "* Constraints: " << _constraint << " (" << _constraint.getVMin() << " " << _constraint.getVMax() << ")" << endl;
|
|
cdebug_log(159,0) << "* Perpandicular: " << perpandicular << endl;
|
|
cdebug_log(159,0) << "* AxisHint: " << DbU::getValueString(_event1->getAxisHint()) << endl;
|
|
|
|
if (_event1->getTracksNb()) {
|
|
if (_constraint.getIntersection(perpandicular).isEmpty()) {
|
|
cdebug_log(159,0) << "Perpandicular free is too tight." << endl;
|
|
_state = EmptyTrackList;
|
|
} else
|
|
_constraint.intersection( perpandicular );
|
|
} else {
|
|
cdebug_log(159,0) << "No Track in perpandicular free." << endl;
|
|
if (not segment1->isNonPref()) _state = EmptyTrackList;
|
|
else {
|
|
cdebug_log(159,0) << "But in non-preferred direction, so that may happen." << endl;
|
|
}
|
|
}
|
|
|
|
if (_state == EmptyTrackList) return;
|
|
|
|
cdebug_log(159,0) << "Negociate intervals:" << endl;
|
|
cdebug_log(159,0) << "* Optimal: " << _optimal << endl;
|
|
cdebug_log(159,0) << "* Constraints: " << _constraint << endl;
|
|
cdebug_log(159,1) << "* _sameAxis: " << _sameAxis << endl;
|
|
|
|
// if ( segment->isLocal() and (_data->getState() >= DataNegociate::MaximumSlack) )
|
|
// _constraint.inflate ( 0, DbU::lambda(1.0) );
|
|
|
|
RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(segment1->getLayer());
|
|
|
|
if (segment1->isNonPref()) {
|
|
Track* baseTrack = plane->getTrackByPosition( segment1->base()->getSourcePosition(), Constant::Superior );
|
|
RoutingPlane* perpPlane = plane->getTop();
|
|
if (not perpPlane) perpPlane = plane->getBottom();
|
|
|
|
for ( Track* ptrack : Tracks_Range::get(perpPlane,_constraint) ) {
|
|
_costs.push_back( new TrackCost(segment1,NULL,baseTrack,NULL,ptrack->getAxis(),0) );
|
|
|
|
cdebug_log(155,0) << "AxisWeight:" << DbU::getValueString(_costs.back()->getRefCandidateAxis())
|
|
<< " sum:" << DbU::getValueString(_costs.back()->getAxisWeight())
|
|
<< endl;
|
|
|
|
if ( _fullBlocked and (not _costs.back()->isBlockage() and not _costs.back()->isFixed()) )
|
|
_fullBlocked = false;
|
|
|
|
cdebug_log(155,0) << "| " << _costs.back() << ((_fullBlocked)?" FB ": " -- ") << ptrack << endl;
|
|
}
|
|
if (_costs.empty()) {
|
|
_costs.push_back( new TrackCost(segment1,NULL,baseTrack,NULL,segment1->getAxis(),0) );
|
|
if ( _fullBlocked and (not _costs.back()->isBlockage() and not _costs.back()->isFixed()) )
|
|
_fullBlocked = false;
|
|
}
|
|
} else {
|
|
for ( Track* track1 : Tracks_Range::get(plane,_constraint) ) {
|
|
Track* track2 = NULL;
|
|
DbU::Unit symAxis = 0;
|
|
if (_event2) {
|
|
track2 =
|
|
(_sameAxis) ? track1 : plane->getTrackByPosition
|
|
( segment2->getSymmetricAxis( symData->getSymmetrical( track1->getAxis() ) ) );
|
|
|
|
if (track2) symAxis = track2->getAxis();
|
|
|
|
cdebug_log(155,0) << "refTrack:" << track1 << endl;
|
|
cdebug_log(155,0) << "symTrack:" << track2 << endl;
|
|
cdebug_log(155,0) << "by symData: " << DbU::getValueString( symData->getSymmetrical(track1->getAxis()) ) << endl;
|
|
cdebug_log(155,0) << "plus segment2:" << DbU::getValueString( segment2->getSymmetricAxis(symData->getSymmetrical(track1->getAxis())) ) << endl;
|
|
}
|
|
|
|
_costs.push_back( new TrackCost(segment1,segment2,track1,track2,track1->getAxis(),symAxis) );
|
|
cdebug_log(155,0) << "Same Ripup:" << _data1->getSameRipup() << endl;
|
|
if ((_data1->getSameRipup() > 10) and (track1->getAxis() == segment1->getAxis())) {
|
|
cdebug_log(155,0) << "Track blacklisted" << endl;
|
|
_costs.back()->setBlacklisted();
|
|
}
|
|
|
|
cdebug_log(155,0) << "AxisWeight:" << DbU::getValueString(_costs.back()->getRefCandidateAxis())
|
|
<< " sum:" << DbU::getValueString(_costs.back()->getAxisWeight())
|
|
<< endl;
|
|
|
|
if ( _fullBlocked and (not _costs.back()->isBlockage() and not _costs.back()->isFixed()) )
|
|
_fullBlocked = false;
|
|
|
|
cdebug_log(155,0) << "| " << _costs.back() << ((_fullBlocked)?" FB ": " -- ") << track1 << endl;
|
|
}
|
|
}
|
|
cdebug_tabw(159,-1);
|
|
|
|
if (_costs.empty()) {
|
|
Track* nearest = plane->getTrackByPosition(_constraint.getCenter());
|
|
|
|
if ( (nearest->getAxis() < _constraint.getVMin())
|
|
or (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(segment1).c_str()
|
|
, getString(_constraint).c_str()
|
|
) << endl;
|
|
}
|
|
_state = EmptyTrackList;
|
|
}
|
|
|
|
uint32_t flags = 0;
|
|
flags |= (segment1->isStrap()) ? TrackCost::IgnoreAxisWeight : 0;
|
|
flags |= (segment1->isLocal()
|
|
and (_data1->getState() < DataNegociate::Minimize)
|
|
and (_data1->getRipupCount() < 5))
|
|
? TrackCost::DiscardGlobals : 0;
|
|
flags |= (Session::getStage() == StageRepair ) ? TrackCost::IgnoreSharedLength : 0;
|
|
flags |= (Session::getStage() == StageRealign) ? TrackCost::IgnoreTerminals : 0;
|
|
|
|
if (flags & TrackCost::DiscardGlobals) {
|
|
cdebug_log(159,0) << "TrackCost::Compare() - DiscardGlobals" << endl;
|
|
}
|
|
|
|
// FOR ANALOG ONLY.
|
|
//flags |= TrackCost::IgnoreSharedLength;
|
|
sort( _costs.begin(), _costs.end(), TrackCost::Compare(flags) );
|
|
|
|
size_t i=0;
|
|
for ( ; (i<_costs.size()) and _costs[i]->isFree() ; i++ );
|
|
_event1->setTracksFree( i );
|
|
if (_event2) _event2->setTracksFree( i );
|
|
|
|
// if (not segment1->isDrag()) {
|
|
// cdebug_log(159,0) << "Not a draggable segment and _costs.size():" << _costs.size() << endl;
|
|
// if (_costs.size() == 1) {
|
|
// segment1->base()->setFlags( AutoSegment::SegFixedAxis );
|
|
// if (segment2) segment2->base()->setFlags( AutoSegment::SegFixedAxis );
|
|
// } else {
|
|
// segment1->base()->unsetFlags( AutoSegment::SegFixedAxis );
|
|
// if (segment2) segment2->base()->unsetFlags( AutoSegment::SegFixedAxis );
|
|
// }
|
|
// }
|
|
}
|
|
|
|
|
|
SegmentFsm::~SegmentFsm ()
|
|
{
|
|
for ( TrackCost* cost : _costs ) delete cost;
|
|
}
|
|
|
|
|
|
void SegmentFsm::setDataState ( uint32_t state )
|
|
{
|
|
_data1->setState( state );
|
|
if (_data2) _data2->setState( state );
|
|
}
|
|
|
|
|
|
void SegmentFsm::addAction ( TrackElement* segment
|
|
, uint32_t type
|
|
, DbU::Unit axisHint
|
|
, uint32_t toSegmentFsm )
|
|
{
|
|
if ( not segment->isFixed() ) {
|
|
_actions.push_back ( SegmentAction(segment,type,axisHint,toSegmentFsm) );
|
|
cdebug_log(159,0) << "SegmentFsm::addAction(): " << segment << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void SegmentFsm::doActions ()
|
|
{
|
|
cdebug_log(159,1) << "SegmentFsm::doActions() - " << _actions.size() << endl;
|
|
|
|
bool ripupOthersParallel = false;
|
|
bool ripedByLocal = getEvent()->getSegment()->isLocal();
|
|
|
|
for ( size_t i=0 ; i<_actions.size() ; i++ ) {
|
|
if ( ripedByLocal ) _actions[i].setFlag ( SegmentAction::RipedByLocal );
|
|
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 );
|
|
|
|
DebugSession::open ( _actions[i].getSegment()->getNet(), 156, 160 );
|
|
if ( not _actions[i].doAction(_queue) ) {
|
|
cinfo << "[INFO] Failed action on " << _actions[i].getSegment() << endl;
|
|
}
|
|
DebugSession::close ();
|
|
}
|
|
|
|
_actions.clear ();
|
|
|
|
cdebug_tabw(159,-1);
|
|
}
|
|
|
|
|
|
void SegmentFsm::incRipupCount ()
|
|
{
|
|
_data1->incRipupCount();
|
|
if (_data2) _data2->incRipupCount();
|
|
}
|
|
|
|
|
|
bool SegmentFsm::insertInTrack ( size_t i )
|
|
{
|
|
cdebug_log(159,0) << "SegmentFsm::insertInTrack() istate:" << _event1->getInsertState()
|
|
<< " track:" << i << endl;
|
|
|
|
bool success = true;
|
|
|
|
_event1->incInsertState();
|
|
switch ( _event1->getInsertState() ) {
|
|
case 1:
|
|
success = Manipulator(_event1->getSegment(),useEvent1()).insertInTrack(i);
|
|
success = success and (not _event2 or Manipulator(_event2->getSegment(),useEvent2()).insertInTrack(i));
|
|
if (success) break;
|
|
_event1->incInsertState();
|
|
clearActions();
|
|
case 2:
|
|
success = Manipulator(_event1->getSegment(),useEvent1()).shrinkToTrack(i);
|
|
success = success and (not _event2 or Manipulator(_event2->getSegment(),useEvent2()).shrinkToTrack(i));
|
|
if (success) break;
|
|
_event1->incInsertState();
|
|
clearActions();
|
|
case 3:
|
|
success = Manipulator(_event1->getSegment(),useEvent1()).forceToTrack(i);
|
|
success = success and (not _event2 or Manipulator(_event2->getSegment(),useEvent2()).forceToTrack(i));
|
|
if (success) break;
|
|
_event1->incInsertState();
|
|
clearActions();
|
|
}
|
|
|
|
useEvent1();
|
|
if (_event2) _event2->setInsertState( _event1->getInsertState() );
|
|
|
|
if (success and Session::disableStackedVias())
|
|
Manipulator( _event1->getSegment(), useEvent1() ).avoidStackedVias( getCandidateAxis1(i) );
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
void SegmentFsm::bindToTrack ( size_t i )
|
|
{
|
|
cdebug_log(159,0) << "SegmentFsm::bindToTrack() track:" << i << endl;
|
|
|
|
_event1->resetInsertState();
|
|
_event1->updateAxisHistory();
|
|
_event1->setEventLevel( 0 );
|
|
|
|
cdebug_log(9000,0) << "Deter| addInsertEvent() @" << getTrack1(i) << endl;
|
|
Session::addInsertEvent( getSegment1(), getTrack1(i), getCandidateAxis1(i) );
|
|
|
|
if (_event2) {
|
|
_event2->resetInsertState();
|
|
_event2->updateAxisHistory();
|
|
_event2->setEventLevel( 0 );
|
|
_event2->setProcessed( true );
|
|
|
|
cdebug_log(9000,0) << "Deter| addInsertEvent() @" << getTrack2(i) << endl;
|
|
Session::addInsertEvent( getSegment2(), getTrack2(i), getCandidateAxis2(i) );
|
|
}
|
|
|
|
setState( SegmentFsm::SelfInserted );
|
|
|
|
if (Session::disableStackedVias())
|
|
Manipulator( _event1->getSegment(), useEvent1() ).avoidStackedVias( getCandidateAxis1(i) );
|
|
}
|
|
|
|
|
|
void SegmentFsm::moveToTrack ( size_t i )
|
|
{
|
|
cdebug_log(159,0) << "SegmentFsm::moveToTrack() :" << " track:" << i << endl;
|
|
|
|
Session::addMoveEvent( getSegment1(), getTrack1(i), getCandidateAxis1(i) );
|
|
|
|
if (_event2) {
|
|
cdebug_log(9000,0) << "Deter| addInsertEvent() @" << getTrack1(i) << endl;
|
|
Session::addMoveEvent( getSegment2(), getTrack2(i), getCandidateAxis2(i) );
|
|
}
|
|
|
|
setState( SegmentFsm::SelfInserted );
|
|
|
|
if (Session::disableStackedVias())
|
|
Manipulator( _event1->getSegment(), useEvent1() ).avoidStackedVias( getCandidateAxis1(i) );
|
|
}
|
|
|
|
|
|
void SegmentFsm::ripupPerpandiculars ()
|
|
{
|
|
Manipulator(getSegment1(),*this).ripupPerpandiculars();
|
|
if (_event2)
|
|
Manipulator(getSegment2(),*this).ripupPerpandiculars();
|
|
}
|
|
|
|
|
|
bool SegmentFsm::canRipup ( uint32_t flags )
|
|
{
|
|
return Manipulator(getSegment1(),*this).canRipup(flags)
|
|
and (not _event2 or Manipulator(getSegment2(),*this).canRipup(flags));
|
|
}
|
|
|
|
|
|
bool SegmentFsm::conflictSolveByHistory ()
|
|
{
|
|
bool success = false;
|
|
RipupHistory ripupHistory ( _event1 );
|
|
RoutingEvent* event;
|
|
TrackElement* segment = getEvent()->getSegment();
|
|
|
|
cdebug_log(159,0) << "SegmentFsm::conflictSolveByHistory()" << 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 (not event) continue;
|
|
if ( (event->getSegment() != segment) and ripupHistory.isDislodger(event) )
|
|
ripupHistory.addDislodger( event );
|
|
}
|
|
|
|
//ripupHistory.print ( cout );
|
|
|
|
UnionIntervals* intervals = ripupHistory.getUnionIntervals( segment->getAxis() );
|
|
if (intervals and not 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);
|
|
Point breakPoint;
|
|
|
|
if (sourceDogleg) {
|
|
if (segment->isHorizontal()) {
|
|
breakPoint = Point( minConflict, segment->getAxis() );
|
|
cdebug_log(159,0) << breakPoint << endl;
|
|
} else {
|
|
breakPoint = Point( segment->getAxis(), minConflict );
|
|
cdebug_log(159,0) << breakPoint << endl;
|
|
}
|
|
|
|
Anabatic::GCell* dogLegGCell = Session::getGCellUnder( breakPoint.getX(), breakPoint.getY() );
|
|
if (dogLegGCell) {
|
|
if (segment->canDogleg(dogLegGCell))
|
|
success = segment->makeDogleg(dogLegGCell);
|
|
} else {
|
|
cerr << Bug( "No GCell under source %s for:\n %s."
|
|
, getString(breakPoint).c_str(), getString(segment).c_str() ) << endl;
|
|
}
|
|
}
|
|
|
|
if (not success and targetDogleg) {
|
|
if (segment->isHorizontal()) {
|
|
breakPoint = Point( maxConflict, segment->getAxis() );
|
|
cdebug_log(159,0) << breakPoint << endl;
|
|
} else {
|
|
breakPoint = Point( segment->getAxis(), maxConflict );
|
|
cdebug_log(159,0) << breakPoint << endl;
|
|
}
|
|
|
|
Anabatic::GCell* dogLegGCell = Session::getGCellUnder( breakPoint.getX(), breakPoint.getY() );
|
|
if (dogLegGCell) {
|
|
if (segment->canDogleg(dogLegGCell)) {
|
|
success = segment->makeDogleg(dogLegGCell);
|
|
}
|
|
} else {
|
|
cerr << Bug( "No GCell under target %s for:\n %s."
|
|
, getString(breakPoint).c_str(), getString(segment).c_str() ) << endl;
|
|
}
|
|
}
|
|
} else {
|
|
cdebug_log(159,0) << "No disloggers found @" << DbU::getValueString(segment->getAxis()) << endl;
|
|
|
|
Track* track = Session::getKatanaEngine()->getTrackByPosition( segment->getLayer()
|
|
, segment->getAxis () );
|
|
if (track) {
|
|
Interval freeSpan = track->getFreeInterval( segment->getSourceU(), segment->getNet() );
|
|
|
|
if (freeSpan.contains(segment->getCanonicalInterval())) {
|
|
cdebug_log(159,0) << "Disloggers vanished, Segment can be re-inserted." << endl;
|
|
success = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
bool SegmentFsm::conflictSolveByPlaceds ()
|
|
{
|
|
bool success = false;
|
|
Interval constraints;
|
|
vector<Cs1Candidate> candidates;
|
|
TrackElement* segment = getEvent()->getSegment();
|
|
bool canMoveUp = (segment->isLocal()) ? segment->canPivotUp(0.5,Flags::NoFlags) : segment->canMoveUp(1.0,Flags::CheckLowDensity); // MARK 1
|
|
uint32_t relaxFlags = Manipulator::NoDoglegReuse
|
|
| ((_data1 and (_data1->getStateCount() < 2)) ? Manipulator::AllowExpand
|
|
: Manipulator::NoExpand);
|
|
|
|
cdebug_log(159,0) << "SegmentFsm::conflictSolveByPlaceds()" << endl;
|
|
cdebug_log(159,0) << "| Candidates Tracks: " << endl;
|
|
|
|
segment->base()->getConstraints( constraints );
|
|
Interval overlap = segment->getCanonicalInterval();
|
|
RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(segment->getLayer());
|
|
Track* track = plane->getTrackByPosition(constraints.getVMin(),Constant::Superior);
|
|
|
|
if (not track) {
|
|
cerr << Bug( "SegmentFsm::conflictSolveByPlaceds():\n"
|
|
" For: %s\n"
|
|
" In %s, no Track near %s"
|
|
, getString(segment).c_str()
|
|
, getString(plane).c_str()
|
|
, DbU::getValueString(constraints.getVMin()).c_str()
|
|
) << endl;
|
|
return false;
|
|
}
|
|
|
|
for ( ; track and track->getAxis() <= constraints.getVMax() ; track = track->getNextTrack() ) {
|
|
candidates.push_back( Cs1Candidate(track,segment->getPPitch()) );
|
|
|
|
size_t begin;
|
|
size_t end;
|
|
TrackElement* other;
|
|
Net* otherNet = NULL;
|
|
Interval otherOverlap;
|
|
bool otherIsGlobal = false;
|
|
|
|
track->getOverlapBounds( overlap, begin, end );
|
|
candidates.back().setBegin( begin );
|
|
candidates.back().setEnd ( end );
|
|
|
|
cdebug_log(159,0) << "* " << track << " [" << begin << ":" << end << "]" << endl;
|
|
|
|
for ( ; (begin < end) ; ++begin ) {
|
|
other = track->getSegment( begin );
|
|
otherIsGlobal = otherIsGlobal
|
|
or other->isGlobal()
|
|
or other->isBlockage()
|
|
or other->isFixed()
|
|
or other->isFixedAxis();
|
|
|
|
if (other->getNet() == segment->getNet()) {
|
|
cdebug_log(159,0) << " | " << begin << " Same net: " << " " << other << endl;
|
|
continue;
|
|
}
|
|
if (not other->getCanonicalInterval().intersect(overlap)) {
|
|
cdebug_log(159,0) << " | " << begin << " No Conflict: " << " " << other << endl;
|
|
if (otherNet == NULL) candidates.back().setBegin( begin+1 );
|
|
continue;
|
|
}
|
|
cdebug_log(159,0) << " | " << begin << " Conflict: " << " " << other << endl;
|
|
|
|
if (otherNet != other->getNet()) {
|
|
if (otherNet) {
|
|
if (otherIsGlobal) {
|
|
candidates.back().addConflict( otherOverlap );
|
|
cdebug_log(159,0) << " | Other overlap G: " << otherOverlap << endl;
|
|
} else {
|
|
cdebug_log(159,0) << " | Other overlap L: " << otherOverlap << " ignored." << endl;
|
|
}
|
|
}
|
|
otherNet = other->getNet();
|
|
otherOverlap = other->getCanonicalInterval();
|
|
otherIsGlobal = other->isGlobal() or other->isBlockage() or other->isFixed();
|
|
} else {
|
|
otherOverlap.merge(other->getCanonicalInterval());
|
|
otherIsGlobal = otherIsGlobal or other->isGlobal() or other->isBlockage() or other->isFixed() or other->isFixedAxis();
|
|
}
|
|
}
|
|
if (not otherOverlap.isEmpty()) {
|
|
if (otherIsGlobal) {
|
|
candidates.back().addConflict( otherOverlap );
|
|
cdebug_log(159,0) << " | Other overlap G: " << otherOverlap << endl;
|
|
} else {
|
|
cdebug_log(159,0) << " | Other overlap L: " << otherOverlap << " ignored." << endl;
|
|
}
|
|
}
|
|
|
|
candidates.back().consolidate();
|
|
}
|
|
|
|
sort( candidates.begin(), candidates.end() );
|
|
|
|
for ( size_t icandidate=0 ; icandidate<candidates.size() ; ++icandidate ) {
|
|
cdebug_log(159,0) << "Trying l:" << candidates[icandidate].getLength()
|
|
<< " " << candidates[icandidate].getTrack() << endl;
|
|
|
|
Interval overlap0 = candidates[icandidate].getLongestConflict();
|
|
cdebug_log(159,0) << "| overlap0: " << overlap0 << endl;
|
|
|
|
if (overlap0.isEmpty()) {
|
|
cdebug_log(159,0) << "overlap0 is empty, no conflict, ignoring Track candidate." << endl;
|
|
continue;
|
|
}
|
|
|
|
Track* track = candidates[icandidate].getTrack();
|
|
TrackElement* other = track->getSegment( overlap.getCenter() );
|
|
if (not other) {
|
|
cdebug_log(159,0) << "conflictSolveByPlaceds(): No segment under overlap center." << endl;
|
|
other = track->getSegment( overlap0.getCenter() );
|
|
|
|
if (not other) {
|
|
cdebug_log(159,0) << "conflictSolveByPlaceds(): No segment under overlap0 center." << endl;
|
|
continue;
|
|
}
|
|
}
|
|
cdebug_log(159,0) << "| other: " << other << endl;
|
|
|
|
if (Session::getConfiguration()->isVH() and (segment->getDepth() == 1)) {
|
|
if (Manipulator(segment,*this).makeDogleg(overlap0,Flags::ShortDogleg)) {
|
|
//cerr << "Break using ShortDogleg." << endl;
|
|
success = true;
|
|
break;
|
|
}
|
|
} else {
|
|
cdebug_log(159,0) << "conflictSolveByPlaceds() other->isGlobal():" << other->isGlobal() << endl;
|
|
if (other->isGlobal()) {
|
|
cdebug_log(159,0) << "conflictSolveByPlaceds() - Conflict with global, other move up" << endl;
|
|
if ((success = Manipulator(other,*this).moveUp(Manipulator::IgnoreContacts))) break;
|
|
}
|
|
|
|
cdebug_log(159,0) << "conflictSolveByPlaceds() - 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|Manipulator::NoDoglegReuse) ) {
|
|
cdebug_log(159,0) << "Cannot move up but successful narrow breaking." << endl;
|
|
success = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( not success and segment->isGlobal() and (_costs.size() <= 1) ) {
|
|
cdebug_log(159,0) << "Overconstrained perpandiculars, rip them up. On track:" << endl;
|
|
cdebug_log(159,0) << " " << track << endl;
|
|
Manipulator(segment,*this).ripupPerpandiculars ();
|
|
success = true;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
bool SegmentFsm::solveTerminalVsGlobal ()
|
|
{
|
|
TrackElement* segment = getEvent()->getSegment();
|
|
cdebug_log(159,0) << "SegmentFsm::solveTerminalVsGlobal: " << " " << segment << endl;
|
|
|
|
if (not (segment->isTerminal() and segment->isLocal())) return false;
|
|
|
|
for ( size_t icost=0 ; icost<_costs.size() ; ++icost ) {
|
|
Interval overlap = segment->getCanonicalInterval();
|
|
size_t begin;
|
|
size_t end;
|
|
getTrack1(icost)->getOverlapBounds( overlap, begin, end );
|
|
|
|
for ( ; begin<end ; ++begin ) {
|
|
TrackElement* other = getTrack1(icost)->getSegment(begin);
|
|
Interval otherOverlap = other->getCanonicalInterval();
|
|
|
|
if (other->getNet() == segment->getNet()) continue;
|
|
if (not other->isGlobal()) continue;
|
|
if (not otherOverlap.contains(overlap)) continue;
|
|
|
|
cdebug_log(159,0) << "| Global candidate:" << other << endl;
|
|
if (Manipulator(other,*this).moveUp(Manipulator::AllowTerminalMoveUp)) {
|
|
cdebug_log(159,0) << "| Global candidate selected." << endl;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool SegmentFsm::solveFullBlockages ()
|
|
{
|
|
bool success = false;
|
|
TrackElement* segment = getEvent()->getSegment();
|
|
|
|
cdebug_log(159,1) << "SegmentFsm::solveFullBlockages: " << " " << segment << endl;
|
|
|
|
if ( segment->isLocal() ) {
|
|
success = Manipulator(segment,*this).pivotUp();
|
|
if ( not success ) {
|
|
cdebug_log(159,0) << "Tightly constrained local segment overlapping a blockage, move up." << endl;
|
|
cdebug_log(159,0) << segment << endl;
|
|
success = Manipulator(segment,*this).moveUp
|
|
(Manipulator::AllowLocalMoveUp|Manipulator::AllowTerminalMoveUp);
|
|
}
|
|
} else if (not _costs.empty()) {
|
|
Interval overlap = segment->getCanonicalInterval();
|
|
size_t begin;
|
|
size_t end;
|
|
|
|
getTrack1(0)->getOverlapBounds ( overlap, begin, end );
|
|
for ( ; begin<end ; ++begin ) {
|
|
TrackElement* other = getTrack1(0)->getSegment(begin);
|
|
Interval otherOverlap = other->getCanonicalInterval();
|
|
|
|
if ( other->getNet() == segment->getNet() ) continue;
|
|
if ( not otherOverlap.intersect(overlap) ) continue;
|
|
|
|
cdebug_log(159,0) << "| " << begin << " Blockage conflict: " << " " << other << endl;
|
|
if ( (success = Manipulator(segment,*this).relax
|
|
(otherOverlap,Manipulator::NoDoglegReuse|Manipulator::NoExpand)) ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( not success ) {
|
|
cparanoid << Error( "Tighly constrained segment overlapping a blockage:\n %s"
|
|
, getString(segment).c_str() ) << endl;
|
|
cdebug_log(159,0) << "Segment is hard blocked, bypass to Unimplemented." << endl;
|
|
}
|
|
|
|
cdebug_tabw(159,-1);
|
|
return success;
|
|
}
|
|
|
|
|
|
bool SegmentFsm::desaturate ()
|
|
{
|
|
cdebug_log(159,1) << "SegmentFsm::desaturate()" << endl;
|
|
|
|
size_t itrack = 0;
|
|
|
|
#if THIS_IS_DISABLED
|
|
TrackElement* segment = getEvent()->getSegment();
|
|
for ( ; itrack<getCosts().size() ; ++itrack ) {
|
|
cdebug_log(159,0) << "Trying track:" << itrack << endl;
|
|
|
|
if ( getCost(itrack)->isGlobalEnclosed() ) {
|
|
Track* track = getTrack(itrack);
|
|
size_t begin = getBegin(itrack);
|
|
size_t end = getEnd (itrack);
|
|
Net* ownerNet = segment->getNet();
|
|
Interval toFree (segment->getCanonicalInterval());
|
|
bool success = true;
|
|
|
|
for ( size_t i = begin ; success and (i < end) ; i++ ) {
|
|
TrackElement* segment2 = track->getSegment(i);
|
|
|
|
cdebug_log(159,0) << "* Looking // " << segment2 << endl;
|
|
|
|
if ( segment2->getNet() == ownerNet ) continue;
|
|
if ( not toFree.intersect(segment2->getCanonicalInterval()) ) continue;
|
|
if ( segment2->isFixed() or not segment2->isBipoint() ) {
|
|
success = false;
|
|
continue;
|
|
}
|
|
|
|
DataNegociate* data2 = segment2->getDataNegociate();
|
|
if ( not data2 ) {
|
|
cdebug_log(159,0) << "No DataNegociate, ignoring." << endl;
|
|
success = false;
|
|
continue;
|
|
}
|
|
|
|
cdebug_log(159,0) << "- Forced moveUp " << segment2 << endl;
|
|
if ( not (success=Manipulator(segment2,*this).moveUp(Manipulator::AllowTerminalMoveUp)) ) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ( success ) {
|
|
setState ( SegmentFsm::OtherRipup );
|
|
addAction( segment
|
|
, SegmentAction::SelfInsert|SegmentAction::MoveToAxis
|
|
, getTrack1(itrack)->getAxis()
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
cdebug_tabw(159,-1);
|
|
return (itrack < _costs.size());
|
|
}
|
|
|
|
|
|
bool SegmentFsm::_slackenStrap ( TrackElement*& segment, DataNegociate*& data, uint32_t flags )
|
|
{
|
|
cdebug_log(159,0) << "Strap segment Fsm." << endl;
|
|
|
|
bool success = false;
|
|
uint32_t nextState = data->getState();
|
|
Manipulator manipulator ( segment, *this );
|
|
|
|
if (segment->isNonPref()
|
|
and not getCosts().empty()
|
|
and (getCost(0)->isBlockage() or getCost(0)->isAtRipupLimit())) {
|
|
cdebug_log(159,0) << "Non-preferred conflicts with a blockage or other's at ripup limit." << endl;
|
|
success = manipulator.avoidBlockage();
|
|
}
|
|
|
|
if (not success) {
|
|
switch ( data->getState() ) {
|
|
case DataNegociate::RipupPerpandiculars:
|
|
nextState = DataNegociate::Minimize;
|
|
success = manipulator.ripupPerpandiculars();
|
|
if (success) break;
|
|
case DataNegociate::Minimize:
|
|
if (data->getStateCount() >= 2) {
|
|
nextState = DataNegociate::Slacken;
|
|
}
|
|
success = manipulator.minimize();
|
|
if (success) break;
|
|
case DataNegociate::Dogleg:
|
|
case DataNegociate::Slacken:
|
|
if ((success = manipulator.slacken(Flags::HalfSlacken))) {
|
|
nextState = DataNegociate::LocalVsGlobal;
|
|
break;
|
|
}
|
|
case DataNegociate::LocalVsGlobal:
|
|
if (segment->isUnbreakable()) {
|
|
nextState = DataNegociate::MaximumSlack;
|
|
success = true;
|
|
break;
|
|
}
|
|
case DataNegociate::ConflictSolveByHistory:
|
|
case DataNegociate::ConflictSolveByPlaceds:
|
|
case DataNegociate::MoveUp:
|
|
case DataNegociate::MaximumSlack:
|
|
case DataNegociate::Unimplemented:
|
|
nextState = DataNegociate::Unimplemented;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (not success and (nextState != DataNegociate::Unimplemented))
|
|
success = manipulator.ripupPerpandiculars(Manipulator::ToRipupLimit);
|
|
|
|
// if (not (flags&NoTransition)) {
|
|
data->setState( nextState );
|
|
cdebug_log(159,0) << "Incrementing state (after): " << nextState << " count:" << data->getStateCount() << endl;
|
|
// }
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
bool SegmentFsm::_slackenLocal ( TrackElement*& segment, DataNegociate*& data, uint32_t flags )
|
|
{
|
|
cdebug_log(159,0) << "Local segment Fsm." << endl;
|
|
|
|
bool success = false;
|
|
uint32_t nextState = data->getState();
|
|
Manipulator manipulator ( segment, *this );
|
|
|
|
|
|
switch (data->getState()) {
|
|
case DataNegociate::RipupPerpandiculars:
|
|
if (segment->isDrag() and getCost(0)->isInfinite()) {
|
|
nextState = DataNegociate::Slacken;
|
|
success = manipulator.dragMinimize();
|
|
if (success) _minimizeDrag = true;
|
|
} else {
|
|
nextState = DataNegociate::Minimize;
|
|
success = manipulator.ripupPerpandiculars();
|
|
}
|
|
if (success) break;
|
|
case DataNegociate::Minimize:
|
|
if (nextState == DataNegociate::Minimize) {
|
|
if (isFullBlocked() and not segment->isTerminal()) {
|
|
cdebug_log(159,0) << "Is Fully blocked." << endl;
|
|
if (_costs.size() > 7) {
|
|
success = manipulator.moveUp( Manipulator::AllowLocalMoveUp );
|
|
if (success) {
|
|
cdebug_log(159,0) << "Was able to move up." << endl;
|
|
break;
|
|
}
|
|
}
|
|
nextState = DataNegociate::Unimplemented;
|
|
break;
|
|
}
|
|
nextState = DataNegociate::Dogleg;
|
|
success = manipulator.minimize();
|
|
if (success) break;
|
|
}
|
|
case DataNegociate::Dogleg:
|
|
if (nextState == DataNegociate::Dogleg) {
|
|
nextState = DataNegociate::Slacken;
|
|
success = manipulator.makeDogleg();
|
|
}
|
|
if (success) break;
|
|
case DataNegociate::Slacken:
|
|
if (nextState == DataNegociate::Slacken) {
|
|
nextState = DataNegociate::ConflictSolveByPlaceds;
|
|
success = manipulator.slacken();
|
|
if (success) break;
|
|
}
|
|
case DataNegociate::ConflictSolveByHistory:
|
|
case DataNegociate::ConflictSolveByPlaceds:
|
|
if ( (nextState == DataNegociate::ConflictSolveByHistory)
|
|
or (nextState == DataNegociate::ConflictSolveByPlaceds) ) {
|
|
nextState = DataNegociate::LocalVsGlobal;
|
|
success = conflictSolveByHistory();
|
|
break;
|
|
}
|
|
case DataNegociate::LocalVsGlobal:
|
|
if (nextState == DataNegociate::LocalVsGlobal) {
|
|
nextState = DataNegociate::MoveUp;
|
|
success = solveTerminalVsGlobal();
|
|
if (success) break;
|
|
}
|
|
case DataNegociate::MoveUp:
|
|
if (nextState == DataNegociate::LocalVsGlobal) {
|
|
nextState = DataNegociate::MaximumSlack;
|
|
success = manipulator.moveUp();
|
|
if (success) break;
|
|
}
|
|
case DataNegociate::MaximumSlack:
|
|
if (nextState == DataNegociate::MaximumSlack) {
|
|
if (segment->isStrap()) {
|
|
if ( (nextState < DataNegociate::MaximumSlack) or (data->getStateCount() < 2) ) {
|
|
nextState = DataNegociate::MaximumSlack;
|
|
success = conflictSolveByPlaceds();
|
|
if (success) break;
|
|
}
|
|
}
|
|
}
|
|
case DataNegociate::Unimplemented:
|
|
//if (segment->isDrag()) cerr << "Slacken DRAG:" << segment << endl;
|
|
nextState = DataNegociate::Unimplemented;
|
|
break;
|
|
}
|
|
|
|
if (not success and (nextState != DataNegociate::Unimplemented)) {
|
|
if (data->getStateCount() < 6)
|
|
success = manipulator.ripupPerpandiculars(Manipulator::ToRipupLimit);
|
|
}
|
|
|
|
if (not success
|
|
and (nextState == DataNegociate::Unimplemented)
|
|
and segment->isSlackened()
|
|
and isFullBlocked()) {
|
|
if (solveFullBlockages()) nextState = DataNegociate::MoveUp;
|
|
}
|
|
|
|
// if (not (flags&NoTransition)) {
|
|
data->setState( nextState );
|
|
cdebug_log(159,0) << "Incrementing state (after): "
|
|
<< DataNegociate::getStateString(nextState,data->getStateCount()) << endl;
|
|
// }
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
bool SegmentFsm::_slackenGlobal ( TrackElement*& segment, DataNegociate*& data, uint32_t flags )
|
|
{
|
|
bool success = false;
|
|
uint32_t nextState = data->getState();
|
|
Manipulator manipulator ( segment, *this );
|
|
uint32_t moveUpFlags = Manipulator::AllowShortPivotUp|Manipulator::IgnoreContacts;
|
|
|
|
switch ( data->getState() ) {
|
|
case DataNegociate::RipupPerpandiculars:
|
|
case DataNegociate::Minimize:
|
|
case DataNegociate::Dogleg:
|
|
if (NetRoutingExtension::isAnalog(segment->getNet())) {
|
|
cdebug_log(159,0) << "Global, SegmentFsm / Analogic: Try to dogleg once." << endl;
|
|
success = manipulator.makeDogleg( segment->getCanonicalInterval().getCenter() );
|
|
if (success) break;
|
|
} else {
|
|
cdebug_log(159,0) << "Global, SegmentFsm: RipupPerpandiculars." << endl;
|
|
}
|
|
nextState = DataNegociate::Slacken;
|
|
break;
|
|
case DataNegociate::Slacken:
|
|
cdebug_log(159,0) << "Global, SegmentFsm: Slacken "
|
|
<< ((manipulator.getEvent())
|
|
? manipulator.getEvent()->getConstraints() : "(no event yet)") << endl;
|
|
if ( manipulator.getEvent()
|
|
and ( manipulator.getEvent()->getConstraints().isPonctual()
|
|
or (isFullBlocked() and (_costs.size() > 7)))
|
|
and segment->canMoveUp(1.0,Flags::CheckLowUpDensity|Flags::AllowTerminal) ) {
|
|
cdebug_log(159,0) << "Next state: MoveUp." << endl;
|
|
moveUpFlags |= Manipulator::AllowTerminalMoveUp;
|
|
} else {
|
|
if ((success = manipulator.slacken(Flags::HalfSlacken))) {
|
|
nextState = DataNegociate::RipupPerpandiculars;
|
|
cdebug_log(159,0) << "Next state: RipupPerpandiculars (half-slacken succeeded)." << endl;
|
|
break;
|
|
}
|
|
}
|
|
case DataNegociate::MoveUp:
|
|
cdebug_log(159,0) << "Global, SegmentFsm: MoveUp." << endl;
|
|
if ((success = manipulator.moveUp(moveUpFlags))) {
|
|
break;
|
|
}
|
|
nextState = DataNegociate::ConflictSolveByHistory;
|
|
break;
|
|
case DataNegociate::ConflictSolveByHistory:
|
|
case DataNegociate::ConflictSolveByPlaceds:
|
|
cdebug_log(159,0) << "Global, SegmentFsm: ConflictSolveByHistory or ConflictSolveByPlaceds." << endl;
|
|
if ((success = conflictSolveByPlaceds())) {
|
|
if (segment->canMoveUp(1.0,Flags::CheckLowDensity))
|
|
nextState = DataNegociate::MoveUp;
|
|
else {
|
|
if (data->getStateCount() > 3)
|
|
nextState = DataNegociate::MaximumSlack;
|
|
}
|
|
if (segment->getDataNegociate()->getState() < DataNegociate::ConflictSolveByHistory)
|
|
nextState = segment->getDataNegociate()->getState();
|
|
break;
|
|
}
|
|
case DataNegociate::MaximumSlack:
|
|
if ((success=manipulator.forceOverLocals())) {
|
|
break;
|
|
}
|
|
case DataNegociate::Unimplemented:
|
|
cdebug_log(159,0) << "Global, SegmentFsm: MaximumSlack or Unimplemented." << endl;
|
|
nextState = DataNegociate::Unimplemented;
|
|
break;
|
|
}
|
|
|
|
if (not success and (nextState != DataNegociate::Unimplemented)) {
|
|
if (data->getStateCount() < 6)
|
|
success = manipulator.ripupPerpandiculars(Manipulator::ToRipupLimit);
|
|
}
|
|
|
|
// Special case: all tracks are overlaping a blockage.
|
|
if (not success
|
|
and (nextState == DataNegociate::Unimplemented)
|
|
and segment->isSlackened() ) {
|
|
if (solveFullBlockages()) nextState = DataNegociate::MoveUp;
|
|
}
|
|
|
|
//if (not (flags&NoTransition)) {
|
|
if (data->getChildSegment()) {
|
|
TrackElement* child = segment;
|
|
cdebug_log(159,0) << "Incrementing state of childs (after): " << endl;
|
|
while ( child ) {
|
|
cdebug_log(159,0) << "| " << child << endl;
|
|
if (child->base()->isGlobal()) {
|
|
child->getDataNegociate()->setState( nextState );
|
|
cdebug_log(159,0) << "| Update:" << nextState << " count:" << child->getDataNegociate()->getStateCount() << endl;
|
|
}
|
|
TrackElement* parent = child;
|
|
child = parent->getDataNegociate()->getChildSegment();
|
|
parent->getDataNegociate()->setChildSegment( NULL );
|
|
}
|
|
} else {
|
|
data->setState( nextState );
|
|
cdebug_log(159,0) << "Incrementing state (after): " << segment << endl;
|
|
cdebug_log(159,0) << "| " << nextState << " count:" << data->getStateCount() << endl;
|
|
}
|
|
//}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
bool SegmentFsm::slackenTopology ( uint32_t flags )
|
|
{
|
|
bool success = false;
|
|
TrackElement* segment1 = getSegment1();
|
|
uint32_t actionFlags = SegmentAction::SelfInsert|SegmentAction::EventLevel5;
|
|
|
|
DebugSession::open( segment1->getNet(), 156, 160 );
|
|
cdebug_log(159,1) << "Slacken Topology for " << segment1->getNet()
|
|
<< " " << segment1 << endl;
|
|
|
|
if (_data2) {
|
|
cdebug_log(159,0) << "Symmetric segments are not allowed to slacken (yet)" << endl;
|
|
cdebug_tabw(159,-1);
|
|
DebugSession::close();
|
|
return false;
|
|
}
|
|
|
|
if (segment1->isShortNet()) {
|
|
cdebug_log(159,0) << "Short net segments are not allowed to slacken" << endl;
|
|
cdebug_tabw(159,-1);
|
|
DebugSession::close();
|
|
return false;
|
|
}
|
|
|
|
if (not segment1 or not _data1) { cdebug_tabw(159,-1); DebugSession::close(); return false; }
|
|
|
|
_event1->resetInsertState();
|
|
_data1->resetRipupCount();
|
|
if (_event2) {
|
|
_event2->resetInsertState();
|
|
_data2->resetRipupCount();
|
|
}
|
|
|
|
if (segment1->isStrap() or segment1->isUnbreakable())
|
|
success = _slackenStrap ( segment1, _data1, flags );
|
|
else if (segment1->isLocal())
|
|
success = _slackenLocal ( segment1, _data1, flags );
|
|
else
|
|
success = _slackenGlobal( segment1, _data1, flags );
|
|
|
|
if (success) {
|
|
actionFlags |= SegmentAction::ResetRipup;
|
|
if (isMinimizeDrag()) {
|
|
actionFlags &= ~SegmentAction::EventLevel5;
|
|
actionFlags |= SegmentAction::EventLevel3;
|
|
}
|
|
if (segment1->isNonPref()) {
|
|
actionFlags &= ~SegmentAction::AllEventLevels;
|
|
}
|
|
addAction( segment1, actionFlags );
|
|
} else {
|
|
clearActions();
|
|
if (_data1->getState() == DataNegociate::Unimplemented) {
|
|
cinfo << "[UNSOLVED] " << segment1 << " unable to slacken topology." << endl;
|
|
}
|
|
}
|
|
|
|
cdebug_tabw(159,-1);
|
|
DebugSession::close();
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
} // Katana namespace.
|