coriolis/knik/src/LoadSolution.cpp

458 lines
14 KiB
C++

// -*- 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 <iostream>
#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<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;
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<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 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<double> ( getCell(), "knikT", 0.0, 8 );
addMeasure<size_t> ( getCell(), "knikS", 0 , 8 );
computeSymbolicWireLength ();
}
} // End of Knik namespace.