// -*- 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 n i k - Global Router | // | | // | Author : Damien Dupuis | // | E-mail : Damien.Dupuis@lip6.fr | // | =============================================================== | // | C++ Module : "./LoadSolution.cpp" | // +-----------------------------------------------------------------+ #include #include "hurricane/Error.h" #include "hurricane/Warning.h" #include "hurricane/DataBase.h" #include "hurricane/Technology.h" #include "hurricane/Layer.h" #include "hurricane/NetRoutingProperty.h" #include "hurricane/Contact.h" #include "hurricane/Vertical.h" #include "hurricane/Horizontal.h" #include "hurricane/RoutingPad.h" #include "hurricane/Cell.h" #include "hurricane/UpdateSession.h" #include "crlcore/Utilities.h" #include "crlcore/Measures.h" #include "crlcore/AllianceFramework.h" #include "crlcore/CellGauge.h" #include "knik/Configuration.h" #include "knik/Graph.h" #include "knik/KnikEngine.h" namespace { using std::string; using std::cerr; using std::endl; using std::vector; using std::map; using std::make_pair; using CRL::IoFile; using CRL::AllianceFramework; using Hurricane::ForEachIterator; using Hurricane::Error; using Hurricane::Warning; using Hurricane::DbU; using Hurricane::Point; using Hurricane::Box; using Hurricane::Name; using Hurricane::DataBase; using Hurricane::Technology; using Hurricane::Layer; using Hurricane::Net; using Hurricane::NetRoutingExtension; using Hurricane::NetRoutingState; using Hurricane::Contact; using Hurricane::Segment; using Hurricane::Vertical; using Hurricane::Horizontal; using Hurricane::RoutingPad; using Hurricane::Cell; using Hurricane::UpdateSession; using Knik::Configuration; using Knik::KnikEngine; using Knik::Vertex; const char* LoadError = "KnikEngine::LoadSolution(): %s.\n (file: %s, at line: %d)"; const char* NotManhattan = "KnikEngine::LoadSolution(): Encountered a Segment neither Horizontal nor Vertical.\n" " ([%s %s] [%s %s], file: %s, at line: %d)"; const char* BadLong = "KnikEngine::LoadSolution(): Incomplete string to integer conversion for \"%s\" (%ld).\n" " (file: %s, at line: %d)"; struct PointCompare { bool operator() ( const Point& lhs, const Point& rhs ) const; }; bool PointCompare::operator() ( const Point& lhs, const Point& rhs ) const { if ( lhs.getX() < rhs.getX() ) return true; if ( lhs.getX() > rhs.getX() ) return false; if ( lhs.getY() < rhs.getY() ) return true; return false; } class GContactMap { public: GContactMap ( KnikEngine* knik , const Layer* gmetalh , const Layer* gmetalv ); void setNet ( Net* ); const Layer* getLayer ( unsigned int z ); Contact* find ( DbU::Unit x, DbU::Unit y, unsigned int z ); Contact* findVertexContact ( const Box& ); size_t size () const; void clear (); private: void _mergeLayer ( Contact*, unsigned int ); private: KnikEngine* _knik; Technology* _technology; Net* _net; map _contactMap; map _vertexMap; const Layer* _gmetalh; const Layer* _gmetalv; }; GContactMap::GContactMap ( KnikEngine* knik , const Layer* gmetalh , const Layer* gmetalv ) : _knik (knik) , _technology(DataBase::getDB()->getTechnology()) , _net (NULL) , _contactMap() , _vertexMap () , _gmetalh (gmetalh) , _gmetalv (gmetalv) { } void GContactMap::setNet ( Net* net ) { _net = net; } const Layer* GContactMap::getLayer ( unsigned int z ) { return (z%2) ? _gmetalh : _gmetalv; } Contact* GContactMap::find ( DbU::Unit x, DbU::Unit y, unsigned int z ) { map::iterator icontact = _contactMap.find ( Point(x,y) ); Contact* contact; if ( icontact == _contactMap.end() ) { contact = Contact::create ( _net, getLayer(z), x, y, DbU::lambda(3.0), DbU::lambda(3.0) ); Vertex* vertex = _knik->getVertex ( x, y ); _contactMap.insert ( make_pair(Point(x,y),contact) ); _vertexMap .insert ( make_pair(vertex ,contact) ); } else { contact = icontact->second; } _mergeLayer ( contact, z ); return contact; } Contact* GContactMap::findVertexContact ( const Box& boundingBox ) { Point reference = boundingBox.getCenter(); Vertex* vertex = _knik->getVertex ( reference ); if ( !vertex ) return NULL; map::iterator icontact = _vertexMap.find ( vertex ); if ( icontact == _vertexMap.end() ) return NULL; return icontact->second; } size_t GContactMap::size () const { return _contactMap.size(); } void GContactMap::clear () { _contactMap.clear(); _vertexMap.clear(); } void GContactMap::_mergeLayer ( Contact* contact, unsigned int z ) { const Layer* mergeLayer = getLayer ( z ); const Layer* contactLayer = contact->getLayer(); if ( contactLayer->contains(mergeLayer) ) return; contactLayer = _technology->getViaBetween ( contactLayer, mergeLayer ); if ( contactLayer ) contact->setLayer ( contactLayer ); } class SolutionParser { public: SolutionParser ( KnikEngine*, const string& loadFileName ); void load (); private: long _getLong ( const char* ); vector _splitSegmentString ( char* ); vector _splitString ( char* ); private: enum Constants { RawLineSize = 4096 }; private: char _rawLine [ RawLineSize ]; size_t _lineNumber; string _fileName; KnikEngine* _knik; const Layer* _gmetalh; const Layer* _gmetalv; const Layer* _gcontact; }; SolutionParser::SolutionParser ( KnikEngine* knik, const string& fileName ) : _lineNumber(0) , _fileName (fileName) , _knik (knik) , _gmetalh (Configuration::getGMetalH()) , _gmetalv (Configuration::getGMetalV()) , _gcontact (Configuration::getGContact()) { } long SolutionParser::_getLong ( const char* s ) { char* end; long value = strtol ( s, &end, 10 ); if ( *end != '\0' ) cerr << Error(BadLong,s,value,_fileName.c_str(),_lineNumber) << endl; return value; } vector SolutionParser::_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 SolutionParser::_splitSegmentString ( char* s ) { vector fields; while ( *s != '\0' ) { switch ( *s ) { case '(': case ',': *s = '\0'; ++s; break; case ')': *s = '\0'; ++s; if ( *s == '-' ) { *s = '\0'; ++s; } break; default: fields.push_back ( s ); while ( *s && ( (*s != ')') && (*s != ',') ) ) ++s; } } return fields; } void SolutionParser::load () { UpdateSession::open(); try { cmess1 << " o Loading solution: \"" << _fileName << "\"." << endl; DbU::Unit sliceHeight = AllianceFramework::get()->getCellGauge()->getSliceHeight(); CRL::IoFile fileStream ( _fileName ); fileStream.open( "r" ); if (not fileStream.isOpen()) throw Error( "Can't open/read file: %s.", _fileName.c_str() ); unsigned int missingGlobalRouting = 0; unsigned int contactCount = 0; unsigned int segmentCount = 0; GContactMap contactMap ( _knik, _gmetalh, _gmetalv ); while ( not fileStream.eof() ) { fileStream.readLine( _rawLine, RawLineSize ); _lineNumber++; if (_rawLine[0] == '\0') break; if (_rawLine[0] == '\n') continue; vector fields = _splitString( _rawLine ); if ( fields.size() != 3 ) throw Error( LoadError, "Malformed Net Line", _fileName.c_str(), _lineNumber ); else { Name netName = Name ( fields[0] ); unsigned int nbPins = _getLong( fields[2] ); unsigned int nbSegments = 0; unsigned int nbRoutingPad = 0; Net* net = _knik->getCell()->getNet( netName ); if (not net) { string message = "Cell has no Net: "; message += getString(netName); throw Error( LoadError, message.c_str(), _fileName.c_str(), _lineNumber ); } contactMap.setNet( net ); for ( unsigned i = 0 ; i < nbPins ; i++ ) { fileStream.readLine( _rawLine, RawLineSize ); _lineNumber++; fields = _splitSegmentString( _rawLine ); if (fields.size() != 6) throw Error( LoadError, "Malformed Net Line", _fileName.c_str(), _lineNumber ); else { DbU::Unit xSource = DbU::lambda( _getLong(fields[0]) ); DbU::Unit ySource = DbU::lambda( _getLong(fields[1]) ); unsigned int zSource = (unsigned) ( _getLong(fields[2]) ); DbU::Unit xTarget = DbU::lambda( _getLong(fields[3]) ); DbU::Unit yTarget = DbU::lambda( _getLong(fields[4]) ); unsigned int zTarget = (unsigned) ( _getLong(fields[5]) ); Contact* source = contactMap.find( xSource, ySource, zSource ); Contact* target = contactMap.find( xTarget, yTarget, zTarget ); Segment* segment = NULL; unsigned int type = ((ySource == yTarget)?1:0) + ((xSource == xTarget)?2:0); switch ( type ) { case 0: throw Error( NotManhattan , DbU::getValueString(xSource).c_str() , DbU::getValueString(ySource).c_str() , DbU::getValueString(xTarget).c_str() , DbU::getValueString(yTarget).c_str() , _fileName.c_str() , _lineNumber ); case 1: segment = Horizontal::create( source, target, _gmetalh, ySource, DbU::lambda(2.0) ); ++nbSegments; break; case 2: segment = Vertical::create( source, target, _gmetalv, xSource, DbU::lambda(2.0) ); ++nbSegments; break; case 3: break; } if (segment) _knik->insertSegment( segment ); } } fileStream.readLine( _rawLine, RawLineSize ); _lineNumber++; if (_rawLine[0] != '!') throw Error( "KnikEngine::loadSolution(): Tu t'es vu quand t'as bu! (%ld)." , getString(_lineNumber).c_str()); Box rpBox; RoutingPad* previousRp = NULL; if (NetRoutingExtension::isAutomaticGlobalRoute(net)) { forEach ( RoutingPad*, rp, net->getRoutingPads() ) { rpBox.merge( rp->getBoundingBox() ); Contact* gcontact = contactMap.findVertexContact( rp->getBoundingBox() ); if (gcontact) { rp->getBodyHook()->attach( gcontact->getBodyHook() ); } else { if (previousRp) rp->getBodyHook()->attach( previousRp->getBodyHook() ); } previousRp = *rp; ++nbRoutingPad; //cerr << rp->_getString() << " should be attached to " << gcontact << endl; } } if ( (nbRoutingPad > 1) and (not contactMap.size()) and ( (rpBox.getHeight() > sliceHeight) or (rpBox.getWidth () > sliceHeight) ) ) { ++missingGlobalRouting; cerr << Warning( "Net <%s> is missing global routing." , getString(net->getName()).c_str() ) << endl; } segmentCount += nbSegments; contactCount += contactMap.size(); contactMap.clear(); } } fileStream.close(); if (missingGlobalRouting) throw Error( "At least %d nets are missing global routing. Maybe a corrupted <.kgr> file?" , missingGlobalRouting ); } catch ( Error& e ) { UpdateSession::close (); //cerr << e << endl; throw; } UpdateSession::close (); } } // End of anonymous namespace. namespace Knik { using CRL::addMeasure; void KnikEngine::loadSolution ( const string& fileName ) { string loadFileName = fileName; if ( loadFileName.empty() ) loadFileName = _getSolutionName(); SolutionParser parser ( this, loadFileName ); parser.load (); addMeasure ( getCell(), "knikT", 0.0, 8 ); addMeasure ( getCell(), "knikS", 0 , 8 ); computeSymbolicWireLength (); } } // End of Knik namespace.