From 49a37addae02b5d68644e691333720a961b0f5fe Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Thu, 3 Aug 2023 17:01:48 +0200 Subject: [PATCH] Add the ability to specify the H-track position of a H-Tree. Formerly, the H-Track could be shifted *relative* to the position of the center of the RoutingPad. Which may become fragile in case of a change in the standard cell library. So we create a new feature allowing to specify the H-track as an offset *from the bottom of the slice*. Two offset can be specified: * spares.htreeOffsetDriver : for the main H part, connected to the driver. * spares.htreeOffsetSink : for the small parts connecting to every fours sinks of the tree. This to avoid those two to overlap. The sink of the "N" stage with the driver of the "N+1" stage (so input & ouput of the same buffer). --- crlcore/python/technos/symbolic/cmos/kite.py | 2 + cumulus/src/plugins/block/configuration.py | 66 ++++--- cumulus/src/plugins/block/htree.py | 171 ++++++++++++++----- 3 files changed, 179 insertions(+), 60 deletions(-) diff --git a/crlcore/python/technos/symbolic/cmos/kite.py b/crlcore/python/technos/symbolic/cmos/kite.py index 9eaafc6b..dae53963 100644 --- a/crlcore/python/technos/symbolic/cmos/kite.py +++ b/crlcore/python/technos/symbolic/cmos/kite.py @@ -30,6 +30,8 @@ p = Cfg.getParamInt ( "katabatic.globalLengthThreshold" ).setInt ( 1 p = Cfg.getParamPercentage( "katabatic.saturateRatio" ).setPercentage( 80 ) p = Cfg.getParamInt ( "katabatic.saturateRp" ).setInt ( 8 ) p = Cfg.getParamString ( 'katabatic.topRoutingLayer' ).setString ( 'METAL5' ) +#p = Cfg.getParamInt ( "spares.htreeOffsetDriver" ).setInt ( 4 ) +#p = Cfg.getParamInt ( "spares.htreeOffsetSink" ).setInt ( 6 ) # Kite parameters. p = Cfg.getParamInt( "kite.hTracksReservedLocal" ); p.setInt( 3 ); p.setMin( 0 ); p.setMax( 20 ) diff --git a/cumulus/src/plugins/block/configuration.py b/cumulus/src/plugins/block/configuration.py index 700dbb8e..78efa292 100644 --- a/cumulus/src/plugins/block/configuration.py +++ b/cumulus/src/plugins/block/configuration.py @@ -67,10 +67,12 @@ class GaugeConf ( object ): OffsetTop1 = 0x0008 OffsetTop2 = 0x0010 OffsetBottom1 = 0x0020 - DeepDepth = 0x0040 - UseContactWidth = 0x0080 - ExpandWidth = 0x0100 - SourceExtend = 0x0200 + OffsetBottom2 = 0x0040 + OffsetFromSlice = 0x0080 + DeepDepth = 0x0100 + UseContactWidth = 0x0200 + ExpandWidth = 0x0400 + SourceExtend = 0x0800 def __init__ ( self ): self._cellGauge = None @@ -245,6 +247,11 @@ class GaugeConf ( object ): trace( 550, ' -> utrack={}\n'.format( DbU.getValueString(utrack) )) return utrack + offset*rg.getPitch() + def getHorizontalPitch ( self, flags ): + if flags & GaugeConf.DeepDepth: depth = self.horizontalDeepDepth + else: depth = self.horizontalDepth + return self._routingGauge.getLayerGauge( depth ).getPitch() + def getNearestHorizontalTrack ( self, y, flags, offset=0 ): if flags & GaugeConf.DeepDepth: depth = self.horizontalDeepDepth else: depth = self.horizontalDepth @@ -289,8 +296,9 @@ class GaugeConf ( object ): trace( 550, segment ) return segment - def rpAccess ( self, rp, flags ): - trace( 550, ',+', '\tGaugeConf.rpAccess() {}\n'.format(rp) ) + def rpAccess ( self, rp, flags, yoffset ): + trace( 550, ',+', '\tGaugeConf.rpAccess() {}\n'.format( rp )) + trace( 550, '\tHAccess set : {}\n'.format( flags&GaugeConf.HAccess )) startDepth = self.routingGauge.getLayerDepth( rp.getOccurrence().getEntity().getLayer() ) trace( 550, '\tlayer:{} startDepth:{}\n'.format(rp.getOccurrence().getEntity().getLayer(),startDepth) ) if rp in self._rpToAccess: @@ -315,15 +323,28 @@ class GaugeConf ( object ): #if flags & GaugeConf.OffsetTop1: dy -= hpitch #contact1.setDy( dy ) - yoffset = 0 - if flags & GaugeConf.OffsetBottom1: yoffset = 1 - if flags & GaugeConf.OffsetTop1: yoffset = -1 - if flags & GaugeConf.OffsetTop2: yoffset = -2 - trace( 550, '\tyoffset:{}\n'.format(yoffset) ) + rg = self.routingGauge.getLayerGauge( startDepth ) + rpContact = Contact.create( rp, rg.getLayer(), 0, 0 ) + if startDepth == 0: - rg = self.routingGauge.getLayerGauge( 0 ) - rpContact = Contact.create( rp, rg.getLayer(), 0, 0 ) - ytrack = self.getTrack( rpContact.getY(), self.horizontalDeepDepth, yoffset ) + if flags & GaugeConf.OffsetFromSlice: + sliceY = rpContact.getY() - (rpContact.getY() % self._cellGauge.getSliceHeight()) + if yoffset < 0: + sliceY += self._cellGauge.getSliceHeight() + ytrack = self.getTrack( sliceY, self.horizontalDeepDepth, yoffset ) + trace( 550, '\tyoffset (from slice):{}\n'.format(yoffset) ) + trace( 550, '\tPut on Y-track:{}\n'.format(DbU.getValueString(ytrack)) ) + else: + if yoffset is None: + yoffset = 0 + if flags & GaugeConf.OffsetBottom1: yoffset = -1 + if flags & GaugeConf.OffsetBottom2: yoffset = -2 + if flags & GaugeConf.OffsetTop1: yoffset = 1 + if flags & GaugeConf.OffsetTop2: yoffset = 2 + trace( 550, '\tyoffset (from flags):{}\n'.format( yoffset )) + ytrack = self.getTrack( rpContact.getY(), self.horizontalDeepDepth, yoffset ) + trace( 550, '\tyoffset (from contact):{}\n'.format(yoffset) ) + trace( 550, '\tPut on Y-track:{}\n'.format(DbU.getValueString(ytrack)) ) contact1 = Contact.create( rp.getNet() , self._routingGauge.getContactLayer( 0 ) , rpContact.getX() @@ -341,8 +362,6 @@ class GaugeConf ( object ): #trace( 550, '\tPut on Y-tracks:{}\n'.format(DbU.getValueString(ytrack)) ) #contact1.setDy( dy ) else: - rg = self.routingGauge.getLayerGauge( startDepth ) - rpContact = Contact.create( rp, rg.getLayer(), 0, 0 ) ytrack = self.getTrack( rpContact.getY(), startDepth, 0 ) #dy = ytrack - contact1.getY() contact1 = Contact.create( rp.getNet() @@ -433,14 +452,14 @@ class GaugeConf ( object ): self._plugToRp[plug] = rp return rp - def rpAccessByOccurrence ( self, occurrence, net, flags ): + def rpAccessByOccurrence ( self, occurrence, net, flags, yoffset=None ): plug = occurrence.getEntity() if plug in self._plugToRp: rp = self._plugToRp[plug] else: rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea ) self._plugToRp[plug] = rp - return self.rpAccess( self.rpByOccurrence(occurrence,net), flags ) + return self.rpAccess( self.rpByOccurrence(occurrence,net), flags, yoffset ) def rpByPlug ( self, plug, net ): """ @@ -464,15 +483,15 @@ class GaugeConf ( object ): """ return self.rpByPlug( getPlugByName(instance,plugName), net ) - def rpAccessByPlug ( self, plug, net, flags ): - return self.rpAccess( self.rpByPlug(plug,net), flags ) + def rpAccessByPlug ( self, plug, net, flags, yoffset=None ): + return self.rpAccess( self.rpByPlug(plug,net), flags, yoffset ) - def rpAccessByPlugName ( self, instance, plugName, net, flags=0 ): + def rpAccessByPlugName ( self, instance, plugName, net, flags=0, yoffset=None ): """ Creates a RoutingPad from a Plug (using ``rpByPlug()``) and build a contact stack using a relative positionning specified by ``flags``. """ - return self.rpAccess( self.rpByPlugName(instance,plugName,net), flags ) + return self.rpAccess( self.rpByPlugName(instance,plugName,net), flags, yoffset ) def setStackPosition ( self, topContact, x, y ): trace( 550, '\tGaugeConf.setStackPosition() @({},{}) for {}\n' \ @@ -1376,6 +1395,9 @@ class BlockConf ( GaugeConf ): self.editor = None self.framework = AllianceFramework.get() self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive) + # H-Tree/Spares parameters (triggers loading from disk). + self.cfg.spares.htreeOffsetDriver = None + self.cfg.spares.htreeOffsetSink = None self.bufferConf = None self.constantsConf = None self.feedsConf = None diff --git a/cumulus/src/plugins/block/htree.py b/cumulus/src/plugins/block/htree.py index af30af17..a4b63779 100644 --- a/cumulus/src/plugins/block/htree.py +++ b/cumulus/src/plugins/block/htree.py @@ -146,7 +146,7 @@ class HTree ( object ): hLeafDepth = gaugeConf.horizontalDepth if gaugeConf.horizontalDepth > 2 and (gaugeConf.horizontalDepth > gaugeConf.verticalDepth): hLeafDepth = gaugeConf.horizontalDepth - 2 - leafFlags = GaugeConf.OffsetLeft1 + leafFlags = 0 blContact = None brContact = None tlContact = None @@ -160,55 +160,146 @@ class HTree ( object ): or (qt.br and len(qt.br.buffers) > 1) \ or (qt.tr and len(qt.tr.buffers) > 1): leafFlags |= GaugeConf.HAccess - yoffset = gaugeConf.cfg.spares.htreeRootOffset + bufferTransf = qt.buffers[0].getTransformation() + botSinkTransf = None + topSinkTransf = None + driverY = None + sinkBotY = None + sinkTopY = None + yoffsetDriver = gaugeConf.cfg.spares.htreeOffsetDriver + yoffsetTopSink = gaugeConf.cfg.spares.htreeOffsetSink + yoffsetBotSink = gaugeConf.cfg.spares.htreeOffsetSink + trace( 550, '\tyoffsetDriver={}\n'.format( yoffsetDriver )) + trace( 550, '\tyoffsetSink={}\n'.format( yoffsetTopSink )) + + if bufferTransf.getOrientation() in ( Transformation.Orientation.ID + , Transformation.Orientation.MX ): + driverFlags = leafFlags | GaugeConf.HAccess | GaugeConf.OffsetTop1 + else: + driverFlags = leafFlags | GaugeConf.HAccess | GaugeConf.OffsetBottom1 + if yoffsetDriver is not None: + yoffsetDriver = -yoffsetDriver + if yoffsetDriver is not None: + driverFlags = leafFlags | GaugeConf.HAccess | GaugeConf.OffsetFromSlice + driverY = gaugeConf.getNearestHorizontalTrack( bufferTransf.getTy(), 0, yoffsetDriver ) + trace( 550, '\tdriverY:{}\n'.format( DbU.getValueString(driverY) )) + + if qt.bl: + botSinkTransf = qt.bl.buffers[0].getTransformation() + elif qt.br: + botSinkTransf = qt.br.buffers[0].getTransformation() + if botSinkTransf: + if botSinkTransf.getOrientation() in ( Transformation.Orientation.ID + , Transformation.Orientation.MX ): + sinkBotFlags = leafFlags | GaugeConf.OffsetLeft1 | GaugeConf.OffsetBottom1 + else: + sinkBotFlags = leafFlags | GaugeConf.OffsetLeft1 | GaugeConf.OffsetTop1 + if yoffsetBotSink is not None: + yoffsetBotSink = -yoffsetBotSink + if yoffsetBotSink is not None: + sinkBotFlags = leafFlags | GaugeConf.OffsetLeft1 | GaugeConf.OffsetFromSlice + ty = botSinkTransf.getTy() + if yoffsetBotSink < 0: + ty += gaugeConf._cellGauge.getSliceHeight() + sinkBotY = gaugeConf.getTrack( ty, hLeafDepth, yoffsetBotSink ) + trace( 550, '\tsinkBotY:{}\n'.format( DbU.getValueString(sinkBotY) )) + + if qt.tl: + topSinkTransf = qt.tl.buffers[0].getTransformation() + elif qt.tr: + topSinkTransf = qt.tr.buffers[0].getTransformation() + if topSinkTransf: + if topSinkTransf.getOrientation() in ( Transformation.Orientation.ID + , Transformation.Orientation.MX ): + sinkTopFlags = leafFlags | GaugeConf.OffsetLeft1 | GaugeConf.OffsetBottom1 + else: + sinkTopFlags = leafFlags | GaugeConf.OffsetLeft1 | GaugeConf.OffsetTop1 + if yoffsetTopSink is not None: + yoffsetTopSink = -yoffsetTopSink + if yoffsetTopSink is not None: + sinkTopFlags = leafFlags | GaugeConf.OffsetLeft1 | GaugeConf.OffsetFromSlice + ty = topSinkTransf.getTy() + if yoffsetTopSink < 0: + ty += gaugeConf._cellGauge.getSliceHeight() + sinkTopY = gaugeConf.getTrack( ty, hLeafDepth, yoffsetTopSink ) + trace( 550, '\tsinkTopY:{}\n'.format( DbU.getValueString(sinkTopY) )) + if not qt.isRoot(): ckParentNet = qt.bInputPlug(0).getNet() driverContact = gaugeConf.rpAccessByPlugName( qt.buffers[0], bufferConf.input, ckParentNet ) - driverY = driverContact.getY() - yoffset = gaugeConf.cfg.spares.htreeOffset trace( 550, '\tdriverContact={}\n'.format( driverContact )) if qt.bl: trace( 550, '+,', '\tblContact\n' ) - blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffers[0], bufferConf.input, ckNet, leafFlags ) + blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffers[0] + , bufferConf.input + , ckNet + , sinkBotFlags + , yoffsetBotSink ) + if sinkBotY is None: + sinkBotY = gaugeConf.getTrack( blContact.getY(), hLeafDepth, 0 ) trace( 550, ',-', '\tblContact={}\n'.format(blContact) ) if qt.br: trace( 550, '+,', '\tbrContact\n' ) - brContact = gaugeConf.rpAccessByPlugName( qt.br.buffers[0], bufferConf.input, ckNet, leafFlags ) + brContact = gaugeConf.rpAccessByPlugName( qt.br.buffers[0] + , bufferConf.input + , ckNet + , sinkBotFlags + , yoffsetBotSink ) + if sinkBotY is None: + sinkBotY = gaugeConf.getTrack( brContact.getY(), hLeafDepth, 0 ) trace( 550, ',-', '\tbrContact={}\n'.format(brContact) ) if qt.tl: trace( 550, '+,', '\ttlContact\n' ) - tlContact = gaugeConf.rpAccessByPlugName( qt.tl.buffers[0], bufferConf.input, ckNet, leafFlags ) + tlContact = gaugeConf.rpAccessByPlugName( qt.tl.buffers[0] + , bufferConf.input + , ckNet + , sinkTopFlags + , yoffsetTopSink ) + if sinkTopY is None: + sinkTopY = gaugeConf.getTrack( tlContact.getY(), hLeafDepth, 0 ) trace( 550, ',-', '\ttlContact={}\n'.format(tlContact) ) if qt.tr: trace( 550, '+,', '\ttrContact\n' ) - trContact = gaugeConf.rpAccessByPlugName( qt.tr.buffers[0], bufferConf.input, ckNet, leafFlags ) + trContact = gaugeConf.rpAccessByPlugName( qt.tr.buffers[0] + , bufferConf.input + , ckNet + , sinkTopFlags + , yoffsetTopSink ) + if sinkTopY is None: + sinkTopY = gaugeConf.getTrack( trContact.getY(), hLeafDepth, 0 ) trace( 550, ',-', '\ttrContact={}\n'.format(trContact) ) - flags = GaugeConf.OffsetTop2 - bufferTransf = qt.buffers[0].getTransformation() - if bufferTransf == Transformation.Orientation.ID: - yoffset = -yoffset + if qt.bl or qt.tl: trace( 550, '\tLeft branch\n' ) leafContact = blContact if brContact else tlContact - leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffers[0], bufferConf.output, ckNet , GaugeConf.HAccess|flags ) - leftSourceX = gaugeConf.getNearestVerticalTrack ( leftSourceContact.getX(), 0 ) + leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffers[0] + , bufferConf.output + , ckNet + , driverFlags + , yoffsetDriver ) + leftSourceX = gaugeConf.getNearestVerticalTrack ( leftSourceContact.getX(), 0, 0 ) if driverY is None: - driverY = leftSourceContact.getY() - leftSourceY = gaugeConf.getNearestHorizontalTrack( driverY, 0, yoffset ) + leftSourceY = gaugeConf.getNearestHorizontalTrack( leftSourceContact.getY(), 0, 0 ) + else: + leftSourceY = driverY leftContact = gaugeConf.createContact( ckNet, leafContact.getX(), leftSourceContact.getY(), 0 ) leftX = gaugeConf.getNearestVerticalTrack( leftContact.getX(), 0 ) gaugeConf.setStackPosition( leftSourceContact, leftSourceX, leftSourceY ) leftContact .setX( leftX ) leftContact .setY( leftSourceY ) - flags = 0 if qt.br or qt.tr: trace( 550, '\tRight branch\n' ) leafContact = brContact if brContact else trContact - rightSourceContact = gaugeConf.rpAccessByPlugName( qt.buffers[0], bufferConf.output, ckNet , GaugeConf.HAccess|flags ) + rightSourceContact = gaugeConf.rpAccessByPlugName( qt.buffers[0] + , bufferConf.output + , ckNet + , driverFlags + , yoffsetDriver ) + rightSourceX = gaugeConf.getNearestVerticalTrack( rightSourceContact.getX(), 0, 0 ) if driverY is None: - driverY = rightSourceContact.getY() - rightSourceX = gaugeConf.getNearestVerticalTrack( rightSourceContact.getX(), 0 ) - rightSourceY = gaugeConf.getNearestHorizontalTrack( driverY, 0, yoffset ) + rightSourceY = gaugeConf.getNearestHorizontalTrack( rightSourceContact.getY(), 0, 0 ) + else: + rightSourceY = driverY rightContact = gaugeConf.createContact( ckNet, leafContact.getX(), rightSourceContact.getY(), 0 ) rightX = gaugeConf.getNearestVerticalTrack( rightContact.getX(), 0 ) gaugeConf.setStackPosition( rightSourceContact, rightSourceX, rightSourceY ) @@ -218,27 +309,31 @@ class HTree ( object ): gaugeConf.createHorizontal( leftContact, leftSourceContact, leftSourceY , 0 ) if qt.br or qt.tr: gaugeConf.createHorizontal( rightSourceContact, rightContact, rightSourceY, 0 ) - if tlContact: - tlY = gaugeConf.getTrack( tlContact.getY(), hLeafDepth, -1 ) - elif trContact: - tlY = gaugeConf.getTrack( trContact.getY(), hLeafDepth, -1 ) - if blContact: - blY = gaugeConf.getTrack( blContact.getY(), hLeafDepth, 2 ) - trace( 550, '\tblY:{}\n'.format( DbU.getValueString(blY) )) - elif brContact: - blY = gaugeConf.getTrack( brContact.getY(), hLeafDepth, 2 ) - trace( 550, '\tblY:{}\n'.format( DbU.getValueString(blY) )) + + #if tlContact: + # tlY = gaugeConf.getTrack( tlContact.getY(), hLeafDepth, yoffsetTopSink ) + #elif trContact: + # tlY = gaugeConf.getTrack( trContact.getY(), hLeafDepth, yoffsetTopSink ) + #if blContact: + # blY = gaugeConf.getTrack( blContact.getY(), hLeafDepth, yoffsetBotSink ) + # trace( 550, '\tblY:{}\n'.format( DbU.getValueString(blY) )) + #elif brContact: + # blY = gaugeConf.getTrack( brContact.getY(), hLeafDepth, yoffsetBotSink ) + # trace( 550, '\tblY:{}\n'.format( DbU.getValueString(blY) )) + if qt.tl: - self._connectLeaf( qt.tl, ckNet, leftContact, tlContact, leftX, tlY ) + self._connectLeaf( qt.tl, ckNet, leftContact, tlContact, leftX, sinkTopY ) 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 ) ) + trace( 550, '\tConnect BL leaf, leftX={} blY={}\n' \ + .format( DbU.getValueString(leftX), DbU.getValueString(sinkBotY) )) + self._connectLeaf( qt.bl, ckNet, leftContact, blContact, leftX, sinkBotY ) + #gaugeConf.addTrackAvoid( Box( leftX, leftSourceY, leftX, sinkBotY ) ) if qt.tr: - self._connectLeaf( qt.tr, ckNet, rightContact, trContact, rightX, tlY ) - #gaugeConf.addTrackAvoid( Box( rightX, rightSourceY, rightX, tlY ) ) + self._connectLeaf( qt.tr, ckNet, rightContact, trContact, rightX, sinkTopY ) + #gaugeConf.addTrackAvoid( Box( rightX, rightSourceY, rightX, si,kTopY ) ) if qt.br: - self._connectLeaf( qt.br, ckNet, rightContact, brContact, rightX, blY ) + self._connectLeaf( qt.br, ckNet, rightContact, brContact, rightX, sinkBotY ) + if qt.isRoot(): ckNet = self.treeNet if not self.spares.conf.isCoreBlock \