coriolis/knik/src/LoadSolution.cpp

436 lines
13 KiB
C++
Raw Normal View History

// -*- 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 <iostream>
#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<Point,Contact*,PointCompare> _contactMap;
map<Vertex*,Contact*> _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<Point,Contact*,PointCompare>::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<Vertex*,Contact*>::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<char*> _splitSegmentString ( char* );
vector<char*> _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<char*> SolutionParser::_splitString ( char* s )
{
vector<char*> 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<char*> SolutionParser::_splitSegmentString ( char* s )
{
vector<char*> 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<char*> 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<RoutingPad*>() ) {
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<double> ( getCell(), "knikT", 0.0 );
addMeasure<size_t> ( getCell(), "knikS", 0 );
computeSymbolicWireLength ();
}
} // End of Knik namespace.