coriolis/katana/src/SegmentFsm.cpp

1441 lines
51 KiB
C++

// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2008-2016, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | 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 : "CompareCostArray".
class CompareCostArray {
public:
inline CompareCostArray ( uint32_t flags=0 );
inline bool operator() ( const array<TrackCost,2>& lhs, const array<TrackCost,2>& rhs );
private:
TrackCost::Compare _compare;
};
inline CompareCostArray::CompareCostArray ( uint32_t flags )
: _compare(flags)
{ }
inline bool CompareCostArray::operator() ( const array<TrackCost,2>& lhs, const array<TrackCost,2>& rhs )
{ return _compare( lhs[0], rhs[0] ); }
// -------------------------------------------------------------------
// 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 & Perpandicular) {
cdebug_log(159,0) << "* Riping Pp " << _segment << endl;
} else {
cdebug_log(159,0) << "* Riping // " << _segment << endl;
}
if (_segment->isFixed()) { DebugSession::close(); return true; }
DataNegociate* data = _segment->getDataNegociate();
if (data == NULL) { DebugSession::close(); return true; }
if (_type & ResetRipup) data->resetRipupCount();
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 & 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 );
if (fork) {
uint32_t mode = RoutingEvent::Repair;
if (RoutingEvent::getStage() < RoutingEvent::Repair)
mode = (_type&PackingMode) ? RoutingEvent::Pack : RoutingEvent::Negociate;
fork->setMode( mode );
}
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)
{
DataSymmetric* symData = NULL;
TrackElement* segment1 = _event1->getSegment();
TrackElement* segment2 = segment1->getSymmetric();
uint32_t depth = Session::getRoutingGauge()->getLayerDepth(segment1->getLayer());
_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;
_state = EmptyTrackList;
}
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) );
bool inLocalDepth = (depth < 3);
bool isOneLocalTrack = (segment1->isLocal())
and (segment1->base()->getAutoSource()->getGCell()->getGlobalsCount(depth) >= 9.0);
RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(segment1->getLayer());
for ( Track* track1 : Tracks_Range::get(plane,_constraint) ) {
uint32_t costflags = 0;
costflags |= (segment1->isLocal() and (depth >= 3)) ? TrackCost::LocalAndTopDepth : 0;
costflags |= (segment1->isAnalog()) ? TrackCost::Analog : 0;
Track* track2 = NULL;
if (_event2) {
track2 =
(_sameAxis) ? track1 : plane->getTrackByPosition( symData->getSymmetrical( track1->getAxis() ) );
}
_costs.push_back( array<TrackCost,2>( { TrackCost(NULL), TrackCost(NULL) } ) );
if (not segment1->isReduced()) {
_costs.back()[0] = track1->getOverlapCost(segment1,costflags);
if (_event2) _costs.back()[1] = track2->getOverlapCost(segment2,costflags);
} else {
_costs.back()[0] = TrackCost(track1);
if (_event2) _costs.back()[1] = TrackCost(track2);
}
_costs.back()[0].setAxisWeight ( _event1->getAxisWeight(track1->getAxis()) );
_costs.back()[0].incDeltaPerpand( _data1->getWiringDelta(track1->getAxis()) );
if (_event2) {
_costs.back()[1].setAxisWeight ( _event2->getAxisWeight(track2->getAxis()) );
_costs.back()[1].incDeltaPerpand( _data2->getWiringDelta(track2->getAxis()) );
_costs.back()[0].merge( _costs.back()[1] );
}
if (segment1->isGlobal()) {
cdebug_log(9000,0) << "Deter| setForGlobal() on " << track1 << endl;
_costs.back()[0].setForGlobal();
}
if ( inLocalDepth and (_costs.back()[0].getDataState() == DataNegociate::MaximumSlack) )
_costs.back()[0].setInfinite();
if ( isOneLocalTrack
and _costs.back()[0].isOverlapGlobal()
and (_costs.back()[0].getDataState() >= DataNegociate::ConflictSolveByHistory) )
_costs.back()[0].setInfinite();
_costs.back()[0].consolidate();
if ( _fullBlocked and (not _costs.back()[0].isBlockage() and not _costs.back()[0].isFixed()) )
_fullBlocked = false;
cdebug_log(155,0) << "| " << _costs.back()[0] << ((_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 |= (RoutingEvent::getStage() == RoutingEvent::Repair) ? TrackCost::IgnoreSharedLength : 0;
if (flags & TrackCost::DiscardGlobals) {
cdebug_log(159,0) << "TrackCost::Compare() - DiscardGlobals" << endl;
}
// FOR ANALOG ONLY.
//flags |= TrackCost::IgnoreSharedLength;
sort( _costs.begin(), _costs.end(), CompareCostArray(flags) );
size_t i=0;
for ( ; (i<_costs.size()) and _costs[i][0].isFree() ; i++ );
_event1->setTracksFree ( i );
if (_event2) {
for ( ; (i<_costs.size()) and _costs[i][1].isFree() ; i++ );
_event2->setTracksFree ( i );
}
}
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() );
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() @" << getCost1(i).getTrack() << endl;
Session::addInsertEvent( getSegment1(), getCost1(i).getTrack() );
if (_event2) {
_event2->resetInsertState();
_event2->updateAxisHistory();
_event2->setEventLevel( 0 );
_event2->setProcessed( true );
cdebug_log(9000,0) << "Deter| addInsertEvent() @" << getCost1(i).getTrack() << endl;
Session::addInsertEvent( getSegment2(), getCost2(i).getTrack() );
}
setState( SegmentFsm::SelfInserted );
}
void SegmentFsm::moveToTrack ( size_t i )
{
cdebug_log(159,0) << "SegmentFsm::moveToTrack() :" << " track:" << i << endl;
Session::addMoveEvent( getSegment1(), getCost1(i).getTrack() );
if (_event2) {
cdebug_log(9000,0) << "Deter| addInsertEvent() @" << getCost1(i).getTrack() << endl;
Session::addMoveEvent( getSegment2(), getCost2(i).getTrack() );
}
setState( SegmentFsm::SelfInserted );
}
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;
Interval freeSpan = Session::getKatanaEngine()->
getTrackByPosition(segment->getLayer(),segment->getAxis())->
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 );
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();
}
}
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) {
cbug << Error("conflictSolveByPlaceds(): No segment under overlap center.") << endl;
continue;
}
if (other->isGlobal()) {
cdebug_log(159,0) << "conflictSolveByPlaceds() - Conflict with global, other move up" << endl;
if ((success = Manipulator(other,*this).moveUp())) 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;
getCost(icost).getTrack()->getOverlapBounds( overlap, begin, end );
for ( ; begin<end ; ++begin ) {
TrackElement* other = getCost(icost).getTrack()->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 {
Interval overlap = segment->getCanonicalInterval();
size_t begin;
size_t end;
getCost(0).getTrack()->getOverlapBounds ( overlap, begin, end );
for ( ; begin<end ; ++begin ) {
TrackElement* other = getCost(0).getTrack()->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
, getCost(itrack).getTrack()->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 );
switch ( data->getState() ) {
case DataNegociate::RipupPerpandiculars:
nextState = DataNegociate::Minimize;
success = manipulator.ripupPerpandiculars();
if (success) break;
case DataNegociate::Minimize:
if (data->getStateCount() >= 2) {
nextState = DataNegociate::MaximumSlack;
}
success = manipulator.minimize();
if (success) break;
case DataNegociate::Dogleg:
case DataNegociate::Slacken:
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:
nextState = DataNegociate::Minimize;
success = manipulator.ripupPerpandiculars();
if (success) break;
case DataNegociate::Minimize:
if (isFullBlocked() and not segment->isTerminal()) {
cdebug_log(159,0) << "Is Fully blocked." << endl;
nextState = DataNegociate::Unimplemented;
break;
}
nextState = DataNegociate::Dogleg;
success = manipulator.minimize();
if (success) break;
case DataNegociate::Dogleg:
nextState = DataNegociate::Slacken;
success = manipulator.makeDogleg();
if (success) break;
case DataNegociate::Slacken:
nextState = DataNegociate::ConflictSolveByPlaceds;
success = manipulator.slacken();
if (success) break;
case DataNegociate::ConflictSolveByHistory:
case DataNegociate::ConflictSolveByPlaceds:
nextState = DataNegociate::LocalVsGlobal;
success = conflictSolveByHistory();
break;
case DataNegociate::LocalVsGlobal:
nextState = DataNegociate::MoveUp;
success = solveTerminalVsGlobal();
if (success) break;
break;
case DataNegociate::MoveUp:
nextState = DataNegociate::MaximumSlack;
success = manipulator.moveUp();
if (success) break;
case DataNegociate::MaximumSlack:
if (segment->isStrap()) {
if ( (nextState < DataNegociate::MaximumSlack) or (data->getStateCount() < 2) ) {
nextState = DataNegociate::MaximumSlack;
success = conflictSolveByPlaceds();
if (success) break;
}
}
case DataNegociate::Unimplemented:
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): " << nextState << " count:" << 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:
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() : "(not event yet)") << endl;
if ( manipulator.getEvent()
and manipulator.getEvent()->getConstraints().isPonctual()
and segment->canMoveUp(1.0,Flags::CheckLowUpDensity|Flags::AllowTerminal) ) {
moveUpFlags |= Manipulator::AllowTerminalMoveUp;
} else {
if ((success = manipulator.slacken(Flags::HalfSlacken))) {
nextState = DataNegociate::RipupPerpandiculars;
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 (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()) { 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;
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.