507 lines
17 KiB
C++
507 lines
17 KiB
C++
// -*- mode: C++; explicit-buffer-name: "Session.cpp<katana>" -*-
|
|
//
|
|
// 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@asim.lip6.fr |
|
|
// | =============================================================== |
|
|
// | C++ Module : "./Session.cpp" |
|
|
// +-----------------------------------------------------------------+
|
|
|
|
|
|
#include "hurricane/Bug.h"
|
|
#include "hurricane/Point.h"
|
|
#include "hurricane/Error.h"
|
|
#include "hurricane/RoutingPad.h"
|
|
#include "anabatic/AutoContactTerminal.h"
|
|
#include "katana/Session.h"
|
|
#include "katana/Track.h"
|
|
#include "katana/TrackElement.h"
|
|
#include "katana/KatanaEngine.h"
|
|
#include "katana/RoutingPlane.h"
|
|
#include "katana/NegociateWindow.h"
|
|
|
|
|
|
namespace {
|
|
|
|
using namespace std;
|
|
using namespace Hurricane;
|
|
using namespace CRL;
|
|
using namespace Katana;
|
|
using Anabatic::perpandicularTo;
|
|
using Anabatic::AutoSegment;
|
|
using Anabatic::AutoContactTerminal;
|
|
using Anabatic::AutoSegments_OnContact;
|
|
using Anabatic::AutoSegments;
|
|
|
|
|
|
const char* reopenSession = "Katana::Session::_open(): Session already open for %s (internal error).";
|
|
|
|
|
|
void metal2protect ( AutoContactTerminal* contact )
|
|
{
|
|
const Layer* metal2 = Session::getRoutingLayer(1);
|
|
RoutingPlane* metal3plane = Session::getKatanaEngine()->getRoutingPlaneByIndex( 2 );
|
|
DbU::Unit metal3axis = metal3plane->getTrackByPosition( contact->getY() )->getAxis();
|
|
RoutingPad* rp = dynamic_cast<RoutingPad*>( contact->getAnchor() );
|
|
DbU::Unit viaSideProtect = Session::getViaWidth((size_t)0);
|
|
Point position ( contact->getX(), metal3axis );
|
|
|
|
AutoContact* sourceVia12 = AutoContactTerminal::create( contact->getGCell()
|
|
, rp
|
|
, metal2
|
|
, position
|
|
, viaSideProtect, viaSideProtect
|
|
);
|
|
AutoContact* targetVia12 = AutoContactTerminal::create( contact->getGCell()
|
|
, rp
|
|
, metal2
|
|
, position
|
|
, viaSideProtect, viaSideProtect
|
|
);
|
|
|
|
AutoSegment* segment = AutoSegment::create( sourceVia12, targetVia12, Flags::Vertical );
|
|
|
|
sourceVia12->setFlags( Anabatic::CntFixed|Anabatic::CntIgnoreAnchor );
|
|
targetVia12->setFlags( Anabatic::CntFixed|Anabatic::CntIgnoreAnchor );
|
|
segment->setFlags( AutoSegment::SegFixed );
|
|
|
|
Session::getNegociateWindow()->createTrackSegment( segment, Flags::NoFlags );
|
|
|
|
cdebug_log(145,0) << "Hard protect: " << contact << endl;
|
|
cdebug_log(145,0) << "X:" << DbU::getValueString(position.getX())
|
|
<< " Metal3 Track Y:" << DbU::getValueString(metal3axis) << endl;
|
|
}
|
|
|
|
|
|
} // Anonymous namespace.
|
|
|
|
|
|
namespace Katana {
|
|
|
|
using std::cerr;
|
|
using std::endl;
|
|
using Hurricane::tab;
|
|
using Hurricane::Error;
|
|
using Hurricane::Bug;
|
|
using Hurricane::Point;
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "Session".
|
|
|
|
Session::Session ( KatanaEngine* katana )
|
|
: Super(katana)
|
|
, _indirectInvalids()
|
|
, _insertEvents ()
|
|
, _removeEvents ()
|
|
, _sortEvents ()
|
|
{ }
|
|
|
|
|
|
void Session::_postCreate ()
|
|
{ Super::_postCreate(); }
|
|
|
|
|
|
Session::~Session ()
|
|
{ }
|
|
|
|
|
|
void Session::_preDestroy ()
|
|
{
|
|
Super::_preDestroy();
|
|
_isEmpty();
|
|
}
|
|
|
|
|
|
Session* Session::_open ( KatanaEngine* katana )
|
|
{
|
|
cdebug_log(159,0) << "Katana::Session::_open()" << endl;
|
|
|
|
Session* session = Session::get();
|
|
if (session) {
|
|
if (session->_getKatanaEngine() != katana)
|
|
throw Error( reopenSession, getString(session->getKatanaEngine()).c_str() );
|
|
|
|
return session;
|
|
}
|
|
|
|
session = new Session ( katana );
|
|
session->_postCreate();
|
|
|
|
return session;
|
|
}
|
|
|
|
|
|
Session* Session::get ( const char* message )
|
|
{ return dynamic_cast<Session*>( Super::get(message) ); }
|
|
|
|
|
|
Configuration* Session::getConfiguration ()
|
|
{ return Session::getKatanaEngine()->getConfiguration(); }
|
|
|
|
|
|
uint32_t Session::getStage ()
|
|
{ return get("getStage()")->_getKatanaEngine()->getStage(); }
|
|
|
|
|
|
AutoContact* Session::lookup ( Contact* contact )
|
|
{ return Super::lookup(contact); }
|
|
|
|
|
|
TrackElement* Session::lookup ( Segment* segment )
|
|
{ return Session::get("Session::lookup(Segment*)")->_getKatanaEngine()->_lookup(segment); }
|
|
|
|
|
|
TrackElement* Session::lookup ( AutoSegment* segment )
|
|
{ return Session::get("lookup(AutoSegment*)")->_getKatanaEngine()->_lookup ( segment ); }
|
|
|
|
|
|
void Session::addShortDogleg ( TrackElement* segmentA, TrackElement* segmentB )
|
|
{ Session::get("addShortDogleg(AutoSegment*)")->_getKatanaEngine()->_addShortDogleg( segmentA, segmentB ); }
|
|
|
|
|
|
TrackElement* Session::getDoglegPaired ( TrackElement* segment )
|
|
{ return Session::get("getDoglegPaired(AutoSegment*)")->_getKatanaEngine()->_getDoglegPaired( segment ); }
|
|
|
|
|
|
void Session::setInterrupt ( bool state )
|
|
{ Session::get("setInterrupt()")->_getKatanaEngine()->setInterrupt(state); }
|
|
|
|
|
|
KatanaEngine* Session::_getKatanaEngine ()
|
|
{ return static_cast<KatanaEngine*>(_anabatic); }
|
|
|
|
|
|
Net* Session::_getBlockageNet ()
|
|
{ return _getKatanaEngine()->getBlockageNet(); };
|
|
|
|
|
|
NegociateWindow* Session::_getNegociateWindow ()
|
|
{ return _getKatanaEngine()->getNegociateWindow(); };
|
|
|
|
|
|
uint32_t Session::_getRipupCost ()
|
|
{ return _getKatanaEngine()->getRipupCost(); };
|
|
|
|
|
|
Anabatic::GCell* Session::_getGCellUnder ( DbU::Unit x, DbU::Unit y )
|
|
{ return _getKatanaEngine()->getGCellUnder(Point(x,y)); };
|
|
|
|
|
|
Interval& Session::_toAxisInterval ( Interval& interval, size_t depth ) const
|
|
{
|
|
RoutingLayerGauge* rg = getLayerGauge(depth);
|
|
if (not rg) return interval;
|
|
|
|
Box ab = getKatanaEngine()->getCell()->getAbutmentBox();
|
|
DbU::Unit abMin = (rg->isHorizontal()) ? ab.getYMin() : ab.getXMin();
|
|
DbU::Unit abMax = (rg->isHorizontal()) ? ab.getYMax() : ab.getXMax() ;
|
|
|
|
DbU::Unit trackMin = rg->getTrackPosition( abMin, abMax, interval.getVMin(), Constant::Superior );
|
|
DbU::Unit trackMax = rg->getTrackPosition( abMin, abMax, interval.getVMax(), Constant::Inferior );
|
|
interval = Interval( trackMin, trackMax );
|
|
|
|
return interval;
|
|
}
|
|
|
|
|
|
void Session::_doRemovalEvents ( bool reschedule )
|
|
{
|
|
cdebug_log(159,1) << "Katana::Session::_doRemovalEvents()" << endl;
|
|
|
|
TrackSet packTracks;
|
|
|
|
for ( size_t i=0 ; i<_removeEvents.size() ; ++i ) {
|
|
cdebug_log(159,0) << "Remove event for:" << _removeEvents[i]._segment << endl;
|
|
|
|
if (not _removeEvents[i]._segment->getTrack()) continue;
|
|
_removeEvents[i]._segment->detach( packTracks );
|
|
if (reschedule) _removeEvents[i]._segment->reschedule( 0 );
|
|
}
|
|
_removeEvents.clear();
|
|
|
|
for ( TrackSet::iterator it=packTracks.begin() ; it != packTracks.end() ; ++it )
|
|
(*it)->doRemoval();
|
|
|
|
cdebug_tabw(159,-1);
|
|
}
|
|
|
|
|
|
void Session::_doLockEvents ()
|
|
{
|
|
for ( size_t i=0 ; i<_lockEvents.size() ; ++i ) {
|
|
AutoContactTerminal* source = dynamic_cast<AutoContactTerminal*>( _lockEvents[i]._segment->base()->getAutoSource() );
|
|
AutoContactTerminal* target = dynamic_cast<AutoContactTerminal*>( _lockEvents[i]._segment->base()->getAutoTarget() );
|
|
if (source and source->canDrag()) metal2protect( source );
|
|
if (target and target->canDrag()) metal2protect( target );
|
|
}
|
|
_lockEvents.clear();
|
|
}
|
|
|
|
|
|
size_t Session::_revalidate ()
|
|
{
|
|
cdebug_log(159,1) << "Katana::Session::_revalidate()" << endl;
|
|
uint32_t overlaps = 0;
|
|
|
|
//Track* checkTrack = NULL;
|
|
//if (getKatanaEngine()->getRoutingPlaneByIndex( 1 ))
|
|
// checkTrack = getKatanaEngine()->getRoutingPlaneByIndex( 1 )->getTrackByIndex( 87 );
|
|
|
|
_doLockEvents();
|
|
_doRemovalEvents();
|
|
//if (checkTrack) checkTrack->check( overlaps, "Session::_revalidate() - check track 82 @270." );
|
|
|
|
for ( const Event& event : _insertEvents ) {
|
|
if (event._segment) {
|
|
if (event._segment->getAxis() != event._axis) event._segment->setAxis( event._axis );
|
|
if (not event._segment->isReduced()) event._track->insert( event._segment );
|
|
}
|
|
if (event._marker) event._track->insert( event._marker );
|
|
}
|
|
_insertEvents.clear();
|
|
_doRemovalEvents( false );
|
|
//if (checkTrack) checkTrack->check( overlaps, "Session::_revalidate() - check track 82 @270." );
|
|
|
|
// Check if to be destroyeds are not associateds with TrackSegments.
|
|
const set<AutoSegment*>& destroyeds = getDestroyeds();
|
|
set<AutoSegment*>::const_iterator idestroyed = destroyeds.begin();
|
|
for ( ; idestroyed != destroyeds.end() ; ++idestroyed ) {
|
|
if (lookup(*idestroyed)) {
|
|
cdebug_tabw(155,-1);
|
|
throw Error( "Destroyed AutoSegment is associated with a TrackSegment\n"
|
|
" (%s)"
|
|
, getString(*idestroyed).c_str());
|
|
}
|
|
}
|
|
|
|
size_t count = Super::_revalidate();
|
|
|
|
Interval span;
|
|
const vector<AutoSegment*>& revalidateds = getRevalidateds();
|
|
//const set<Net*>& netsModificateds = getNetsModificateds();
|
|
|
|
for ( size_t i=0 ; i<revalidateds.size() ; ++i ) {
|
|
if (not revalidateds[i]->isCanonical()) continue;
|
|
|
|
//Net* currentNet = NULL;
|
|
TrackElement* trackSegment = lookup( revalidateds[i] );
|
|
|
|
if (trackSegment and trackSegment->isInvalidated()) {
|
|
trackSegment->revalidate();
|
|
}
|
|
}
|
|
_doglegReset();
|
|
|
|
for ( Track* track : _sortEvents ) {
|
|
track->doReorder();
|
|
if (cdebug.enabled()) {
|
|
track->check( overlaps, "Session::_revalidate() - track sorting." );
|
|
}
|
|
# if defined(CHECK_DATABASE)
|
|
track->check( overlaps, "Session::_revalidate() - track sorting." );
|
|
# endif
|
|
}
|
|
|
|
# if defined(CHECK_DATABASE)
|
|
for ( set<Track*>::iterator it=packTracks.begin() ; it != packTracks.end() ; ++it )
|
|
(*it)->check( overlaps, "Session::_revalidate() - on packed track." );
|
|
|
|
for ( size_t i=0 ; i<revalidateds.size() ; ++i ) {
|
|
revalidateds[i]->check();
|
|
}
|
|
# endif
|
|
|
|
_sortEvents.clear();
|
|
|
|
// Looking for reduced/raised segments.
|
|
for ( size_t i=0 ; i<revalidateds.size() ; ++i ) {
|
|
if (revalidateds[i]->mustRaise()) {
|
|
cdebug_log(159,0) << "Session: raise:" << revalidateds[i] << endl;
|
|
revalidateds[i]->raise();
|
|
TrackElement* trackSegment = lookup( revalidateds[i] );
|
|
if (trackSegment) trackSegment->reschedule( 0 );
|
|
}
|
|
// if (revalidateds[i]->isUnderMinLength()) {
|
|
// cdebug_log(159,0) << "Session: under min length:" << revalidateds[i] << endl;
|
|
// revalidateds[i]->expandToMinLength();
|
|
// TrackElement* trackSegment = lookup( revalidateds[i] );
|
|
// if (trackSegment) {
|
|
// trackSegment->invalidate();
|
|
// trackSegment->reschedule( 0 );
|
|
// }
|
|
// } else {
|
|
// if (revalidateds[i]->isAtMinArea()) {
|
|
// if (revalidateds[i]->unexpandToMinLength()) {
|
|
// TrackElement* trackSegment = lookup( revalidateds[i] );
|
|
// if (trackSegment) {
|
|
// trackSegment->invalidate();
|
|
// trackSegment->reschedule( 0 );
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
if (revalidateds[i]->canReduce()) {
|
|
revalidateds[i]->reduce();
|
|
TrackElement* trackSegment = lookup( revalidateds[i] );
|
|
if (trackSegment and trackSegment->getTrack()) _addRemoveEvent( trackSegment );
|
|
cdebug_log(159,0) << "Session: reduce:" << revalidateds[i] << endl;
|
|
}
|
|
}
|
|
|
|
// for ( TrackElement* trackSegment : _indirectInvalids ) {
|
|
// cdebug_log(159,0) << "Indirect reschedule:" << trackSegment << endl;
|
|
// trackSegment->reschedule( 0 );
|
|
// // addRemoveEvent( trackSegment );
|
|
|
|
// // if (trackSegment->getDataNegociate() and trackSegment->getDataNegociate()->hasRoutingEvent()) {
|
|
// // RoutingEvent* event = trackSegment->getDataNegociate()->getRoutingEvent();
|
|
// // if ( not event->isDisabled()
|
|
// // and not event->isUnimplemented()
|
|
// // and event->isProcessed()) {
|
|
// // trackSegment->reschedule( 0 );
|
|
// // }
|
|
// // }
|
|
// }
|
|
_indirectInvalids.clear();
|
|
|
|
_doRemovalEvents();
|
|
for ( Track* track : _sortEvents ) track->doReorder();
|
|
_sortEvents.clear();
|
|
|
|
cdebug_tabw(159,-1);
|
|
return count;
|
|
}
|
|
|
|
|
|
bool Session::_isEmpty () const
|
|
{
|
|
if ( not _insertEvents.empty() or not _removeEvents.empty() or not _sortEvents.empty() ) {
|
|
cerr << Bug( "Session::_isEmpty() failed :\n"
|
|
" %u inserts, %u removes and %u sort events remains."
|
|
, _insertEvents.size()
|
|
, _removeEvents.size()
|
|
, _sortEvents .size() ) << endl;
|
|
if (not _sortEvents.empty()) {
|
|
cerr << " Remaining sort events on Tracks:" << endl;
|
|
for ( Track* track : _sortEvents ) {
|
|
cerr << " | " << track << endl;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Session::_disableStackedVias ()
|
|
{ return _getKatanaEngine()->getConfiguration()->disableStackedVias(); }
|
|
|
|
|
|
void Session::_addInsertEvent ( TrackMarker* marker, Track* track )
|
|
{
|
|
_insertEvents.push_back( Event(marker,track) );
|
|
_addSortEvent( track, true );
|
|
}
|
|
|
|
|
|
void Session::_addInsertEvent ( TrackElement* segment, Track* track, DbU::Unit axis, bool check )
|
|
{
|
|
cdebug_log(159,0) << "addInsertEvent() " << segment
|
|
<< "\n @" << DbU::getValueString(axis)
|
|
<< " " << track << endl;
|
|
|
|
if ( check and (segment->getTrack() != NULL) ) {
|
|
cerr << Bug("Session::addInsertEvent(): Segment already in Track."
|
|
"\n %s."
|
|
"\n to %s."
|
|
,getString(segment).c_str()
|
|
,getString(track).c_str()
|
|
) << endl;
|
|
return;
|
|
}
|
|
|
|
_insertEvents.push_back( Event(segment,track,axis) );
|
|
_addSortEvent( track, true );
|
|
}
|
|
|
|
|
|
void Session::_addRemoveEvent ( TrackElement* segment )
|
|
{
|
|
if (not segment->getTrack()) {
|
|
cerr << Bug( " Katana::Session::addRemoveEvent() : %s is not in any Track."
|
|
, getString(segment).c_str() ) << endl;
|
|
return;
|
|
}
|
|
|
|
cdebug_log(159,0) << "Ripup: @" << DbU::getValueString(segment->getAxis()) << " " << segment << endl;
|
|
_removeEvents.push_back( Event(segment,segment->getTrack(),segment->getAxis()) );
|
|
_addSortEvent( segment->getTrack(), true );
|
|
}
|
|
|
|
|
|
void Session::_addLockEvent ( TrackElement* segment )
|
|
{
|
|
if (not segment->isTerminal()) {
|
|
cerr << Bug( " Katana::Session::addLockEvent() : %s is not connected to a terminal."
|
|
, getString(segment).c_str() ) << endl;
|
|
return;
|
|
}
|
|
|
|
cdebug_log(159,0) << "Lock: @" << DbU::getValueString(segment->getAxis()) << " " << segment << endl;
|
|
_lockEvents.push_back( Event(segment,NULL,0) );
|
|
}
|
|
|
|
|
|
void Session::_addMoveEvent ( TrackElement* segment, Track* track, DbU::Unit axis )
|
|
{
|
|
if (not segment->getTrack()) {
|
|
if (not segment->isNonPref() and not segment->isReduced()) {
|
|
cerr << Bug( " Katana::Session::addMoveEvent() : %s is not yet in a track."
|
|
, getString(segment).c_str() ) << endl;
|
|
}
|
|
} else {
|
|
_addRemoveEvent( segment );
|
|
}
|
|
_addInsertEvent( segment, track, axis, false );
|
|
}
|
|
|
|
|
|
void Session::_addSortEvent ( Track* track, bool forced )
|
|
{
|
|
if (not track ) {
|
|
cerr << Bug( " Katana::Session::addSortEvent() : no Track to sort." ) << endl;
|
|
return;
|
|
}
|
|
if (forced) track->invalidate();
|
|
for ( Track* elem : _sortEvents ) if (elem == track) return;
|
|
_sortEvents.push_back( track );
|
|
}
|
|
|
|
|
|
void Session::setStage ( uint32_t stage )
|
|
{ get("setStage()")->_getKatanaEngine()->setStage(stage); }
|
|
|
|
|
|
string Session::_getTypeName () const
|
|
{ return "Katana::Session"; }
|
|
|
|
|
|
Record* Session::_getRecord () const
|
|
{
|
|
Record* record = Super::_getRecord ();
|
|
record->add( getSlot( "_sortEvents" , &_sortEvents ) );
|
|
|
|
return record;
|
|
}
|
|
|
|
|
|
} // Katana namespace.
|