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 );
|
//AutoSegment::setShortNetMode( true );
|
||||||
++shortNets;
|
++shortNets;
|
||||||
}
|
}
|
||||||
|
if (NetRoutingExtension::isManualDetailRoute(net))
|
||||||
|
continue;
|
||||||
if ( NetRoutingExtension::isManualGlobalRoute(net)
|
if ( NetRoutingExtension::isManualGlobalRoute(net)
|
||||||
or NetRoutingExtension::isAutomaticGlobalRoute(net)) {
|
or NetRoutingExtension::isAutomaticGlobalRoute(net)) {
|
||||||
DebugSession::open( net, 145, 150 );
|
DebugSession::open( net, 145, 150 );
|
||||||
|
|
|
@ -1057,7 +1057,9 @@ namespace Anabatic {
|
||||||
uint32_t total = 0;
|
uint32_t total = 0;
|
||||||
for ( Net* net : getCell()->getNets() ) {
|
for ( Net* net : getCell()->getNets() ) {
|
||||||
if (net->isSupply()) continue;
|
if (net->isSupply()) continue;
|
||||||
if (net->isClock ()) continue;
|
if ( NetRoutingExtension::isManualDetailRoute(net)
|
||||||
|
or NetRoutingExtension::isFixed(net))
|
||||||
|
continue;
|
||||||
antennaProtect( net, failed, total );
|
antennaProtect( net, failed, total );
|
||||||
}
|
}
|
||||||
cmess2 << Dots::asString ( " - Antenna gate maximum WL" , DbU::getValueString(etesian->getAntennaGateMaxWL()) ) << endl;
|
cmess2 << Dots::asString ( " - Antenna gate maximum WL" , DbU::getValueString(etesian->getAntennaGateMaxWL()) ) << endl;
|
||||||
|
|
|
@ -94,13 +94,13 @@ namespace Anabatic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getId() == 1518590) {
|
// if (getId() == 1518590) {
|
||||||
cerr << "AutoHorizontal::_postCreate(): " << this << endl;
|
// cerr << "AutoHorizontal::_postCreate(): " << this << endl;
|
||||||
cerr << "| Source contact:" << source << endl;
|
// cerr << "| Source contact:" << source << endl;
|
||||||
cerr << "| Source GCell: " << getGCell() << endl;
|
// cerr << "| Source GCell: " << getGCell() << endl;
|
||||||
cerr << "| Target contact:" << target << endl;
|
// cerr << "| Target contact:" << target << endl;
|
||||||
cerr << "| Target GCell: " << target->getGCell() << 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/bigvia.py
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/spares.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/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/timing.py
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/rsmt.py
|
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/rsmt.py
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/hfns1.py
|
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/hfns1.py
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
|
from copy import deepcopy
|
||||||
import Cfg
|
import Cfg
|
||||||
from Hurricane import Breakpoint, DbU, Box, Transformation, Point, \
|
from Hurricane import Breakpoint, DbU, Box, Transformation, Point, \
|
||||||
Box, Path, Layer, Occurrence, Net, \
|
Box, Path, Layer, Occurrence, Net, \
|
||||||
|
@ -35,7 +36,7 @@ from plugins import getParameter
|
||||||
from plugins.alpha.macro.macro import Macro
|
from plugins.alpha.macro.macro import Macro
|
||||||
from plugins.alpha.block import timing
|
from plugins.alpha.block import timing
|
||||||
from plugins.alpha.block.spares import Spares
|
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.hfns1 import BufferTree
|
||||||
#from plugins.alpha.block.hfns2 import BufferTree
|
#from plugins.alpha.block.hfns2 import BufferTree
|
||||||
#from plugins.alpha.block.hfns3 import BufferTree
|
#from plugins.alpha.block.hfns3 import BufferTree
|
||||||
|
@ -286,6 +287,7 @@ class Block ( object ):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
LUT = {}
|
LUT = {}
|
||||||
|
FLATTENED = 0x0001
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def lookup ( cell ):
|
def lookup ( cell ):
|
||||||
|
@ -300,10 +302,11 @@ class Block ( object ):
|
||||||
self.flags = 0
|
self.flags = 0
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
self.spares = Spares( self )
|
self.spares = Spares( self )
|
||||||
self.clockTrees = []
|
self.hTrees = []
|
||||||
self.hfnTrees = []
|
self.hfnTrees = []
|
||||||
self.blockInstances = []
|
self.blockInstances = []
|
||||||
self.placeHolderCount = 0
|
self.placeHolderCount = 0
|
||||||
|
self.excludedNets = deepcopy( self.conf.hTreeNames )
|
||||||
self.sides = { IoPin.WEST : Side( self.conf, IoPin.WEST )
|
self.sides = { IoPin.WEST : Side( self.conf, IoPin.WEST )
|
||||||
, IoPin.EAST : Side( self.conf, IoPin.EAST )
|
, IoPin.EAST : Side( self.conf, IoPin.EAST )
|
||||||
, IoPin.SOUTH : Side( self.conf, IoPin.SOUTH )
|
, IoPin.SOUTH : Side( self.conf, IoPin.SOUTH )
|
||||||
|
@ -329,7 +332,6 @@ class Block ( object ):
|
||||||
.format(self.conf.cell.getName()) )
|
.format(self.conf.cell.getName()) )
|
||||||
Block.LUT[ self.conf.cell ] = self
|
Block.LUT[ self.conf.cell ] = self
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _getInstance ( cell, pattern, level=0 ):
|
def _getInstance ( cell, pattern, level=0 ):
|
||||||
"""
|
"""
|
||||||
|
@ -370,6 +372,35 @@ class Block ( object ):
|
||||||
"""
|
"""
|
||||||
return Block._rgetInstance( self.conf.core, path )
|
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 ):
|
def setUnexpandPins ( self, sides ):
|
||||||
"""
|
"""
|
||||||
Prevent Pins from the selected sides to be stick out of one pitch.
|
Prevent Pins from the selected sides to be stick out of one pitch.
|
||||||
|
@ -433,43 +464,65 @@ class Block ( object ):
|
||||||
else:
|
else:
|
||||||
self.conf.setRoutingBb( self.conf.cell.getAbutmentBox() )
|
self.conf.setRoutingBb( self.conf.cell.getAbutmentBox() )
|
||||||
|
|
||||||
def addClockTrees ( self ):
|
def flattenNets ( self ):
|
||||||
"""Create the trunk of all the clock trees (recursive H-Tree)."""
|
if self.flags & Block.FLATTENED: return
|
||||||
print( ' o Building clock tree(s).' )
|
if self.conf.isCoreBlock:
|
||||||
af = CRL.AllianceFramework.get()
|
self.conf.corona.flattenNets( self.conf.icore, self.conf.hTreeNames, Cell.Flags_NoClockFlatten )
|
||||||
clockNets = []
|
else:
|
||||||
for net in self.conf.cellPnR.getNets():
|
self.conf.cell.flattenNets( None, self.excludedNets, Cell.Flags_NoClockFlatten )
|
||||||
if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net)
|
self.flags |= Block.FLATTENED
|
||||||
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 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.
|
if the H-Tree.
|
||||||
"""
|
"""
|
||||||
for clockTree in self.clockTrees:
|
for hTree in self.hTrees:
|
||||||
clockTree.splitClock()
|
hTree.splitNet()
|
||||||
|
|
||||||
def findHfnTrees4 ( self ):
|
def findHfnTrees4 ( self ):
|
||||||
"""Perform simple HFNS, just break nets regardless of placement."""
|
"""Perform simple HFNS, just break nets regardless of placement."""
|
||||||
print( ' o Building high fanout nets trees.' )
|
print( ' o Building high fanout nets trees.' )
|
||||||
if self.spares:
|
if self.spares:
|
||||||
if self.conf.isCoreBlock:
|
self.flattenNets()
|
||||||
self.conf.corona.flattenNets( self.conf.icore, Cell.Flags_NoClockFlatten )
|
|
||||||
else:
|
|
||||||
self.conf.cell.flattenNets( None, Cell.Flags_NoClockFlatten )
|
|
||||||
beginCount = self.conf.bufferConf.count
|
beginCount = self.conf.bufferConf.count
|
||||||
maxSinks = 10
|
maxSinks = 10
|
||||||
dots( 82
|
dots( 82
|
||||||
|
@ -578,7 +631,7 @@ class Block ( object ):
|
||||||
for side in self.sides.values():
|
for side in self.sides.values():
|
||||||
side.expand()
|
side.expand()
|
||||||
|
|
||||||
def place ( self ):
|
def initEtesian ( self ):
|
||||||
editor = self.conf.editor
|
editor = self.conf.editor
|
||||||
if self.conf.isCoreBlock:
|
if self.conf.isCoreBlock:
|
||||||
self.etesian = Etesian.EtesianEngine.create( self.conf.corona )
|
self.etesian = Etesian.EtesianEngine.create( self.conf.corona )
|
||||||
|
@ -588,9 +641,11 @@ class Block ( object ):
|
||||||
Breakpoint.stop( 100, 'Block.place(), corona loaded.')
|
Breakpoint.stop( 100, 'Block.place(), corona loaded.')
|
||||||
else:
|
else:
|
||||||
self.etesian = Etesian.EtesianEngine.create( self.conf.cell )
|
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:
|
if self.conf.placeArea:
|
||||||
self.etesian.setPlaceArea( self.conf.placeArea )
|
self.etesian.setPlaceArea( self.conf.placeArea )
|
||||||
self.etesian.getCell().flattenNets( None, Cell.Flags_NoClockFlatten )
|
|
||||||
if self.conf.useHFNS: self.etesian.doHFNS()
|
if self.conf.useHFNS: self.etesian.doHFNS()
|
||||||
self.etesian.place()
|
self.etesian.place()
|
||||||
Breakpoint.stop( 100, 'Placement done.' )
|
Breakpoint.stop( 100, 'Placement done.' )
|
||||||
|
@ -738,6 +793,7 @@ class Block ( object ):
|
||||||
blockInstance.block.build()
|
blockInstance.block.build()
|
||||||
if editor: editor.setCell( self.conf.cellPnR )
|
if editor: editor.setCell( self.conf.cellPnR )
|
||||||
self.conf.cfg.apply()
|
self.conf.cfg.apply()
|
||||||
|
self.initEtesian()
|
||||||
iteration = -1
|
iteration = -1
|
||||||
while True:
|
while True:
|
||||||
iteration += 1
|
iteration += 1
|
||||||
|
@ -748,14 +804,14 @@ class Block ( object ):
|
||||||
self.checkIoPins()
|
self.checkIoPins()
|
||||||
self.spares.build()
|
self.spares.build()
|
||||||
#if self.conf.useHFNS: self.findHfnTrees4()
|
#if self.conf.useHFNS: self.findHfnTrees4()
|
||||||
if self.conf.useClockTree: self.addClockTrees()
|
self.addHTrees()
|
||||||
#if self.conf.useHFNS: self.addHfnBuffers()
|
#if self.conf.useHFNS: self.addHfnBuffers()
|
||||||
if editor: editor.fit()
|
if editor: editor.fit()
|
||||||
#Breakpoint.stop( 0, 'Clock tree(s) done.' )
|
#Breakpoint.stop( 0, 'Clock tree(s) done.' )
|
||||||
self.place()
|
self.place()
|
||||||
#if self.conf.useHFNS: self.findHfnTrees()
|
#if self.conf.useHFNS: self.findHfnTrees()
|
||||||
break
|
break
|
||||||
if self.conf.useClockTree: self.splitClocks()
|
self.splitHTrees()
|
||||||
self.spares.removeUnusedBuffers()
|
self.spares.removeUnusedBuffers()
|
||||||
self.etesian.toHurricane()
|
self.etesian.toHurricane()
|
||||||
self.etesian.flattenPower()
|
self.etesian.flattenPower()
|
||||||
|
|
|
@ -1109,6 +1109,7 @@ class BlockConf ( GaugeConf ):
|
||||||
self.placeArea = None
|
self.placeArea = None
|
||||||
self.deltaAb = [ 0, 0, 0, 0 ]
|
self.deltaAb = [ 0, 0, 0, 0 ]
|
||||||
self.useClockTree = False
|
self.useClockTree = False
|
||||||
|
self.hTreeNames = [ ]
|
||||||
self.useHFNS = False
|
self.useHFNS = False
|
||||||
self.useSpares = True
|
self.useSpares = True
|
||||||
self.isBuilt = False
|
self.isBuilt = False
|
||||||
|
@ -1210,6 +1211,10 @@ class BlockConf ( GaugeConf ):
|
||||||
trace( 550, '\tNew cloned cell: "{}"\n'.format(masterCell) )
|
trace( 550, '\tNew cloned cell: "{}"\n'.format(masterCell) )
|
||||||
self.cloneds.append( masterCell )
|
self.cloneds.append( masterCell )
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def useHTree ( self, netName ):
|
||||||
|
if not netName in self.hTreeNames:
|
||||||
|
self.hTreeNames.append( netName );
|
||||||
|
|
||||||
def save ( self, flags ):
|
def save ( self, flags ):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
# | Author : Jean-Paul CHAPUT |
|
# | Author : Jean-Paul CHAPUT |
|
||||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
# | 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 sys
|
||||||
import os.path
|
import os.path
|
||||||
import Cfg
|
import Cfg
|
||||||
from Hurricane import Breakpoint
|
from Hurricane import Breakpoint, DbU, Box, Transformation, Box, \
|
||||||
from Hurricane import DbU
|
Path, Layer, Occurrence, Net, HyperNet, \
|
||||||
from Hurricane import Box
|
RoutingPad, Horizontal, Vertical, Contact, \
|
||||||
from Hurricane import Transformation
|
Pin, Plug, Instance
|
||||||
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
|
|
||||||
import CRL
|
import CRL
|
||||||
from CRL import RoutingLayerGauge
|
from CRL import RoutingLayerGauge
|
||||||
from helpers import trace
|
from helpers import trace
|
||||||
from helpers.io import ErrorMessage
|
from helpers.io import ErrorMessage, WarningMessage, catch
|
||||||
from helpers.io import WarningMessage
|
|
||||||
from helpers.io import catch
|
|
||||||
from helpers.overlay import UpdateSession
|
from helpers.overlay import UpdateSession
|
||||||
from plugins import getParameter
|
from plugins import getParameter
|
||||||
from plugins.alpha import utils
|
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.spares = spares
|
||||||
self.clockNet = clockNet
|
self.treeNetOcc = treeNetOcc
|
||||||
self.clockIndex = index
|
self.treeIndex = index
|
||||||
self.subNets = []
|
self.subNets = []
|
||||||
if not self.clockNet.isClock():
|
#if not self.treeNetOcc.getEntity().isClock():
|
||||||
print( WarningMessage( 'ClockTree.__init__(): Net "{}" is not of CLOCK type.' \
|
# print( WarningMessage( 'HTree.__init__(): Net "{}" is not of CLOCK type.' \
|
||||||
.format(self.clockNet.getName()) ))
|
# .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 ):
|
def destroy ( self ):
|
||||||
trace( 550, ',+', '\tClockTree.destroy() "{}"\n'.format(self.clockNet.getName()) )
|
trace( 550, ',+', '\tHTree.destroy() "{}"\n'.format(self.treeNet.getName()) )
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
for subNet in self.subNets + [ self.clockNet ]:
|
for subNet in self.subNets + [ self.treeNet ]:
|
||||||
components = []
|
components = []
|
||||||
for comp in subNet.getComponents():
|
for comp in subNet.getComponents():
|
||||||
if isinstance(comp,RoutingPad): components.append( comp )
|
if isinstance(comp,RoutingPad): components.append( comp )
|
||||||
if isinstance(comp,Pin ): components.append( comp )
|
if isinstance(comp,Pin ): components.append( comp )
|
||||||
for comp in components:
|
for comp in components:
|
||||||
comp.destroy()
|
comp.destroy()
|
||||||
if subNet != self.clockNet:
|
if subNet != self.treeNet:
|
||||||
subNet.destroy()
|
subNet.destroy()
|
||||||
trace( 550, '-' )
|
trace( 550, '-' )
|
||||||
|
|
||||||
|
@ -82,7 +81,7 @@ class ClockTree ( object ):
|
||||||
if qt.isLeaf(): return False
|
if qt.isLeaf(): return False
|
||||||
qt.rconnectBuffer()
|
qt.rconnectBuffer()
|
||||||
driverNet = qt.bOutputPlug.getNet()
|
driverNet = qt.bOutputPlug.getNet()
|
||||||
driverNet.setType( Net.Type.CLOCK )
|
driverNet.setType( self.treeNet.getType() )
|
||||||
for leaf in qt.leafs:
|
for leaf in qt.leafs:
|
||||||
leaf.bInputPlug.setNet( driverNet )
|
leaf.bInputPlug.setNet( driverNet )
|
||||||
self._rconnectHTree( leaf )
|
self._rconnectHTree( leaf )
|
||||||
|
@ -92,7 +91,7 @@ class ClockTree ( object ):
|
||||||
"""
|
"""
|
||||||
Recursively build one HTree branch for all non-terminal nodes of the QuadTree.
|
Recursively build one HTree branch for all non-terminal nodes of the QuadTree.
|
||||||
"""
|
"""
|
||||||
trace( 550, ',+', '\tClockTree._rrouteHTree() {}\n'.format(qt.bOutputPlug.getNet()) )
|
trace( 550, ',+', '\tHTree._rrouteHTree() {}\n'.format(qt.bOutputPlug.getNet()) )
|
||||||
trace( 550, '\tOn: {}\n'.format(qt) )
|
trace( 550, '\tOn: {}\n'.format(qt) )
|
||||||
if qt.isLeaf():
|
if qt.isLeaf():
|
||||||
trace( 550, '-' )
|
trace( 550, '-' )
|
||||||
|
@ -165,13 +164,13 @@ class ClockTree ( object ):
|
||||||
gaugeConf.setStackPosition( brContact, rightX, blY )
|
gaugeConf.setStackPosition( brContact, rightX, blY )
|
||||||
gaugeConf.createVertical ( rightContact, brContact, rightX, 0 )
|
gaugeConf.createVertical ( rightContact, brContact, rightX, 0 )
|
||||||
if qt.isRoot():
|
if qt.isRoot():
|
||||||
ckNet = self.clockNet
|
ckNet = self.treeNet
|
||||||
if not self.spares.conf.isCoreBlock:
|
if not self.spares.conf.isCoreBlock:
|
||||||
trace( 550, '\tRemoving any previous pin...\n' )
|
trace( 550, '\tRemoving any previous pin...\n' )
|
||||||
pins = []
|
pins = []
|
||||||
for pin in ckNet.getPins(): pins.append( pin )
|
for pin in ckNet.getPins(): pins.append( pin )
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
print( WarningMessage('ClockTree._rrouteHTree(): Removing {}.'.format(pin)) )
|
print( WarningMessage('HTree._rrouteHTree(): Removing {}.'.format(pin)) )
|
||||||
pin.destroy()
|
pin.destroy()
|
||||||
layerGauge = gaugeConf.vRoutingGauge
|
layerGauge = gaugeConf.vRoutingGauge
|
||||||
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
|
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
|
||||||
|
@ -196,41 +195,44 @@ class ClockTree ( object ):
|
||||||
|
|
||||||
def buildHTree ( self ):
|
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.
|
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.
|
buffers of the leafs of the QuadTree.
|
||||||
"""
|
"""
|
||||||
qt = self.spares.quadTree
|
qt = self.spares.quadTree
|
||||||
qt.bufferTag = self.clockNet.getName()
|
qt.bufferTag = self.treeNet.getName()
|
||||||
qt.rselectBuffer( self.clockIndex, self.clockIndex, Spares.CHECK_USED|Spares.MARK_USED)
|
qt.rselectBuffer( self.treeIndex, self.treeIndex, Spares.CHECK_USED|Spares.MARK_USED)
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
self._rconnectHTree( qt )
|
self._rconnectHTree( qt )
|
||||||
self._rrouteHTree ( qt )
|
self._rrouteHTree ( qt )
|
||||||
|
|
||||||
def splitClock ( self ):
|
def splitNet ( self ):
|
||||||
"""
|
"""
|
||||||
Disconnect the registers from the main clock and reconnect them to
|
Disconnect the sinks from the main tree and reconnect them to
|
||||||
the leaf buffers of the clock tree.
|
the leaf buffers of the tree tree.
|
||||||
"""
|
"""
|
||||||
bufferConf = self.spares.conf.bufferConf
|
bufferConf = self.spares.conf.bufferConf
|
||||||
quadTree = self.spares.quadTree
|
quadTree = self.spares.quadTree
|
||||||
quadTree.bufferTag = self.clockNet.getName()
|
quadTree.bufferTag = self.treeNet.getName()
|
||||||
quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 )
|
quadTree.rselectBuffer( self.treeIndex, self.treeIndex, 0 )
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
coronaPlugs = []
|
driverPlugs = []
|
||||||
hyperClock = HyperNet.create( Occurrence(self.clockNet) )
|
hyperNet = HyperNet.create( Occurrence(self.treeNet) )
|
||||||
for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences():
|
for plugOcc in hyperNet.getTerminalNetlistPlugOccurrences():
|
||||||
if quadTree.isUnderArea(plugOccurrence):
|
trace( 550, '\tReattach "{}"\n'.format(plugOcc) )
|
||||||
quadTree.attachToLeaf( plugOccurrence )
|
plug = plugOcc.getEntity()
|
||||||
|
if not (plug.getMasterNet().getDirection() & Net.Direction.OUT) \
|
||||||
|
and quadTree.isUnderArea(plugOcc):
|
||||||
|
quadTree.attachToLeaf( plugOcc )
|
||||||
else:
|
else:
|
||||||
coronaPlugs.append( plugOccurrence )
|
driverPlugs.append( plugOcc )
|
||||||
quadTree.rsplitNetlist()
|
quadTree.rsplitNetlist()
|
||||||
if self.spares.conf.isCoreBlock:
|
if self.spares.conf.isCoreBlock:
|
||||||
plug = utils.getPlugByName( quadTree.buffer, bufferConf.input )
|
plug = utils.getPlugByName( quadTree.buffer, bufferConf.input )
|
||||||
plug.setNet( self.clockNet )
|
plug.setNet( self.treeNet )
|
||||||
trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.clockNet.getName()) )
|
trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.treeNet.getName()) )
|
||||||
trace( 550, '\tPlug of "{}" (Cell:{})\n'.format(self.clockNet.getName()
|
trace( 550, '\tPlug of "{}" (Cell:{})\n'.format(self.treeNet.getName()
|
||||||
,self.clockNet.getCell()) )
|
,self.treeNet.getCell()) )
|
||||||
for plug in self.clockNet.getPlugs():
|
for plug in self.treeNet.getPlugs():
|
||||||
trace( 550, '\t| {}\n'.format(plug) )
|
trace( 550, '\t| {}\n'.format(plug) )
|
|
@ -120,7 +120,7 @@ class Chip ( Block ):
|
||||||
if self.conf.routingGauge.hasPowerSupply():
|
if self.conf.routingGauge.hasPowerSupply():
|
||||||
power = plugins.alpha.chip.powerplane.Builder( self.conf )
|
power = plugins.alpha.chip.powerplane.Builder( self.conf )
|
||||||
power.connectPower()
|
power.connectPower()
|
||||||
power.connectClocks()
|
power.connectHTrees( self.hTrees )
|
||||||
power.doLayout()
|
power.doLayout()
|
||||||
Breakpoint.stop( 101, 'After Query power.' )
|
Breakpoint.stop( 101, 'After Query power.' )
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -455,23 +455,23 @@ class Builder ( object ):
|
||||||
trace( 550, '-' )
|
trace( 550, '-' )
|
||||||
self.activePlane = None
|
self.activePlane = None
|
||||||
|
|
||||||
def _connectClock ( self, ck, trackNb ):
|
def _connectHTree ( self, coronaNet, trackNb ):
|
||||||
trace( 550, '\tpower.Builder._connectClock() {}\n'.format(ck) )
|
trace( 550, '\tpower.Builder._connectHTree() {} on track {}\n'.format(coronaNet,trackNb) )
|
||||||
blockCk = None
|
coreNet = None
|
||||||
for plug in self.conf.icore.getPlugs():
|
for plug in self.conf.icore.getPlugs():
|
||||||
if plug.getNet() == ck:
|
if plug.getNet() == coronaNet:
|
||||||
blockCk = plug.getMasterNet()
|
coreNet = plug.getMasterNet()
|
||||||
if not blockCk:
|
if not coreNet:
|
||||||
raise ErrorMessage( 1, 'Block "{}" has no net connected to the clock "{}".' \
|
raise ErrorMessage( 1, 'Block "{}" has no net connected to the H-Tree "{}".' \
|
||||||
.format(self.conf.icore.getName(),ck.getName()) )
|
.format(self.conf.icore.getName(),coronaNet.getName()) )
|
||||||
return
|
return
|
||||||
htPlugs = []
|
htPlugs = []
|
||||||
for plug in ck.getPlugs():
|
for plug in coronaNet.getPlugs():
|
||||||
if plug.getInstance().isTerminalNetlist():
|
if plug.getInstance().isTerminalNetlist():
|
||||||
htPlugs.append( plug )
|
htPlugs.append( plug )
|
||||||
if len(htPlugs) != 1:
|
if len(htPlugs) != 1:
|
||||||
message = [ 'Clock "{}" of block "{}" is not organized as a H-Tree ({} plugs).' \
|
message = [ 'Net "{}" of block "{}" is not organized as a H-Tree ({} plugs).' \
|
||||||
.format( ck.getName()
|
.format( coronaNet.getName()
|
||||||
, self.conf.icore.getName()
|
, self.conf.icore.getName()
|
||||||
, len(htPlugs)) ]
|
, len(htPlugs)) ]
|
||||||
for plug in htPlugs:
|
for plug in htPlugs:
|
||||||
|
@ -479,17 +479,17 @@ class Builder ( object ):
|
||||||
raise ErrorMessage( 1, message )
|
raise ErrorMessage( 1, message )
|
||||||
return
|
return
|
||||||
coronaPin = None
|
coronaPin = None
|
||||||
for pin in ck.getPins():
|
for pin in coronaNet.getPins():
|
||||||
coronaPin = pin
|
coronaPin = pin
|
||||||
break
|
break
|
||||||
if not coronaPin:
|
if not coronaPin:
|
||||||
message = [ 'Clock "{}" of block "{}" is not connected to a corona Pin.' \
|
message = [ 'Net "{}" of block "{}" is not connected to a corona Pin.' \
|
||||||
.format( ck.getName() , self.conf.icore.getName() ) ]
|
.format( coronaNet.getName() , self.conf.icore.getName() ) ]
|
||||||
raise ErrorMessage( 1, message )
|
raise ErrorMessage( 1, message )
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
coronaAb = self.conf.cellPnR.getAbutmentBox()
|
coronaAb = self.conf.cellPnR.getAbutmentBox()
|
||||||
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()), ck, 0 )
|
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()), coronaNet, 0 )
|
||||||
pinRp = self.conf.rpAccessByOccurrence( Occurrence(coronaPin , Path()), ck, 0 )
|
pinRp = self.conf.rpAccessByOccurrence( Occurrence(coronaPin , Path()), coronaNet, 0 )
|
||||||
trace( 550, '\tpinRp={}\n'.format(pinRp) )
|
trace( 550, '\tpinRp={}\n'.format(pinRp) )
|
||||||
self.conf.expandMinArea( bufferRp )
|
self.conf.expandMinArea( bufferRp )
|
||||||
self.conf.expandMinArea( pinRp )
|
self.conf.expandMinArea( pinRp )
|
||||||
|
@ -508,40 +508,39 @@ class Builder ( object ):
|
||||||
isVertical = False
|
isVertical = False
|
||||||
axis = coronaAb.getXMin()
|
axis = coronaAb.getXMin()
|
||||||
if isVertical:
|
if isVertical:
|
||||||
pitch = self.conf.vRoutingGauge.getPitch()
|
pitch = self.conf.hRoutingGauge.getPitch()
|
||||||
yaxis = axis + pitch * trackNb
|
yaxis = axis + 2 * pitch * trackNb
|
||||||
|
trace( 550, '\tyaxis(request)={}\n'.format(DbU.getValueString(yaxis)) )
|
||||||
yaxis = self.conf.getNearestHorizontalTrack( yaxis, 0 )
|
yaxis = self.conf.getNearestHorizontalTrack( yaxis, 0 )
|
||||||
xaxisRp = self.conf.getNearestVerticalTrack( bufferRp.getX(), 0 )
|
xaxisRp = self.conf.getNearestVerticalTrack( bufferRp.getX(), 0 )
|
||||||
xaxisPin = self.conf.getNearestVerticalTrack( pin.getX(), 0 )
|
xaxisPin = self.conf.getNearestVerticalTrack( pin.getX(), 0 )
|
||||||
contact1 = self.conf.createContact( ck, xaxisRp , yaxis, 0 )
|
contact1 = self.conf.createContact( coronaNet, xaxisRp , yaxis, 0 )
|
||||||
contact2 = self.conf.createContact( ck, xaxisPin, yaxis, 0 )
|
contact2 = self.conf.createContact( coronaNet, xaxisPin, yaxis, 0 )
|
||||||
self.conf.createVertical ( bufferRp, contact1, xaxisRp , 0 )
|
self.conf.createVertical ( bufferRp, contact1, xaxisRp , 0 )
|
||||||
self.conf.createHorizontal( contact1, contact2, yaxis , 0 )
|
self.conf.createHorizontal( contact1, contact2, yaxis , 0 )
|
||||||
self.conf.createVertical ( contact2, pinRp , xaxisPin, 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, '\tcontact1={}\n'.format(contact1) )
|
||||||
trace( 550, '\tcontact2={}\n'.format(contact2) )
|
trace( 550, '\tcontact2={}\n'.format(contact2) )
|
||||||
else:
|
else:
|
||||||
pitch = self.conf.hRoutingGauge.getPitch()
|
pitch = self.conf.vRoutingGauge.getPitch()
|
||||||
xaxis = axis + pitch * trackNb
|
xaxis = axis + 2 * pitch * trackNb
|
||||||
|
trace( 550, '\txaxis(request)={} vpitch={}\n' \
|
||||||
|
.format(DbU.getValueString(xaxis), DbU.getValueString(pitch)) )
|
||||||
xaxis = self.conf.getNearestVerticalTrack( xaxis, 0 )
|
xaxis = self.conf.getNearestVerticalTrack( xaxis, 0 )
|
||||||
yaxisRp = self.conf.getNearestHorizontalTrack( bufferRp.getY(), 0 )
|
yaxisRp = self.conf.getNearestHorizontalTrack( bufferRp.getY(), 0 )
|
||||||
yaxisPin = self.conf.getNearestHorizontalTrack( pin.getY(), 0 )
|
yaxisPin = self.conf.getNearestHorizontalTrack( pin.getY(), 0 )
|
||||||
contact1 = self.conf.createContact( ck, xaxis, yaxisRp , 0 )
|
contact1 = self.conf.createContact( coronaNet, xaxis, yaxisRp , 0 )
|
||||||
contact2 = self.conf.createContact( ck, xaxis, yaxisPin, 0 )
|
contact2 = self.conf.createContact( coronaNet, xaxis, yaxisPin, 0 )
|
||||||
self.conf.createHorizontal( bufferRp, contact1, yaxisRp , 0 )
|
self.conf.createHorizontal( bufferRp, contact1, yaxisRp , 0 )
|
||||||
self.conf.createVertical ( contact1, contact2, xaxis , 0 )
|
self.conf.createVertical ( contact1, contact2, xaxis , 0 )
|
||||||
self.conf.createHorizontal( contact2, pinRp , yaxisPin, 0 )
|
self.conf.createHorizontal( contact2, pinRp , yaxisPin, 0 )
|
||||||
|
trace( 550, '\txaxis(track)={}\n'.format(DbU.getValueString(xaxis)) )
|
||||||
return
|
return
|
||||||
|
|
||||||
def connectClocks ( self ):
|
def connectHTrees ( self, hTrees ):
|
||||||
if not self.conf.useClockTree:
|
for i in range(len(hTrees)):
|
||||||
print( WarningMessage( "Clock tree generation has been disabled ('chip.clockTree':False)." ))
|
self._connectHTree( hTrees[i].treeNet, i+2 )
|
||||||
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 doLayout ( self ):
|
def doLayout ( self ):
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
|
|
|
@ -323,6 +323,7 @@ namespace Etesian {
|
||||||
, _fixedAbWidth (0)
|
, _fixedAbWidth (0)
|
||||||
, _diodeCount (0)
|
, _diodeCount (0)
|
||||||
, _bufferCount (0)
|
, _bufferCount (0)
|
||||||
|
, _excludedNets ()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
@ -792,7 +793,7 @@ namespace Etesian {
|
||||||
cmess1 << " - Building RoutingPads (transhierarchical)" << endl;
|
cmess1 << " - Building RoutingPads (transhierarchical)" << endl;
|
||||||
//getCell()->flattenNets( Cell::Flags::BuildRings|Cell::Flags::NoClockFlatten );
|
//getCell()->flattenNets( Cell::Flags::BuildRings|Cell::Flags::NoClockFlatten );
|
||||||
//getCell()->flattenNets( getBlockInstance(), 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;
|
bool tooManyInstances = false;
|
||||||
index_t instanceId = 0;
|
index_t instanceId = 0;
|
||||||
|
@ -929,9 +930,10 @@ namespace Etesian {
|
||||||
for ( Net* net : getCell()->getNets() )
|
for ( Net* net : getCell()->getNets() )
|
||||||
{
|
{
|
||||||
const char* excludedType = NULL;
|
const char* excludedType = NULL;
|
||||||
if (net->getType() == Net::Type::POWER ) excludedType = "POWER";
|
if (net->getType() == Net::Type::POWER ) excludedType = "POWER";
|
||||||
if (net->getType() == Net::Type::GROUND) excludedType = "GROUND";
|
if (net->getType() == Net::Type::GROUND) excludedType = "GROUND";
|
||||||
if (net->getType() == Net::Type::CLOCK ) excludedType = "CLOCK";
|
if (net->getType() == Net::Type::CLOCK ) excludedType = "CLOCK";
|
||||||
|
if (isExcluded(getString(net->getName()))) excludedType = "USER_EXCLUDED";
|
||||||
if (excludedType) {
|
if (excludedType) {
|
||||||
cparanoid << Warning( "%s is not a routable net (%s,excluded)."
|
cparanoid << Warning( "%s is not a routable net (%s,excluded)."
|
||||||
, getString(net).c_str(), excludedType ) << endl;
|
, getString(net).c_str(), excludedType ) << endl;
|
||||||
|
@ -952,9 +954,10 @@ namespace Etesian {
|
||||||
for ( Net* net : getCell()->getNets() )
|
for ( Net* net : getCell()->getNets() )
|
||||||
{
|
{
|
||||||
const char* excludedType = NULL;
|
const char* excludedType = NULL;
|
||||||
if (net->getType() == Net::Type::POWER ) excludedType = "POWER";
|
if (net->getType() == Net::Type::POWER ) excludedType = "POWER";
|
||||||
if (net->getType() == Net::Type::GROUND) excludedType = "GROUND";
|
if (net->getType() == Net::Type::GROUND) excludedType = "GROUND";
|
||||||
if (net->getType() == Net::Type::CLOCK ) excludedType = "CLOCK";
|
if (net->getType() == Net::Type::CLOCK ) excludedType = "CLOCK";
|
||||||
|
if (isExcluded(getString(net->getName()))) excludedType = "USER_EXCLUDED";
|
||||||
if (excludedType) continue;
|
if (excludedType) continue;
|
||||||
if (af->isBLOCKAGE(net->getName())) continue;
|
if (af->isBLOCKAGE(net->getName())) continue;
|
||||||
|
|
||||||
|
|
|
@ -456,6 +456,8 @@ namespace Etesian {
|
||||||
BufferDatas* bufferDatas = getBufferCells().getBiggestBuffer();
|
BufferDatas* bufferDatas = getBufferCells().getBiggestBuffer();
|
||||||
vector< tuple<Net*,uint32_t> > netDatas;
|
vector< tuple<Net*,uint32_t> > netDatas;
|
||||||
for ( Net* net : getCell()->getNets() ) {
|
for ( Net* net : getCell()->getNets() ) {
|
||||||
|
if (isExcluded(getString(net->getName()))) continue;
|
||||||
|
|
||||||
uint32_t rpCount = 0;
|
uint32_t rpCount = 0;
|
||||||
for ( RoutingPad* rp : net->getRoutingPads() ) {
|
for ( RoutingPad* rp : net->getRoutingPads() ) {
|
||||||
Occurrence rpOcc = rp->getPlugOccurrence();
|
Occurrence rpOcc = rp->getPlugOccurrence();
|
||||||
|
|
|
@ -77,13 +77,14 @@ extern "C" {
|
||||||
DirectVoidMethod(EtesianEngine,etesian,clearColoquinte)
|
DirectVoidMethod(EtesianEngine,etesian,clearColoquinte)
|
||||||
DirectVoidMethod(EtesianEngine,etesian,flattenPower)
|
DirectVoidMethod(EtesianEngine,etesian,flattenPower)
|
||||||
DirectVoidMethod(EtesianEngine,etesian,toHurricane)
|
DirectVoidMethod(EtesianEngine,etesian,toHurricane)
|
||||||
DirectGetUIntAttribute (PyEtesianEngine_doHFNS ,doHFNS ,PyEtesianEngine,EtesianEngine)
|
DirectGetUIntAttribute (PyEtesianEngine_doHFNS ,doHFNS ,PyEtesianEngine,EtesianEngine)
|
||||||
DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine)
|
DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine)
|
||||||
DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine)
|
DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine)
|
||||||
DirectSetDoubleAttribute(PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine)
|
DirectSetDoubleAttribute (PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine)
|
||||||
DirectSetDoubleAttribute(PyEtesianEngine_setAspectRatio ,setAspectRatio ,PyEtesianEngine,EtesianEngine)
|
DirectSetDoubleAttribute (PyEtesianEngine_setAspectRatio ,setAspectRatio ,PyEtesianEngine,EtesianEngine)
|
||||||
DirectGetLongAttribute (PyEtesianEngine_getFixedAbHeight,getFixedAbHeight,PyEtesianEngine,EtesianEngine)
|
DirectGetLongAttribute (PyEtesianEngine_getFixedAbHeight,getFixedAbHeight,PyEtesianEngine,EtesianEngine)
|
||||||
DirectGetLongAttribute (PyEtesianEngine_getFixedAbWidth ,getFixedAbWidth ,PyEtesianEngine,EtesianEngine)
|
DirectGetLongAttribute (PyEtesianEngine_getFixedAbWidth ,getFixedAbWidth ,PyEtesianEngine,EtesianEngine)
|
||||||
|
DirectSetCStringAttribute(PyEtesianEngine_exclude ,exclude ,PyEtesianEngine,EtesianEngine)
|
||||||
|
|
||||||
|
|
||||||
static PyObject* PyEtesianEngine_get ( PyObject*, PyObject* args )
|
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." }
|
, "Returns the Etesian engine attached to the Cell, None if there isn't." }
|
||||||
, { "create" , (PyCFunction)PyEtesianEngine_create , METH_VARARGS|METH_STATIC
|
, { "create" , (PyCFunction)PyEtesianEngine_create , METH_VARARGS|METH_STATIC
|
||||||
, "Create an Etesian engine on this cell." }
|
, "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
|
, { "getFixedAbHeight" , (PyCFunction)PyEtesianEngine_getFixedAbHeight , METH_NOARGS
|
||||||
, "Returns the forced abutment box height." }
|
, "Returns the forced abutment box height." }
|
||||||
, { "getFixedAbWidth" , (PyCFunction)PyEtesianEngine_getFixedAbWidth , METH_NOARGS
|
, { "getFixedAbWidth" , (PyCFunction)PyEtesianEngine_getFixedAbWidth , METH_NOARGS
|
||||||
|
|
|
@ -71,11 +71,13 @@ namespace Etesian {
|
||||||
typedef std::tuple<Instance*, std::vector<RoutingPad*> > InstanceInfos;
|
typedef std::tuple<Instance*, std::vector<RoutingPad*> > InstanceInfos;
|
||||||
typedef std::map<Instance*,size_t,DBo::CompareById> InstancesToIds;
|
typedef std::map<Instance*,size_t,DBo::CompareById> InstancesToIds;
|
||||||
typedef std::map<Net*,size_t,DBo::CompareById> NetsToIds;
|
typedef std::map<Net*,size_t,DBo::CompareById> NetsToIds;
|
||||||
|
typedef std::set<std::string> NetNameSet;
|
||||||
public:
|
public:
|
||||||
static const Name& staticGetName ();
|
static const Name& staticGetName ();
|
||||||
static EtesianEngine* create ( Cell* );
|
static EtesianEngine* create ( Cell* );
|
||||||
static EtesianEngine* get ( const Cell* );
|
static EtesianEngine* get ( const Cell* );
|
||||||
public:
|
public:
|
||||||
|
inline bool isExcluded ( std::string ) const;
|
||||||
virtual Configuration* getConfiguration ();
|
virtual Configuration* getConfiguration ();
|
||||||
virtual const Configuration* getConfiguration () const;
|
virtual const Configuration* getConfiguration () const;
|
||||||
virtual const Name& getName () const;
|
virtual const Name& getName () const;
|
||||||
|
@ -106,6 +108,7 @@ namespace Etesian {
|
||||||
inline void setViewer ( Hurricane::CellViewer* );
|
inline void setViewer ( Hurricane::CellViewer* );
|
||||||
inline Cell* getBlockCell () const;
|
inline Cell* getBlockCell () const;
|
||||||
inline Instance* getBlockInstance () const;
|
inline Instance* getBlockInstance () const;
|
||||||
|
inline const NetNameSet& getExcludedNets () const;
|
||||||
inline void setBlock ( Instance* );
|
inline void setBlock ( Instance* );
|
||||||
inline void setFixedAbHeight ( DbU::Unit );
|
inline void setFixedAbHeight ( DbU::Unit );
|
||||||
inline void setFixedAbWidth ( DbU::Unit );
|
inline void setFixedAbWidth ( DbU::Unit );
|
||||||
|
@ -136,6 +139,7 @@ namespace Etesian {
|
||||||
uint32_t doHFNS ();
|
uint32_t doHFNS ();
|
||||||
inline void useFeed ( Cell* );
|
inline void useFeed ( Cell* );
|
||||||
size_t findYSpin ();
|
size_t findYSpin ();
|
||||||
|
inline void exclude ( string netName );
|
||||||
void addFeeds ();
|
void addFeeds ();
|
||||||
void toHurricane ();
|
void toHurricane ();
|
||||||
void flattenPower ();
|
void flattenPower ();
|
||||||
|
@ -174,6 +178,7 @@ namespace Etesian {
|
||||||
DbU::Unit _fixedAbWidth;
|
DbU::Unit _fixedAbWidth;
|
||||||
uint32_t _diodeCount;
|
uint32_t _diodeCount;
|
||||||
uint32_t _bufferCount;
|
uint32_t _bufferCount;
|
||||||
|
NetNameSet _excludedNets;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Constructors & Destructors.
|
// Constructors & Destructors.
|
||||||
|
@ -229,6 +234,8 @@ namespace Etesian {
|
||||||
inline uint32_t EtesianEngine::_getNewDiodeId () { return _diodeCount++; }
|
inline uint32_t EtesianEngine::_getNewDiodeId () { return _diodeCount++; }
|
||||||
inline const Box& EtesianEngine::getPlaceArea () const { return _placeArea; }
|
inline const Box& EtesianEngine::getPlaceArea () const { return _placeArea; }
|
||||||
inline Area* EtesianEngine::getArea () const { return _area; }
|
inline Area* EtesianEngine::getArea () const { return _area; }
|
||||||
|
inline const EtesianEngine::NetNameSet&
|
||||||
|
EtesianEngine::getExcludedNets () const { return _excludedNets; }
|
||||||
|
|
||||||
inline void EtesianEngine::setBlock ( Instance* block )
|
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.
|
// Variables.
|
||||||
extern const char* missingEtesian;
|
extern const char* missingEtesian;
|
||||||
|
|
||||||
|
|
|
@ -820,6 +820,13 @@ void Cell::flattenNets (uint64_t flags )
|
||||||
|
|
||||||
void Cell::flattenNets ( const Instance* instance, 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;
|
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->isClock() and (flags & Flags::NoClockFlatten)) continue;
|
||||||
if (net->isPower() or net->isGround() or net->isBlockage()) continue;
|
if (net->isPower() or net->isGround() or net->isBlockage()) continue;
|
||||||
|
if (excludeds.find(getString(occurrence.getName())) != excludeds.end()) continue;
|
||||||
|
|
||||||
HyperNet hyperNet ( occurrence );
|
HyperNet hyperNet ( occurrence );
|
||||||
if ( not occurrence.getPath().isEmpty() ) {
|
if ( not occurrence.getPath().isEmpty() ) {
|
||||||
|
|
|
@ -728,9 +728,6 @@ void Net::_preDestroy()
|
||||||
// *******************
|
// *******************
|
||||||
{
|
{
|
||||||
cdebug_log(18,1) << "entering Net::_preDestroy: " << this << endl;
|
cdebug_log(18,1) << "entering Net::_preDestroy: " << this << endl;
|
||||||
if (getName() == "pipe_middle_0_rb[0]")
|
|
||||||
cerr << "entering Net::_preDestroy: " << this << endl;
|
|
||||||
|
|
||||||
Inherit::_preDestroy();
|
Inherit::_preDestroy();
|
||||||
|
|
||||||
cdebug_log(18,0) << "Net::_preDestroy: " << this << " slave Plugs..." << endl;
|
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 setAbstractedSupply(bool state) { _flags.set(Flags::AbstractedSupply,state); };
|
||||||
public: void flattenNets(uint64_t flags=Flags::BuildRings);
|
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, 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 createRoutingPadRings(uint64_t flags=Flags::BuildRings);
|
||||||
public: void setFlags(uint64_t flags) { _flags |= flags; }
|
public: void setFlags(uint64_t flags) { _flags |= flags; }
|
||||||
public: void resetFlags(uint64_t flags) { _flags &= ~flags; }
|
public: void resetFlags(uint64_t flags) { _flags &= ~flags; }
|
||||||
|
|
|
@ -29,6 +29,24 @@
|
||||||
|
|
||||||
namespace Isobar {
|
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;
|
using namespace Hurricane;
|
||||||
|
|
||||||
|
@ -730,30 +748,36 @@ extern "C" {
|
||||||
{
|
{
|
||||||
cdebug_log(20,0) << "PyCell_flattenNets()" << endl;
|
cdebug_log(20,0) << "PyCell_flattenNets()" << endl;
|
||||||
|
|
||||||
Instance* instance = NULL;
|
uint64_t flags = 0;
|
||||||
PyObject* arg0 = NULL;
|
set<string> excludeds;
|
||||||
PyObject* arg1 = NULL;
|
Instance* instance = NULL;
|
||||||
|
PyObject* arg0 = NULL;
|
||||||
|
PyObject* arg1 = NULL;
|
||||||
|
PyObject* arg2 = NULL;
|
||||||
|
|
||||||
HTRY
|
HTRY
|
||||||
METHOD_HEAD ( "Cell.flattenNets()" )
|
METHOD_HEAD ( "Cell.flattenNets()" )
|
||||||
__cs.init( "Cell.flattenNets" );
|
__cs.init( "Cell.flattenNets" );
|
||||||
if (not PyArg_ParseTuple(args,"O&O&:Cell.flattenNets"
|
if (not PyArg_ParseTuple(args,"OO|O:Cell.flattenNets", &arg0, &arg1, &arg2 )) {
|
||||||
,Converter,&arg0
|
PyErr_SetString( ConstructorError, "Cell.flattenNets(): Takes between two and three parameters." );
|
||||||
,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() );
|
|
||||||
return NULL;
|
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
|
HCATCH
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue