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:
parent
5b6bc7c91b
commit
205a6877db
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
@ -1211,6 +1212,10 @@ class BlockConf ( GaugeConf ):
|
|||
self.cloneds.append( masterCell )
|
||||
return
|
||||
|
||||
def useHTree ( self, netName ):
|
||||
if not netName in self.hTreeNames:
|
||||
self.hTreeNames.append( netName );
|
||||
|
||||
def save ( self, flags ):
|
||||
"""
|
||||
Frontend to BlockConf.rsave(). Append the "_cts" suffix to the cloned
|
||||
|
|
|
@ -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) )
|
|
@ -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:
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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;
|
||||
|
@ -932,6 +933,7 @@ namespace Etesian {
|
|||
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;
|
||||
|
@ -955,6 +957,7 @@ namespace Etesian {
|
|||
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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -80,10 +80,11 @@ extern "C" {
|
|||
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)
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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() ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -30,6 +30,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;
|
||||
|
||||
extern "C" {
|
||||
|
@ -730,30 +748,36 @@ extern "C" {
|
|||
{
|
||||
cdebug_log(20,0) << "PyCell_flattenNets()" << endl;
|
||||
|
||||
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." );
|
||||
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) {
|
||||
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 (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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue