coriolis/mauka/src/Surface.cpp

858 lines
32 KiB
C++
Raw Normal View History

// This file is part of the Coriolis Project.
// Copyright (C) Laboratoire LIP6 - Departement ASIM
// Universite Pierre et Marie Curie
//
// Main contributors :
// Christophe Alexandre <Christophe.Alexandre@lip6.fr>
// Sophie Belloeil <Sophie.Belloeil@lip6.fr>
// Hugo Cl<43>ment <Hugo.Clement@lip6.fr>
// Jean-Paul Chaput <Jean-Paul.Chaput@lip6.fr>
// Damien Dupuis <Damien.Dupuis@lip6.fr>
// Christian Masson <Christian.Masson@lip6.fr>
// Marek Sroka <Marek.Sroka@lip6.fr>
//
// The Coriolis Project is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// The Coriolis Project is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the Coriolis Project; if not, write to the Free Software
// Foundation, inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//
// License-Tag
//
// Date : 29/01/2004
// Author : Christophe Alexandre <Christophe.Alexandre@lip6.fr>
//
// Authors-Tag
#include "hurricane/Warning.h"
#include "hurricane/Cell.h"
#include "nimbus/NimbusEngine.h"
#include "mauka/MaukaEngine.h"
#include "mauka/SimAnnealingPlacer.h"
#include "mauka/SubRow.h"
#include "mauka/Row.h"
#include "mauka/Surface.h"
namespace {
using namespace std;
using namespace Hurricane;
using namespace Mauka;
void VerifyInstanceQuadtreeInsertion(Cell *cell)
{
cerr << "VerifyInstanceQuadtreeInsertion" << endl;
for_each_instance(instance, cell->getInstances())
{
if (!instance->isMaterialized())
{
Cell* masterCell = instance->getMasterCell();
cerr << tab << instance << " of " << masterCell << " is not materialized..." << endl;
tab++;
VerifyInstanceQuadtreeInsertion(masterCell);
tab--;
}
end_for;
}
}
void DisplayInstanceOccurrence(Occurrence& instanceOccurrence)
{
cerr << instanceOccurrence << " " << instanceOccurrence.getBoundingBox() << endl;
Instance* instance = static_cast<Instance*>(instanceOccurrence.getEntity());
Path path = instanceOccurrence.getPath();
cerr << path.getTransformation() << endl;
cerr << instance->getTransformation() << endl;
while (!path.isEmpty())
{
cerr << path.getTailInstance() << " " << path.getTailInstance()->getTransformation() << endl;
cerr << path.getTailInstance()->getMasterCell() << endl;
cerr << path.getTailInstance()->getMasterCell()->getAbutmentBox() << endl;
cerr << path.getTailInstance()->getMasterCell()->getBoundingBox() << endl;
cerr << path.getTailInstance()->getAbutmentBox() << endl;
cerr << path.getTailInstance()->getBoundingBox() << endl;
path = path.getHeadPath();
}
}
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
void DisplayNonTerminalNetlistInstances(Cell* cell, Box area)
{
ltrace(100) << "display of " << cell << " in " << area << endl;
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
for_each_instance(instance, cell->getNonTerminalNetlistInstancesUnder(area))
{
ltrace(100) << instance << " " << instance->getBoundingBox() << endl;
Cell* masterCell = instance->getMasterCell();
ltracein(20);
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
DisplayNonTerminalNetlistInstances(masterCell, area);
ltraceout(20);
end_for;
}
}
} // End of anonymous namespace.
namespace Mauka {
using Nimbus::NimbusEngine;
using Nimbus::GCellLocator;
Surface::Surface(MaukaEngine* mauka, const Box& placementbox) :
Inherit(mauka->getCell(), placementbox),
_mauka(mauka),
_rowVector(),
_rowYMax(),
_rowYMinInv(),
_rowZeroOrientation(false),
_margin(0.0),
_binWidthMax(0),
_binWidthMin(0),
_searchWidth(0),
_searchHeight(0)
{}
Surface* Surface::create(MaukaEngine* mauka, const Box& placementbox) {
if (!mauka) {
throw Error("Can't create " + _TName("Surface") + " : empty mauka");
}
if (!mauka->getCell()) {
throw Error("Can't create " + _TName("Surface") + " : empty cell on mauka");
}
Surface* surface = new Surface(mauka, placementbox);
surface->_postCreate();
return surface;
}
namespace {
void PlacementVerification(Cell* cell, Box& box) {
set<Occurrence> occurrenceSet;
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
for_each_occurrence(occurrence, cell->getTerminalNetlistInstanceOccurrencesUnder(box)) {
occurrenceSet.insert(occurrence);
end_for;
}
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
// for_each_occurrence(occurrence, cell->getTerminalNetlistInstanceOccurrences()) {
// if (occurrenceSet.find(occurrence) == occurrenceSet.end()) {
// cerr << occurrence << ":" << occurrence.getBoundingBox() << endl;
// throw Error("occurrence is badly placed");
// }
// end_for;
// }
}
typedef list<Occurrence> InstanceOccurrencesList;
class PlacementProblem {
public: GCell* _gcell;
public: InstanceOccurrencesList _fixedInstanceOccurrenceList;
public: MaukaEngine::UVector _toPlaceInstanceOccurrencesUVector;
public: Surface::SubRowList _subRowList;
PlacementProblem(GCell* gcell)
: _gcell(gcell)
, _fixedInstanceOccurrenceList()
, _toPlaceInstanceOccurrencesUVector()
, _subRowList()
{}
};
typedef list<PlacementProblem*> PlacementProblemList;
}
void Surface::_postCreate ()
{
typedef set<Occurrence> OccurrenceSet;
Inherit::_postCreate();
bool partitionned = false;
NimbusEngine* nimbus = NULL;
if (_box.isEmpty()) {
nimbus = NimbusEngine::get ( getCell() );
if (nimbus == NULL) {
throw Error("Can't create Mauka::Surface, no Box and no Nimbus");
}
_box = nimbus->getGrid()->getRoot()->getBox();
partitionned = (nimbus->getDepth() > 1);
if ( partitionned )
cmess2 << " - Design is partionned (depth:" << nimbus->getDepth() << ")" << endl;
}
PlacementVerification ( getCell(), _box );
DbU::Unit sliceHeight = _mauka->getSliceHeight();
DbU::Unit pitch = _mauka->getPitch();
if ( _box.isEmpty() or _box.isPonctual() or _box.isFlat())
throw Error("Wrong Box for Area: %s",getString(_box).c_str());
if ( getHeight() % sliceHeight )
throw Error("Box Height %s must be a multiple of Slice Height %s"
,DbU::getValueString(getHeight()).c_str()
,DbU::getValueString(sliceHeight).c_str());
DbU::Unit instanceToPlaceWidthMax = 0;
double instanceToPlaceWidthSum = 0.0;
for ( unsigned int id = 0; id < _mauka->_instanceWidths.size(); ++id ) {
DbU::Unit instanceWidth = _mauka->_instanceWidths[id];
instanceToPlaceWidthSum += (double)instanceWidth;
if ( instanceWidth % pitch )
throw Error("Width of %s (%s) is not a multiple of pitch (%s)."
,getString(_mauka->_instanceOccurrencesVector[id]).c_str()
,DbU::getValueString(instanceWidth).c_str()
,DbU::getValueString(pitch).c_str());
if (instanceWidth > instanceToPlaceWidthMax)
instanceToPlaceWidthMax = instanceWidth;
}
// _binWidthMax = DbU::lambda
// ((unsigned)( 3.0 * DbU::getLambda(instanceToPlaceWidthMax) / DbU::getLambda(pitch))
// * DbU::getLambda(pitch));
// _binWidthMin = DbU::lambda
// ((unsigned)(DbU::getLambda(_binWidthMax) / (DbU::getLambda(pitch) * 2)) * DbU::getLambda(pitch));
_binWidthMax = 2 * (instanceToPlaceWidthMax / pitch) * pitch;
_binWidthMin = (_binWidthMax / (pitch * 2)) * pitch;
// cerr << "_binWidthMax:" << DbU::getValueString(_binWidthMax) << endl;
// cerr << "_binWidthMin:" << DbU::getValueString(_binWidthMin) << endl;
double surfaceTotalWidth = 0.0;
PlacementProblemList placementProblemList;
OccurrenceSet verifyInstanceOccurrencesSet;
if ( nimbus ) {
forEach ( GCell*, igcell, nimbus->getPlacementLeaves() ) {
PlacementProblem* placementProblem = new PlacementProblem(*igcell);
placementProblemList.push_back(placementProblem);
InstanceOccurrencesList toPlaceInstanceOccurrencesList;
// Search for preplaced leaf instances
forEach ( Occurrence
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
, ioccurrence, _mauka->getCell()->getTerminalNetlistInstanceOccurrencesUnder(igcell->getBox()) ) {
Instance* instance = static_cast<Instance*>((*ioccurrence).getEntity());
if ( instance->isFixed() ) {
placementProblem->_fixedInstanceOccurrenceList.push_back(*ioccurrence);
} else {
MaukaEngine::InstanceOccurrencesMap::const_iterator
iomit = _mauka->_instanceOccurrencesMap.find(*ioccurrence);
if ( iomit == _mauka->_instanceOccurrencesMap.end() )
throw Error("Instance occurrence unexpectedly appeared:\n"
" %s",getString(*ioccurrence).c_str());
placementProblem->_toPlaceInstanceOccurrencesUVector.push_back(iomit->second);
verifyInstanceOccurrencesSet.insert(*ioccurrence);
}
}
// Special case: no Nimbus run, Instances are *not* in the quadtree yet.
if ( not partitionned ) {
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, _mauka->getCell()->getTerminalNetlistInstanceOccurrences() ) {
Instance* instance = static_cast<Instance*>((*ioccurrence).getEntity());
if ( instance->isFixed() ) continue;
MaukaEngine::InstanceOccurrencesMap::const_iterator iomit
= _mauka->_instanceOccurrencesMap.find(*ioccurrence);
if (iomit == _mauka->_instanceOccurrencesMap.end())
throw Error("Instance occurrence unexpectedly appeared:\n"
" %s",getString(*ioccurrence).c_str());
placementProblem->_toPlaceInstanceOccurrencesUVector.push_back(iomit->second);
verifyInstanceOccurrencesSet.insert(*ioccurrence);
}
}
DbU::Unit searchWidth = DbU::lambda(_mauka->getSearchRatio() * DbU::getLambda(igcell->getWidth()));
if (_searchWidth < searchWidth) _searchWidth = searchWidth;
DbU::Unit searchHeight = DbU::lambda(_mauka->getSearchRatio() * DbU::getLambda(igcell->getHeight()));
if (_searchHeight < searchHeight) _searchHeight = searchHeight;
}
for ( PlacementProblemList::iterator pplit = placementProblemList.begin();
pplit != placementProblemList.end(); pplit++) {
PlacementProblem* placementProblem = *pplit;
GCell* gcell = placementProblem->_gcell;
if ( placementProblem->_fixedInstanceOccurrenceList.size() != 0 ) {
bool rowZeroOrientation = false;
int width = (unsigned)(gcell->getWidth () / pitch); // Number of X pitch
int height = (unsigned)(gcell->getHeight() / sliceHeight); // Number of Y slices
MaukaEngine::PrePlaceTab prePlaceTab(height, MaukaEngine::PrePlaceRow(width, false));
InstanceOccurrencesList::const_iterator iolit
= placementProblem->_fixedInstanceOccurrenceList.begin();
// Find the orientation of the first row.
Instance* refInstance = static_cast<Instance*>(iolit->getEntity());
Box refAbutmentBox = refInstance->getAbutmentBox();
Transformation refTransformation = refInstance->getTransformation();
iolit->getPath().getTransformation().applyOn(refAbutmentBox);
iolit->getPath().getTransformation().applyOn(refTransformation);
Box preplacedBox = gcell->getIntersection(refAbutmentBox);
// Position en y ramene au slice
int refInsYPos = (int)((preplacedBox.getYMin() - gcell->getYMin()) / sliceHeight);
// Hauteur ramene a la hauteur du slice
int refInsSliceHeight = (int)(preplacedBox.getHeight() / sliceHeight);
Transformation::Orientation orientation = refTransformation.getOrientation();
if ( refInsYPos % 2 == 0 ) {
if ( (refInsSliceHeight % 2 == 0)
or (orientation == Transformation::Orientation::ID)
or (orientation == Transformation::Orientation::MX))
rowZeroOrientation = false;
else
rowZeroOrientation = true;
} else {
if ( (refInsSliceHeight % 2 == 0)
or (orientation == Transformation::Orientation::ID)
or (orientation == Transformation::Orientation::MX))
rowZeroOrientation = true;
else
rowZeroOrientation = false;
}
// Tests for each Instance.
for ( InstanceOccurrencesList::iterator iolit = placementProblem->_fixedInstanceOccurrenceList.begin();
iolit != placementProblem->_fixedInstanceOccurrenceList.end(); iolit++ ) {
Instance* instance = static_cast<Instance*>(iolit->getEntity());
Box instanceAbutmentBox = instance->getAbutmentBox();
iolit->getPath().getTransformation().applyOn(instanceAbutmentBox);
Box preplacedBox = gcell->getIntersection(instanceAbutmentBox);
DbU::Unit insWidth = preplacedBox.getWidth();
DbU::Unit insHeight = preplacedBox.getHeight();
int insPitchWidth = (int)(insWidth / pitch); // Largeur ramene au pitch
int insSliceHeight = (int)(insHeight / sliceHeight); // Hauteur ramene a la hauteur du slice
int ypos = (int)((preplacedBox.getYMin() - gcell->getYMin()) / sliceHeight); // Position en Y ramene au slice
int xpos = (int)((preplacedBox.getXMin() - gcell->getXMin()) / pitch); // Position en X ramene au pitch
for ( int yit = ypos; yit < ypos + insSliceHeight; ++yit ) {
for ( int xit = xpos; xit < xpos + insPitchWidth; ++xit ) {
if ( (xit > width - 1) or (yit > height - 1) or (xit < 0) or (yit < 0) )
throw Error("%s is out of the abutment box"
,getString(*iolit).c_str());
if ( prePlaceTab[yit][xit] == false )
prePlaceTab[yit][xit] = true;
else
throw Error("%s is badly placed. There is another instance at it's position"
,getString(*iolit).c_str());
}
}
}
bool rowOrientation = rowZeroOrientation;
for ( int y = 0; y < (int)prePlaceTab.size(); ++y ) {
int x = 0;
while ( x < (int)prePlaceTab[y].size() ) {
while ( (x < (int)prePlaceTab[y].size()) and (prePlaceTab[y][x] == true) ) ++x;
DbU::Unit subRowXMin = gcell->getXMin() + x * pitch;
if (x >= (int)prePlaceTab[y].size()) break;
while ( (x < (int)prePlaceTab[y].size()) and (prePlaceTab[y][x] == false) ) ++x;
DbU::Unit subRowXMax = gcell->getXMin() + x * pitch;
if ( subRowXMax - subRowXMin > _binWidthMin ) {
SubRow* subRow = SubRow::create ( getCell()
, this
, Box(subRowXMin, gcell->getYMin() + y * sliceHeight
,subRowXMax, gcell->getYMin() + (y+1) * sliceHeight)
, rowOrientation );
placementProblem->_subRowList.push_back(subRow);
}
}
rowOrientation = not rowOrientation;
}
} else {
bool rowOrientation = false;
for ( DbU::Unit ymin = gcell->getYMin()
; ymin <= gcell->getYMax() - sliceHeight
; ymin += sliceHeight ) {
SubRow* subRow = SubRow::create ( getCell()
, this
, Box(gcell->getXMin(), ymin
,gcell->getXMax(), ymin + sliceHeight)
, rowOrientation );
placementProblem->_subRowList.push_back(subRow);
rowOrientation = not rowOrientation;
}
}
}
} else {
PlacementProblem* placementProblem = new PlacementProblem(NULL);
_searchHeight = getHeight();
_searchWidth = getWidth();
bool rowOrientation = false;
unsigned int nRows = getHeight() / sliceHeight;
surfaceTotalWidth = ((double)getWidth()) * nRows;
for ( DbU::Unit ymin = getYMin(); ymin <= getYMax() - sliceHeight; ymin += sliceHeight ) {
SubRow* subRow = SubRow::create ( getCell()
, this
, Box(getXMin(), ymin,getXMax(), ymin + sliceHeight)
, rowOrientation );
placementProblem->_subRowList.push_back(subRow);
rowOrientation = not rowOrientation;
}
for ( unsigned int id=0; id < _mauka->_instanceOccurrencesVector.size(); ++id ) {
placementProblem->_toPlaceInstanceOccurrencesUVector.push_back(id);
}
throw Error("MaukaEngine needs NimbusEngine");
}
_computeCapacity();
linefill output (" ",cmess2);
for (PlacementProblemList::iterator pplit = placementProblemList.begin();
pplit != placementProblemList.end(); pplit++) {
//cmess2 << " - Initial placement of " << (*pplit)->_gcell->getBox() << endl;
output << (*pplit)->_gcell->getBox();
_DisplayInstances((*pplit)->_toPlaceInstanceOccurrencesUVector, (*pplit)->_subRowList);
delete *pplit;
}
output << endl;
placementProblemList.clear ();
if ( verifyInstanceOccurrencesSet.size() != _mauka->_instanceOccurrencesVector.size() ) {
cerr << Error("There are %d Instances not taken into account"
,(_mauka->_instanceOccurrencesVector.size() - verifyInstanceOccurrencesSet.size())) << endl;
VerifyInstanceQuadtreeInsertion(_mauka->getCell());
for ( MaukaEngine::InstanceOccurrencesVector::iterator iovit = _mauka->_instanceOccurrencesVector.begin();
iovit != _mauka->_instanceOccurrencesVector.end(); iovit++ ) {
OccurrenceSet::iterator osit = verifyInstanceOccurrencesSet.find(*iovit);
if ( osit == verifyInstanceOccurrencesSet.end() ) {
cerr << " o Problem with " << *iovit << endl;
DisplayInstanceOccurrence ( *iovit );
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
DisplayNonTerminalNetlistInstances ( _mauka->getCell(), iovit->getBoundingBox() );
return;
}
}
throw Error("There are %d Instances not taken into account"
,(_mauka->_instanceOccurrencesVector.size() - verifyInstanceOccurrencesSet.size()));
}
for ( RowVector::const_iterator rvit = _rowVector.begin(); rvit != _rowVector.end(); rvit++ ) {
surfaceTotalWidth += (double)((*rvit)->getSubRowsWidth());
}
_computeRowsAndSubRows();
_margin = 1.0 - instanceToPlaceWidthSum / surfaceTotalWidth;
if ( _margin < 0.0 ) {
throw Error("There is not enough free space to place the circuit %s < %s"
,DbU::getValueString(surfaceTotalWidth).c_str()
,DbU::getValueString(instanceToPlaceWidthSum).c_str()
);
}
if (_margin < 0.15)
cerr << Warning("Low margin %f, may not be able to complete successfully",_margin) << endl;
_computeCapacity();
}
void Surface::_preDestroy()
{
Inherit::_preDestroy();
for (RowVector::const_iterator rvit = _rowVector.begin();
rvit != _rowVector.end();
rvit++)
(*rvit)->destroy();
_rowVector.clear();
}
void Surface::_computeCapacity()
{
for (RowVector::const_iterator rvit = _rowVector.begin();
rvit != _rowVector.end();
rvit++)
(*rvit)->_computeCapacity(_margin);
}
namespace {
struct RowSortByY
{
bool operator()(const Container* row1, const Container* row2) const
{
return row1->getYMin() < row2->getYMin();
}
};
}
Row* Surface::InsertSubRowInRow(SubRow* subrow, bool orientation)
{
Row* row = NULL;
if (_rowVector.size() == 0)
{
row = Row::create(getCell(), this, subrow->getBox(), orientation);
_rowVector.push_back(row);
}
else
{
RowVector::iterator rvit = lower_bound(_rowVector.begin(), _rowVector.end(), subrow, RowSortByY());
if (rvit == _rowVector.end())
{
row = Row::create(getCell(), this, subrow->getBox(), orientation);
_rowVector.push_back(row);
}
else if ((*rvit)->getYMin() == subrow->getYMin())
{
row = *rvit;
if (row->_orientation != orientation)
{
cerr << "PROBLEM in " << row << " orientation with " << subrow << endl;
}
//assert(row->_orientation == orientation);
}
else
{
row = Row::create(getCell(), this, subrow->getBox(), orientation);
_rowVector.insert(rvit, row);
}
}
row->_InsertSubRow(subrow);
return row;
}
void Surface::_computeRowsAndSubRows()
{
_rowYMax.clear();
_rowYMinInv.clear();
for (unsigned i = 0; i < _rowVector.size(); i++)
{
Row* row = _rowVector[i];
_rowYMax[row->getYMax()] = i;
_rowYMinInv[row->getYMin()] = i;
row->_computeSubRows();
}
}
Bin* Surface::getBinInSurface(Bin* srcbin, double dist)
{
Point srcPos = srcbin->getCenter();
DbU::Unit lowerY = srcPos.getY() - DbU::lambda((dist * DbU::getLambda(_searchHeight)));
if (lowerY < getYMin())
lowerY = getYMin();
DbU::Unit upperY = srcPos.getY() + DbU::lambda((dist * DbU::getLambda(_searchHeight)));
if (upperY > getYMax())
upperY = getYMax();
RowYMax::iterator rinf = _rowYMax.upper_bound(lowerY);
RowYMinInv::iterator rsup = _rowYMinInv.upper_bound(upperY);
unsigned randidx = rinf->second +
(unsigned)((rsup->second - rinf->second + 1) * (rand() / (RAND_MAX+1.0)));
Row* searchRow = _rowVector[randidx];
DbU::Unit lowerX = srcPos.getX() - DbU::lambda((dist * DbU::getLambda(_searchWidth)));
if ((lowerX < searchRow->getXMin()) || (lowerX > searchRow->getXMax()))
lowerX = searchRow->getXMin();
DbU::Unit upperX = srcPos.getX() + DbU::lambda((dist * DbU::getLambda(_searchWidth)));
if ((upperX > searchRow->getXMax()) || (upperX < searchRow->getXMin()))
upperX = searchRow->getXMax();
SubRow* subRow = searchRow->getSubRowBetween(lowerX, upperX);
if ((lowerX < subRow->getXMin()) || (lowerX > subRow->getXMax()))
lowerX = subRow->getXMin();
if ((upperX > subRow->getXMax()) || (upperX < subRow->getXMin()))
upperX = subRow->getXMax();
Bin* dstBin = subRow->getBinBetween(lowerX, upperX, srcbin);
return dstBin;
}
double Surface::getBinCost() const
{
double binCost = 0.0;
for (RowVector::const_iterator rvit = _rowVector.begin();
rvit != _rowVector.end();
rvit++)
binCost += (*rvit)->getBinCost();
return binCost;
}
double Surface::getRowCost() const
{
double rowCost = 0.0;
for (RowVector::const_iterator rvit = _rowVector.begin();
rvit != _rowVector.end();
rvit++)
rowCost += (*rvit)->getCost();
return rowCost;
}
double Surface::getBinsSize() const
{
double totalBinsSize = 0.0;
for (RowVector::const_iterator rvit = _rowVector.begin();
rvit != _rowVector.end();
rvit++)
totalBinsSize += (double)(*rvit)->getBinsSize();
return totalBinsSize;
}
double Surface::getBinsCapa() const
{
double totalBinsCapa = 0.0;
for (RowVector::const_iterator rvit = _rowVector.begin();
rvit != _rowVector.end();
rvit++)
totalBinsCapa += (double)(*rvit)->getBinsCapa();
return totalBinsCapa;
}
double Surface::getSubRowsCapa() const
{
double totalSubRowsCapa = 0.0;
for (RowVector::const_iterator rvit = _rowVector.begin();
rvit != _rowVector.end();
rvit++)
{
totalSubRowsCapa += (double)(*rvit)->getSubRowsCapa();
}
return totalSubRowsCapa;
}
namespace {
class sortInstanceOccurrencesIdsByWidth
{
private: MaukaEngine* _mauka;
public: sortInstanceOccurrencesIdsByWidth(MaukaEngine* mauka): _mauka(mauka) {}
public:
bool operator()(unsigned instanceoccurrenceid1, unsigned instanceoccurrenceid2) const
{
DbU::Unit width1 = _mauka->getInstanceIdWidth(instanceoccurrenceid1);
DbU::Unit width2 = _mauka->getInstanceIdWidth(instanceoccurrenceid2);
return width1 > width2;
}
};
}
void Surface::_DisplayInstances(MaukaEngine::UVector& instanceids, SubRowList& subrowlist)
{
// Insert instances in subrows
sort(instanceids.begin(), instanceids.end(), sortInstanceOccurrencesIdsByWidth(_mauka));
SubRowList::iterator srlit = subrowlist.begin();
MaukaEngine::UVector::const_iterator insIterator = instanceids.begin();
MaukaEngine::UVector::const_iterator lastLoopInsertedInsIterator = insIterator;
size_t nbInstancesPlaced = 0;
// First instance.
// if ( insIterator != instanceids.end() ) {
// Cell* master = (static_cast<Instance*>(_mauka->_instanceOccurrencesVector[*insIterator].getEntity()))->getMasterCell();
// DbU::Unit instanceWidth = _mauka->_instanceWidths[*insIterator];
// cerr << " Trying to add #0 id:" << *insIterator
// << " w:" << DbU::getValueString(instanceWidth)<< " " << master << endl;
// }
while (true)
{
if (insIterator == instanceids.end())
{
break;
// end of insertion
}
if (srlit == subrowlist.end())
{
//if ( cmess2.enabled() ) cerr << "\n";
cerr << Warning("Mauka::_DisplayInstances(): Cannot honor Bin margin, bypassing.") << endl;
srlit = subrowlist.begin();
if (lastLoopInsertedInsIterator != insIterator)
lastLoopInsertedInsIterator = insIterator;
else
{
// insertion of instances with respect of Bins margin
// did not succeed, inserting what's left.
while (insIterator != instanceids.end())
{
for (SubRow::BinVector::iterator bvit = (*srlit)->_binVector.begin();
bvit != (*srlit)->_binVector.end();
bvit++)
{
Bin* bin = *bvit;
unsigned instanceId = *insIterator;
DbU::Unit instanceWidth = _mauka->_instanceWidths[instanceId];
if (instanceWidth > (*srlit)->getWidthVsSize())
break;
bin->addInstance(instanceId);
++insIterator;
if (insIterator == instanceids.end())
break;
}
if (insIterator == instanceids.end())
break;
++srlit;
if (srlit == subrowlist.end())
{
if (lastLoopInsertedInsIterator == insIterator)
{
//impossible to succeed
// try to merge all bins in subrows
bool merged = false;
for (srlit = subrowlist.begin();
srlit != subrowlist.end();
srlit++)
{
merged = (*srlit)->_MergeBins();
}
if (merged)
{
insIterator = instanceids.begin();
}
else
{
//count instances to place
unsigned nbInstancesToPlace = 0;
while (insIterator++ != instanceids.end())
++nbInstancesToPlace;
//cerr << "Box: " << getBoundingBox() << endl;
throw Error("Not enough free space to place all the instances.<br>\n"
"Please increase the abutment box: %s %d placeds (%d instances remains to place)"
,getString(getBoundingBox()).c_str()
,nbInstancesPlaced
,(nbInstancesToPlace - nbInstancesPlaced)
);
}
}
srlit = subrowlist.begin();
lastLoopInsertedInsIterator = insIterator;
}
}
}
}
if (insIterator != instanceids.end())
{
SubRow* subRow = *srlit;
for (SubRow::BinVector::iterator bvit = (*srlit)->_binVector.begin();
bvit != (*srlit)->_binVector.end();
bvit++)
{
Bin* bin = *bvit;
// cerr << " Bin: " << bin->getBoundingBox()
// << " capa:" << DbU::getValueString(bin->getCapa())
// << " size:" << DbU::getValueString(bin->getSize())
// << " SubRow:"
// << " capa:" << DbU::getValueString(subRow->getCapa())
// << " size:" << DbU::getValueString(subRow->getSize())
// << endl;
if (insIterator == instanceids.end()) break;
unsigned instanceId = *insIterator;
DbU::Unit instanceWidth = _mauka->_instanceWidths[instanceId];
if (instanceWidth > subRow->getCapaVsSize()) {
// cerr << " SubRow capacity exceeded" << endl;
break;
}
if (bin->TryAddInstance(instanceId)) {
srlit = subrowlist.begin();
++nbInstancesPlaced;
++insIterator;
// if ( insIterator != instanceids.end() ) {
// Instance* instance = static_cast<Instance*>(_mauka->_instanceOccurrencesVector[instanceId].getEntity());
// instanceWidth = _mauka->_instanceWidths[instanceId];
// cerr << " Trying to add #" << nbInstancesPlaced
// << " id:" << *insIterator
// << " w:" << DbU::getValueString(instanceWidth)<< " " << instance << endl;
// cerr << " " << _mauka->_instanceOccurrencesVector[instanceId]<< endl;
// }
break;
}
}
++srlit;
// if ( srlit != subrowlist.end() ) {
// cerr << " SubRow capaVsSize: " << DbU::getValueString((*srlit)->getCapaVsSize()) << endl;
// }
}
}
}
Record* Surface::_getRecord() const
{
Record* record = Inherit::_getRecord();
if (record) {
record->add(getSlot("MaukaEngine", _mauka));
}
return record;
}
void Surface::DisplayBinHits() const
{
for (RowVector::const_iterator rvit = _rowVector.begin();
rvit != _rowVector.end();
rvit++)
(*rvit)->DisplayBinHits();
}
void Surface::PlotBinsStats(ofstream& out) const
{
out << "plot [:] '-' w l 2" << endl ;
}
void Surface::Plot(ofstream& out) const
{
out << getXMin() << " " << getYMin() << endl
<< getXMin() << " " << getYMax() << endl
<< getXMax() << " " << getYMax() << endl
<< getXMax() << " " << getYMin() << endl
<< getXMin() << " " << getYMin() << endl << endl;
out << "EOF" << endl;
}
}