406 lines
13 KiB
C++
406 lines
13 KiB
C++
// -*- C++ -*-
|
|
//
|
|
// This file is part of the Coriolis Software.
|
|
// Copyright (c) UPMC 2015-2016, All Rights Reserved
|
|
//
|
|
// +-----------------------------------------------------------------+
|
|
// | C O R I O L I S |
|
|
// | E t e s i a n - A n a l y t i c P l a c e r |
|
|
// | |
|
|
// | Author : Jean-Paul CHAPUT |
|
|
// | E-mail : Jean-Paul.Chaput@asim.lip6.fr |
|
|
// | =============================================================== |
|
|
// | C++ Module : "./AddFeeds.cpp" |
|
|
// +-----------------------------------------------------------------+
|
|
|
|
|
|
#include <map>
|
|
#include <list>
|
|
#include "hurricane/Error.h"
|
|
#include "hurricane/Warning.h"
|
|
#include "hurricane/DataBase.h"
|
|
#include "hurricane/UpdateSession.h"
|
|
#include "hurricane/Instance.h"
|
|
#include "hurricane/Plug.h"
|
|
#include "hurricane/Path.h"
|
|
#include "hurricane/viewer/CellWidget.h"
|
|
#include "hurricane/viewer/CellViewer.h"
|
|
#include "crlcore/AllianceFramework.h"
|
|
#include "crlcore/ToolBox.h"
|
|
#include "etesian/EtesianEngine.h"
|
|
|
|
|
|
namespace {
|
|
|
|
using namespace std;
|
|
using Hurricane::tab;
|
|
using Hurricane::ForEachIterator;
|
|
using Hurricane::Warning;
|
|
using Hurricane::Error;
|
|
using Hurricane::DbU;
|
|
using Hurricane::Box;
|
|
using Hurricane::Interval;
|
|
using Hurricane::Instance;
|
|
using Hurricane::Path;
|
|
using Hurricane::Transformation;
|
|
using Hurricane::DataBase;
|
|
using Hurricane::Cell;
|
|
using CRL::AllianceFramework;
|
|
using CRL::CatalogExtension;
|
|
using CRL::getTransformation;
|
|
using Etesian::EtesianEngine;
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Class : "::SliceHoles".
|
|
|
|
class SliceHoles;
|
|
|
|
class Slice {
|
|
public:
|
|
Slice ( SliceHoles*, DbU::Unit ybottom, Interval xspan );
|
|
inline DbU::Unit getYBottom () const;
|
|
inline const Interval& getXSpan () const;
|
|
inline DbU::Unit getXMin () const;
|
|
inline DbU::Unit getXMax () const;
|
|
inline SliceHoles* getSliceHoles () const;
|
|
inline EtesianEngine* getEtesian () const;
|
|
inline size_t getSpinSlice0 () const;
|
|
void merge ( DbU::Unit source, DbU::Unit target );
|
|
void addFeeds ( size_t islice );
|
|
void fillHole ( DbU::Unit xmin, DbU::Unit xmax, DbU::Unit ybottom, size_t yspin );
|
|
string _getString () const;
|
|
private:
|
|
SliceHoles* _sliceHoles;
|
|
DbU::Unit _ybottom;
|
|
Interval _xspan;
|
|
list<Interval> _chunks;
|
|
};
|
|
|
|
|
|
class SliceHoles {
|
|
public:
|
|
SliceHoles ( EtesianEngine* );
|
|
~SliceHoles ();
|
|
inline EtesianEngine* getEtesian () const;
|
|
inline size_t getSpinSlice0 () const;
|
|
inline void setSpinSlice0 ( size_t );
|
|
void merge ( const Box& );
|
|
void addFeeds ();
|
|
private:
|
|
EtesianEngine* _etesian;
|
|
Box _cellAb;
|
|
DbU::Unit _sliceHeight;
|
|
vector<Slice*> _slices;
|
|
size_t _spinSlice0;
|
|
};
|
|
|
|
|
|
Slice::Slice ( SliceHoles* sliceHoles, DbU::Unit ybottom, Interval xspan )
|
|
: _sliceHoles(sliceHoles)
|
|
, _ybottom (ybottom)
|
|
, _xspan (xspan)
|
|
, _chunks ()
|
|
{ }
|
|
|
|
inline DbU::Unit Slice::getYBottom () const { return _ybottom; }
|
|
inline DbU::Unit Slice::getXMin () const { return _xspan.getVMin(); }
|
|
inline DbU::Unit Slice::getXMax () const { return _xspan.getVMax(); }
|
|
inline const Interval& Slice::getXSpan () const { return _xspan; }
|
|
inline SliceHoles* Slice::getSliceHoles () const { return _sliceHoles; }
|
|
inline EtesianEngine* Slice::getEtesian () const { return getSliceHoles()->getEtesian(); }
|
|
inline size_t Slice::getSpinSlice0 () const { return getSliceHoles()->getSpinSlice0(); }
|
|
|
|
|
|
void Slice::merge ( DbU::Unit source, DbU::Unit target )
|
|
{
|
|
Interval chunkToMerge = _xspan.getIntersection( Interval(source,target) );
|
|
cdebug_log(129,0) << " Slice::merge() " << " " << chunkToMerge << endl;
|
|
cdebug_log(129,0) << " | " << _getString() << endl;
|
|
|
|
if (chunkToMerge.isEmpty()) return;
|
|
|
|
list<Interval>::iterator imerge = _chunks.end();
|
|
list<Interval>::iterator ichunk = _chunks.begin();
|
|
|
|
while ( ichunk != _chunks.end() ) {
|
|
if (imerge == _chunks.end()) {
|
|
if (chunkToMerge.getVMax() < (*ichunk).getVMin()) {
|
|
cdebug_log(129,0) << " | Insert before " << *ichunk << endl;
|
|
imerge = _chunks.insert( ichunk, chunkToMerge );
|
|
break;
|
|
}
|
|
|
|
if (chunkToMerge.intersect(*ichunk)) {
|
|
cdebug_log(129,0) << " | Merge with " << *ichunk << endl;
|
|
imerge = ichunk;
|
|
(*imerge).merge( chunkToMerge );
|
|
}
|
|
} else {
|
|
if (chunkToMerge.getVMax() >= (*ichunk).getVMin()) {
|
|
(*imerge).merge( *ichunk );
|
|
cdebug_log(129,0) << " | Absorb (erase) " << *ichunk << endl;
|
|
ichunk = _chunks.erase( ichunk );
|
|
continue;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
++ichunk;
|
|
}
|
|
|
|
if (imerge == _chunks.end()) {
|
|
_chunks.insert( ichunk, chunkToMerge );
|
|
cdebug_log(129,0) << " | Insert at end " << DbU::getValueString(_ybottom) << " " << chunkToMerge << endl;
|
|
cdebug_log(129,0) << " | " << _getString() << endl;
|
|
}
|
|
}
|
|
|
|
|
|
void Slice::addFeeds ( size_t islice )
|
|
{
|
|
if (_chunks.empty()) {
|
|
fillHole( getXMin(), getXMax(), getYBottom(), islice%2 );
|
|
return;
|
|
}
|
|
|
|
list<Interval>::iterator ichunk = _chunks.begin();
|
|
list<Interval>::iterator ichunknext = ichunk;
|
|
++ichunknext;
|
|
|
|
// Hole before the first chunk.
|
|
if ((*ichunk).getVMin() > getXMin()) {
|
|
fillHole( getXMin(), (*ichunk).getVMin(), getYBottom(), (islice+getSpinSlice0())%2 );
|
|
}
|
|
|
|
for ( ; ichunknext != _chunks.end() ; ++ichunk, ++ichunknext ) {
|
|
fillHole( (*ichunk).getVMax(), (*ichunknext).getVMin(), getYBottom(), (islice+getSpinSlice0())%2 );
|
|
}
|
|
|
|
// Hole after the last chunk.
|
|
if ((*ichunk).getVMax() < getXMax()) {
|
|
fillHole( (*ichunk).getVMax(), getXMax(), getYBottom(), (islice+getSpinSlice0())%2 );
|
|
}
|
|
}
|
|
|
|
|
|
void Slice::fillHole ( DbU::Unit xmin, DbU::Unit xmax, DbU::Unit ybottom, size_t yspin )
|
|
{
|
|
Cell* feed = getEtesian()->getFeedCells().getBiggestFeed();
|
|
if (feed == NULL) {
|
|
cerr << Error("EtesianEngine: No feed has been registered, ignoring.") << endl;
|
|
return;
|
|
}
|
|
|
|
DbU::Unit feedWidth = feed->getAbutmentBox().getWidth();
|
|
DbU::Unit xtie = xmin;
|
|
|
|
while ( true ) {
|
|
if (xtie >= xmax) break;
|
|
if (xtie+feedWidth > xmax) {
|
|
// Feed is too big, try to find a smaller one.
|
|
int pitch = (int)((xmax-xtie) / getEtesian()->getPitch());
|
|
for ( ; pitch > 0 ; --pitch ) {
|
|
feed = getEtesian()->getFeedCells().getFeed( pitch );
|
|
feedWidth = feed->getAbutmentBox().getWidth();
|
|
if (feed != NULL) break;
|
|
}
|
|
if (feed == NULL) break;
|
|
}
|
|
|
|
Instance::create ( getEtesian()->getCell()
|
|
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
|
|
, feed
|
|
, getTransformation( feed->getAbutmentBox()
|
|
, xtie
|
|
, _ybottom
|
|
, (yspin)?Transformation::Orientation::MY
|
|
:Transformation::Orientation::ID
|
|
)
|
|
, Instance::PlacementStatus::PLACED
|
|
);
|
|
|
|
xtie += feedWidth;
|
|
}
|
|
}
|
|
|
|
|
|
string Slice::_getString () const
|
|
{
|
|
ostringstream os;
|
|
|
|
os << "<Slice " << " @" << DbU::getValueString(_ybottom) << " ";
|
|
list<Interval>::const_iterator ichunk = _chunks.begin();
|
|
for ( ; ichunk != _chunks.end() ; ++ichunk ) {
|
|
if (ichunk != _chunks.begin()) os << " ";
|
|
os << "[" << DbU::getValueString((*ichunk).getVMin())
|
|
<< " " << DbU::getValueString((*ichunk).getVMax()) << "]";
|
|
}
|
|
os << ">";
|
|
return os.str();
|
|
}
|
|
|
|
|
|
SliceHoles::SliceHoles ( EtesianEngine* etesian )
|
|
: _etesian (etesian)
|
|
, _cellAb (etesian->getCell()->getAbutmentBox())
|
|
, _sliceHeight(_etesian->getSliceHeight())
|
|
, _slices ()
|
|
{
|
|
size_t slicesNb = _cellAb.getHeight() / _sliceHeight;
|
|
for ( size_t islice=0 ; islice<slicesNb ; ++islice )
|
|
_slices.push_back( new Slice( this
|
|
, _cellAb.getYMin()+islice*_sliceHeight
|
|
, Interval(_cellAb.getXMin(),_cellAb.getXMax()) ) );
|
|
}
|
|
|
|
|
|
SliceHoles::~SliceHoles ()
|
|
{
|
|
for ( size_t islice=0 ; islice<_slices.size() ; ++islice )
|
|
delete _slices[islice];
|
|
}
|
|
|
|
|
|
inline EtesianEngine* SliceHoles::getEtesian () const { return _etesian; }
|
|
inline size_t SliceHoles::getSpinSlice0 () const { return _spinSlice0; }
|
|
inline void SliceHoles::setSpinSlice0 ( size_t spinSlice0 ) { _spinSlice0 = spinSlice0; }
|
|
|
|
|
|
void SliceHoles::merge ( const Box& bb )
|
|
{
|
|
if (bb.getYMin() < _cellAb.getYMin()) {
|
|
cerr << Warning("Attempt to merge instance outside the Cell abutment box.") << endl;
|
|
return;
|
|
}
|
|
|
|
size_t ibegin = (bb.getYMin()-_cellAb.getYMin()) / _sliceHeight;
|
|
size_t iend = (bb.getYMax()-_cellAb.getYMin()) / _sliceHeight;
|
|
|
|
for ( size_t islice=ibegin ; islice<iend ; ++islice ) {
|
|
_slices[islice]->merge( bb.getXMin(), bb.getXMax() );
|
|
}
|
|
}
|
|
|
|
|
|
void SliceHoles::addFeeds ()
|
|
{
|
|
for ( size_t islice=0 ; islice<_slices.size() ; islice++ )
|
|
_slices[islice]->addFeeds( islice );
|
|
}
|
|
|
|
|
|
} // End of anonymous namespace.
|
|
|
|
|
|
namespace Etesian {
|
|
|
|
|
|
using Hurricane::ForEachIterator;
|
|
using Hurricane::DataBase;
|
|
using Hurricane::UpdateSession;
|
|
using Hurricane::Occurrence;
|
|
|
|
|
|
size_t EtesianEngine::findYSpin ()
|
|
{
|
|
_ySpinSet = false;
|
|
_yspinSlice0 = 0;
|
|
|
|
Box topCellAb = getCell()->getAbutmentBox();
|
|
|
|
if (not topCellAb.isEmpty()) {
|
|
forEach ( Occurrence, ioccurrence, getCell()->getLeafInstanceOccurrences() )
|
|
{
|
|
Instance* instance = static_cast<Instance*>((*ioccurrence).getEntity());
|
|
Cell* masterCell = instance->getMasterCell();
|
|
Box instanceAb = masterCell->getAbutmentBox();
|
|
Transformation instanceTransf = instance->getTransformation();
|
|
|
|
(*ioccurrence).getPath().getTransformation().applyOn( instanceTransf );
|
|
instanceTransf.applyOn( instanceAb );
|
|
|
|
if (not topCellAb.contains(instanceAb)) continue;
|
|
|
|
_ySpinSet = true;
|
|
|
|
int islice = (instanceAb.getYMin() - getCell()->getAbutmentBox().getYMin()) / getSliceHeight();
|
|
|
|
switch ( instanceTransf.getOrientation() ) {
|
|
case Transformation::Orientation::ID:
|
|
case Transformation::Orientation::MX:
|
|
_yspinSlice0 = (islice % 2);
|
|
break;
|
|
case Transformation::Orientation::R2:
|
|
case Transformation::Orientation::MY:
|
|
_yspinSlice0 = ((islice+1) % 2);
|
|
break;
|
|
case Transformation::Orientation::R1:
|
|
case Transformation::Orientation::R3:
|
|
case Transformation::Orientation::XR:
|
|
case Transformation::Orientation::YR:
|
|
cerr << Warning( "Instance %s has invalid transformation %s."
|
|
, getString(instance->getName()).c_str()
|
|
, getString(instanceTransf.getOrientation()).c_str()
|
|
) << endl;
|
|
_ySpinSet = false;
|
|
break;
|
|
}
|
|
|
|
if (_ySpinSet) break;
|
|
}
|
|
}
|
|
|
|
return _yspinSlice0;
|
|
}
|
|
|
|
|
|
void EtesianEngine::addFeeds ()
|
|
{
|
|
if (not getFeedCells().feedNumbers()) {
|
|
cerr << Warning( "No feed cells available, skipping." ) << endl;
|
|
return;
|
|
}
|
|
|
|
UpdateSession::open();
|
|
|
|
SliceHoles sliceHoles ( this );
|
|
Box topCellAb = getCell()->getAbutmentBox();
|
|
|
|
sliceHoles.setSpinSlice0( _yspinSlice0 );
|
|
|
|
forEach ( Occurrence, ioccurrence, getCell()->getLeafInstanceOccurrences() )
|
|
{
|
|
Instance* instance = static_cast<Instance*>((*ioccurrence).getEntity());
|
|
Cell* masterCell = instance->getMasterCell();
|
|
|
|
if (CatalogExtension::isFeed(masterCell)) {
|
|
cerr << Warning( "Feed instance %s already present."
|
|
, getString(instance->getName()).c_str() ) << endl;
|
|
}
|
|
|
|
Box instanceAb = masterCell->getAbutmentBox();
|
|
|
|
Transformation instanceTransf = instance->getTransformation();
|
|
(*ioccurrence).getPath().getTransformation().applyOn( instanceTransf );
|
|
instanceTransf.applyOn( instanceAb );
|
|
|
|
if (not topCellAb.contains(instanceAb)) {
|
|
cerr << Warning( "Instance %s is not fully enclosed in the top cell."
|
|
, getString(instance->getName()).c_str() ) << endl;
|
|
continue;
|
|
}
|
|
|
|
sliceHoles.merge( instanceAb );
|
|
}
|
|
|
|
sliceHoles.addFeeds();
|
|
|
|
UpdateSession::close();
|
|
|
|
if (_viewer) _viewer->getCellWidget()->refresh();
|
|
}
|
|
|
|
|
|
} // Kite namespace.
|