coriolis/mauka/src/InsertFeeds.cpp

329 lines
10 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 |
// | M a u k a - P l a c e r |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@asim.lip6.fr |
// | =============================================================== |
// | C++ Module : "./InsertFeeds.cpp" |
// +-----------------------------------------------------------------+
#include "hurricane/UpdateSession.h"
#include "crlcore/ToolBox.h"
#include "mauka/MaukaEngine.h"
namespace {
using namespace std;
using namespace Mauka;
using namespace Hurricane;
using namespace CRL;
// -------------------------------------------------------------------
// Class : "::RowFeed"
class SurfaceFeeds;
class RowFeed {
public:
RowFeed ( SurfaceFeeds*, const Box& bb );
inline const Box& getBox () const;
inline SurfaceFeeds* getSurfaceFeeds ();
inline MaukaEngine* getMauka ();
inline void setOrientation ( Transformation::Orientation );
void mergeInstanceSpan ( DbU::Unit source, DbU::Unit target );
void insertTieChunk ( DbU::Unit xmin
, DbU::Unit xmax
, DbU::Unit y
, const Transformation::Orientation& );
void insertFeeds ();
private:
SurfaceFeeds* _surface;
Box _boundingBox;
Transformation::Orientation _orientation;
list<Interval> _instanceSpans;
};
// -------------------------------------------------------------------
// Class : "::SurfaceFeeds"
class SurfaceFeeds {
public:
SurfaceFeeds ( MaukaEngine* );
~SurfaceFeeds ();
inline MaukaEngine* getMauka ();
void addInstanceOccurrence ( Occurrence );
void insertFeeds ();
private:
void _orientRows ( Transformation::Orientation );
private:
MaukaEngine* _mauka;
Box _area;
vector<RowFeed*> _rowFeeds;
bool _oriented;
};
// -------------------------------------------------------------------
// Class Implantation : "::RowFeed"
RowFeed::RowFeed ( SurfaceFeeds* surface, const Box& bb )
: _surface (surface)
, _boundingBox (bb)
, _orientation (Transformation::Orientation::ID)
, _instanceSpans()
{ }
inline const Box& RowFeed::getBox () const { return _boundingBox; }
inline MaukaEngine* RowFeed::getMauka () { return _surface->getMauka(); }
inline void RowFeed::setOrientation ( Transformation::Orientation orientation )
{ _orientation = orientation; }
void RowFeed::mergeInstanceSpan ( DbU::Unit source, DbU::Unit target )
{
Interval spanMerge ( source, target );
list<Interval>::iterator imerge = _instanceSpans.end();
list<Interval>::iterator ispan = _instanceSpans.begin();
while ( ispan != _instanceSpans.end() ) {
if ( spanMerge.getVMax() < (*ispan).getVMin() ) break;
if ( spanMerge.intersect(*ispan) ) {
if ( imerge == _instanceSpans.end() ) {
imerge = ispan;
(*imerge).merge ( spanMerge );
} else {
(*imerge).merge ( *ispan );
ispan = _instanceSpans.erase ( ispan );
continue;
}
}
ispan++;
}
if ( imerge == _instanceSpans.end() ) {
_instanceSpans.insert ( ispan, spanMerge );
}
}
void RowFeed::insertTieChunk ( DbU::Unit xmin
, DbU::Unit xmax
, DbU::Unit y
, const Transformation::Orientation& orientation )
{
Cell* feed = getMauka()->getFeedCells().getBiggestFeed();
if ( feed == NULL ) {
cerr << Error("No feed has been registered, ignoring.") << endl;
}
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) / getMauka()->getPitch());
for ( ; pitch > 0 ; --pitch ) {
feed = getMauka()->getFeedCells().getFeed ( pitch );
feedWidth = feed->getAbutmentBox().getWidth();
if ( feed != NULL ) break;
}
if ( feed == NULL ) break;
}
Instance::create ( getMauka()->getCell()
, getMauka()->getFeedCells().getNewFeedName().c_str()
, feed
, getTransformation(feed->getAbutmentBox(),xtie,y,orientation)
, Instance::PlacementStatus::PLACED
);
xtie += feedWidth;
}
}
void RowFeed::insertFeeds ()
{
list<Interval>::iterator ispan = _instanceSpans.begin();
DbU::Unit minFeed = _boundingBox.getXMin();
DbU::Unit maxFeed;
if ( ispan == _instanceSpans.end() ) {
maxFeed = _boundingBox.getXMax();
insertTieChunk ( minFeed, maxFeed, _boundingBox.getYMin(), _orientation );
return;
}
maxFeed = (*ispan).getVMin();
insertTieChunk ( minFeed, maxFeed, _boundingBox.getYMin(), _orientation );
while ( ispan != _instanceSpans.end() ) {
minFeed = (*ispan).getVMax();
if ( ++ispan != _instanceSpans.end() )
maxFeed = (*ispan).getVMin();
else
maxFeed = _boundingBox.getXMax();
insertTieChunk ( minFeed, maxFeed, _boundingBox.getYMin(), _orientation );
}
}
// -------------------------------------------------------------------
// Class Implantation : "::SurfaceFeeds"
SurfaceFeeds::SurfaceFeeds ( MaukaEngine* mauka )
: _mauka (mauka)
, _area (mauka->getCell()->getAbutmentBox())
, _rowFeeds()
, _oriented(false)
{
DbU::Unit sliceHeight = _mauka->getSliceHeight();
size_t rowsNb = _area.getHeight() / sliceHeight;
_rowFeeds.reserve ( rowsNb );
for ( size_t irow=0 ; irow<rowsNb ; ++irow )
_rowFeeds.push_back ( new RowFeed(this,Box(_area.getXMin()
, irow * sliceHeight
,_area.getXMax()
,(irow+1) * sliceHeight )) );
}
SurfaceFeeds::~SurfaceFeeds ()
{
for ( size_t irow=0 ; irow<_rowFeeds.size() ; ++irow )
delete _rowFeeds[irow];
}
inline MaukaEngine* SurfaceFeeds::getMauka () { return _mauka; }
void SurfaceFeeds::addInstanceOccurrence ( Occurrence occurrence )
{
Instance* instance = dynamic_cast<Instance*>(occurrence.getEntity());
if ( instance == NULL ) {
cerr << Error("Entity of occurrence %s is not an instance."
,getString(occurrence).c_str()) << endl;
return;
}
DbU::Unit sliceHeight = _mauka->getSliceHeight();
Box masterABox = instance->getAbutmentBox();
Transformation transformation = occurrence.getPath().getTransformation();
transformation.applyOn(masterABox);
Transformation::Orientation orientation = occurrence.getPath().getTransformation().getOrientation();
int rowStart = (masterABox.getYMin() - _area.getYMin()) / sliceHeight;
int rowStop = (masterABox.getYMax() - _area.getYMin()) / sliceHeight;
if ( (rowStart < 0) or (rowStop > (int)_rowFeeds.size()) ) {
cerr << Error("Instance %s (AB:%s) is outside the placement area."
,getString(occurrence).c_str()
,getString(masterABox).c_str()
) << endl;
return;
}
if ( not _oriented ) {
size_t instanceRowMY = 0;
switch ( orientation ) {
case Transformation::Orientation::ID: instanceRowMY = 0; break;
default:
case Transformation::Orientation::MY: instanceRowMY = 1; break;
}
Transformation::Orientation rowZeroOrientation = Transformation::Orientation::ID;
switch ( (rowStart+instanceRowMY) % 2 ) {
case 0: orientation = Transformation::Orientation::ID; break;
case 1: orientation = Transformation::Orientation::MY; break;
}
_orientRows ( rowZeroOrientation );
}
for ( size_t irow = rowStart ; (int)irow<rowStop ; ++irow ) {
_rowFeeds[irow]->mergeInstanceSpan ( masterABox.getXMin(), masterABox.getXMax() );
}
}
void SurfaceFeeds::insertFeeds ()
{
for ( size_t irow=0 ; irow<_rowFeeds.size() ; ++irow )
_rowFeeds[irow]->insertFeeds ();
}
void SurfaceFeeds::_orientRows ( Transformation::Orientation rowZeroOrientation )
{
if ( _oriented ) return;
_oriented = true;
size_t rowZeroMY = 0;
switch ( rowZeroOrientation ) {
case Transformation::Orientation::ID: rowZeroMY = 0; break;
default:
case Transformation::Orientation::MY: rowZeroMY = 1; break;
}
for ( size_t irow=0 ; irow<_rowFeeds.size() ; ++irow ) {
Transformation::Orientation orientation = Transformation::Orientation::ID;
switch ( (irow+rowZeroMY) % 2 ) {
case 0: orientation = Transformation::Orientation::ID; break;
case 1: orientation = Transformation::Orientation::MY; break;
}
_rowFeeds[irow]->setOrientation(orientation);
}
}
} // End of anonymous namespace.
namespace Mauka {
using Hurricane::UpdateSession;
void MaukaEngine::insertFeeds ()
{
UpdateSession::open ();
SurfaceFeeds surfaceFeeds ( this );
forEach ( Occurrence, ioccurrence, getCell()->getLeafInstanceOccurrences() )
{
surfaceFeeds.addInstanceOccurrence ( *ioccurrence );
}
surfaceFeeds.insertFeeds ();
UpdateSession::close ();
}
} // End of Mauka namespace.