2010-07-12 10:19:31 -05:00
|
|
|
// -*- C++ -*-
|
|
|
|
//
|
|
|
|
// This file is part of the Coriolis Software.
|
2018-01-06 10:55:44 -06:00
|
|
|
// Copyright (c) UPMC 2008-2018, All Rights Reserved
|
2010-07-12 10:19:31 -05:00
|
|
|
//
|
2014-10-01 17:42:59 -05:00
|
|
|
// +-----------------------------------------------------------------+
|
2010-07-12 10:19:31 -05:00
|
|
|
// | 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" |
|
2014-10-01 17:42:59 -05:00
|
|
|
// +-----------------------------------------------------------------+
|
2010-07-12 10:19:31 -05:00
|
|
|
|
|
|
|
|
2014-10-01 17:42:59 -05:00
|
|
|
#include "hurricane/UpdateSession.h"
|
|
|
|
#include "crlcore/ToolBox.h"
|
|
|
|
#include "mauka/MaukaEngine.h"
|
2010-07-12 10:19:31 -05:00
|
|
|
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
Clarify semantic of flatten Collections (walkthrough).
In the Cell/Instance hierarchy, the "terminal" and "leaf cell" concepts
where not clearly defined and partially overlapping. Now, "Terminal" is
the refer to the physical hierarchy (layout) and "TerminalNetlist" to
the logical hierarchy (netlist). The logical hierarchy can be less deep
than the physical one thanks to a Cell dedicated cell flags. Collections
related to the physical hierarchy keep their old names, the one related
to the logical hierarchy are renamed from "Leaf" to "TerminalNetlist".
The name "Leaf" was too ambiguous (leaf for *what* hierarchy).
* Change: In Hurricane::Device, set the "TerminalNetlist" flag once and
for all. No need set it in all the derived classes again.
* New: In Hurricane::MultiCapacitor, added new parameter "dummy" to
create dummies around the capacity matrix.
* Change: In Hurricane::Cell, remove "Leaf" related methods, replace
them by "TerminalNetlist" one, especially Collections. Now we have
two clear sets of Collections to walkthough the layout or the
netlist.
Change the "Terminal" flag into "TerminalNetlist".
* Change: In Hurricane::CellCollections, rename "Leaf" into
"TerminalNetlist" collections and apply the new semantic to the
locators.
* Change: In Hurricane::DataBase, Leaf to TerminalInstance renaming.
* Change: In Hurricane::DeepNet, Leaf to TerminalInstance renaming.
* Change: In Hurricane::HyperNet, Leaf to TerminalInstance renaming.
* Change: In Hurricane::Instance, Leaf to TerminalInstance renaming.
* Change: In Hurricane::Viewer::HierarchyInformations, Leaf to
TerminalInstance renaming.
* Change: In CRL::AllianceFramework, Leaf to TerminalInstance renaming.
* Change: In CRL::Catalog, Leaf to TerminalInstance renaming.
* Change: In CRL::ApParser, Leaf to TerminalInstance renaming.
* Change: In EtesianEngine::AddFeeds, Leaf to TerminalInstance renaming.
* Bug: In EtesianEngine::resetPlacement, move there the loop over
non terminal netlist instances to flag fully placed sub-blocks
as terminal for the netlist. Only then remove the feed cells
from unplaced instances. Previously, the feed cells where stripped
even from already placed instances.
* Change: In Katana, Leaf to TerminalInstance renaming.
* Bug: In Bora::PyDSlicingNode, allow the range parameter to be the
Python None object when we do not want to pass one but need to
have it as positional parameter.
* Change: In Cumulus/clocktree/ClockTree.py, Leaf to TerminalInstance
renaming.
2020-03-10 06:10:53 -05:00
|
|
|
forEach ( Occurrence, ioccurrence, getCell()->getTerminalNetlistInstanceOccurrences() )
|
2010-07-12 10:19:31 -05:00
|
|
|
{
|
|
|
|
surfaceFeeds.addInstanceOccurrence ( *ioccurrence );
|
|
|
|
}
|
|
|
|
surfaceFeeds.insertFeeds ();
|
|
|
|
|
|
|
|
UpdateSession::close ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // End of Mauka namespace.
|