// -*- C++ -*- // // 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@lip6.fr | // | =============================================================== | // | C++ Header : "./GraphicKatanaEngine.cpp" | // +-----------------------------------------------------------------+ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Katana { using namespace std; using Hurricane::Error; using Hurricane::Warning; using Hurricane::Exception; using Hurricane::Breakpoint; using Hurricane::DebugSession; using Hurricane::Point; using Hurricane::Entity; using Hurricane::Net; using Hurricane::Graphics; using Hurricane::ColorScale; using Hurricane::DisplayStyle; using Hurricane::ControllerWidget; using Hurricane::ExceptionWidget; using CRL::Catalog; using CRL::AllianceFramework; using Anabatic::Edge; using Anabatic::GCell; size_t GraphicKatanaEngine::_references = 0; GraphicKatanaEngine* GraphicKatanaEngine::_singleton = NULL; void GraphicKatanaEngine::initGCell ( CellWidget* widget ) { widget->getDrawingPlanes().setPen( Qt::NoPen ); KatanaEngine* katana = KatanaEngine::get( widget->getCell() ); if (katana) katana->setDensityMode( GCell::MaxDensity ); } void GraphicKatanaEngine::drawGCell ( CellWidget* widget , const Go* go , const BasicLayer* basicLayer , const Box& box , const Transformation& transformation ) { const GCell* gcell = static_cast(go); QPainter& painter = widget->getPainter(); QPen pen = Graphics::getPen ("Anabatic::GCell",widget->getDarkening()); Box bb = gcell->getBoundingBox(); QRect pixelBb = widget->dbuToScreenRect(bb); if (GCell::getDisplayMode() == GCell::Density) { uint32_t density = (unsigned int)( 255.0 * gcell->getDensity() ); if (density > 255) density = 255; painter.setBrush( Graphics::getColorScale( ColorScale::Fire ).getBrush( density, widget->getDarkening() ) ); painter.drawRect( pixelBb ); } else { int fontScale = 0; int halfHeight = 20; int halfWidth = 80; if (widget->isPrinter()) { fontScale = -5; halfHeight = 9; halfWidth = 39; } painter.setPen ( pen ); painter.setBrush( Graphics::getBrush("Anabatic::GCell",widget->getDarkening()) ); painter.drawRect( pixelBb ); if ( (pixelBb.width() > 2*halfWidth) and (pixelBb.height() > 2*halfHeight) ) { QString text = QString("%1").arg(gcell->getId()); QFont font = Graphics::getFixedFont( QFont::Normal, false, false, fontScale ); painter.setFont(font); pen.setWidth( 1 ); painter.setPen( pen ); painter.save (); painter.translate( widget->dbuToScreenPoint(bb.getCenter().getX(), bb.getCenter().getY()) ); painter.drawRect ( QRect( -halfWidth, -halfHeight, 2*halfWidth, 2*halfHeight ) ); painter.drawText ( QRect( -halfWidth, -halfHeight, 2*halfWidth, 2*halfHeight ) , text , QTextOption(Qt::AlignCenter) ); painter.restore (); } } } void GraphicKatanaEngine::initEdge ( CellWidget* widget ) { widget->getDrawingPlanes().setPen( Qt::NoPen ); } void GraphicKatanaEngine::drawEdge ( CellWidget* widget , const Go* go , const BasicLayer* basicLayer , const Box& box , const Transformation& transformation ) { static QFont font = Graphics::getFixedFont( QFont::Bold ); static int fontHeight = QFontMetrics(font).height(); const Edge* edge = static_cast(go); if (edge) { Box bb = edge->getBoundingBox(); uint32_t occupancy = 255; //if (edge->getRealOccupancy() < edge->getCapacity()) // occupancy = (uint32_t)( 255.0 * ( (float)edge->getRealOccupancy() / (float)edge->getCapacity() ) ); float edgeOccupancy = edge->getEstimateOccupancy() + (float)edge->getRealOccupancy(); #define NORMAL_DENSITY_DISPLAY 1 #if NORMAL_DENSITY_DISPLAY if ((unsigned int)edgeOccupancy <= edge->getCapacity()) occupancy = (uint32_t)( 255.0 * (edgeOccupancy / (float)edge->getCapacity()) ); #endif #if HISTORIC_COST_DISPLAY occupancy = (uint32_t)( 10.0 * edge->getHistoricCost() ); #endif #if EDGE_OVERLOAD_DISPLAY if ((unsigned int)edgeOccupancy <= edge->getCapacity()) occupancy = 0; else occupancy = (uint32_t)( 20.0 * ((unsigned int)edgeOccupancy - edge->getCapacity()) ); #endif if (occupancy > 254) occupancy = 254; QPainter& painter = widget->getPainter(); if ((unsigned int)edgeOccupancy > edge->getCapacity()) { QColor color ( Qt::cyan ); painter.setPen( DisplayStyle::darken(color,widget->getDarkening()) ); } QBrush brush = QBrush( Qt::white, Qt::DiagCrossPattern ); if (edge->getCapacity() > 0.0) brush = Graphics::getColorScale( ColorScale::Fire ).getBrush( occupancy, widget->getDarkening() ); QRect pixelBb = widget->dbuToScreenRect( bb, false); painter.setPen( Qt::NoPen ); painter.setBrush( brush ); painter.drawRect( pixelBb ); if (fontHeight > ((edge->isHorizontal()) ? pixelBb.height() : pixelBb.width()) + 4) return; //QString text = QString("%1/%2").arg(edge->getRealOccupancy()).arg(edge->getCapacity()); QString text = QString("%1/%2[-%3] %4") .arg( edgeOccupancy ) .arg( edge->getCapacity() ) .arg( edge->getReservedCapacity() ) .arg( edge->getHistoricCost() ); QColor color ( (occupancy > 170) ? Qt::black : Qt::white ); painter.setPen (DisplayStyle::darken(color,widget->getDarkening())); painter.setFont(font); if (edge->isVertical()) { painter.save (); painter.translate( widget->dbuToScreenPoint(bb.getXMin(), bb.getYMin()) ); painter.rotate ( -90 ); painter.drawText (QRect( 0 , 0 , widget->dbuToScreenLength(bb.getHeight()) , widget->dbuToScreenLength(bb.getWidth ())) , text , QTextOption(Qt::AlignCenter) ); painter.restore (); } else painter.drawText( widget->dbuToScreenRect(bb,false ), text, QTextOption(Qt::AlignCenter) ); painter.setPen( Qt::NoPen ); } } KatanaEngine* GraphicKatanaEngine::createEngine () { Cell* cell = getCell (); KatanaEngine* katana = KatanaEngine::get( cell ); if (not katana) { katana = KatanaEngine::create( cell ); katana->setPostEventCb( boost::bind(&GraphicKatanaEngine::postEvent,this) ); katana->setViewer( _viewer ); katana->printConfiguration(); katana->digitalInit(); } else cerr << Warning( "%s already has a Katana engine.", getString(cell).c_str() ) << endl; return katana; } KatanaEngine* GraphicKatanaEngine::getForFramework ( uint32_t flags ) { // Currently, only one framework is avalaible: Alliance. KatanaEngine* katana = KatanaEngine::get( getCell() ); if (katana) return katana; if (flags & CreateEngine) { katana = createEngine(); if (not katana) throw Error( "Failed to create Katana engine on %s.", getString(getCell()).c_str() ); } else { throw Error( "KatanaEngine not created yet, run the global router first." ); } return katana; } void GraphicKatanaEngine::_globalRoute () { KatanaEngine* katana = getForFramework( CreateEngine ); katana->runGlobalRouter(); //Breakpoint::stop( 0, "GraphicKatanaEngine::_globalRoute() done." ); } void GraphicKatanaEngine::_loadGlobalRouting () { KatanaEngine* katana = getForFramework( NoFlags ); _viewer->clearToolInterrupt(); katana->loadGlobalRouting( Anabatic::EngineLoadGrByNet ); //Breakpoint::stop( 0, "GraphicKatanaEngine::_loadGlobalRouting() done." ); } void GraphicKatanaEngine::_balanceGlobalDensity () { KatanaEngine* katana = getForFramework( NoFlags ); //katana->balanceGlobalDensity(); katana->layerAssign( Anabatic::EngineNoNetLayerAssign ); //Breakpoint::stop( 0, "GraphicKatanaEngine::_balanceGlobalDensity() done." ); } void GraphicKatanaEngine::_runNegociatePreRouted () { KatanaEngine* katana = getForFramework( CreateEngine ); katana->runNegociate( Flags::PreRoutedStage ); } void GraphicKatanaEngine::_runNegociate () { KatanaEngine* katana = getForFramework( NoFlags ); katana->runNegociate( Flags::PairSymmetrics ); } void GraphicKatanaEngine::_finalize () { KatanaEngine* katana = getForFramework( NoFlags ); if (katana) { katana->finalizeLayout(); katana->destroy(); } } void GraphicKatanaEngine::_runTest () { KatanaEngine* katana = getForFramework( NoFlags ); if (katana) { katana->loadGlobalRouting( Anabatic::EngineLoadGrByNet ); // Now done through Horus. //katana->runTest(); katana->runNegociate( Flags::PairSymmetrics ); //katana->runNegociate(); } } void GraphicKatanaEngine::_dumpMeasures () { KatanaEngine* katana = getForFramework( NoFlags ); if (katana) katana->dumpMeasures(); } void GraphicKatanaEngine::_save () { Cell* cell = getCell(); AllianceFramework* af = AllianceFramework::get(); string name = getString(cell->getName()) + "_katana"; cell->setName( name ); af->saveCell( cell, Catalog::State::Physical ); } void GraphicKatanaEngine::_detailRoute () { _loadGlobalRouting (); //Breakpoint::stop( 0, "Global routing loaded." ); _balanceGlobalDensity(); //Breakpoint::stop( 0, "Global density balanced." ); _runNegociate (); } void GraphicKatanaEngine::_route () { _runNegociatePreRouted(); _globalRoute (); _detailRoute (); _finalize (); } void GraphicKatanaEngine::postEvent () { static uint32_t count = 0; if (not (count++ % 500)) { QApplication::processEvents(); if (_viewer->isToolInterrupted()) { KatanaEngine* katana = KatanaEngine::get( getCell() ); if (katana) katana->setInterrupt( true ); _viewer->clearToolInterrupt(); } } } void GraphicKatanaEngine::addToMenu ( CellViewer* viewer ) { assert( _viewer == NULL ); _viewer = viewer; if (_viewer->hasMenuAction("placeAndRoute.route")) { cerr << Warning( "GraphicKatanaEngine::addToMenu() - Katana detailed router already hooked in." ) << endl; return; } _viewer->addMenu ( "placeAndRoute.stepByStep", "&Step by step" ); _viewer->addToMenu( "placeAndRoute.route" , "&Route . . . . . [Katana]" , "Route the design (global & detailed)" , std::bind(&GraphicKatanaEngine::_route,this) , QIcon() , "placeAndRoute.stepByStep" ); _viewer->addToMenu( "placeAndRoute.stepByStep.========" ); _viewer->addToMenu( "placeAndRoute.stepByStep.detailedPreRoute" , "Detailed Pre-Route . [Katana]" , "Run the Katana detailed router on pre-routed nets" , std::bind(&GraphicKatanaEngine::_runNegociatePreRouted,this) ); _viewer->addToMenu( "placeAndRoute.stepByStep.globalRoute" , "&Global Route . . . [Katana]" , "Run the Katana global router" , std::bind(&GraphicKatanaEngine::_globalRoute,this) ); _viewer->addToMenu( "placeAndRoute.stepByStep.detailedRoute" , "&Detailed Route . . [Katana]" , "Run the Katana detailed router" , std::bind(&GraphicKatanaEngine::_detailRoute,this) ); _viewer->addToMenu( "placeAndRoute.stepByStep.finalize" , "&Finalize Routing . [Katana]" , "Closing Routing" , std::bind(&GraphicKatanaEngine::_finalize,this) ); _viewer->addToMenu( "placeAndRoute.stepByStep.dumpMeasures" , "Dump &Measures . . [Katana]" , "Dumping Measurements on the disk" , std::bind(&GraphicKatanaEngine::_dumpMeasures,this) ); #if NO_NEED_OF_IT_NOW _viewer->addToMenu( "placeAndRoute.stepByStep.save" , "&Save Design" , "Save routed design (temporary hack)" , std::bind(&GraphicKatanaEngine::_save,this) ); _viewer->addToMenu( "placeAndRoute.stepByStep.runTest" , "Run &Test" , "Run Test Program (symmetric routing of gmChamla)" , std::bind(&GraphicKatanaEngine::_runTest,this) ); #endif } const Name& GraphicKatanaEngine::getName () const { return KatanaEngine::staticGetName(); } Cell* GraphicKatanaEngine::getCell () { if (_viewer == NULL) { throw Error( "Katana: GraphicKatanaEngine not bound to any Viewer." ); return NULL; } if (_viewer->getCell() == NULL) { throw Error( "Katana: No Cell is loaded into the Viewer." ); return NULL; } return _viewer->getCell(); } GraphicKatanaEngine* GraphicKatanaEngine::grab () { if (not _references) { _singleton = new GraphicKatanaEngine (); } _references++; return _singleton; } size_t GraphicKatanaEngine::release () { --_references; if (not _references) { delete _singleton; _singleton = NULL; } return _references; } GraphicKatanaEngine::GraphicKatanaEngine () : GraphicTool() , _viewer (NULL) { addDrawGo( "Anabatic::GCell", initGCell, drawGCell ); addDrawGo( "Anabatic::Edge" , initEdge , drawEdge ); } GraphicKatanaEngine::~GraphicKatanaEngine () { } } // Katana namespace.