Merged QuadTrees in overlayed Cells (placed together).

* New: In Hurricane, in Cell & Instance, add the ability to merge the
    QuadTree when *second level* instances of a Cell are placed in
    the same space as the top Cell. This is the case of a deeply
    hierarchical design made of only standard cells that are to
    be placed in a "flat" manner.
      The design is uniquified then the intermediate instances models,
    which should be unique at that point have their QuadTree merged
    through a call to Instance::slaveAbutmentBox(). That method will
    make the model of the instance use the QuadTree of the Cell to
    which the instance belong. The instance model no longer posseses
    a dedicated QuadTree. As a corollary the abutment box of both
    Cell are kept identical and the Instance has it's transformation
    set to (0,0,ID).
      Remark: when we talk about "QuadTree", we mean in fact the
    QuadTree for the instances *and* the SliceMap (Layer+QuadTree).
      Consequence in Query: when going through the resulting
    "flattened" QuadTree we will find objects with an incomplete
    Path du to the fact that we didn't have to explore their
    Instance/Cell level to reach them. The shunted part of the
    Path is stored in the Go master Cell in the _shuntedPath
    attribute. This also affect the displayed depth of hierarchy,
    but not too badly.
* New: In Hurricane, in Cell, new methods:
    - Cell::updatePlacedFlag() : set the placement flags.
    - Cell::isUnique() : one or less instance.
    - Cell::isUniquified() : is the result of an uniquification.
    - Cell::isUniquifyMaster() : is the reference cell of the
    uniquification.
* Change: In Hurricane, in Cell::Uniquify(), uniquify a Cell only
    if it is unplaced. We do not need to duplicate placed Cells
    (see datapathes).
This commit is contained in:
Jean-Paul Chaput 2015-06-26 18:35:11 +02:00
parent 61f2b8630f
commit ae6eeb8f56
17 changed files with 347 additions and 209 deletions

View File

@ -838,15 +838,7 @@ namespace {
UpdateSession::close (); UpdateSession::close ();
if (materializationState) Go::disableAutoMaterialization (); if (materializationState) Go::disableAutoMaterialization ();
_cell->updatePlacedFlag();
bool isPlaced = true;
forEach ( Instance*, iinstance, _cell->getInstances() ) {
if (iinstance->getPlacementStatus() == Instance::PlacementStatus::UNPLACED) {
isPlaced = false;
break;
}
}
if (isPlaced) _cell->setFlags( Cell::Flags::Placed );
fileStream.close (); fileStream.close ();
} }

View File

@ -46,6 +46,10 @@ except Exception, e:
# Write back layout to disk if everything has gone fine. # Write back layout to disk if everything has gone fine.
# Must write all the sub-blocks of the core but *not* the # Must write all the sub-blocks of the core but *not* the
# standard cell (mainly the feed-through). # standard cell (mainly the feed-through).
#
# If the model has been uniquified, in the case of a merging
# of abutment box for placement, the netlist view must also
# be saved.
def rsave ( cell, depth=0 ): def rsave ( cell, depth=0 ):
if cell.isTerminal(): return if cell.isTerminal(): return
@ -54,7 +58,9 @@ def rsave ( cell, depth=0 ):
if depth == 0: print ' o Recursive Save-Cell.' if depth == 0: print ' o Recursive Save-Cell.'
print ' %s+ %s (layout).' % ( ' '*(depth*2), cell.getName() ) print ' %s+ %s (layout).' % ( ' '*(depth*2), cell.getName() )
framework.saveCell( cell, CRL.Catalog.State.Physical ) views = CRL.Catalog.State.Physical
if cell.isUniquified(): views |= CRL.Catalog.State.Logical
framework.saveCell( cell, views )
for instance in cell.getInstances(): for instance in cell.getInstances():
masterCell = instance.getMasterCell() masterCell = instance.getMasterCell()

View File

@ -472,11 +472,14 @@ namespace Etesian {
Instance* instance = static_cast<Instance*>(occurrence.getEntity()); Instance* instance = static_cast<Instance*>(occurrence.getEntity());
Cell* masterCell = instance->getMasterCell(); Cell* masterCell = instance->getMasterCell();
if (masterCell->getAbutmentBox().isEmpty()) { if ( masterCell->getAbutmentBox().isEmpty()
or ( (masterCell->getAbutmentBox().getHeight() == topAb.getHeight())
and (masterCell->getAbutmentBox().getWidth () == topAb.getWidth ()) ) ) {
// Have to check here if the model is fully placed or not. // Have to check here if the model is fully placed or not.
masterCell->setAbutmentBox( topAb ); //masterCell->setAbutmentBox( topAb );
instance->setTransformation( Transformation() ); // (0,0,ID). //instance->setTransformation( Transformation() ); // (0,0,ID).
instance->setPlacementStatus( Instance::PlacementStatus::PLACED ); //instance->setPlacementStatus( Instance::PlacementStatus::PLACED );
instance->slaveAbutmentBox();
} }
} }
UpdateSession::close(); UpdateSession::close();

View File

@ -164,6 +164,18 @@
* \false. * \false.
*/ */
//! \function bool Cell::isUnique () const;
//! Returns \true if the Cell has one or less instances, regardless of
//! it's uniquification state.
//! \function bool Cell::isUniquified () const;
//! Returns \true if this Cell is the result of an uniquification \b and
//! is not the reference (the original) Cell.
//! \function bool Cell::isUniquifyMaster () const;
//! Returns \true if the Cell has been uniquified and this is the original
//! Cell. The original Cell can have both normal instances and uniquified
//! instances.
/*! \function void Cell::setName ( const Name& name ); /*! \function void Cell::setName ( const Name& name );
* Allows to change the Cell Name. * Allows to change the Cell Name.

View File

@ -39,6 +39,16 @@
* \section secInstancePredefinedFilters Predefined filters * \section secInstancePredefinedFilters Predefined filters
* *
* <b>Hurricane::Instance::getIsUnderFilter</b> * <b>Hurricane::Instance::getIsUnderFilter</b>
*
*
* \section secInstanceDestroy Instance Destruction
*
* When the Instance::destroy() method is called, if the master Cell
* is uniquified, that is, is unique \b and a copy of the reference
* Cell, it is destroyed as well. That state means that the master
* Cell has been created for the only purpose as to serve as a model
* for this peculiar Instance. It is then logical that it should be
* removed with it.
*/ */

View File

