Commit 205a6877 authored by Jean-Paul Chaput's avatar Jean-Paul Chaput
Browse files

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.
parent 5b6bc7c9
......@@ -1241,6 +1241,8 @@ namespace Anabatic {
//AutoSegment::setShortNetMode( true );
++shortNets;
}
if (NetRoutingExtension::isManualDetailRoute(net))
continue;
if ( NetRoutingExtension::isManualGlobalRoute(net)
or NetRoutingExtension::isAutomaticGlobalRoute(net)) {
DebugSession::open( net, 145, 150 );
......
......@@ -1057,7 +1057,9 @@ namespace Anabatic {
uint32_t total = 0;
for ( Net* net : getCell()->getNets() ) {
if (net->isSupply()) continue;
if (net->isClock ()) continue;
if ( NetRoutingExtension::isManualDetailRoute(net)
or NetRoutingExtension::isFixed(net))
continue;
antennaProtect( net, failed, total );
}
cmess2 << Dots::asString ( " - Antenna gate maximum WL" , DbU::getValueString(etesian->getAntennaGateMaxWL()) ) << endl;
......
......@@ -94,13 +94,13 @@ namespace Anabatic {
}
}
if (getId() == 1518590) {
cerr << "AutoHorizontal::_postCreate(): " << this << endl;
cerr << "| Source contact:" << source << endl;
cerr << "| Source GCell: " << getGCell() << endl;
cerr << "| Target contact:" << target << endl;
cerr << "| Target GCell: " << target->getGCell() << endl;
}
// if (getId() == 1518590) {
// cerr << "AutoHorizontal::_postCreate(): " << this << endl;
// cerr << "| Source contact:" << source << endl;
// cerr << "| Source GCell: " << getGCell() << endl;
// cerr << "| Target contact:" << target << endl;
// cerr << "| Target GCell: " << target->getGCell() << endl;
// }
}
......
......@@ -52,7 +52,7 @@
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/bigvia.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/spares.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/block.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/clocktree.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/htree.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/timing.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/rsmt.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/hfns1.py
......
......@@ -16,6 +16,7 @@
from __future__ import print_function
import sys
import os.path
from copy import deepcopy
import Cfg
from Hurricane import Breakpoint, DbU, Box, Transformation, Point, \
Box, Path, Layer, Occurrence, Net, \
......@@ -35,7 +36,7 @@ from plugins import getParameter
from plugins.alpha.macro.macro import Macro
from plugins.alpha.block import timing
from plugins.alpha.block.spares import Spares
from plugins.alpha.block.clocktree import ClockTree
from plugins.alpha.block.htree import HTree
#from plugins.alpha.block.hfns1 import BufferTree
#from plugins.alpha.block.hfns2 import BufferTree
#from plugins.alpha.block.hfns3 import BufferTree
......@@ -286,6 +287,7 @@ class Block ( object ):
"""
LUT = {}
FLATTENED = 0x0001
@staticmethod
def lookup ( cell ):
......@@ -300,10 +302,11 @@ class Block ( object ):
self.flags = 0
self.conf = conf
self.spares = Spares( self )
self.clockTrees = []
self.hTrees = []
self.hfnTrees = []
self.blockInstances = []
self.placeHolderCount = 0
self.excludedNets = deepcopy( self.conf.hTreeNames )
self.sides = { IoPin.WEST : Side( self.conf, IoPin.WEST )
, IoPin.EAST : Side( self.conf, IoPin.EAST )
, IoPin.SOUTH : Side( self.conf, IoPin.SOUTH )
......@@ -329,7 +332,6 @@ class Block ( object ):
.format(self.conf.cell.getName()) )
Block.LUT[ self.conf.cell ] = self
@staticmethod
def _getInstance ( cell, pattern, level=0 ):
"""
......@@ -370,6 +372,35 @@ class Block ( object ):
"""
return Block._rgetInstance( self.conf.core, path )
@staticmethod
def _rinstancesToPath ( path, instances ):
instance = path.getTailInstance().getMasterCell().getInstance( instances[0] )
path = Path( path, instance )
if len(instances) > 1:
return Block._rinstanceToPath( path, instances[1:] )
return path
@staticmethod
def _instancesToPath ( cell, instances ):
instance = cell.getInstance( instances[0] )
return Block._rinstancesToPath( Path(instance), instances[1:] )
def getFlattenedNet ( self, path ):
"""
Find a net in the hierarchy. The path argument is a list pathname of instance
endind by a net name, like "instance1.instance2.net_name". The function returns
a an Occurrence, the instance path and the Net, or None.
"""
for net in self.conf.cellPnR.getNets():
if net.getName() == path:
return Occurrence( net, Path() )
elements = path.split('.')
if len(elements) == 1:
return None
path = Block._instancesToPath( self.conf.cellPnR, elements[:-1] )
net = path.getTailInstance().getMasterCell().getNet( elements[-1] )
return Occurrence( net, path )
def setUnexpandPins ( self, sides ):
"""
Prevent Pins from the selected sides to be stick out of one pitch.
......@@ -433,43 +464,65 @@ class Block ( object ):
else:
self.conf.setRoutingBb( self.conf.cell.getAbutmentBox() )
def addClockTrees ( self ):
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 addHTrees ( self ):
"""Create the trunk of all the clock trees (recursive H-Tree)."""
print( ' o Building clock tree(s).' )
print( ' o Building H-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()) )
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 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()
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.addClockTrees() on {} done.'.format(self.conf.cellPnR) )
Breakpoint.stop( 100, 'Block.addHTrees() on {} done.'.format(self.conf.cellPnR) )
def splitClocks ( self ):
def splitHTrees ( self ):
"""
Break the clock net and attach all it's Pins to the closest leaf
Break the H-Tree root nets and attach all it's Pins to the closest leaf
if the H-Tree.
"""
for clockTree in self.clockTrees:
clockTree.splitClock()
for hTree in self.hTrees:
hTree.splitNet()
def findHfnTrees4 ( self ):
"""Perform simple HFNS, just break nets regardless of placement."""
print( ' o Building high fanout nets trees.' )
if self.spares:
if self.conf.isCoreBlock:
self.conf.corona.flattenNets( self.conf.icore, Cell.Flags_NoClockFlatten )
else:
self.conf.cell.flattenNets( None, Cell.Flags_NoClockFlatten )
self.flattenNets()
beginCount = self.conf.bufferConf.count
maxSinks = 10
dots( 82
......@@ -578,7 +631,7 @@ class Block ( object ):
for side in self.sides.values():
side.expand()
def place ( self ):
def initEtesian ( self ):
editor = self.conf.editor
if self.conf.isCoreBlock:
self.etesian = Etesian.EtesianEngine.create( self.conf.corona )
......@@ -588,9 +641,11 @@ class Block ( object ):
Breakpoint.stop( 100, 'Block.place(), corona loaded.')
else:
self.etesian = Etesian.EtesianEngine.create( self.conf.cell )
self.etesian.getCell().flattenNets( None, self.excludedNets, Cell.Flags_NoClockFlatten )
def place ( self ):
if self.conf.placeArea:
self.etesian.setPlaceArea( self.conf.placeArea )
self.etesian.getCell().flattenNets( None, Cell.Flags_NoClockFlatten )
if self.conf.useHFNS: self.etesian.doHFNS()
self.etesian.place()
Breakpoint.stop( 100, 'Placement done.' )
......@@ -738,6 +793,7 @@ class Block ( object ):
blockInstance.block.build()
if editor: editor.setCell( self.conf.cellPnR )
self.conf.cfg.apply()
self.initEtesian()
iteration = -1
while True:
iteration += 1
......@@ -748,14 +804,14 @@ class Block ( object ):
self.checkIoPins()
self.spares.build()
#if self.conf.useHFNS: self.findHfnTrees4()
if self.conf.useClockTree: self.addClockTrees()
self.addHTrees()
#if self.conf.useHFNS: self.addHfnBuffers()
if editor: editor.fit()
#Breakpoint.stop( 0, 'Clock tree(s) done.' )
self.place()
#if self.conf.useHFNS: self.findHfnTrees()
break
if self.conf.useClockTree: self.splitClocks()
self.splitHTrees()
self.spares.removeUnusedBuffers()
self.etesian.toHurricane()
self.etesian.flattenPower()
......
......@@ -1109,6 +1109,7 @@ class BlockConf ( GaugeConf ):
self.placeArea = None
self.deltaAb = [ 0, 0, 0, 0 ]
self.useClockTree = False
self.hTreeNames = [ ]
self.useHFNS = False
self.useSpares = True
self.isBuilt = False
......@@ -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 ):
"""
......
......@@ -9,7 +9,7 @@
# | Author : Jean-Paul CHAPUT |
# | E-mail : Jean-Paul.Chaput@lip6.fr |
# | =============================================================== |
# | Python : "./plugins/block/clocktree.py" |
# | Python : "./plugins/block/htree.py" |
# +-----------------------------------------------------------------+
......@@ -17,29 +17,14 @@ from __future__ import print_function
import sys
import os.path
import Cfg
from Hurricane import Breakpoint
from Hurricane import DbU
from Hurricane import Box
from Hurricane import Transformation
from Hurricane import Box
from Hurricane import Path
from Hurricane import Layer
from Hurricane import Occurrence
from Hurricane import Net
from Hurricane import HyperNet
from Hurricane import RoutingPad
from Hurricane import Horizontal
from Hurricane import Vertical
from Hurricane import Contact
from Hurricane import Pin
from Hurricane import Plug
from Hurricane import Instance
from Hurricane import Breakpoint, DbU, Box, Transformation, Box, \
Path, Layer, Occurrence, Net, HyperNet, \
RoutingPad, Horizontal, Vertical, Contact, \
Pin, Plug, Instance
import CRL
from CRL import RoutingLayerGauge
from helpers import trace
from helpers.io import ErrorMessage
from helpers.io import WarningMessage
from helpers.io import catch
from helpers.io import ErrorMessage, WarningMessage, catch
from helpers.overlay import UpdateSession
from plugins import getParameter
from plugins.alpha import utils
......@@ -48,33 +33,47 @@ from plugins.alpha.block.spares import Spares
# ----------------------------------------------------------------------------
# Class : "clocktree.ClockTree".
# Class : "htree.HTree".
class ClockTree ( object ):
class HTree ( object ):
"""
Build a clock tree on a block.
Build a H-Tree on a net occurrene.
"""
def __init__ ( self, spares, clockNet, index ):
def __init__ ( self, spares, treeNetOcc, index ):
self.spares = spares
self.clockNet = clockNet
self.clockIndex = index
self.treeNetOcc = treeNetOcc
self.treeIndex = index
self.subNets = []
if not self.clockNet.isClock():
print( WarningMessage( 'ClockTree.__init__(): Net "{}" is not of CLOCK type.' \
.format(self.clockNet.getName()) ))
#if not self.treeNetOcc.getEntity().isClock():
# print( WarningMessage( 'HTree.__init__(): Net "{}" is not of CLOCK type.' \
# .format(self.treeNet.getEntity().getName()) ))
if treeNetOcc.getPath().isEmpty():
self.treeNet = self.treeNetOcc.getEntity()
else:
botNet = self.treeNetOcc.getEntity()
botNet.setExternal( True )
topNetName = self.treeNetOcc.getName()
topNet = Net.create( self.treeNetOcc.getPath().getOwnerCell(), topNetName )
topNet.setType ( botNet.getType() )
topNet.setDirection( botNet.getDirection() )
path = self.treeNetOcc.getPath().getHeadPath()
self.spares.raddTransNet( topNet, path )
botInstance = self.treeNetOcc.getPath().getTailInstance()
botInstance.getPlug( botNet ).setNet( botInstance.getCell().getNet( topNetName ))
self.treeNet = topNet
def destroy ( self ):
trace( 550, ',+', '\tClockTree.destroy() "{}"\n'.format(self.clockNet.getName()) )
trace( 550, ',+', '\tHTree.destroy() "{}"\n'.format(self.treeNet.getName()) )
with UpdateSession():
for subNet in self.subNets + [ self.clockNet ]:
for subNet in self.subNets + [ self.treeNet ]:
components = []
for comp in subNet.getComponents():
if isinstance(comp,RoutingPad): components.append( comp )
if isinstance(comp,Pin ): components.append( comp )
for comp in components:
comp.destroy()
if subNet != self.clockNet:
if subNet != self.treeNet:
subNet.destroy()
trace( 550, '-' )
......@@ -82,7 +81,7 @@ class ClockTree ( object ):
if qt.isLeaf(): return False
qt.rconnectBuffer()
driverNet = qt.bOutputPlug.getNet()
driverNet.setType( Net.Type.CLOCK )
driverNet.setType( self.treeNet.getType() )
for leaf in qt.leafs:
leaf.bInputPlug.setNet( driverNet )
self._rconnectHTree( leaf )
......@@ -92,7 +91,7 @@ class ClockTree ( object ):
"""
Recursively build one HTree branch for all non-terminal nodes of the QuadTree.
"""
trace( 550, ',+', '\tClockTree._rrouteHTree() {}\n'.format(qt.bOutputPlug.getNet()) )
trace( 550, ',+', '\tHTree._rrouteHTree() {}\n'.format(qt.bOutputPlug.getNet()) )
trace( 550, '\tOn: {}\n'.format(qt) )
if qt.isLeaf():
trace( 550, '-' )
......@@ -165,13 +164,13 @@ class ClockTree ( object ):
gaugeConf.setStackPosition( brContact, rightX, blY )
gaugeConf.createVertical ( rightContact, brContact, rightX, 0 )
if qt.isRoot():
ckNet = self.clockNet
ckNet = self.treeNet
if not self.spares.conf.isCoreBlock:
trace( 550, '\tRemoving any previous pin...\n' )
pins = []
for pin in ckNet.getPins(): pins.append( pin )
for pin in pins:
print( WarningMessage('ClockTree._rrouteHTree(): Removing {}.'.format(pin)) )
print( WarningMessage('HTree._rrouteHTree(): Removing {}.'.format(pin)) )
pin.destroy()
layerGauge = gaugeConf.vRoutingGauge
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
......@@ -196,41 +195,44 @@ class ClockTree ( object ):
def buildHTree ( self ):
"""
Create the clock tree netlist in two steps:
Create the tree tree netlist in two steps:
1. Connect the buffers of the spares QuadTree to form a H-Tree.
2. Detach the all the clock sink point and reconnect them to the
2. Detach the all the tree sink point and reconnect them to the
buffers of the leafs of the QuadTree.
"""
qt = self.spares.quadTree
qt.bufferTag = self.clockNet.getName()
qt.rselectBuffer( self.clockIndex, self.clockIndex, Spares.CHECK_USED|Spares.MARK_USED)
qt.bufferTag = self.treeNet.getName()
qt.rselectBuffer( self.treeIndex, self.treeIndex, Spares.CHECK_USED|Spares.MARK_USED)
with UpdateSession():
self._rconnectHTree( qt )
self._rrouteHTree ( qt )
def splitClock ( self ):
def splitNet ( self ):
"""
Disconnect the registers from the main clock and reconnect them to
the leaf buffers of the clock tree.
Disconnect the sinks from the main tree and reconnect them to
the leaf buffers of the tree tree.
"""
bufferConf = self.spares.conf.bufferConf
quadTree = self.spares.quadTree
quadTree.bufferTag = self.clockNet.getName()
quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 )
quadTree.bufferTag = self.treeNet.getName()
quadTree.rselectBuffer( self.treeIndex, self.treeIndex, 0 )
with UpdateSession():
coronaPlugs = []
hyperClock = HyperNet.create( Occurrence(self.clockNet) )
for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences():
if quadTree.isUnderArea(plugOccurrence):
quadTree.attachToLeaf( plugOccurrence )
driverPlugs = []
hyperNet = HyperNet.create( Occurrence(self.treeNet) )
for plugOcc in hyperNet.getTerminalNetlistPlugOccurrences():
trace( 550, '\tReattach "{}"\n'.format(plugOcc) )
plug = plugOcc.getEntity()
if not (plug.getMasterNet().getDirection() & Net.Direction.OUT) \
and quadTree.isUnderArea(plugOcc):
quadTree.attachToLeaf( plugOcc )
else:
coronaPlugs.append( plugOccurrence )
driverPlugs.append( plugOcc )
quadTree.rsplitNetlist()
if self.spares.conf.isCoreBlock:
plug = utils.getPlugByName( quadTree.buffer, bufferConf.input )
plug.setNet( self.clockNet )
trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.clockNet.getName()) )
trace( 550, '\tPlug of "{}" (Cell:{})\n'.format(self.clockNet.getName()
,self.clockNet.getCell()) )
for plug in self.clockNet.getPlugs():
plug.setNet( self.treeNet )
trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.treeNet.getName()) )
trace( 550, '\tPlug of "{}" (Cell:{})\n'.format(self.treeNet.getName()
,self.treeNet.getCell()) )
for plug in self.treeNet.getPlugs():
trace( 550, '\t| {}\n'.format(plug) )
......@@ -120,7 +120,7 @@ class Chip ( Block ):
if self.conf.routingGauge.hasPowerSupply():
power = plugins.alpha.chip.powerplane.Builder( self.conf )
power.connectPower()
power.connectClocks()
power.connectHTrees( self.hTrees )
power.doLayout()
Breakpoint.stop( 101, 'After Query power.' )
else:
......
......@@ -455,23 +455,23 @@ class Builder ( object ):
trace( 550, '-' )
self.activePlane = None
def _connectClock ( self, ck, trackNb ):
trace( 550, '\tpower.Builder._connectClock() {}\n'.format(ck) )
blockCk = None
def _connectHTree ( self, coronaNet, trackNb ):
trace( 550, '\tpower.Builder._connectHTree() {} on track {}\n'.format(coronaNet,trackNb) )
coreNet = None
for plug in self.conf.icore.getPlugs():
if plug.getNet() == ck:
blockCk = plug.getMasterNet()
if not blockCk:
raise ErrorMessage( 1, 'Block "{}" has no net connected to the clock "{}".' \
.format(self.conf.icore.getName(),ck.getName()) )
if plug.getNet() == coronaNet:
coreNet = plug.getMasterNet()
if not coreNet:
raise ErrorMessage( 1, 'Block "{}" has no net connected to the H-Tree "{}".' \
.format(self.conf.icore.getName(),coronaNet.getName()) )
return
htPlugs = []
for plug in ck.getPlugs():
for plug in coronaNet.getPlugs():
if plug.getInstance().isTerminalNetlist():
htPlugs.append( plug )
if len(htPlugs) != 1:
message = [ 'Clock "{}" of block "{}" is not organized as a H-Tree ({} plugs).' \
.format( ck.getName()
message = [ 'Net "{}" of block "{}" is not organized as a H-Tree ({} plugs).' \
.format( coronaNet.getName()
, self.conf.icore.getName()
, len(htPlugs)) ]
for plug in htPlugs:
......@@ -479,17 +479,17 @@ class Builder ( object ):
raise ErrorMessage( 1, message )
return
coronaPin = None
for pin in ck.getPins():
for pin in coronaNet.getPins():
coronaPin = pin
break
if not coronaPin:
message = [ 'Clock "{}" of block "{}" is not connected to a corona Pin.' \
.format( ck.getName() , self.conf.icore.getName() ) ]
message = [ 'Net "{}" of block "{}" is not connected to a corona Pin.' \
.format( coronaNet.getName() , self.conf.icore.getName() ) ]
raise ErrorMessage( 1, message )
with UpdateSession():
coronaAb = self.conf.cellPnR.getAbutmentBox()
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()), ck, 0 )
pinRp = self.conf.rpAccessByOccurrence( Occurrence(coronaPin , Path()), ck, 0 )
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()), coronaNet, 0 )
pinRp = self.conf.rpAccessByOccurrence( Occurrence(coronaPin , Path()), coronaNet, 0 )
trace( 550, '\tpinRp={}\n'.format(pinRp) )
self.conf.expandMinArea( bufferRp )
self.conf.expandMinArea( pinRp )
......@@ -508,40 +508,39 @@ class Builder ( object ):
isVertical = False
axis = coronaAb.getXMin()
if isVertical:
pitch = self.conf.vRoutingGauge.getPitch()
yaxis = axis + pitch * trackNb
pitch = self.conf.hRoutingGauge.getPitch()
yaxis = axis + 2 * pitch * trackNb
trace( 550, '\tyaxis(request)={}\n'.format(DbU.getValueString(yaxis)) )
yaxis = self.conf.getNearestHorizontalTrack( yaxis, 0 )
xaxisRp = self.conf.getNearestVerticalTrack( bufferRp.getX(), 0 )
xaxisPin = self.conf.getNearestVerticalTrack( pin.getX(), 0 )
contact1 = self.conf.createContact( ck, xaxisRp , yaxis, 0 )
contact2 = self.conf.createContact( ck, xaxisPin, yaxis, 0 )
contact1 = self.conf.createContact( coronaNet, xaxisRp , yaxis, 0 )
contact2 = self.conf.createContact( coronaNet, xaxisPin, yaxis, 0 )
self.conf.createVertical ( bufferRp, contact1, xaxisRp , 0 )
self.conf.createHorizontal( contact1, contact2, yaxis , 0 )
self.conf.createVertical ( contact2, pinRp , xaxisPin, 0 )
trace( 550, '\tyaxis(track)={}\n'.format(DbU.getValueString(yaxis)) )
trace( 550, '\tcontact1={}\n'.format(contact1) )