No longer straight route the root of a H-Tree.

* Change: In cumulus/plugins.block.HTree._rrouteHTree(), make the
    non-routing of the root net the default policy. Straight routing
    can still be activated with the use of Spares.ROUTE_ROOT_NET.
This commit is contained in:
Jean-Paul Chaput 2021-11-16 17:11:00 +01:00
parent 0f636912e0
commit c595a8e73e
5 changed files with 864 additions and 2 deletions

View File

@ -185,7 +185,9 @@ class HTree ( object ):
self._connectLeaf( qt.br, ckNet, rightContact, brContact, rightX, blY )
if qt.isRoot():
ckNet = self.treeNet
if not self.spares.conf.isCoreBlock and ckNet.isExternal():
if not self.spares.conf.isCoreBlock \
and ckNet.isExternal() \
and (self.flags & Spares.ROUTE_ROOT_NET):
trace( 550, '\tRemoving any previous pin...\n' )
pins = []
for pin in ckNet.getPins(): pins.append( pin )

View File

@ -892,7 +892,7 @@ class QuadTree ( object ):
class Spares ( object ):
"""
Manages all the spare buffer over a Cell abutment box. Used for clock tree
synthesis (CTS) and high fanout net synthesis (HFS). 4 buffers are created
synthesis (CTS) and high fanout net synthesis (HNFS). 4 buffers are created
in each pool. Pools are set in a regular matrix over the whole abutment box.
Excess area is put in the topmost and rightmost pools.
"""
@ -901,6 +901,7 @@ class Spares ( object ):
CHECK_USED = 0x00010000
MARK_USED = 0x00020000
HEAVY_LEAF_LOAD = 0x00040000
ROUTE_ROOT_NET = 0x00080000
def __init__ ( self, block ):
self.conf = block.conf

View File

