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