coriolis/katana/src/KatanaEngine.cpp

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.