1160 lines
44 KiB
Python
1160 lines
44 KiB
Python
|
|
# This file is part of the Coriolis Software.
|
|
# Copyright (c) Sorbonne Université 2020-2021, All Rights Reserved
|
|
#
|
|
# +-----------------------------------------------------------------+
|
|
# | C O R I O L I S |
|
|
# | C u m u l u s - P y t h o n T o o l s |
|
|
# | |
|
|
# | Author : Jean-Paul CHAPUT |
|
|
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
|
# | =============================================================== |
|
|
# | Python : "./plugins/matrixplacer.py" |
|
|
# +-----------------------------------------------------------------+
|
|
|
|
|
|
import sys
|
|
import traceback
|
|
import helpers
|
|
from helpers.io import ErrorMessage
|
|
from helpers.io import WarningMessage
|
|
from helpers.overlay import UpdateSession
|
|
from helpers import trace
|
|
import plugins
|
|
from Hurricane import Breakpoint
|
|
from Hurricane import DbU
|
|
from Hurricane import Box
|
|
from Hurricane import Net
|
|
from Hurricane import Cell
|
|
from Hurricane import Instance
|
|
from Hurricane import Transformation
|
|
from plugins.chip.configuration import GaugeConf
|
|
|
|
|
|
DIRECT = 0x0001
|
|
REVERSE = 0x0002
|
|
BACKLASH = 0x0004
|
|
|
|
|
|
def dictKeysStr ( dictionary ):
|
|
keys = dictionary.keys()
|
|
keys.sort()
|
|
s = '{'
|
|
for i in range(len(keys)):
|
|
if i: s += ','
|
|
s += '{}'.format(keys[i])
|
|
s += '}'
|
|
return s
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
# Class : Signature.
|
|
|
|
class Signature ( object ):
|
|
|
|
def __init__ ( self, instance ):
|
|
self.instance = instance
|
|
self.rchilds = []
|
|
for plug in self.instance.getConnectedPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
if masterNet.getDirection() != Net.Direction.OUT: continue
|
|
for outPlug in plug.getNet().getPlugs():
|
|
outInstance = outPlug.getInstance()
|
|
self.rchilds.append( outInstance.getMasterCell().getName() )
|
|
self.rchilds.sort()
|
|
|
|
def __cmp__ ( self, other ):
|
|
if self.instance.getMasterCell().getName() < other.instance.getMasterCell().getName(): return -1
|
|
if self.instance.getMasterCell().getName() > other.instance.getMasterCell().getName(): return +1
|
|
|
|
if len(self.rchilds) < len(other.rchilds): return -1
|
|
if len(self.rchilds) > len(other.rchilds): return +1
|
|
#print( 'number of childs OK, {}' .format(len(self.rchilds)))
|
|
for i in range(len(self.rchilds)):
|
|
if self.rchilds[i] < other.rchilds[i]: return -1
|
|
if self.rchilds[i] > other.rchilds[i]: return +1
|
|
# print( 'rchilds[{}] OK'.format(i) )
|
|
#if self.instance.getId() < other.instance.getId(): return -1
|
|
#if self.instance.getId() > other.instance.getId(): return +1
|
|
return 0
|
|
|
|
def __str__ ( self ):
|
|
s = self.instance.getName() + ':' + str(self.rchilds)
|
|
return s
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
# Class : NetDatas.
|
|
|
|
class NetDatas ( object ):
|
|
"""
|
|
Datas associated to a Net in a DAG.
|
|
"""
|
|
|
|
REACHED = 0x0001
|
|
INLOOP = 0x0002
|
|
|
|
def __init__ ( self, net ):
|
|
self.net = net
|
|
self.flags = 0
|
|
self.depthSpan = [ -1, -1 ]
|
|
self._dtags = {}
|
|
self._rtags = {}
|
|
self.plugCount = 0
|
|
for plug in self.net.getPlugs(): self.plugCount += 1
|
|
|
|
trace( 500, '\tNew NetDatas:{}\n'.format(self) )
|
|
return
|
|
|
|
@property
|
|
def id ( self ): return self.net.getId()
|
|
|
|
@property
|
|
def rtags ( self ): return self._rtags
|
|
|
|
@property
|
|
def dtags ( self ): return self._dtags
|
|
|
|
@property
|
|
def krtags ( self ): return dictKeysStr(self._rtags)
|
|
|
|
@property
|
|
def kdtags ( self ): return dictKeysStr(self._dtags)
|
|
|
|
@property
|
|
def minDepth ( self ): return self.depthSpan[0]
|
|
|
|
@property
|
|
def maxDepth ( self ): return self.depthSpan[1]
|
|
|
|
def updateDepth ( self, depth, direction ):
|
|
i = 0 if direction & DIRECT else 1
|
|
if self.depthSpan[i] < 0:
|
|
self.depthSpan[i] = depth
|
|
else:
|
|
self.depthSpan[i] = min( self.depthSpan[i], depth )
|
|
|
|
def consolidateDepth ( self, dagDepth ):
|
|
self.depthSpan[1] = dagDepth-1 - self.depthSpan[1]
|
|
|
|
@property
|
|
def reached ( self ): return self.flags & NetDatas.REACHED
|
|
|
|
@reached.setter
|
|
def reached ( self, state ):
|
|
if state: self.flags |= NetDatas.REACHED
|
|
else: self.flags &= ~NetDatas.REACHED
|
|
|
|
@property
|
|
def inloop ( self ): return self.flags & NetDatas.INLOOP
|
|
|
|
@inloop.setter
|
|
def inloop ( self, state ):
|
|
if state: self.flags |= NetDatas.INLOOP
|
|
else: self.flags &= ~NetDatas.INLOOP
|
|
|
|
def mergeTag ( self, tag, direction ):
|
|
if direction & BACKLASH:
|
|
tags = self._dtags if not(direction & DIRECT) else self._rtags
|
|
if not len(tags):
|
|
tags[tag] = 1
|
|
else:
|
|
tags = self._dtags if direction & DIRECT else self._rtags
|
|
if tag in tags: tags[tag] += 1
|
|
else: tags[tag] = 1
|
|
return
|
|
|
|
def mergeTags ( self, tags, direction ):
|
|
for tag in tags.keys(): self.mergeTag( tag, direction )
|
|
return
|
|
|
|
def __str__ ( self ):
|
|
s = '{} {} [{}:{}]'.format( self.net
|
|
, self.plugCount
|
|
, self.depthSpan[0]
|
|
, self.depthSpan[1] )
|
|
return s
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
# Class : InstanceDatas.
|
|
|
|
class InstanceDatas ( object ):
|
|
"""
|
|
Datas associated to an Instance in a DAG.
|
|
"""
|
|
|
|
REACHED = 0x0001
|
|
REGISTER = 0x0004
|
|
NO_INPUTS = 0x0008
|
|
NO_OUTPUTS = 0x0010
|
|
|
|
def __init__ ( self, instance ):
|
|
self.instance = instance
|
|
self.flags = 0
|
|
self._dtags = {}
|
|
self._rtags = {}
|
|
self.depthSpan = [ -1, -1 ]
|
|
self._matchSets = []
|
|
self.signature = Signature( self.instance )
|
|
|
|
masterCell = instance.getMasterCell()
|
|
if masterCell.getName().startswith('sff'):
|
|
self.flags |= InstanceDatas.REGISTER
|
|
else:
|
|
hasInputs = False
|
|
hasOutputs = False
|
|
for plug in instance.getConnectedPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
if masterNet.isSupply() or masterNet.isClock(): continue
|
|
if masterNet.getDirection() & Net.Direction.DirIn: hasInputs = True
|
|
if masterNet.getDirection() & Net.Direction.DirOut: hasOutputs = True
|
|
if not hasInputs:
|
|
self.flags |= InstanceDatas.NO_INPUTS
|
|
if not hasOutputs:
|
|
self.flags |= InstanceDatas.NO_OUTPUTS
|
|
|
|
trace( 500, '\tNew InstanceDatas:{}\n'.format(self) )
|
|
return
|
|
|
|
@property
|
|
def id ( self ): return self.instance.getId()
|
|
|
|
@property
|
|
def dtags ( self ): return self._dtags
|
|
|
|
@property
|
|
def rtags ( self ): return self._rtags
|
|
|
|
@property
|
|
def krtags ( self ): return dictKeysStr(self._rtags)
|
|
|
|
@property
|
|
def kdtags ( self ): return dictKeysStr(self._dtags)
|
|
|
|
@property
|
|
def register ( self ): return self.flags & InstanceDatas.REGISTER
|
|
|
|
@property
|
|
def noInputs ( self ): return self.flags & InstanceDatas.NO_INPUTS
|
|
|
|
@property
|
|
def noOutputs ( self ): return self.flags & InstanceDatas.NO_OUTPUTS
|
|
|
|
@property
|
|
def reached ( self ): return self.flags & InstanceDatas.REACHED
|
|
|
|
@reached.setter
|
|
def reached ( self, state ):
|
|
if state: self.flags |= InstanceDatas.REACHED
|
|
else: self.flags &= ~InstanceDatas.REACHED
|
|
|
|
@property
|
|
def inMatchSets ( self ): return len(self._matchSets)
|
|
|
|
@property
|
|
def matchSets ( self ): return self._matchSets
|
|
|
|
def addToMatchSet ( self, matchSet ):
|
|
self._matchSets.append( matchSet )
|
|
|
|
def updateDepth ( self, depth, direction ):
|
|
i = 0 if direction & DIRECT else 1
|
|
if self.depthSpan[i] < 0:
|
|
self.depthSpan[i] = depth
|
|
else:
|
|
self.depthSpan[i] = max( self.depthSpan[i], depth )
|
|
|
|
def consolidateDepth ( self, dagDepth ):
|
|
self.depthSpan[1] = dagDepth-1 - self.depthSpan[1]
|
|
|
|
def mergeTag ( self, tag, direction ):
|
|
if direction & BACKLASH:
|
|
tags = self._dtags if not(direction & DIRECT) else self._rtags
|
|
if not len(tags):
|
|
tags[tag] = 1
|
|
else:
|
|
tags = self._dtags if direction & DIRECT else self._rtags
|
|
if tag in tags: tags[tag] += 1
|
|
else: tags[tag] = 1
|
|
return
|
|
|
|
def mergeTags ( self, tags, direction ):
|
|
for tag in tags.keys(): self.mergeTag( tag, direction )
|
|
return
|
|
|
|
def __cmp__ ( self, other ):
|
|
if self.depthSpan[0] < other.depthSpan[0]: return -1
|
|
if self.depthSpan[0] > other.depthSpan[0]: return +1
|
|
return cmp( self.signature, other.signature )
|
|
|
|
def __str__ ( self ):
|
|
s = '{} [{}:{}]'.format( self.instance
|
|
, self.depthSpan[0]
|
|
, self.depthSpan[1] )
|
|
return s
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
# Class : MatchSet.
|
|
|
|
class MatchSet ( object ):
|
|
|
|
def __init__ ( self, row, col, tags ):
|
|
self.row = row
|
|
self.col = col
|
|
self.tags = tags
|
|
self.instancesDatas = []
|
|
self._length = 0
|
|
|
|
@property
|
|
def length ( self ):
|
|
if not self.instancesDatas or (self._length > 0): return self._length
|
|
for instanceDatas in self.instancesDatas:
|
|
if instanceDatas.inMatchSets > 1: continue
|
|
self._length += instanceDatas.instance.getMasterCell().getAbutmentBox().getWidth()
|
|
return self._length
|
|
|
|
def match ( self, cellDag ):
|
|
for instanceDatas in cellDag.directOrdereds:
|
|
matched = True
|
|
for tag in self.tags:
|
|
if not tag in instanceDatas.dtags \
|
|
and not tag in instanceDatas.rtags:
|
|
matched = False
|
|
break
|
|
if matched:
|
|
self.instancesDatas.append( instanceDatas )
|
|
instanceDatas.addToMatchSet( self )
|
|
self.instancesDatas.sort()
|
|
|
|
def isIsomorph ( self, other ):
|
|
count = len( self.instancesDatas )
|
|
trace( 500, '{} vs. {}'.format(count,len(other.instancesDatas)) )
|
|
if count != len(other.instancesDatas): return False
|
|
|
|
iself = 0
|
|
iother = 0
|
|
while iself < len(other.instancesDatas) and iother < len(other.instancesDatas):
|
|
skip = False
|
|
if self.instancesDatas[iself].inMatchSets > 1:
|
|
iself += 1
|
|
skip = True
|
|
if other.instancesDatas[iother].inMatchSets > 1:
|
|
iother += 1
|
|
skip = True
|
|
if skip: continue
|
|
if self.instancesDatas[iself].signature != other.instancesDatas[iother].signature:
|
|
trace( 500, ' [{}]:{}'.format(iself,self.instancesDatas[iself]) )
|
|
trace( 500, ' [{}]:{}'.format(iother,other.instancesDatas[iother]) )
|
|
return False
|
|
iself += 1
|
|
iother += 1
|
|
return True
|
|
|
|
def show ( self ):
|
|
print( 'Match set for tags: {}'.format(self.tags) )
|
|
print( ' {} instances matcheds.'.format(len(self.instancesDatas)) )
|
|
for i in range(len(self.instancesDatas)):
|
|
print( ' | {:02}: {} {}+{}'.format( i
|
|
, self.instancesDatas[i]
|
|
, self.instancesDatas[i].kdtags
|
|
, self.instancesDatas[i].krtags) )
|
|
for i in range(len(self.instancesDatas)):
|
|
if self.instancesDatas[i].inMatchSets > 1:
|
|
print( '[WARNING] {} affectations for {} {}+{}.'.format( self.instancesDatas[i].inMatchSets
|
|
, self.instancesDatas[i]
|
|
, self.instancesDatas[i].kdtags
|
|
, self.instancesDatas[i].krtags ) )
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
# Class : CellDag.
|
|
|
|
class CellDag ( object ):
|
|
"""
|
|
Build a DAG from the Cell netlist.
|
|
"""
|
|
|
|
def __init__ ( self, cell ):
|
|
trace( 500, ',+', '\tCellDag.__init__() on {}\n'.format(cell) )
|
|
self.cell = cell
|
|
self.instancesDatas = {}
|
|
self.netsDatas = {}
|
|
self.orderedNets = []
|
|
self.orderedInstances = []
|
|
self.directOrdereds = []
|
|
self.reverseOrdereds = []
|
|
self.depth = 0
|
|
self.dagDepth = 0
|
|
self.direction = DIRECT
|
|
self.matchSets = []
|
|
|
|
for instance in self.cell.getInstances():
|
|
instanceDatas = InstanceDatas( instance )
|
|
self.instancesDatas[ instanceDatas.id ] = instanceDatas
|
|
|
|
for net in self.cell.getNets():
|
|
netDatas = NetDatas( net )
|
|
self.netsDatas[ netDatas.id ] = netDatas
|
|
|
|
if not net.isExternal() or not net.getDirection() & Net.Direction.DirIn:
|
|
continue
|
|
trace( 500, '-' )
|
|
return
|
|
|
|
def consolidateDepth ( self ):
|
|
for datas in self.netsDatas.values():
|
|
datas.consolidateDepth( self.dagDepth )
|
|
for datas in self.instancesDatas.values():
|
|
datas.consolidateDepth( self.dagDepth )
|
|
return
|
|
|
|
def initDirect ( self ):
|
|
trace( 500, ',+', '\tCellDag.initDirect() on {}\n'.format(self.cell) )
|
|
self.depth = 0
|
|
self.direction = DIRECT
|
|
self.orderedNets = []
|
|
self.orderedInstances = []
|
|
|
|
for instance in self.cell.getInstances():
|
|
instanceDatas = self.lookup( instance )
|
|
instanceDatas.reached = False
|
|
|
|
for net in self.cell.getNets():
|
|
netDatas = self.lookup( net )
|
|
if net.getDirection() & Net.Direction.DirIn:
|
|
netDatas.reached = True
|
|
netDatas.updateDepth( 0, self.direction )
|
|
self.addOrdered( netDatas, 0 )
|
|
trace( 500, '\tDAG input:{}\n'.format(netDatas) )
|
|
else:
|
|
netDatas.reached = False
|
|
|
|
self.findStartInstances()
|
|
trace( 500, '-' )
|
|
return
|
|
|
|
def initReverse ( self ):
|
|
trace( 500, ',+', '\tCellDag.initReverse() on {}\n'.format(self.cell) )
|
|
self.depth = 0
|
|
self.direction = REVERSE
|
|
self.orderedNets = []
|
|
self.orderedInstances = []
|
|
|
|
for instance in self.cell.getInstances():
|
|
instanceDatas = self.lookup( instance )
|
|
instanceDatas.reached = False
|
|
|
|
for net in self.cell.getNets():
|
|
netDatas = self.lookup( net )
|
|
if net.getDirection() & Net.Direction.DirOut:
|
|
netDatas.reached = True
|
|
netDatas.updateDepth( 0, self.direction )
|
|
self.addOrdered( netDatas, 0 )
|
|
trace( 500, '\tR-DAG input:{}\n'.format(netDatas) )
|
|
else:
|
|
netDatas.reached = False
|
|
|
|
self.findStartInstances()
|
|
trace( 500, '-' )
|
|
return
|
|
|
|
def isInPropagateDirection ( self, net, direction=None ):
|
|
if direction is None: direction = self.direction
|
|
return not ( (direction & DIRECT and net.getDirection() != Net.Direction.OUT) \
|
|
or (direction & REVERSE and net.getDirection() != Net.Direction.IN ))
|
|
|
|
def lookup ( self, element ):
|
|
if isinstance(element,Net):
|
|
if element.getId() in self.netsDatas:
|
|
return self.netsDatas[element.getId()]
|
|
raise ErrorMessage( 1, 'CellDag.lookup(): Missing NetDatas for {}.'.format(element) )
|
|
if isinstance(element,Instance):
|
|
if element.getId() in self.instancesDatas:
|
|
return self.instancesDatas[element.getId()]
|
|
raise ErrorMessage( 1, 'CellDag.lookup(): Missing InstanceDatas for {}.'.format(element) )
|
|
raise ErrorMessage( 1, 'CellDag.lookup(): {} has not Datas support.'.format(element) )
|
|
|
|
def isOrdered ( self, element ):
|
|
return self.lookup(element).reached
|
|
|
|
def addOrdered ( self, datas, depth ):
|
|
if isinstance(datas,NetDatas):
|
|
datas.reached = True
|
|
datas.updateDepth( depth, self.direction )
|
|
while len(self.orderedNets) < depth+1:
|
|
self.orderedNets.append( {} )
|
|
self.orderedNets[depth][datas.id] = datas
|
|
if isinstance(datas,InstanceDatas):
|
|
datas.reached = True
|
|
datas.updateDepth( depth, self.direction )
|
|
while len(self.orderedInstances) < depth+1:
|
|
self.orderedInstances.append( {} )
|
|
self.orderedInstances[depth][datas.id] = datas
|
|
|
|
if self.direction & DIRECT:
|
|
self.directOrdereds.append( datas )
|
|
else:
|
|
self.reverseOrdereds.append( datas )
|
|
return
|
|
|
|
def addInstanceOutputs ( self, instance, depth, direction=None ):
|
|
for plug in instance.getConnectedPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
if not self.isInPropagateDirection(masterNet,direction): continue
|
|
netDatas = self.lookup( plug.getNet() )
|
|
self.addOrdered( netDatas, depth )
|
|
return
|
|
|
|
def findStartInstances ( self ):
|
|
for instance in self.cell.getInstances():
|
|
datas = self.lookup( instance )
|
|
if datas.register:
|
|
trace( 500, '\tREGISTER:{}\n'.format(instance) )
|
|
self.addInstanceOutputs( instance, 0, DIRECT )
|
|
if self.direction & DIRECT and datas.noInputs:
|
|
trace( 500, '\tNO-INPUTS:{}\n'.format(instance) )
|
|
self.addInstanceOutputs( instance, 0 )
|
|
if self.direction & REVERSE and datas.noOutputs:
|
|
trace( 500, '\tNO-R-INPUTS:{}\n'.format(instance) )
|
|
self.addInstanceOutputs( instance, 0 )
|
|
return
|
|
|
|
def processNetDatas ( self, netDatas ):
|
|
trace( 500, ',+', '\tCellDag.processNetDatas() {}\n'.format(netDatas) )
|
|
for plug in netDatas.net.getPlugs():
|
|
instance = plug.getInstance()
|
|
if self.isOrdered(instance): continue
|
|
self.processInstance( instance )
|
|
trace( 500, '-' )
|
|
return
|
|
|
|
def processInstance ( self, instance ):
|
|
trace( 500, ',+', '\tCellDag.processInstance() {}\n'.format(instance) )
|
|
datas = self.lookup( instance )
|
|
if datas.reached:
|
|
trace( 500, '-' )
|
|
return
|
|
|
|
reached = True
|
|
for plug in instance.getConnectedPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
if self.isInPropagateDirection(masterNet): continue
|
|
net = plug.getNet()
|
|
if not self.isOrdered(net):
|
|
trace( 500, '\tunordered:{}:{}\n'.format(net,masterNet) )
|
|
reached = False
|
|
break
|
|
else:
|
|
trace( 500, '\tordered:{}:{}\n'.format(net,masterNet) )
|
|
|
|
if reached:
|
|
trace( 500, '\tORDERED:{}\n'.format(instance) )
|
|
self.addOrdered( datas, self.depth )
|
|
|
|
self.addInstanceOutputs( instance, self.depth+1 )
|
|
|
|
for plug in instance.getConnectedPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
if not self.isInPropagateDirection(masterNet): continue
|
|
netDatas = self.lookup( plug.getNet() )
|
|
netDatas.updateDepth( self.depth+1, self.direction )
|
|
|
|
trace( 500, '-' )
|
|
|
|
def processNets ( self ):
|
|
trace( 500, ',+', '\tCellDag.processNets() @depth:{}\n'.format(self.depth) )
|
|
for depth in range(self.depth+1):
|
|
for id in self.orderedNets[depth].keys():
|
|
trace( 500, '\t| orderedNets[{}][{}] = {}\n'.format(depth,id,self.orderedNets[depth][id]) )
|
|
|
|
trace( 500, '+' )
|
|
for netDatas in self.orderedNets[self.depth].values():
|
|
self.processNetDatas( netDatas )
|
|
trace( 500, '--' )
|
|
|
|
def build ( self ):
|
|
self.initDirect()
|
|
while len(self.orderedNets) > self.depth:
|
|
trace( 500, '+' )
|
|
self.processNets()
|
|
self.depth += 1
|
|
trace( 500, '-' * self.depth )
|
|
self.dagDepth = max( self.dagDepth, self.depth )
|
|
|
|
self.initReverse()
|
|
while len(self.orderedNets) > self.depth:
|
|
trace( 500, '+' )
|
|
self.processNets()
|
|
self.depth += 1
|
|
trace( 500, '-' * self.depth )
|
|
self.dagDepth = max( self.dagDepth, self.depth )
|
|
|
|
self.consolidateDepth()
|
|
return
|
|
|
|
def showReverseCone ( self, reference, maxDepth ):
|
|
instance = None
|
|
if isinstance(reference,str):
|
|
instance = self.cell.getInstance( reference )
|
|
elif isinstance(reference,Instance):
|
|
instance = reference
|
|
elif isinstance(reference,InstanceDatas):
|
|
instance = reference.instance
|
|
if not instance: return
|
|
|
|
instanceDatas = self.lookup( instance )
|
|
if not instanceDatas:
|
|
trace( 500, '\t+ No datas for {}\n'.format(instance) )
|
|
return
|
|
|
|
s = 'dtags:{}'.format( instanceDatas.dtags )
|
|
s += ' rtags:{}'.format( instanceDatas.rtags )
|
|
trace( 500, ',+', '\t+ {} {}\n'.format(s,instance) )
|
|
|
|
for plug in instance.getConnectedPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
if masterNet.getDirection() == Net.Direction.IN \
|
|
and not (masterNet.isSupply() or masterNet.isClock()):
|
|
netDatas = self.lookup(plug.getNet())
|
|
s = 'dtags:{}'.format( netDatas.dtags )
|
|
s += ' rtags:{}'.format( netDatas.rtags )
|
|
trace( 500, '\t| {} input "{}" {}\n'.format(s,masterNet.getName(),netDatas.net) )
|
|
|
|
for driverPlug in plug.getNet().getPlugs():
|
|
if driverPlug == plug: continue
|
|
driverMasterNet = driverPlug.getMasterNet()
|
|
if driverMasterNet.getDirection() == Net.Direction.OUT \
|
|
and not (driverMasterNet.isSupply() or driverMasterNet.isClock()):
|
|
driverInstance = driverPlug.getInstance()
|
|
driverDatas = self.lookup( driverInstance )
|
|
if driverDatas.register:
|
|
trace( 500, '\t| register {} \n'.format(driverInstance) )
|
|
if maxDepth > 0:
|
|
self.showReverseCone( driverInstance, maxDepth-1 )
|
|
else:
|
|
trace( 500, '\t| Max depth {} \n'.format(driverInstance) )
|
|
|
|
trace( 500, '-' )
|
|
|
|
def showNetHistogram ( self ):
|
|
histogram = {}
|
|
for netDatas in self.netsDatas.values():
|
|
print( 'netDatas:{}'.format(netDatas) )
|
|
if netDatas.plugCount in histogram:
|
|
histogram[netDatas.plugCount] += 1
|
|
else:
|
|
histogram[netDatas.plugCount] = 1
|
|
orderedKeys = histogram.keys()
|
|
orderedKeys.sort()
|
|
for key in orderedKeys:
|
|
print( '[{}] = {}'.format(key,histogram[key]) )
|
|
return
|
|
|
|
def getConnectedInstances ( self, netDatas ):
|
|
instances = []
|
|
if isinstance(datas,NetDatas):
|
|
for plug in datas.net.getPlugs():
|
|
instanceDatas = self.lookup( plug.getInstance() )
|
|
instances.append( instanceDatas )
|
|
return instances
|
|
|
|
def show ( self ):
|
|
instancesNb = 0
|
|
for instance in self.cell.getInstances(): instancesNb += 1
|
|
|
|
instancesReacheds = 0
|
|
for datas in self.instancesDatas.values():
|
|
if datas.reached == True:
|
|
instancesReacheds += 1
|
|
|
|
print( 'CellDag.show() {}'.format(self.cell) )
|
|
print( 'instances reacheds: {} / {}'.format(instancesReacheds,instancesNb) )
|
|
depth = 0
|
|
for depthLayer in self.orderedInstances:
|
|
print( 'thickness of depth {}: {}'.format(depth,len(depthLayer)) )
|
|
for datas in self.orderedInstances[depth].values():
|
|
print( '[{0:03d}] {1}'.format(depth,datas.instance) )
|
|
depth += 1
|
|
|
|
print( 'nets ordereds:' )
|
|
depth = 0
|
|
for depthLayer in self.orderedNets:
|
|
print( 'thickness of depth {}: {}'.format(depth,len(depthLayer)) )
|
|
for datas in self.orderedNets[depth].values():
|
|
print( '[{0:03d}] {1}'.format(depth,datas) )
|
|
depth += 1
|
|
|
|
self.showNetHistogram()
|
|
return
|
|
|
|
def addNetTag ( self, netName, tag ):
|
|
net = self.cell.getNet( netName )
|
|
if not net:
|
|
print( ErrorMessage(1, 'CellDag.addNetTag(): No net named "{}", ignored.'.format(netName)) )
|
|
return
|
|
if not net.isExternal():
|
|
print( Warning('CellDag.addNetTag(): Net "{}" is not external.'.format(netName)) )
|
|
direction = DIRECT
|
|
if net.getDirection() & Net.Direction.DirOut: direction = REVERSE
|
|
if net.getDirection() & Net.Direction.DirIn: direction = DIRECT
|
|
netDatas = self.lookup( net )
|
|
if netDatas: netDatas.mergeTag( tag, direction )
|
|
return
|
|
|
|
def directPropagate ( self, count, backlash=False ):
|
|
trace( 500, ',+', '\tCellDag.directPropagate(): count:{}, backlash:{}\n'.format(count,backlash) )
|
|
direction = DIRECT
|
|
if backlash: direction |= BACKLASH
|
|
for iteration in range(count):
|
|
for instanceDatas in self.directOrdereds:
|
|
trace( 500, ',+', '\t+ direct:{}\n'.format(instanceDatas) )
|
|
for plug in instanceDatas.instance.getConnectedPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
if masterNet.getDirection() == Net.Direction.IN \
|
|
and not (masterNet.isSupply() or masterNet.isClock()):
|
|
netDatas = self.lookup(plug.getNet())
|
|
netTags = netDatas.dtags if not backlash else netDatas.rtags
|
|
instanceDatas.mergeTags( netTags, direction )
|
|
s = 'DTAGS:{}'.format( netTags )
|
|
s += ' rtags:{}'.format( netTags )
|
|
trace( 500, '\t| {} from {}\n'.format(s,netDatas.net) )
|
|
for plug in instanceDatas.instance.getConnectedPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
if masterNet.getDirection() == Net.Direction.OUT \
|
|
and not (masterNet.isSupply() or masterNet.isClock()):
|
|
netDatas = self.lookup(plug.getNet())
|
|
instanceTags = instanceDatas.dtags if not backlash else instanceDatas.rtags
|
|
netDatas.mergeTags( instanceTags, direction )
|
|
s = 'DTAGS:{}'.format( netTags )
|
|
s += ' rtags:{}'.format( netTags )
|
|
trace( 500, '\t> {} from {}\n'.format(s,netDatas.net) )
|
|
trace( 500, ',-' )
|
|
trace( 500, '-' )
|
|
return
|
|
|
|
def reversePropagate ( self, count, backlash=False ):
|
|
trace( 500, ',+', '\tCellDag.reversePropagate(): count:{}, backlash:{}\n'.format(count,backlash) )
|
|
direction = REVERSE
|
|
if backlash: direction |= BACKLASH
|
|
for iteration in range(count):
|
|
for instanceDatas in self.reverseOrdereds:
|
|
trace( 500, ',+', '\t+ reverse:{}\n'.format(instanceDatas) )
|
|
for plug in instanceDatas.instance.getConnectedPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
if masterNet.getDirection() == Net.Direction.OUT \
|
|
and not (masterNet.isSupply() or masterNet.isClock()):
|
|
netDatas = self.lookup(plug.getNet())
|
|
netTags = netDatas.rtags if not backlash else netDatas.dtags
|
|
instanceDatas.mergeTags( netTags, direction )
|
|
s = 'dtags:{}'.format( netDatas.dtags )
|
|
s += ' RTAGS:{}'.format( netDatas.rtags )
|
|
trace( 500, '\t| {} from {}\n'.format(s,netDatas.net) )
|
|
s = 'dtags:{}'.format( instanceDatas.dtags )
|
|
s += ' RTAGS:{}'.format( instanceDatas.rtags )
|
|
trace( 500, '\t> {}\n'.format(s) )
|
|
|
|
for plug in instanceDatas.instance.getConnectedPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
if masterNet.getDirection() == Net.Direction.IN \
|
|
and not (masterNet.isSupply() or masterNet.isClock()):
|
|
self.lookup(plug.getNet()).mergeTags( instanceDatas.rtags, direction )
|
|
netDatas = self.lookup(plug.getNet())
|
|
instanceTags = instanceDatas.rtags if not backlash else instanceDatas.dtags
|
|
netDatas.mergeTags( instanceTags, direction )
|
|
s = 'dtags:{}'.format( netDatas.dtags )
|
|
s += ' RTAGS:{}'.format( netDatas.rtags )
|
|
trace( 500, '\t| {} on {}\n'.format(s,netDatas.net) )
|
|
trace( 500, '-' )
|
|
|
|
trace( 500, '-' )
|
|
return
|
|
|
|
def createMatchSet ( self, row, col, tags ):
|
|
self.matchSets.append( MatchSet(row,col,tags) )
|
|
self.matchSets[-1].match( self )
|
|
return self.matchSets[-1]
|
|
|
|
def checkIsomorphy ( self ):
|
|
if len(self.matchSets) == 0: return False
|
|
reference = self.matchSets[0]
|
|
isomorphic = True
|
|
for i in range(len(self.matchSets)):
|
|
if not reference.isIsomorph(self.matchSets[i]):
|
|
print( Warning('CellDag.chackIsomorphy(): MatchSets {} and 0 differs.'.format(i)) )
|
|
isomorphic = False
|
|
return isomorphic
|
|
|
|
def showMultimatcheds ( self ):
|
|
count = 0
|
|
print( 'Multimatcheds instances:' )
|
|
for datas in self.directOrdereds:
|
|
if datas.inMatchSets < 2: continue
|
|
print( ' | {} {}+{}'.format(datas, datas.kdtags, datas.krtags) )
|
|
count += 1
|
|
print( 'Total multimatcheds instances: {}'.format(count) )
|
|
|
|
def showUnmatcheds ( self ):
|
|
count = 0
|
|
print( 'Unmatcheds instances:' )
|
|
for datas in self.directOrdereds:
|
|
if datas.inMatchSets > 0: continue
|
|
print( ' | {} {}+{}'.format(datas, datas.kdtags, datas.krtags) )
|
|
count += 1
|
|
print( 'Total unmatcheds instances: {}'.format(count) )
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
# Class : Column.
|
|
|
|
class Column ( object ):
|
|
|
|
def __init__ ( self, size=0 ):
|
|
self.rows = []
|
|
self.rowCaps = []
|
|
self.bottomRows = []
|
|
self.bottomAlign = 0
|
|
self._colWidth = 0
|
|
self._capWidth = 0
|
|
self._valid = False
|
|
self.expand( size )
|
|
|
|
def __getitem__ ( self, row ):
|
|
return self.rows[row]
|
|
|
|
def __setitem__ ( self, row, element ):
|
|
self.addRow( row, element )
|
|
|
|
def _update ( self ):
|
|
if self._valid: return
|
|
for element in self.rows:
|
|
if not (element is None):
|
|
self._colWidth = max( self._colWidth, element.length )
|
|
self._capWidth = 0
|
|
for elements in self.rowCaps:
|
|
capWidth = 0
|
|
for element in elements:
|
|
capWidth += element.instance.getMasterCell().getAbutmentBox().getWidth()
|
|
self._capWidth = max( self._capWidth, capWidth )
|
|
self._valid = True
|
|
|
|
@property
|
|
def width ( self ):
|
|
self._update()
|
|
return self._colWidth + self._capWidth
|
|
|
|
@property
|
|
def rowCount ( self ): return len(self.rows)
|
|
|
|
def expand ( self, size ):
|
|
self._valid = False
|
|
if size:
|
|
while len(self.rows) < size:
|
|
self.rows.append( None )
|
|
self.rowCaps.append( [] )
|
|
|
|
def addRow ( self, j, element=None ):
|
|
self._valid = False
|
|
self.expand( j+1 )
|
|
if isinstance(element,MatchSet):
|
|
self.rows[j] = element
|
|
|
|
def addRowCap ( self, element ):
|
|
self._valid = False
|
|
if not isinstance(element,InstanceDatas): return
|
|
tags = element.dtags.keys() + element.rtags.keys()
|
|
vtags = []
|
|
jspan = [ self.rowCount, 0 ]
|
|
for tag in tags:
|
|
if tag[0] == 'v': vtags.append( tag )
|
|
if tag[0] == 'h':
|
|
j = int(tag[1:])
|
|
jspan[0] = min( jspan[0], j )
|
|
jspan[1] = max( jspan[1], j )
|
|
if len(vtags) != 1:
|
|
print( ErrorMessage( 1, 'Column.addRowCap(): {} has not exactly *one* vertical tag ({}).'.format(element,vtags)) )
|
|
return
|
|
if jspan[0] > jspan[1]:
|
|
jspan = [ 0, self.rowCount ]
|
|
jinsert = jspan[0]
|
|
for j in range(jspan[0],jspan[1]+1):
|
|
if len(self.rowCaps[j]) < len(self.rowCaps[jinsert]):
|
|
jinsert = j
|
|
self.rowCaps[jinsert].append( element )
|
|
|
|
def addBottom ( self, element ):
|
|
if not isinstance(element,InstanceDatas): return
|
|
if not len(self.bottomRows): self.bottomRows.append( [] )
|
|
self.bottomRows[0].append( element )
|
|
|
|
def balanceBottomRows ( self ):
|
|
trace( 500, ',+', 'Column.balanceBottomrows()' )
|
|
if not len(self.bottomRows):
|
|
trace( 500, '-' )
|
|
return
|
|
|
|
bottomWidth = 0
|
|
for element in self.bottomRows[0]:
|
|
bottomWidth += element.instance.getMasterCell().getAbutmentBox().getWidth()
|
|
if bottomWidth > self.width:
|
|
splits = bottomWidth / self.width + 1
|
|
splitWidth = bottomWidth / splits #+ bottomWidth / (splits+1)
|
|
rowWidth = 0
|
|
elements = self.bottomRows[0]
|
|
trace( 500, '\t| column width: {}\n'.format(DbU.getValueString(self.width)) )
|
|
trace( 500, '\t| bottom width: {}\n'.format(DbU.getValueString(bottomWidth)) )
|
|
trace( 500, '\t| splits: {}\n'.format(splits) )
|
|
trace( 500, '\t| split width: {}\n'.format(DbU.getValueString(splitWidth)) )
|
|
self.bottomRows[0] = []
|
|
for element in elements:
|
|
abWidth = element.instance.getMasterCell().getAbutmentBox().getWidth()
|
|
if rowWidth+abWidth > splitWidth:
|
|
self.bottomRows.append( [] )
|
|
rowWidth = 0
|
|
self.bottomRows[-1].append( element )
|
|
rowWidth += abWidth
|
|
trace( 500, '-' )
|
|
|
|
def place ( self, xorigin, sliceHeight ):
|
|
trace( 500, ',+', '\tColumn.place() @{}\n'.format(DbU.getValueString(xorigin)) )
|
|
self._update()
|
|
regRows = len( self.rows )
|
|
botRows = self.bottomAlign
|
|
allRows = regRows + botRows
|
|
for j in range(regRows):
|
|
trace( 500, ',+', '\tplacing row {} (colW:{}, capW:{})\n' \
|
|
.format( j
|
|
, DbU.getValueString(self._colWidth)
|
|
, DbU.getValueString(self._capWidth)) )
|
|
if (j+botRows)%2:
|
|
y = (allRows - j) * sliceHeight
|
|
orient = Transformation.Orientation.MY
|
|
else:
|
|
y = (allRows - j - 1) * sliceHeight
|
|
orient = Transformation.Orientation.ID
|
|
x = xorigin
|
|
trace( 500, '\t+ Regular elements @{}\n'.format(DbU.getValueString(x)) )
|
|
for element in self.rows[j].instancesDatas:
|
|
if element.inMatchSets > 1: continue
|
|
element.instance.setTransformation ( Transformation(x,y,orient) )
|
|
element.instance.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
|
abWidth = element.instance.getMasterCell().getAbutmentBox().getWidth()
|
|
trace( 500, '\t| placed @({},{}) {}\n'.format( DbU.getValueString(x)
|
|
, DbU.getValueString(y)
|
|
, element.instance) )
|
|
x += abWidth
|
|
|
|
x = xorigin + self._colWidth
|
|
trace( 500, '\t+ Endcap elements @{}\n'.format(DbU.getValueString(x)) )
|
|
for element in self.rowCaps[j]:
|
|
element.instance.setTransformation ( Transformation(x,y,orient) )
|
|
element.instance.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
|
abWidth = element.instance.getMasterCell().getAbutmentBox().getWidth()
|
|
trace( 500, '\t| placed @({},{}) {}\n'.format( DbU.getValueString(x)
|
|
, DbU.getValueString(y)
|
|
, element.instance) )
|
|
x += abWidth
|
|
trace( 500, '-' )
|
|
|
|
for j in range(len(self.bottomRows)):
|
|
trace( 500, ',+', '\tplacing bottom row {} (colW:{}, capW:{})\n' \
|
|
.format( j
|
|
, DbU.getValueString(self._colWidth)
|
|
, DbU.getValueString(self._capWidth)) )
|
|
if j%2:
|
|
y = (allRows - j - regRows) * sliceHeight
|
|
orient = Transformation.Orientation.MY
|
|
else:
|
|
y = (allRows - j - regRows - 1) * sliceHeight
|
|
orient = Transformation.Orientation.ID
|
|
x = xorigin
|
|
trace( 500, '\t+ Bottom elements @{}\n'.format(DbU.getValueString(x)) )
|
|
for element in self.bottomRows[j]:
|
|
element.instance.setTransformation ( Transformation(x,y,orient) )
|
|
element.instance.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
|
abWidth = element.instance.getMasterCell().getAbutmentBox().getWidth()
|
|
trace( 500, '\t| placed @({},{}) {}\n'.format( DbU.getValueString(x)
|
|
, DbU.getValueString(y)
|
|
, element.instance) )
|
|
x += abWidth
|
|
x = xorigin + self._colWidth
|
|
trace( 500, '-' )
|
|
trace( 500, '-' )
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
# Class : MatrixPlacer.
|
|
|
|
class MatrixPlacer ( object ):
|
|
|
|
def __init__ ( self, cell ):
|
|
self.gaugeConf = GaugeConf()
|
|
self.cell = cell
|
|
self.columns = []
|
|
self.dag = CellDag( cell )
|
|
self.tagRows = {}
|
|
self.tagColumns = {}
|
|
self.dag.build()
|
|
|
|
def tagsToMatrix ( self, propagateSteps=2 ):
|
|
self.dag.directPropagate ( propagateSteps )
|
|
self.dag.reversePropagate( 1, True )
|
|
self.dag.reversePropagate( propagateSteps )
|
|
|
|
matchSets = []
|
|
for h in self.tagRows.keys():
|
|
for v in self.tagColumns.keys():
|
|
self.dag.createMatchSet( h, v, ['h{}'.format(h), 'v{}'.format(v)] )
|
|
self.addElement( v, h, self.dag.matchSets[-1] )
|
|
|
|
for instanceDatas in self.dag.instancesDatas.values():
|
|
if instanceDatas.inMatchSets < 2: continue
|
|
tags = instanceDatas.dtags.keys() + instanceDatas.rtags.keys()
|
|
vtags = []
|
|
for tag in tags:
|
|
if tag[0] == 'v': vtags.append( tag )
|
|
if len(vtags) != 1: continue
|
|
v = int( vtags[0][1:] )
|
|
self.addCapElement( v, instanceDatas )
|
|
|
|
for instanceDatas in self.dag.instancesDatas.values():
|
|
if instanceDatas.inMatchSets: continue
|
|
tags = instanceDatas.dtags.keys() + instanceDatas.rtags.keys()
|
|
print( 'Unmatched {} {}'.format(instanceDatas,tags) )
|
|
vtags = []
|
|
for tag in tags:
|
|
if tag[0] == 'v': vtags.append( tag )
|
|
if len(vtags) != 1: continue
|
|
v = int( vtags[0][1:] )
|
|
self.addBottomElement( v, instanceDatas )
|
|
|
|
self.finalizeBottom()
|
|
|
|
def tagRow ( self, row, nets ):
|
|
if not row in self.tagRows:
|
|
self.tagRows[row] = []
|
|
self.tagRows[row] += nets
|
|
for net in nets:
|
|
self.dag.addNetTag( net, 'h{}'.format(row) )
|
|
|
|
def tagColumn ( self, column, nets ):
|
|
if not column in self.tagColumns:
|
|
self.tagColumns[column] = []
|
|
self.tagColumns[column] += nets
|
|
for net in nets:
|
|
self.dag.addNetTag( net, 'v{}'.format(column) )
|
|
|
|
def expand ( self, columnSize, rowSize ):
|
|
for column in self.columns:
|
|
column.expand( rowSize )
|
|
while len(self.columns) < columnSize:
|
|
self.columns.append( Column(rowSize) )
|
|
|
|
def addElement ( self, i, j, matchSet ):
|
|
self.expand( i+1, j+1 )
|
|
if not (self.columns[i][j] is None):
|
|
print( ErrorMessage(1, 'MatrixPlacer.addElement(): Redefinition of matrix element [{},{}]'.format(i,j)) )
|
|
else:
|
|
self.columns[i][j] = matchSet
|
|
|
|
def addCapElement ( self, i, instanceDatas ):
|
|
self.columns[i].addRowCap( instanceDatas )
|
|
|
|
def addBottomElement ( self, i, instanceDatas ):
|
|
self.columns[i].addBottom( instanceDatas )
|
|
|
|
def finalizeBottom ( self ):
|
|
for i in range(len(self.columns)):
|
|
self.columns[i].balanceBottomRows()
|
|
|
|
bottomAlign = 0
|
|
for i in range(len(self.columns)):
|
|
bottomAlign = max( bottomAlign, len(self.columns[i].bottomRows) )
|
|
for i in range(len(self.columns)):
|
|
self.columns[i].bottomAlign = bottomAlign
|
|
|
|
def place ( self ):
|
|
with UpdateSession():
|
|
xcolumn = 0
|
|
sliceHeight = self.gaugeConf.getSliceHeight()
|
|
for i in range(len(self.columns)):
|
|
self.columns[i].place( xcolumn, sliceHeight )
|
|
xcolumn += self.columns[i].width
|
|
self.cell.setAbutmentBox( Box( 0, 0, xcolumn, (self.columns[0].rowCount+self.columns[0].bottomAlign)*sliceHeight) )
|
|
|
|
def checkUnplaceds ( self ):
|
|
for instanceDatas in self.dag.instancesDatas.values():
|
|
if instanceDatas.instance.getPlacementStatus() != Instance.PlacementStatus.PLACED:
|
|
print( ErrorMessage(1, 'MatrixPlace.checkUnplaceds(): Unplaced {}.'.format(instanceDatas)) )
|
|
|
|
def showTags ( self ):
|
|
print( 'MatrixPlacer on "{}"'.format(self.cell.getName()) )
|
|
print( ' Rows tags/nets: {}'.format(len(self.tagRows)) )
|
|
for item in self.tagRows.items():
|
|
print( ' | {:03} : {}'.format(item[0],item[1]) )
|
|
print( ' Columns tags/nets: {}'.format(len(self.tagColumns)) )
|
|
for item in self.tagColumns.items():
|
|
print( ' | {:03} : {}'.format(item[0],item[1]) )
|
|
|
|
def showGrid ( self ):
|
|
for ms in self.dag.matchSets:
|
|
ms.show()
|
|
self.dag.showMultimatcheds()
|
|
self.dag.showUnmatcheds()
|
|
#self.dag.checkIsomorphy()
|
|
|
|
|
|
# --------------------------------------------------------------------
|
|
# Plugin hook functions, unicornHook:menus, ScritMain:call
|
|
|
|
def unicornHook ( **kw ):
|
|
kw['beforeAction'] = 'misc.alpha'
|
|
|
|
#plugins.kwAddMenu ( 'placeAndRoute', 'P&&R', **kw )
|
|
plugins.kwUnicornHook( 'misc.alpha.matrixPlacer'
|
|
, 'Matrix Placer'
|
|
, 'Look for a Matrix-Like netlist strucure and place it'
|
|
, sys.modules[__name__].__file__
|
|
, **kw
|
|
)
|
|
return
|
|
|
|
|
|
def scriptMain ( **kw ):
|
|
rvalue = True
|
|
try:
|
|
#helpers.setTraceLevel( 500 )
|
|
cell, editor = plugins.kwParseMain( **kw )
|
|
|
|
matrix = MatrixPlacer( cell )
|
|
|
|
fuNb = 30
|
|
#fuNb = 4
|
|
gorwNb = 3
|
|
for fu in range(fuNb):
|
|
matrix.tagColumn( fu, ['readable_o({})'.format(fu)] )
|
|
matrix.tagColumn( fu, ['writable_o({})'.format(fu)] )
|
|
for gorwi in range(gorwNb):
|
|
matrix.tagRow( (fu*gorwNb + gorwi)*2 , ['gord{}_i({})'.format(gorwi+1,fu)] )
|
|
matrix.tagRow( (fu*gorwNb + gorwi)*2 + 1, ['gowr{}_i({})'.format(gorwi+1,fu)] )
|
|
matrix.showTags()
|
|
|
|
matrix.tagsToMatrix( 2 )
|
|
matrix.showGrid()
|
|
matrix.place()
|
|
matrix.checkUnplaceds()
|
|
if editor: editor.fit()
|
|
#Breakpoint.stop( 0, 'Showing cone' )
|
|
matrix.dag.showReverseCone( 'subckt_5_dm13_subckt_332_src3_c_63_subckt_112_sff1_x4', 10 )
|
|
|
|
return True
|
|
except Exception as e:
|
|
helpers.io.catch( e )
|
|
rvalue = False
|
|
|
|
sys.stdout.flush()
|
|
sys.stderr.flush()
|
|
|
|
return rvalue
|