Support for dedicated power plane in Cumulus (vertical stripes).
* New: In cumulus/plugins.chip.powerplane, build the overall power grid when there is a dedicated supply layer. Makes vertical supply stripes and connect them the *horizontal* power rails inside the blocks (could be in *any* layer). Stripes positions are determined by the pins createds by the pads module. * New: In cumulus/plugins.chip.chip, use the powerplane builder if the RoutingGauge provides a PowerSupply kind. * New: In cumulus/plugins.block.configuration, add support for PowerSupply gauges. * New: In cumulus/plugins.block.pads, if the gauge provides a PowerSupply, create north/south border pins for power & ground to direct the corona to make vertical power strips. This assume that we are using LibreSOC like I/O pads that can be connected straight from everywhere in the corona. First and last 2 stripes are "cap end" and narrower. Positions and width of the sripes are set through the configuration parameters: * "chip.supplyRailWidth" * "chip.supplyRailPitch" * Change: In cumulus/plugins.block.spares, now take into account the "placeArea" parameter. * Change: In cumulus/plugins.block.bigvia, now have a per metal layer area that *may* be expanded if it is too narrow to put at least one cut. Add flags to allow controlled expansion of the metal plates. As a security, now raise an exception if no cut can be created.
This commit is contained in:
parent
3a68cdf549
commit
f4204c52d7
|
@ -69,6 +69,7 @@
|
|||
set ( pyPluginAlphaChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/__init__.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/configuration.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/power.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/powerplane.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/corona.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/pads.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/chip.py
|
||||
|
|
|
@ -38,18 +38,29 @@ class BigVia ( object ):
|
|||
"""
|
||||
Draw a large are VIA and manage the matrix of cuts.
|
||||
"""
|
||||
AllowTopMetalExpand = 0x0001
|
||||
AllowBotMetalExpand = 0x0002
|
||||
AllowHorizontalExpand = 0x0004
|
||||
AllowVerticalExpand = 0x0008
|
||||
AllowAllExpand = AllowTopMetalExpand \
|
||||
| AllowBotMetalExpand \
|
||||
| AllowHorizontalExpand \
|
||||
| AllowVerticalExpand
|
||||
|
||||
def __init__ ( self, net, depth, x, y, width, height ):
|
||||
def __init__ ( self, net, depth, x, y, width, height, flags=0 ):
|
||||
self.flags = flags
|
||||
self.hasLayout = False
|
||||
self.net = net
|
||||
self.bottomDepth = depth
|
||||
self.topDepth = depth
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.widths = {}
|
||||
self.heights = {}
|
||||
self.plates = {}
|
||||
self.vias = {}
|
||||
self.widths [depth] = width
|
||||
self.heights[depth] = height
|
||||
|
||||
def __str__ ( self ):
|
||||
global rg
|
||||
|
@ -60,8 +71,22 @@ class BigVia ( object ):
|
|||
, rg.getRoutingLayer(self.topDepth).getName()
|
||||
, DbU.getValueString(self.x)
|
||||
, DbU.getValueString(self.y)
|
||||
, DbU.getValueString(self.width)
|
||||
, DbU.getValueString(self.height) )
|
||||
, DbU.getValueString(self.widths [self.topDepth])
|
||||
, DbU.getValueString(self.heights[self.topDepth]) )
|
||||
|
||||
@property
|
||||
def height ( self ):
|
||||
maxHeight = 0
|
||||
for depth in range(self.bottomDepth,self.topDepth+1):
|
||||
maxHeight = max( maxHeight, self.heights[depth] )
|
||||
return maxHeight
|
||||
|
||||
@property
|
||||
def width ( self ):
|
||||
maxWidth = 0
|
||||
for depth in range(self.bottomDepth,self.topDepth+1):
|
||||
maxWidth = max( maxWidth, self.widths[depth] )
|
||||
return maxWidth
|
||||
|
||||
def getNet ( self ): return self.net
|
||||
|
||||
|
@ -75,25 +100,53 @@ class BigVia ( object ):
|
|||
if self.hasLayout:
|
||||
print( WarningMessage( 'BigVia.mergeDepth(): Cannot be called *after* BigVia.doLayout()' ))
|
||||
return
|
||||
if depth < self.bottomDepth: self.bottomDepth = depth
|
||||
if depth > self.topDepth: self.topDepth = depth
|
||||
if depth < self.bottomDepth:
|
||||
bdepth = depth
|
||||
while depth < self.bottomDepth:
|
||||
self.widths [depth] = self.widths [self.topDepth]
|
||||
self.heights[depth] = self.heights[self.topDepth]
|
||||
depth += 1
|
||||
self.bottomDepth = bdepth
|
||||
if depth > self.topDepth:
|
||||
tdepth = depth
|
||||
while depth > self.topDepth:
|
||||
self.widths [depth] = self.widths [self.topDepth]
|
||||
self.heights[depth] = self.heights[self.topDepth]
|
||||
depth -= 1
|
||||
self.topDepth = tdepth
|
||||
|
||||
def doLayout ( self ):
|
||||
global rg
|
||||
if rg is None: rg = CRL.AllianceFramework.get().getRoutingGauge()
|
||||
for depth in range(self.bottomDepth,self.topDepth+1):
|
||||
minSize = rg.getRoutingLayer( depth ).getMinimalSize()
|
||||
if self.widths[depth] < minSize and (self.flags & BigVia.AllowHorizontalExpand):
|
||||
self.widths[depth] = minSize
|
||||
if self.heights[depth] < minSize and (self.flags & BigVia.AllowVerticalExpand):
|
||||
self.heights[depth] = minSize
|
||||
for depth in range(self.bottomDepth,self.topDepth+1):
|
||||
minArea = rg.getRoutingLayer( depth ).getMinimalArea()
|
||||
minLength = DbU.fromPhysical( minArea / DbU.toPhysical( self.width, DbU.UnitPowerMicro )
|
||||
, DbU.UnitPowerMicro )
|
||||
#minLength = toFoundryGrid( minLength, DbU.SnapModeSuperior )
|
||||
plateArea = DbU.toPhysical( self.width , DbU.UnitPowerMicro ) \
|
||||
* DbU.toPhysical( self.height, DbU.UnitPowerMicro )
|
||||
plateArea = DbU.toPhysical( self.widths [depth], DbU.UnitPowerMicro ) \
|
||||
* DbU.toPhysical( self.heights[depth], DbU.UnitPowerMicro )
|
||||
if plateArea < minArea:
|
||||
print( WarningMessage( 'BigVia::doLayout(): Area too small for {}'.format(self.net) ))
|
||||
if depth == self.bottomDepth and not (self.flags & BigVia.AllowBotMetalExpand):
|
||||
print( WarningMessage( 'BigVia::doLayout(): @({},{}) Area too small for {} in layer "{}"' \
|
||||
.format( DbU.getValueString(self.x)
|
||||
, DbU.getValueString(self.y)
|
||||
, rg.getRoutingLayer(depth).getName()
|
||||
, self.net
|
||||
) ))
|
||||
if depth == self.topDepth and not (self.flags & BigVia.AllowTopMetalExpand):
|
||||
print( WarningMessage( 'BigVia::doLayout(): @({},{}) Area too small for {} in layer "{}"' \
|
||||
.format( DbU.getValueString(self.x)
|
||||
, DbU.getValueString(self.y)
|
||||
, rg.getRoutingLayer(depth).getName()
|
||||
, self.net
|
||||
) ))
|
||||
self.plates[ depth ] = Contact.create( self.net
|
||||
, rg.getRoutingLayer(depth)
|
||||
, self.x , self.y
|
||||
, self.width, self.height
|
||||
, self.widths[depth], self.heights[depth]
|
||||
)
|
||||
if rg.isSymbolic():
|
||||
for depth in range(self.bottomDepth,self.topDepth):
|
||||
|
@ -101,8 +154,8 @@ class BigVia ( object ):
|
|||
, rg.getContactLayer( depth )
|
||||
, self.x
|
||||
, self.y
|
||||
, self.width - DbU.fromLambda( 1.0 )
|
||||
, self.height - DbU.fromLambda( 1.0 ) )
|
||||
, self.widths [depth] - DbU.fromLambda( 1.0 )
|
||||
, self.heights[depth] - DbU.fromLambda( 1.0 ) )
|
||||
else:
|
||||
for depth in range(self.bottomDepth,self.topDepth):
|
||||
self._doCutMatrix( depth )
|
||||
|
@ -129,13 +182,28 @@ class BigVia ( object ):
|
|||
trace( 550, '\t| botEnclosure[{}]: {}\n'.format(depth,DbU.getValueString(botEnclosure)) )
|
||||
trace( 550, '\t| enclosure [{}]: {}\n'.format(depth,DbU.getValueString(enclosure)) )
|
||||
cutArea = self.plates[ depth ].getBoundingBox()
|
||||
cutArea.inflate( - enclosure - cutSide/2 )
|
||||
hEnclosure = enclosure + cutSide/2
|
||||
vEnclosure = hEnclosure
|
||||
if hEnclosure*2 > cutArea.getWidth():
|
||||
if self.flags & BigVia.AllowHorizontalExpand:
|
||||
hEnclosure = cutArea.getWidth()/2
|
||||
else:
|
||||
raise ErrorMessage( 1, [ 'BigVia._doCutMatrix(): Cannot create cut of {} in {}.' \
|
||||
.format( cutLayer.getName(), self )
|
||||
, 'Width is too small to fit a single VIA cut.'
|
||||
] )
|
||||
if vEnclosure*2 > cutArea.getHeight():
|
||||
if self.flags & BigVia.AllowVerticalExpand:
|
||||
vEnclosure = cutArea.getHeight()/2
|
||||
else:
|
||||
raise ErrorMessage( 1, [ 'BigVia._doCutMatrix(): Cannot create cut of {} in {}.' \
|
||||
.format( cutLayer.getName(), self )
|
||||
, 'Height is too small to fit a single VIA cut.'
|
||||
] )
|
||||
cutArea.inflate( -hEnclosure, -vEnclosure )
|
||||
xoffset = (cutArea.getWidth () % (cutSide+cutSpacing)) / 2
|
||||
yoffset = (cutArea.getHeight() % (cutSide+cutSpacing)) / 2
|
||||
cutArea.translate( xoffset, yoffset )
|
||||
#if cutArea.isEmpty():
|
||||
# raise ErrorMessage( 1, 'BigVia._doCutMatrix(): Cannot create at least a single cut in {}.' \
|
||||
# .format(self))
|
||||
self.vias[ depth ] = []
|
||||
y = cutArea.getYMin()
|
||||
while y <= cutArea.getYMax():
|
||||
|
|
|
@ -547,6 +547,7 @@ class Block ( object ):
|
|||
if self.conf.placeArea:
|
||||
self.etesian.setPlaceArea( self.conf.placeArea )
|
||||
self.etesian.place()
|
||||
self.etesian.flattenPower()
|
||||
Breakpoint.stop( 100, 'Placement done.' )
|
||||
self.etesian.clearColoquinte()
|
||||
|
||||
|
@ -559,7 +560,7 @@ class Block ( object ):
|
|||
Breakpoint.stop( 100, 'Block.route() Before global routing.' )
|
||||
self.katana.runGlobalRouter ( Katana.Flags.NoFlags )
|
||||
self.katana.loadGlobalRouting( Anabatic.EngineLoadGrByNet )
|
||||
Breakpoint.stop( 99, 'Block.route() After global routing.' )
|
||||
Breakpoint.stop( 100, 'Block.route() After global routing.' )
|
||||
self.katana.layerAssign ( Anabatic.EngineNoNetLayerAssign )
|
||||
self.katana.runNegociate ( Katana.Flags.NoFlags )
|
||||
success = self.katana.isDetailedRoutingSuccess()
|
||||
|
|
|
@ -18,30 +18,15 @@ import re
|
|||
import os.path
|
||||
from operator import itemgetter
|
||||
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 NetExternalComponents
|
||||
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 DataBase, Breakpoint, DbU, Box, Transformation, \
|
||||
Path, Layer, Occurrence, Net, \
|
||||
NetExternalComponents, RoutingPad, Horizontal, \
|
||||
Vertical, Contact, Pin, Plug, Instance
|
||||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
from helpers import trace, l, u, n
|
||||
from helpers.utils import classdecorator
|
||||
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 CfgCache
|
||||
from plugins import getParameter
|
||||
from plugins.rsave import rsave
|
||||
|
@ -133,7 +118,13 @@ class GaugeConf ( object ):
|
|||
@property
|
||||
def routingBb ( self ): return self._routingBb
|
||||
|
||||
def getLayerDepth ( self, layer ): return self._routingGauge.getLayerDepth( layer )
|
||||
def getRoutingLayer ( self, depth ):
|
||||
return self._routingGauge.getRoutingLayer( depth )
|
||||
|
||||
def getLayerDepth ( self, layer ):
|
||||
if isinstance(layer,str):
|
||||
layer = DataBase.getDB().getTechnology().getLayer( layer )
|
||||
return self._routingGauge.getLayerDepth( layer )
|
||||
|
||||
def getPitch ( self, layer ): return self._routingGauge.getPitch( layer )
|
||||
|
||||
|
@ -173,6 +164,8 @@ class GaugeConf ( object ):
|
|||
|
||||
if self._routingGauge.getLayerGauge(depth).getType() == RoutingLayerGauge.PinOnly:
|
||||
continue
|
||||
if self._routingGauge.getLayerGauge(depth).getType() == RoutingLayerGauge.PowerSupply:
|
||||
continue
|
||||
if self._routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
|
||||
if self.horizontalDeepDepth < 0:
|
||||
self.horizontalDeepDepth = depth
|
||||
|
|
|
@ -129,7 +129,7 @@ class BufferPool ( object ):
|
|||
|
||||
def _createBuffers ( self ):
|
||||
"""Create the matrix of instances buffer."""
|
||||
trace( 540, ',+', '\tBufferPool.createBuffers()\n' )
|
||||
trace( 540, ',+', '\tBufferPool.createBuffers() of {}\n'.format(self.quadTree) )
|
||||
yoffset = 0
|
||||
if self.quadTree.spares.conf.isCoreBlock:
|
||||
yoffset = self.quadTree.spares.conf.icore.getTransformation().getTy()
|
||||
|
@ -239,9 +239,19 @@ class QuadTree ( object ):
|
|||
|
||||
@staticmethod
|
||||
def create ( spares ):
|
||||
#area = spares.conf.cell.getAbutmentBox()
|
||||
#if spares.conf.isCoreBlock:
|
||||
# area = spares.conf.core.getAbutmentBox()
|
||||
# spares.conf.icore.getTransformation().applyOn( area )
|
||||
area = spares.conf.placeArea
|
||||
if area is None:
|
||||
area = spares.conf.cell.getAbutmentBox()
|
||||
if spares.conf.isCoreBlock:
|
||||
area = spares.conf.placeArea
|
||||
if area is None:
|
||||
area = spares.conf.core.getAbutmentBox()
|
||||
else:
|
||||
area = Box( area )
|
||||
spares.conf.icore.getTransformation().applyOn( area )
|
||||
root = QuadTree( spares, None, area )
|
||||
root.rpartition()
|
||||
|
@ -277,7 +287,13 @@ class QuadTree ( object ):
|
|||
self.pool._destroyBuffers()
|
||||
|
||||
def __str__ ( self ):
|
||||
if hasattr(self,'pool'):
|
||||
occupancy, capacity = self.pool.getUse()
|
||||
rtag = self.rtag
|
||||
else:
|
||||
occupancy = 'occ'
|
||||
capacity = 'cap'
|
||||
rtag = 'rtag'
|
||||
s = '<QuadTree [{},{} {},{}] {}/{} "{}">' \
|
||||
.format( DbU.getValueString(self.area.getXMin())
|
||||
, DbU.getValueString(self.area.getYMin())
|
||||
|
@ -285,7 +301,7 @@ class QuadTree ( object ):
|
|||
, DbU.getValueString(self.area.getYMax())
|
||||
, occupancy
|
||||
, capacity
|
||||
, self.rtag )
|
||||
, rtag )
|
||||
return s
|
||||
|
||||
def __eq__ ( self, other ):
|
||||
|
@ -821,10 +837,11 @@ class Spares ( object ):
|
|||
if self.conf.cfg.etesian.latchUpDistance is None:
|
||||
return
|
||||
trace( 540, ',+', '\tSpares._addCapTies()\n' )
|
||||
area = self.conf.cell.getAbutmentBox()
|
||||
if self.conf.isCoreBlock:
|
||||
area = self.conf.core.getAbutmentBox()
|
||||
self.conf.icore.getTransformation().applyOn( area )
|
||||
area = self.quadTree.area
|
||||
#area = self.conf.cell.getAbutmentBox()
|
||||
#if self.conf.isCoreBlock:
|
||||
# area = self.conf.core.getAbutmentBox()
|
||||
# self.conf.icore.getTransformation().applyOn( area )
|
||||
y = area.getYMin()
|
||||
sliceHeight = self.conf.sliceHeight
|
||||
tieWidth = self.conf.feedsConf.tieWidth()
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function, absolute_import
|
||||
import sys
|
||||
import traceback
|
||||
import os.path
|
||||
|
@ -24,30 +23,16 @@ import cProfile
|
|||
import pstats
|
||||
import Cfg
|
||||
import Hurricane
|
||||
from Hurricane import DataBase
|
||||
from Hurricane import DbU
|
||||
from Hurricane import Point
|
||||
from Hurricane import Transformation
|
||||
from Hurricane import Box
|
||||
from Hurricane import Path
|
||||
from Hurricane import Occurrence
|
||||
from Hurricane import UpdateSession
|
||||
from Hurricane import Breakpoint
|
||||
from Hurricane import Net
|
||||
from Hurricane import RoutingPad
|
||||
from Hurricane import Contact
|
||||
from Hurricane import Horizontal
|
||||
from Hurricane import Vertical
|
||||
from Hurricane import Instance
|
||||
from Hurricane import HyperNet
|
||||
from Hurricane import Query
|
||||
from Hurricane import DataBase, DbU ,Point, Transformation, Box, \
|
||||
Path, Occurrence, UpdateSession, Breakpoint, \
|
||||
Net, RoutingPad, Contact, Horizontal, Vertical, \
|
||||
Instance, HyperNet, Query
|
||||
import Viewer
|
||||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
import helpers
|
||||
from helpers import trace
|
||||
from helpers.io import ErrorMessage
|
||||
from helpers.io import WarningMessage
|
||||
from helpers.io import ErrorMessage, WarningMessage
|
||||
from helpers.overlay import UpdateSession
|
||||
import Etesian
|
||||
import Anabatic
|
||||
|
@ -58,6 +43,7 @@ import plugins.rsave
|
|||
from plugins.alpha.block.block import Block
|
||||
import plugins.alpha.chip.pads
|
||||
import plugins.alpha.chip.power
|
||||
import plugins.alpha.chip.powerplane
|
||||
import plugins.alpha.chip.corona
|
||||
|
||||
|
||||
|
@ -114,6 +100,13 @@ class Chip ( Block ):
|
|||
self.conf.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
|
||||
def doConnectCore ( self ):
|
||||
if self.conf.routingGauge.hasPowerSupply():
|
||||
power = plugins.alpha.chip.powerplane.Builder( self.conf )
|
||||
power.connectPower()
|
||||
power.connectClocks()
|
||||
power.doLayout()
|
||||
Breakpoint.stop( 101, 'After Query power.' )
|
||||
else:
|
||||
power = plugins.alpha.chip.power.Builder( self.conf )
|
||||
power.connectPower()
|
||||
power.connectClocks()
|
||||
|
@ -140,6 +133,7 @@ class Chip ( Block ):
|
|||
self.padsCorona.doLayout()
|
||||
self.validate()
|
||||
self.doCoronaFloorplan()
|
||||
self.padsCorona.doPowerLayout()
|
||||
self.conf.refresh()
|
||||
super(Chip,self).doPnR()
|
||||
self.conf.refresh( self.conf.chip )
|
||||
|
|
|
@ -94,6 +94,8 @@ class ChipConf ( BlockConf ):
|
|||
# trace( 550, '\tONE LAMBDA = %s\n' % DbU.getValueString(DbU.fromLambda(1.0)) )
|
||||
self.validated = True
|
||||
# Block Corona parameters (triggers loading from disk).
|
||||
self.cfg.chip.supplyRailWidth = None
|
||||
self.cfg.chip.supplyRailPitch = None
|
||||
self.cfg.chip.block.rails.count = None
|
||||
self.cfg.chip.block.rails.hWidth = None
|
||||
self.cfg.chip.block.rails.vWidth = None
|
||||
|
|
|
@ -21,14 +21,15 @@ from Hurricane import DbU, Point, Transformation, Interval, Box, \
|
|||
Path, Occurrence, UpdateSession, Layer, \
|
||||
BasicLayer, Net, Pin, Contact, Segment, \
|
||||
Horizontal, Vertical, Diagonal, RoutingPad, \
|
||||
Instance
|
||||
Instance, DataBase
|
||||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
from CRL import RoutingGauge, RoutingLayerGauge
|
||||
import helpers
|
||||
from helpers import trace, l, u, n, onFGrid
|
||||
from helpers.io import ErrorMessage, WarningMessage
|
||||
from helpers.overlay import UpdateSession
|
||||
import plugins.alpha.chip
|
||||
from plugins.alpha.block.bigvia import BigVia
|
||||
|
||||
plugins.alpha.chip.importConstants( globals() )
|
||||
|
||||
|
@ -810,6 +811,7 @@ class Corona ( object ):
|
|||
self.padSpacers = []
|
||||
self.padCorner = []
|
||||
self.padRails = [] # [ , [net, layer, axis, width] ]
|
||||
self.powerCount = 0
|
||||
self.conf.cfg.chip.padCoreSide = None
|
||||
if self.conf.cfg.chip.padCoreSide.lower() == 'south':
|
||||
self.padOrient = Transformation.Orientation.MY
|
||||
|
@ -827,6 +829,12 @@ class Corona ( object ):
|
|||
if self.conf.cfg.chip.padCorner is not None:
|
||||
self.padCorner = self.padLib.getCell( self.conf.cfg.chip.padCorner )
|
||||
|
||||
@property
|
||||
def supplyRailWidth ( self ): return self.conf.cfg.chip.supplyRailWidth
|
||||
|
||||
@property
|
||||
def supplyRailPitch ( self ): return self.conf.cfg.chip.supplyRailPitch
|
||||
|
||||
def toGrid ( self, u ): return u - (u % self.conf.ioPadPitch)
|
||||
|
||||
def validate ( self ):
|
||||
|
@ -946,6 +954,10 @@ class Corona ( object ):
|
|||
bb = component.getBoundingBox()
|
||||
padInstance.getTransformation().applyOn( bb )
|
||||
trace( 550, '\t| External:{} bb:{}\n'.format(component,bb) )
|
||||
if self.conf.routingGauge.hasPowerSupply():
|
||||
if chipIntNet.isPower() or chipIntNet.isGround():
|
||||
trace( 550, '\t| Skipped, pads uses distributed power terminals.\n' )
|
||||
continue
|
||||
if self.conf.chipConf.ioPadGauge == 'LibreSOCIO':
|
||||
if chipIntNet.isPower() or chipIntNet.isGround():
|
||||
if side.type == North or side.type == South:
|
||||
|
@ -1041,6 +1053,7 @@ class Corona ( object ):
|
|||
if not padNet: continue
|
||||
padConnected = self._createCoreWire( chipIntNet, padNet, doneInstances[-1], padConnected )
|
||||
if padConnected == 0:
|
||||
if not (chipIntNet.isSupply() and self.conf.routingGauge.hasPowerSupply()):
|
||||
trace( 550, '-' )
|
||||
raise ErrorMessage( 1, 'PadsCorona._placeInnerCorona(): Chip net "{}" is not connected to a pad.' \
|
||||
.format(chipIntNet.getName()) )
|
||||
|
@ -1088,6 +1101,88 @@ class Corona ( object ):
|
|||
, self.eastSide .coreWires[-1].chipNet.getName()) ] ))
|
||||
trace( 550, '-' )
|
||||
|
||||
def _supplyToPad ( self, chipNet, coronaNet, coronaAxis, stripeWidth, side ):
|
||||
trace( 550, ',+', '\tCorona.Builder._supplyToPads()\n' )
|
||||
supplyLayerDepth = self.conf.routingGauge.getPowerSupplyGauge().getDepth()
|
||||
supplyLayer = self.conf.routingGauge.getPowerSupplyGauge().getLayer()
|
||||
chipLayer = self.conf.getRoutingLayer( self.conf.routingGauge.getPowerSupplyGauge().getDepth() - 1 )
|
||||
coronaAb = self.conf.icorona.getAbutmentBox()
|
||||
chipAxis = coronaAxis + self.conf.icorona.getTransformation().getTx()
|
||||
trace( 550, '\tchipLayer={}\n'.format(chipLayer) )
|
||||
for rail in self.padRails:
|
||||
net = rail[0]
|
||||
layer = rail[1]
|
||||
railAxis = rail[2]
|
||||
width = rail[3]
|
||||
if net != chipNet or chipLayer.getMask() != layer.getMask():
|
||||
continue
|
||||
if side == North:
|
||||
trace( 550, '\tcoronaAb={}\n'.format(coronaAb) )
|
||||
trace( 550, '\tcoronaAxis={}\n'.format(DbU.getValueString(coronaAxis)) )
|
||||
trace( 550, '\tchipAxis={}\n'.format(DbU.getValueString(chipAxis)) )
|
||||
trace( 550, '\trailNet={} <-> {}\n'.format(net,chipNet) )
|
||||
trace( 550, '\trailAxis={}\n'.format(DbU.getValueString(railAxis)) )
|
||||
Vertical.create( chipNet
|
||||
, supplyLayer
|
||||
, chipAxis
|
||||
, stripeWidth
|
||||
, coronaAb.getYMax()
|
||||
, self.conf.chipAb.getYMax() - railAxis
|
||||
)
|
||||
via = BigVia( chipNet
|
||||
, supplyLayerDepth
|
||||
, chipAxis
|
||||
, self.conf.chipAb.getYMax() - railAxis
|
||||
, stripeWidth
|
||||
, width
|
||||
, BigVia.AllowAllExpand
|
||||
)
|
||||
trace( 550, '\tpower depth: {}\n'.format( self.conf.routingGauge.getPowerSupplyGauge().getDepth() ))
|
||||
via.mergeDepth( self.conf.routingGauge.getPowerSupplyGauge().getDepth()-1 )
|
||||
via.doLayout()
|
||||
pin = Pin.create( coronaNet
|
||||
, '{}.{}'.format(coronaNet.getName(),self.powerCount)
|
||||
, Pin.Direction.NORTH
|
||||
, Pin.PlacementStatus.FIXED
|
||||
, supplyLayer
|
||||
, coronaAxis
|
||||
, self.conf.icorona.getMasterCell().getAbutmentBox().getYMax()
|
||||
, stripeWidth
|
||||
, DbU.fromLambda( 1.0 )
|
||||
)
|
||||
trace( 550, '\tpin={}\n'.format(pin) )
|
||||
self.powerCount += 1
|
||||
elif side == South:
|
||||
Vertical.create( chipNet
|
||||
, supplyLayer
|
||||
, chipAxis
|
||||
, stripeWidth
|
||||
, self.conf.chipAb.getYMin() + railAxis
|
||||
, coronaAb.getYMin()
|
||||
)
|
||||
via = BigVia( chipNet
|
||||
, supplyLayerDepth
|
||||
, chipAxis
|
||||
, self.conf.chipAb.getYMin() + railAxis
|
||||
, stripeWidth
|
||||
, width
|
||||
, BigVia.AllowAllExpand
|
||||
)
|
||||
via.mergeDepth( supplyLayerDepth-1 )
|
||||
via.doLayout()
|
||||
pin = Pin.create( coronaNet
|
||||
, '{}.{}'.format(coronaNet.getName(),self.powerCount)
|
||||
, Pin.Direction.SOUTH
|
||||
, Pin.PlacementStatus.FIXED
|
||||
, supplyLayer
|
||||
, coronaAxis
|
||||
, self.conf.icorona.getMasterCell().getAbutmentBox().getYMin()
|
||||
, stripeWidth
|
||||
, DbU.fromLambda( 1.0 )
|
||||
)
|
||||
self.powerCount += 1
|
||||
trace( 550, '-' )
|
||||
|
||||
def doLayout ( self ):
|
||||
if not self.conf.validated: return
|
||||
with UpdateSession():
|
||||
|
@ -1099,3 +1194,85 @@ class Corona ( object ):
|
|||
self.westSide.doLayout()
|
||||
self._placeInnerCorona()
|
||||
self.conf.chip.setRouted( True )
|
||||
|
||||
def doPowerLayout ( self ):
|
||||
if not self.conf.routingGauge.hasPowerSupply(): return
|
||||
with UpdateSession():
|
||||
capViaWidth = self.conf.vDeepRG.getPitch()*3
|
||||
coreAb = self.conf.coreAb
|
||||
stripesNb = int( (coreAb.getWidth() - 8*capViaWidth + self.supplyRailWidth) \
|
||||
/ self.supplyRailPitch - 1 )
|
||||
offset = (coreAb.getWidth() - self.supplyRailPitch*(stripesNb-1)) / 2
|
||||
powerNet = None
|
||||
groundNet = None
|
||||
chipPowerNet = None
|
||||
chipGroundNet = None
|
||||
corona = self.conf.corona
|
||||
for net in corona.getNets():
|
||||
if net.isPower (): powerNet = net
|
||||
if net.isGround(): groundNet = net
|
||||
if powerNet:
|
||||
if powerNet.isGlobal():
|
||||
chipPowerNet = self.conf.chip.getNet( powerNet.getName() )
|
||||
else:
|
||||
for net in self.conf.chip.getNets():
|
||||
if net.getName() == powerNet.getName():
|
||||
chipPowerNet = net
|
||||
break
|
||||
if not chipPowerNet:
|
||||
raise ErrorMessage( 1, 'pads.Corona.doPowerLayout(): No core power net not connected in "{}"' \
|
||||
.format(self.conf.chip.getName()) )
|
||||
else:
|
||||
raise ErrorMessage( 1, 'pads.Corona.doPowerLayout(): No power net found in "{}"' \
|
||||
.format(corona.getName()) )
|
||||
if groundNet:
|
||||
if groundNet.isGlobal():
|
||||
chipGroundNet = self.conf.chip.getNet( groundNet.getName() )
|
||||
else:
|
||||
for net in self.conf.chip.getNets():
|
||||
if net.getName() == groundNet.getName():
|
||||
chipGroundNet = net
|
||||
break
|
||||
if not chipGroundNet:
|
||||
raise ErrorMessage( 1, 'pads.Corona.doPowerLayout(): No core power net not connected in "{}"' \
|
||||
.format(self.conf.chip.getName()) )
|
||||
else:
|
||||
raise ErrorMessage( 1, 'pads.Corona.doPowerLayout(): No ground net found in "{}"' \
|
||||
.format(corona.getName()) )
|
||||
icore = self.conf.icore
|
||||
xcore = icore.getTransformation().getTx()
|
||||
trace( 550, '\ticoreAb={}\n'.format(icore.getAbutmentBox()) )
|
||||
print( 'capViaWidth={}'.format(DbU.getValueString(capViaWidth)))
|
||||
stripeSpecs = []
|
||||
for i in range(stripesNb+4):
|
||||
if i % 2:
|
||||
coronaNet = groundNet
|
||||
chipNet = chipGroundNet
|
||||
else:
|
||||
coronaNet = powerNet
|
||||
chipNet = chipPowerNet
|
||||
if i < 2:
|
||||
axis = xcore + 2*i*capViaWidth + capViaWidth/2
|
||||
width = capViaWidth
|
||||
elif i >= stripesNb+2:
|
||||
axis = xcore + coreAb.getWidth() - 2*(i-stripesNb-1)*capViaWidth + capViaWidth/2
|
||||
width = capViaWidth
|
||||
else:
|
||||
axis = xcore + offset + (i-2)*self.supplyRailPitch
|
||||
width = self.supplyRailWidth
|
||||
stripeSpecs.append( [ chipNet, coronaNet, axis, width ] )
|
||||
for chipNet, coronaNet, axis, width in stripeSpecs:
|
||||
self._supplyToPad( chipNet, coronaNet, axis, width, North )
|
||||
self._supplyToPad( chipNet, coronaNet, axis, width, South )
|
||||
#for istripe in range(stripesNb):
|
||||
# trace( 550, '\tistripe={}\n'.format(istripe) )
|
||||
# axis = xcore + offset + istripe*self.supplyRailPitch
|
||||
# if istripe % 2:
|
||||
# coronaNet = groundNet
|
||||
# chipNet = chipGroundNet
|
||||
# else:
|
||||
# coronaNet = powerNet
|
||||
# chipNet = chipPowerNet
|
||||
# self._supplyToPad( chipNet, coronaNet, axis, North )
|
||||
# self._supplyToPad( chipNet, coronaNet, axis, South )
|
||||
|
||||
|
|
|
@ -0,0 +1,544 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) UPMC 2021-2021, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | C u m u l u s - P y t h o n T o o l s |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./plugins/chip/powerplane.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
from Hurricane import DbU, Point, Transformation, Box, Interval, \
|
||||
Path, Occurrence, UpdateSession, Net, \
|
||||
Contact, Horizontal, Vertical, Cell, Query, \
|
||||
DataBase, Pin, NetExternalComponents
|
||||
import CRL
|
||||
import helpers
|
||||
from helpers import trace
|
||||
from helpers.io import ErrorMessage, WarningMessage
|
||||
from helpers.overlay import UpdateSession
|
||||
import plugins
|
||||
import plugins.chip
|
||||
from plugins.alpha.block.bigvia import BigVia
|
||||
|
||||
__all__ = [ 'Builder' ]
|
||||
|
||||
plugins.chip.importConstants( globals() )
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "corona.IntervalSet"
|
||||
|
||||
class IntervalSet ( object ):
|
||||
|
||||
def __init__ ( self ):
|
||||
self.chunks = []
|
||||
return
|
||||
|
||||
def merge ( self, min, max ):
|
||||
toMerge = Interval( min, max )
|
||||
imerge = len(self.chunks)
|
||||
length = len(self.chunks)
|
||||
i = 0
|
||||
while i < length:
|
||||
if imerge >= length:
|
||||
if toMerge.getVMax() < self.chunks[i].getVMin():
|
||||
self.chunks.insert( i, toMerge )
|
||||
length += 1
|
||||
imerge = 0
|
||||
break
|
||||
if toMerge.intersect(self.chunks[i]):
|
||||
imerge = i
|
||||
self.chunks[imerge].merge( toMerge )
|
||||
else:
|
||||
if toMerge.getVMax() >= self.chunks[i].getVMin():
|
||||
self.chunks[imerge].merge( self.chunks[i] )
|
||||
del self.chunks[ i ]
|
||||
length -= 1
|
||||
continue
|
||||
else:
|
||||
break
|
||||
i += 1
|
||||
if imerge >= length:
|
||||
self.chunks.insert( length, toMerge )
|
||||
|
||||
def toStr ( self ):
|
||||
s = ''
|
||||
for interval in self.chunks:
|
||||
if len(s): s += ' '
|
||||
s += '[{}:{}]'.format( DbU.getValueString(interval.getVMin())
|
||||
, DbU.getValueString(interval.getVMax()) )
|
||||
return s
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.Rail"
|
||||
|
||||
class Rail ( object ):
|
||||
|
||||
@staticmethod
|
||||
def create ( bb ):
|
||||
rail = None
|
||||
if bb.getWidth() >= bb.getHeight():
|
||||
rail = HorizontalRail( bb )
|
||||
rail.merge( bb )
|
||||
else:
|
||||
rail = VerticalRail( bb )
|
||||
rail.merge( bb )
|
||||
return rail
|
||||
|
||||
def __init__ ( self, axis, width ):
|
||||
self.axis = axis
|
||||
self.width = width
|
||||
self.intervals = IntervalSet()
|
||||
|
||||
def __str__ ( self ):
|
||||
s = '<{} @{} w={} {}>'.format( self.typeName
|
||||
, DbU.getValueString(self.axis)
|
||||
, DbU.getValueString(self.width)
|
||||
, self.intervals.toStr() )
|
||||
return s
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.HorizontalRail"
|
||||
|
||||
class HorizontalRail ( Rail ):
|
||||
|
||||
def __init__ ( self, bb ):
|
||||
super(HorizontalRail,self).__init__( bb.getYCenter(), bb.getHeight() )
|
||||
self.isHorizontal = True
|
||||
|
||||
@property
|
||||
def typeName ( self ): return 'HorizontalRail'
|
||||
|
||||
def merge ( self, bb ):
|
||||
self.intervals.merge( bb.getXMin(), bb.getXMax() )
|
||||
|
||||
def doLayout ( self, plane, stripes ):
|
||||
trace( 550, ',+', '\tHorizontalRail.doLayout() metal={} {}\n' \
|
||||
.format( plane.metal.getName(), self ))
|
||||
viaWidth = plane.conf.vDeepRG.getPitch()*5
|
||||
for stripe in stripes:
|
||||
trace( 550, ',+', '\t{}\n'.format(stripe) )
|
||||
stripeBb = stripe.getBoundingBox()
|
||||
for chunk in self.intervals.chunks:
|
||||
if chunk.getVMax() <= stripeBb.getXMin(): continue
|
||||
if chunk.getVMin() >= stripeBb.getXMax(): break
|
||||
trace( 550, '\t| Chunk=[{} {}]\n'.format( DbU.getValueString(chunk.getVMin())
|
||||
, DbU.getValueString(chunk.getVMax()) ))
|
||||
chunkBb = Box( chunk.getVMin()
|
||||
, self.axis - self.width/2
|
||||
, chunk.getVMax()
|
||||
, self.axis + self.width/2 )
|
||||
overlap = stripeBb.getIntersection( chunkBb )
|
||||
if overlap.isEmpty(): continue
|
||||
if overlap.getWidth() > 5*viaWidth:
|
||||
trace( 550, '\t| Large overlap={}\n'.format(overlap) )
|
||||
via = BigVia( stripe.getNet()
|
||||
, plane.getLayerDepth(stripe.getLayer())
|
||||
, overlap.getXMin() + viaWidth/2
|
||||
, overlap.getYCenter()
|
||||
, viaWidth
|
||||
, overlap.getHeight()
|
||||
, BigVia.AllowTopMetalExpand|BigVia.AllowVerticalExpand
|
||||
)
|
||||
via.mergeDepth( plane.getLayerDepth(plane.getLayer()) )
|
||||
via.doLayout()
|
||||
via = BigVia( stripe.getNet()
|
||||
, plane.getLayerDepth(stripe.getLayer())
|
||||
, overlap.getXMax() - viaWidth/2
|
||||
, overlap.getYCenter()
|
||||
, viaWidth
|
||||
, overlap.getHeight()
|
||||
, BigVia.AllowTopMetalExpand|BigVia.AllowVerticalExpand
|
||||
)
|
||||
via.mergeDepth( plane.getLayerDepth(plane.getLayer()) )
|
||||
via.doLayout()
|
||||
else:
|
||||
trace( 550, '\t| Narrow overlap={}\n'.format(overlap) )
|
||||
via = BigVia( stripe.getNet()
|
||||
, plane.getLayerDepth(stripe.getLayer())
|
||||
, overlap.getXCenter()
|
||||
, overlap.getYCenter()
|
||||
, overlap.getWidth()
|
||||
, overlap.getHeight()
|
||||
, BigVia.AllowTopMetalExpand|BigVia.AllowVerticalExpand
|
||||
)
|
||||
via.mergeDepth( plane.getLayerDepth(plane.getLayer()) )
|
||||
via.doLayout()
|
||||
trace( 550, '-' )
|
||||
trace( 550, '-' )
|
||||
return
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.VerticalRail"
|
||||
|
||||
class VerticalRail ( Rail ):
|
||||
|
||||
def __init__ ( self, bb ):
|
||||
super(VerticalRail,self).__init__( bb.getXCenter(), bb.getWidth() )
|
||||
self.isHorizontal = False
|
||||
|
||||
@property
|
||||
def typeName ( self ): return 'VerticalRail'
|
||||
|
||||
def merge ( self, bb ):
|
||||
self.intervals.merge( bb.getYMin(), bb.getYMax() )
|
||||
|
||||
def doLayout ( self, plane, stripes ):
|
||||
return
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.Rails"
|
||||
|
||||
class Rails ( object ):
|
||||
|
||||
def __init__ ( self, net ):
|
||||
self.net = net
|
||||
self.axisLut = {}
|
||||
|
||||
def merge ( self, bb ):
|
||||
if self.isHorizontal:
|
||||
axis = bb.getYCenter()
|
||||
width = bb.getHeight()
|
||||
else:
|
||||
axis = bb.getXCenter()
|
||||
width = bb.getWidth()
|
||||
if not self.axisLut.has_key(axis):
|
||||
self.axisLut[ axis ] = {}
|
||||
if not self.axisLut[axis].has_key(width):
|
||||
if self.isHorizontal:
|
||||
self.axisLut[ axis ][ width ] = HorizontalRail( bb )
|
||||
else:
|
||||
self.axisLut[ axis ][ width ] = VerticalRail( bb )
|
||||
trace( 550, '\tRails.merge() on {} bb={}\n'.format(type(self.axisLut[ axis ][ width ]),bb) )
|
||||
self.axisLut[ axis ][ width ].merge( bb )
|
||||
|
||||
def doLayout ( self, plane, stripes ):
|
||||
for wrail in self.axisLut.values():
|
||||
for rail in wrail.values():
|
||||
rail.doLayout( plane, stripes )
|
||||
return
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.HorizontalRails"
|
||||
|
||||
class HorizontalRails ( Rails ):
|
||||
|
||||
def __init__ ( self, net ):
|
||||
super(HorizontalRails,self).__init__( net )
|
||||
self.isHorizontal = True
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.VerticalRails"
|
||||
|
||||
class VerticalRails ( Rails ):
|
||||
|
||||
def __init__ ( self, net ):
|
||||
super(VerticalRails,self).__init__( net )
|
||||
self.isHorizontal = False
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.Plane"
|
||||
|
||||
class Plane ( object ):
|
||||
|
||||
Horizontal = 0001
|
||||
Vertical = 0002
|
||||
|
||||
def __init__ ( self, builder, metal ):
|
||||
self.builder = builder
|
||||
self.metal = metal
|
||||
self.powerHRails = HorizontalRails( self.conf.coronaVdd )
|
||||
self.powerVRails = VerticalRails ( self.conf.coronaVdd )
|
||||
self.groundHRails = HorizontalRails( self.conf.coronaVss )
|
||||
self.groundVRails = VerticalRails ( self.conf.coronaVss )
|
||||
|
||||
@property
|
||||
def conf ( self ): return self.builder.conf
|
||||
|
||||
def getLayer ( self ): return self.metal
|
||||
|
||||
def getLayerDepth ( self, layer ): return self.conf.getLayerDepth( layer )
|
||||
|
||||
def addRail ( self, net, bb ):
|
||||
if net.isPower():
|
||||
if bb.getWidth() >= bb.getHeight(): self.powerHRails.merge( bb )
|
||||
else: self.powerVRails.merge( bb )
|
||||
elif net.isGround():
|
||||
if bb.getWidth() >= bb.getHeight(): self.groundHRails.merge( bb )
|
||||
else: self.groundVRails.merge( bb )
|
||||
else:
|
||||
trace( 550, '\nPlane.addRail(): Reject, not a supply net:{}\n'.format(net) )
|
||||
|
||||
def doLayout ( self, stripes ):
|
||||
self.powerHRails .doLayout( self, stripes.powerStripes )
|
||||
self.groundHRails.doLayout( self, stripes.groundStripes )
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.Stripe"
|
||||
|
||||
class Stripe ( object ):
|
||||
|
||||
def __init__ ( self, builder, southPin, northPin ):
|
||||
self.builder = builder
|
||||
self.southPin = southPin
|
||||
self.northPin = northPin
|
||||
self.stripe = None
|
||||
|
||||
@property
|
||||
def conf ( self ): return self.builder.conf
|
||||
|
||||
def __str__ ( self ):
|
||||
s = '<Stripe "{}" @{}>'.format( self.southPin.getNet().getName()
|
||||
, DbU.getValueString(self.southPin.getX()) )
|
||||
return s
|
||||
|
||||
def getNet ( self ):
|
||||
if self.southPin: return self.southPin.getNet()
|
||||
if self.northPin: return self.northPin.getNet()
|
||||
return None
|
||||
|
||||
def getLayer ( self ):
|
||||
if self.southPin: return self.southPin.getLayer()
|
||||
if self.northPin: return self.northPin.getLayer()
|
||||
return None
|
||||
|
||||
def getBoundingBox ( self ):
|
||||
if self.stripe: return self.stripe.getBoundingBox()
|
||||
bb = Box()
|
||||
if self.southPin: bb.merge( self.southPin.getBoundingBox() )
|
||||
if self.northPin: bb.merge( self.northPin.getBoundingBox() )
|
||||
return bb
|
||||
|
||||
def doLayout ( self ):
|
||||
if self.southPin is None:
|
||||
print( ErrorMessage( 1, [ 'Stripes.doLayout(): Power/ground stripe is missing a south Pin.'
|
||||
, '(north:'.format(self.northPin) ] ))
|
||||
return
|
||||
if self.northPin is None:
|
||||
print( ErrorMessage( 1, [ 'Stripes.doLayout(): Power/ground stripe is missing a north Pin.'
|
||||
, '(north:'.format(self.southPin) ] ))
|
||||
return
|
||||
self.stripe = Vertical.create( self.southPin
|
||||
, self.northPin
|
||||
, self.southPin.getLayer()
|
||||
, self.southPin.getX()
|
||||
, self.southPin.getWidth() )
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.Stripes"
|
||||
|
||||
class Stripes ( object ):
|
||||
|
||||
def __init__ ( self, builder ):
|
||||
self.builder = builder
|
||||
self.powers = {}
|
||||
self.grounds = {}
|
||||
self.supplyLayer = self.conf.routingGauge.getPowerSupplyGauge().getLayer()
|
||||
for pin in self.conf.coronaVdd.getPins():
|
||||
if pin.getLayer() != self.supplyLayer: continue
|
||||
key = pin.getX()
|
||||
if pin.getAccessDirection() == Pin.Direction.SOUTH:
|
||||
if not self.powers.has_key(key): self.powers[ key ] = Stripe( self, pin, None )
|
||||
else: self.powers[ key ].southPin = pin
|
||||
elif pin.getAccessDirection() == Pin.Direction.NORTH:
|
||||
if not self.powers.has_key(key): self.powers[ key ] = Stripe( self, None, pin )
|
||||
else: self.powers[ key ].northPin = pin
|
||||
for pin in self.conf.coronaVss.getPins():
|
||||
if pin.getLayer() != self.supplyLayer: continue
|
||||
key = pin.getX()
|
||||
if pin.getAccessDirection() == Pin.Direction.SOUTH:
|
||||
if not self.grounds.has_key(key): self.grounds[ key ] = Stripe( self, pin, None )
|
||||
else: self.grounds[ key ].southPin = pin
|
||||
elif pin.getAccessDirection() == Pin.Direction.NORTH:
|
||||
if not self.grounds.has_key(key): self.grounds[ key ] = Stripe( self, None, pin )
|
||||
else: self.grounds[ key ].northPin = pin
|
||||
|
||||
@property
|
||||
def conf ( self ): return self.builder.conf
|
||||
|
||||
@property
|
||||
def powerStripes ( self ): return self.powers.values()
|
||||
|
||||
@property
|
||||
def groundStripes ( self ): return self.grounds.values()
|
||||
|
||||
def doLayout ( self ):
|
||||
for stripe in self.powers .values(): stripe.doLayout()
|
||||
for stripe in self.grounds.values(): stripe.doLayout()
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.GoCb"
|
||||
|
||||
class GoCb ( object ):
|
||||
|
||||
def __init__ ( self, builder ):
|
||||
self.builder = builder
|
||||
|
||||
def __call__ ( self, query, go ):
|
||||
managed = False
|
||||
if isinstance(go,Horizontal): managed = True
|
||||
elif isinstance(go,Vertical): managed = True
|
||||
if not managed: return
|
||||
rootNet = None
|
||||
if go.getNet().getType() == long(Net.Type.POWER): rootNet = self.builder.conf.coronaVdd
|
||||
if go.getNet().getType() == long(Net.Type.GROUND): rootNet = self.builder.conf.coronaVss
|
||||
if not rootNet: return
|
||||
if not NetExternalComponents.isExternal(go): return
|
||||
if self.builder.activePlane:
|
||||
layer = self.builder.activePlane.metal
|
||||
if layer.isSymbolic():
|
||||
layer = layer.getBasicLayer()
|
||||
bb = go.getBoundingBox( layer )
|
||||
query.getPath().getTransformation().applyOn( bb )
|
||||
trace( 550, '\tGoCb.__call__(): path={} go={}\n'.format(query.getPath(),go) )
|
||||
self.builder.activePlane.addRail( rootNet, bb )
|
||||
else:
|
||||
print( WarningMessage( 'power.GoCb() callback called without an active plane.' ))
|
||||
return
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.Builder"
|
||||
|
||||
class Builder ( object ):
|
||||
|
||||
def __init__ ( self, conf ):
|
||||
self.conf = conf
|
||||
self.path = Path()
|
||||
self.corona = self.conf.icorona.getMasterCell()
|
||||
self.icoreAb = self.conf.icore.getAbutmentBox()
|
||||
self.planes = {}
|
||||
self.stripes = Stripes( self )
|
||||
self.activePlane = None
|
||||
for layerGauge in self.conf.routingGauge.getLayerGauges():
|
||||
self.planes[ layerGauge.getLayer().getName() ] = Plane( self, layerGauge.getLayer() )
|
||||
|
||||
def connectPower ( self ):
|
||||
if not self.conf.coronaVdd or not self.conf.coronaVss:
|
||||
raise ErrorMessage( 1, 'Cannot build block power terminals as core vdd and/or vss are not known.' )
|
||||
return
|
||||
goCb = GoCb( self )
|
||||
query = Query()
|
||||
query.setGoCallback( goCb )
|
||||
query.setCell( self.corona )
|
||||
query.setArea( self.icoreAb )
|
||||
query.setFilter( Query.DoComponents|Query.DoTerminalCells )
|
||||
query.setStopCellFlags( Cell.Flags_AbstractedSupply )
|
||||
for layerGauge in self.conf.routingGauge.getLayerGauges():
|
||||
self.activePlane = self.planes[ layerGauge.getLayer().getName() ]
|
||||
layer = layerGauge.getLayer()
|
||||
if layer.isSymbolic():
|
||||
layer = layer.getBasicLayer()
|
||||
query.setBasicLayer( layer )
|
||||
trace( 550, ',+', 'query.doQuery() {}'.format(layer) )
|
||||
query.doQuery()
|
||||
trace( 550, '-' )
|
||||
self.activePlane = None
|
||||
|
||||
def _connectClock ( self, ck, trackNb ):
|
||||
trace( 550, '\tpower.Builder._connectClock() {}\n'.format(ck) )
|
||||
blockCk = 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()) )
|
||||
return
|
||||
htPlugs = []
|
||||
for plug in ck.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()
|
||||
, self.conf.icore.getName()
|
||||
, len(htPlugs)) ]
|
||||
for plug in htPlugs:
|
||||
message += [ '\n - {} {}'.format(plug,plug.getInstance()) ]
|
||||
raise ErrorMessage( 1, message )
|
||||
return
|
||||
coronaPin = None
|
||||
for pin in ck.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() ) ]
|
||||
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 )
|
||||
self.conf.expandMinArea( bufferRp )
|
||||
if coronaPin.getAccessDirection() == Pin.Direction.NORTH:
|
||||
isVertical = True
|
||||
axis = coronaAb.getYMax()
|
||||
trackNb = -trackNb
|
||||
elif coronaPin.getAccessDirection() == Pin.Direction.SOUTH:
|
||||
isVertical = True
|
||||
axis = coronaAb.getYMin()
|
||||
elif coronaPin.getAccessDirection() == Pin.Direction.EAST:
|
||||
isVertical = False
|
||||
axis = coronaAb.getXMax()
|
||||
trackNb = -trackNb
|
||||
elif coronaPin.getAccessDirection() == Pin.Direction.WEST:
|
||||
isVertical = False
|
||||
axis = coronaAb.getXMin()
|
||||
if isVertical:
|
||||
pitch = self.conf.vRoutingGauge.getPitch()
|
||||
yaxis = axis + pitch * trackNb
|
||||
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 )
|
||||
self.conf.createVertical ( bufferRp, contact1, xaxisRp , 0 )
|
||||
self.conf.createHorizontal( contact1, contact2, yaxis , 0 )
|
||||
self.conf.createVertical ( contact2, pinRp , xaxisPin, 0 )
|
||||
else:
|
||||
pitch = self.conf.hRoutingGauge.getPitch()
|
||||
xaxis = axis + pitch * trackNb
|
||||
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 )
|
||||
self.conf.createHorizontal( bufferRp, contact1, yaxisRp , 0 )
|
||||
self.conf.createVertical ( contact1, contact2, xaxis , 0 )
|
||||
self.conf.createHorizontal( contact2, pinRp , yaxisPin, 0 )
|
||||
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+1 )
|
||||
|
||||
def doLayout ( self ):
|
||||
with UpdateSession():
|
||||
self.stripes.doLayout()
|
||||
for plane in self.planes.values():
|
||||
plane.doLayout( self.stripes )
|
Loading…
Reference in New Issue