@ -0,0 +1,711 @@
# This file is part of the Coriolis Software.
# Copyright (c) Sorbonne Université 2014-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/configuration.py" |
# +-----------------------------------------------------------------+
import sys
import os.path
import Cfg
from Hurricane import Breakpoint, DbU, Box, Transformation, Box, \
Path, Layer, Occurrence, Net, RoutingPad, \
Horizontal, Vertical, Contact, Pin, Plug, \
Instance
import CRL
from CRL import RoutingLayerGauge
from helpers import trace
from helpers.utils import classdecorator
from helpers.overlay import UpdateSession
from helpers.io import ErrorMessage, WarningMessage, \
vprint, catch
import plugins.chip
from plugins.alpha.block.configuration import BlockConf
__all__ = [ 'ChipConf' ]
plugins.alpha.chip.importConstants( globals() )
af = CRL.AllianceFramework.get()
# -------------------------------------------------------------------
# Class : "Configuration.ChipConf".
class ChipConf ( BlockConf ):
@staticmethod
def _toSymbolic ( u, rounding ):
"""
Pitch the coordinates ``u`` to the symbolic grid, according
to ``rounding`` (Superior or Inferior).
"""
oneLambda = DbU.fromLambda( 1.0 )
remainder = u % oneLambda
if remainder:
if rounding == Superior: u = u + (oneLambda - remainder)
else: u = u - remainder
return u
@staticmethod
def toSymbolic ( v, rounding ):
"""
Pitch the coordinates of object ``v`` to the symbolic grid,
according to ``rounding``. Were ``v`` can be:
* A scalar, then rounding is Inferior or Superior.
* A Box, then rounding is:
* Inwards: the pitched box will be fully enclosed in the
original box.
* Outwards: the pitched box will fully enclose the original
box.
"""
if isinstance(v,int): return ChipConf._toSymbolic( v, rounding )
if isinstance(v,Box):
if rounding & Inwards:
roundings = [ Superior
, Superior
, Inferior
, Inferior ]
else:
roundings = [ Inferior
, Inferior
, Superior
, Superior ]
xMin = ChipConf._toSymbolic( v.getXMin(), roundings[0] )
yMin = ChipConf._toSymbolic( v.getYMin(), roundings[1] )
xMax = ChipConf._toSymbolic( v.getXMax(), roundings[2] )
yMax = ChipConf._toSymbolic( v.getYMax(), roundings[3] )
return Box( xMin, yMin, xMax, yMax )
return v
def __init__ ( self, cell, ioPins=[], ioPads=[] ):
trace( 550, ',+', 'ChipConf.__init__(): "{}"'.format(cell.getName()) )
super(ChipConf,self).__init__( cell, ioPins, ioPads )
#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.padCoreSide = None
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
self.cfg.chip.block.rails.hSpacing = None
self.cfg.chip.block.rails.vSpacing = None
self._railsCount = self.cfg.chip.block.rails.count
# Global Net names.
self.blockageName = "blockagenet"
# Global Nets.
self.coronaVdd = None
self.coronaVss = None
self.coronaCks = []
self.blockageNet = None
self.padsHavePosition = False
self.chipLogos = []
trace( 550, '-' )
@property
def padCoreSide ( self ):
return self.cfg.chip.padCoreSide
@property
def railsCount ( self ):
return self._railsCount
@railsCount.setter
def railsCount ( self, count ):
self._railsCount = count
@property
def hRailWidth ( self ):
return self.cfg.chip.block.rails.hWidth
@property
def vRailWidth ( self ):
return self.cfg.chip.block.rails.vWidth
@property
def hRailSpace ( self ):
return self.cfg.chip.block.rails.hSpacing
@property
def vRailSpace ( self ):
return self.cfg.chip.block.rails.vSpacing
def computeCoronaBorder ( self ):
global af
if self.useClockTree:
clockNets = []
for net in self.cellPnR.getNets():
if net.isClock():
clockNets.append( net )
self.railsCount = self.cfg.chip.block.rails.count + len(clockNets)
trace( 550, '\tself.railsCount: {}\n'.format(self.railsCount) )
hRailsSize = self.railsCount*(self.hRailWidth + self.hRailSpace) + self.hRailSpace
if hRailsSize % self.sliceHeight:
hRailsSize += self.sliceHeight - (hRailsSize % self.sliceHeight)
self.minHCorona = hRailsSize + self.sliceHeight
vRailsSize = self.railsCount*(self.vRailWidth + self.vRailSpace) + self.vRailSpace
if vRailsSize % self.sliceHeight:
vRailsSize += self.sliceHeight - (vRailsSize % self.sliceHeight)
self.minVCorona = vRailsSize + self.sliceHeight
def chipValidate ( self ):
#self.checkPads()
#self.checkCorona()
#self.computeChipSize()
#self.checkChipSize()
self.findPowerAndClockNets()
return
def getInstanceAb ( self, instance ):
ab = instance.getMasterCell().getAbutmentBox()
instance.getTransformation().applyOn( ab )
if instance.getCell() == self.chip: return ab
if instance.getCell() != self.corona:
raise ErrorMessage( 1, 'ChipConf.getInstanceAb(): Instance "{}" neither belong to chip or corona.' \
.format(instance.getName()) )
return ab
self.icorona.getTransformation().applyOn( ab )
return ab
def setupICore ( self ):
"""
Setup the abutment box of the *core* master cell and position it's unique
instance (*icore*) in the center of the *corona* master cell.
"""
with UpdateSession():
trace( 550, ',+', '\tChipConf.setupICore()\n' )
ab = self.getInstanceAb( self.icorona )
if ab.isEmpty():
raise ErrorMessage( 1, 'ChipConf.setupICore(): Attempt to setup core *before* corona.' )
return
#ab.inflate( -gapX1, -gapY1, -gapX2, -gapY2 )
ab = self.toSymbolic( ab, Inwards )
trace( 550, '\tself.coreAb:{}\n'.format(self.coreAb) )
if self.core.getAbutmentBox().isEmpty():
if not self.coreAb.isEmpty():
trace( 550, '\tUsing user-defined CORE size:{}\n'.format(self.coreSize) )
ab = self.coreAb
else:
ab.inflate( -self.minHCorona, -self.minVCorona )
self.coreSize = (ab.getWidth(), ab.getHeight())
trace( 550, '\tSetting CORE abutment box:{}\n'.format(ab) )
self.core.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
self.coreSize = ( self.coreSize[0] - self.coreSize[0] % self.sliceStep
, self.coreSize[1] - self.coreSize[1] % self.sliceHeight )
self.core.setAbutmentBox( Box( 0, 0, self.coreAb.getWidth(), self.coreAb.getHeight() ) )
trace( 550, '\tCORE ab:{}\n'.format(self.coreAb) )
coreX = (self.coronaAb.getWidth () - self.coreAb.getWidth ()) // 2
trace( 550, '\tCore X, {} '.format(DbU.getValueString(coreX)) )
coreX = coreX - (coreX % self.sliceHeight)
trace( 550, ' adjusted on {}, {}\n'.format( DbU.getValueString(self.sliceHeight)
, DbU.getValueString(coreX)) )
coreY = (self.coronaAb.getHeight() - self.coreAb.getHeight()) // 2
coreY = coreY - (coreY % self.sliceHeight)
self.icore.setTransformation( Transformation( coreX, coreY, Transformation.Orientation.ID ) )
self.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
trace( 550, '-' )
def getCoronaNet ( self, chipNet ):
for plug in chipNet.getPlugs():
if plug.getInstance() == self.icorona:
return plug.getMasterNet()
return None
def toRoutingGauge ( self, uMin, uMax, layer ):
trace( 550, ',+', '\ttoRoutingGauge() [{} {}] {}\n' \
.format(DbU.getValueString(uMin), DbU.getValueString(uMax), layer) )
ab = self.corona.getAbutmentBox()
lg = None
mask = layer.getMask()
for layerGauge in self.routingGauge.getLayerGauges():
if layerGauge.getLayer().getMask() == mask:
lg = layerGauge
trace( 550, '\tUsing layer gauge {}\n'.format(lg) )
break
if uMax < uMin: uMin, uMax = uMax, uMin
if lg:
if lg.getDirection() == RoutingLayerGauge.Horizontal:
abMin = ab.getYMin()
abMax = ab.getYMax()
else:
abMin = ab.getXMin()
abMax = ab.getXMax()
if uMin <= abMin:
shiftRight = abMin - uMin + lg.getPitch()
uMin += shiftRight
uMax += shiftRight
if uMax >= abMax:
shiftLeft = uMax - abMax + lg.getPitch()
uMin -= shiftLeft
uMax -= shiftLeft
iTrackMin = lg.getTrackIndex( abMin, abMax, uMin, RoutingLayerGauge.Superior )
iTrackMax = lg.getTrackIndex( abMin, abMax, uMax, RoutingLayerGauge.Inferior )
if iTrackMax < iTrackMin: iTrackMax = iTrackMin
uTrackMin = lg.getTrackPosition( abMin, iTrackMin )
uTrackMax = lg.getTrackPosition( abMin, iTrackMax )
axis = (uTrackMax + uTrackMin) // 2
width = (iTrackMax - iTrackMin) * lg.getPitch() + lg.getWireWidth()
if self.routingGauge.isSymbolic():
trace( 550, '\tRoutingGauge is symbolic, adjust on lambda.\n' )
oneLambda = DbU.fromLambda( 1.0 )
if axis % oneLambda:
axis -= oneLambda // 2
width -= oneLambda
trace( 550, '\t[{} {}] -> [{} {}]\n'.format( iTrackMin
, iTrackMax
, DbU.getValueString(uTrackMin)
, DbU.getValueString(uTrackMax) ) )
trace( 550, '\taxis: {:.1f}L {}\n'.format(DbU.toLambda(axis ), DbU.getValueString(axis )) )
trace( 550, '\twidth: {:.1f}L {}\n'.format(DbU.toLambda(width), DbU.getValueString(width)) )
else:
axis = (uMax + uMin) // 2
width = (uMax - uMin)
trace( 550, '-' )
return axis, width
def toCoronaPitchInChip ( self, uCore, layer ):
trace( 550, ',+', '\tChipConf.toCoronaPitchInChip(): uCore: {:.1f}L {}\n' \
.format(DbU.toLambda(uCore), DbU.getValueString(uCore)) )
coronaAb = self.getInstanceAb( self.icorona )
lg = None
mask = layer.getMask()
for layerGauge in self.routingGauge.getLayerGauges():
if layerGauge.getLayer().getMask() == mask:
lg = layerGauge
break
if not lg:
trace( 550, '-' )
return 0
trace( 550, '\t{}\n'.format(lg) )
if lg:
if lg.getDirection() == RoutingLayerGauge.Horizontal:
uCorona = uCore - coronaAb.getYMin()
else:
uCorona = uCore - coronaAb.getXMin()
uCorona, width = self.toRoutingGauge( uCorona, uCorona, layer )
trace( 550, '\ttoCoronaPitchInChip(): uCorona: {:.1f}L {}\n' \
.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) )
if lg:
if lg.getDirection() == RoutingLayerGauge.Horizontal:
uCore = uCorona + coronaAb.getYMin()
else:
uCore = uCorona + coronaAb.getXMin()
trace( 550, '\ttoCoronaPitchInChip(): uCorona: {:.1f}L {}\n'.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) )
trace( 550, '\ttoCoronaPitchInChip(): uCore: {:.1f}L {}\n'.format(DbU.toLambda(uCore ), DbU.getValueString(uCore )) )
trace( 550, '-' )
return uCore
def coronaHorizontal ( self, chipNet, layer, chipY, width, chipXMin, chipXMax ):
trace( 550, ',+', '\tChipConf.coronaHorizontal\n' )
coronaAb = self.getInstanceAb( self.icorona )
coronaNet = self.getCoronaNet ( chipNet )
if not coronaNet: return None
coronaY = chipY - coronaAb.getYMin()
dxMin = ChipConf.toSymbolic( chipXMin - coronaAb.getXMin(), Superior )
dxMax = ChipConf.toSymbolic( chipXMax - coronaAb.getXMin(), Inferior )
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) )
trace( 550, '\t| Real\n' )
trace( 550, '\t| axis: {}\n'.format(DbU.getValueString(coronaY)) )
trace( 550, '\t| width:{}\n'.format(DbU.getValueString(width)) )
trace( 550, '\t| dxMin:{} ({:.1f}L)\n' \
.format( DbU.getValueString(chipXMin - coronaAb.getXMin())
, DbU.toLambda(chipXMin - coronaAb.getXMin()) ) )
trace( 550, '\t| dxMax:{}\n'.format(DbU.getValueString(chipXMax - coronaAb.getXMin())) )
coronaY, width = self.toRoutingGauge( coronaY - width//2, coronaY + width//2, layer )
trace( 550, '\t| On Grid\n' )
trace( 550, '\t| axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaY), DbU.getValueString(coronaY)) )
trace( 550, '\t| width:{:.1f}L or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) )
trace( 550, '\t| dxMin:{:.1f}L\n'.format(DbU.toLambda(dxMin)) )
trace( 550, '\t| dxMax:{:.1f}L\n'.format(DbU.toLambda(dxMax)) )
h = Horizontal.create( coronaNet, layer, coronaY, width, dxMin, dxMax )
trace( 550, '\t| {}\n'.format(h) )
trace( 550, '-' )
return h
def coronaVertical ( self, chipNet, layer, chipX, width, chipYMin, chipYMax ):
trace( 550, ',+', '\tChipConf.coronaVertical\n' )
coronaAb = self.getInstanceAb( self.icorona )
coronaNet = self.getCoronaNet( chipNet )
if not coronaNet: return None
coronaX = chipX - coronaAb.getXMin()
dyMin = ChipConf.toSymbolic( chipYMin - coronaAb.getYMin(), Superior )
dyMax = ChipConf.toSymbolic( chipYMax - coronaAb.getYMin(), Inferior )
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) )
trace( 550, '\t| Real\n' )
trace( 550, '\t| axis: {}\n'.format(DbU.getValueString(coronaX)) )
trace( 550, '\t| width:{}\n'.format(DbU.getValueString(width)) )
coronaX, width = self.toRoutingGauge( coronaX - width//2, coronaX + width//2, layer )
trace( 550, '\t| On Grid\n' )
trace( 550, '\t| axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaX), DbU.getValueString(coronaX)) )
trace( 550, '\t| width:{:.1f}L or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) )
v = Vertical.create( coronaNet, layer, coronaX, width, dyMin, dyMax )
trace( 550, '\t| {}\n'.format(v) )
trace( 550, '-' )
return v
def coronaContact ( self, chipNet, layer, chipX, chipY, width, height, flags=0 ):
trace( 550, ',+', '\tChipConf.coronaContact\n' )
coronaAb = self.getInstanceAb( self.icorona )
coronaNet = self.getCoronaNet( chipNet )
if not coronaNet: return None
coronaX = chipX - coronaAb.getXMin()
coronaY = chipY - coronaAb.getYMin()
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet,layer) )
trace( 550, '\t| Real\n' )
trace( 550, '\t| center: {:>12} {:>12}\n'.format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
trace( 550, '\t| WxH: {:>12} {:>12}\n'.format(DbU.getValueString(width ), DbU.getValueString(height )) )
topLayer = layer.getTop()
botLayer = layer.getBottom()
if self.isHorizontal(topLayer):
coronaX, width = self.toRoutingGauge( coronaX - width //2, coronaX + width //2, botLayer )
coronaY, height = self.toRoutingGauge( coronaY - height//2, coronaY + height//2, topLayer )
else:
coronaX, width = self.toRoutingGauge( coronaX - width //2, coronaX + width //2, topLayer )
coronaY, height = self.toRoutingGauge( coronaY - height//2, coronaY + height//2, botLayer )
if not (flags & OnHorizontalPitch):
trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' )
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior )
if not (flags & OnVerticalPitch ):
trace( 550, '\tNot on vertical routing pitch, X on lambda only.\n' )
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior )
trace( 550, '\t| On Grid\n' )
trace( 550, '\t| X axis: {:>12.1f}L or {:>12}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) )
trace( 550, '\t| Y axis: {:>12.1f}L or {:>12}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) )
trace( 550, '\t| center: {:>12} {:>12}\n' .format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
trace( 550, '\t| WxH: {:>12} {:>12}\n' .format(DbU.getValueString(width ), DbU.getValueString(height )) )
c = Contact.create( coronaNet
, layer
, coronaX
, coronaY
, width
, height
)
trace( 550, '\t| {}\n'.format(c) )
trace( 550, '-' )
return c
def getViaPitch ( self, viaLayer ):
topLayer = viaLayer.getTop()
if topLayer.isSymbolic():
topLayer = topLayer.getBasicLayer()
topEnclosure = viaLayer.getEnclosure( topLayer, Layer.EnclosureH|Layer.EnclosureV )
topPitch = 2*topEnclosure + viaLayer.getMinimalSize() + topLayer.getMinimalSpacing()
botLayer = viaLayer.getBottom()
if botLayer.isSymbolic():
botLayer = botLayer.getBasicLayer()
botEnclosure = viaLayer.getEnclosure( botLayer, Layer.EnclosureH|Layer.EnclosureV )
botPitch = 2*botEnclosure + viaLayer.getMinimalSize() + botLayer.getMinimalSpacing()
viaPitch = max( topPitch, botPitch )
trace( 550, '\tgetViaPitch of {}: {}\n'.format(viaLayer.getName(),DbU.getValueString(viaPitch)) )
trace( 550, '\t| minimal size of {}: {}\n'.format(viaLayer.getName(),DbU.getValueString(viaLayer.getMinimalSize())) )
trace( 550, '\t| enclosure of {}: {}\n'.format(topLayer.getName(),DbU.getValueString(topEnclosure)) )
trace( 550, '\t| enclosure of {}: {}\n'.format(botLayer.getName(),DbU.getValueString(botEnclosure)) )
return viaPitch
def coronaContactArray ( self, chipNet, layer, chipX, chipY, array, flags ):
trace( 550, ',+', '\tChipConf.coronaContactArray\n' )
viaPitch = self.getViaPitch( layer )
coronaAb = self.getInstanceAb( self.icorona )
coronaNet = self.getCoronaNet( chipNet )
if not coronaNet: return None
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) )
coronaX = chipX - coronaAb.getXMin()
coronaY = chipY - coronaAb.getYMin()
topLayer = layer.getTop()
if self.isHorizontal(topLayer):
coronaX, width = self.toRoutingGauge( coronaX, coronaX, layer.getBottom() )
coronaY, height = self.toRoutingGauge( coronaY, coronaY, topLayer )
else:
coronaX, width = self.toRoutingGauge( coronaX, coronaX, topLayer )
coronaY, height = self.toRoutingGauge( coronaY, coronaY, layer.getBottom() )
if not (flags & OnHorizontalPitch):
trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' )
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior )
if not (flags & OnVerticalPitch ):
trace( 550, '\tNot on vertical routing pitch, X on lambda only.\n' )
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior )
contacts = []
xContact = coronaX - viaPitch * (array[0]-1)//2
yContact = coronaY - viaPitch * (array[1]-1)//2
contactSize = layer.getMinimalSize()
trace( 550, '\txContact:{} yContact:{}\n'.format(DbU.getValueString(xContact),DbU.getValueString(yContact)) )
for i in range(array[0]):
for j in range(array[1]):
c = Contact.create( coronaNet
, layer
, xContact + i*viaPitch
, yContact + j*viaPitch
, contactSize
, contactSize
)
trace( 550, '\t+ {}\n'.format(c) )
contacts.append( c )
trace( 550, '-' )
return contacts
def coronaPin ( self, chipNet, count, direction, layer, chipX, chipY, width, height ):
trace( 550, ',+', '\tChipConf.coronaPin\n' )
coronaAb = self.getInstanceAb( self.icorona )
coronaNet = self.getCoronaNet( chipNet )
if not coronaNet: return None
coronaX = chipX - coronaAb.getXMin()
coronaY = chipY - coronaAb.getYMin()
trace( 550, '\t| chipNet: {} ({}) {}\n'.format(chipNet, count, layer) )
trace( 550, '\t| Real\n' )
trace( 550, '\t| center: {} {}\n'.format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
trace( 550, '\t| WxH: {} {}\n'.format(DbU.getValueString(width ), DbU.getValueString(height )) )
topLayer = layer.getTop()
if self.isHorizontal(topLayer):
coronaX, width = self.toRoutingGauge( coronaX - width //2, coronaX + width //2, layer.getBottom() )
coronaY, height = self.toRoutingGauge( coronaY - height//2, coronaY + height//2, topLayer )
else:
coronaX, width = self.toRoutingGauge( coronaX - width //2, coronaX + width //2, topLayer )
coronaY, height = self.toRoutingGauge( coronaY - height//2, coronaY + height//2, layer.getBottom() )
if direction == Pin.Direction.NORTH or direction == Pin.Direction.SOUTH:
trace( 550, '\tEast/West not on horizontal routing pitch, Y on lambda only.\n' )
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior )
if direction == Pin.Direction.EAST or direction == Pin.Direction.WEST:
trace( 550, '\tNorth/South not on vertical routing pitch, X on lambda only.\n' )
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior )
trace( 550, '\t| On Grid\n' )
trace( 550, '\t| X axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) )
trace( 550, '\t| Y axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) )
trace( 550, '\t| center: {} {}\n' .format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
trace( 550, '\t| WxH: {} {}\n' .format(DbU.getValueString(width ), DbU.getValueString(height )) )
c = Pin.create( coronaNet
, '{}.{}'.format(coronaNet.getName(),count)
, direction
, Pin.PlacementStatus.FIXED
, layer
, coronaX
, coronaY
, width
, height
)
trace( 550, '\t| {}\n'.format(c) )
trace( 550, '-' )
return c
def checkPads ( self ):
def contains ( padList, side, padInstance ):
for i in range(len(padList)):
if padList[i][1] == padInstance.getName():
if (padInstance.getMasterCell().getAbutmentBox().getHeight() != self.ioPadHeight):
raise ErrorMessage( 1, 'The pad [{}] {} ({}) on {} side is not an instance of a pad cell.' \
.format(i,padInstance.getName(),padInstance.getMasterCell().getName(),side) )
padList[i][1] = padInstance
return True
return False
def checkNotFounds ( padList, side ):
for i in range(len(padList)):
if not isinstance(padList[i][1],Instance):
print( ErrorMessage( 1, 'The pad [{}] ({}) of list {} do not exists in netlist (skipped).'
.format(i,padList[i][1],side) ))
return
global af
cellPads = []
for instance in self.chip.getInstances():
if contains(self.southPads,'south',instance): continue
if contains(self.northPads,'north',instance): continue
if contains(self.eastPads ,'east' ,instance): continue
if contains(self.westPads ,'west' ,instance): continue
if (instance.getMasterCell().getAbutmentBox().getHeight() == self.ioPadHeight):
raise ErrorMessage( 1, 'Pad "{}" is not on any side (N/S/E/W).'.format(instance.getName()) )
self.validated = False
else:
self.coronas.append( instance )
checkNotFounds( self.southPads, 'south' )
checkNotFounds( self.northPads, 'north' )
checkNotFounds( self.eastPads , 'east' )
checkNotFounds( self.westPads , 'west' )
if len(self.coronas) > 1:
message = [ 'Chip "{}" have more than one corona:'.format(self.chip.getName()) ]
for i in range(len(self.coronas)):
message.append( '{}: {}'.format(i,self.coronas[i].getName()) )
raise ErrorMessage( 1, message )
self.validated = False
if len(self.coronas) < 1:
raise ErrorMessage( 1, 'Chip "{}" doesn\'t seems to have a corona.' \
.format(self.chip.getName()) )
self.validated = False
else:
for instance in self.corona.getInstances():
self.cores.append( instance )
if len(self.cores) > 1:
message = [ 'Chip "{}" have more than one core:'.format(self.chip.getName()) ]
for i in range(len(self.cores)):
message.append( '{}: {}'.format(i,self.cores[i].getName()) )
raise ErrorMessage( 1, message )
self.validated = False
if len(self.cores) < 1:
raise ErrorMessage( 1, 'Chip "{} doesn\'t seems to have a core.' \
.format(self.chip.getName()) )
self.validated = False
return
def findPowerAndClockNets ( self ):
if self.icore:
for plug in self.icore.getPlugs():
masterNet = plug.getMasterNet()
netType = masterNet.getType()
if netType != Net.Type.POWER \
and netType != Net.Type.GROUND \
and netType != Net.Type.CLOCK:
continue
net = plug.getNet()
if not net:
net = self.corona.getNet( masterNet.getName() )
if not net:
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Missing global net "{}" at corona level.' \
.format(asterNet.getName()) )
self._validated = False
continue
if netType == Net.Type.GROUND:
if self.coronaVss and self.coronaVss != net:
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple ground nets "{}" and "{}" at corona level.' \
.format(self.coronaVss.getName(), net.getName()) )
self._validated = False
continue
else:
self.coronaVss = net
if netType == Net.Type.POWER:
if self.coronaVdd and self.coronaVdd != net:
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple power nets "{}" and "{}" at corona level.' \
.format(self.coronaVdd.getName(), net.getName()) )
self._validated = False
continue
else:
self.coronaVdd = net
if netType == Net.Type.CLOCK:
if not net in self.coronaCks:
self.coronaCks.append( net )
vprint( 2, ' - Using clock "{}".'.format(net.getName()) )
for net in self.corona.getNets():
if net.getType() == Net.Type.BLOCKAGE:
self.blockageNet = net
self.blockageName = net.getName()
if not self.blockageNet:
self.blockageNet = Net.create( self.corona, self.blockageName )
self.blockageNet.setType( Net.Type.BLOCKAGE )
return
def checkChipSize ( self ):
if self.chipSize[0] % self.sliceStep:
print( WarningMessage( 'ChipConf.checkChipSize(): Width of "{}" ({})is not on sliceStep ({}), ajusted.' \
.format( self.chipConf.name
, DbU.getValueString(self.chipSize[0])
, DbU.getValueString(self.sliceStep))) )
adjust = self.sliceStep - self.chipSize[0] % self.sliceStep
self.chipSize = (self.chipSize[0] + adjust, self.chipSize[1])
if self.chipSize[1] % self.sliceStep:
print( WarningMessage( 'ChipConf.checkChipSize(): Height of "{}" ({})is not on sliceStep ({}), ajusted.' \
.format( self.chipConf.name
, DbU.getValueString(self.chipSize[1])
, DbU.getValueString(self.sliceStep))) )
adjust = self.sliceStep - self.chipSize[1] % self.sliceStep
self.chipSize = (self.chipSize[0], self.chipSize[1] + adjust)
#if self._coreSize.isEmpty(): return
#
#minWidth = self._coreSize.getWidth () + self._minCorona + 2*self._padHeight
#minHeight = self._coreSize.getHeight() + self._minCorona + 2*self._padHeight
#
#if self._chipSize.getWidth() < minWidth:
# raise ErrorMessage( 1, 'Core is too wide to fit into the chip. Needs: %d, but has %d' \
# % ( DbU.toLambda(minWidth), DbU.toLambda(self._chipSize.getWidth()) ) )
# self._validated = False
#
#if self._chipSize.getHeight() < minHeight:
# raise ErrorMessage( 1, 'Core is too wide to fit into the chip. Needs: %d, but has %d' \
# % ( DbU.toLambda(minHeight), DbU.toLambda(self._chipSize.getHeight()) ) )
# self._validated = False
return
def checkCorona ( self ):
trace( 550, ',+', 'Configuration.checkCorona()\n' )
netPads = {}
for plug in self.icorona.getPlugs():
padNet = plug.getNet()
coronaNet = plug.getMasterNet()
if not padNet and coronaNet.isGlobal():
padNet = self.chip.getNet( coronaNet.getName() )
if padNet:
if not padNet in netPads:
trace( 550, '\t{:>20} <-> {:<20}\n'.format(padNet.getName(),coronaNet.getName()) )
netPads[ padNet ] = coronaNet
else:
raise ErrorMessage( 1, 'ChipConf.checkCorona(): Corona nets "{}" and "{}" connected to the same pad net "{}".' \
.format(coronaNet.getName(),netPads[padNet].getName(),padNet.getName()) )
self._validated = False
trace( 550, '-' )
return
def computeChipSize ( self ):
def getSideLength ( pads ):
sideLength = self.ioPadHeight * 2
for pad in pads: sideLength += pad.getMasterCell().getAbutmentBox().getWidth()
return sideLength
if not self.chipSize.isEmpty(): return
southPadsLength = getSideLength( self.southPads )
northPadsLength = getSideLength( self.northPads )
eastPadsLength = getSideLength( self.eastPads )
westPadsLength = getSideLength( self.westPads )
horizontalPads = max( len(self.southPads), len(self.northPads) )
verticalPads = max( len(self.eastPads ), len(self.westPads ) )
self.chipSize = ( max( southPadsLength, northPadsLength )
, max( westPadsLength, eastPadsLength ) )
def setupCorona ( self, gapX1, gapY1, gapX2, gapY2 ):
ab = self.chip.getAbutmentBox()
ab.inflate ( -gapX1, -gapY1, -gapX2, -gapY2 )
ab.inflate ( - self.ioPadHeight )
ab.translate( - self.ioPadHeight, - self.ioPadHeight)
ab = self.toSymbolic( ab, Inwards )
self. corona.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
self.icorona.setTransformation(
Transformation( self.toSymbolic( self.ioPadHeight + ab.getXMin(), Superior )
, self.toSymbolic( self.ioPadHeight + ab.getYMin(), Superior )
, Transformation.Orientation.ID ) )
self.icorona.setPlacementStatus( Instance.PlacementStatus.FIXED )
self.setRoutingBb( self.corona.getAbutmentBox() )
def setupCore ( self, gapX1, gapY1, gapX2, gapY2 ):
trace( 550, ',+', '\tChipConf.setupCore()\n' )
ab = self.getInstanceAb( self.icorona )
if ab.isEmpty():
raise ErrorMessage( 1, 'ChipConf.setupCore(): Attempt to setup core *before* corona.' )
return
ab.inflate( -gapX1, -gapY1, -gapX2, -gapY2 )
ab = self.toSymbolic( ab, Inwards )
tracee( 550, '\tself.coreAb:{}\n'.format(self.coreAb) )
if not self.coreAb.isEmpty():
trace( 550, '\tUsing user-defined CORE size:{}\n'.format(self.coreSize) )
ab = self.coreAb
trace( 550, '\tSetting CORE abutment box:{}\n'.format(ab) )
self.core.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
self.icore.setTransformation(
Transformation( ChipConf.toSymbolic(ab.getXMin(),Inferior) - self.icorona.getTransformation().getTx()
, ChipConf.toSymbolic(ab.getYMin(),Inferior) - self.icorona.getTransformation().getTy()
, Transformation.Orientation.ID ) )
self.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
trace( 550, '-' )

View File

@ -0,0 +1,148 @@
# This file is part of the Coriolis Software.
# Copyright (c) Sorbonne Université 2014-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/chip.py" |
# +-----------------------------------------------------------------+
import sys
import traceback
import os.path
import optparse
import math
import cProfile
import pstats
import Cfg
import Hurricane
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, WarningMessage
from helpers.overlay import UpdateSession
import Etesian
import Anabatic
import Katana
import Unicorn
import plugins
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
# --------------------------------------------------------------------
# Class : "chip.Chip"
class Chip ( Block ):
def __init__ ( self, conf ):
super(Chip,self).__init__( conf )
def validate ( self ):
self.conf.validated = True
coreAb = self.conf.core.getAbutmentBox()
if (not coreAb.isEmpty()):
if coreAb.getWidth () <= self.conf.coreAb.getWidth() \
and coreAb.getHeight() <= self.conf.coreAb.getHeight():
self.conf.coreSize = (coreAb.getWidth(), coreAb.getHeight())
else:
raise ErrorMessage( 1, [ 'Core "{}" already have an abutment box, bigger than the requested one:' \
.format(self.conf.core.getName())
, " Cell abutment box: {}".format(coreAb)
, " Maximum abutment box: {}".format(self.conf.coreAb) ] )
self.conf.validated = False
return self.conf.validated
def doChipFloorplan ( self ):
print( ' - Chip has {} north pads.'.format(len(self.conf.chipConf.northPads)) )
print( ' - Chip has {} south pads.'.format(len(self.conf.chipConf.southPads)) )
print( ' - Chip has {} east pads.' .format(len(self.conf.chipConf.eastPads )) )
print( ' - Chip has {} west pads.' .format(len(self.conf.chipConf.westPads )) )
self.conf.computeCoronaBorder()
self.conf.chipValidate()
if not self.conf.validated:
raise ErrorMessage( 1, 'chip.doChipFloorplan(): Chip is not valid, aborting.' )
self.conf.chip.setAbutmentBox( self.conf.chipAb )
trace( 550, '\tSet chip ab:{}\n'.format(self.conf.chip.getAbutmentBox()) )
trace( 550, '\tUsing core ab:{}\n'.format(self.conf.core.getAbutmentBox()) )
self.padsCorona = plugins.alpha.chip.pads.Corona( self )
self.conf.validated = self.padsCorona.validate()
if not self.conf.validated:
return False
self.padsCorona.doLayout()
self.validate()
minHCorona = self.conf.minHCorona
minVCorona = self.conf.minVCorona
innerBb = Box( self.conf.coreAb )
innerBb.inflate( minHCorona, minVCorona )
coronaAb = self.conf.corona.getAbutmentBox()
if innerBb.getWidth() > coronaAb.getWidth():
raise ErrorMessage( 1, 'Core is too wide to fit into the corona, needs {} but only has {}.' \
.format( DbU.getValueString(innerBb .getWidth())
, DbU.getValueString(coronaAb.getWidth()) ) )
if innerBb.getHeight() > coronaAb.getHeight():
raise ErrorMessage( 1, 'Core is too tall to fit into the corona, needs {} but only has {}.' \
.format( DbU.getValueString(innerBb .getHeight())
, DbU.getValueString(coronaAb.getHeight()) ) )
with UpdateSession():
self.conf.core.setAbutmentBox( self.conf.coreAb )
x = (coronaAb.getWidth () - self.conf.coreAb.getWidth ()) // 2
y = (coronaAb.getHeight() - self.conf.coreAb.getHeight()) // 2
trace( 550, '\tCore X, {} '.format(DbU.getValueString(x)) )
x = x - (x % self.conf.sliceHeight)
trace( 550, ' adjusted on {}, {}\n'.format( DbU.getValueString(self.conf.sliceHeight)
, DbU.getValueString(x)) )
y = y - (y % self.conf.sliceHeight)
self.conf.icore.setTransformation ( Transformation(x,y,Transformation.Orientation.ID) )
self.conf.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
self.conf.refresh()
def doConnectCore ( self ):
if self.padsCorona:
self.padsCorona.doPowerLayout()
if self.conf.routingGauge.hasPowerSupply():
power = plugins.alpha.chip.powerplane.Builder( self.conf )
power.connectPower()
#power.connectHTrees( self.hTrees )
power.doLayout()
Breakpoint.stop( 101, 'After Query power.' )
else:
power = plugins.alpha.chip.power.Builder( self.conf )
power.connectPower()
power.connectClocks()
power.doLayout()
self.conf.refresh()
corona = plugins.alpha.chip.corona.Builder( power )
corona.connectPads( self.padsCorona )
corona.connectCore()
corona.doLayout()
self.conf.refresh()
def doPnR ( self ):
super(Chip,self).doPnR()
self.conf.refresh( self.conf.chip )
return self.conf.validated
def save ( self, flags=0 ):
if not self.conf.validated:
raise ErrorMessage( 1, 'chip.save(): Chip is not valid, aborting.' )
views = CRL.Catalog.State.Logical
if self.conf.routingGauge.isSymbolic():
views = views | CRL.Catalog.State.Physical
super(Chip,self).save( flags )