// -*- 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 #include #include #include #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 { using namespace std; using Hurricane::Error; using Hurricane::NetRoutingState; using Hurricane::NetRoutingExtension; using Hurricane::Net; using Hurricane::Cell; void setSymmetricSelf ( Cell* cell, string name ) { Net* net = cell->getNet( name ); if (not net) throw Error( "::setSymmetricSelf() Net \"%s\" not found." , name.c_str() ); NetRoutingState* state = NetRoutingExtension::get( net ); if (not state) state = NetRoutingExtension::create( net ); state->setFlags ( NetRoutingState::AutomaticGlobalRoute | NetRoutingState::Symmetric | NetRoutingState::Vertical ); state->setSymAxis( cell->getAbutmentBox().getCenter().getX() ); } void setSymmetricPair ( Cell* cell, string masterName, string slaveName ) { Net* masterNet = cell->getNet( masterName ); if (not masterNet) throw Error( "::setSymmetricPair() Net \"%s\" not found." , masterName.c_str() ); NetRoutingState* masterState = NetRoutingExtension::get( masterNet ); if (not masterState) masterState = NetRoutingExtension::create( masterNet ); masterState->setFlags ( NetRoutingState::AutomaticGlobalRoute | NetRoutingState::Symmetric | NetRoutingState::SymmetricMaster | NetRoutingState::Vertical ); masterState->setSymAxis( cell->getAbutmentBox().getCenter().getX() ); Net* slaveNet = cell->getNet( slaveName ); if (not slaveNet) throw Error( "KatanaEngine::runTest() Net \"%s\" not found." , slaveName.c_str() ); NetRoutingState* slaveState = NetRoutingExtension::get( slaveNet ); if (not slaveState) slaveState = NetRoutingExtension::create( slaveNet ); slaveState ->setFlags ( NetRoutingState::AutomaticGlobalRoute | NetRoutingState::Symmetric | NetRoutingState::Vertical ); slaveState ->setSymAxis(cell->getAbutmentBox().getCenter().getX() ); slaveState ->setSymNet ( masterNet ); masterState->setSymNet ( slaveNet ); } } // Anonymous namespace. 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::NetRoutingState; 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(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 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::digitalInit () { cdebug_log(155,1) << "KatanaEngine::_initDataBase()" << endl; Super::chipPrep(); setupGlobalGraph( Flags::NoFlags ); setupRoutingPlanes(); setupSpecialNets(); setupPreRouteds(); setupPowerRails(); protectRoutingPads(); _runKatanaInit(); cdebug_tabw(155,-1); } void KatanaEngine::analogInit () { cdebug_log(155,1) << "KatanaEngine::_initDataBase()" << endl; Super::chipPrep(); setupRoutingPlanes(); _runKatanaInit(); cdebug_tabw(155,-1); } void KatanaEngine::setupRoutingPlanes () { cdebug_log(155,1) << "KatanaEngine::setupRoutingPlanes()" << endl; bool sessionReUse = Session::isOpen(); if (not sessionReUse) openSession(); size_t maxDepth = getConfiguration()->getRoutingGauge()->getDepth(); _routingPlanes.reserve( maxDepth ); for ( size_t depth=0 ; depth < maxDepth ; depth++ ) { _routingPlanes.push_back( RoutingPlane::create( this, depth ) ); } if (not sessionReUse) Session::close(); } KatanaEngine* KatanaEngine::create ( Cell* cell ) { KatanaEngine* katana = new KatanaEngine ( cell ); katana->_postCreate(); 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 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 ; itrackgetTrackByIndex( itrack ); cdebug_log(159,0) << "Capacity from: " << track << endl; for ( size_t ielement=0 ; ielementgetSize() ; ++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 ; isize()-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 Katana capacity overload h:" << hTracksReservedLocal // << " v:." << vTracksReservedLocal << endl; // getGCellGrid()->checkEdgeOverflow( hTracksReservedLocal, vTracksReservedLocal ); // } _check( overlaps ); Session::close(); _toolSuccess = _toolSuccess and (overlaps == 0); } void KatanaEngine::runTest () { if (getCell()->getName() != "gmchamla") throw Error( "KatanaEngine::runTest() Work only on \"gmchamla\" (loaded:\"%s\")." , getString(getCell()->getName()).c_str() ); setSymmetricSelf( getCell(), "Vc" ); setSymmetricSelf( getCell(), "vb5" ); setSymmetricSelf( getCell(), "vb7" ); setSymmetricPair( getCell(), "ampp_73", "ampn_72" ); setSymmetricPair( getCell(), "ampp_71", "ampn_71" ); setSymmetricPair( getCell(), "m2n_in" , "m2p_in" ); setSymmetricPair( getCell(), "ampp_4" , "ampn_4" ); setSymmetricPair( getCell(), "ampp_2" , "ampn_2" ); setSymmetricPair( getCell(), "ampp_1" , "ampn_1" ); } void KatanaEngine::printCompletion () const { size_t routeds = 0; unsigned long long totalWireLength = 0; unsigned long long routedWireLength = 0; vector unrouteds; vector 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 ( getCell(), "Segs" , routeds+unrouteds.size() ); addMeasure( getCell(), "DWL(l)" , totalWireLength , 12 ); addMeasure( getCell(), "fWL(l)" , totalWireLength-routedWireLength , 12 ); addMeasure ( getCell(), "WLER(%)", (expandRatio-1.0)*100.0 ); } void KatanaEngine::dumpMeasures ( ostream& out ) const { vector 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() ) { 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 = std::min( getConfiguration()->getRoutingGauge()->getDepth(), _routingPlanes.size() ); 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() ) { 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.