488 lines
13 KiB
C++
488 lines
13 KiB
C++
// -*- 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 |
|
|
// | S O L S T I C E - C o m p a r a t o r |
|
|
// | |
|
|
// | Author : Wu Yife |
|
|
// | E-mail : Wu.Yifei@lip6.fr |
|
|
// | =============================================================== |
|
|
// | C++ Header : "./SolsticeEngine.cpp" |
|
|
// | *************************************************************** |
|
|
// | U p d a t e s |
|
|
// | |
|
|
// x-----------------------------------------------------------------x
|
|
#include <hurricane/DataBase.h>
|
|
#include <hurricane/Cell.h>
|
|
#include <hurricane/Technology.h>
|
|
|
|
#include <crlcore/Utilities.h>
|
|
#include <crlcore/ToolEngine.h>
|
|
|
|
#include <equinox/Equi.h>
|
|
#include <equinox/Strategy.h>
|
|
#include <equinox/IntervalTree.h>
|
|
#include <equinox/Tiles.h>
|
|
#include <equinox/EquinoxEngine.h>
|
|
|
|
|
|
#include <solstice/Brick.h>
|
|
#include <solstice/SolsticeEngine.h>
|
|
#include <solstice/BrickSweepLine.h>
|
|
#include <solstice/RoutingError.h>
|
|
#include <solstice/ShortCircuitError.h>
|
|
#include <solstice/DisconnectError.h>
|
|
|
|
namespace Solstice {
|
|
|
|
|
|
using namespace std;
|
|
using namespace Hurricane;
|
|
using Equinox::DefaultStrategy;
|
|
using Equinox::EquinoxEngine;
|
|
using Equinox::Equi;
|
|
using Equinox::CompByXmin;
|
|
using Equinox::CompByXmax;
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "Solstice::SolsticeEngine".
|
|
|
|
Name SolsticeEngine::_toolName = "Solstice";
|
|
Strategy * SolsticeEngine::_strategy = NULL;
|
|
|
|
|
|
|
|
void SolsticeEngine::setStrategy (Strategy * s)
|
|
{
|
|
if (_strategy)
|
|
delete _strategy;
|
|
_strategy = s;
|
|
};
|
|
|
|
Strategy* SolsticeEngine::getStrategy ()
|
|
{
|
|
if (!_strategy) {
|
|
_strategy = new DefaultStrategy();
|
|
}
|
|
return _strategy;
|
|
}
|
|
|
|
|
|
Cell* SolsticeEngine::getCommonPath(Path path1, Path path2, Path& newpath1, Path& newpath2)
|
|
{
|
|
Instance * instance1 = path1.getHeadInstance();
|
|
Instance * instance2 = path2.getHeadInstance();
|
|
Path commonpath;
|
|
|
|
while(instance1==instance2)
|
|
{
|
|
if(!instance1) break;
|
|
|
|
path1 = path1.getTailPath();
|
|
path2 = path2.getTailPath();
|
|
|
|
commonpath = commonpath.isEmpty()?Path(instance1):Path(commonpath, instance1);
|
|
|
|
if(path1.isEmpty()) break;
|
|
if(path2.isEmpty()) break;
|
|
|
|
instance1 = path1.getHeadInstance();
|
|
instance2 = path2.getHeadInstance();
|
|
}
|
|
|
|
newpath1 = path1;
|
|
newpath2 = path2;
|
|
|
|
if (commonpath.isEmpty())
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return commonpath.getMasterCell();
|
|
}
|
|
}
|
|
|
|
SolsticeEngine* SolsticeEngine::create (Cell* cell)
|
|
{
|
|
SolsticeEngine* solstice = new SolsticeEngine ( cell );
|
|
|
|
if(!solstice){
|
|
throw Error("can't create Solstice : allocation failed");
|
|
}
|
|
|
|
solstice->_postCreate ();
|
|
return solstice;
|
|
}
|
|
|
|
|
|
void SolsticeEngine::_depthCreate(Cell * cell)
|
|
{
|
|
forEach(Instance*,instance, cell->getInstances())
|
|
{
|
|
Cell * subcell = (*instance)->getMasterCell();
|
|
SolsticeEngine * solstice = get(subcell);
|
|
if( (!(subcell->isLeaf())) && (!solstice) ) {
|
|
_depthCreate(subcell);
|
|
}
|
|
}
|
|
SolsticeEngine * solstice = get(cell);
|
|
if(!solstice)
|
|
create(cell);
|
|
}
|
|
|
|
|
|
SolsticeEngine* SolsticeEngine::get (const Cell* cell )
|
|
{
|
|
return static_cast<SolsticeEngine*>(ToolEngine::get(cell,_toolName));
|
|
}
|
|
|
|
|
|
Record* SolsticeEngine::_getRecord () const
|
|
{
|
|
Record* record = ToolEngine::_getRecord ();
|
|
return ( record );
|
|
}
|
|
|
|
|
|
SolsticeEngine::~SolsticeEngine ()
|
|
{
|
|
}
|
|
|
|
SolsticeEngine::SolsticeEngine (Cell* cell):
|
|
ToolEngine(cell),
|
|
_isCompared(false),
|
|
_routingErrors()
|
|
{
|
|
_routingErrors = new set<RoutingError*>;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SolsticeEngine::_depthDestroy()
|
|
{
|
|
if(_cell->isLeaf())
|
|
return ;
|
|
else {
|
|
forEach(Instance*,instance, _cell->getInstances())
|
|
{
|
|
Cell * cell = (*instance)->getMasterCell();
|
|
SolsticeEngine * solstice = get(cell);
|
|
if(solstice) solstice->_depthDestroy();
|
|
}
|
|
this->destroy();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void SolsticeEngine::compare()
|
|
{
|
|
// Verify the extractor Equinox
|
|
// ******************************
|
|
EquinoxEngine * equinox = EquinoxEngine::get(_cell);
|
|
if(!equinox){
|
|
throw Error("Can't do comparison, because the extractor haven't been created");
|
|
}
|
|
|
|
if(!(equinox->isExtracted())) {
|
|
throw Error("Can't do comparison, because the extraction haven't been done");
|
|
}
|
|
|
|
// Create CEngine Solstice for all models except standards models.
|
|
// *****************************************************************
|
|
_depthCreate(_cell);
|
|
|
|
// If repeat Comparison, flush those olds errors and reset flags to false.
|
|
// *************************************************************************
|
|
if(isCompared()) flushErrors();
|
|
|
|
// Run comparison and Print Statistique datas.
|
|
// *********************************************
|
|
runComparison();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SolsticeEngine::runComparison()
|
|
{
|
|
map<Occurrence, set<Equi*> > map_hypernet2hyperequi;
|
|
set<Occurrence> hypernets;
|
|
EquinoxEngine * equinox = Equinox::EquinoxEngine::get(_cell);
|
|
|
|
forEach(Equi*,equi, equinox->getRoutingEquis())
|
|
{
|
|
forEach(Occurrence,occurrence, (*equi)->getAllOccurrences())
|
|
{
|
|
|
|
// Check Net Power/Ground/Global
|
|
//*******************************
|
|
Net * net = dynamic_cast<Net*>((*occurrence).getEntity());
|
|
if(!net)
|
|
net = dynamic_cast<Component*>((*occurrence).getEntity())->getNet();
|
|
|
|
if(net->isGlobal() || net->isGround() || net->isPower()) {
|
|
continue;
|
|
}
|
|
|
|
|
|
// Add HyperNet
|
|
//**************
|
|
Occurrence hypernet = getTopNetOccurrence((*occurrence));
|
|
#ifdef ASSERT
|
|
assert(isHyperNetRootNetOccurrence(hypernet));
|
|
#endif
|
|
hypernets.insert(hypernet);
|
|
map_hypernet2hyperequi[hypernet].insert((*equi));
|
|
|
|
} //end of forEach occurrence
|
|
|
|
|
|
// ShortCircuits Detection
|
|
//*************************
|
|
if(hypernets.size() > 1) {
|
|
cmess1 << "[BUG] ShortCircuit Detection with " << hypernets.size() << " nets on same Equi" << endl;
|
|
for (set<Occurrence>::iterator i = hypernets.begin() ; i!= hypernets.end();i++)
|
|
cmess1 << " - Net " << (*i).getEntity()->_getString() << endl;
|
|
detectShortCircuit((*equi));
|
|
}
|
|
|
|
hypernets.clear();
|
|
|
|
} //end of forEach equi
|
|
|
|
|
|
// Disconnects Detection
|
|
//***********************
|
|
for (map<Occurrence, set<Equi*> >::iterator i = map_hypernet2hyperequi.begin();
|
|
i != map_hypernet2hyperequi.end();
|
|
i++)
|
|
{
|
|
if( (*i).second.size()>1 ) {
|
|
cmess1 << "[BUG] Disconnection Detection with " << (*i).second.size() << " equi for net " << (*i).first.getEntity()->_getString() << endl;
|
|
|
|
for (set<Equi*>::iterator j = (*i).second.begin();
|
|
j != (*i).second.end();
|
|
j++)
|
|
{
|
|
cmess1 << " - " << (*j) << endl ;
|
|
forEach(Occurrence,k,(*j)->getAllOccurrences()) {
|
|
cmess1 << " - " << (*k) << endl ;
|
|
}
|
|
}
|
|
|
|
this->_routingErrors->insert(DisconnectError::create(getCell(),Occurrence((*i).first),(*i).second.size()));
|
|
|
|
}
|
|
}
|
|
|
|
map_hypernet2hyperequi.clear();
|
|
setIsComparedTrue(_cell);
|
|
}
|
|
|
|
|
|
|
|
|
|
Occurrence SolsticeEngine::getTopNetOccurrence(Occurrence occurrence)
|
|
{
|
|
Path path = occurrence.getPath();
|
|
|
|
if( path.isEmpty() ) {
|
|
Net * net = dynamic_cast<Net*>(occurrence.getEntity());
|
|
if(net) {
|
|
return occurrence;
|
|
}
|
|
else {
|
|
Component * component = dynamic_cast<Component*>(occurrence.getEntity());
|
|
if(!component)
|
|
throw Error("Unknow occurrence in EQUINOX::GetUpperNetOccurrence()");
|
|
return Occurrence(component->getNet());
|
|
}
|
|
}
|
|
else {
|
|
Net * net = dynamic_cast<Net*>(occurrence.getEntity());
|
|
|
|
if(net) {
|
|
if( !(net->isExternal()) )
|
|
return occurrence;
|
|
Instance * tailinstance = path.getTailInstance();
|
|
Plug * plug = tailinstance->getPlug(net);
|
|
|
|
if( !(plug->isConnected()) )
|
|
return occurrence;
|
|
|
|
|
|
Net * uppernet = plug->getNet();
|
|
return getTopNetOccurrence(Occurrence(uppernet, path.getHeadPath()));
|
|
}
|
|
else {
|
|
Component* component = dynamic_cast<Component*>(occurrence.getEntity());
|
|
return getTopNetOccurrence(Occurrence(component->getNet(), occurrence.getPath()));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void SolsticeEngine::detectShortCircuit(Equi* equi)
|
|
{
|
|
|
|
// Create Bricks for all component occurrences in this hyper-equi.
|
|
// ***************************************************************
|
|
vector<Brick*>* BricksByXmin = new vector<Brick*> ;
|
|
vector<Brick*>* BricksByXmax = new vector<Brick*> ;
|
|
|
|
forEach(Occurrence,occurrence, equi->getEquiComponentOccurrences()) {
|
|
Occurrence hypernet = getTopNetOccurrence((*occurrence));
|
|
Component* component = dynamic_cast<Component*>((*occurrence).getEntity());
|
|
|
|
Box box = (*occurrence).getBoundingBox();
|
|
|
|
forEach ( BasicLayer*, i, component->getLayer()->getBasicLayers() )
|
|
if (Strategy::isExtractableLayer(*i))
|
|
{
|
|
|
|
Brick * brick = Brick::create(hypernet, (*occurrence), box, *i);
|
|
BricksByXmin->push_back(brick);
|
|
BricksByXmax->push_back(brick);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Sort these two tables.
|
|
// *********************
|
|
sort< vector<Brick*>::iterator , CompByXmin<Brick*> > ( BricksByXmin->begin(), BricksByXmin->end(), CompByXmin<Brick*>() );
|
|
sort< vector<Brick*>::iterator , CompByXmax<Brick*> > ( (BricksByXmax->begin()), BricksByXmax->end(), CompByXmax<Brick*>() );
|
|
|
|
|
|
BrickSweepLine* sweepLine = BrickSweepLine::create(this,getStrategy());
|
|
|
|
sweepLine->run(BricksByXmin,BricksByXmax,false,0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SolsticeEngine::setIsComparedTrue(Cell * cell)
|
|
{
|
|
SolsticeEngine * solstice = get(cell);
|
|
solstice->setIsCompared(true);
|
|
|
|
forEach(Instance*,instance, cell->getInstances())
|
|
{
|
|
Cell * subcell = (*instance)->getMasterCell();
|
|
SolsticeEngine * solstice = get(subcell);
|
|
if( (!(subcell->isLeaf())) && (!(solstice->isCompared())) )
|
|
setIsComparedTrue(subcell);
|
|
}
|
|
}
|
|
|
|
|
|
void SolsticeEngine::getAllSolstices(Cell* cell, set<SolsticeEngine*>& solstices)
|
|
{
|
|
SolsticeEngine* solstice = get(cell);
|
|
solstices.insert(solstice);
|
|
forEach(Instance*,instance, cell->getInstances())
|
|
{
|
|
Cell * subcell = (*instance)->getMasterCell();
|
|
if( (!(subcell->isLeaf())) )
|
|
getAllSolstices(subcell, solstices);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void SolsticeEngine::insertInterval ( Brick*brick ,stack <Equinox::Interval*>* enumResultStack)
|
|
{
|
|
while( !(enumResultStack->empty()) ) {
|
|
Brick* findedbrick = dynamic_cast<Brick*>(enumResultStack->top());
|
|
enumResultStack->pop();
|
|
if(findedbrick->getHyperNet()!=brick->getHyperNet()) { // Shorts-Circuits
|
|
Occurrence occurrence1 = brick->getComponentOccurrence();
|
|
Occurrence occurrence2 = findedbrick->getComponentOccurrence();
|
|
Path newpath1;
|
|
Path newpath2;
|
|
|
|
Cell * errorcell = getCommonPath(occurrence1.getPath(), occurrence2.getPath(), newpath1, newpath2);
|
|
SolsticeEngine * solstice = NULL;
|
|
|
|
if(errorcell) {
|
|
solstice = get(errorcell);
|
|
|
|
if(!solstice) {
|
|
cout << getString(errorcell) <<endl;
|
|
throw Error("Can't get CEngine solstice in function SolsticeEngine::insertInterval");
|
|
}
|
|
}
|
|
else { // If errorcell is Null, the top-model is current model.
|
|
solstice = this;
|
|
errorcell = _cell;
|
|
}
|
|
|
|
ShortCircuitError* error = ShortCircuitError::create(
|
|
errorcell,
|
|
Occurrence(occurrence1.getEntity(), newpath1),
|
|
Occurrence(occurrence2.getEntity(), newpath2)
|
|
);
|
|
|
|
solstice->_routingErrors->insert(error);
|
|
}
|
|
}
|
|
}
|
|
void SolsticeEngine::removeInterval (Brick* item)
|
|
{
|
|
item->destroy();
|
|
}
|
|
|
|
|
|
void SolsticeEngine::clearErrors() {
|
|
for(set<RoutingError*>::iterator e = _routingErrors->begin();
|
|
e != _routingErrors->end() ;
|
|
e++)
|
|
(*e)->destroy();
|
|
_routingErrors->clear();
|
|
|
|
};
|
|
|
|
void SolsticeEngine::flushErrors()
|
|
{
|
|
forEach(Instance*,instance, _cell->getInstances())
|
|
{
|
|
Cell * cell = (*instance)->getMasterCell();
|
|
SolsticeEngine * solstice = get(cell);
|
|
if( (!(cell->isLeaf())) && (solstice->isCompared()) ) {
|
|
solstice->flushErrors();
|
|
}
|
|
}
|
|
|
|
clearErrors();
|
|
setIsCompared(false);
|
|
}
|
|
|
|
|
|
|
|
|
|
}// End of namespace Solstice
|