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).
This commit is contained in:
Jean-Paul Chaput 2023-08-03 17:01:48 +02:00
parent f29e65d908
commit 49a37addae
3 changed files with 179 additions and 60 deletions

View File

@ -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 )

View File

@ -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

View File

@ -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 \