From ca41dbd5efcedc0f39f40d3f51bfd29f82f83185 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Tue, 13 Dec 2022 16:02:23 +0100 Subject: [PATCH] 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. --- anabatic/src/NetBuilder.cpp | 8 + anabatic/src/NetBuilderHybridVH.cpp | 35 +- anabatic/src/anabatic/NetBuilder.h | 3 + anabatic/src/anabatic/NetBuilderHybridVH.h | 1 + cumulus/src/plugins/alpha/block/block.py | 6 + .../src/plugins/alpha/block/configuration.py | 71 +++- cumulus/src/plugins/alpha/block/htree.py | 15 +- cumulus/src/plugins/alpha/block/spares.py | 16 +- .../src/plugins/alpha/core2chip/core2chip.py | 1 + etesian/src/BloatCells.cpp | 10 +- etesian/src/EtesianEngine.cpp | 21 +- etesian/src/Placement.cpp | 147 ++++++- etesian/src/PyEtesianEngine.cpp | 20 +- etesian/src/etesian/BloatCells.h | 18 +- etesian/src/etesian/EtesianEngine.h | 159 +++---- etesian/src/etesian/Placement.h | 4 + hurricane/src/configuration/Parameter.cpp | 4 +- .../hurricane/grenier/PyAttributesHolder.cpp | 72 ++++ .../hurricane/grenier/PyAttributesHolder.h | 48 +++ .../hurricane/grenier/PythonProperties.cpp | 393 ++++++++++++++++++ .../src/hurricane/grenier/PythonProperties.h | 205 +++++++++ katana/src/GlobalRoute.cpp | 2 +- 22 files changed, 1137 insertions(+), 122 deletions(-) create mode 100644 hurricane/src/hurricane/grenier/PyAttributesHolder.cpp create mode 100644 hurricane/src/hurricane/grenier/PyAttributesHolder.h create mode 100644 hurricane/src/hurricane/grenier/PythonProperties.cpp create mode 100644 hurricane/src/hurricane/grenier/PythonProperties.h 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 |