@ -19,6 +19,7 @@
//#define TEST_INTRUSIVESET //#define TEST_INTRUSIVESET
#include "hurricane/Warning.h"
#include "hurricane/SharedName.h" #include "hurricane/SharedName.h"
#include "hurricane/Cell.h" #include "hurricane/Cell.h"
#include "hurricane/DataBase.h" #include "hurricane/DataBase.h"
@ -155,11 +156,12 @@ Cell::Cell(Library* library, const Name& name)
: Inherit(), : Inherit(),
_library(library), _library(library),
_name(name), _name(name),
_shuntedPath(),
_instanceMap(), _instanceMap(),
_quadTree(), _quadTree(new QuadTree()),
_slaveInstanceSet(), _slaveInstanceSet(),
_netMap(), _netMap(),
_sliceMap(), _sliceMap(new SliceMap()),
_extensionSlices(), _extensionSlices(),
_markerSet(), _markerSet(),
//_viewSet(), //_viewSet(),
@ -197,7 +199,7 @@ Box Cell::getBoundingBox() const
if (_boundingBox.isEmpty()) { if (_boundingBox.isEmpty()) {
Box& boundingBox = (Box&)_boundingBox; Box& boundingBox = (Box&)_boundingBox;
boundingBox = _abutmentBox; boundingBox = _abutmentBox;
boundingBox.merge(_quadTree.getBoundingBox()); boundingBox.merge(_quadTree->getBoundingBox());
for_each_slice(slice, getSlices()) { for_each_slice(slice, getSlices()) {
boundingBox.merge(slice->getBoundingBox()); boundingBox.merge(slice->getBoundingBox());
end_for; end_for;
@ -232,6 +234,26 @@ bool Cell::isNetAlias ( const Name& name ) const
return _netAliasSet.find(&key) != _netAliasSet.end(); return _netAliasSet.find(&key) != _netAliasSet.end();
} }
bool Cell::isUnique() const
// ************************
{
return getSlaveInstances().getSize() < 2;
}
bool Cell::isUniquified() const
// ****************************
{
UniquifyRelation* relation = UniquifyRelation::get( this );
return relation and (relation->getMasterOwner() != this);
}
bool Cell::isUniquifyMaster() const
// ********************************
{
UniquifyRelation* relation = UniquifyRelation::get( this );
return (not relation) or (relation->getMasterOwner() == this);
}
Net* Cell::getNet ( const Name& name ) const Net* Cell::getNet ( const Name& name ) const
//****************************************** //******************************************
{ {
@ -267,11 +289,17 @@ void Cell::setAbutmentBox(const Box& abutmentBox)
// ********************************************** // **********************************************
{ {
if (abutmentBox != _abutmentBox) { if (abutmentBox != _abutmentBox) {
if (!_abutmentBox.isEmpty() && if (not _abutmentBox.isEmpty() and
(abutmentBox.isEmpty() || !abutmentBox.contains(_abutmentBox))) (abutmentBox.isEmpty() or not abutmentBox.contains(_abutmentBox)))
_unfit(_abutmentBox); _unfit( _abutmentBox );
_abutmentBox = abutmentBox; _abutmentBox = abutmentBox;
_fit(_abutmentBox); _fit( _abutmentBox );
}
for ( Instance* instance : getInstances() ) {
Cell* masterCell = instance->getMasterCell();
if (masterCell->getFlags().isset(Flags::MergedQuadTree))
masterCell->setAbutmentBox( abutmentBox );
} }
} }
@ -424,6 +452,21 @@ Cell* Cell::getCloneMaster() const
} }
bool Cell::updatePlacedFlag()
// **************************
{
bool isPlaced = true;
for ( Instance* instance : getInstances() ) {
if (instance->getPlacementStatus() == Instance::PlacementStatus::UNPLACED) {
isPlaced = false;
break;
}
}
if (isPlaced) setFlags( Cell::Flags::Placed );
return isPlaced;
}
Cell* Cell::getClone() Cell* Cell::getClone()
// ******************* // *******************
{ {
@ -462,50 +505,146 @@ Cell* Cell::getClone()
void Cell::uniquify(unsigned int depth) void Cell::uniquify(unsigned int depth)
// ************************************ // ************************************
{ {
//cerr << "Cell::uniquify() " << this << endl;
vector<Instance*> toUniquify; vector<Instance*> toUniquify;
set<Cell*> masterCells; set<Cell*> masterCells;
for ( Instance* iinstance : getInstances() ) { for ( Instance* instance : getInstances() ) {
Cell* masterCell = iinstance->getMasterCell(); Cell* masterCell = instance->getMasterCell();
if (masterCell->isTerminal()) continue; if (masterCell->isTerminal()) continue;
if (masterCells.find(masterCell) == masterCells.end()) {
masterCells.insert( masterCell ); masterCells.insert( masterCell );
if (masterCell->getSlaveInstances().getSize() > 1) { masterCell->updatePlacedFlag();
toUniquify.push_back( iinstance ); }
if ( (masterCell->getSlaveInstances().getSize() > 1) and not masterCell->isPlaced() ) {
toUniquify.push_back( instance );
} }
} }
for ( auto iinst : toUniquify ) { for ( auto instance : toUniquify ) {
iinst->uniquify(); instance->uniquify();
masterCells.insert( iinst->getMasterCell() ); masterCells.insert( instance->getMasterCell() );
} }
if (depth > 0) { if (depth > 0) {
for ( auto icell : masterCells ) for ( auto cell : masterCells )
icell->uniquify( depth-1 ); cell->uniquify( depth-1 );
} }
} }
void Cell::materialize() void Cell::materialize()
// ********************* // *********************
{ {
forEach ( Instance*, iinstance, getInstances() ) { if (_flags.isset(Flags::Materialized)) return;
if ( iinstance->getPlacementStatus() != Instance::PlacementStatus::UNPLACED )
iinstance->materialize(); _flags |= Flags::Materialized;
for ( Instance* instance : getInstances() ) {
if ( instance->getPlacementStatus() != Instance::PlacementStatus::UNPLACED )
instance->materialize();
} }
forEach ( Net* , inet , getNets () ) inet ->materialize(); for ( Net* net : getNets () ) net ->materialize();
forEach ( Marker*, imarker, getMarkers() ) imarker->materialize(); for ( Marker* marker : getMarkers() ) marker->materialize();
} }
void Cell::unmaterialize() void Cell::unmaterialize()
// *********************** // ***********************
{ {
for_each_instance(instance, getInstances()) instance->unmaterialize(); end_for; if (not _flags.isset(Flags::Materialized)) return;
for_each_net(net, getNets()) net->unmaterialize(); end_for;
for_each_marker(marker, getMarkers()) marker->unmaterialize(); end_for; _flags &= ~Flags::Materialized;
for ( Instance* instance : getInstances()) instance->unmaterialize();
for ( Net* net : getNets() ) net ->unmaterialize();
for ( Marker* marker : getMarkers() ) marker ->unmaterialize();
} }
void Cell::slaveAbutmentBox ( Cell* topCell )
// ******************************************
{
if (_flags.isset(Flags::MergedQuadTree)) {
cerr << Error( "Cell::slaveAbutmentBox(): %s is already slaved, action cancelled."
, getString(this).c_str() ) << endl;
return;
}
if (not isUnique()) {
cerr << Error( "Cell::slaveAbutmentBox(): %s is *not* unique, action cancelled."
, getString(this).c_str() ) << endl;
return;
}
_slaveAbutmentBox( topCell );
}
void Cell::_slaveAbutmentBox ( Cell* topCell )
// *******************************************
{
if (not getAbutmentBox().isEmpty()) {
if ( (getAbutmentBox().getWidth() != topCell->getAbutmentBox().getWidth())
or (getAbutmentBox().getWidth() != topCell->getAbutmentBox().getWidth()) ) {
cerr << Warning( "Slaving abutment boxes of different sizes, fixed blocks may shift.\n"
" topCell: %s (AB:%s)\n"
" slave : %s (AB:%s)"
, getString(topCell->getName()).c_str()
, getString(topCell->getAbutmentBox()).c_str()
, getString(getName()).c_str()
, getString(getAbutmentBox()).c_str()
);
}
Transformation transf ( topCell->getAbutmentBox().getXMin() - getAbutmentBox().getXMin()
, topCell->getAbutmentBox().getYMin() - getAbutmentBox().getYMin() );
for ( Instance* instance : getInstances() ) {
if (instance->getPlacementStatus() != Instance::PlacementStatus::UNPLACED) {
Transformation instanceTransf = instance->getTransformation();
transf.applyOn( instanceTransf );
instance->setTransformation( instanceTransf );
}
}
}
setAbutmentBox( topCell->getAbutmentBox() );
_changeQuadTree( topCell );
for ( Instance* instance : getInstances() ) {
Cell* masterCell = instance->getMasterCell();
if (masterCell->getFlags().isset(Flags::MergedQuadTree))
masterCell->_slaveAbutmentBox( topCell );
}
}
void Cell::_changeQuadTree ( Cell* topCell )
// *****************************************
{
bool isMaterialized = _flags.isset(Flags::Materialized);
unmaterialize();
if (topCell or _flags.isset(Flags::MergedQuadTree)) {
delete _sliceMap;
delete _quadTree;
if (topCell) {
_sliceMap = topCell->_getSliceMap();
_quadTree = topCell->_getQuadTree();
} else {
_sliceMap = new SliceMap();
_quadTree = new QuadTree();
}
}
if (isMaterialized) materialize();
}
void Cell::_postCreate() void Cell::_postCreate()
// ********************* // *********************
{ {
@ -517,23 +656,28 @@ void Cell::_postCreate()
void Cell::_preDestroy() void Cell::_preDestroy()
// ******************** // ********************
{ {
while(_slaveEntityMap.size()) { while ( _slaveEntityMap.size() ) {
_slaveEntityMap.begin()->second->destroy(); _slaveEntityMap.begin()->second->destroy();
} }
//for_each_view(view, getViews()) view->SetCell(NULL); end_for; //for ( View* view : getViews() ) view->setCell( NULL );
for_each_marker(marker, getMarkers()) marker->destroy(); end_for; for ( Marker* marker : getMarkers() ) marker->destroy();
for_each_instance(slaveInstance, getSlaveInstances()) slaveInstance->destroy(); end_for; for ( Instance* slaveInstance : getSlaveInstances() ) slaveInstance->destroy();
for_each_instance(instance, getInstances()) instance->destroy(); end_for; for ( Instance* instance : getInstances() ) instance->destroy();
forEach( Net*, inet, getNets() ) { for ( Net* net : getNets() ) {
inet->_getMainName().detachAll(); net->_getMainName().detachAll();
inet->destroy(); net->destroy();
} }
for ( auto islave : _netAliasSet ) delete islave; for ( auto islave : _netAliasSet ) delete islave;
for_each_slice(slice, getSlices()) slice->_destroy(); end_for; for ( Slice* slice : getSlices() ) slice->_destroy();
while(!_extensionSlices.empty()) _removeSlice(_extensionSlices.begin()->second); while ( not _extensionSlices.empty() ) _removeSlice( _extensionSlices.begin()->second );
_library->_getCellMap()._remove(this); if (not _flags.isset(Flags::MergedQuadTree)) {
delete _sliceMap;
delete _quadTree;
}
_library->_getCellMap()._remove( this );
Inherit::_preDestroy(); Inherit::_preDestroy();
} }
@ -554,12 +698,12 @@ Record* Cell::_getRecord() const
record->add( getSlot("_library" , _library ) ); record->add( getSlot("_library" , _library ) );
record->add( getSlot("_name" , &_name ) ); record->add( getSlot("_name" , &_name ) );
record->add( getSlot("_instances" , &_instanceMap ) ); record->add( getSlot("_instances" , &_instanceMap ) );
record->add( getSlot("_quadTree" , &_quadTree ) ); record->add( getSlot("_quadTree" , _quadTree ) );
record->add( getSlot("_slaveInstances", &_slaveInstanceSet) ); record->add( getSlot("_slaveInstances", &_slaveInstanceSet) );
record->add( getSlot("_netMap" , &_netMap ) ); record->add( getSlot("_netMap" , &_netMap ) );
record->add( getSlot("_netAliasSet" , &_netAliasSet ) ); record->add( getSlot("_netAliasSet" , &_netAliasSet ) );
record->add( getSlot("_pinMap" , &_pinMap ) ); record->add( getSlot("_pinMap" , &_pinMap ) );
record->add( getSlot("_sliceMap" , &_sliceMap ) ); record->add( getSlot("_sliceMap" , _sliceMap ) );
record->add( getSlot("_markerSet" , &_markerSet ) ); record->add( getSlot("_markerSet" , &_markerSet ) );
record->add( getSlot("_slaveEntityMap", &_slaveEntityMap ) ); record->add( getSlot("_slaveEntityMap", &_slaveEntityMap ) );
record->add( getSlot("_abutmentBox" , &_abutmentBox ) ); record->add( getSlot("_abutmentBox" , &_abutmentBox ) );

View File

@ -1775,7 +1775,7 @@ Instances Cell::getInstancesUnder(const Box& area) const
// ***************************************************** // *****************************************************
{ {
// return _quadTree.getGosUnder(area).getSubSet<Instance*>(); // return _quadTree.getGosUnder(area).getSubSet<Instance*>();
return SubTypeCollection<Go*, Instance*>(_quadTree.getGosUnder(area)); return SubTypeCollection<Go*, Instance*>(_quadTree->getGosUnder(area));
} }
Instances Cell::getSlaveInstances() const Instances Cell::getSlaveInstances() const
@ -1951,21 +1951,21 @@ Rubbers Cell::getRubbers() const
// ***************************** // *****************************
{ {
// return _quadTree.getGos().getSubSet<Rubber*>(); // return _quadTree.getGos().getSubSet<Rubber*>();
return SubTypeCollection<Go*, Rubber*>(_quadTree.getGos()); return SubTypeCollection<Go*, Rubber*>(_quadTree->getGos());
} }
Rubbers Cell::getRubbersUnder(const Box& area) const Rubbers Cell::getRubbersUnder(const Box& area) const
// ************************************************* // *************************************************
{ {
// return (area.isEmpty()) ? Rubbers() : _quadTree.getGosUnder(area).getSubSet<Rubber*>(); // return (area.isEmpty()) ? Rubbers() : _quadTree.getGosUnder(area).getSubSet<Rubber*>();
return SubTypeCollection<Go*, Rubber*>(_quadTree.getGosUnder(area)); return SubTypeCollection<Go*, Rubber*>(_quadTree->getGosUnder(area));
} }
Markers Cell::getMarkersUnder(const Box& area) const Markers Cell::getMarkersUnder(const Box& area) const
// ************************************************* // *************************************************
{ {
// return (area.isEmpty()) ? Markers() : _quadTree.getGosUnder(area).getSubSet<Marker*>(); // return (area.isEmpty()) ? Markers() : _quadTree.getGosUnder(area).getSubSet<Marker*>();
return SubTypeCollection<Go*, Marker*>(_quadTree.getGosUnder(area)); return SubTypeCollection<Go*, Marker*>(_quadTree->getGosUnder(area));
} }
References Cell::getReferences() const References Cell::getReferences() const
@ -2171,7 +2171,7 @@ Cell_Slices::Locator::Locator(const Cell* cell, const Layer::Mask& mask)
_sliceLocator() _sliceLocator()
{ {
if (_cell && !_mask.zero()) { if (_cell && !_mask.zero()) {
_sliceLocator = ((Cell*)_cell)->_getSliceMap().getElements().getLocator(); _sliceLocator = ((Cell*)_cell)->_getSliceMap()->getElements().getLocator();
while (_sliceLocator.isValid() && !(_sliceLocator.getElement()->getLayer()->getMask() & _mask)) while (_sliceLocator.isValid() && !(_sliceLocator.getElement()->getLayer()->getMask() & _mask))
_sliceLocator.progress(); _sliceLocator.progress();
} }

View File

@ -81,7 +81,6 @@ namespace Hurricane {
{ {
size_t nbRoutingPads = 0; size_t nbRoutingPads = 0;
HyperNet hyperNet ( _netOccurrence ); HyperNet hyperNet ( _netOccurrence );
RoutingPad* previousRp = NULL;
RoutingPad* currentRp = NULL; RoutingPad* currentRp = NULL;
forEach ( Occurrence, ioccurrence, hyperNet.getLeafPlugOccurrences() ) { forEach ( Occurrence, ioccurrence, hyperNet.getLeafPlugOccurrences() ) {

View File

@ -200,22 +200,32 @@ Instance::Instance(Cell* cell, const Name& name, Cell* masterCell, const Transfo
Instance* Instance::create(Cell* cell, const Name& name, Cell* masterCell, bool secureFlag) Instance* Instance::create(Cell* cell, const Name& name, Cell* masterCell, bool secureFlag)
// **************************************************************************************** // ****************************************************************************************
{ {
if (not cell)
throw Error( "Instance::create(): NULL master Cell argument." );
// if (cell->isUniquified())
// throw Error( "Instance::create(): %s master Cell is an uniquified copy.", getString(cell).c_str() );
Instance* instance = Instance* instance =
new Instance(cell, name, masterCell, Transformation(), PlacementStatus(), secureFlag); new Instance(cell, name, masterCell, Transformation(), PlacementStatus(), secureFlag);
instance->_postCreate(); instance->_postCreate();
return instance; return instance;
} }
Instance* Instance::create(Cell* cell, const Name& name, Cell* masterCell, const Transformation& transformation, const PlacementStatus& placementstatus, bool secureFlag) Instance* Instance::create(Cell* cell, const Name& name, Cell* masterCell, const Transformation& transformation, const PlacementStatus& placementstatus, bool secureFlag)
// **************************************************************************************************** // **********************************************************************************************************************************************************************
{ {
if (not cell)
throw Error( "Instance::create(): NULL master Cell argument." );
// if (cell->isUniquified())
// throw Error( "Instance::create(): %s master Cell is an uniquified copy.", getString(cell).c_str() );
Instance* instance = Instance* instance =
new Instance(cell, name, masterCell, transformation, placementstatus, secureFlag); new Instance(cell, name, masterCell, transformation, placementstatus, secureFlag);
instance->_postCreate(); instance->_postCreate();
return instance; return instance;
} }
@ -261,6 +271,25 @@ bool Instance::isLeaf() const
return getMasterCell()->isLeaf(); return getMasterCell()->isLeaf();
} }
bool Instance::isUnique() const
// ****************************
{
return _masterCell->isUnique();
}
bool Instance::isUniquified() const
// ********************************
{
return _masterCell->isUniquified();
}
bool Instance::isUniquifyMaster() const
// ************************************
{
return _masterCell->isUniquifyMaster();
}
InstanceFilter Instance::getIsUnderFilter(const Box& area) InstanceFilter Instance::getIsUnderFilter(const Box& area)
// ******************************************************* // *******************************************************
{ {
@ -453,15 +482,26 @@ void Instance::setMasterCell(Cell* masterCell, bool secureFlag)
void Instance::uniquify() void Instance::uniquify()
// ********************** // **********************
{ {
if (_masterCell->getSlaveInstances().getSize() == 1) { if (_masterCell->isUniquified()) {
cerr << Warning( "Instance::uniquify(): Master Cell %s of %s is already unique." cerr << Warning( "Instance::uniquify(): Master Cell %s of %s is already uniquified, cancelled."
, getString(_masterCell->getName()).c_str() , getString(_masterCell->getName()).c_str()
, getString(getName()).c_str() , getString(getName()).c_str()
) << endl; ) << endl;
return;
} }
setMasterCell( _masterCell->getClone() ); setMasterCell( _masterCell->getClone() );
} }
void Instance::slaveAbutmentBox()
// ******************************
{
if (not _masterCell->isUniquified()) uniquify();
setTransformation( Transformation() );
setPlacementStatus( Instance::PlacementStatus::PLACED );
_masterCell->slaveAbutmentBox( getCell() );
_masterCell->_setShuntedPath( Path(getCell()->getShuntedPath(),this) );
}
Instance* Instance::getClone(Cell* cloneCell) const Instance* Instance::getClone(Cell* cloneCell) const
// ************************************************ // ************************************************
{ {
@ -524,6 +564,8 @@ void Instance::_preDestroy()
_masterCell->_getSlaveInstanceSet()._remove(this); _masterCell->_getSlaveInstanceSet()._remove(this);
_cell->_getInstanceMap()._remove(this); _cell->_getInstanceMap()._remove(this);
if (_masterCell->isUniquified()) _masterCell->destroy();
} }
string Instance::_getString() const string Instance::_getString() const
@ -553,120 +595,6 @@ Record* Instance::_getRecord() const
return record; return record;
} }
//void Instance::_DrawPhantoms(View* view, const Box& updateArea, const Transformation& transformation)
//// **************************************************************************************************
//{
// Symbol* symbol = _masterCell->getSymbol();
// if (!symbol) {
// Box masterArea = updateArea;
// Transformation masterTransformation = _transformation;
// _transformation.getInvert().ApplyOn(masterArea);
// transformation.ApplyOn(masterTransformation);
// _masterCell->_DrawPhantoms(view, masterArea, masterTransformation);
// }
//}
//
//void Instance::_DrawBoundaries(View* view, const Box& updateArea, const Transformation& transformation)
//// ****************************************************************************************************
//{
// Box masterArea = updateArea;
// Transformation masterTransformation = _transformation;
// _transformation.getInvert().ApplyOn(masterArea);
// transformation.ApplyOn(masterTransformation);
// Symbol* symbol = _masterCell->getSymbol();
// if (!symbol)
// _masterCell->_DrawBoundaries(view, masterArea, masterTransformation);
// else
// _masterCell->getSymbol()->_Draw(view, masterArea, masterTransformation);
//}
//
//void Instance::_DrawRubbers(View* view, const Box& updateArea, const Transformation& transformation)
//// *************************************************************************************************
//{
// Box masterArea = updateArea;
// Transformation masterTransformation = _transformation;
// _transformation.getInvert().ApplyOn(masterArea);
// transformation.ApplyOn(masterTransformation);
// _masterCell->_DrawRubbers(view, masterArea, masterTransformation);
//}
//
//void Instance::_DrawMarkers(View* view, const Box& updateArea, const Transformation& transformation)
//// *************************************************************************************************
//{
// Box masterArea = updateArea;
// Transformation masterTransformation = _transformation;
// _transformation.getInvert().ApplyOn(masterArea);
// transformation.ApplyOn(masterTransformation);
// _masterCell->_DrawMarkers(view, masterArea, masterTransformation);
//}
//
//void Instance::_DrawDisplaySlots(View* view, const Box& area, const Box& updateArea, const Transformation& transformation)
//// ***********************************************************************************************************************
//{
// Box masterArea = updateArea;
// Transformation masterTransformation = _transformation;
// _transformation.getInvert().ApplyOn(masterArea);
// transformation.ApplyOn(masterTransformation);
// _masterCell->_DrawDisplaySlots(view, area, masterArea, masterTransformation);
//}
//
//bool Instance::_IsInterceptedBy(View* view, const Point& point, const DbU::Unit& aperture) const
//// ****************************************************************************************
//{
// Symbol* symbol = _masterCell->getSymbol();
// if (!symbol)
// return (view->PhantomsAreVisible() || view->BoundariesAreVisible()) &&
// getAbutmentBox().intersect(Box(point).Inflate(aperture));
// else {
// Point masterPoint = point;
// _transformation.getInvert().ApplyOn(masterPoint);
// return (view->BoundariesAreVisible() && symbol->_IsInterceptedBy(view, masterPoint, aperture));
// }
//}
//
//void Instance::_Draw(View* view, BasicLayer* basicLayer, const Box& updateArea, const Transformation& transformation)
//// ****************************************************************************************************
//{
// Symbol* symbol = _masterCell->getSymbol();
// if (!symbol) {
// Box masterArea = updateArea;
// Transformation masterTransformation = _transformation;
// _transformation.getInvert().ApplyOn(masterArea);
// transformation.ApplyOn(masterTransformation);
// _masterCell->_DrawContent(view, basicLayer, masterArea, masterTransformation);
// }
//}
//
//void Instance::_Highlight(View* view, const Box& updateArea, const Transformation& transformation)
//// ***********************************************************************************************
//{
// Symbol* symbol = _masterCell->getSymbol();
// if (!symbol) {
// Box abutmentBox = transformation.getBox(getAbutmentBox());
// view->FillRectangle(abutmentBox);
// view->DrawRectangle(abutmentBox);
//
// if ( view->getScale() > 1 )
// {
// if ( view->IsTextVisible() )
// {
// string text = getString ( _name ) + " ("
// + getString ( getValue ( abutmentBox.getXCenter () ) ) + ","
// + getString ( getValue ( abutmentBox.getYCenter () ) ) + ")";
// view->DrawString ( text, abutmentBox.getXMin(), abutmentBox.getYMax() );
// }
// }
// }
// else {
// Box masterArea = updateArea;
// Transformation masterTransformation = _transformation;
// _transformation.getInvert().ApplyOn(masterArea);
// transformation.ApplyOn(masterTransformation);
// symbol->_Highlight(view, masterArea, masterTransformation);
// }
//}
//
// **************************************************************************************************** // ****************************************************************************************************
// Instance::PlugMap implementation // Instance::PlugMap implementation
// **************************************************************************************************** // ****************************************************************************************************

View File

@ -121,7 +121,13 @@ SharedPath::SharedPath(Instance* headInstance, SharedPath* tailSharedPath)
throw Error("Can't create " + _TName("SharedPath") + " : already exists"); throw Error("Can't create " + _TName("SharedPath") + " : already exists");
if (_tailSharedPath && (_tailSharedPath->getOwnerCell() != _headInstance->getMasterCell())) if (_tailSharedPath && (_tailSharedPath->getOwnerCell() != _headInstance->getMasterCell()))
throw Error("Can't create " + _TName("SharedPath") + " : incompatible tail path"); throw Error( "Can't create %s, incompatible tail path between:\n"
" - head owner %s\n"
" - tail owner %s\n"
, _TName("SharedPath").c_str()
, getString(_headInstance ->getMasterCell()).c_str()
, getString(_tailSharedPath->getOwnerCell ()).c_str()
);
_headInstance->_getSharedPathMap()._insert(this); _headInstance->_getSharedPathMap()._insert(this);
} }

View File

@ -48,13 +48,13 @@ Slice::Slice(Cell* cell, const Layer* layer)
if (_cell->getSlice(_layer)) if (_cell->getSlice(_layer))
throw Error("Can't create " + _TName("Slice") + " : already exists"); throw Error("Can't create " + _TName("Slice") + " : already exists");
_cell->_getSliceMap()._insert(this); _cell->_getSliceMap()->_insert(this);
} }
Slice::~Slice() Slice::~Slice()
// ************ // ************
{ {
_cell->_getSliceMap()._remove(this); _cell->_getSliceMap()->_remove(this);
} }
Components Slice::getComponents() const Components Slice::getComponents() const

View File

@ -90,13 +90,13 @@ void UpdateSession::_destroy()
UPDATOR_STACK->pop(); UPDATOR_STACK->pop();
vector<Cell*> changedCells; vector<Cell*> changedCells;
forEach( DBo*, iowner, getOwners() ) { for ( DBo* owner : getOwners() ) {
Cell* cell = dynamic_cast<Cell*>(*iowner); Cell* cell = dynamic_cast<Cell*>(owner);
if (cell) { if (cell) {
//cerr << "Notify Cell::CellChanged to: " << cell << endl; //cerr << "Notify Cell::CellChanged to: " << cell << endl;
changedCells.push_back( cell ); changedCells.push_back( cell );
} else { } else {
Go* go = dynamic_cast<Go*>(*iowner); Go* go = dynamic_cast<Go*>(owner);
if (go) go->materialize(); if (go) go->materialize();
} }
} }
@ -180,8 +180,8 @@ void UpdateSession::onNotOwned()
//cerr << "Notify Cell::CellAboutToChange to: " << getCell() << endl; //cerr << "Notify Cell::CellAboutToChange to: " << getCell() << endl;
getCell()->put ( UPDATOR_STACK->top() ); getCell()->put ( UPDATOR_STACK->top() );
getCell()->notify( Cell::Flags::CellAboutToChange ); getCell()->notify( Cell::Flags::CellAboutToChange );
forEach( Instance*, iinstance, getCell()->getSlaveInstances() ) { for ( Instance* instance : getCell()->getSlaveInstances() ) {
iinstance->invalidate( false ); instance->invalidate( false );
} }
} }
} }

View File

@ -91,6 +91,8 @@ class Cell : public Entity {
, FlattenedNets = 0x00008000 , FlattenedNets = 0x00008000
, Placed = 0x00010000 , Placed = 0x00010000
, Routed = 0x00020000 , Routed = 0x00020000
, MergedQuadTree = 0x00040000
, Materialized = 0x00080000
}; };
public: public:
@ -231,12 +233,13 @@ class Cell : public Entity {
private: Library* _library; private: Library* _library;
private: Name _name; private: Name _name;
private: Path _shuntedPath;
private: InstanceMap _instanceMap; private: InstanceMap _instanceMap;
private: QuadTree _quadTree; private: QuadTree* _quadTree;
private: SlaveInstanceSet _slaveInstanceSet; private: SlaveInstanceSet _slaveInstanceSet;
private: NetMap _netMap; private: NetMap _netMap;
private: PinMap _pinMap; private: PinMap _pinMap;
private: SliceMap _sliceMap; private: SliceMap* _sliceMap;
private: ExtensionSliceMap _extensionSlices; private: ExtensionSliceMap _extensionSlices;
private: MarkerSet _markerSet; private: MarkerSet _markerSet;
private: Box _abutmentBox; private: Box _abutmentBox;
@ -268,11 +271,11 @@ class Cell : public Entity {
public: static Slot* getFlagSlot( unsigned int ); public: static Slot* getFlagSlot( unsigned int );
public: InstanceMap& _getInstanceMap() {return _instanceMap;}; public: InstanceMap& _getInstanceMap() {return _instanceMap;};
public: QuadTree* _getQuadTree() {return &_quadTree;}; public: QuadTree* _getQuadTree() {return _quadTree;};
public: SlaveInstanceSet& _getSlaveInstanceSet() {return _slaveInstanceSet;}; public: SlaveInstanceSet& _getSlaveInstanceSet() {return _slaveInstanceSet;};
public: NetMap& _getNetMap() {return _netMap;}; public: NetMap& _getNetMap() {return _netMap;};
public: PinMap& _getPinMap() {return _pinMap;}; public: PinMap& _getPinMap() {return _pinMap;};
public: SliceMap& _getSliceMap() {return _sliceMap;}; public: SliceMap* _getSliceMap() {return _sliceMap;};
public: ExtensionSliceMap& _getExtensionSliceMap() {return _extensionSlices;}; public: ExtensionSliceMap& _getExtensionSliceMap() {return _extensionSlices;};
public: MarkerSet& _getMarkerSet() {return _markerSet;}; public: MarkerSet& _getMarkerSet() {return _markerSet;};
public: Cell* _getNextOfLibraryCellMap() const {return _nextOfLibraryCellMap;}; public: Cell* _getNextOfLibraryCellMap() const {return _nextOfLibraryCellMap;};
@ -292,8 +295,11 @@ class Cell : public Entity {
public: void _removeSlaveEntity(Entity* entity, Entity* slaveEntity); public: void _removeSlaveEntity(Entity* entity, Entity* slaveEntity);
public: void _getSlaveEntities(SlaveEntityMap::iterator& begin, SlaveEntityMap::iterator& end); public: void _getSlaveEntities(SlaveEntityMap::iterator& begin, SlaveEntityMap::iterator& end);
public: void _getSlaveEntities(Entity* entity, SlaveEntityMap::iterator& begin, SlaveEntityMap::iterator& end); public: void _getSlaveEntities(Entity* entity, SlaveEntityMap::iterator& begin, SlaveEntityMap::iterator& end);
public: void _insertSlice ( ExtensionSlice* ); public: void _insertSlice(ExtensionSlice*);
public: void _removeSlice ( ExtensionSlice* ); public: void _removeSlice(ExtensionSlice*);
public: void _slaveAbutmentBox(Cell*);
public: void _changeQuadTree(Cell*);
public: void _setShuntedPath(Path path) { _shuntedPath=path; }
// Constructors // Constructors
// ************ // ************
@ -307,6 +313,8 @@ class Cell : public Entity {
public: virtual Box getBoundingBox() const; public: virtual Box getBoundingBox() const;
public: Library* getLibrary() const {return _library;}; public: Library* getLibrary() const {return _library;};
public: const Name& getName() const {return _name;}; public: const Name& getName() const {return _name;};
public: const Flags& getFlags() const { return _flags; }
public: Path getShuntedPath() const { return _shuntedPath; }
public: Instance* getInstance(const Name& name) const {return _instanceMap.getElement(name);}; public: Instance* getInstance(const Name& name) const {return _instanceMap.getElement(name);};
public: Instances getInstances() const {return _instanceMap.getElements();}; public: Instances getInstances() const {return _instanceMap.getElements();};
public: Instances getPlacedInstances() const; public: Instances getPlacedInstances() const;
@ -339,7 +347,7 @@ class Cell : public Entity {
public: Nets getGroundNets() const; public: Nets getGroundNets() const;
public: Pin* getPin(const Name& name) const {return _pinMap.getElement(name);}; public: Pin* getPin(const Name& name) const {return _pinMap.getElement(name);};
public: Pins getPins() const {return _pinMap.getElements();}; public: Pins getPins() const {return _pinMap.getElements();};
public: Slice* getSlice(const Layer* layer) const {return _sliceMap.getElement(layer);}; public: Slice* getSlice(const Layer* layer) const {return _sliceMap->getElement(layer);};
public: Slices getSlices(const Layer::Mask& mask = ~0) const; public: Slices getSlices(const Layer::Mask& mask = ~0) const;
public: const ExtensionSliceMap& getExtensionSliceMap() const { return _extensionSlices; }; public: const ExtensionSliceMap& getExtensionSliceMap() const { return _extensionSlices; };
public: ExtensionSlice* getExtensionSlice(const Name& name) const; public: ExtensionSlice* getExtensionSlice(const Name& name) const;
@ -379,6 +387,9 @@ class Cell : public Entity {
public: bool isTerminal() const {return _flags.isset(Flags::Terminal);}; public: bool isTerminal() const {return _flags.isset(Flags::Terminal);};
public: bool isFlattenLeaf() const {return _flags.isset(Flags::FlattenLeaf);}; public: bool isFlattenLeaf() const {return _flags.isset(Flags::FlattenLeaf);};
public: bool isLeaf() const; public: bool isLeaf() const;
public: bool isUnique() const;
public: bool isUniquified() const;
public: bool isUniquifyMaster() const;
public: bool isPad() const {return _flags.isset(Flags::Pad);}; public: bool isPad() const {return _flags.isset(Flags::Pad);};
public: bool isFlattenedNets() const {return _flags.isset(Flags::FlattenedNets);}; public: bool isFlattenedNets() const {return _flags.isset(Flags::FlattenedNets);};
public: bool isPlaced() const {return _flags.isset(Flags::Placed);}; public: bool isPlaced() const {return _flags.isset(Flags::Placed);};
@ -390,6 +401,8 @@ class Cell : public Entity {
public: void setName(const Name& name); public: void setName(const Name& name);
public: void setAbutmentBox(const Box& abutmentBox); public: void setAbutmentBox(const Box& abutmentBox);
public: void slaveAbutmentBox(Cell*);
public: void unslaveAbutmentBox(Cell*);
public: void setTerminal(bool isTerminal) {_flags.set(Flags::Terminal,isTerminal);}; public: void setTerminal(bool isTerminal) {_flags.set(Flags::Terminal,isTerminal);};
public: void setFlattenLeaf(bool isFlattenLeaf) {_flags.set(Flags::FlattenLeaf,isFlattenLeaf);}; public: void setFlattenLeaf(bool isFlattenLeaf) {_flags.set(Flags::FlattenLeaf,isFlattenLeaf);};
public: void setPad(bool isPad) {_flags.set(Flags::Pad,isPad);}; public: void setPad(bool isPad) {_flags.set(Flags::Pad,isPad);};
@ -397,6 +410,7 @@ class Cell : public Entity {
public: void createRoutingPadRings(unsigned int flags=Flags::BuildRings); public: void createRoutingPadRings(unsigned int flags=Flags::BuildRings);
public: void setFlags(unsigned int flags) { _flags |= flags; } public: void setFlags(unsigned int flags) { _flags |= flags; }
public: void resetFlags(unsigned int flags) { _flags &= ~flags; } public: void resetFlags(unsigned int flags) { _flags &= ~flags; }
public: bool updatePlacedFlag();
public: void materialize(); public: void materialize();
public: void unmaterialize(); public: void unmaterialize();
public: Cell* getClone(); public: Cell* getClone();

View File

@ -137,6 +137,9 @@ class Instance : public Go {
public: bool isFixed() const {return _placementStatus == PlacementStatus::FIXED;}; public: bool isFixed() const {return _placementStatus == PlacementStatus::FIXED;};
public: bool isTerminal() const; public: bool isTerminal() const;
public: bool isLeaf() const; public: bool isLeaf() const;
public: bool isUnique() const;
public: bool isUniquified() const;
public: bool isUniquifyMaster() const;
// Filters // Filters
// ******* // *******
@ -162,6 +165,7 @@ class Instance : public Go {
public: void setPlacementStatus(const PlacementStatus& placementstatus); public: void setPlacementStatus(const PlacementStatus& placementstatus);
public: void setMasterCell(Cell* masterCell, bool secureFlag = true); public: void setMasterCell(Cell* masterCell, bool secureFlag = true);
public: void uniquify(); public: void uniquify();
public: void slaveAbutmentBox();
public: Instance* getClone(Cell* cloneCell) const; public: Instance* getClone(Cell* cloneCell) const;
// Others // Others

View File

@ -210,7 +210,7 @@ namespace Hurricane {
instance->getTransformation().getInvert().applyOn ( child->_area ); instance->getTransformation().getInvert().applyOn ( child->_area );
parent->_transformation.applyOn ( child->_transformation ); parent->_transformation.applyOn ( child->_transformation );
child->_path = Path ( parent->_path, instance ); child->_path = Path ( Path(parent->_path,instance->getCell()->getShuntedPath()) , instance );
} }

View File

@ -690,8 +690,11 @@ extern "C" {
// Standart Predicates (Attributes). // Standart Predicates (Attributes).
DirectGetBoolAttribute(PyCell_isTerminal, isTerminal ,PyCell,Cell) DirectGetBoolAttribute(PyCell_isTerminal , isTerminal ,PyCell,Cell)
DirectGetBoolAttribute(PyCell_isLeaf, isLeaf ,PyCell,Cell) DirectGetBoolAttribute(PyCell_isLeaf , isLeaf ,PyCell,Cell)
DirectGetBoolAttribute(PyCell_isUnique , isUnique ,PyCell,Cell)
DirectGetBoolAttribute(PyCell_isUniquified , isUniquified ,PyCell,Cell)
DirectGetBoolAttribute(PyCell_isUniquifyMaster, isUniquifyMaster ,PyCell,Cell)
GetBoundStateAttribute(PyCell_isPyBound ,PyCell,Cell) GetBoundStateAttribute(PyCell_isPyBound ,PyCell,Cell)
@ -727,6 +730,9 @@ extern "C" {
, { "getAbutmentBox" , (PyCFunction)PyCell_getAbutmentBox , METH_NOARGS , "Returns the abutment box of the cell(which is defined by the designer unlike the bounding box which is managed dynamically)" } , { "getAbutmentBox" , (PyCFunction)PyCell_getAbutmentBox , METH_NOARGS , "Returns the abutment box of the cell(which is defined by the designer unlike the bounding box which is managed dynamically)" }
, { "isTerminal" , (PyCFunction)PyCell_isTerminal , METH_NOARGS , "Returns true if the cell is marked as terminal, else false." } , { "isTerminal" , (PyCFunction)PyCell_isTerminal , METH_NOARGS , "Returns true if the cell is marked as terminal, else false." }
, { "isLeaf" , (PyCFunction)PyCell_isLeaf , METH_NOARGS , "Returns true if the cell is a leaf of the hierarchy, else false." } , { "isLeaf" , (PyCFunction)PyCell_isLeaf , METH_NOARGS , "Returns true if the cell is a leaf of the hierarchy, else false." }
, { "isUnique" , (PyCFunction)PyCell_isUnique , METH_NOARGS , "Returns true if the cell has one or less instance." }
, { "isUniquified" , (PyCFunction)PyCell_isUniquified , METH_NOARGS , "Returns true if the cell is the result of an uniquification." }
, { "isUniquifyMaster" , (PyCFunction)PyCell_isUniquifyMaster , METH_NOARGS , "Returns true if the cell is the reference for an uniquification." }
, { "isBound" , (PyCFunction)PyCell_isPyBound , METH_NOARGS , "Returns true if the cell is bounded to the hurricane cell" } , { "isBound" , (PyCFunction)PyCell_isPyBound , METH_NOARGS , "Returns true if the cell is bounded to the hurricane cell" }
, { "setName" , (PyCFunction)PyCell_setName , METH_VARARGS, "Allows to change the cell name." } , { "setName" , (PyCFunction)PyCell_setName , METH_VARARGS, "Allows to change the cell name." }
, { "setAbutmentBox" , (PyCFunction)PyCell_setAbutmentBox , METH_VARARGS, "Sets the cell abutment box." } , { "setAbutmentBox" , (PyCFunction)PyCell_setAbutmentBox , METH_VARARGS, "Sets the cell abutment box." }

View File

@ -293,6 +293,19 @@ extern "C" {
} }
static PyObject* PyInstance_slaveAbutmentBox ( PyInstance *self )
{
trace << "PyInstance_slaveAbutmentBox ()" << endl;
METHOD_HEAD ( "Instance.slaveAbutmentBox()" )
HTRY
instance->slaveAbutmentBox();
HCATCH
Py_RETURN_NONE;
}
static PyObject* PyInstance_getClone ( PyInstance *self, PyObject* args ) static PyObject* PyInstance_getClone ( PyInstance *self, PyObject* args )
{ {
@ -379,6 +392,7 @@ extern "C" {
, { "setPlacementStatus" , (PyCFunction)PyInstance_setPlacementStatus , METH_VARARGS, "Allows to modify the instance placement status." } , { "setPlacementStatus" , (PyCFunction)PyInstance_setPlacementStatus , METH_VARARGS, "Allows to modify the instance placement status." }
, { "setMasterCell" , (PyCFunction)PyInstance_setMasterCell , METH_VARARGS, "Allows to change the cell referenced by this instance." } , { "setMasterCell" , (PyCFunction)PyInstance_setMasterCell , METH_VARARGS, "Allows to change the cell referenced by this instance." }
, { "uniquify" , (PyCFunction)PyInstance_uniquify , METH_NOARGS , "Uniquify the Instance (clone it's master Cell)." } , { "uniquify" , (PyCFunction)PyInstance_uniquify , METH_NOARGS , "Uniquify the Instance (clone it's master Cell)." }
, { "slaveAbutmentBox" , (PyCFunction)PyInstance_slaveAbutmentBox , METH_NOARGS , "Bind instance's master Cell and owner Cell together." }
, { "getClone" , (PyCFunction)PyInstance_getClone , METH_VARARGS, "Create a clone of this Instance into the cloned Cell (placement only)." } , { "getClone" , (PyCFunction)PyInstance_getClone , METH_VARARGS, "Create a clone of this Instance into the cloned Cell (placement only)." }
, { "destroy" , (PyCFunction)PyInstance_destroy , METH_NOARGS , "Destroy associated hurricane object The python object remains." } , { "destroy" , (PyCFunction)PyInstance_destroy , METH_NOARGS , "Destroy associated hurricane object The python object remains." }
, {NULL, NULL, 0, NULL} /* sentinel */ , {NULL, NULL, 0, NULL} /* sentinel */