// -*- 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 | // | K n i k - Global Router | // | | // | Author : Damien Dupuis | // | E-mail : Damien.Dupuis@lip6.fr | // | =============================================================== | // | C++ Module : "./LoadSolution.cpp" | // | *************************************************************** | // | U p d a t e s | // | | // x-----------------------------------------------------------------x #include #include "hurricane/Error.h" #include "hurricane/DataBase.h" #include "hurricane/Technology.h" #include "hurricane/Layer.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 "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 Hurricane::ForEachIterator; using Hurricane::Error; 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::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; CRL::IoFile fileStream ( _fileName ); fileStream.open ( "r" ); if ( !fileStream.isOpen() ) throw Error ("Can't open/read file: %s.",_fileName.c_str()); unsigned int contactCount = 0; unsigned int segmentCount = 0; GContactMap contactMap ( _knik, _gmetalh, _gmetalv ); while ( !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 nbPins = _getLong ( fields[2] ); Net* net = _knik->getCell()->getNet ( netName ); if ( !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 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])); 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) ); segmentCount++; break; case 2: segment = Vertical::create ( source, target, _gmetalv, xSource, DbU::lambda(2.0) ); segmentCount++; 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()); RoutingPad* previousRp = NULL; forEach ( RoutingPad*, rp, net->getComponents().getSubSet() ) { Contact* gcontact = contactMap.findVertexContact ( rp->getBoundingBox() ); if ( gcontact ) { rp->getBodyHook()->attach ( gcontact->getBodyHook() ); } else { if ( previousRp ) rp->getBodyHook()->attach ( previousRp->getBodyHook() ); } previousRp = *rp; //cerr << rp->_getString() << " should be attached to " << gcontact << endl; } contactCount += contactMap.size (); contactMap.clear (); } } fileStream.close (); } catch ( Error& e ) { cerr << e << endl; } 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 ); addMeasure ( getCell(), "knikS", 0 ); } } // End of Knik namespace.