Added multiple clock support in cumulus/plugins/alpha/block.
* New: Added multiple clock support in H-Tree generation in alpha/block. * New: In CRL/etc/<NODE>/<TECH>/plugins.py, added three new parameters for block plugin config: "block.spareSide" : The size of the minimum side of a buffered area. (quad-tree leaf). "spare.buffer" : The model of the cell buffer to be used. "spare.maxSinks" : max number of sinks on a buffer before issuing a warning (non-blocking). * Bug: In Etesian::BloatCell::getAb(), never apply the bloat profile to fixed cells. In case of buffers from the spare maxtrix it was leading Coloquinte to detect an overlap of fixed cells, which it do not support (rightly so).
This commit is contained in:
parent
38375fd9ae
commit
51e3639687
|
@ -27,3 +27,6 @@ Cfg.getParamInt ( "chip.block.rails.vSpacing" ).setInt ( l( 12) )
|
||||||
Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(1200) )
|
Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(1200) )
|
||||||
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x2')
|
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x2')
|
||||||
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
||||||
|
Cfg.getParamString( 'spares.buffer' ).setString( 'buf_x8')
|
||||||
|
Cfg.getParamInt ( 'spares.maxSinks' ).setInt ( 31 )
|
||||||
|
|
||||||
|
|
|
@ -27,3 +27,6 @@ Cfg.getParamInt ( "chip.block.rails.vSpacing" ).setInt ( l( 12) )
|
||||||
Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(1200) )
|
Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(1200) )
|
||||||
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x2')
|
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x2')
|
||||||
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
||||||
|
Cfg.getParamString( 'spares.buffer' ).setString( 'buf_x8')
|
||||||
|
Cfg.getParamInt ( 'spares.maxSinks' ).setInt ( 31 )
|
||||||
|
|
||||||
|
|
|
@ -27,3 +27,6 @@ Cfg.getParamInt ( "chip.block.rails.vSpacing" ).setInt ( l( 12) )
|
||||||
Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(1200) )
|
Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(1200) )
|
||||||
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x2')
|
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x2')
|
||||||
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
||||||
|
Cfg.getParamString( 'spares.buffer' ).setString( 'buf_x8')
|
||||||
|
Cfg.getParamInt ( 'spares.maxSinks' ).setInt ( 31 )
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,8 @@ p.addValue( "Density" , 2 )
|
||||||
|
|
||||||
p = Cfg.getParamInt ( "katana.hTracksReservedLocal" ); p.setInt ( 3 ); p.setMin(0); p.setMax(20)
|
p = Cfg.getParamInt ( "katana.hTracksReservedLocal" ); p.setInt ( 3 ); p.setMin(0); p.setMax(20)
|
||||||
p = Cfg.getParamInt ( "katana.vTracksReservedLocal" ); p.setInt ( 3 ); p.setMin(0); p.setMax(20)
|
p = Cfg.getParamInt ( "katana.vTracksReservedLocal" ); p.setInt ( 3 ); p.setMin(0); p.setMax(20)
|
||||||
|
p = Cfg.getParamInt ( "katana.hTracksReservedMin" ); p.setInt ( 1 ); p.setMin(0); p.setMax(20)
|
||||||
|
p = Cfg.getParamInt ( "katana.vTracksReservedMin" ); p.setInt ( 1 ); p.setMin(0); p.setMax(20)
|
||||||
p = Cfg.getParamInt ( "katana.termSatReservedLocal" ); p.setInt ( 8 )
|
p = Cfg.getParamInt ( "katana.termSatReservedLocal" ); p.setInt ( 8 )
|
||||||
p = Cfg.getParamInt ( "katana.termSatThreshold" ); p.setInt ( 9 )
|
p = Cfg.getParamInt ( "katana.termSatThreshold" ); p.setInt ( 9 )
|
||||||
p = Cfg.getParamInt ( "katana.eventsLimit" ); p.setInt ( 4000002 )
|
p = Cfg.getParamInt ( "katana.eventsLimit" ); p.setInt ( 4000002 )
|
||||||
|
|
|
@ -28,3 +28,6 @@ Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(600) )
|
||||||
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x2')
|
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x2')
|
||||||
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
||||||
Cfg.getParamInt ( 'block.spareSide' ).setInt ( 10 )
|
Cfg.getParamInt ( 'block.spareSide' ).setInt ( 10 )
|
||||||
|
Cfg.getParamString( 'spares.buffer' ).setString( 'buf_x8')
|
||||||
|
Cfg.getParamInt ( 'spares.maxSinks' ).setInt ( 31 )
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,8 @@ p = Cfg.getParamInt ( "katana.searchHalo" ); p.setInt ( 1 )
|
||||||
p = Cfg.getParamInt ( "katana.hTracksReservedLocal" ); p.setInt ( 3 ); p.setMin(0); p.setMax(20)
|
p = Cfg.getParamInt ( "katana.hTracksReservedLocal" ); p.setInt ( 3 ); p.setMin(0); p.setMax(20)
|
||||||
p = Cfg.getParamInt ( "katana.vTracksReservedLocal" ); p.setInt ( 3 ); p.setMin(0); p.setMax(20)
|
p = Cfg.getParamInt ( "katana.vTracksReservedLocal" ); p.setInt ( 3 ); p.setMin(0); p.setMax(20)
|
||||||
p = Cfg.getParamInt ( "katana.termSatReservedLocal" ); p.setInt ( 8 )
|
p = Cfg.getParamInt ( "katana.termSatReservedLocal" ); p.setInt ( 8 )
|
||||||
|
p = Cfg.getParamInt ( "katana.hTracksReservedMin" ); p.setInt ( 1 ); p.setMin(0); p.setMax(20)
|
||||||
|
p = Cfg.getParamInt ( "katana.vTracksReservedMin" ); p.setInt ( 1 ); p.setMin(0); p.setMax(20)
|
||||||
p = Cfg.getParamInt ( "katana.termSatThreshold" ); p.setInt ( 9 )
|
p = Cfg.getParamInt ( "katana.termSatThreshold" ); p.setInt ( 9 )
|
||||||
p = Cfg.getParamInt ( "katana.eventsLimit" ); p.setInt ( 4000002 )
|
p = Cfg.getParamInt ( "katana.eventsLimit" ); p.setInt ( 4000002 )
|
||||||
p = Cfg.getParamInt ( "katana.ripupCost" ); p.setInt ( 3 ); p.setMin(0)
|
p = Cfg.getParamInt ( "katana.ripupCost" ); p.setInt ( 3 ); p.setMin(0)
|
||||||
|
@ -74,10 +76,86 @@ p = Cfg.getParamInt ( "katana.localRipupLimit" ); p.setInt ( 9 );
|
||||||
p = Cfg.getParamInt ( "katana.globalRipupLimit" ); p.setInt ( 5 ); p.setMin(1)
|
p = Cfg.getParamInt ( "katana.globalRipupLimit" ); p.setInt ( 5 ); p.setMin(1)
|
||||||
p = Cfg.getParamInt ( "katana.longGlobalRipupLimit" ); p.setInt ( 5 ); p.setMin(1)
|
p = Cfg.getParamInt ( "katana.longGlobalRipupLimit" ); p.setInt ( 5 ); p.setMin(1)
|
||||||
p = Cfg.getParamString( 'chip.padCoreSide' ); p.setString( 'South' )
|
p = Cfg.getParamString( 'chip.padCoreSide' ); p.setString( 'South' )
|
||||||
|
p = Cfg.getParamInt ( "block.spareSide" ); p.setInt ( l(2000) )
|
||||||
|
|
||||||
|
|
||||||
tech = DataBase.getDB().getTechnology()
|
tech = DataBase.getDB().getTechnology()
|
||||||
af = AllianceFramework.get()
|
af = AllianceFramework.get()
|
||||||
|
rg = RoutingGauge.create( 'msxlib_uniform' )
|
||||||
|
|
||||||
|
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL1') # metal.
|
||||||
|
, RoutingLayerGauge.Vertical # preferred routing direction.
|
||||||
|
, RoutingLayerGauge.PinOnly # layer usage.
|
||||||
|
, 0 # depth.
|
||||||
|
, 0.0 # density (deprecated).
|
||||||
|
, l(0) # track offset from AB.
|
||||||
|
, l(10) # track pitch.
|
||||||
|
, l(3) # wire width.
|
||||||
|
, l(2) # VIA side (that is VIA12).
|
||||||
|
, l(7) # obstacle dW.
|
||||||
|
) )
|
||||||
|
|
||||||
|
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL2') # metal.
|
||||||
|
, RoutingLayerGauge.Horizontal # preferred routing direction.
|
||||||
|
, RoutingLayerGauge.Default # layer usage.
|
||||||
|
, 1 # depth.
|
||||||
|
, 0.0 # density (deprecated).
|
||||||
|
, l(0) # track offset from AB.
|
||||||
|
, l(10) # track pitch.
|
||||||
|
, l(3) # wire width.
|
||||||
|
, l(2) # VIA side (that is VIA23).
|
||||||
|
, l(8) # obstacle dW.
|
||||||
|
) )
|
||||||
|
|
||||||
|
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL3') # metal.
|
||||||
|
, RoutingLayerGauge.Vertical # preferred routing direction.
|
||||||
|
, RoutingLayerGauge.Default # layer usage.
|
||||||
|
, 2 # depth.
|
||||||
|
, 0.0 # density (deprecated).
|
||||||
|
, l(0) # track offset from AB.
|
||||||
|
, l(10) # track pitch.
|
||||||
|
, l(3) # wire width.
|
||||||
|
, l(2) # VIA side (that is VIA34).
|
||||||
|
, l(8) # obstacle dW.
|
||||||
|
) )
|
||||||
|
|
||||||
|
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL4') # metal.
|
||||||
|
, RoutingLayerGauge.Horizontal # preferred routing direction.
|
||||||
|
, RoutingLayerGauge.Default # layer usage.
|
||||||
|
, 3 # depth.
|
||||||
|
, 0.0 # density (deprecated).
|
||||||
|
, l(0) # track offset from AB.
|
||||||
|
, l(10) # track pitch.
|
||||||
|
, l(3) # wire width.
|
||||||
|
, l(2) # VIA side (that is VIA23).
|
||||||
|
, l(8) # obstacle dW.
|
||||||
|
) )
|
||||||
|
|
||||||
|
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL5') # metal.
|
||||||
|
, RoutingLayerGauge.Vertical # preferred routing direction.
|
||||||
|
, RoutingLayerGauge.Default # layer usage.
|
||||||
|
, 4 # depth.
|
||||||
|
, 0.0 # density (deprecated).
|
||||||
|
, l(0) # track offset from AB.
|
||||||
|
, l(10) # track pitch.
|
||||||
|
, l(3) # wire width.
|
||||||
|
, l(2) # VIA side (that is VIA23).
|
||||||
|
, l(8) # obstacle dW.
|
||||||
|
) )
|
||||||
|
|
||||||
|
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL6') # metal.
|
||||||
|
, RoutingLayerGauge.Horizontal # preferred routing direction.
|
||||||
|
, RoutingLayerGauge.Default # layer usage.
|
||||||
|
, 5 # depth.
|
||||||
|
, 0.0 # density (deprecated).
|
||||||
|
, l(0) # track offset from AB.
|
||||||
|
, l(10) # track pitch.
|
||||||
|
, l(3) # wire width.
|
||||||
|
, l(2) # VIA side (that is VIA23).
|
||||||
|
, l(8) # obstacle dW.
|
||||||
|
) )
|
||||||
|
|
||||||
|
af.addRoutingGauge( rg )
|
||||||
rg = RoutingGauge.create( 'msxlib' )
|
rg = RoutingGauge.create( 'msxlib' )
|
||||||
|
|
||||||
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL1') # metal.
|
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL1') # metal.
|
||||||
|
@ -237,6 +315,13 @@ af.addRoutingGauge( rg )
|
||||||
af.setRoutingGauge( 'msxlib' )
|
af.setRoutingGauge( 'msxlib' )
|
||||||
|
|
||||||
# Gauge for standard cells.
|
# Gauge for standard cells.
|
||||||
|
cg = CellGauge.create( 'msxlib_uniform'
|
||||||
|
, 'metal2' # pin layer name.
|
||||||
|
, l( 10.0) # pitch.
|
||||||
|
, l(100.0) # cell slice height.
|
||||||
|
, l( 10.0) # cell slice step.
|
||||||
|
)
|
||||||
|
af.addCellGauge( cg )
|
||||||
cg = CellGauge.create( 'msxlib'
|
cg = CellGauge.create( 'msxlib'
|
||||||
, 'metal2' # pin layer name.
|
, 'metal2' # pin layer name.
|
||||||
, l( 10.0) # pitch.
|
, l( 10.0) # pitch.
|
||||||
|
|
|
@ -25,5 +25,7 @@ Cfg.getParamInt ( "chip.block.rails.vWidth" ).setInt ( l( 24) )
|
||||||
Cfg.getParamInt ( "chip.block.rails.hSpacing" ).setInt ( l( 12) )
|
Cfg.getParamInt ( "chip.block.rails.hSpacing" ).setInt ( l( 12) )
|
||||||
Cfg.getParamInt ( "chip.block.rails.vSpacing" ).setInt ( l( 12) )
|
Cfg.getParamInt ( "chip.block.rails.vSpacing" ).setInt ( l( 12) )
|
||||||
Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(1200) )
|
Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(1200) )
|
||||||
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x2')
|
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x8')
|
||||||
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
||||||
|
Cfg.getParamString( 'spares.buffer' ).setString( 'buf_x8')
|
||||||
|
Cfg.getParamInt ( 'spares.maxSinks' ).setInt ( 31 )
|
||||||
|
|
|
@ -173,6 +173,9 @@ class Side ( object ):
|
||||||
if net is None:
|
if net is None:
|
||||||
print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] ))
|
print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] ))
|
||||||
continue
|
continue
|
||||||
|
if net.isClock() and self.block.state.useClockTree:
|
||||||
|
print( WarningMessage( 'Side.place(IoPin): Skipping clock IoPin "{}".'.format(pinName) ))
|
||||||
|
continue
|
||||||
pinName += '.{}'.format(self.block.state.getIoPinsCounts(net))
|
pinName += '.{}'.format(self.block.state.getIoPinsCounts(net))
|
||||||
pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep )
|
pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep )
|
||||||
if pinPos.getX() > self.block.state.xMax or pinPos.getX() < self.block.state.xMin:
|
if pinPos.getX() > self.block.state.xMax or pinPos.getX() < self.block.state.xMin:
|
||||||
|
@ -371,19 +374,25 @@ class Block ( object ):
|
||||||
self.state.cfg.apply()
|
self.state.cfg.apply()
|
||||||
for side in self.sides.values(): side.setupAb()
|
for side in self.sides.values(): side.setupAb()
|
||||||
|
|
||||||
def addClockTree ( self, clockNet=None ):
|
def addClockTrees ( self ):
|
||||||
"""Create the trunk of the clock tree (recursive H-Tree)."""
|
"""Create the trunk of all the clock trees (recursive H-Tree)."""
|
||||||
if not clockNet:
|
print( ' o Buildding clock tree(s).' )
|
||||||
|
af = CRL.AllianceFramework.get()
|
||||||
|
clockNets = []
|
||||||
for net in self.state.cell.getNets():
|
for net in self.state.cell.getNets():
|
||||||
|
if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net)
|
||||||
if net.isClock():
|
if net.isClock():
|
||||||
clockNet = net
|
trace( 550, '\tBlock.addClockTrees(): Found clock {}.\n'.format(net) )
|
||||||
break
|
clockNets.append( net )
|
||||||
if not clockNet:
|
if not clockNets:
|
||||||
raise ErrorMessage( 3, 'Block.clockTree(): Cell "{}" has no clock net.'.format(self.state.cell.getName()) )
|
raise ErrorMessage( 3, 'Block.clockTree(): Cell "{}" has no clock net(s).'.format(self.state.cell.getName()) )
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
self.clockTrees.append( ClockTree(self.spares,clockNet) )
|
for clockNet in clockNets:
|
||||||
|
print( ' - "{}".'.format(clockNet.getName()) )
|
||||||
|
trace( 550, ',+', '\tBlock.addClockTrees(): Build clock tree for {}.\n'.format(clockNet) )
|
||||||
|
self.clockTrees.append( ClockTree(self.spares,clockNet,len(self.clockTrees)) )
|
||||||
self.clockTrees[-1].buildHTree()
|
self.clockTrees[-1].buildHTree()
|
||||||
return self.clockTrees[-1]
|
trace( 550, '-' )
|
||||||
|
|
||||||
def splitClocks ( self ):
|
def splitClocks ( self ):
|
||||||
"""
|
"""
|
||||||
|
@ -428,6 +437,10 @@ class Block ( object ):
|
||||||
.format(net.getName() )))
|
.format(net.getName() )))
|
||||||
|
|
||||||
def expandIoPins ( self ):
|
def expandIoPins ( self ):
|
||||||
|
"""
|
||||||
|
Stick out the block I/O pins of one pitch on all sides.
|
||||||
|
See setUnexpandPins() to prevent it to happen on a specific side.
|
||||||
|
"""
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
for side in self.sides.values():
|
for side in self.sides.values():
|
||||||
side.expand()
|
side.expand()
|
||||||
|
@ -502,7 +515,8 @@ class Block ( object ):
|
||||||
self.checkIoPins()
|
self.checkIoPins()
|
||||||
self.spares.build()
|
self.spares.build()
|
||||||
if editor: editor.fit()
|
if editor: editor.fit()
|
||||||
if self.state.useClockTree: self.addClockTree()
|
if self.state.useClockTree: self.addClockTrees()
|
||||||
|
#Breakpoint.stop( 0, 'Clock tree(s) done.' )
|
||||||
self.place()
|
self.place()
|
||||||
if self.state.useClockTree: self.splitClocks()
|
if self.state.useClockTree: self.splitClocks()
|
||||||
status = self.route()
|
status = self.route()
|
||||||
|
|
|
@ -44,6 +44,7 @@ from helpers.overlay import UpdateSession
|
||||||
from plugins import getParameter
|
from plugins import getParameter
|
||||||
from plugins import utils
|
from plugins import utils
|
||||||
from plugins.alpha.block.configuration import GaugeConf
|
from plugins.alpha.block.configuration import GaugeConf
|
||||||
|
from plugins.alpha.block.spares import Spares
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
@ -54,51 +55,54 @@ class ClockTree ( object ):
|
||||||
Build a clock tree on a block.
|
Build a clock tree on a block.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__ ( self, spares, clockNet ):
|
def __init__ ( self, spares, clockNet, index ):
|
||||||
self.spares = spares
|
self.spares = spares
|
||||||
self.clockNet = clockNet
|
self.clockNet = clockNet
|
||||||
|
self.clockIndex = index
|
||||||
|
if not self.clockNet.isClock():
|
||||||
print( WarningMessage( 'ClockTree.__init__(): Net "{}" is not of CLOCK type.' \
|
print( WarningMessage( 'ClockTree.__init__(): Net "{}" is not of CLOCK type.' \
|
||||||
.format(self.clockNet.getName()) ))
|
.format(self.clockNet.getName()) ))
|
||||||
|
|
||||||
def _rconnectHTree ( self, quadTree ):
|
def _rconnectHTree ( self, qt ):
|
||||||
if quadTree.isLeaf(): return False
|
if qt.isLeaf(): return False
|
||||||
driverNet = quadTree.bOutputPlug.getNet()
|
qt.rconnectBuffer()
|
||||||
for leaf in quadTree.leafs:
|
driverNet = qt.bOutputPlug.getNet()
|
||||||
|
for leaf in qt.leafs:
|
||||||
leaf.bInputPlug.setNet( driverNet )
|
leaf.bInputPlug.setNet( driverNet )
|
||||||
self._rconnectHTree( leaf )
|
self._rconnectHTree( leaf )
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _rrouteHTree ( self, quadT ):
|
def _rrouteHTree ( self, qt ):
|
||||||
"""
|
"""
|
||||||
Recursively build one HTree branch for all non-terminal nodes of the QuadTree.
|
Recursively build one HTree branch for all non-terminal nodes of the QuadTree.
|
||||||
"""
|
"""
|
||||||
trace( 550, ',+', '\tClockTree._rrouteHTree() {}\n'.format(quadT.bOutputPlug.getNet()) )
|
trace( 550, ',+', '\tClockTree._rrouteHTree() {}\n'.format(qt.bOutputPlug.getNet()) )
|
||||||
if quadT.isLeaf():
|
trace( 550, '\tOn: {}\n'.format(qt) )
|
||||||
|
if qt.isLeaf():
|
||||||
trace( 550, '-' )
|
trace( 550, '-' )
|
||||||
return False
|
return False
|
||||||
|
|
||||||
gaugeConf = self.spares.state.gaugeConf
|
gaugeConf = self.spares.state.gaugeConf
|
||||||
bufferConf = self.spares.state.bufferConf
|
bufferConf = self.spares.state.bufferConf
|
||||||
ckNet = quadT.bOutputPlug.getNet()
|
ckNet = qt.bOutputPlug.getNet()
|
||||||
|
|
||||||
leftSourceContact = gaugeConf.rpAccessByPlugName( quadT.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
|
leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
|
||||||
rightSourceContact = gaugeConf.rpAccessByPlugName( quadT.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
|
rightSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
|
||||||
blContact = gaugeConf.rpAccessByPlugName( quadT.bl.buffer, bufferConf.input , ckNet )
|
blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffer, bufferConf.input , ckNet )
|
||||||
brContact = gaugeConf.rpAccessByPlugName( quadT.br.buffer, bufferConf.input , ckNet )
|
brContact = gaugeConf.rpAccessByPlugName( qt.br.buffer, bufferConf.input , ckNet )
|
||||||
tlContact = gaugeConf.rpAccessByPlugName( quadT.tl.buffer, bufferConf.input , ckNet )
|
tlContact = gaugeConf.rpAccessByPlugName( qt.tl.buffer, bufferConf.input , ckNet )
|
||||||
trContact = gaugeConf.rpAccessByPlugName( quadT.tr.buffer, bufferConf.input , ckNet )
|
trContact = gaugeConf.rpAccessByPlugName( qt.tr.buffer, bufferConf.input , ckNet )
|
||||||
leftContact = gaugeConf.createContact( ckNet, blContact.getX(), leftSourceContact.getY(), 0 )
|
leftContact = gaugeConf.createContact( ckNet, blContact.getX(), leftSourceContact.getY(), 0 )
|
||||||
rightContact = gaugeConf.createContact( ckNet, brContact.getX(), rightSourceContact.getY(), 0 )
|
rightContact = gaugeConf.createContact( ckNet, brContact.getX(), rightSourceContact.getY(), 0 )
|
||||||
|
|
||||||
leftSourceX = gaugeConf.getNearestVerticalTrack ( quadT.root.area, leftSourceContact.getX(), 0 )
|
leftSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, leftSourceContact.getX(), 0 )
|
||||||
leftSourceY = gaugeConf.getNearestHorizontalTrack( quadT.root.area, leftSourceContact.getY(), 0 )
|
leftSourceY = gaugeConf.getNearestHorizontalTrack( qt.root.area, leftSourceContact.getY(), 0 )
|
||||||
rightSourceX = gaugeConf.getNearestVerticalTrack ( quadT.root.area, rightSourceContact.getX(), 0 )
|
rightSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, rightSourceContact.getX(), 0 )
|
||||||
rightSourceY = gaugeConf.getNearestHorizontalTrack( quadT.root.area, rightSourceContact.getY(), 0 )
|
rightSourceY = gaugeConf.getNearestHorizontalTrack( qt.root.area, rightSourceContact.getY(), 0 )
|
||||||
leftX = gaugeConf.getNearestVerticalTrack ( quadT.root.area, leftContact.getX(), 0 )
|
leftX = gaugeConf.getNearestVerticalTrack ( qt.root.area, leftContact.getX(), 0 )
|
||||||
rightX = gaugeConf.getNearestVerticalTrack ( quadT.root.area, rightContact.getX(), 0 )
|
rightX = gaugeConf.getNearestVerticalTrack ( qt.root.area, rightContact.getX(), 0 )
|
||||||
tlY = gaugeConf.getNearestHorizontalTrack( quadT.root.area, tlContact.getY(), 0 )
|
tlY = gaugeConf.getNearestHorizontalTrack( qt.root.area, tlContact.getY(), 0 )
|
||||||
blY = gaugeConf.getNearestHorizontalTrack( quadT.root.area, blContact.getY(), 0 )
|
blY = gaugeConf.getNearestHorizontalTrack( qt.root.area, blContact.getY(), 0 )
|
||||||
|
|
||||||
gaugeConf.setStackPosition( leftSourceContact, leftSourceX, leftSourceY )
|
gaugeConf.setStackPosition( leftSourceContact, leftSourceX, leftSourceY )
|
||||||
gaugeConf.setStackPosition( rightSourceContact, rightSourceX, rightSourceY )
|
gaugeConf.setStackPosition( rightSourceContact, rightSourceX, rightSourceY )
|
||||||
|
@ -119,7 +123,33 @@ class ClockTree ( object ):
|
||||||
gaugeConf.createVertical ( rightContact , brContact , rightX , 0 )
|
gaugeConf.createVertical ( rightContact , brContact , rightX , 0 )
|
||||||
gaugeConf.createVertical ( trContact , rightContact , rightX , 0 )
|
gaugeConf.createVertical ( trContact , rightContact , rightX , 0 )
|
||||||
|
|
||||||
for leaf in quadT.leafs:
|
if qt.isRoot():
|
||||||
|
ckNet = self.clockNet
|
||||||
|
trace( 550, '\tRemoving any previous pin...\n' )
|
||||||
|
pins = []
|
||||||
|
for pin in ckNet.getPins(): pins.append( pin )
|
||||||
|
for pin in pins:
|
||||||
|
print( WarningMessage('ClockTree._rrouteHTree(): Removing {}.'.format(pin)) )
|
||||||
|
pin.destroy()
|
||||||
|
|
||||||
|
layerGauge = gaugeConf.vRoutingGauge
|
||||||
|
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
|
||||||
|
x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 )
|
||||||
|
y = gaugeConf.getNearestHorizontalTrack( qt.area, rootContact.getY(), 0 )
|
||||||
|
rootPin = Pin.create( ckNet
|
||||||
|
, ckNet.getName()+'.0'
|
||||||
|
, Pin.Direction.NORTH
|
||||||
|
, Pin.PlacementStatus.FIXED
|
||||||
|
, layerGauge.getLayer()
|
||||||
|
, x
|
||||||
|
, qt.area.getYMax()
|
||||||
|
, layerGauge.getViaWidth()
|
||||||
|
, layerGauge.getViaWidth()
|
||||||
|
)
|
||||||
|
gaugeConf.setStackPosition( rootContact, x, y )
|
||||||
|
gaugeConf.createVertical( rootContact, rootPin, x, 0 )
|
||||||
|
|
||||||
|
for leaf in qt.leafs:
|
||||||
self._rrouteHTree( leaf )
|
self._rrouteHTree( leaf )
|
||||||
trace( 550, '-' )
|
trace( 550, '-' )
|
||||||
return True
|
return True
|
||||||
|
@ -131,12 +161,12 @@ class ClockTree ( object ):
|
||||||
2. Detach the all the clock sink point and reconnect them to the
|
2. Detach the all the clock sink point and reconnect them to the
|
||||||
buffers of the leafs of the QuadTree.
|
buffers of the leafs of the QuadTree.
|
||||||
"""
|
"""
|
||||||
quadTree = self.spares.quadTree
|
qt = self.spares.quadTree
|
||||||
quadTree.bufferTag = self.clockNet.getName()
|
qt.bufferTag = self.clockNet.getName()
|
||||||
quadTree.ruseBuffer()
|
qt.rselectBuffer( self.clockIndex, self.clockIndex, Spares.CHECK_USED|Spares.MARK_USED)
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
self._rconnectHTree( quadTree )
|
self._rconnectHTree( qt )
|
||||||
self._rrouteHTree ( quadTree )
|
self._rrouteHTree ( qt )
|
||||||
|
|
||||||
def splitClock ( self ):
|
def splitClock ( self ):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -356,7 +356,11 @@ class GaugeConf ( object ):
|
||||||
segment = component
|
segment = component
|
||||||
count += 1
|
count += 1
|
||||||
if count > 1:
|
if count > 1:
|
||||||
raise ErrorMessage( 1, 'GaugeConf::_setStackPosition(): There must be exactly one segment connected to %s, not %d.' % (topContact,count) )
|
message = [ 'GaugeConf::_setStackPosition(): There must be exactly one segment connected to contact, not {}.'.format(count)
|
||||||
|
, '+ {}'.format(topContact) ]
|
||||||
|
for component in topContact.getSlaveComponents():
|
||||||
|
message.append( '| {}'.format(component) )
|
||||||
|
raise ErrorMessage( 1, message )
|
||||||
|
|
||||||
if count == 1:
|
if count == 1:
|
||||||
if isinstance(segment,Horizontal):
|
if isinstance(segment,Horizontal):
|
||||||
|
@ -375,14 +379,16 @@ class BufferInterface ( object ):
|
||||||
|
|
||||||
def __init__ ( self, framework ):
|
def __init__ ( self, framework ):
|
||||||
trace( 550, ',+', '\tBufferInterface.__init__()\n' )
|
trace( 550, ',+', '\tBufferInterface.__init__()\n' )
|
||||||
self.masterCell = framework.getCell( Cfg.getParamString('clockTree.buffer').asString()
|
self.maxSinks = Cfg.getParamInt('spares.maxSinks').asInt()
|
||||||
|
self.masterCell = framework.getCell( Cfg.getParamString('spares.buffer').asString()
|
||||||
, CRL.Catalog.State.Views )
|
, CRL.Catalog.State.Views )
|
||||||
if not self.masterCell:
|
if not self.masterCell:
|
||||||
trace( 550, '-' )
|
trace( 550, '-' )
|
||||||
raise ErrorMessage( 3, [ 'ClockTree: Buffer cell "{}" not found in library,' \
|
raise ErrorMessage( 3, [ 'ClockTree: Buffer cell "{}" not found in library,' \
|
||||||
.format(Cfg.getParamString('clockTree.buffer').asString())
|
.format(Cfg.getParamString('spares.buffer').asString())
|
||||||
, ' please check the "clockTree.buffer" configuration parameter in "plugins.conf".' ] )
|
, ' please check the "spares.buffer" configuration parameter in "plugins.conf".' ] )
|
||||||
trace( 550, '\tmasterCell :<{}>\n'.format(self.masterCell) )
|
trace( 550, '\t| masterCell :{}\n'.format(self.masterCell) )
|
||||||
|
trace( 550, '\t| maximum sinks:{}\n'.format(self.maxSinks) )
|
||||||
|
|
||||||
self.count = 0
|
self.count = 0
|
||||||
self.input = None
|
self.input = None
|
||||||
|
@ -393,8 +399,8 @@ class BufferInterface ( object ):
|
||||||
if net.getDirection() & Net.Direction.IN: self.input = net.getName()
|
if net.getDirection() & Net.Direction.IN: self.input = net.getName()
|
||||||
elif net.getDirection() & Net.Direction.OUT: self.output = net.getName()
|
elif net.getDirection() & Net.Direction.OUT: self.output = net.getName()
|
||||||
|
|
||||||
trace( 550, '\tinput :<{}>\n'.format(self.input ) )
|
trace( 550, '\t| input :"{}"\n'.format(self.input ) )
|
||||||
trace( 550, '\toutput:<{}>\n'.format(self.output) )
|
trace( 550, '\t| output :"{}"\n'.format(self.output) )
|
||||||
trace( 550, '-' )
|
trace( 550, '-' )
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -575,9 +581,11 @@ class BlockState ( object ):
|
||||||
def __init__ ( self, cell, ioPins=[] ):
|
def __init__ ( self, cell, ioPins=[] ):
|
||||||
self.editor = None
|
self.editor = None
|
||||||
self.framework = CRL.AllianceFramework.get()
|
self.framework = CRL.AllianceFramework.get()
|
||||||
self.cfg = CfgCache('')
|
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
|
||||||
self.gaugeConf = GaugeConf()
|
self.gaugeConf = GaugeConf()
|
||||||
self.bufferConf = BufferInterface( self.framework )
|
self.bufferConf = BufferInterface( self.framework )
|
||||||
|
self.bColumns = 2
|
||||||
|
self.bRows = 2
|
||||||
self.cell = cell
|
self.cell = cell
|
||||||
self.fixedWidth = None
|
self.fixedWidth = None
|
||||||
self.fixedHeight = None
|
self.fixedHeight = None
|
||||||
|
|
|
@ -46,6 +46,116 @@ from plugins.alpha import utils
|
||||||
framework = CRL.AllianceFramework.get()
|
framework = CRL.AllianceFramework.get()
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Class : "spares.BufferPool".
|
||||||
|
|
||||||
|
class BufferPool ( object ):
|
||||||
|
"""
|
||||||
|
Manage a matrix of buffer and their allocations. One pool is created
|
||||||
|
at the center of each QuadTree level (both terminal and non-terminal).
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__ ( self, quadTree ):
|
||||||
|
self.quadTree = quadTree
|
||||||
|
self.columns = quadTree.spares.state.bColumns
|
||||||
|
self.rows = quadTree.spares.state.bRows
|
||||||
|
self.buffers = []
|
||||||
|
self.selectedIndex = None
|
||||||
|
for i in range(self.rows*self.columns):
|
||||||
|
self.buffers.append( [ 0, None ] )
|
||||||
|
self._createBuffers()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def selected ( self ):
|
||||||
|
"""
|
||||||
|
Returns the selected buffer instance within the pool. Selection is to
|
||||||
|
be made with either select() or selectFree().
|
||||||
|
"""
|
||||||
|
if self.selectedIndex is None:
|
||||||
|
raise ErrorMessage( 3, 'BufferPool.selected: No buffer has been selected yet.' )
|
||||||
|
return self.buffers[ self.selectedIndex ][ 1 ]
|
||||||
|
|
||||||
|
def toIndex ( self, column, row ): return column + row*self.columns
|
||||||
|
|
||||||
|
def fromIndex ( self, index ): return (index%self.columns, index/self.columns)
|
||||||
|
|
||||||
|
def select ( self, column, row, flags=0 ):
|
||||||
|
"""
|
||||||
|
Select a specific buffer in the pool matrix. The ``flags`` arguments are
|
||||||
|
used to specify additional checks & actions. Flags operations are done by
|
||||||
|
the low level function _select(). To actually access the selected buffer,
|
||||||
|
use the selected property.
|
||||||
|
|
||||||
|
:param column: The colum of the buffer (aka X).
|
||||||
|
:param row: The row of the buffer (aka Y).
|
||||||
|
:param flags: A combination of flags, defined in the Spares object.
|
||||||
|
|
||||||
|
Flags can be used to:
|
||||||
|
|
||||||
|
* CHECK_USED, raise an error if the designated buffer is already used.
|
||||||
|
* MARK_USED, tag the designated buffer as USED.
|
||||||
|
"""
|
||||||
|
|
||||||
|
trace( 550, ',+', '\tBufferPool.select() column:{}, row={}, flags={:x}\n' \
|
||||||
|
.format(column,row,flags) )
|
||||||
|
if column >= self.columns:
|
||||||
|
trace( 550, '-' )
|
||||||
|
raise ErrorMessage( 3, 'BufferPool.select(): Column {} is out of range (max:{}).' \
|
||||||
|
.format(column,self.columns) )
|
||||||
|
if row >= self.rows:
|
||||||
|
trace( 550, '-' )
|
||||||
|
raise ErrorMessage( 3, 'BufferPool.select(): Row {} is out of range (max:{}).' \
|
||||||
|
.format(row,self.rows) )
|
||||||
|
self._select( self.toIndex( column, row ), flags )
|
||||||
|
trace( 550, '-' )
|
||||||
|
|
||||||
|
def _select ( self, index, flags ):
|
||||||
|
self.selectedIndex = index
|
||||||
|
selectedBuffer = self.buffers[ self.selectedIndex ]
|
||||||
|
if flags & Spares.CHECK_USED and selectedBuffer[0] & Spares.USED:
|
||||||
|
raise ErrorMessage( 3, 'BufferPool.select(): Buffer a index {} is already used.' \
|
||||||
|
.format(self.selectedIndex) )
|
||||||
|
if flags & Spares.MARK_USED:
|
||||||
|
selectedBuffer[0] |= Spares.USED
|
||||||
|
|
||||||
|
def selectFree ( self ):
|
||||||
|
"""Select the first free buffer available."""
|
||||||
|
for i in range(self.rows*self.columns):
|
||||||
|
if not (self.buffers[i][0] & Spares.USED):
|
||||||
|
self._select( i, Spares.MARK_USED )
|
||||||
|
|
||||||
|
def _createBuffers ( self ):
|
||||||
|
"""Create the matrix of instances buffer."""
|
||||||
|
trace( 550, ',+', '\tBufferPool.createBuffers()\n' )
|
||||||
|
|
||||||
|
state = self.quadTree.spares.state
|
||||||
|
sliceHeight = state.gaugeConf.sliceHeight
|
||||||
|
x = self.quadTree.onXPitch( self.quadTree.area.getXCenter()
|
||||||
|
- (state.bufferConf.width * self.columns)/2 )
|
||||||
|
y = self.quadTree.onYSlice( self.quadTree.area.getYCenter()
|
||||||
|
- (state.bufferConf.height * self.rows)/2 )
|
||||||
|
slice = y / sliceHeight
|
||||||
|
|
||||||
|
trace( 550, '\tSlice height: {}\n'.format(DbU.getValueString(sliceHeight)) )
|
||||||
|
|
||||||
|
for row in range(self.rows):
|
||||||
|
orientation = Transformation.Orientation.ID
|
||||||
|
y = (slice+row) * sliceHeight
|
||||||
|
if (slice+row)%2:
|
||||||
|
orientation = Transformation.Orientation.MY
|
||||||
|
y += sliceHeight
|
||||||
|
for column in range(self.columns):
|
||||||
|
index = self.toIndex(column,row)
|
||||||
|
transf = Transformation( x + column*state.bufferConf.width, y, orientation )
|
||||||
|
instance = state.createBuffer()
|
||||||
|
instance.setTransformation( transf )
|
||||||
|
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||||
|
self.buffers[ index ][1] = instance
|
||||||
|
trace( 550, '\tBuffer[{}]: {} @{}\n'.format(index,self.buffers[index],transf) )
|
||||||
|
trace( 550, '-' )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# Class : "spares.QuadTree".
|
# Class : "spares.QuadTree".
|
||||||
|
|
||||||
|
@ -61,7 +171,6 @@ class QuadTree ( object ):
|
||||||
def create ( spares ):
|
def create ( spares ):
|
||||||
root = QuadTree( spares, None, spares.state.cell.getAbutmentBox() )
|
root = QuadTree( spares, None, spares.state.cell.getAbutmentBox() )
|
||||||
root.rpartition()
|
root.rpartition()
|
||||||
root.rcreateBuffers()
|
|
||||||
return root
|
return root
|
||||||
|
|
||||||
def __init__ ( self, spares, parent, area, rtag='root' ):
|
def __init__ ( self, spares, parent, area, rtag='root' ):
|
||||||
|
@ -74,16 +183,23 @@ class QuadTree ( object ):
|
||||||
self.br = None
|
self.br = None
|
||||||
self.tl = None
|
self.tl = None
|
||||||
self.tr = None
|
self.tr = None
|
||||||
self.buseds = 0
|
|
||||||
self.bufferTag = 'spare'
|
self.bufferTag = 'spare'
|
||||||
self.bufferNet = None
|
self.bufferNet = None
|
||||||
self.buffers = []
|
self.pool = BufferPool( self )
|
||||||
self.plugs = []
|
self.plugs = []
|
||||||
if self.parent and self.parent.rtag != '':
|
if self.parent and self.parent.rtag != '':
|
||||||
self.rtag = self.parent.rtag + '_' + rtag
|
self.rtag = self.parent.rtag + '_' + rtag
|
||||||
else:
|
else:
|
||||||
self.rtag = rtag
|
self.rtag = rtag
|
||||||
|
|
||||||
|
def __str__ ( self ):
|
||||||
|
s = '<QuadTree [{},{} {},{}] "{}">'.format( DbU.getValueString(self.area.getXMin())
|
||||||
|
, DbU.getValueString(self.area.getYMin())
|
||||||
|
, DbU.getValueString(self.area.getXMax())
|
||||||
|
, DbU.getValueString(self.area.getYMax())
|
||||||
|
, self.rtag )
|
||||||
|
return s
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def leafs ( self ):
|
def leafs ( self ):
|
||||||
activeLeafs = []
|
activeLeafs = []
|
||||||
|
@ -101,6 +217,9 @@ class QuadTree ( object ):
|
||||||
def isHBipart ( self ): return self.ycut is None
|
def isHBipart ( self ): return self.ycut is None
|
||||||
def isVBipart ( self ): return self.xcut is None
|
def isVBipart ( self ): return self.xcut is None
|
||||||
|
|
||||||
|
def isRoot ( self ):
|
||||||
|
return self.parent is None
|
||||||
|
|
||||||
def isLeaf ( self ):
|
def isLeaf ( self ):
|
||||||
for leaf in (self.bl, self.br, self.tl, self.tr):
|
for leaf in (self.bl, self.br, self.tl, self.tr):
|
||||||
if leaf is not None: return False
|
if leaf is not None: return False
|
||||||
|
@ -109,7 +228,7 @@ class QuadTree ( object ):
|
||||||
@property
|
@property
|
||||||
def buffer ( self ):
|
def buffer ( self ):
|
||||||
"""The the currently selected buffer instance in the pool."""
|
"""The the currently selected buffer instance in the pool."""
|
||||||
return self.buffers[self.buseds]
|
return self.pool.selected
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bInputPlug ( self ):
|
def bInputPlug ( self ):
|
||||||
|
@ -121,7 +240,17 @@ class QuadTree ( object ):
|
||||||
"""The output Plug of the currently selected buffer in the pool."""
|
"""The output Plug of the currently selected buffer in the pool."""
|
||||||
return utils.getPlugByName( self.buffer, self.spares.state.bufferConf.output )
|
return utils.getPlugByName( self.buffer, self.spares.state.bufferConf.output )
|
||||||
|
|
||||||
def useBuffer ( self, doLeaf=False ):
|
def onYSlice ( self, y ):
|
||||||
|
"""Returns the coordinate of the slice immediately inferior to Y."""
|
||||||
|
modulo = (y - self.area.getYMin()) % self.spares.state.gaugeConf.sliceHeight
|
||||||
|
return y - modulo
|
||||||
|
|
||||||
|
def onXPitch ( self, x ):
|
||||||
|
"""Returns the coordinate of the pitch immediately inferior to X."""
|
||||||
|
modulo = (x - self.area.getXMin()) % self.spares.state.gaugeConf.sliceStep
|
||||||
|
return x - modulo
|
||||||
|
|
||||||
|
def connectBuffer ( self, doLeaf=False ):
|
||||||
"""
|
"""
|
||||||
Create output nets for the currently selected buffer, if they do not
|
Create output nets for the currently selected buffer, if they do not
|
||||||
already exists. The nets are created in the top level cell, and their
|
already exists. The nets are created in the top level cell, and their
|
||||||
|
@ -129,38 +258,49 @@ class QuadTree ( object ):
|
||||||
"""
|
"""
|
||||||
if self.isLeaf() and not doLeaf: return
|
if self.isLeaf() and not doLeaf: return
|
||||||
|
|
||||||
trace( 550, '\tQuadTree.useBuffer(): rtag:"{}"\n'.format(self.rtag) )
|
trace( 550, '\tQuadTree.connectBuffer(): rtag:"{}"\n'.format(self.rtag) )
|
||||||
plug = self.bOutputPlug
|
plug = self.bOutputPlug
|
||||||
if not plug.getNet():
|
if not plug.getNet():
|
||||||
outputNetBuff = Net.create( self.spares.state.cell,'{}_{}_{}' \
|
outputNetBuff = Net.create( self.spares.state.cell,'{}_{}' \
|
||||||
.format(self.root.bufferTag,self.buseds,self.rtag) )
|
.format(self.root.bufferTag,self.rtag) )
|
||||||
plug.setNet( outputNetBuff )
|
plug.setNet( outputNetBuff )
|
||||||
trace( 550, '\t| {}\n'.format(plug) )
|
trace( 550, '\t| {}\n'.format(plug) )
|
||||||
trace( 550, '\t| {}\n'.format(outputNetBuff) )
|
trace( 550, '\t| {}\n'.format(outputNetBuff) )
|
||||||
|
|
||||||
def ruseBuffer ( self ):
|
def rconnectBuffer ( self ):
|
||||||
"""Recursive call of useBuffer()"""
|
"""[R]ecursive call of connectBuffer()"""
|
||||||
self.useBuffer()
|
self.connectBuffer()
|
||||||
for leaf in self.leafs:
|
for leaf in self.leafs:
|
||||||
leaf.ruseBuffer()
|
leaf.rconnectBuffer()
|
||||||
|
|
||||||
def useNextBuffer ( self ):
|
def rselectBuffer ( self, column, row, flags=0 ):
|
||||||
"""
|
"""
|
||||||
Reset the quadtree buffering cache in order to buffer the next net.
|
Setup the buffer to be used for the next buffering operation.
|
||||||
Flush the plugs list and increase the buffer counter (buseds).
|
For a more detailed explanation of the parameter, please refer
|
||||||
|
to BufferPool.select().
|
||||||
"""
|
"""
|
||||||
|
trace( 550, '+' )
|
||||||
if self.plugs:
|
if self.plugs:
|
||||||
self.plugs = []
|
self.plugs = []
|
||||||
self.buseds += 1
|
self.pool.select( column, row, flags )
|
||||||
if not self.isLeaf():
|
if not self.isLeaf():
|
||||||
for leaf in self.leafs: leaf.useNextBuffer()
|
for leaf in self.leafs: leaf.rselectBuffer( column, row, flags )
|
||||||
|
trace( 550, '-' )
|
||||||
|
|
||||||
def partition ( self ):
|
def partition ( self ):
|
||||||
trace( 550, ',+', '\tQuadTree.partition(): {}\n'.format(self.area) )
|
"""
|
||||||
|
Build one level of the quad-tree, if the side of the area is bigger than
|
||||||
|
twice the "block.spareSide" value.
|
||||||
|
|
||||||
|
Depending on the initial aspect ratio, the first levels *may* not be a
|
||||||
|
quad-tree, but only a vertical or horizontal bi-partition.
|
||||||
|
"""
|
||||||
|
trace( 550, ',+', '\tQuadTree.partition(): {} (spareSide:{})\n' \
|
||||||
|
.format(self.area, DbU.getValueString(self.spares.state.cfg.block.spareSide)) )
|
||||||
|
|
||||||
spareSide = self.spares.state.cfg.block.spareSide
|
spareSide = self.spares.state.cfg.block.spareSide
|
||||||
sliceHeight = self.spares.state.gaugeConf.sliceHeight
|
sliceHeight = self.spares.state.gaugeConf.sliceHeight
|
||||||
side = float(spareSide * sliceHeight)
|
side = float(spareSide)
|
||||||
aspectRatio = float(self.area.getWidth()) / float(self.area.getHeight())
|
aspectRatio = float(self.area.getWidth()) / float(self.area.getHeight())
|
||||||
|
|
||||||
if self.area.getHeight() < side*2.0 or self.area.getWidth () < side*2.0:
|
if self.area.getHeight() < side*2.0 or self.area.getWidth () < side*2.0:
|
||||||
|
@ -243,6 +383,7 @@ class QuadTree ( object ):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def rpartition ( self ):
|
def rpartition ( self ):
|
||||||
|
""""[R]ecursively partition the the area."""
|
||||||
trace( 550, ',+', '\tQuadTree.rpartition(): {}\n'.format(self.area) )
|
trace( 550, ',+', '\tQuadTree.rpartition(): {}\n'.format(self.area) )
|
||||||
if self.partition():
|
if self.partition():
|
||||||
for leaf in self.leafs:
|
for leaf in self.leafs:
|
||||||
|
@ -250,40 +391,6 @@ class QuadTree ( object ):
|
||||||
leaf.rpartition()
|
leaf.rpartition()
|
||||||
trace( 550, '-' )
|
trace( 550, '-' )
|
||||||
|
|
||||||
def createBuffers ( self ):
|
|
||||||
trace( 550, ',+', '\tQuadTree.createBuffers()\n' )
|
|
||||||
#if not self.isLeaf(): return
|
|
||||||
|
|
||||||
state = self.spares.state
|
|
||||||
x = self.area.getXCenter() - state.bufferConf.width
|
|
||||||
y = self.area.getYCenter() - state.bufferConf.height
|
|
||||||
slice = y / state.gaugeConf.sliceHeight - 1
|
|
||||||
|
|
||||||
for slice in range(slice,slice+2):
|
|
||||||
orientation = Transformation.Orientation.ID
|
|
||||||
yadjust = 0
|
|
||||||
if slice%2:
|
|
||||||
orientation = Transformation.Orientation.MY
|
|
||||||
yadjust = 2 * state.gaugeConf.sliceHeight
|
|
||||||
for i in range(2):
|
|
||||||
instance = state.createBuffer()
|
|
||||||
instance.setTransformation( Transformation( x + i*state.bufferConf.width
|
|
||||||
, y + yadjust
|
|
||||||
, orientation ) )
|
|
||||||
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
|
||||||
self.buffers.append( instance )
|
|
||||||
trace( 550, '\tBuffer: {}\n'.format(self.buffers[-1]) )
|
|
||||||
trace( 550, '-' )
|
|
||||||
|
|
||||||
def rcreateBuffers ( self ):
|
|
||||||
self.createBuffers()
|
|
||||||
trace( 550, ',+' )
|
|
||||||
if self.bl: self.bl.rcreateBuffers()
|
|
||||||
if self.br: self.br.rcreateBuffers()
|
|
||||||
if self.tl: self.tl.rcreateBuffers()
|
|
||||||
if self.tr: self.tr.rcreateBuffers()
|
|
||||||
trace( 550, '-' )
|
|
||||||
|
|
||||||
def getLeafUnder ( self, position ):
|
def getLeafUnder ( self, position ):
|
||||||
"""Find the QuadTree leaf under `position`."""
|
"""Find the QuadTree leaf under `position`."""
|
||||||
if self.isLeaf(): return self
|
if self.isLeaf(): return self
|
||||||
|
@ -300,6 +407,7 @@ class QuadTree ( object ):
|
||||||
return self.tr.getLeafUnder(position)
|
return self.tr.getLeafUnder(position)
|
||||||
|
|
||||||
def attachToLeaf ( self, plugOccurrence ):
|
def attachToLeaf ( self, plugOccurrence ):
|
||||||
|
"""Assign the plug occurrence to the QuadTree leaf it is under."""
|
||||||
position = plugOccurrence.getBoundingBox().getCenter()
|
position = plugOccurrence.getBoundingBox().getCenter()
|
||||||
self.getLeafUnder(position).plugs.append( plugOccurrence )
|
self.getLeafUnder(position).plugs.append( plugOccurrence )
|
||||||
|
|
||||||
|
@ -325,7 +433,7 @@ class QuadTree ( object ):
|
||||||
if not self.plugs: return
|
if not self.plugs: return
|
||||||
|
|
||||||
trace( 550, ',+', '\tQuadTree.spliNetlist()\n' )
|
trace( 550, ',+', '\tQuadTree.spliNetlist()\n' )
|
||||||
self.useBuffer( doLeaf=True )
|
self.connectBuffer( doLeaf=True )
|
||||||
netBuff = self.bOutputPlug.getNet()
|
netBuff = self.bOutputPlug.getNet()
|
||||||
trace( 550, '\tBuffer: {}\n'.format(self.buffer) )
|
trace( 550, '\tBuffer: {}\n'.format(self.buffer) )
|
||||||
trace( 550, '\tBuffer output: {}\n'.format(netBuff) )
|
trace( 550, '\tBuffer output: {}\n'.format(netBuff) )
|
||||||
|
@ -338,6 +446,11 @@ class QuadTree ( object ):
|
||||||
deepNetBuff = deepPlug.getMasterNet() if deepPlug else netBuff
|
deepNetBuff = deepPlug.getMasterNet() if deepPlug else netBuff
|
||||||
trace( 550, '\t| deepNetBuff: {} {}\n'.format(deepNetBuff,netBuff) )
|
trace( 550, '\t| deepNetBuff: {} {}\n'.format(deepNetBuff,netBuff) )
|
||||||
plug.getEntity().setNet( deepNetBuff )
|
plug.getEntity().setNet( deepNetBuff )
|
||||||
|
|
||||||
|
maxSinks = self.spares.state.bufferConf.maxSinks
|
||||||
|
if len(self.plugs) > maxSinks:
|
||||||
|
print( WarningMessage( 'QuadTree.splitNetlist(): More than {} sink points ({}) on "{}".' \
|
||||||
|
.format(maxSinks,len(self.plugs),netBuff.getName())) )
|
||||||
trace( 550, '-' )
|
trace( 550, '-' )
|
||||||
|
|
||||||
def rsplitNetlist ( self ):
|
def rsplitNetlist ( self ):
|
||||||
|
@ -358,6 +471,10 @@ class Spares ( object ):
|
||||||
Excess area is put in the topmost and rightmost pools.
|
Excess area is put in the topmost and rightmost pools.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
USED = 0x00000001
|
||||||
|
CHECK_USED = 0x00010000
|
||||||
|
MARK_USED = 0x00020000
|
||||||
|
|
||||||
def __init__ ( self, block ):
|
def __init__ ( self, block ):
|
||||||
self.state = block.state
|
self.state = block.state
|
||||||
self.quadTree = None
|
self.quadTree = None
|
||||||
|
@ -370,8 +487,13 @@ class Spares ( object ):
|
||||||
"""
|
"""
|
||||||
if not self.state.useSpares: return 0.0
|
if not self.state.useSpares: return 0.0
|
||||||
spareSide = self.state.cfg.block.spareSide
|
spareSide = self.state.cfg.block.spareSide
|
||||||
|
if not spareSide:
|
||||||
|
raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): "block.spareSide" parameter is zero ({}).' \
|
||||||
|
.format(spareSide) )
|
||||||
areaLength = spareSide * spareSide / self.state.gaugeConf.sliceHeight
|
areaLength = spareSide * spareSide / self.state.gaugeConf.sliceHeight
|
||||||
bufferLength = self.state.bufferConf.width * 4
|
bufferLength = self.state.bufferConf.width * self.state.bColumns * self.state.bRows
|
||||||
|
if not areaLength:
|
||||||
|
raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): Spare leaf area is zero.' )
|
||||||
return float(bufferLength) / float(areaLength)
|
return float(bufferLength) / float(areaLength)
|
||||||
|
|
||||||
def toXGCellGrid ( self, x ):
|
def toXGCellGrid ( self, x ):
|
||||||
|
|
|
@ -182,6 +182,8 @@ namespace Etesian {
|
||||||
, getString(instanceOcc).c_str() ) << endl;
|
, getString(instanceOcc).c_str() ) << endl;
|
||||||
return Box();
|
return Box();
|
||||||
}
|
}
|
||||||
|
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED)
|
||||||
|
return instance->getMasterCell()->getAbutmentBox();
|
||||||
|
|
||||||
DbU::Unit dx = 0;
|
DbU::Unit dx = 0;
|
||||||
Cell* cell = instance->getMasterCell();
|
Cell* cell = instance->getMasterCell();
|
||||||
|
|
|
@ -670,6 +670,8 @@ namespace Etesian {
|
||||||
|coloquinte::YFlippable;
|
|coloquinte::YFlippable;
|
||||||
} else {
|
} else {
|
||||||
instances[instanceId].attributes = 0;
|
instances[instanceId].attributes = 0;
|
||||||
|
//cerr << "FIXED: " << instance << " size:(" << xsize << " " << ysize
|
||||||
|
// << ") pos:(" << xpos << " " << ypos << ")" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cellsToIds.insert( make_pair(instanceName,instanceId) );
|
_cellsToIds.insert( make_pair(instanceName,instanceId) );
|
||||||
|
|
Loading…
Reference in New Issue