597 lines
18 KiB
C++
597 lines
18 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@asim.lip6.fr |
|
|
// | =============================================================== |
|
|
// | C++ Module : "./KatanaEngine.cpp" |
|
|
// +-----------------------------------------------------------------+
|
|
|
|
|
|
#include <Python.h>
|
|
#include <sstream>
|
|
#include <fstream>
|
|
#include <iomanip>
|
|
#include "vlsisapd/utilities/Path.h"
|
|
#include "hurricane/DebugSession.h"
|
|
#include "hurricane/UpdateSession.h"
|
|
#include "hurricane/Bug.h"
|
|
#include "hurricane/Error.h"
|
|
#include "hurricane/Warning.h"
|
|
#include "hurricane/Breakpoint.h"
|
|
#include "hurricane/Layer.h"
|
|
#include "hurricane/Net.h"
|
|
#include "hurricane/Pad.h"
|
|
#include "hurricane/Plug.h"
|
|
#include "hurricane/Cell.h"
|
|
#include "hurricane/Instance.h"
|
|
#include "hurricane/Vertical.h"
|
|
#include "hurricane/Horizontal.h"
|
|
#include "hurricane/viewer/Script.h"
|
|
#include "crlcore/Measures.h"
|
|
#include "anabatic/AutoContact.h"
|
|
#include "katana/DataNegociate.h"
|
|
#include "katana/RoutingPlane.h"
|
|
#include "katana/Session.h"
|
|
#include "katana/TrackSegment.h"
|
|
#include "katana/NegociateWindow.h"
|
|
#include "katana/KatanaEngine.h"
|
|
#include "katana/PyKatanaEngine.h"
|
|
|
|
|
|
namespace Katana {
|
|
|
|
using std::cout;
|
|
using std::cerr;
|
|
using std::endl;
|
|
using std::dec;
|
|
using std::setw;
|
|
using std::left;
|
|
using std::ostream;
|
|
using std::ofstream;
|
|
using std::ostringstream;
|
|
using std::setprecision;
|
|
using std::vector;
|
|
using std::make_pair;
|
|
using Hurricane::dbo_ptr;
|
|
using Hurricane::UpdateSession;
|
|
using Hurricane::DebugSession;
|
|
using Hurricane::tab;
|
|
using Hurricane::ForEachIterator;
|
|
using Hurricane::Bug;
|
|
using Hurricane::Error;
|
|
using Hurricane::Warning;
|
|
using Hurricane::Breakpoint;
|
|
using Hurricane::Box;
|
|
using Hurricane::Torus;
|
|
using Hurricane::Layer;
|
|
using Hurricane::Horizontal;
|
|
using Hurricane::Vertical;
|
|
using Hurricane::NetRoutingExtension;
|
|
using Hurricane::Cell;
|
|
using CRL::System;
|
|
using CRL::addMeasure;
|
|
using CRL::Measures;
|
|
using CRL::MeasuresSet;
|
|
using Anabatic::EngineState;
|
|
using Anabatic::GCellsUnder;
|
|
using Anabatic::AutoContact;
|
|
using Anabatic::AutoSegmentLut;
|
|
using Anabatic::ChipTools;
|
|
|
|
|
|
const char* missingRW =
|
|
"%s:\n\n"
|
|
" Cell %s do not have any KatanaEngine (or not yet created).\n";
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "Katana::KatanaEngine".
|
|
|
|
Name KatanaEngine::_toolName = "Katana";
|
|
|
|
|
|
const Name& KatanaEngine::staticGetName ()
|
|
{ return _toolName; }
|
|
|
|
|
|
KatanaEngine* KatanaEngine::get ( const Cell* cell )
|
|
{ return static_cast<KatanaEngine*>(ToolEngine::get(cell,staticGetName())); }
|
|
|
|
|
|
KatanaEngine::KatanaEngine ( Cell* cell )
|
|
: Super (cell)
|
|
, _viewer (NULL)
|
|
, _configuration (new Configuration())
|
|
, _routingPlanes ()
|
|
, _negociateWindow(NULL)
|
|
, _minimumWL (0.0)
|
|
, _toolSuccess (false)
|
|
{ }
|
|
|
|
|
|
void KatanaEngine::_postCreate ()
|
|
{
|
|
Super::_postCreate ();
|
|
}
|
|
|
|
|
|
void KatanaEngine::_runKatanaInit ()
|
|
{
|
|
Utilities::Path pythonSitePackages = System::getPath("pythonSitePackages");
|
|
Utilities::Path systemConfDir = pythonSitePackages / "katana";
|
|
Utilities::Path systemConfFile = systemConfDir / "katanaInit.py";
|
|
|
|
if (systemConfFile.exists()) {
|
|
Isobar::Script::addPath( systemConfDir.toString() );
|
|
|
|
dbo_ptr<Isobar::Script> script = Isobar::Script::create( systemConfFile.stem().toString() );
|
|
script->addKwArgument( "katana" , (PyObject*)PyKatanaEngine_Link(this) );
|
|
script->runFunction ( "katanaHook", getCell() );
|
|
|
|
Isobar::Script::removePath( systemConfDir.toString() );
|
|
} else {
|
|
cerr << Warning( "Katana system configuration file:\n <%s> not found."
|
|
, systemConfFile.toString().c_str() ) << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void KatanaEngine::_initDataBase ()
|
|
{
|
|
cdebug_log(155,1) << "KatanaEngine::_initDataBase()" << endl;
|
|
|
|
setupGlobalGraph( Flags::NoFlags );
|
|
setupSpecialNets();
|
|
setupPreRouteds();
|
|
setupPowerRails();
|
|
protectRoutingPads();
|
|
_runKatanaInit();
|
|
|
|
cdebug_tabw(155,-1);
|
|
}
|
|
|
|
|
|
KatanaEngine* KatanaEngine::create ( Cell* cell )
|
|
{
|
|
KatanaEngine* katana = new KatanaEngine ( cell );
|
|
|
|
katana->_postCreate();
|
|
katana->_initDataBase();
|
|
|
|
return katana;
|
|
}
|
|
|
|
|
|
void KatanaEngine::_preDestroy ()
|
|
{
|
|
cdebug_log(155,1) << "KatanaEngine::_preDestroy()" << endl;
|
|
|
|
cmess1 << " o Deleting ToolEngine<" << getName() << "> from Cell <"
|
|
<< _cell->getName() << ">" << endl;
|
|
|
|
if (getState() < EngineState::EngineGutted)
|
|
setState( EngineState::EnginePreDestroying );
|
|
|
|
_gutKatana();
|
|
Super::_preDestroy();
|
|
|
|
cmess2 << " - RoutingEvents := " << RoutingEvent::getAllocateds() << endl;
|
|
|
|
cdebug_tabw(155,-1);
|
|
}
|
|
|
|
|
|
KatanaEngine::~KatanaEngine ()
|
|
{ delete _configuration; }
|
|
|
|
|
|
const Name& KatanaEngine::getName () const
|
|
{ return _toolName; }
|
|
|
|
|
|
Configuration* KatanaEngine::getConfiguration ()
|
|
{ return _configuration; }
|
|
|
|
|
|
unsigned int KatanaEngine::getRipupLimit ( const TrackElement* segment ) const
|
|
{
|
|
if (segment->isBlockage()) return 0;
|
|
|
|
if (segment->isStrap ()) return _configuration->getRipupLimit( Configuration::StrapRipupLimit );
|
|
if (segment->isGlobal()) {
|
|
vector<GCell*> gcells;
|
|
segment->getGCells( gcells );
|
|
if (gcells.size() > 2)
|
|
return _configuration->getRipupLimit( Configuration::LongGlobalRipupLimit );
|
|
return _configuration->getRipupLimit( Configuration::GlobalRipupLimit );
|
|
}
|
|
return _configuration->getRipupLimit( Configuration::LocalRipupLimit );
|
|
}
|
|
|
|
|
|
RoutingPlane* KatanaEngine::getRoutingPlaneByIndex ( size_t index ) const
|
|
{
|
|
if (index >= getRoutingPlanesSize() ) return NULL;
|
|
return _routingPlanes[index];
|
|
}
|
|
|
|
|
|
RoutingPlane* KatanaEngine::getRoutingPlaneByLayer ( const Layer* layer ) const
|
|
{
|
|
for ( size_t index=0 ; index < getRoutingPlanesSize() ; index++ ) {
|
|
if (_routingPlanes[index]->getLayer() == layer)
|
|
return _routingPlanes[index];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
Track* KatanaEngine::getTrackByPosition ( const Layer* layer, DbU::Unit axis, unsigned int mode ) const
|
|
{
|
|
RoutingPlane* plane = getRoutingPlaneByLayer( layer );
|
|
if (not plane) return NULL;
|
|
|
|
return plane->getTrackByPosition( axis, mode );
|
|
}
|
|
|
|
|
|
void KatanaEngine::openSession ()
|
|
{ Session::_open(this); }
|
|
|
|
|
|
void KatanaEngine::setInterrupt ( bool state )
|
|
{
|
|
if (_negociateWindow) {
|
|
_negociateWindow->setInterrupt( state );
|
|
cerr << "Interrupt [CRTL+C] of " << this << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void KatanaEngine::annotateGlobalGraph ()
|
|
{
|
|
cmess1 << " o Back annotate global routing graph." << endl;
|
|
|
|
for ( size_t depth=0 ; depth<_routingPlanes.size() ; ++depth ) {
|
|
RoutingPlane* rp = _routingPlanes[depth];
|
|
if (rp->getLayerGauge()->getType() == Constant::PinOnly) continue;
|
|
if (rp->getLayerGauge()->getDepth() > getConfiguration()->getAllowedDepth()) continue;
|
|
|
|
size_t tracksSize = rp->getTracksSize();
|
|
for ( size_t itrack=0 ; itrack<tracksSize ; ++itrack ) {
|
|
Track* track = rp->getTrackByIndex( itrack );
|
|
|
|
cdebug_log(159,0) << "Capacity from: " << track << endl;
|
|
|
|
for ( size_t ielement=0 ; ielement<track->getSize() ; ++ielement ) {
|
|
TrackElement* element = track->getSegment( ielement );
|
|
|
|
if (element->getNet() == NULL) {
|
|
cdebug_log(159,0) << "Reject capacity from (not Net): " << element << endl;
|
|
continue;
|
|
}
|
|
if ( (not element->isFixed())
|
|
and (not element->isBlockage())
|
|
and (not element->isUserDefined()) ) {
|
|
cmess2 << "Reject capacity from (neither fixed, blockage nor user defined): " << element << endl;
|
|
continue;
|
|
}
|
|
|
|
Segment* segment = element->getSegment();
|
|
Flags side = Flags::EastSide;
|
|
DbU::Unit axis = segment->getY();
|
|
if (track->getDirection() == Flags::Vertical) {
|
|
side = Flags::NorthSide;
|
|
axis = segment->getX();
|
|
}
|
|
|
|
int elementCapacity = -1;
|
|
cdebug_log(159,0) << "Capacity from: " << element << ":" << elementCapacity << endl;
|
|
|
|
GCellsUnder gcells = getGCellsUnder( segment );
|
|
if (not gcells->empty()) {
|
|
for ( size_t i=0 ; i<gcells->size()-1 ; ++i )
|
|
gcells->gcellAt(i)->getEdgeAt( side, axis )->incCapacity( elementCapacity );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void KatanaEngine::runNegociate ( unsigned int flags )
|
|
{
|
|
if (_negociateWindow) return;
|
|
|
|
startMeasures();
|
|
openSession();
|
|
|
|
_negociateWindow = NegociateWindow::create( this );
|
|
_negociateWindow->setGCells( getGCells() );
|
|
_computeCagedConstraints();
|
|
_negociateWindow->run( flags );
|
|
_negociateWindow->destroy();
|
|
_negociateWindow = NULL;
|
|
|
|
Session::close();
|
|
stopMeasures();
|
|
//if ( _editor ) _editor->refresh ();
|
|
|
|
printMeasures( "algo" );
|
|
|
|
openSession();
|
|
unsigned int overlaps = 0;
|
|
// size_t hTracksReservedLocal = getHTracksReservedLocal();
|
|
// size_t vTracksReservedLocal = getVTracksReservedLocal();
|
|
|
|
// if (cparanoid.enabled()) {
|
|
// cparanoid << " o Post-checking Knik capacity overload h:" << hTracksReservedLocal
|
|
// << " v:." << vTracksReservedLocal << endl;
|
|
// getGCellGrid()->checkEdgeOverflow( hTracksReservedLocal, vTracksReservedLocal );
|
|
// }
|
|
|
|
_check( overlaps );
|
|
Session::close();
|
|
|
|
_toolSuccess = _toolSuccess and (overlaps == 0);
|
|
}
|
|
|
|
|
|
void KatanaEngine::printCompletion () const
|
|
{
|
|
size_t routeds = 0;
|
|
unsigned long long totalWireLength = 0;
|
|
unsigned long long routedWireLength = 0;
|
|
vector<TrackElement*> unrouteds;
|
|
vector<TrackElement*> reduceds;
|
|
ostringstream result;
|
|
|
|
AutoSegmentLut::const_iterator ilut = _getAutoSegmentLut().begin();
|
|
for ( ; ilut != _getAutoSegmentLut().end() ; ilut++ ) {
|
|
TrackElement* segment = _lookup( ilut->second );
|
|
if (segment == NULL) continue;
|
|
|
|
unsigned long long wl = (unsigned long long)DbU::toLambda( segment->getLength() );
|
|
if (wl > 100000) {
|
|
cerr << Error("KatanaEngine::printCompletion(): Suspiciously long wire: %llu for %p:%s"
|
|
,wl,ilut->first,getString(segment).c_str()) << endl;
|
|
continue;
|
|
}
|
|
|
|
if (segment->isFixed() or segment->isBlockage()) continue;
|
|
if (segment->isReduced()) reduceds.push_back( segment );
|
|
|
|
totalWireLength += wl;
|
|
if ( (segment->getTrack() != NULL) or (segment->isReduced()) ) {
|
|
routeds++;
|
|
routedWireLength += wl;
|
|
continue;
|
|
}
|
|
|
|
unrouteds.push_back( segment );
|
|
}
|
|
|
|
float segmentRatio = (float)(routeds) / (float)(routeds+unrouteds.size()) * 100.0;
|
|
float wireLengthRatio = (float)(routedWireLength) / (float)(totalWireLength) * 100.0;
|
|
|
|
_toolSuccess = (unrouteds.empty());
|
|
|
|
if (not unrouteds.empty()) {
|
|
cerr << " o Routing did not complete, unrouted segments:" << endl;
|
|
for ( size_t i=0; i<unrouteds.size() ; ++i ) {
|
|
cerr << " " << dec << setw(4) << (i+1) << "| " << unrouteds[i] << endl;
|
|
}
|
|
}
|
|
|
|
// if (not reduceds.empty()) {
|
|
// cerr << " o Reduced segments:" << endl;
|
|
// for ( size_t i=0; i<reduceds.size() ; ++i ) {
|
|
// cerr << " " << dec << setw(4) << (i+1) << "| " << reduceds[i] << endl;
|
|
// }
|
|
// }
|
|
|
|
result << setprecision(4) << segmentRatio
|
|
<< "% [" << routeds << "+" << unrouteds.size() << "]";
|
|
cmess1 << Dots::asString( " - Track Segment Completion Ratio", result.str() ) << endl;
|
|
|
|
result.str("");
|
|
result << setprecision(4) << wireLengthRatio
|
|
<< "% [" << totalWireLength << "+"
|
|
<< (totalWireLength - routedWireLength) << "]";
|
|
cmess1 << Dots::asString( " - Wire Length Completion Ratio", result.str() ) << endl;
|
|
|
|
float expandRatio = 1.0;
|
|
if (_minimumWL != 0.0) {
|
|
expandRatio = ((totalWireLength-_minimumWL) / _minimumWL) * 100.0;
|
|
|
|
result.str("");
|
|
result << setprecision(3) << expandRatio << "% [min:" << setprecision(9) << _minimumWL << "]";
|
|
cmess1 << Dots::asString( " - Wire Length Expand Ratio", result.str() ) << endl;
|
|
}
|
|
|
|
addMeasure<size_t> ( getCell(), "Segs" , routeds+unrouteds.size() );
|
|
addMeasure<unsigned long long>( getCell(), "DWL(l)" , totalWireLength , 12 );
|
|
addMeasure<unsigned long long>( getCell(), "fWL(l)" , totalWireLength-routedWireLength , 12 );
|
|
addMeasure<double> ( getCell(), "WLER(%)", (expandRatio-1.0)*100.0 );
|
|
}
|
|
|
|
|
|
void KatanaEngine::dumpMeasures ( ostream& out ) const
|
|
{
|
|
vector<Name> measuresLabels;
|
|
measuresLabels.push_back( "Gates" );
|
|
measuresLabels.push_back( "GCells" );
|
|
measuresLabels.push_back( "knikT" );
|
|
measuresLabels.push_back( "knikS" );
|
|
measuresLabels.push_back( "GWL(l)" );
|
|
measuresLabels.push_back( "Area(l2)");
|
|
measuresLabels.push_back( "Sat." );
|
|
measuresLabels.push_back( "loadT" );
|
|
measuresLabels.push_back( "loadS" );
|
|
measuresLabels.push_back( "Globals" );
|
|
measuresLabels.push_back( "Edges" );
|
|
measuresLabels.push_back( "assignT" );
|
|
measuresLabels.push_back( "algoT" );
|
|
measuresLabels.push_back( "algoS" );
|
|
measuresLabels.push_back( "finT" );
|
|
measuresLabels.push_back( "Segs" );
|
|
measuresLabels.push_back( "DWL(l)" );
|
|
measuresLabels.push_back( "fWL(l)" );
|
|
measuresLabels.push_back( "WLER(%)" );
|
|
measuresLabels.push_back( "Events" );
|
|
measuresLabels.push_back( "UEvents" );
|
|
|
|
const MeasuresSet* measures = Measures::get( getCell() );
|
|
|
|
out << "#" << endl;
|
|
out << "# " << getCell()->getName() << endl;
|
|
out << measures->toStringHeaders(measuresLabels) << endl;
|
|
out << measures->toStringDatas (measuresLabels) << endl;
|
|
|
|
measures->toGnuplot( "GCells Density Histogram", getString(getCell()->getName()) );
|
|
}
|
|
|
|
|
|
void KatanaEngine::dumpMeasures () const
|
|
{
|
|
ostringstream path;
|
|
path << getCell()->getName() << ".knik-katana.dat";
|
|
|
|
ofstream sfile ( path.str().c_str() );
|
|
dumpMeasures( sfile );
|
|
sfile.close();
|
|
}
|
|
|
|
|
|
bool KatanaEngine::_check ( unsigned int& overlap, const char* message ) const
|
|
{
|
|
cmess1 << " o Checking Katana Database coherency." << endl;
|
|
|
|
bool coherency = true;
|
|
coherency = coherency and Super::_check( message );
|
|
for ( size_t i=0 ; i<_routingPlanes.size() ; i++ )
|
|
coherency = _routingPlanes[i]->_check(overlap) and coherency;
|
|
|
|
Anabatic::Session* anbtSession = Session::base ();
|
|
for( Net* net : getCell()->getNets() ) {
|
|
for( Segment* segment : net->getComponents().getSubSet<Segment*>() ) {
|
|
AutoSegment* autoSegment = anbtSession->lookup( segment );
|
|
if (not autoSegment) continue;
|
|
if (not autoSegment->isCanonical()) continue;
|
|
|
|
TrackElement* trackSegment = Session::lookup( segment );
|
|
if (not trackSegment) {
|
|
coherency = false;
|
|
cerr << Bug( "%p %s without Track Segment"
|
|
, autoSegment
|
|
, getString(autoSegment).c_str() ) << endl;
|
|
} else
|
|
trackSegment->_check();
|
|
}
|
|
}
|
|
|
|
return coherency;
|
|
}
|
|
|
|
|
|
void KatanaEngine::finalizeLayout ()
|
|
{
|
|
|
|
cdebug_log(155,0) << "KatanaEngine::finalizeLayout()" << endl;
|
|
if (getState() > Anabatic::EngineDriving) return;
|
|
|
|
cdebug_tabw(155,1);
|
|
|
|
setState( Anabatic::EngineDriving );
|
|
_gutKatana();
|
|
|
|
Super::finalizeLayout();
|
|
cdebug_log(155,0) << "State: " << getState() << endl;
|
|
|
|
getCell()->setFlags( Cell::Flags::Routed );
|
|
|
|
cdebug_tabw(155,-1);
|
|
}
|
|
|
|
|
|
void KatanaEngine::_gutKatana ()
|
|
{
|
|
cdebug_log(155,1) << "KatanaEngine::_gutKatana()" << endl;
|
|
cdebug_log(155,0) << "State: " << getState() << endl;
|
|
|
|
if (getState() < EngineState::EngineGutted) {
|
|
openSession();
|
|
|
|
size_t maxDepth = getConfiguration()->getRoutingGauge()->getDepth();
|
|
for ( size_t depth=0 ; depth < maxDepth ; depth++ ) {
|
|
_routingPlanes[depth]->destroy();
|
|
}
|
|
|
|
Session::close();
|
|
}
|
|
|
|
cdebug_tabw(155,-1);
|
|
}
|
|
|
|
|
|
TrackElement* KatanaEngine::_lookup ( Segment* segment ) const
|
|
{
|
|
AutoSegment* autoSegment = Super::_lookup( segment );
|
|
if (not autoSegment or not autoSegment->isCanonical()) return NULL;
|
|
|
|
return _lookup( autoSegment );
|
|
}
|
|
|
|
|
|
void KatanaEngine::_check ( Net* net ) const
|
|
{
|
|
cerr << " o Checking " << net << endl;
|
|
|
|
for( Segment* segment : net->getComponents().getSubSet<Segment*>() ) {
|
|
TrackElement* trackSegment = _lookup( segment );
|
|
if (trackSegment) {
|
|
trackSegment->_check();
|
|
|
|
AutoContact* autoContact = trackSegment->base()->getAutoSource();
|
|
if (autoContact) autoContact->checkTopology ();
|
|
|
|
autoContact = trackSegment->base()->getAutoTarget();
|
|
if (autoContact) autoContact->checkTopology ();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
string KatanaEngine::_getTypeName () const
|
|
{ return "Katana::KatanaEngine"; }
|
|
|
|
|
|
string KatanaEngine::_getString () const
|
|
{
|
|
ostringstream os;
|
|
os << "<" << "KatanaEngine " << _cell->getName () << ">";
|
|
return os.str();
|
|
}
|
|
|
|
|
|
Record* KatanaEngine::_getRecord () const
|
|
{
|
|
Record* record = Super::_getRecord ();
|
|
|
|
if (record) {
|
|
record->add( getSlot( "_routingPlanes", &_routingPlanes ) );
|
|
record->add( getSlot( "_configuration", _configuration ) );
|
|
}
|
|
return record;
|
|
}
|
|
|
|
|
|
} // Katana namespace.
|