More generic H-Tree support to accomodate the LS180 PLL internal clock.

The H-Tree support is now allowed for any net, not only the clocks and
not only top-level nets. This allow to better management of the LS180
internal clock signal.

* New: In Cell::flattenNets(Instance*,set<string>,uint64_t) new overload
    of the function to allow the user to select nets that will *not*
    be flattened. This makes the NoClockFlatten flag effectively obsolete,
    we keep it for backward compatibility.
      The net names can be of non top level ones. In that case, they must
    use the name an HyperNet will get (the Occurrence name). For example:
         "instance1.instance2.deep_net_name".
* New: In PyCell, update the wrapper for the new parameter of flattenNets(),
    new utility function pyListToStringSet() to translate a Python list into
    a C++ set of names.
* New: In EtesianEngine, add support for a list of nets to be excluded
    from the flattening procedure. Those excluded nets will also be
    excludeds from the Coloquinte nets *and* HFNS synthesis, as they
    are likely to be manageds by a H-Tree.
* Change: In AnabaticEngine::_loadGrByNet(), now also skip nets that are
    flagged as manually detailed route.
* New: In AnabaticEngine::antennaProtect(), do not try to insert diodes
    on nets that are already fixed or detaled route. This replace the
    clock exclusion.
* New: In cumulus/plugins.{block,htree,chip}, replace the concept
    of clock-tree by the more generic H-Tree. That is, we can ask the P&R
    to create H-Tree on any net of the design, not only the ones matcheds
    as clock. The net does not even need to be top-level.
      This is to manage the PLL internal clock generated by the PLL in
    the LS180 chip.
      Start to change all reference to "clock" into "H-Tree".
* Bug: In cumulus/plugins.chip.powerplanes.Builder._connectHTree(),
    there was an inversion of the H & V routing gauges to compute the
    track into which put the H-Tree center to corona edge wiring.
      This was causing tracks to be used twice, seen in the ao68000 test
    bench.
This commit is contained in:
Jean-Paul Chaput 2021-05-31 00:02:23 +02:00
parent 5b6bc7c91b
commit 205a6877db
17 changed files with 299 additions and 170 deletions

View File

@ -1241,6 +1241,8 @@ namespace Anabatic {
//AutoSegment::setShortNetMode( true );
++shortNets;
}
if (NetRoutingExtension::isManualDetailRoute(net))
continue;
if ( NetRoutingExtension::isManualGlobalRoute(net)
or NetRoutingExtension::isAutomaticGlobalRoute(net)) {
DebugSession::open( net, 145, 150 );

View File

@ -1057,7 +1057,9 @@ namespace Anabatic {
uint32_t total = 0;
for ( Net* net : getCell()->getNets() ) {
if (net->isSupply()) continue;
if (net->isClock ()) continue;
if ( NetRoutingExtension::isManualDetailRoute(net)
or NetRoutingExtension::isFixed(net))
continue;
antennaProtect( net, failed, total );
}
cmess2 << Dots::asString ( " - Antenna gate maximum WL" , DbU::getValueString(etesian->getAntennaGateMaxWL()) ) << endl;

View File

@ -94,13 +94,13 @@ namespace Anabatic {
}
}
if (getId() == 1518590) {
cerr << "AutoHorizontal::_postCreate(): " << this << endl;
cerr << "| Source contact:" << source << endl;
cerr << "| Source GCell: " << getGCell() << endl;
cerr << "| Target contact:" << target << endl;
cerr << "| Target GCell: " << target->getGCell() << endl;
}
// if (getId() == 1518590) {
// cerr << "AutoHorizontal::_postCreate(): " << this << endl;
// cerr << "| Source contact:" << source << endl;
// cerr << "| Source GCell: " << getGCell() << endl;
// cerr << "| Target contact:" << target << endl;
// cerr << "| Target GCell: " << target->getGCell() << endl;
// }
}

View File

@ -52,7 +52,7 @@
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/bigvia.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/spares.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/block.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/clocktree.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/htree.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/timing.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/rsmt.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/hfns1.py

View File

