diff --git a/ispd/CMakeLists.txt b/ispd/CMakeLists.txt new file mode 100644 index 00000000..857d1200 --- /dev/null +++ b/ispd/CMakeLists.txt @@ -0,0 +1,42 @@ +PROJECT(UNICORN) + +CMAKE_MINIMUM_REQUIRED(VERSION 2.4.0) +IF(COMMAND CMAKE_POLICY) + CMAKE_POLICY(SET CMP0003 NEW) +ENDIF(COMMAND CMAKE_POLICY) + +IF(APPLE) + EXECUTE_PROCESS( + COMMAND sw_vers -productVersion + OUTPUT_VARIABLE OSX_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + MESSAGE(STATUS "OSX_VERSION='${OSX_VERSION}'") + IF(${OSX_VERSION} MATCHES "^10\\.[012345]\\.?") + MESSAGE(STATUS "OSX < 10.6") + ELSE(${OSX_VERSION} MATCHES "^10\\.[012345]\\.?") + SET(CMAKE_OSX_ARCHITECTURES "i386;ppc") # for QT4.5 32bits on snow leopard + ENDIF(${OSX_VERSION} MATCHES "^10\\.[012345]\\.?") +ENDIF(APPLE) + +SET(CMAKE_C_FLAGS_DEBUG "-g -Wall" CACHE STRING "Debug options." FORCE) +SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall" CACHE STRING "Debug options." FORCE) +#SET(CMAKE_LINKER_FLAGS_DEBUG "-pg" CACHE STRING "Debug options." FORCE) +#SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG "-pg" CACHE STRING "Debug options." FORCE) +#SET(CMAKE_MODULE_LINKER_FLAGS_DEBUG "-pg" CACHE STRING "Debug options." FORCE) +#SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "-pg" CACHE STRING "Debug options." FORCE) + +SET(CMAKE_MODULE_PATH "$ENV{HURRICANE_TOP}/share/cmake_modules/") + +SET(QT_USE_QTXML "true") + +FIND_PACKAGE(Boost 1.33.1 COMPONENTS program_options REQUIRED) +FIND_PACKAGE(Qt4 REQUIRED) # find and setup Qt4 for this project +FIND_PACKAGE(LEFDEF REQUIRED) +FIND_PACKAGE(HURRICANE REQUIRED) +FIND_PACKAGE(CORIOLIS REQUIRED) +FIND_PACKAGE(KNIK REQUIRED) +FIND_PACKAGE(KATABATIC REQUIRED) + +SET_LIB_LINK_MODE() + +ADD_SUBDIRECTORY(src) diff --git a/ispd/src/CMakeLists.txt b/ispd/src/CMakeLists.txt new file mode 100644 index 00000000..ec915774 --- /dev/null +++ b/ispd/src/CMakeLists.txt @@ -0,0 +1,29 @@ + + include ( ${QT_USE_FILE} ) + include_directories ( ${Boost_INCLUDE_DIRS} + ${HURRICANE_INCLUDE_DIR} + ${CORIOLIS_INCLUDE_DIR} + ) + + set ( mocincludes IspdGui.h + ) + set ( cpps IspdGui.cpp + IspdMain.cpp + ) + + qt4_wrap_cpp ( MOCcpps ${mocincludes} ) + + add_executable ( ispd ${cpps} ${MOCcpps} ) + target_link_libraries ( ispd ${KATABATIC_GRAPHICAL_LIBRARIES} + ${KATABATIC_LIBRARIES} + ${KNIK_GRAPHICAL_LIBRARIES} + ${KNIK_LIBRARIES} + ${CORIOLIS_LIBRARIES} + ${HURRICANE_GRAPHICAL_LIBRARIES} + ${HURRICANE_LIBRARIES} + ${OA_LIBRARIES} + ${LEFDEF_LIBRARIES} + ${QT_LIBRARIES} + ${Boost_LIBRARIES} ) + install ( TARGETS ispd DESTINATION /bin ) + diff --git a/ispd/src/IspdGui.cpp b/ispd/src/IspdGui.cpp new file mode 100644 index 00000000..c5d786f3 --- /dev/null +++ b/ispd/src/IspdGui.cpp @@ -0,0 +1,126 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC/LIP6 2008-2008, All Rights Reserved +// +// =================================================================== +// +// $Id$ +// +// x-----------------------------------------------------------------x +// | | +// | C O R I O L I S | +// | I s p d G l o b a l r o u t i n g - M a i n G U I | +// | | +// | Author : Damien Dupuis | +// | E-mail : Damien.Dupuis@lip6.fr | +// | =============================================================== | +// | C++ Module : "./IspdGui.cpp" | +// | *************************************************************** | +// | U p d a t e s | +// | | +// x-----------------------------------------------------------------x + + +#include +#include + +#include "hurricane/Warning.h" +#include "hurricane/viewer/CellWidget.h" + +#include "crlcore/Catalog.h" +#include "crlcore/GraphicToolEngine.h" + +#include "IspdGui.h" + + +namespace Ispd { + + + using Hurricane::Warning; + using CRL::Catalog; + + +// ------------------------------------------------------------------- +// Class : "IspdGui". + + + IspdGui::IspdGui ( QWidget* parent ) + : CellViewer(parent) + , _banner ( "Ispd" + , "1.0a" + , "Coriolis Ispd Main GUI" + , "2008" + , "Damien Dupuis" + , "" + ) + , _tools() + { } + + + IspdGui::~IspdGui () + { } + + + IspdGui* IspdGui::create ( QWidget* parent ) + { + IspdGui* ispdgui = new IspdGui ( parent ); + + ispdgui->_postCreate (); + + return ispdgui; + } + + + void IspdGui::destroy () + { + _preDestroy (); + delete this; + } + + + void IspdGui::_postCreate () + { + setApplicationName ( tr("ispd") ); + + //QAction* openAction = findChild("viewer.menuBar.file.openCell"); + //if ( openAction ) { + // connect ( openAction, SIGNAL(triggered()), this, SLOT(openCell()) ); + //} + } + + + void IspdGui::_preDestroy () + { + set::iterator itool = _tools.begin(); + for ( ; itool != _tools.end() ; itool++ ) + (*itool)->release (); + } + + + void IspdGui::registerTool ( GraphicTool* tool ) + { + assert ( tool != NULL ); + + if ( _tools.find(tool) != _tools.end() ) { + cerr << Warning ( "Tool %s already registered in Ispd (ignored)." + , getString(tool->getName()).c_str() ) << endl; + return; + } + + _tools.insert ( tool ); + + const GraphicTool::DrawGoMap& drawGos = tool->getDrawGos (); + GraphicTool::DrawGoMap::const_iterator idrawGo = drawGos.begin(); + + for ( ; idrawGo != drawGos.end() ; idrawGo++ ) + getCellWidget()->addDrawExtensionGo ( idrawGo->first + , idrawGo->second.getInit() + , idrawGo->second.getDraw() + ); + + tool->addToMenu ( this ); + } + +} // End of Ispd namespace. diff --git a/ispd/src/IspdGui.h b/ispd/src/IspdGui.h new file mode 100644 index 00000000..8e48cdb5 --- /dev/null +++ b/ispd/src/IspdGui.h @@ -0,0 +1,79 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC/LIP6 2008-2008, All Rights Reserved +// +// =================================================================== +// +// $Id$ +// +// x-----------------------------------------------------------------x +// | | +// | C O R I O L I S | +// | I s p d G l o b a l r o u t i n g - M a i n G U I | +// | | +// | Author : Damien Dupuis | +// | E-mail : Damien.Dupuis@lip6.fr | +// | =============================================================== | +// | C++ Header : "./IspdGui.h" | +// | *************************************************************** | +// | U p d a t e s | +// | | +// x-----------------------------------------------------------------x + + + + +#ifndef __ISPD_ISPD__ +#define __ISPD_ISPD__ + +#include +#include +using namespace std; + +#include "hurricane/viewer/CellViewer.h" + +#include "crlcore/Banner.h" +namespace CRL { + class GraphicTool; +} + + +namespace Ispd { + + + using std::set; + using Hurricane::CellViewer; + using Hurricane::Cell; + using CRL::Banner; + using CRL::GraphicTool; + + + class IspdGui : public CellViewer { + Q_OBJECT; + + public: + static IspdGui* create ( QWidget* parent=NULL); + void destroy (); + inline const Banner& getBanner () const; + void registerTool ( GraphicTool* ); + protected: + IspdGui ( QWidget* parent ); + virtual ~IspdGui (); + virtual void _postCreate (); + virtual void _preDestroy (); + protected: + Banner _banner; + set _tools; + }; + + + inline const Banner& IspdGui::getBanner () const { return _banner; } + + +} // End of Ispd namespace. + + +#endif // __ISPD_ISPD__ + diff --git a/ispd/src/IspdMain.cpp b/ispd/src/IspdMain.cpp new file mode 100644 index 00000000..5418bed2 --- /dev/null +++ b/ispd/src/IspdMain.cpp @@ -0,0 +1,950 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC/LIP6 2008-2009, All Rights Reserved +// +// =================================================================== +// +// $Id$ +// +// x-----------------------------------------------------------------x +// | | +// | C O R I O L I S | +// | I s p d G l o b a l r o u t i n g - M a i n G U I | +// | | +// | Author : Damien Dupuis | +// | E-mail : Damien.Dupuis@lip6.fr | +// | =============================================================== | +// | C++ Module : "./IspdMain.cpp" | +// | *************************************************************** | +// | U p d a t e s | +// | | +// x-----------------------------------------------------------------x + + +#include +namespace poptions = boost::program_options; + +#include + +#include "hurricane/DataBase.h" +#include "hurricane/Technology.h" +#include "hurricane/Cell.h" +#include "hurricane/Warning.h" +#include "hurricane/Net.h" +#include "hurricane/RoutingPad.h" +#include "hurricane/UpdateSession.h" +#include "hurricane/Horizontal.h" +#include "hurricane/Vertical.h" +#include "hurricane/viewer/Graphics.h" +#include "hurricane/viewer/HApplication.h" +using namespace Hurricane; + +#include "crlcore/Utilities.h" +#include "crlcore/AllianceFramework.h" +using namespace CRL; + +#include "knik/GraphicKnikEngine.h" +#include "knik/KnikEngine.h" +#include "knik/NetExtension.h" +using namespace Knik; + +#include "katabatic/GraphicKatabaticEngine.h" +using namespace Katabatic; + +#include "IspdGui.h" +using namespace Ispd; + + +namespace { +// ------------------------------------------------------------------- +// Global variables + +# define LINE_SIZE 4096 + + enum ParserState { StateGrid + , StateVerti + , StateHoriz + , StateWidth + , StateSpacing + , StateVia + , StateDim + , StateNet + , StateObs + , StateEOF + }; + + unsigned __congestion__ = 1; + unsigned __precongestion__ = 2; + float __edge_cost__ = 3.0; + + + Cell* _cell = NULL; + DataBase::DataBase* _db = NULL; + KnikEngine* _knik = NULL; + AllianceFramework* _af = AllianceFramework::create (); + string _filePath; + int _parserState = StateGrid; + size_t _lineNumber = 0; + char _rawLine[LINE_SIZE]; + unsigned _nbGCellsX; + unsigned _nbGCellsY; + unsigned _nbLayers; + DbU::Unit _lowerLeftX; + DbU::Unit _lowerLeftY; + DbU::Unit _tileWidth; + DbU::Unit _tileHeight; + vector _vertiCap; + vector _horizCap; + vector _minWidth; + vector _minSpacing; + vector _viaSpacing; + unsigned _nbNets; + unsigned _nbObs; + Layer* _layers[2]; + bool _createRings = true; + +// ------------------------------------------------------------------- +// Function : "printHelp()". + + void printHelp () + { + cout << endl; + cout << "Usage: unicorn [-v|--verbose] [-V|--very-verbose] [-D|--core-dump] \\\n" + << " [-l|--trace-level ] [-c|--cell ] \\\n" + << endl; + cout << "Options:\n" + << " o [-v|--verbose] : First level of verbosity.\n" + << " o [-V|--very-verbose] : Second level of verbosity (very talkative).\n" + << " o [-D|--core-dump] : Enable core dumping.\n" + << " o [-l|--trace-level ] :\n" + << " Sets the level of trace, trace messages with a level superior to\n" + << " will be printed on .\n" + << " o [-c|--cell ] :\n" + << " The name of the Cell to load, without extention.\n" + << " o [-k|--knik] : Run the global router : Knik.\n" + << " o [-K|--KNIK] : Run the global router : Knik, then analyse routing and unroute overflowed segments.\n" + << endl; + } + + void _printWarning ( const char* format, ... ) + { + static char formatted [ 8192 ]; + va_list args; + + va_start ( args, format ); + vsnprintf ( formatted, 8191, format, args ); + va_end ( args ); + + cerr << "[WARNING] GrParser(): " << formatted << "\n" + << " (file: " << _filePath << ", line: " << _lineNumber << ")" << endl; + } + + void _printError ( bool interrupt, const char* format, ... ) + { + static char formatted [ 8192 ]; + va_list args; + + va_start ( args, format ); + vsnprintf ( formatted, 8191, format, args ); + va_end ( args ); + + cerr << "[ERROR] GrParser(): " << formatted << "\n" + << " (file: " << _filePath << ", line: " << _lineNumber << ")" << endl; + + if ( interrupt ) + throw Error ( "GrParser processed" ); + } + + long _getLong ( const char* s ) + { + char* end; + long value = strtol ( s, &end, 10 ); + if ( *end != '\0' ) + _printError ( false, "Incomplete string to integer conversion for \"%s\" (%ld).", s, value ); + return value; + } + + vector _splitString ( char* s ) + { + vector fields; + + fields.push_back ( s ); + while ( *s != '\0' ) { + unsigned i = 0; + if ( *s == ' ' || *s == '\t' ) { + i++; + *s = '\0'; + while ( *(s+i) == ' ' || *(s+i) == '\t' ) + i++; + fields.push_back ( s+i ); + s += i; + } + else + s++; + } + + return fields; + } + + vector _splitSegmentString ( char* s ) + { + vector fields; + + //fields.push_back ( s ); + while ( *s != '\0' ) { + unsigned i = 0; + if ( *s == '(' || *s == ')' || *s == ',' || *s == '-' ) { + i++; + *s = '\0'; + while ( *(s+i) == '(' || *(s+i) == ')' || *(s+i) == ',' || *(s+i) == '-' ) + i++; + if ( *(s+i+1) != '\0' ) + fields.push_back ( s+i ); + s += i; + } + else + s++; + } + + return fields; + } + + void _parseGrid () + { + if ( strncmp(_rawLine,"grid", 4) ) + _printError ( true, "Missing Grid Declaration." ); + + vector fields =_splitString ( _rawLine+5 ); + if ( fields.size() != 3 ) { + _printError ( true, "Malformed Grid Line." ); + } + else { + _nbGCellsX = _getLong ( fields[0] ); + _nbGCellsY = _getLong ( fields[1] ); + _nbLayers = _getLong ( fields[2] ); + } + if ( _nbLayers != 2 ) + _printError ( false, "Global routing only supports two layers right now !" ); + } + + void _parseVerti () + { + if ( strncmp(_rawLine, "vertical capacity", 17) ) + _printError ( true, "Missing Vertical Declaration." ); + + vector fields = _splitString ( _rawLine+18 ); + + if ( fields.size() < _nbLayers ) + _printError ( true, "Malformed Vertical line." ); + else + for ( unsigned i = 0 ; i < _nbLayers ; i++ ) { + _vertiCap.push_back ( _getLong ( fields[i] ) ); + } + } + + void _parseHoriz () + { + if ( strncmp(_rawLine, "horizontal capacity", 19) ) + _printError ( true, "Missing Horizontal Declaration." ); + + vector fields = _splitString ( _rawLine+20 ); + + if ( fields.size() < _nbLayers ) + _printError ( true, "Malformed Horizontal line." ); + else + for ( unsigned i = 0 ; i < _nbLayers ; i++ ) { + _horizCap.push_back ( _getLong ( fields[i] ) ); + } + } + + void _parseWidth () + { + if ( strncmp(_rawLine, "minimum width", 13) ) + _printError ( true, "Missing Minimum Width Declaration." ); + + vector fields = _splitString ( _rawLine+14 ); + + if ( fields.size() < _nbLayers ) + _printError ( true, "Malformed Minimum Width line." ); + else + for ( unsigned i = 0 ; i < _nbLayers ; i++ ) { + _minWidth.push_back ( _getLong ( fields[i] ) ); + } + } + + void _parseSpacing () + { + if ( strncmp(_rawLine, "minimum spacing", 15) ) + _printError ( true, "Missing Minimum Spacing Declaration." ); + + vector fields = _splitString ( _rawLine+16 ); + + if ( fields.size() < _nbLayers ) + _printError ( true, "Malformed Minimum Spacing line." ); + else + for ( unsigned i = 0 ; i < _nbLayers ; i++ ) { + _minSpacing.push_back ( _getLong ( fields[i] ) ); + } + } + + void _parseVia () + { + if ( strncmp(_rawLine, "via spacing", 11) ) + _printError ( true, "Missing Via Spacing Declaration." ); + + vector fields = _splitString ( _rawLine+12 ); + + if ( fields.size() < _nbLayers ) + _printError ( true, "Malformed Via Spacing line." ); + else + for ( unsigned i = 0 ; i < _nbLayers ; i++ ) { + _viaSpacing.push_back ( _getLong ( fields[i] ) ); + } + } + + void _parseDim () + { + vector fields = _splitString ( _rawLine ); + + if ( fields.size() < 4 ) + _printError ( true, "Malformed Dimension line." ); + else { + _lowerLeftX = DbU::lambda ( _getLong ( fields[0] ) ); + _lowerLeftY = DbU::lambda ( _getLong ( fields[1] ) ); + _tileWidth = DbU::lambda ( _getLong ( fields[2] ) ); + _tileHeight = DbU::lambda ( _getLong ( fields[3] ) ); + } + + DbU::Unit cellWidth = (2*_lowerLeftX)+(_nbGCellsX*_tileWidth); + DbU::Unit cellHeight = (2*_lowerLeftY)+(_nbGCellsY*_tileHeight); + + cmess1 << " o Creating cell ..." << endl + << " - " << _nbGCellsX << "x" << _nbGCellsY << " -> " << DbU::getValueString(cellWidth) << "x" << DbU::getValueString(cellHeight) << endl + << " - congestion: " << __congestion__ << endl + << " - precongestion: " << __precongestion__ << endl + << " - edge cost: " << __edge_cost__ << endl; + _cell = Cell::create ( _af->getLibrary(0), _filePath ); + assert ( _cell ); + _cell->setTerminal(0); + _cell->setAbutmentBox ( Box ( DbU::lambda(0), DbU::lambda(0), cellWidth, cellHeight ) ); + _knik = KnikEngine::get ( _cell ); + if ( !_knik ) + _knik = KnikEngine::create ( _cell, __congestion__, __precongestion__, true, true, __edge_cost__ ); + + unsigned hcapacity = 0; + for ( unsigned i = 0 ; i < _horizCap.size() ; i++ ) + hcapacity += _horizCap[i]; + hcapacity = hcapacity / ( _minWidth[0]+_minSpacing[0] ); + + unsigned vcapacity = 0; + for ( unsigned i = 0 ; i < _vertiCap.size() ; i++ ) + vcapacity += _vertiCap[i]; + vcapacity = vcapacity / ( _minWidth[1]+_minSpacing[1] ); // XXX we consider only 2 layers!!! + + _knik->createRoutingGrid ( _nbGCellsX, _nbGCellsY, _lowerLeftX, _lowerLeftY, _tileWidth, _tileHeight, hcapacity, vcapacity ); + // for ispd07 reload + _knik->createRoutingGraph(); + } + + void _parseNets () + { + if ( strncmp(_rawLine, "num net", 7) ) + _printError ( true, "Missing Number of Nets Declaration." ); + + cmess1 << " o Parsing nets ..." << endl; + + vector fields = _splitString ( _rawLine+8 ); + if ( fields.size() != 1 ) + _printError ( true, "Malformed Number of Nets line." ); + else + _nbNets = _getLong ( fields[0] ); + + cmess1 << " - " << _nbNets << " nets found" << endl; + } + + void _parseNet ( Net* &net, unsigned &nbPins) + { + vector fields = _splitString ( _rawLine ); + if ( fields.size() != 4 ) + _printError ( true, "Malformed Net Line." ); + else { + Name netName = Name ( fields[0] ); + long netID = _getLong ( fields[1] ); + + nbPins = _getLong ( fields[2] ); + net = Net::create ( _cell, netName ); + + //net->put ( StandardPrivateProperty::create(netID) ); + NetExtension::setId ( net, netID ); + } + } + + void _parseNode ( Net* net, RoutingPad* &firstRoutingPad ) + { + DbU::Unit x,y; + long layerID; + vector fields = _splitString ( _rawLine ); + if ( fields.size() != 3 ) { + for (unsigned i = 0 ; i < fields.size(); i ++ ){ + cerr << fields[i] << ","; + } + cerr << endl; + _printError ( true, "Malformed Node Line." ); + } + else { + x = DbU::lambda ( _getLong ( fields[0] ) ); + y = DbU::lambda ( _getLong ( fields[1] ) ); + layerID = _getLong ( fields[2] ) - 1; + } + //UpdateSession::open(); + Contact* contact = Contact::create ( net, _layers[layerID], x, y, DbU::lambda(2), DbU::lambda(2) ); + RoutingPad* routingPad = RoutingPad::create ( net, Occurrence ( contact ) ); + + // Dans le cas d'un chargment de solution, il se peut que le routingPad ne soit pas au centre du vertex -> on crée arbitrairement un contact au centre qu'on attache au vertex + if ( !_createRings ) + _knik->addRoutingPadToGraph ( routingPad ); + + if ( _createRings ) { + if ( firstRoutingPad ) + routingPad->getBodyHook()->attach ( firstRoutingPad->getBodyHook() ); + else + firstRoutingPad = routingPad; + } + //UpdateSession::close(); + } + + void _parseObs () + { + cmess1 << " o Parsing obstacles ..." << endl; + + vector fields = _splitString ( _rawLine ); + if ( fields.size() != 1 ) + _printError ( true, "Malformed Number of Obstacles line." ); + else + _nbObs = _getLong ( fields[0] ); + + cmess1 << " - " << _nbObs << " obstacles found" << endl; + } + + void _parseObstacle () + { + unsigned col1, row1, lID1, col2, row2, lID2, cap; + + vector fields = _splitString ( _rawLine ); + if ( fields.size() != 7 ) + _printError ( true, "Malformed Obstacle line." ); + else { + col1 = _getLong ( fields[0] ); + row1 = _getLong ( fields[1] ); + lID1 = _getLong ( fields[2] ); + col2 = _getLong ( fields[3] ); + row2 = _getLong ( fields[4] ); + lID2 = _getLong ( fields[5] ); + cap = _getLong ( fields[6] ); + + if ( lID1 != lID2 ) + _printError( true, "Layers must be the same on Obstacle line." ); + + cap = cap / (_minWidth[lID1-1]+_minSpacing[lID1-1]); + _knik->updateEdgeCapacity ( col1, row1, col2, row2, cap ); + } + } + + Cell* loadFromFile() + { + string fullPath = _filePath; + fullPath += ".gr"; + cmess1 << " o Loading cell :" << fullPath << endl; + + + IoFile fileStream ( fullPath ); + fileStream.open ( "r" ); + if ( !fileStream.isOpen() ) { + cerr << " [ERROR] Can't find file : " << fullPath << " !" << endl; + exit (48); + } + + _db = DataBase::getDB (); + _layers[0] = _db->getTechnology()->getLayer ( Name ( "metal1" ) ); + _layers[1] = _db->getTechnology()->getLayer ( Name ( "metal2" ) ); + + _lineNumber = 0; + _parserState = StateGrid; + + try { + while ( !fileStream.eof() ) { + fileStream.readLine ( _rawLine, LINE_SIZE ); + _lineNumber++; + + if ( _rawLine[0] == '\0' ) { + if ( _parserState == StateEOF ) break; + continue; + } else { + if ( _parserState == StateEOF ) + _printError ( true, "Garbage after EOF." ); + } + if ( !strcmp(_rawLine,"EOF") ) { _parserState = StateEOF; continue; } + + if ( _parserState == StateGrid ) { + _parseGrid (); + _parserState = StateVerti; + continue; + } + + if ( _parserState == StateVerti ) { + _parseVerti (); + _parserState = StateHoriz; + continue; + } + + if ( _parserState == StateHoriz ) { + _parseHoriz (); + _parserState = StateWidth; + continue; + } + + if ( _parserState == StateWidth ) { + _parseWidth (); + _parserState = StateSpacing; + continue; + } + + if ( _parserState == StateSpacing ) { + _parseSpacing (); + _parserState = StateVia; + continue; + } + + if ( _parserState == StateVia ) { + _parseVia (); + _parserState = StateDim; + continue; + } + + if ( _parserState == StateDim ) { + _parseDim (); + _parserState = StateNet; + continue; + } + + if ( _parserState == StateNet ) { + _parseNets (); + for ( unsigned i = 0 ; i < _nbNets ; i++ ) { + fileStream.readLine ( _rawLine, LINE_SIZE ); + _lineNumber++; + Net* net = NULL; + RoutingPad* firstRoutingPad = NULL; + unsigned nbPins = 0; + _parseNet( net, nbPins ); + for ( unsigned j = 0 ; j < nbPins ; j++ ) { + fileStream.readLine ( _rawLine, LINE_SIZE ); + _lineNumber++; + _parseNode ( net, firstRoutingPad ); + } + //cmess1 << " ["; + //cmess1.width(3); + //cmess1 << floor((float)(i*100/(float)(_nbNets))); + //cmess1 << "%]\r"; + } + cmess1 << " [100%] Done." << endl; + + _knik->initGlobalRouting(); + _parserState = StateObs; + continue; + } + + if ( _parserState == StateObs ) { + _parseObs (); + for ( unsigned i = 0 ; i < _nbObs ; i++ ) + { + fileStream.readLine ( _rawLine, LINE_SIZE ); + _lineNumber++; + _parseObstacle (); + //cmess1 << " [" << floor((float)(i*100/(float)(_nbObs))) << "%]\r"; + } + cmess1 << " [100%] Done." << endl; + _parserState = StateEOF; + continue; + } + } + } catch ( Error& e ) { + if ( e.what() != "[ERROR] GrParser processed" ) + cerr << e.what() << endl; + } + + fileStream.close (); + + return _cell; + } + + void loadSolutionFile() + // ******************** + { + cmess1 << " o Loading solution :" << _filePath << endl; + + + IoFile fileStream ( _filePath ); + fileStream.open ( "r" ); + if ( !fileStream.isOpen() ) { + cerr << " [ERROR] Can't find file : " << _filePath << " !" << endl; + exit (48); + } + + _db = DataBase::getDB (); + Layer* _gmetalh = _db->getTechnology()->getLayer ( Name ( "gmetalh" ) ); + Layer* _gmetalv = _db->getTechnology()->getLayer ( Name ( "gmetalv" ) ); + Layer* _gcontact = _db->getTechnology()->getLayer ( Name ( "gcontact" ) ); + + _lineNumber = 0; + unsigned _uselessContact = 0; + unsigned _illegalVerti = 0; + unsigned _illegalHoriz = 0; + unsigned _illegalDiag = 0; + unsigned _totalVias = 0; + unsigned _validSegments = 0; + + try { + while ( !fileStream.eof() ) { + fileStream.readLine ( _rawLine, LINE_SIZE ); + _lineNumber++; + + if ( _rawLine[0] == '\0' ) + break; + if ( _rawLine[0] == '\n' ) + continue; + + vector fields = _splitString ( _rawLine ); + if ( fields.size() != 3 ) + _printError ( true, "Malformed Net Line." ); + else { + Name netName = Name ( fields[0] ); + long netID = _getLong ( fields[1] ); + + unsigned nbPins = _getLong ( fields[2] ); + Net* net = _cell->getNet ( netName ); + if ( !net ) { + string message = "Parse solution failed : cannot find net : "; + message += getString(netName); + _printError ( true , message.c_str() ); + } + + vector segments; + for ( unsigned i = 0 ; i < nbPins ; i++ ) { + fileStream.readLine ( _rawLine, LINE_SIZE ); + _lineNumber++; + fields = _splitSegmentString ( _rawLine ); + if ( fields.size() != 6 ) + _printError ( true, "Malformed Net Line." ); + else { + DbU::Unit xSource = DbU::lambda(_getLong(fields[0])); + DbU::Unit ySource = DbU::lambda(_getLong(fields[1])); + unsigned zSource = (unsigned)(_getLong(fields[2])); + DbU::Unit xTarget = DbU::lambda(_getLong(fields[3])); + DbU::Unit yTarget = DbU::lambda(_getLong(fields[4])); + unsigned zTarget = (unsigned)(_getLong(fields[5])); + + if ( xSource == xTarget ) { + if ( ySource == yTarget ) { //contact + if ( zSource != zTarget ) { + //UpdateSession::open(); + Contact::create ( net, _gcontact, xSource, ySource ); + //UpdateSession::close(); + _totalVias++; + } + else + _uselessContact++; + } + else { // segment vertical + if ( zSource != zTarget ) // illegal segment + _illegalVerti++; + else { + //UpdateSession::open(); + Vertical* verti = Vertical::create ( net, _gmetalv, xSource ); + segments.push_back(verti); + if ( ySource < yTarget ) { + verti->setDySource ( ySource ); + verti->setDyTarget ( yTarget ); + } + else { + verti->setDySource ( yTarget ); + verti->setDyTarget ( ySource ); + } + _knik->insertSegment ( verti ); + //UpdateSession::close(); + _validSegments++; + } + } + } + else { // segment horizontal + if ( ySource != yTarget ) + _illegalDiag++; + else { + if ( zSource != zTarget ) + _illegalHoriz++; + else { + //UpdateSession::open(); + Horizontal* horiz = Horizontal::create ( net, _gmetalh, ySource ); + segments.push_back(horiz); + if ( xSource < xTarget ) { + horiz->setDxSource ( xSource ); + horiz->setDxTarget ( xTarget ); + } + else { + horiz->setDxSource ( xTarget ); + horiz->setDxTarget ( xSource ); + } + _knik->insertSegment ( horiz ); + //UpdateSession::close(); + _validSegments++; + } + } + } + } + } + fileStream.readLine ( _rawLine, LINE_SIZE ); + _lineNumber++; + if ( _rawLine[0] != '!' ) + throw Error ("gnagnagnagnagna"+getString(_lineNumber)); + // on va relier les segments et les contacts : + for ( unsigned i = 0 ; i < segments.size() ; i++ ) { + Segment* segment = segments[i]; + Point sourcePos = segment->getSourcePosition(); + Point targetPos = segment->getTargetPosition(); + Contact* source = NULL; + Contact* target = NULL; + forEach ( Contact*, contact, net->getContacts() ) { + Point pos = contact->getPosition(); + if ( pos == sourcePos ) + source = *contact; + else if ( pos == targetPos ) + target = *contact; + if ( source && target ) + break; + } + if ( !source ) { + string message = "Cannot find source contact for "; + message += getString(segment); + throw Error (message); + } + if ( !target ) { + string message = "Cannot find target contact for "; + message += getString(segment); + throw Error (message); + } + //UpdateSession::open(); + if ( Horizontal* horiz = dynamic_cast(segment) ) { + horiz->setDxSource(0); + horiz->setDxTarget(0); + } + else if ( Vertical* verti = dynamic_cast(segment) ) { + verti->setDySource(0); + verti->setDyTarget(0); + } + else + throw Error ("A segment which is not a Horizontal nor a Vertical !!!"); + segment->getSourceHook()->attach(source->getBodyHook()); + segment->getTargetHook()->attach(target->getBodyHook()); + //UpdateSession::close(); + } + } + } + } catch ( Error& e ) { + if ( e.what() != "[ERROR] GrParser processed" ) + cerr << e.what() << endl; + } + + fileStream.close (); + } + + void printToFile(IspdGui* ispd) + // **************************** + { + float width = DbU::getLambda(_cell->getAbutmentBox().getWidth()); + float height = DbU::getLambda(_cell->getAbutmentBox().getHeight()); + assert(width); + assert(height); + float minSize = 800; + unsigned wWidth = (unsigned int)((width < height) ? minSize : floor(width*minSize/height)); + unsigned wHeight = (unsigned int)((width < height) ? floor(height*minSize/width) : minSize); + //unsigned wWidth = floor(width); + //unsigned wHeight = floor(height); + CellWidget* widget = ispd->getCellWidget(); + widget->setFixedSize(wWidth, wHeight); + widget->fitToContents(); + forEach ( Layer*, layer, DataBase::getDB()->getTechnology()->getLayers() ) + widget->setLayerVisible ( layer->getName(), false ); + widget->setLayerVisible ( Name("Knik::Edges"), true ); + + QImage image (wWidth, wHeight+60, QImage::Format_RGB32); + widget->copyToImage(&image); + string savePath = _filePath; + savePath += "_map.png"; + image.save(savePath.c_str(),"png"); + } + +} // End of anonymous namespace. + + + + +// x-----------------------------------------------------------------x +// | Fonctions Definitions | +// x-----------------------------------------------------------------x + + +// ------------------------------------------------------------------- +// Function : "main()". + +int main ( int argc, char *argv[] ) +{ + int returnCode = 0; + + try { + float edgeCapacity; + unsigned int traceLevel; + bool verbose1; + bool verbose2; + bool coreDump; + bool textMode; + bool graphicMode; + bool knikSimple; + bool knikOverflow; + bool loadSolution; + bool saveSolution; + + poptions::options_description options ("Command line arguments & options"); + options.add_options() + ( "help,h" , "Print this help." ) + ( "verbose,v" , poptions::bool_switch(&verbose1)->default_value(false) + , "First level of verbosity.") + ( "very-verbose,V", poptions::bool_switch(&verbose2)->default_value(false) + , "Second level of verbosity.") + ( "text,t" , poptions::bool_switch(&textMode)->default_value(false) + , "Run in pure text mode.") + ( "core-dump,D" , poptions::bool_switch(&coreDump)->default_value(false) + , "Enable core dumping.") + ( "trace-level,l" , poptions::value(&traceLevel)->default_value(1000) + , "Set the level of trace, trace messages with a level superior to " + " will be printed on ." ) + ( "cell,c" , poptions::value() + , "The name of the cell to load, whithout extension." ) + ( "knik,k" , poptions::bool_switch(&knikSimple)->default_value(false) + , "Perform a simple routing pass."); + ( "KNIK,K" , poptions::bool_switch(&knikOverflow)->default_value(false) + , "Perform a routing pass, then analyse & re-route overflowed edges."); + ( "solution,s" , poptions::bool_switch(&loadSolution)->default_value(true) + , "Load a previously generated routing solution."); + ( "Save,S" , poptions::bool_switch(&saveSolution)->default_value(false) + , "Save the routed design."); + ( "editor,e" , poptions::bool_switch(&graphicMode)->default_value(false) + , "Launch the graphical editor."); + + poptions::variables_map arguments; + poptions::store ( poptions::parse_command_line(argc,argv,options), arguments ); + poptions::notify ( arguments ); + + if ( arguments.count("help") ) { + cout << options << endl; + exit ( 0 ); + } + + System::getSystem()->setCatchCore ( not coreDump ); + if ( verbose1 ) mstream::enable ( mstream::VerboseLevel1 ); + if ( verbose2 ) mstream::enable ( mstream::VerboseLevel2 ); + ltracelevel ( traceLevel ); + _createRings = not loadSolution; + + if ( arguments.count("cell") ) { + _filePath = arguments["cell"].as(); + UpdateSession::open(); + _cell = loadFromFile(); + UpdateSession::close(); + if (!_cell) { + cerr << "[ERROR] Cell not found: " << arguments["cell"].as() << endl; + exit ( -45 ); + } + } + + if ( loadSolution ) { + _filePath = arguments["cell"].as(); + UpdateSession::open(); + loadSolutionFile(); + UpdateSession::close(); + } + + if ( not textMode ) { + QApplication* qa = new HApplication ( argc, argv ); + Graphics::enable (); + + IspdGui* ispd = IspdGui::create (); + cmess1 << ispd->getBanner() << endl;; + + GraphicKnikEngine* grKnik = Knik::GraphicKnikEngine::grab(); + ispd->registerTool ( grKnik ); + ispd->registerTool ( Katabatic::GraphicKatabaticEngine::grab() ); + + ispd->setCell ( _cell ); + ispd->show(); + if ( arguments.count("knik") ) { + grKnik->route(); + grKnik->analyse(); + } + else if ( arguments.count("KNIK") ) { + grKnik->run(); + //bool done = grKnik->analyse(); + //while ( !done ) { + // grKnik->unroute(); + // grKnik->reroute(); + // done = grKnik->analyse(); + //} + } + else if ( saveSolution ) { + //grKnik->analyse(); + printToFile(ispd); + } + + if ( not saveSolution or graphicMode ) + returnCode = qa->exec(); + + ispd->destroy(); + delete qa; + } else { + KnikEngine* knik = Knik::KnikEngine::get(_cell); + if ( arguments.count("knik") ) { + knik->Route(); + knik->analyseRouting(); + if ( saveSolution ) knik->saveSolution(); + } else if ( arguments.count("KNIK") ) { + //knik->Route(); + //bool done = knik->analyseRouting(); + //while ( !done ) { + // knik->unrouteOvSegments(); + // knik->reroute(); + // done = knik->analyseRouting(); + //} + knik->run(); + if ( saveSolution ) + knik->saveSolution(); + } else if ( loadSolution ) { + knik->analyseRouting(); + } else + cerr << "[ERROR] Using text mode without -k, -K or -s option is useless." << endl; + } + + _af->destroy(); + } + catch ( Error& e ) { + cerr << e.what() << endl; + exit ( 1 ); + } + catch ( ... ) { + cout << "[ERROR] Abnormal termination: unmanaged exception.\n" << endl; + exit ( 2 ); + } + + return returnCode; +} + +