Support for avoidance of vertical tracks in low metal techs.

* New: In NetBuilderHybridVH::_do_1G_xM1_1PinM1(), added configuration
    to manage pins on the north/south sides for VH,2RL.
* Bug: In NetBuilderHybridVH::doRp_xG_xM1_xM3(), correct misplaced
    vertical creation (buildind invalid topologies).
* New: EtesianEngine::toColoquinte(), display histograms of the cells
    widths (in pitch) before and after bloating to get a better feeling
    of the behavior.
* New: In EtesianEngine, add support for track avoidance. Portions of
    tracks to avoid are specified by a Box, which should flat and on
    the axis of the request track. This feature is used by the H-Tree
    to clear the vertical tracks under the tree from any terminal.
* New: In Etesian::Area, Slice and SubSlice, add support for track
    avoidance. Exported to the Python wrapper.
* New: SubSlice::getUsedVTracks() to get a set of tracks blocked by
    the cell.
* New: SubSlice::trackAvoid(), shift left/rigth the cell under the
    requested vertical track. Try only to move the cell under the
    track and not it's neighbor, so it assume that there is sufficient
    space left or right of the cell.
* Bug: In cumulus/plugins.block.configuration.BlockConf, the Cfg
    parameters may be read too early from the Cfg space into the
    various sub-conf objects (like FeedsConf). Delay the reading
    of the parameters in a _postInit() functions.
      Modify Block and CoreToChip to call _postInit().
* New: In cumulus/plugins.block.configuration.BlockConf._loadRoutingGauge,
    allow the cell gauge name to differ from the routing gauge name.
* New: In cumulus/plugins.block.configuration.FeedsConf, allow to
    select the default feed to be used with 'etesian.defaultFeed'
    parameter.
* New: In cumulus/plugins.block.spares.BufferPool, allow to control
    whether or not we want tie to either side of the pool.
    (for latch up).
* New: In cumulus/plugins.block.HTree._connectLeaf(), add support
    for track avoidance.
* Bug: In cumulus/plugins.block.HTree._connectLeaf(), the TL2 contact,
   the one on the *top* auxiliary buffer seemed to have been badly
   positioned until now (too low, not using tl2Y).
     This is strange because it should have caused disconnections,
   but I didn't see it in the wiring and the regressions tests didn't
   flag anything wrong. Still a bit weird and worrying.
This commit is contained in:
Jean-Paul Chaput 2022-12-13 16:02:23 +01:00
parent 49bcdb3195
commit ca41dbd5ef
22 changed files with 1137 additions and 122 deletions

View File

