diff --git a/anabatic/src/NetBuilder.cpp b/anabatic/src/NetBuilder.cpp index d375ac61..7b05273f 100644 --- a/anabatic/src/NetBuilder.cpp +++ b/anabatic/src/NetBuilder.cpp @@ -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() ); diff --git a/anabatic/src/NetBuilderHybridVH.cpp b/anabatic/src/NetBuilderHybridVH.cpp index f41af8d4..b292393d 100644 --- a/anabatic/src/NetBuilderHybridVH.cpp +++ b/anabatic/src/NetBuilderHybridVH.cpp @@ -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 rpsM1; + RoutingPad* rpM2 = nullptr; + for ( RoutingPad* rp : getRoutingPads() ) { + if (dynamic_cast(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( 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; diff --git a/anabatic/src/anabatic/NetBuilder.h b/anabatic/src/anabatic/NetBuilder.h index f1f6d5eb..9d08f33f 100644 --- a/anabatic/src/anabatic/NetBuilder.h +++ b/anabatic/src/anabatic/NetBuilder.h @@ -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 ) diff --git a/anabatic/src/anabatic/NetBuilderHybridVH.h b/anabatic/src/anabatic/NetBuilderHybridVH.h index f67c26ba..2b791e5c 100644 --- a/anabatic/src/anabatic/NetBuilderHybridVH.h +++ b/anabatic/src/anabatic/NetBuilderHybridVH.h @@ -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 (); diff --git a/cumulus/src/plugins/alpha/block/block.py b/cumulus/src/plugins/alpha/block/block.py index a91a2b15..04f002f4 100644 --- a/cumulus/src/plugins/alpha/block/block.py +++ b/cumulus/src/plugins/alpha/block/block.py @@ -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() diff --git a/cumulus/src/plugins/alpha/block/configuration.py b/cumulus/src/plugins/alpha/block/configuration.py index 7d42ddd5..7d386a76 100644 --- a/cumulus/src/plugins/alpha/block/configuration.py +++ b/cumulus/src/plugins/alpha/block/configuration.py @@ -135,8 +135,11 @@ class GaugeConf ( object ): def _loadRoutingGauge ( self ): trace( 550, ',+', '\tGaugeConf._loadRoutingGauge()\n' ) - gaugeName = Cfg.getParamString('anabatic.routingGauge').asString() - self._cellGauge = CRL.AllianceFramework.get().getCellGauge( gaugeName ) + gaugeName = Cfg.getParamString('anabatic.routingGauge').asString() + cellGaugeName = Cfg.getParamString('anabatic.cellGauge').asString() + if not cellGaugeName or cellGaugeName == '': + 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.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 = ''.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,22 +1342,33 @@ 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.etesian = None - self.katana = 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 @@ -1437,6 +1466,10 @@ class BlockConf ( GaugeConf ): .format(netName)) ) 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 ): """ diff --git a/cumulus/src/plugins/alpha/block/htree.py b/cumulus/src/plugins/alpha/block/htree.py index 478cb7df..f0ae35fe 100644 --- a/cumulus/src/plugins/alpha/block/htree.py +++ b/cumulus/src/plugins/alpha/block/htree.py @@ -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 ) + 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(): diff --git a/cumulus/src/plugins/alpha/block/spares.py b/cumulus/src/plugins/alpha/block/spares.py index 1393a871..8dd5b813 100644 --- a/cumulus/src/plugins/alpha/block/spares.py +++ b/cumulus/src/plugins/alpha/block/spares.py @@ -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 @@ -159,11 +161,14 @@ class BufferPool ( object ): if (slice+row)%2: orientation = Transformation.Orientation.MY y += sliceHeight - length = 0 - for column in range(self.columns+2): + length = 0 + 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 ) diff --git a/cumulus/src/plugins/alpha/core2chip/core2chip.py b/cumulus/src/plugins/alpha/core2chip/core2chip.py index 3b660b49..1dece882 100644 --- a/cumulus/src/plugins/alpha/core2chip/core2chip.py +++ b/cumulus/src/plugins/alpha/core2chip/core2chip.py @@ -519,6 +519,7 @@ class CoreToChip ( object ): .format( core.getName() ) ] ) conf = block.state + conf._postInit() self.conf = conf self.conf.useHarness = False self.ringNetNames = [] diff --git a/etesian/src/BloatCells.cpp b/etesian/src/BloatCells.cpp index 8cff2e56..f2a369e5 100644 --- a/etesian/src/BloatCells.cpp +++ b/etesian/src/BloatCells.cpp @@ -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; diff --git a/etesian/src/EtesianEngine.cpp b/etesian/src/EtesianEngine.cpp index a01a5c14..267fd03d 100644 --- a/etesian/src/EtesianEngine.cpp +++ b/etesian/src/EtesianEngine.cpp @@ -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)(topAb.getXMin() / vpitch) , (int_t)(topAb.getXMax() / vpitch) diff --git a/etesian/src/Placement.cpp b/etesian/src/Placement.cpp index 7baba043..73fe93e2 100644 --- a/etesian/src/Placement.cpp +++ b/etesian/src/Placement.cpp @@ -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 ; islicemerge( 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 ; islicetrackAvoid( 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& 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( 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 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(); diff --git a/etesian/src/PyEtesianEngine.cpp b/etesian/src/PyEtesianEngine.cpp index 737fe7cb..f51d0e98 100644 --- a/etesian/src/PyEtesianEngine.cpp +++ b/etesian/src/PyEtesianEngine.cpp @@ -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 diff --git a/etesian/src/etesian/BloatCells.h b/etesian/src/etesian/BloatCells.h index 221a1b09..76791b1c 100644 --- a/etesian/src/etesian/BloatCells.h +++ b/etesian/src/etesian/BloatCells.h @@ -117,12 +117,13 @@ namespace Etesian { class BloatCells { public: - inline BloatCells ( EtesianEngine* ); - inline ~BloatCells (); - bool select ( std::string ); - Box getAb ( Occurrence ); - inline DbU::Unit getDxSpace () const; - inline void resetDxSpace (); + inline BloatCells ( EtesianEngine* ); + inline ~BloatCells (); + bool select ( std::string ); + Box getAb ( Occurrence ); + inline const BloatCell* getSelected () const; + inline DbU::Unit getDxSpace () const; + inline void resetDxSpace (); private: EtesianEngine* _etesian; BloatCell* _selected; @@ -153,8 +154,9 @@ namespace Etesian { } - inline DbU::Unit BloatCells::getDxSpace () const { return _dxSpace; } - inline void BloatCells::resetDxSpace () { _dxSpace = 0; } + inline DbU::Unit BloatCells::getDxSpace () const { return _dxSpace; } + inline void BloatCells::resetDxSpace () { _dxSpace = 0; } + inline const BloatCell* BloatCells::getSelected () const { return _selected; } } // Etesian namespace. diff --git a/etesian/src/etesian/EtesianEngine.h b/etesian/src/etesian/EtesianEngine.h index 6e9c1c0f..d0ac415a 100644 --- a/etesian/src/etesian/EtesianEngine.h +++ b/etesian/src/etesian/EtesianEngine.h @@ -73,80 +73,82 @@ namespace Etesian { typedef std::map NetsToIds; typedef std::set NetNameSet; public: - static const Name& staticGetName (); - static EtesianEngine* create ( Cell* ); - static EtesianEngine* get ( const Cell* ); - public: - inline bool isExcluded ( std::string ) const; - virtual Configuration* getConfiguration (); - virtual const Configuration* getConfiguration () const; - virtual const Name& getName () const; - inline RoutingGauge* getGauge () const; - inline CellGauge* getCellGauge () const; - inline DbU::Unit getHorizontalPitch () const; - inline DbU::Unit getVerticalPitch () const; - inline DbU::Unit getSliceHeight () const; - inline DbU::Unit getSliceStep () const; - inline DbU::Unit getFixedAbHeight () const; - inline DbU::Unit getFixedAbWidth () const; - inline Effort getPlaceEffort () const; - inline GraphicUpdate getUpdateConf () const; - inline Density getSpreadingConf () const; - inline double getSpaceMargin () const; - inline double getAspectRatio () const; - inline double getAntennaInsertThreshold () const; - inline DbU::Unit getAntennaGateMaxWL () const; - inline DbU::Unit getAntennaDiodeMaxWL () const; - inline DbU::Unit getLatchUpDistance () const; - inline const FeedCells& getFeedCells () const; - inline const BufferCells& getBufferCells () const; - inline Cell* getDiodeCell () const; - std::string getUniqueDiodeName (); - inline const Box& getPlaceArea () const; - inline Area* getArea () const; - inline Hurricane::CellViewer* getViewer () const; - inline void setViewer ( Hurricane::CellViewer* ); - inline Cell* getBlockCell () const; - inline Instance* getBlockInstance () const; - inline const NetNameSet& getExcludedNets () const; - inline void setBlock ( Instance* ); - inline void setFixedAbHeight ( DbU::Unit ); - inline void setFixedAbWidth ( DbU::Unit ); - inline void setSpaceMargin ( double ); - inline void setAspectRatio ( double ); - void setDefaultAb (); - void adjustSliceHeight (); - void resetPlacement (); - void clearColoquinte (); - void loadLeafCellLayouts (); - inline DbU::Unit toDbU ( int64_t ) const; - inline Occurrence toCell ( Occurrence ) const; - inline Point toCell ( const Point& ) const; - inline Box toCell ( const Box& ) const; - inline Transformation toCell ( Transformation ) const; - inline Path toBlock ( Path ) const; - inline Occurrence toBlock ( Occurrence ) const; - inline Point toBlock ( const Point& ) const; - inline Transformation toBlock ( const Transformation& ) const; - void setPlaceArea ( const Box& ); - size_t toColoquinte (); - void preplace (); - void roughLegalize ( float minDisruption, unsigned options ); - void globalPlace ( float initPenalty, float minDisruption, float targetImprovement, float minInc, float maxInc, unsigned options=0 ); - void detailedPlace ( int iterations, int effort, unsigned options=0 ); - void antennaProtect (); - void place (); - uint32_t doHFNS (); - inline void useFeed ( Cell* ); - size_t findYSpin (); - inline void exclude ( string netName ); - void addFeeds (); - void toHurricane (); - void flattenPower (); - inline void selectBloat ( std::string ); - virtual Record* _getRecord () const; - virtual std::string _getString () const; - virtual std::string _getTypeName () const; + static const Name& staticGetName (); + static EtesianEngine* create ( Cell* ); + static EtesianEngine* get ( const Cell* ); + public: + inline bool isExcluded ( std::string ) const; + virtual Configuration* getConfiguration (); + virtual const Configuration* getConfiguration () const; + virtual const Name& getName () const; + inline RoutingGauge* getGauge () const; + inline CellGauge* getCellGauge () const; + inline DbU::Unit getHorizontalPitch () const; + inline DbU::Unit getVerticalPitch () const; + inline DbU::Unit getSliceHeight () const; + inline DbU::Unit getSliceStep () const; + inline DbU::Unit getFixedAbHeight () const; + inline DbU::Unit getFixedAbWidth () const; + inline Effort getPlaceEffort () const; + inline GraphicUpdate getUpdateConf () const; + inline Density getSpreadingConf () const; + inline double getSpaceMargin () const; + inline double getAspectRatio () const; + inline double getAntennaInsertThreshold () const; + inline DbU::Unit getAntennaGateMaxWL () const; + inline DbU::Unit getAntennaDiodeMaxWL () const; + inline DbU::Unit getLatchUpDistance () const; + inline const FeedCells& getFeedCells () const; + inline const BufferCells& getBufferCells () const; + inline Cell* getDiodeCell () const; + std::string getUniqueDiodeName (); + inline const Box& getPlaceArea () const; + inline Area* getArea () const; + inline Hurricane::CellViewer* getViewer () const; + inline void setViewer ( Hurricane::CellViewer* ); + inline Cell* getBlockCell () const; + inline Instance* getBlockInstance () const; + inline const NetNameSet& getExcludedNets () const; + inline const std::vector& getTrackAvoids () const; + inline void setBlock ( Instance* ); + inline void setFixedAbHeight ( DbU::Unit ); + inline void setFixedAbWidth ( DbU::Unit ); + inline void setSpaceMargin ( double ); + inline void setAspectRatio ( double ); + void setDefaultAb (); + void adjustSliceHeight (); + void resetPlacement (); + void clearColoquinte (); + void loadLeafCellLayouts (); + inline DbU::Unit toDbU ( int64_t ) const; + inline Occurrence toCell ( Occurrence ) const; + inline Point toCell ( const Point& ) const; + inline Box toCell ( const Box& ) const; + inline Transformation toCell ( Transformation ) const; + inline Path toBlock ( Path ) const; + inline Occurrence toBlock ( Occurrence ) const; + inline Point toBlock ( const Point& ) const; + inline Transformation toBlock ( const Transformation& ) const; + void setPlaceArea ( const Box& ); + size_t toColoquinte (); + void preplace (); + void roughLegalize ( float minDisruption, unsigned options ); + void globalPlace ( float initPenalty, float minDisruption, float targetImprovement, float minInc, float maxInc, unsigned options=0 ); + void detailedPlace ( int iterations, int effort, unsigned options=0 ); + void antennaProtect (); + void place (); + uint32_t doHFNS (); + inline void useFeed ( Cell* ); + size_t findYSpin (); + inline void exclude ( string netName ); + void addFeeds (); + 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; private: // Attributes. static Name _toolName; @@ -157,6 +159,7 @@ namespace Etesian { bool _ySpinSet; bool _flatDesign; Box _placeArea; + std::vector _trackAvoids; coloquinte::box* _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& + 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 ) { diff --git a/etesian/src/etesian/Placement.h b/etesian/src/etesian/Placement.h index 0f4bc8ce..2e06a521 100644 --- a/etesian/src/etesian/Placement.h +++ b/etesian/src/etesian/Placement.h @@ -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& 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; diff --git a/hurricane/src/configuration/Parameter.cpp b/hurricane/src/configuration/Parameter.cpp index 928eeb4c..bf9087e4 100644 --- a/hurricane/src/configuration/Parameter.cpp +++ b/hurricane/src/configuration/Parameter.cpp @@ -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; } diff --git a/hurricane/src/hurricane/grenier/PyAttributesHolder.cpp b/hurricane/src/hurricane/grenier/PyAttributesHolder.cpp new file mode 100644 index 00000000..1b0b8fb7 --- /dev/null +++ b/hurricane/src/hurricane/grenier/PyAttributesHolder.cpp @@ -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. + diff --git a/hurricane/src/hurricane/grenier/PyAttributesHolder.h b/hurricane/src/hurricane/grenier/PyAttributesHolder.h new file mode 100644 index 00000000..54a90278 --- /dev/null +++ b/hurricane/src/hurricane/grenier/PyAttributesHolder.h @@ -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. diff --git a/hurricane/src/hurricane/grenier/PythonProperties.cpp b/hurricane/src/hurricane/grenier/PythonProperties.cpp new file mode 100644 index 00000000..617b0e50 --- /dev/null +++ b/hurricane/src/hurricane/grenier/PythonProperties.cpp @@ -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 +#include +#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( (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 = ""; + 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 PythonProperties::_allocateds; + + + PyObjectsMap* PythonProperties::getMap ( const DBo* dbo ) + { + Property* property = dbo->getProperty( PyObjectsProperty::getPropertyName() ); + if (property) + return static_cast( property )->getMap(); + return NULL; + } + + + PyObjectsMap* PythonProperties::create ( DBo* dbo ) + { + PyObjectsProperty* property = static_cast + ( 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 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 + ( 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. diff --git a/hurricane/src/hurricane/grenier/PythonProperties.h b/hurricane/src/hurricane/grenier/PythonProperties.h new file mode 100644 index 00000000..dc4cb6d4 --- /dev/null +++ b/hurricane/src/hurricane/grenier/PythonProperties.h @@ -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 +#include +#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 _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 _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 _allocateds; + }; + +#endif + + +} // Isobar Namespace. + + +#ifdef PROPERTY_MAP_IMPLEMENTATION +INSPECTOR_P_SUPPORT(Isobar::PyObjectsMap); +INSPECTOR_P_SUPPORT(Isobar::PyObjectsProperty); +#endif diff --git a/katana/src/GlobalRoute.cpp b/katana/src/GlobalRoute.cpp index ee953631..66703b45 100644 --- a/katana/src/GlobalRoute.cpp +++ b/katana/src/GlobalRoute.cpp @@ -1,7 +1,7 @@ // -*- mode: C++; explicit-buffer-name: "GlobalRoute.cpp" -*- // // 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 |