@ -16,6 +16,7 @@
from __future__ import print_function
import sys
import os.path
from copy import deepcopy
import Cfg
from Hurricane import Breakpoint, DbU, Box, Transformation, Point, \
Box, Path, Layer, Occurrence, Net, \
@ -35,7 +36,7 @@ from plugins import getParameter
from plugins.alpha.macro.macro import Macro
from plugins.alpha.block import timing
from plugins.alpha.block.spares import Spares
from plugins.alpha.block.clocktree import ClockTree
from plugins.alpha.block.htree import HTree
#from plugins.alpha.block.hfns1 import BufferTree
#from plugins.alpha.block.hfns2 import BufferTree
#from plugins.alpha.block.hfns3 import BufferTree
@ -286,6 +287,7 @@ class Block ( object ):
"""
LUT = {}
FLATTENED = 0x0001
@staticmethod
def lookup ( cell ):
@ -300,10 +302,11 @@ class Block ( object ):
self.flags = 0
self.conf = conf
self.spares = Spares( self )
self.clockTrees = []
self.hTrees = []
self.hfnTrees = []
self.blockInstances = []
self.placeHolderCount = 0
self.excludedNets = deepcopy( self.conf.hTreeNames )
self.sides = { IoPin.WEST : Side( self.conf, IoPin.WEST )
, IoPin.EAST : Side( self.conf, IoPin.EAST )
, IoPin.SOUTH : Side( self.conf, IoPin.SOUTH )
@ -329,7 +332,6 @@ class Block ( object ):
.format(self.conf.cell.getName()) )
Block.LUT[ self.conf.cell ] = self
@staticmethod
def _getInstance ( cell, pattern, level=0 ):
"""
@ -370,6 +372,35 @@ class Block ( object ):
"""
return Block._rgetInstance( self.conf.core, path )
@staticmethod
def _rinstancesToPath ( path, instances ):
instance = path.getTailInstance().getMasterCell().getInstance( instances[0] )
path = Path( path, instance )
if len(instances) > 1:
return Block._rinstanceToPath( path, instances[1:] )
return path
@staticmethod
def _instancesToPath ( cell, instances ):
instance = cell.getInstance( instances[0] )
return Block._rinstancesToPath( Path(instance), instances[1:] )
def getFlattenedNet ( self, path ):
"""
Find a net in the hierarchy. The path argument is a list pathname of instance
endind by a net name, like "instance1.instance2.net_name". The function returns
a an Occurrence, the instance path and the Net, or None.
"""
for net in self.conf.cellPnR.getNets():
if net.getName() == path:
return Occurrence( net, Path() )
elements = path.split('.')
if len(elements) == 1:
return None
path = Block._instancesToPath( self.conf.cellPnR, elements[:-1] )
net = path.getTailInstance().getMasterCell().getNet( elements[-1] )
return Occurrence( net, path )
def setUnexpandPins ( self, sides ):
"""
Prevent Pins from the selected sides to be stick out of one pitch.
@ -433,43 +464,65 @@ class Block ( object ):
else:
self.conf.setRoutingBb( self.conf.cell.getAbutmentBox() )
def addClockTrees ( self ):
"""Create the trunk of all the clock trees (recursive H-Tree)."""
print( ' o Building clock tree(s).' )
af = CRL.AllianceFramework.get()
clockNets = []
for net in self.conf.cellPnR.getNets():
if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net)
if net.isClock():
trace( 550, '\tBlock.addClockTrees(): Found clock {}.\n'.format(net) )
clockNets.append( net )
if not clockNets:
raise ErrorMessage( 3, 'Block.clockTree(): Cell "{}" has no clock net(s).'.format(self.conf.cell.getName()) )
with UpdateSession():
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()
trace( 550, '-' )
Breakpoint.stop( 100, 'Block.addClockTrees() on {} done.'.format(self.conf.cellPnR) )
def flattenNets ( self ):
if self.flags & Block.FLATTENED: return
if self.conf.isCoreBlock:
self.conf.corona.flattenNets( self.conf.icore, self.conf.hTreeNames, Cell.Flags_NoClockFlatten )
else:
self.conf.cell.flattenNets( None, self.excludedNets, Cell.Flags_NoClockFlatten )
self.flags |= Block.FLATTENED
def splitClocks ( self ):
def addHTrees ( self ):
"""Create the trunk of all the clock trees (recursive H-Tree)."""
print( ' o Building H-Tree(s).' )
af = CRL.AllianceFramework.get()
hTreeNets = []
netOcc = None
self.flattenNets()
for netName in self.conf.hTreeNames:
netOcc = self.getFlattenedNet( netName )
#if self.conf.isCoreBlock:
# coreNet = self.conf.cell.getNet( netName )
# if coreNet is not None:
# trace( 550, '\tFound coreNet={}\n'.format(coreNet) )
# for plug in self.conf.icore.getPlugs():
# if plug.getMasterNet() == coreNet:
# net = plug.getNet()
# break
#else:
# net = self.conf.cellPnR.getNet( netName )
if netOcc is None:
print( ErrorMessage( 3, 'Block.addHTrees(): Cell "{}" has no H-Tree net "{}".' \
.format( self.conf.cellPnR.getName(), netName )))
continue
trace( 550, '\tBlock.addHTrees(): Found H-Tree {}.\n'.format(netOcc) )
hTreeNets.append( netOcc )
self.etesian.exclude( netName )
with UpdateSession():
for hTreeNet in hTreeNets:
print( ' - "{}".'.format(hTreeNet.getName()) )
trace( 550, ',+', '\tBlock.addHTrees(): Build clock tree for {}.\n'.format(hTreeNet) )
self.hTrees.append( HTree(self.spares,hTreeNet,len(self.hTrees)) )
self.hTrees[-1].buildHTree()
for net in self.hTrees[-1].subNets:
self.etesian.exclude( net.getName() )
self.excludedNets.append( net.getName() )
trace( 550, '-' )
Breakpoint.stop( 100, 'Block.addHTrees() on {} done.'.format(self.conf.cellPnR) )
def splitHTrees ( self ):
"""
Break the clock net and attach all it's Pins to the closest leaf
Break the H-Tree root nets and attach all it's Pins to the closest leaf
if the H-Tree.
"""
for clockTree in self.clockTrees:
clockTree.splitClock()
for hTree in self.hTrees:
hTree.splitNet()
def findHfnTrees4 ( self ):
"""Perform simple HFNS, just break nets regardless of placement."""
print( ' o Building high fanout nets trees.' )
if self.spares:
if self.conf.isCoreBlock:
self.conf.corona.flattenNets( self.conf.icore, Cell.Flags_NoClockFlatten )
else:
self.conf.cell.flattenNets( None, Cell.Flags_NoClockFlatten )
self.flattenNets()
beginCount = self.conf.bufferConf.count
maxSinks = 10
dots( 82
@ -578,7 +631,7 @@ class Block ( object ):
for side in self.sides.values():
side.expand()
def place ( self ):
def initEtesian ( self ):
editor = self.conf.editor
if self.conf.isCoreBlock:
self.etesian = Etesian.EtesianEngine.create( self.conf.corona )
@ -588,9 +641,11 @@ class Block ( object ):
Breakpoint.stop( 100, 'Block.place(), corona loaded.')
else:
self.etesian = Etesian.EtesianEngine.create( self.conf.cell )
self.etesian.getCell().flattenNets( None, self.excludedNets, Cell.Flags_NoClockFlatten )
def place ( self ):
if self.conf.placeArea:
self.etesian.setPlaceArea( self.conf.placeArea )
self.etesian.getCell().flattenNets( None, Cell.Flags_NoClockFlatten )
if self.conf.useHFNS: self.etesian.doHFNS()
self.etesian.place()
Breakpoint.stop( 100, 'Placement done.' )
@ -738,6 +793,7 @@ class Block ( object ):
blockInstance.block.build()
if editor: editor.setCell( self.conf.cellPnR )
self.conf.cfg.apply()
self.initEtesian()
iteration = -1
while True:
iteration += 1
@ -748,14 +804,14 @@ class Block ( object ):
self.checkIoPins()
self.spares.build()
#if self.conf.useHFNS: self.findHfnTrees4()
if self.conf.useClockTree: self.addClockTrees()
self.addHTrees()
#if self.conf.useHFNS: self.addHfnBuffers()
if editor: editor.fit()
#Breakpoint.stop( 0, 'Clock tree(s) done.' )
self.place()
#if self.conf.useHFNS: self.findHfnTrees()
break
if self.conf.useClockTree: self.splitClocks()
self.splitHTrees()
self.spares.removeUnusedBuffers()
self.etesian.toHurricane()
self.etesian.flattenPower()

View File

@ -1109,6 +1109,7 @@ class BlockConf ( GaugeConf ):
self.placeArea = None
self.deltaAb = [ 0, 0, 0, 0 ]
self.useClockTree = False
self.hTreeNames = [ ]
self.useHFNS = False
self.useSpares = True
self.isBuilt = False
@ -1210,6 +1211,10 @@ class BlockConf ( GaugeConf ):
trace( 550, '\tNew cloned cell: "{}"\n'.format(masterCell) )
self.cloneds.append( masterCell )
return
def useHTree ( self, netName ):
if not netName in self.hTreeNames:
self.hTreeNames.append( netName );
def save ( self, flags ):
"""

View File

@ -9,7 +9,7 @@
# | Author : Jean-Paul CHAPUT |
# | E-mail : Jean-Paul.Chaput@lip6.fr |
# | =============================================================== |
# | Python : "./plugins/block/clocktree.py" |
# | Python : "./plugins/block/htree.py" |
# +-----------------------------------------------------------------+
@ -17,29 +17,14 @@ from __future__ import print_function
import sys
import os.path
import Cfg
from Hurricane import Breakpoint
from Hurricane import DbU
from Hurricane import Box
from Hurricane import Transformation
from Hurricane import Box
from Hurricane import Path
from Hurricane import Layer
from Hurricane import Occurrence
from Hurricane import Net
from Hurricane import HyperNet
from Hurricane import RoutingPad
from Hurricane import Horizontal
from Hurricane import Vertical
from Hurricane import Contact
from Hurricane import Pin
from Hurricane import Plug
from Hurricane import Instance
from Hurricane import Breakpoint, DbU, Box, Transformation, Box, \
Path, Layer, Occurrence, Net, HyperNet, \
RoutingPad, Horizontal, Vertical, Contact, \
Pin, Plug, Instance
import CRL
from CRL import RoutingLayerGauge
from helpers import trace
from helpers.io import ErrorMessage
from helpers.io import WarningMessage
from helpers.io import catch
from helpers.io import ErrorMessage, WarningMessage, catch
from helpers.overlay import UpdateSession
from plugins import getParameter
from plugins.alpha import utils
@ -48,33 +33,47 @@ from plugins.alpha.block.spares import Spares
# ----------------------------------------------------------------------------
# Class : "clocktree.ClockTree".
# Class : "htree.HTree".
class ClockTree ( object ):
class HTree ( object ):
"""
Build a clock tree on a block.
Build a H-Tree on a net occurrene.
"""
def __init__ ( self, spares, clockNet, index ):
def __init__ ( self, spares, treeNetOcc, index ):
self.spares = spares
self.clockNet = clockNet
self.clockIndex = index
self.treeNetOcc = treeNetOcc
self.treeIndex = index
self.subNets = []
if not self.clockNet.isClock():
print( WarningMessage( 'ClockTree.__init__(): Net "{}" is not of CLOCK type.' \
.format(self.clockNet.getName()) ))
#if not self.treeNetOcc.getEntity().isClock():
# print( WarningMessage( 'HTree.__init__(): Net "{}" is not of CLOCK type.' \
# .format(self.treeNet.getEntity().getName()) ))
if treeNetOcc.getPath().isEmpty():
self.treeNet = self.treeNetOcc.getEntity()
else:
botNet = self.treeNetOcc.getEntity()
botNet.setExternal( True )
topNetName = self.treeNetOcc.getName()
topNet = Net.create( self.treeNetOcc.getPath().getOwnerCell(), topNetName )
topNet.setType ( botNet.getType() )
topNet.setDirection( botNet.getDirection() )
path = self.treeNetOcc.getPath().getHeadPath()
self.spares.raddTransNet( topNet, path )
botInstance = self.treeNetOcc.getPath().getTailInstance()
botInstance.getPlug( botNet ).setNet( botInstance.getCell().getNet( topNetName ))
self.treeNet = topNet
def destroy ( self ):
trace( 550, ',+', '\tClockTree.destroy() "{}"\n'.format(self.clockNet.getName()) )
trace( 550, ',+', '\tHTree.destroy() "{}"\n'.format(self.treeNet.getName()) )
with UpdateSession():
for subNet in self.subNets + [ self.clockNet ]:
for subNet in self.subNets + [ self.treeNet ]:
components = []
for comp in subNet.getComponents():
if isinstance(comp,RoutingPad): components.append( comp )
if isinstance(comp,Pin ): components.append( comp )
for comp in components:
comp.destroy()
if subNet != self.clockNet:
if subNet != self.treeNet:
subNet.destroy()
trace( 550, '-' )
@ -82,7 +81,7 @@ class ClockTree ( object ):
if qt.isLeaf(): return False
qt.rconnectBuffer()
driverNet = qt.bOutputPlug.getNet()
driverNet.setType( Net.Type.CLOCK )
driverNet.setType( self.treeNet.getType() )
for leaf in qt.leafs:
leaf.bInputPlug.setNet( driverNet )
self._rconnectHTree( leaf )
@ -92,7 +91,7 @@ class ClockTree ( object ):
"""
Recursively build one HTree branch for all non-terminal nodes of the QuadTree.
"""
trace( 550, ',+', '\tClockTree._rrouteHTree() {}\n'.format(qt.bOutputPlug.getNet()) )
trace( 550, ',+', '\tHTree._rrouteHTree() {}\n'.format(qt.bOutputPlug.getNet()) )
trace( 550, '\tOn: {}\n'.format(qt) )
if qt.isLeaf():
trace( 550, '-' )
@ -165,13 +164,13 @@ class ClockTree ( object ):
gaugeConf.setStackPosition( brContact, rightX, blY )
gaugeConf.createVertical ( rightContact, brContact, rightX, 0 )
if qt.isRoot():
ckNet = self.clockNet
ckNet = self.treeNet
if not self.spares.conf.isCoreBlock:
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)) )
print( WarningMessage('HTree._rrouteHTree(): Removing {}.'.format(pin)) )
pin.destroy()
layerGauge = gaugeConf.vRoutingGauge
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
@ -196,41 +195,44 @@ class ClockTree ( object ):
def buildHTree ( self ):
"""
Create the clock tree netlist in two steps:
Create the tree tree netlist in two steps:
1. Connect the buffers of the spares QuadTree to form a H-Tree.
2. Detach the all the clock sink point and reconnect them to the
2. Detach the all the tree sink point and reconnect them to the
buffers of the leafs of the QuadTree.
"""
qt = self.spares.quadTree
qt.bufferTag = self.clockNet.getName()
qt.rselectBuffer( self.clockIndex, self.clockIndex, Spares.CHECK_USED|Spares.MARK_USED)
qt.bufferTag = self.treeNet.getName()
qt.rselectBuffer( self.treeIndex, self.treeIndex, Spares.CHECK_USED|Spares.MARK_USED)
with UpdateSession():
self._rconnectHTree( qt )
self._rrouteHTree ( qt )
def splitClock ( self ):
def splitNet ( self ):
"""
Disconnect the registers from the main clock and reconnect them to
the leaf buffers of the clock tree.
Disconnect the sinks from the main tree and reconnect them to
the leaf buffers of the tree tree.
"""
bufferConf = self.spares.conf.bufferConf
quadTree = self.spares.quadTree
quadTree.bufferTag = self.clockNet.getName()
quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 )
quadTree.bufferTag = self.treeNet.getName()
quadTree.rselectBuffer( self.treeIndex, self.treeIndex, 0 )
with UpdateSession():
coronaPlugs = []
hyperClock = HyperNet.create( Occurrence(self.clockNet) )
for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences():
if quadTree.isUnderArea(plugOccurrence):
quadTree.attachToLeaf( plugOccurrence )
driverPlugs = []
hyperNet = HyperNet.create( Occurrence(self.treeNet) )
for plugOcc in hyperNet.getTerminalNetlistPlugOccurrences():
trace( 550, '\tReattach "{}"\n'.format(plugOcc) )
plug = plugOcc.getEntity()
if not (plug.getMasterNet().getDirection() & Net.Direction.OUT) \
and quadTree.isUnderArea(plugOcc):
quadTree.attachToLeaf( plugOcc )
else:
coronaPlugs.append( plugOccurrence )
driverPlugs.append( plugOcc )
quadTree.rsplitNetlist()
if self.spares.conf.isCoreBlock:
plug = utils.getPlugByName( quadTree.buffer, bufferConf.input )
plug.setNet( self.clockNet )
trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.clockNet.getName()) )
trace( 550, '\tPlug of "{}" (Cell:{})\n'.format(self.clockNet.getName()
,self.clockNet.getCell()) )
for plug in self.clockNet.getPlugs():
plug.setNet( self.treeNet )
trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.treeNet.getName()) )
trace( 550, '\tPlug of "{}" (Cell:{})\n'.format(self.treeNet.getName()
,self.treeNet.getCell()) )
for plug in self.treeNet.getPlugs():
trace( 550, '\t| {}\n'.format(plug) )

View File

@ -120,7 +120,7 @@ class Chip ( Block ):
if self.conf.routingGauge.hasPowerSupply():
power = plugins.alpha.chip.powerplane.Builder( self.conf )
power.connectPower()
power.connectClocks()
power.connectHTrees( self.hTrees )
power.doLayout()
Breakpoint.stop( 101, 'After Query power.' )
else:

View File

@ -455,23 +455,23 @@ class Builder ( object ):
trace( 550, '-' )
self.activePlane = None
def _connectClock ( self, ck, trackNb ):
trace( 550, '\tpower.Builder._connectClock() {}\n'.format(ck) )
blockCk = None
def _connectHTree ( self, coronaNet, trackNb ):
trace( 550, '\tpower.Builder._connectHTree() {} on track {}\n'.format(coronaNet,trackNb) )
coreNet = None
for plug in self.conf.icore.getPlugs():
if plug.getNet() == ck:
blockCk = plug.getMasterNet()
if not blockCk:
raise ErrorMessage( 1, 'Block "{}" has no net connected to the clock "{}".' \
.format(self.conf.icore.getName(),ck.getName()) )
if plug.getNet() == coronaNet:
coreNet = plug.getMasterNet()
if not coreNet:
raise ErrorMessage( 1, 'Block "{}" has no net connected to the H-Tree "{}".' \
.format(self.conf.icore.getName(),coronaNet.getName()) )
return
htPlugs = []
for plug in ck.getPlugs():
for plug in coronaNet.getPlugs():
if plug.getInstance().isTerminalNetlist():
htPlugs.append( plug )
if len(htPlugs) != 1:
message = [ 'Clock "{}" of block "{}" is not organized as a H-Tree ({} plugs).' \
.format( ck.getName()
message = [ 'Net "{}" of block "{}" is not organized as a H-Tree ({} plugs).' \
.format( coronaNet.getName()
, self.conf.icore.getName()
, len(htPlugs)) ]
for plug in htPlugs:
@ -479,17 +479,17 @@ class Builder ( object ):
raise ErrorMessage( 1, message )
return
coronaPin = None
for pin in ck.getPins():
for pin in coronaNet.getPins():
coronaPin = pin
break
if not coronaPin:
message = [ 'Clock "{}" of block "{}" is not connected to a corona Pin.' \
.format( ck.getName() , self.conf.icore.getName() ) ]
message = [ 'Net "{}" of block "{}" is not connected to a corona Pin.' \
.format( coronaNet.getName() , self.conf.icore.getName() ) ]
raise ErrorMessage( 1, message )
with UpdateSession():
coronaAb = self.conf.cellPnR.getAbutmentBox()
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()), ck, 0 )
pinRp = self.conf.rpAccessByOccurrence( Occurrence(coronaPin , Path()), ck, 0 )
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()), coronaNet, 0 )
pinRp = self.conf.rpAccessByOccurrence( Occurrence(coronaPin , Path()), coronaNet, 0 )
trace( 550, '\tpinRp={}\n'.format(pinRp) )
self.conf.expandMinArea( bufferRp )
self.conf.expandMinArea( pinRp )
@ -508,40 +508,39 @@ class Builder ( object ):
isVertical = False
axis = coronaAb.getXMin()
if isVertical:
pitch = self.conf.vRoutingGauge.getPitch()
yaxis = axis + pitch * trackNb
pitch = self.conf.hRoutingGauge.getPitch()
yaxis = axis + 2 * pitch * trackNb
trace( 550, '\tyaxis(request)={}\n'.format(DbU.getValueString(yaxis)) )
yaxis = self.conf.getNearestHorizontalTrack( yaxis, 0 )
xaxisRp = self.conf.getNearestVerticalTrack( bufferRp.getX(), 0 )
xaxisPin = self.conf.getNearestVerticalTrack( pin.getX(), 0 )
contact1 = self.conf.createContact( ck, xaxisRp , yaxis, 0 )
contact2 = self.conf.createContact( ck, xaxisPin, yaxis, 0 )
contact1 = self.conf.createContact( coronaNet, xaxisRp , yaxis, 0 )
contact2 = self.conf.createContact( coronaNet, xaxisPin, yaxis, 0 )
self.conf.createVertical ( bufferRp, contact1, xaxisRp , 0 )
self.conf.createHorizontal( contact1, contact2, yaxis , 0 )
self.conf.createVertical ( contact2, pinRp , xaxisPin, 0 )
trace( 550, '\tyaxis(track)={}\n'.format(DbU.getValueString(yaxis)) )
trace( 550, '\tcontact1={}\n'.format(contact1) )
trace( 550, '\tcontact2={}\n'.format(contact2) )
else:
pitch = self.conf.hRoutingGauge.getPitch()
xaxis = axis + pitch * trackNb
pitch = self.conf.vRoutingGauge.getPitch()
xaxis = axis + 2 * pitch * trackNb
trace( 550, '\txaxis(request)={} vpitch={}\n' \
.format(DbU.getValueString(xaxis), DbU.getValueString(pitch)) )
xaxis = self.conf.getNearestVerticalTrack( xaxis, 0 )
yaxisRp = self.conf.getNearestHorizontalTrack( bufferRp.getY(), 0 )
yaxisPin = self.conf.getNearestHorizontalTrack( pin.getY(), 0 )
contact1 = self.conf.createContact( ck, xaxis, yaxisRp , 0 )
contact2 = self.conf.createContact( ck, xaxis, yaxisPin, 0 )
contact1 = self.conf.createContact( coronaNet, xaxis, yaxisRp , 0 )
contact2 = self.conf.createContact( coronaNet, xaxis, yaxisPin, 0 )
self.conf.createHorizontal( bufferRp, contact1, yaxisRp , 0 )
self.conf.createVertical ( contact1, contact2, xaxis , 0 )
self.conf.createHorizontal( contact2, pinRp , yaxisPin, 0 )
trace( 550, '\txaxis(track)={}\n'.format(DbU.getValueString(xaxis)) )
return
def connectClocks ( self ):
if not self.conf.useClockTree:
print( WarningMessage( "Clock tree generation has been disabled ('chip.clockTree':False)." ))
return
if len(self.conf.coronaCks) == 0:
raise ErrorMessage( 1, 'Cannot build clock terminal as no clock is not known.' )
return
for i in range(len(self.conf.coronaCks)):
self._connectClock( self.conf.coronaCks[i], i+2 )
def connectHTrees ( self, hTrees ):
for i in range(len(hTrees)):
self._connectHTree( hTrees[i].treeNet, i+2 )
def doLayout ( self ):
with UpdateSession():

View File

@ -323,6 +323,7 @@ namespace Etesian {
, _fixedAbWidth (0)
, _diodeCount (0)
, _bufferCount (0)
, _excludedNets ()
{ }
@ -792,7 +793,7 @@ namespace Etesian {
cmess1 << " - Building RoutingPads (transhierarchical)" << endl;
//getCell()->flattenNets( Cell::Flags::BuildRings|Cell::Flags::NoClockFlatten );
//getCell()->flattenNets( getBlockInstance(), Cell::Flags::NoClockFlatten );
getCell()->flattenNets( NULL, Cell::Flags::NoClockFlatten );
getCell()->flattenNets( NULL, _excludedNets, Cell::Flags::NoClockFlatten );
bool tooManyInstances = false;
index_t instanceId = 0;
@ -929,9 +930,10 @@ namespace Etesian {
for ( Net* net : getCell()->getNets() )
{
const char* excludedType = NULL;
if (net->getType() == Net::Type::POWER ) excludedType = "POWER";
if (net->getType() == Net::Type::GROUND) excludedType = "GROUND";
if (net->getType() == Net::Type::CLOCK ) excludedType = "CLOCK";
if (net->getType() == Net::Type::POWER ) excludedType = "POWER";
if (net->getType() == Net::Type::GROUND) excludedType = "GROUND";
if (net->getType() == Net::Type::CLOCK ) excludedType = "CLOCK";
if (isExcluded(getString(net->getName()))) excludedType = "USER_EXCLUDED";
if (excludedType) {
cparanoid << Warning( "%s is not a routable net (%s,excluded)."
, getString(net).c_str(), excludedType ) << endl;
@ -952,9 +954,10 @@ namespace Etesian {
for ( Net* net : getCell()->getNets() )
{
const char* excludedType = NULL;
if (net->getType() == Net::Type::POWER ) excludedType = "POWER";
if (net->getType() == Net::Type::GROUND) excludedType = "GROUND";
if (net->getType() == Net::Type::CLOCK ) excludedType = "CLOCK";
if (net->getType() == Net::Type::POWER ) excludedType = "POWER";
if (net->getType() == Net::Type::GROUND) excludedType = "GROUND";
if (net->getType() == Net::Type::CLOCK ) excludedType = "CLOCK";
if (isExcluded(getString(net->getName()))) excludedType = "USER_EXCLUDED";
if (excludedType) continue;
if (af->isBLOCKAGE(net->getName())) continue;

View File

@ -456,6 +456,8 @@ namespace Etesian {
BufferDatas* bufferDatas = getBufferCells().getBiggestBuffer();
vector< tuple<Net*,uint32_t> > netDatas;
for ( Net* net : getCell()->getNets() ) {
if (isExcluded(getString(net->getName()))) continue;
uint32_t rpCount = 0;
for ( RoutingPad* rp : net->getRoutingPads() ) {
Occurrence rpOcc = rp->getPlugOccurrence();

View File

@ -77,13 +77,14 @@ extern "C" {
DirectVoidMethod(EtesianEngine,etesian,clearColoquinte)
DirectVoidMethod(EtesianEngine,etesian,flattenPower)
DirectVoidMethod(EtesianEngine,etesian,toHurricane)
DirectGetUIntAttribute (PyEtesianEngine_doHFNS ,doHFNS ,PyEtesianEngine,EtesianEngine)
DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine)
DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine)
DirectSetDoubleAttribute(PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine)
DirectSetDoubleAttribute(PyEtesianEngine_setAspectRatio ,setAspectRatio ,PyEtesianEngine,EtesianEngine)
DirectGetLongAttribute (PyEtesianEngine_getFixedAbHeight,getFixedAbHeight,PyEtesianEngine,EtesianEngine)
DirectGetLongAttribute (PyEtesianEngine_getFixedAbWidth ,getFixedAbWidth ,PyEtesianEngine,EtesianEngine)
DirectGetUIntAttribute (PyEtesianEngine_doHFNS ,doHFNS ,PyEtesianEngine,EtesianEngine)
DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine)
DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine)
DirectSetDoubleAttribute (PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine)
DirectSetDoubleAttribute (PyEtesianEngine_setAspectRatio ,setAspectRatio ,PyEtesianEngine,EtesianEngine)
DirectGetLongAttribute (PyEtesianEngine_getFixedAbHeight,getFixedAbHeight,PyEtesianEngine,EtesianEngine)
DirectGetLongAttribute (PyEtesianEngine_getFixedAbWidth ,getFixedAbWidth ,PyEtesianEngine,EtesianEngine)
DirectSetCStringAttribute(PyEtesianEngine_exclude ,exclude ,PyEtesianEngine,EtesianEngine)
static PyObject* PyEtesianEngine_get ( PyObject*, PyObject* args )
@ -236,6 +237,8 @@ extern "C" {
, "Returns the Etesian engine attached to the Cell, None if there isn't." }
, { "create" , (PyCFunction)PyEtesianEngine_create , METH_VARARGS|METH_STATIC
, "Create an Etesian engine on this cell." }
, { "exclude" , (PyCFunction)PyEtesianEngine_exclude , METH_VARARGS
, "Add the specified net to the exclusion list." }
, { "getFixedAbHeight" , (PyCFunction)PyEtesianEngine_getFixedAbHeight , METH_NOARGS
, "Returns the forced abutment box height." }
, { "getFixedAbWidth" , (PyCFunction)PyEtesianEngine_getFixedAbWidth , METH_NOARGS

View File

@ -71,11 +71,13 @@ namespace Etesian {
typedef std::tuple<Instance*, std::vector<RoutingPad*> > InstanceInfos;
typedef std::map<Instance*,size_t,DBo::CompareById> InstancesToIds;
typedef std::map<Net*,size_t,DBo::CompareById> NetsToIds;
typedef std::set<std::string> 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;
@ -106,6 +108,7 @@ namespace Etesian {
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 );
@ -136,6 +139,7 @@ namespace Etesian {
uint32_t doHFNS ();
inline void useFeed ( Cell* );
size_t findYSpin ();
inline void exclude ( string netName );
void addFeeds ();
void toHurricane ();
void flattenPower ();
@ -174,6 +178,7 @@ namespace Etesian {
DbU::Unit _fixedAbWidth;
uint32_t _diodeCount;
uint32_t _bufferCount;
NetNameSet _excludedNets;
protected:
// Constructors & Destructors.
@ -229,6 +234,8 @@ namespace Etesian {
inline uint32_t EtesianEngine::_getNewDiodeId () { return _diodeCount++; }
inline const Box& EtesianEngine::getPlaceArea () const { return _placeArea; }
inline Area* EtesianEngine::getArea () const { return _area; }
inline const EtesianEngine::NetNameSet&
EtesianEngine::getExcludedNets () const { return _excludedNets; }
inline void EtesianEngine::setBlock ( Instance* block )
{
@ -319,6 +326,24 @@ namespace Etesian {
}
inline bool EtesianEngine::isExcluded ( string netName ) const
{ return (_excludedNets.find(netName) != _excludedNets.end()); }
inline void EtesianEngine::exclude ( string netName )
{
// Net* net = getCell()->getNet( netName );
// if (not net) {
// std::cerr << Error( "EtesianEngine::exclude(Net*): %s has no net named \"%s\"."
// , getString(getCell()).c_str()
// , netName.c_str()
// ) << std::endl;
// return;
// }
if (isExcluded(netName)) return;
_excludedNets.insert( netName );
}
// Variables.
extern const char* missingEtesian;

View File

@ -820,6 +820,13 @@ void Cell::flattenNets (uint64_t flags )
void Cell::flattenNets ( const Instance* instance, uint64_t flags )
// ****************************************************************
{
static set<string> excludeds;
flattenNets( instance, excludeds, flags );
}
void Cell::flattenNets ( const Instance* instance, const std::set<string>& excludeds, uint64_t flags )
// ***************************************************************************************************
{
cdebug_log(18,1) << "Cell::flattenNets() flags:0x" << hex << flags << endl;
@ -837,6 +844,7 @@ void Cell::flattenNets ( const Instance* instance, uint64_t flags )
if (net->isClock() and (flags & Flags::NoClockFlatten)) continue;
if (net->isPower() or net->isGround() or net->isBlockage()) continue;
if (excludeds.find(getString(occurrence.getName())) != excludeds.end()) continue;
HyperNet hyperNet ( occurrence );
if ( not occurrence.getPath().isEmpty() ) {

View File

@ -728,9 +728,6 @@ void Net::_preDestroy()
// *******************
{
cdebug_log(18,1) << "entering Net::_preDestroy: " << this << endl;
if (getName() == "pipe_middle_0_rb[0]")
cerr << "entering Net::_preDestroy: " << this << endl;
Inherit::_preDestroy();
cdebug_log(18,0) << "Net::_preDestroy: " << this << " slave Plugs..." << endl;

View File

@ -507,6 +507,7 @@ class Cell : public Entity {
public: void setAbstractedSupply(bool state) { _flags.set(Flags::AbstractedSupply,state); };
public: void flattenNets(uint64_t flags=Flags::BuildRings);
public: void flattenNets(const Instance* instance, uint64_t flags=Flags::BuildRings);
public: void flattenNets(const Instance* instance, const std::set<std::string>& excludeds, uint64_t flags=Flags::BuildRings);
public: void createRoutingPadRings(uint64_t flags=Flags::BuildRings);
public: void setFlags(uint64_t flags) { _flags |= flags; }
public: void resetFlags(uint64_t flags) { _flags &= ~flags; }

View File

@ -29,6 +29,24 @@
namespace Isobar {
bool pyListToStringSet ( PyObject* list, set<string>& v )
{
if (not PyList_Check(list)) return false;
int length = PyList_Size( list );
for ( int i=0 ; i<length ; ++i ) {
PyObject* item = PyList_GetItem( list, i );
if (not PyString_Check(item)) {
string message = "pyListToStringSet: Item at position " + getString(i) + " is not a string.";
PyErr_SetString( ConstructorError, message.c_str() );
return false;
}
v.insert( PyString_AsString(item) );
}
return true;
}
using namespace Hurricane;
@ -730,30 +748,36 @@ extern "C" {
{
cdebug_log(20,0) << "PyCell_flattenNets()" << endl;
Instance* instance = NULL;
PyObject* arg0 = NULL;
PyObject* arg1 = NULL;
uint64_t flags = 0;
set<string> excludeds;
Instance* instance = NULL;
PyObject* arg0 = NULL;
PyObject* arg1 = NULL;
PyObject* arg2 = NULL;
HTRY
METHOD_HEAD ( "Cell.flattenNets()" )
__cs.init( "Cell.flattenNets" );
if (not PyArg_ParseTuple(args,"O&O&:Cell.flattenNets"
,Converter,&arg0
,Converter,&arg1
)) {
PyErr_SetString( ConstructorError, "Cell.flattenNets(): Takes exactly two parameters." );
return NULL;
}
if (arg0 == Py_None) {
cell->flattenNets( NULL, PyInt_AsLong(arg1) );
} else if (__cs.getObjectIds() == ":ent:int") {
cell->flattenNets( PYINSTANCE_O(arg0), PyInt_AsLong(arg1) );
} else {
string message = "Cell.flattenNets(): Bad type of parameter(s), \"" + __cs.getObjectIds() + "\".";
PyErr_SetString( ConstructorError, message.c_str() );
if (not PyArg_ParseTuple(args,"OO|O:Cell.flattenNets", &arg0, &arg1, &arg2 )) {
PyErr_SetString( ConstructorError, "Cell.flattenNets(): Takes between two and three parameters." );
return NULL;
}
if (arg0 != Py_None) {
if (not IsPyInstance(arg0)) {
PyErr_SetString( ConstructorError, "Cell.flattenNets(): First argument must be None or an Instance." );
return NULL;
}
instance = PYINSTANCE_O( arg0 );
}
if (arg2) {
pyListToStringSet( arg1, excludeds );
flags = PyInt_AsLong( arg2 );
} else {
flags = PyInt_AsLong( arg1 );
}
cell->flattenNets( instance, excludeds, flags );
HCATCH
Py_RETURN_NONE;
}