@ -772,6 +772,7 @@ namespace Anabatic {
case Conn_1G_1PinM3: _do_1G_1PinM3 (); break;
case Conn_2G_1PinM3:
case Conn_3G_1PinM3: _do_xG_1PinM3 (); break;
case Conn_1G_2M1_1PinM1: _do_1G_xM1_1PinM1(); break;
case Conn_1G_1M1_1PinM3: _do_1G_1M1_1PinM3(); break;
case Conn_1G_1M1_1PinM2:
case Conn_1G_2M1_1PinM2:
@ -1268,6 +1269,13 @@ namespace Anabatic {
}
bool NetBuilder::_do_1G_xM1_1PinM1 ()
{
throw Error ( "%s::_do_1G_xM1_1PinM1() method *not* reimplemented from base class.", getTypeName().c_str() );
return false;
}
bool NetBuilder::_do_3G_xM1_1PinM3 ()
{
throw Error ( "%s::_do_3G_xM1_1PinM3() method *not* reimplemented from base class.", getTypeName().c_str() );

View File

@ -266,11 +266,10 @@ namespace Anabatic {
} else {
currContact = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(0) );
}
AutoSegment::create( currTerm, currContact, Flags::Vertical );
} else {
currContact = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(0) );
}
AutoSegment::create( currTerm , currContact, Flags::Vertical );
AutoSegment::create( prevContact, currContact, Flags::Horizontal );
}
@ -380,6 +379,38 @@ namespace Anabatic {
}
bool NetBuilderHybridVH::_do_1G_xM1_1PinM1 ()
{
cdebug_log(145,1) << getTypeName() << "::_do_1G_xM1_1PinM1() [Managed Configuration - Optimized] " << getTopology() << endl;
sortRpByX( getRoutingPads(), NoFlags ); // increasing X.
vector<RoutingPad*> rpsM1;
RoutingPad* rpM2 = nullptr;
for ( RoutingPad* rp : getRoutingPads() ) {
if (dynamic_cast<Pin*>(rp->getOccurrence().getEntity())) rpM2 = rp;
else rpsM1.push_back( rp );
}
if (rpsM1.size() > 1)
doRp_xG_xM1_xM3( rpsM1 );
else
doRp_xG_1M1( rpsM1[0] );
Pin* pin = dynamic_cast<Pin*>( rpM2->getOccurrence().getEntity() );
Pin::AccessDirection pinDir = pin->getAccessDirection();
AutoContact* rpContact = doRp_AccessNorthSouthPin( getGCell(), rpM2 );
AutoContact* rpM1Contact = doRp_Access( getGCell(), rpsM1.front(), NoFlags );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(0) );
AutoContact* turn2 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(0) );
AutoSegment::create( rpM1Contact, turn1, Flags::Vertical );
AutoSegment::create( rpContact , turn2, Flags::Vertical );
AutoSegment::create( turn1 , turn2, Flags::Horizontal );
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::doRp_1G_1PinM2 ( RoutingPad* rp )
{
cdebug_log(145,1) << getTypeName() << "::doRp_1G_1PinM2() [Managed Configuration - Optimized] " << getTopology() << endl;

View File

@ -236,6 +236,7 @@ namespace Anabatic {
virtual bool _do_xG_xM2 ();
virtual bool _do_1G_1M3 ();
virtual bool _do_xG_xM3 ();
virtual bool _do_1G_xM1_1PinM1 ();
virtual bool _do_1G_xM1_1PinM2 ();
virtual bool _do_2G_xM1_1PinM2 ();
virtual bool _do_1G_1M1_1PinM3 ();
@ -344,6 +345,8 @@ namespace Anabatic {
, Conn_1G_1PinM2 = CONNEXITY_VALUE( 1, 0, 1, 0, 0 , 1 )
, Conn_2G_1PinM2 = CONNEXITY_VALUE( 2, 0, 1, 0, 0 , 1 )
, Conn_3G_1PinM2 = CONNEXITY_VALUE( 3, 0, 1, 0, 0 , 1 )
, Conn_1G_1M1_1PinM1 = CONNEXITY_VALUE( 1, 1, 0, 0, 0 , 1 )
, Conn_1G_2M1_1PinM1 = CONNEXITY_VALUE( 1, 2, 0, 0, 0 , 1 )
, Conn_1G_1M1_1PinM2 = CONNEXITY_VALUE( 1, 1, 1, 0, 0 , 1 )
, Conn_1G_2M1_1PinM2 = CONNEXITY_VALUE( 1, 2, 1, 0, 0 , 1 )
, Conn_1G_3M1_1PinM2 = CONNEXITY_VALUE( 1, 3, 1, 0, 0 , 1 )

View File

@ -51,6 +51,7 @@ namespace Anabatic {
// virtual bool _do_xG_xM3 ();
// virtual bool _do_xG_1M1_1M2 ();
virtual bool _do_xG_xM1_xM3 ();
virtual bool _do_1G_xM1_1PinM1 ();
virtual bool _do_1G_xM1_1PinM2 ();
// virtual bool _do_4G_1M2 ();
virtual bool _do_2G ();

View File

@ -161,6 +161,7 @@ class Side ( object ):
check for out of bounds coordinates.
"""
trace( 550, '\tSide.place() {}\n'.format(ioPin) )
status = 0
if self.side & (IoPin.NORTH | IoPin.SOUTH):
gauge = self.conf.vDeepRG
@ -298,6 +299,7 @@ class Block ( object ):
Create a Block object. The only parameter ``conf`` must be a BlockConf
object which contains the complete block configuration.
"""
conf._postInit()
self.flags = 0
self.conf = conf
self.spares = Spares( self )
@ -617,6 +619,7 @@ class Block ( object ):
Place the Pins on all the sides. Raise an exception in case of failure.
(mainly due to Pins outside the side range)
"""
trace( 550, ',+', '\tBlock.placeIoPins().\n' )
faileds = 0
with UpdateSession():
for ioPin in self.conf.ioPins:
@ -625,6 +628,7 @@ class Block ( object ):
elif ioPin.flags & IoPin.EAST: side = self.sides[IoPin.EAST ]
else: side = self.sides[IoPin.WEST ]
faileds += side.place( ioPin )
trace( 550, ',-' )
if faileds:
raise ErrorMessage( 3, 'Block.placeIoPins(): Cell "{}" has {} badly placed pins.' \
.format(self.conf.cell.getName(),faileds) )
@ -846,6 +850,8 @@ class Block ( object ):
break
self.splitHTrees()
self.spares.removeUnusedBuffers()
for trackAvoid in self.conf.trackAvoids:
self.etesian.addTrackAvoid( trackAvoid )
self.etesian.toHurricane()
self.etesian.flattenPower()
if self.conf.isCoreBlock: self.doConnectCore()

View File

@ -136,7 +136,10 @@ class GaugeConf ( object ):
def _loadRoutingGauge ( self ):
trace( 550, ',+', '\tGaugeConf._loadRoutingGauge()\n' )
gaugeName = Cfg.getParamString('anabatic.routingGauge').asString()
self._cellGauge = CRL.AllianceFramework.get().getCellGauge( gaugeName )
cellGaugeName = Cfg.getParamString('anabatic.cellGauge').asString()
if not cellGaugeName or cellGaugeName == '<undefined>':
cellGaugeName = gaugeName
self._cellGauge = CRL.AllianceFramework.get().getCellGauge( cellGaugeName )
self._routingGauge = CRL.AllianceFramework.get().getRoutingGauge( gaugeName )
if not self._routingGauge:
@ -882,8 +885,8 @@ class BufferConf ( object ):
instance = Instance.create( cell, 'spare_buffer_{}'.format(self.count), self.masterCell )
trace( 550, '\tBufferConf.createBuffer(): cell={}, instance={}\n' \
.format( cell, instance ))
trace( 550, '\tplug={}\n'.format( instance.getPlug( self.masterCell.getNet('q') ) ))
trace( 550, '\tplug.getCell()={}\n'.format( instance.getPlug( self.masterCell.getNet('q') ).getCell() ))
trace( 550, '\tplug={}\n'.format( instance.getPlug( self.masterCell.getNet(self.output) ) ))
trace( 550, '\tplug.getCell()={}\n'.format( instance.getPlug( self.masterCell.getNet(self.output) ).getCell() ))
self.count += 1
return instance
@ -988,9 +991,11 @@ class FeedsConf ( object ):
trace( 550, ',+', '\tFeedsConf.__init__()\n' )
cfg.etesian.feedNames = None
cfg.etesian.latchUpDistance = None
cfg.etesian.defaultFeed = None
feeds = cfg.etesian.feedNames.split(',')
self.count = 0
self.feeds = []
self.defaultFeed = 0
for feedName in feeds:
feedCell = framework.getCell( feedName, CRL.Catalog.State.Views )
if not feedCell:
@ -1006,16 +1011,20 @@ class FeedsConf ( object ):
for i in range(len(self.feeds)):
trace( 550, '\t[{:>2}] {:>10} {}\n' \
.format(i,DbU.getValueString(self.feeds[i][0]),self.feeds[i][1]) )
if self.feeds[i][1].getName() == cfg.etesian.defaultFeed:
self.defaultFeed = i
trace( 550, '-' )
return
def tieWidth ( self ):
"""Returns the master cell abutment box width of the tie."""
if self.feeds: return self.feeds[0][0]
if self.feeds: return self.feeds[ self.defaultFeed ][0]
return None
def createFeed ( self, cell ):
instance = Instance.create( cell, 'spare_feed_{}'.format(self.count), self.feeds[0][1] )
instance = Instance.create( cell
, 'spare_feed_{}'.format(self.count)
, self.feeds[self.defaultFeed][1] )
self.count += 1
return instance
@ -1152,6 +1161,14 @@ class IoPin ( object ):
s += 'IoPin.'+name
return s
def __repr__ ( self ):
s = '<IoPin "{}" {} @({},{},{})>'.format( self.stem
, IoPin.toStr(self.flags)
, DbU.getValueString(self.upos)
, DbU.getValueString(self.ustep)
, self.count )
return s
def __init__ ( self, flags, stem, upos, ustep=0, count=1 ):
"""
Create an I/O Pin(s) on the abutment box of a block. Could be for one
@ -1304,13 +1321,14 @@ class BlockConf ( GaugeConf ):
self.editor = None
self.framework = CRL.AllianceFramework.get()
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
self.bufferConf = BufferConf( self.framework )
self.constantsConf = ConstantsConf( self.framework, self.cfg )
self.feedsConf = FeedsConf( self.framework, self.cfg )
self.powersConf = PowersConf( self.framework, self.cfg )
self.chipConf = ChipConf( self )
self.bufferConf = None
self.constantsConf = None
self.feedsConf = None
self.powersConf = None
self.chipConf = None
self.bColumns = 2
self.bRows = 2
self.sparesTies = True
self.cloneds = []
self.cell = cell
self.icore = None
@ -1324,23 +1342,34 @@ class BlockConf ( GaugeConf ):
self.hTreeDatas = [ ]
self.useHFNS = False
self.useSpares = True
self.trackAvoids = []
self.isBuilt = False
self.useHarness = False
self.ioPins = []
self.ioPinsCounts = {}
for ioPinSpec in ioPins:
self.ioPins.append( IoPin( *ioPinSpec ) )
for line in range(len(ioPads)):
self.chipConf.addIoPad( ioPads[line], line )
self.ioPinsArg = ioPins
self.ioPadsArg = ioPads
self.cfg.etesian.aspectRatio = None
self.cfg.etesian.spaceMargin = None
self.cfg.etesian.latchUpDistance = None
self.cfg.block.spareSide = None
self.cfg.block.vRailsPeriod = None
self.cfg.katana.dumpMeasures = None
self.chipConf = ChipConf( self )
self.etesian = None
self.katana = None
def _postInit ( self ):
self.cfg.apply()
self.bufferConf = BufferConf( self.framework )
self.constantsConf = ConstantsConf( self.framework, self.cfg )
self.feedsConf = FeedsConf( self.framework, self.cfg )
self.powersConf = PowersConf( self.framework, self.cfg )
for ioPinSpec in self.ioPinsArg:
self.ioPins.append( IoPin( *ioPinSpec ) )
for line in range(len(self.ioPadsArg)):
self.chipConf.addIoPad( self.ioPadsArg[line], line )
@property
def isCoreBlock ( self ): return self.chip is not None
@ -1438,6 +1467,10 @@ class BlockConf ( GaugeConf ):
return
self.hTreeDatas.append( [ netName, flags ] );
def addTrackAvoid ( self, trackAvoid ):
if self.cfg.anabatic.netBuilderStyle == 'VH,2RL':
self.trackAvoids.append( trackAvoid )
def save ( self, flags ):
"""
Frontend to BlockConf.rsave(). Append the "_cts" suffix to the cloned

View File

@ -100,6 +100,7 @@ class HTree ( object ):
return True
def _connectLeaf ( self, leaf, ckNet, forkContact, contact, x, y ):
trace( 550, ',+', '\tHTree.connectLeaf() contact={}\n'.format( contact ))
gaugeConf = self.spares.conf
bufferConf = self.spares.conf.bufferConf
hLeafDepth = gaugeConf.horizontalDepth
@ -107,20 +108,24 @@ class HTree ( object ):
hLeafDepth = gaugeConf.horizontalDepth - 2
gaugeConf.setStackPosition( contact, x, y )
gaugeConf.createVertical ( contact, forkContact, x, 0 )
trace( 550, '\tLeaf contact:{}\n'.format( contact ))
gaugeConf.addTrackAvoid( Box( x, forkContact.getY(), x, y ) )
if len(leaf.buffers) > 1:
tl1Contact = gaugeConf.rpAccessByPlugName( leaf.buffers[1], bufferConf.input, ckNet, GaugeConf.DeepDepth|GaugeConf.HAccess )
tl2Contact = gaugeConf.rpAccessByPlugName( leaf.buffers[2], bufferConf.input, ckNet )
tl2Y = gaugeConf.getTrack( tl2Contact.getY(), hLeafDepth, 2 )
left1X = gaugeConf.getNearestVerticalTrack( tl1Contact.getX(), 0, 0 )
left1Y = gaugeConf.getStackY( contact, GaugeConf.DeepDepth )
trace( 550, '\tleft1Y: {}\n'.format( DbU.getValueString(left1Y) ))
dxLeft = contact.getX() - gaugeConf.getStackX( contact, GaugeConf.DeepDepth )
trace( 550, '\ttl2Contact: {}\n'.format( tl2Contact ))
gaugeConf.setStackPosition( tl1Contact, left1X, left1Y )
gaugeConf.setStackPosition( tl2Contact, x , left1Y )
gaugeConf.setStackPosition( tl2Contact, x , tl2Y )
trace( 550, '\ttl2Contact: {}\n'.format( tl2Contact ))
gaugeConf.expandMinArea( tl2Contact )
#gaugeConf.createHorizontal( contact , tl1Contact, left1Y , GaugeConf.DeepDepth|GaugeConf.SourceExtend )
gaugeConf.createHorizontal( contact , tl1Contact, left1Y , GaugeConf.DeepDepth, dxLeft )
gaugeConf.createVertical ( contact , tl2Contact, x, 0 )
trace( 550, ',-' )
def _rrouteHTree ( self, qt ):
"""
@ -211,8 +216,10 @@ class HTree ( object ):
if qt.bl:
trace( 550, '\tConnect BL leaf, leftX={} blY={}\n'.format( DbU.getValueString(leftX), DbU.getValueString(blY) ))
self._connectLeaf( qt.bl, ckNet, leftContact, blContact, leftX, blY )
#gaugeConf.addTrackAvoid( Box( leftX, leftSourceY, leftX, blY ) )
if qt.tr:
self._connectLeaf( qt.tr, ckNet, rightContact, trContact, rightX, tlY )
#gaugeConf.addTrackAvoid( Box( rightX, rightSourceY, rightX, tlY ) )
if qt.br:
self._connectLeaf( qt.br, ckNet, rightContact, brContact, rightX, blY )
if qt.isRoot():

View File

@ -146,8 +146,10 @@ class BufferPool ( object ):
yoffset = self.quadTree.spares.conf.icore.getTransformation().getTy()
conf = self.quadTree.spares.conf
sliceHeight = conf.sliceHeight
poolHalfWidth = (conf.bufferConf.width * self.columns)//2 + conf.feedsConf.tieWidth()
poolHalfWidth = (conf.bufferConf.width * self.columns)//2
poolHalfHeight = (conf.bufferConf.height * self.rows)//2
if conf.sparesTies:
poolHalfWidth += conf.feedsConf.tieWidth()
x = self.quadTree.spares.toXPitch( self.quadTree.area.getXCenter() - poolHalfWidth )
y = self.quadTree.spares.toYSlice( self.quadTree.area.getYCenter() - poolHalfHeight )
slice = (y - yoffset) // sliceHeight
@ -160,10 +162,13 @@ class BufferPool ( object ):
orientation = Transformation.Orientation.MY
y += sliceHeight
length = 0
for column in range(self.columns+2):
tieCols = 0
if conf.sparesTies:
tieCols = 2
for column in range(self.columns+tieCols):
transf = Transformation( x + length, y, orientation )
if (column > 0) and (column <= self.columns):
index = self.toIndex(column-1,row)
if (not conf.sparesTies) or ((column > 0) and (column <= self.columns)):
index = self.toIndex(column-tieCols//2,row)
instance = conf.createBuffer()
self.buffers[ index ][1] = instance
trace( 540, '\tBuffer[{}]: {} @{}\n'.format(index,self.buffers[index],transf) )
@ -845,6 +850,7 @@ class QuadTree ( object ):
coreTransf = self.spares.conf.icore.getTransformation()
maxSinks = self.spares.conf.bufferConf.maxSinks
#maxSinks = 7
trace( 540, '\tconf.bufferConf.maxSinks={}\n'.format(maxSinks) )
plugOccsByAngle = []
areaCenter = self.area.getCenter()
#coreTransf.applyOn( areaCenter )

View File

@ -519,6 +519,7 @@ class CoreToChip ( object ):
.format( core.getName() )
] )
conf = block.state
conf._postInit()
self.conf = conf
self.conf.useHarness = False
self.ringNetNames = []

View File

@ -158,14 +158,18 @@ namespace Etesian {
DbU::Unit BloatChannel::getDx ( const Cell* cell, const EtesianEngine* etesian ) const
{
Box ab ( cell->getAbutmentBox() );
DbU::Unit vpitch = etesian->getSliceStep();;
int xsize = (ab.getWidth() + vpitch - 1) / vpitch;
#if THIS_IS_DISABLED
return (xsize < 5) ? ((5-xsize)*vpitch) : 0;
#endif
int terminals = 0;
for ( Net* net : cell->getNets() ) {
if (net->isExternal() and not net->isPower()) ++terminals;
}
Box ab ( cell->getAbutmentBox() );
DbU::Unit vpitch = etesian->getSliceStep();;
int xsize = (ab.getWidth() + vpitch - 1) / vpitch;
int extra = 0;
float termRatio = (float)terminals / (float)(ab.getWidth() / vpitch);
if (termRatio > 0.8) extra += 1;

View File

@ -1,14 +1,14 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2014-2018, All Rights Reserved
// Copyright (c) Sorbonne Université 2014-2022, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | E t e s i a n - A n a l y t i c P l a c e r |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@asim.lip6.fr |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./EtesianEngine.cpp" |
// +-----------------------------------------------------------------+
@ -46,6 +46,7 @@
#include "hurricane/viewer/CellViewer.h"
#include "crlcore/Utilities.h"
#include "crlcore/Measures.h"
#include "crlcore/Histogram.h"
#include "crlcore/AllianceFramework.h"
#include "etesian/EtesianEngine.h"
@ -302,6 +303,7 @@ namespace Etesian {
, _ySpinSet (false)
, _flatDesign (false)
, _placeArea (cell->getAbutmentBox())
, _trackAvoids ()
, _surface (NULL)
, _circuit (NULL)
, _placementLB (NULL)
@ -709,6 +711,14 @@ namespace Etesian {
DbU::Unit sliceHeight = getSliceHeight();
bool isFlexLib = (getGauge()->getName() == "FlexLib");
CRL::Histogram stdCellSizes ( 0.0, 1.0, 2 );
stdCellSizes.setTitle ( "Width" , 0 );
stdCellSizes.setColor ( "green" , 0 );
stdCellSizes.setIndent( " ", 0 );
stdCellSizes.setTitle ( "Bloat" , 1 );
stdCellSizes.setColor ( "red" , 1 );
stdCellSizes.setIndent( " ", 1 );
cmess1 << " o Converting \"" << getCell()->getName() << "\" into Coloquinte." << endl;
cmess1 << ::Dots::asString(" - H-pitch" , DbU::getValueString(hpitch)) << endl;
cmess1 << ::Dots::asString(" - V-pitch" , DbU::getValueString(vpitch)) << endl;
@ -885,7 +895,9 @@ namespace Etesian {
}
}
stdCellSizes.addSample( (float)(masterCell->getAbutmentBox().getWidth() / vpitch), 0 );
Box instanceAb = _bloatCells.getAb( occurrence );
stdCellSizes.addSample( (float)(instanceAb.getWidth() / vpitch), 1 );
Transformation instanceTransf = instance->getTransformation();
occurrence.getPath().getTransformation().applyOn( instanceTransf );
@ -1067,6 +1079,11 @@ namespace Etesian {
}
dots.finish( Dots::Reset );
cmess1 << " - Standard cells widths:" << endl;
cmess2 << stdCellSizes.toString(0) << endl;
if (_bloatCells.getSelected()->getName() != "disabled")
cmess2 << stdCellSizes.toString(1) << endl;
_densityLimits = new coloquinte::density_restrictions ();
_surface = new box<int_t>( (int_t)(topAb.getXMin() / vpitch)
, (int_t)(topAb.getXMax() / vpitch)

View File

@ -23,6 +23,8 @@
#include "hurricane/DeepNet.h"
#include "hurricane/Plug.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/Vertical.h"
#include "hurricane/NetExternalComponents.h"
#include "hurricane/Path.h"
#include "hurricane/Library.h"
#include "hurricane/viewer/CellWidget.h"
@ -43,9 +45,12 @@ namespace Etesian {
using Hurricane::Transformation;
using Hurricane::DataBase;
using Hurricane::Library;
using Hurricane::Component;
using Hurricane::DeepNet;
using Hurricane::Plug;
using Hurricane::RoutingPad;
using Hurricane::Vertical;
using Hurricane::NetExternalComponents;
using Hurricane::DebugSession;
using Hurricane::UpdateSession;
using CRL::AllianceFramework;
@ -180,6 +185,20 @@ namespace Etesian {
}
void Slice::trackAvoid ( DbU::Unit xTrack )
{
cdebug_log(121,1) << "Slice::trackAvoid() " << this << " @" << DbU::getValueString(xTrack) << endl;
for ( SubSlice& subSlice : _subSlices ) {
if (subSlice.getXMax() == xTrack) break;
if (subSlice.getXMax() > xTrack) {
subSlice.trackAvoid( xTrack );
break;
}
}
cdebug_tabw(121,-1);
}
void Slice::insertTies ( DbU::Unit latchUpMax )
{
cdebug_log(121,1) << "Slice::insertTies() @" << DbU::getValueString(_ybottom) << endl;
@ -521,7 +540,6 @@ namespace Etesian {
size_t ibegin = (flatAb.getYMin()-_placeArea.getYMin()) / _sliceHeight;
size_t iend = (flatAb.getYMax()-_placeArea.getYMin()) / _sliceHeight;
for ( size_t islice=ibegin ; islice<iend ; ++islice ) {
_slices[islice]->merge( occurrence, flatAb );
}
@ -544,6 +562,29 @@ namespace Etesian {
{ for ( Slice* slice : _slices ) slice->showSubSlices(); }
void Area::trackAvoid ( const Box& trackAvoid )
{
cdebug_log(121,1) << "Area::trackAvoid() over " << trackAvoid << endl;
Box areaTrackAvoid = _placeArea.getIntersection( trackAvoid );
if (areaTrackAvoid.isEmpty()) {
cerr << Warning( "Area::trackAvoid(): Track avoid area %s fully outside placement area %s."
, getString(trackAvoid).c_str()
, getString(_placeArea).c_str()
) << endl;
return;
}
DbU::Unit xTrack = areaTrackAvoid.getXCenter();
size_t ibegin = (areaTrackAvoid.getYMin()-_placeArea.getYMin()) / _sliceHeight;
size_t iend = (areaTrackAvoid.getYMax()-_placeArea.getYMin()) / _sliceHeight + 1;
if (iend and (iend >= _slices.size())) --iend;
for ( size_t islice=ibegin ; islice<iend ; ++islice ) {
_slices[islice]->trackAvoid( xTrack );
}
cdebug_tabw(121,-1);
}
void Area::insertTies ( DbU::Unit latchUpMax )
{
for ( Slice* slice : _slices ) slice->insertTies( latchUpMax );
@ -577,6 +618,34 @@ namespace Etesian {
}
size_t SubSlice::getUsedVTracks ( const Tile& tile, set<DbU::Unit>& vtracks )
{
DbU::Unit vpitch = _slice->getArea()->getEtesian()->getSliceStep();
Cell* cell = tile.getMasterCell();
for ( Net* net : cell->getNets() ) {
if (not net->isExternal()) continue;
if (net->isPower() or net->isGround()) continue;
for ( Component* component : NetExternalComponents::get(net) ) {
Vertical* v = dynamic_cast<Vertical*>( component );
if (not v) continue;
Transformation transf = tile.getInstance()->getTransformation();
tile.getOccurrence().getPath().getTransformation().applyOn( transf );
Point center = transf.getPoint( v->getBoundingBox().getCenter() );
if (center.getX() % vpitch) {
cerr << Error( "Slice::getUsedVTracks(): Misaligned terminal %s.\n"
" (in %s)"
, getString(v).c_str()
, getString(tile.getOccurrence()).c_str()
) << endl;
}
vtracks.insert( center.getX() );
}
}
return vtracks.size();
}
DbU::Unit SubSlice::getAverageChunk ( size_t& count ) const
{
count = 0;
@ -598,6 +667,80 @@ namespace Etesian {
}
void SubSlice::trackAvoid ( DbU::Unit xTrack )
{
DbU::Unit xMin = getXMin();
DbU::Unit xMax = getXMax();
auto beginTile = _beginTile;
auto endTile = _endTile;
if ((*beginTile).isFixed()) {
xMin += (*beginTile).getWidth();
++beginTile;
}
if (endTile == _slice->getTiles().end()) {
--endTile;
} else if ((*endTile).isFixed()) {
xMax = (*endTile).getXMin();
--endTile;
}
auto iTile = _beginTile;
while ( true ) {
Instance* instance = (*iTile).getInstance();
if ((*iTile).getXMin() >= xTrack) break;
if ((*iTile).getXMax() == xTrack) break;
if ((*iTile).getXMax() > xTrack) {
cdebug_log(121,0) << instance->getName() << " accross V-Track @" << DbU::getValueString(xTrack) << endl;
set<DbU::Unit> usedVTracks;
getUsedVTracks( *iTile, usedVTracks );
for ( DbU::Unit x : usedVTracks )
cdebug_log(121,0) << "| V-Track @" << DbU::getValueString(x) << endl;
if (not usedVTracks.count(xTrack)) break;
DbU::Unit vpitch = _slice->getArea()->getEtesian()->getSliceStep();
DbU::Unit maxDxLeft = 0;
DbU::Unit maxDxRight = 0;
if (iTile != beginTile) {
auto prevTile = iTile;
--prevTile;
maxDxLeft = (*prevTile).getXMax() - (*iTile).getXMin();
}
if (iTile != endTile) {
auto nextTile = iTile;
--nextTile;
maxDxRight = (*nextTile).getXMin() - (*iTile).getXMax();
}
DbU::Unit xShift = 0;
for ( ; xShift <= maxDxLeft ; xShift += vpitch ) {
cdebug_log(121,0) << "| try left shift " << DbU::getValueString(-xShift) << endl;
if (not usedVTracks.count( xTrack + xShift )) break;
}
if (xShift > maxDxLeft) {
xShift = - vpitch;
for ( ; xShift > maxDxRight ; xShift -= vpitch ) {
cdebug_log(121,0) << "| try right shift " << DbU::getValueString(-xShift) << endl;
if (not usedVTracks.count( xTrack + xShift )) break;
}
}
if (xShift < maxDxRight) {
cerr << Error( "SubSlice::trackAvoid(): Unable to put out of the way %s."
, getString(*iTile).c_str()
) << endl;
break;
}
cdebug_log(121,0) << "Shifting " << (*iTile) << " by " << DbU::getValueString(-xShift) << endl;
(*iTile).translate( -xShift );
break;
}
if (iTile == endTile) break;
++iTile;
}
}
void SubSlice::insertTies ( DbU::Unit latchUpMax )
{
size_t count = 0;
@ -838,6 +981,8 @@ namespace Etesian {
_area->buildSubSlices();
_area->showSubSlices();
for ( const Box& trackAvoid : _trackAvoids )
_area->trackAvoid( trackAvoid );
#if DISABLED_TIE_INSERTION
if (getConfiguration()->getLatchUpDistance()) {
Cell* feed = getFeedCells().getBiggestFeed();

View File

@ -188,8 +188,6 @@ extern "C" {
Py_RETURN_NONE;
}
// ---------------------------------------------------------------
// Attribute Method : "PyEtesianEngine_setPLaceArea ()"
static PyObject* PyEtesianEngine_setPlaceArea ( PyEtesianEngine *self, PyObject* args )
{
@ -224,6 +222,22 @@ extern "C" {
Py_RETURN_NONE;
}
static PyObject* PyEtesianEngine_addTrackAvoid ( PyEtesianEngine *self, PyObject* args )
{
cdebug_log(34,0) << "EtesianEngine.addTrackAvoid()" << endl;
HTRY
METHOD_HEAD ( "EtesianEngine.addTrackAvoid()" )
PyBox* pyBox;
if (not PyArg_ParseTuple(args,"O!:EtesianEngine.addTrackAvoid", &PyTypeBox, &pyBox)) {
PyErr_SetString( ConstructorError, "EtesianEngine.addTrackAvoid(): Parameter is not an Box." );
return NULL;
}
etesian->addTrackAvoid( *PYBOX_O(pyBox) );
HCATCH
Py_RETURN_NONE;
}
// Standart Accessors (Attributes).
// DirectVoidMethod(EtesianEngine,etesian,runNegociate)
// DirectGetBoolAttribute(PyEtesianEngine_getToolSuccess,getToolSuccess,PyEtesianEngine,EtesianEngine)
@ -271,6 +285,8 @@ extern "C" {
, "Build abstract interface in top cell for supply & blockages." }
, { "doHFNS" , (PyCFunction)PyEtesianEngine_doHFNS , METH_NOARGS
, "Perform the high fanout net synthesis." }
, { "addTrackAvoid" , (PyCFunction)PyEtesianEngine_addTrackAvoid , METH_VARARGS
, "Mark a vertical track under which no terminal should be present." }
, { "toHurricane" , (PyCFunction)PyEtesianEngine_toHurricane , METH_NOARGS
, "Build the Hurricane post-placement manipulation structure." }
, { "destroy" , (PyCFunction)PyEtesianEngine_destroy , METH_NOARGS

View File

@ -121,6 +121,7 @@ namespace Etesian {
inline ~BloatCells ();
bool select ( std::string );
Box getAb ( Occurrence );
inline const BloatCell* getSelected () const;
inline DbU::Unit getDxSpace () const;
inline void resetDxSpace ();
private:
@ -155,6 +156,7 @@ namespace Etesian {
inline DbU::Unit BloatCells::getDxSpace () const { return _dxSpace; }
inline void BloatCells::resetDxSpace () { _dxSpace = 0; }
inline const BloatCell* BloatCells::getSelected () const { return _selected; }
} // Etesian namespace.

View File

@ -109,6 +109,7 @@ namespace Etesian {
inline Cell* getBlockCell () const;
inline Instance* getBlockInstance () const;
inline const NetNameSet& getExcludedNets () const;
inline const std::vector<Box>& getTrackAvoids () const;
inline void setBlock ( Instance* );
inline void setFixedAbHeight ( DbU::Unit );
inline void setFixedAbWidth ( DbU::Unit );
@ -144,6 +145,7 @@ namespace Etesian {
void toHurricane ();
void flattenPower ();
inline void selectBloat ( std::string );
inline void addTrackAvoid ( const Box& );
virtual Record* _getRecord () const;
virtual std::string _getString () const;
virtual std::string _getTypeName () const;
@ -157,6 +159,7 @@ namespace Etesian {
bool _ySpinSet;
bool _flatDesign;
Box _placeArea;
std::vector<Box> _trackAvoids;
coloquinte::box<coloquinte::int_t>* _surface;
coloquinte::netlist* _circuit;
coloquinte::placement_t* _placementLB;
@ -236,6 +239,14 @@ namespace Etesian {
inline Area* EtesianEngine::getArea () const { return _area; }
inline const EtesianEngine::NetNameSet&
EtesianEngine::getExcludedNets () const { return _excludedNets; }
inline const std::vector<Box>&
EtesianEngine::getTrackAvoids () const { return _trackAvoids; }
inline void EtesianEngine::addTrackAvoid ( const Box& box )
{
cdebug_log(121,0) << "EtesianEngine::trackAvoid() over " << box << std::endl;
_trackAvoids.push_back( box );
}
inline void EtesianEngine::setBlock ( Instance* block )
{

View File

@ -219,7 +219,9 @@ namespace Etesian {
inline DbU::Unit getYBottom () const;
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
size_t getUsedVTracks ( const Tile& , std::set<DbU::Unit>& vtracks );
DbU::Unit getAverageChunk ( size_t& ) const;
void trackAvoid ( DbU::Unit xTrack );
void insertTies ( DbU::Unit latchUpMax );
private:
Slice* _slice;
@ -257,6 +259,7 @@ namespace Etesian {
, size_t yspin );
void buildSubSlices ();
void showSubSlices ();
void trackAvoid ( DbU::Unit xTrack );
void insertTies ( DbU::Unit latchUpMax );
Instance* createDiodeUnder ( RoutingPad*, const Box&, DbU::Unit xHint );
inline std::string _getString () const;
@ -296,6 +299,7 @@ namespace Etesian {
void addFeeds ();
void buildSubSlices ();
void showSubSlices ();
void trackAvoid ( const Box& trackAvoid );
void insertTies ( DbU::Unit latchUpMax );
Instance* createDiodeUnder ( RoutingPad*, const Box&, DbU::Unit xHint );
inline std::string _getString () const;

View File

@ -231,6 +231,7 @@ namespace Cfg {
bool Parameter::setInt ( int i, Priority priority )
{
std::cout.flush();
if ( not _updatePriority(priority) ) return false;
if ( (_type != Int) and (_type != Enumerate) )
@ -353,11 +354,12 @@ namespace Cfg {
}
}
//cerr << " updated" << endl;
_value = svalue.str();
_onValueChanged();
//cerr << " updated _value=\"" << _value << "\"" << endl;
return true;
}

View File

@ -0,0 +1,72 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2008-2022, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | I s o b a r - Hurricane / Python Interface |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./PyAttributesHolder.cpp" |
// +-----------------------------------------------------------------+
#include "hurricane/isobar/PyAttributesHolder.h"
namespace Isobar {
using namespace Hurricane;
extern "C" {
// +=================================================================+
// | "PyAttributesHolder" Python Module Code Part |
// +=================================================================+
#if defined(__PYTHON_MODULE__)
static PyObject* PyAttributesHolder_NEW ( PyObject *module, PyObject *args )
{
cdebug_log(20,0) << "PyAttributesHolder_NEW()" << endl;
PyAttributesHolder* pyAttributeHolder = PyObject_NEW(PyAttributesHolder, &PyTypeAttributesHolder);
if (pyAttributeHolder == NULL) return NULL;
return ( (PyObject*)pyAttributeHolder );
}
static int PyAttributesHolder_Init ( PyAttributesHolder* self, PyObject* args, PyObject* kwargs )
{
cdebug_log(20,0) << "PyAttributesHolder_Init(): " << (void*)self << endl;
return 0;
}
PyMethodDef PyAttributesHolder_Methods[] =
{ {NULL, NULL, 0, NULL} /* sentinel */
};
//DirectDeleteMethod(PyAttributesHolder_DeAlloc,PyAttributesHolder)
#else // End of Python Module Code Part.
// +=================================================================+
// | "PyAttributesHolder" Shared Library Code Part |
// +=================================================================+
PyTypeInheritedObjectDefinitions(AttributesHolder,PyList_Type)
# endif // End of Shared Library Code Part.
} // End of extern "C".
} // End of Isobar namespace.

View File

@ -0,0 +1,48 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2022-2022, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | I s o b a r - Hurricane / Python Interface |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./hurricane/isobar/PyAttributesHolder.h" |
// +-----------------------------------------------------------------+
#pragma once
#include "hurricane/isobar/PyHurricane.h"
#include "hurricane/Box.h"
namespace Isobar {
extern "C" {
// -------------------------------------------------------------------
// Python Object : "PyAttributesHolder".
typedef struct {
PyObject _base;
} PyAttributesHolder;
// -------------------------------------------------------------------
// Functions & Types exported to "PyHurricane.cpp".
extern PyTypeObject PyTypeAttributesHolder;
extern PyMethodDef PyAttributesHolder_Methods[];
#define IsPyAttributesHolder(v) ( (v)->ob_type == &PyTypeAttributesHolder )
#define PYATTRIBUTESHOLDER(v) ( (PyAttributesHolder*)(v) )
#define PYATTRIBUTESHOLDER_O(v) ( PYATTRIBUTESHOLDER(v)->_object )
} // extern "C".
} // Isobar namespace.

View File

@ -0,0 +1,393 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2022-2022, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | I s o b a r - Hurricane / Python Interface |
// | |
// | Author : Jean-Paul Chaput |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./PythonProperties.cpp" |
// +-----------------------------------------------------------------+
#include "hurricane/isobar/PythonProperties.h"
#include <iomanip>
#include <ctime>
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
#include "hurricane/Cell.h"
namespace Isobar {
using namespace std;
using Hurricane::Error;
using Hurricane::Warning;
using Hurricane::Property;
#ifdef PROPERTY_MAP_IMPLEMENTATION
// -------------------------------------------------------------------
// Class : "::PyObjectsMap".
ptrdiff_t PyObjectsMap::_offset = 0;
string PyObjectsMap::toPythonName ( std::string name )
{
if (name.substr(0,7) != "Python.") {
cerr << Error( "PyObjectsMap::toPythonName(): Python properties *must* start with \"Python.\"\n"
" (name \"%s\")"
, name.c_str() ) << endl;
return string();
}
return name.substr( 7 );
}
PyObjectsMap::PyObjectsMap ( PyObjectsProperty* property )
: _pyObjects()
{
if (not _offset) {
_offset = (ptrdiff_t)this - (ptrdiff_t)property;
}
}
PyObjectsMap::~PyObjectsMap ()
{
for ( auto item : _pyObjects ) {
Py_DECREF( item.second );
}
}
PyObjectsProperty* PyObjectsMap::getProperty () const
{ return reinterpret_cast<PyObjectsProperty*>( (ptrdiff_t)this - _offset ); }
DBo* PyObjectsMap::getOwner () const
{ return getProperty()->getOwner(); }
void PyObjectsMap::add ( std::string name, PyObject* object )
{
string pyPropName = toPythonName( name );
if (pyPropName.empty()) return;
auto imap = _pyObjects.find( name );
if (imap != _pyObjects.end()) {
cerr << Error( "PyObjectsMap::add(): Overwritting Python property \"%s\"\n"
" (name \"%s\")"
, name.c_str() ) << endl;
Py_DECREF( imap->second );
_pyObjects.erase( imap );
}
Py_INCREF( object );
_pyObjects.insert( make_pair(name,object) );
}
PyObject* PyObjectsMap::get ( std::string name ) const
{
string pyPropName = toPythonName( name );
if (pyPropName.empty()) return NULL;
auto imap = _pyObjects.find( name );
if (imap == _pyObjects.end()) return NULL;
return imap->second;
}
void PyObjectsMap::remove ( std::string name )
{
string pyPropName = toPythonName( name );
if (pyPropName.empty()) return;
auto imap = _pyObjects.find( name );
if (imap != _pyObjects.end()) {
Py_DECREF( imap->second );
_pyObjects.erase( imap );
}
}
string PyObjectsMap::_getString () const
{
string s = "<PyObjectsMap " + getString(getOwner()) + ">";
return s;
}
Record* PyObjectsMap::_getRecord () const
{
Record* record = new Record ( _getString() );
if (record != NULL) {
record->add( getSlot("_pyObjects", &_pyObjects) );
}
return record;
}
// -------------------------------------------------------------------
// Class : "PyObjectsProperty"
Name PyObjectsProperty::_name = "Isobar::PyObjectsProperty";
PyObjectsProperty* PyObjectsProperty::create ( DBo* owner )
{
PyObjectsProperty *property = new PyObjectsProperty();
property->_postCreate ();
return property;
}
void PyObjectsProperty::onReleasedBy ( DBo* owner )
{ PrivateProperty::onReleasedBy( owner ); }
Name PyObjectsProperty::getPropertyName ()
{ return _name; }
Name PyObjectsProperty::getName () const
{ return getPropertyName(); }
string PyObjectsProperty::_getTypeName () const
{ return "Isobar::PyObjectsProperty"; }
string PyObjectsProperty::_getString () const
{
string s = PrivateProperty::_getString ();
s.insert ( s.length() - 1 , " " + getString(&_pyObjectsMap) );
return s;
}
Record* PyObjectsProperty::_getRecord () const
{
Record* record = PrivateProperty::_getRecord();
if ( record ) {
record->add( getSlot( "_name" , _name ) );
record->add( getSlot( "_pyObjectsMap", &_pyObjectsMap ) );
}
return record;
}
// -------------------------------------------------------------------
// Class : "PythonProperties"
std::vector<PyObjectsProperty*> PythonProperties::_allocateds;
PyObjectsMap* PythonProperties::getMap ( const DBo* dbo )
{
Property* property = dbo->getProperty( PyObjectsProperty::getPropertyName() );
if (property)
return static_cast<PyObjectsProperty*>( property )->getMap();
return NULL;
}
PyObjectsMap* PythonProperties::create ( DBo* dbo )
{
PyObjectsProperty* property = static_cast<PyObjectsProperty*>
( dbo->getProperty( PyObjectsProperty::getPropertyName() ));
if (not property) {
property = PyObjectsProperty::create( dbo );
dbo->put( property );
_allocateds.push_back( property );
}
return property->getMap();
}
void PythonProperties::destroy ( DBo* dbo )
{
Property* property = dbo->getProperty( PyObjectsProperty::getPropertyName() );
if (property) {
dbo->remove( property );
for ( size_t i=0 ; i<_allocateds.size(); ++i ) {
if (_allocateds[i] == property) {
_allocateds[i] = _allocateds[ _allocateds.size() - 1 ];
_allocateds.resize( _allocateds.size() - 1 );
break;
}
}
}
}
void PythonProperties::removeAll ( std::string name )
{
if (_allocateds.empty()) return;
size_t removeds = 0;
if (not name.empty()) {
for ( size_t i=0 ; i+removeds<_allocateds.size() ; ) {
PyObjectsMap* pyMap = _allocateds[i]->getMap();
pyMap->remove( name );
if (pyMap->empty()) {
_allocateds[i]->getOwner()->remove( _allocateds[i] );
++removeds;
_allocateds[i] = _allocateds[ _allocateds.size()-removeds ];
} else
++i;
}
if (removeds)
_allocateds.resize( _allocateds.size() - removeds );
} else {
for ( size_t i=0 ; i<_allocateds.size() ; ++i ) {
_allocateds[i]->getOwner()->remove( _allocateds[i] );
}
_allocateds.clear();
}
}
#else
// -------------------------------------------------------------------
// Class : "PyObjectsProperty"
Name PyObjectsProperty::_name = "Isobar::PyObjectsProperty";
PyObjectsProperty* PyObjectsProperty::create ( DBo* owner )
{
PyObjectsProperty *property = new PyObjectsProperty();
property->_postCreate ();
return property;
}
void PyObjectsProperty::_preDestroy ()
{
Py_DECREF( _pyObject );
Super::_preDestroy();
}
void PyObjectsProperty::onReleasedBy ( DBo* owner )
{ PrivateProperty::onReleasedBy( owner ); }
Name PyObjectsProperty::getPropertyName ()
{ return _name; }
Name PyObjectsProperty::getName () const
{ return getPropertyName(); }
string PyObjectsProperty::_getTypeName () const
{ return "Isobar::PyObjectsProperty"; }
string PyObjectsProperty::_getString () const
{
string s = PrivateProperty::_getString ();
s.insert ( s.length() - 1 , " " + getString(_pyObject) );
return s;
}
Record* PyObjectsProperty::_getRecord () const
{
Record* record = PrivateProperty::_getRecord();
if ( record ) {
record->add( getSlot( "_name" , _name ) );
record->add( getSlot( "_pyObject", _pyObject ) );
}
return record;
}
// -------------------------------------------------------------------
// Class : "PythonProperties"
std::vector<PyObjectsProperty*> PythonProperties::_allocateds;
PyObject* PythonProperties::get ( const DBo* dbo )
{
Property* property = dbo->getProperty( PyObjectsProperty::getPropertyName() );
if (property)
return property->getHolder();
return NULL;
}
PyObject* PythonProperties::create ( DBo* dbo )
{
PyObjectsProperty* property = static_cast<PyObjectsProperty*>
( dbo->getProperty( PyObjectsProperty::getPropertyName() ));
if (not property) {
property = PyObjectsProperty::create( dbo );
dbo->put( property );
_allocateds.push_back( property );
}
return property->getPyObject();
}
void PythonProperties::destroy ( DBo* dbo )
{
Property* property = dbo->getProperty( PyObjectsProperty::getPropertyName() );
if (property) {
dbo->remove( property );
for ( size_t i=0 ; i<_allocateds.size(); ++i ) {
if (_allocateds[i] == property) {
_allocateds[i] = _allocateds[ _allocateds.size() - 1 ];
_allocateds.resize( _allocateds.size() - 1 );
break;
}
}
}
}
void PythonProperties::removeAll ( std::string name )
{
if (_allocateds.empty()) return;
size_t removeds = 0;
if (not name.empty()) {
for ( size_t i=0 ; i+removeds<_allocateds.size() ; ) {
// PyObject* pyObject = _allocateds[i]->getPyObject();
// pyMap->remove( name );
// if (pyMap->empty()) {
// _allocateds[i]->getOwner()->remove( _allocateds[i] );
// ++removeds;
// _allocateds[i] = _allocateds[ _allocateds.size()-removeds ];
// } else
++i;
}
if (removeds)
_allocateds.resize( _allocateds.size() - removeds );
} else {
for ( size_t i=0 ; i<_allocateds.size() ; ++i ) {
_allocateds[i]->getOwner()->remove( _allocateds[i] );
}
_allocateds.clear();
}
}
#endif
} // Isobar namespace.

View File

@ -0,0 +1,205 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2022-2022, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | I s o b a r - Hurricane / Python Interface |
// | |
// | Author : Jean-Paul Chaput |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./hurricane/isobar/PythonProperties.h" |
// +-----------------------------------------------------------------+
#pragma once
#include <Python.h>
#include <string>
#include "hurricane/Name.h"
#include "hurricane/Property.h"
#include "hurricane/Slot.h"
#include "hurricane/DBo.h"
#include "hurricane/isobar/PyAttributesHolder.h"
namespace Isobar {
using Hurricane::Record;
using Hurricane::Name;
using Hurricane::DBo;
using Hurricane::PrivateProperty;
class PyObjectsProperty;
#ifdef PROPERTY_MAP_IMPLEMENTATION
// -------------------------------------------------------------------
// Class : "Isobar::PyObjectsMap".
class PyObjectsMap {
public:
static std::string toPythonName ( std::string );
public:
PyObjectsMap ( PyObjectsProperty* );
~PyObjectsMap ();
inline bool empty () const;
PyObjectsProperty* getProperty () const;
DBo* getOwner () const;
void add ( std::string, PyObject* );
PyObject* get ( std::string ) const;
void remove ( std::string );
std::string _getString () const;
Record* _getRecord () const;
private:
static std::ptrdiff_t _offset;
std::map<std::string,PyObject*> _pyObjects;
};
inline bool PyObjectsMap::empty () const { return _pyObjects.empty(); }
// -------------------------------------------------------------------
// Class : "Isobar::PyObjectsProperty".
class PyObjectsProperty : public Hurricane::PrivateProperty {
friend class PythonProperties;
public:
static Name _name;
public:
static PyObjectsProperty* create ( DBo* );
static Name getPropertyName ();
virtual Name getName () const;
inline PyObjectsMap* getMap ();
virtual void onReleasedBy ( DBo* owner );
virtual std::string _getTypeName () const;
virtual std::string _getString () const;
virtual Record* _getRecord () const;
protected:
// Attributes.
PyObjectsMap _pyObjectsMap;
protected:
// Constructor.
inline PyObjectsProperty ();
};
inline PyObjectsProperty::PyObjectsProperty ()
: PrivateProperty(), _pyObjectsMap(this)
{ }
inline PyObjectsMap* PyObjectsProperty::getMap () { return &_pyObjectsMap; }
// -------------------------------------------------------------------
// Class : "Isobar::PythonProperties".
class PythonProperties {
public:
static PyObjectsMap* getMap ( const DBo* );
static PyObjectsMap* create ( DBo* );
static void destroy ( DBo* );
static inline PyObject* get ( const DBo*, std::string );
static inline void add ( DBo*, std::string, PyObject* );
static inline void remove ( DBo*, std::string );
static void removeAll ( std::string );
private:
static std::vector<PyObjectsProperty*> _allocateds;
};
inline PyObject* PythonProperties::get ( const DBo* dbo, std::string name )
{
PyObjectsMap* pyMap = getMap( dbo );
return (pyMap == nullptr) ? nullptr : pyMap->get( name );
}
inline void PythonProperties::add ( DBo* dbo, std::string name, PyObject* pyObject )
{
PyObjectsMap* pyMap = getMap( dbo );
if (pyMap == nullptr)
pyMap = create( dbo );
pyMap->add( name, pyObject );
}
inline void PythonProperties::remove ( DBo* dbo, std::string name )
{
PyObjectsMap* pyMap = getMap( dbo );
if (pyMap == nullptr) return;
pyMap->remove( name );
if (pyMap->empty()) {
destroy( dbo );
}
}
#else
// -------------------------------------------------------------------
// Class : "Isobar::PyObjectsProperty".
class PyObjectsProperty : public Hurricane::PrivateProperty {
friend class PythonProperties;
public:
typedef Hurricane::PrivateProperty Super;
static Name _name;
public:
static PyObjectsProperty* create ( DBo* );
static Name getPropertyName ();
virtual Name getName () const;
inline PyObject* getPyObject ();
virtual void onReleasedBy ( DBo* owner );
virtual std::string _getTypeName () const;
virtual std::string _getString () const;
virtual Record* _getRecord () const;
protected:
virtual void _preDestroy ();
protected:
// Attributes.
PyObject* _pyObject;
protected:
// Constructor.
inline PyObjectsProperty ();
};
inline PyObjectsProperty::PyObjectsProperty ()
: PrivateProperty(), _pyObject(NULL)
{
_pyObject = (PyObject*)PyObject_NEW( PyAttributesHolder, &PyTypeAttributesHolder );
}
inline PyObject* PyObjectsProperty::getPyObject () { return _pyObject; }
// -------------------------------------------------------------------
// Class : "Isobar::PythonProperties".
class PythonProperties {
public:
static PyObject* get ( const DBo* );
static PyObject* create ( DBo* );
static void destroy ( DBo* );
static void removeAll ( std::string );
private:
static std::vector<PyObjectsProperty*> _allocateds;
};
#endif
} // Isobar Namespace.
#ifdef PROPERTY_MAP_IMPLEMENTATION
INSPECTOR_P_SUPPORT(Isobar::PyObjectsMap);
INSPECTOR_P_SUPPORT(Isobar::PyObjectsProperty);
#endif

View File

@ -1,7 +1,7 @@
// -*- mode: C++; explicit-buffer-name: "GlobalRoute.cpp<katana>" -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2016-2018, All Rights Reserved
// Copyright (c) Sorbonne Université 2016-2022, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |