1286 lines
51 KiB
Python
1286 lines
51 KiB
Python
# -*- explicit-buffer-name: "Configuration.py<cumulus/src/plugins/chip>" -*-
|
|
#
|
|
# This file is part of the Coriolis Software.
|
|
# Copyright (c) UPMC 2014-2018, 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@asim.lip6.fr |
|
|
# | =============================================================== |
|
|
# | Python : "./plugins/chip/Configuration.py" |
|
|
# +-----------------------------------------------------------------+
|
|
|
|
|
|
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 Occurrence
|
|
from Hurricane import Net
|
|
from Hurricane import RoutingPad
|
|
from Hurricane import Horizontal
|
|
from Hurricane import Vertical
|
|
from Hurricane import Contact
|
|
from Hurricane import Pin
|
|
from Hurricane import Plug
|
|
from Hurricane import Instance
|
|
import CRL
|
|
from CRL import RoutingLayerGauge
|
|
from helpers import trace
|
|
from helpers.io import ErrorMessage
|
|
from helpers.io import WarningMessage
|
|
from plugins import getParameter
|
|
import chip
|
|
|
|
|
|
def breakpoint ( editor, level, message ):
|
|
if editor:
|
|
editor.fit()
|
|
editor.refresh()
|
|
Breakpoint.stop( level, message )
|
|
return
|
|
|
|
|
|
def getPlugByName ( instance, netName ):
|
|
masterCell = instance.getMasterCell()
|
|
masterNet = masterCell.getNet( netName )
|
|
if masterNet:
|
|
return instance.getPlug( masterNet )
|
|
return None
|
|
|
|
|
|
def getPlugByNet ( instance, net ):
|
|
for plug in net.getPlugs():
|
|
if plug.getInstance() == instance:
|
|
return plug
|
|
return None
|
|
|
|
|
|
def getRpBb ( instance, netName ):
|
|
bb = Box()
|
|
for net in instance.getMasterCell().getNets():
|
|
if net.isExternal() and net.getName() == netName:
|
|
for component in net.getExternalComponents():
|
|
if isinstance(component,Vertical):
|
|
bb = component.getBoundingBox()
|
|
instance.getTransformation().applyOn( bb )
|
|
return bb
|
|
|
|
|
|
def showNet ( cell, netName ):
|
|
net = cell.getNet(netName)
|
|
if not net:
|
|
print ErrorMessage( 3, 'Cell %s doesn\'t have net %s' % (cell.getName(),netName) )
|
|
return
|
|
|
|
print 'Components of', netName
|
|
for component in net.getComponents():
|
|
print '| ', component, component.getBoundingBox()
|
|
return
|
|
|
|
|
|
def destroyNetComponents ( net ):
|
|
# 1. We cannot iterate over a Hurricane Collection if we are deleting
|
|
# some of it's elements at the same time (could be improved as it
|
|
# is an intrusive map.
|
|
# 2. Lazy programming: as we don't know the destruction order, some
|
|
# components can be deleted by (previous) others so we can endup
|
|
# on dangling Python proxy which send an exception that we catch.
|
|
# 3. Plugs are not destroyed (they cannot as they are part of the
|
|
# Instance). They stay connected to the net.
|
|
toDestroy = []
|
|
for component in net.getComponents():
|
|
if not isinstance(component,Plug):
|
|
toDestroy.append( component )
|
|
for component in toDestroy:
|
|
try:
|
|
component.destroy()
|
|
except:
|
|
pass
|
|
return
|
|
|
|
|
|
# -------------------------------------------------------------------
|
|
# Class : "IoPadConf".
|
|
|
|
class IoPadConf ( object ):
|
|
# self._datas is a table of 6 elements, the five first coming from
|
|
# the configuration itself. Direction are taken from the core point
|
|
# of view.
|
|
#
|
|
# Meaning of the table element's:
|
|
#
|
|
# +---------+-----------------------------------------------------------+
|
|
# | Index | Type |
|
|
# +=========+===========================================================+
|
|
# | 0 | Pad instance name |
|
|
# +---------+-----------------------------------------------------------+
|
|
# | 1 | Pad connected signal name. |
|
|
# | | The name of the external signal at chip level |
|
|
# +---------+-----------------------------------------------------------+
|
|
# | 2 | The name of the signal going *from* the pad to the core. |
|
|
# | | OUT direction in the core |
|
|
# +---------+-----------------------------------------------------------+
|
|
# | 3 | The name of the signal going *to* the pad from the core. |
|
|
# | | IN direction in core |
|
|
# +---------+-----------------------------------------------------------+
|
|
# | 4 | The enable signal, coming from the core |
|
|
# +---------+-----------------------------------------------------------+
|
|
# | 5 | The IoPad associated object. It is set to None initially |
|
|
# +---------+-----------------------------------------------------------+
|
|
|
|
def __init__ ( self, datas ):
|
|
if not isinstance(datas,list):
|
|
raise ErrorMessage( 1, [ 'IoPadConf.__init__(): The "datas" parameter is not a list.'
|
|
, str(datas) ] )
|
|
if len(datas) < 3 and len(datas) > 5:
|
|
raise ErrorMessage( 1, [ 'IoPadConf.__init__(): The "datas" list must have between 3 to 5 elements.'
|
|
, str(datas) ] )
|
|
|
|
self._datas = datas
|
|
self._datas.append( None )
|
|
return
|
|
|
|
@property
|
|
def padInstanceName ( self ): return self._datas[0]
|
|
|
|
@property
|
|
def padNetName ( self ): return self._datas[1]
|
|
|
|
@property
|
|
def fromCoreNet ( self ): return self._datas[2]
|
|
|
|
@property
|
|
def toCoreNet ( self ): return self._datas[3]
|
|
|
|
@property
|
|
def enableNet ( self ): return self._datas[-2]
|
|
|
|
@property
|
|
def nets ( self ): return self._datas[2:-1]
|
|
|
|
@property
|
|
def udata ( self ): return self._datas[-1]
|
|
|
|
@udata.setter
|
|
def udata ( self, data ): self._datas[-1] = data
|
|
|
|
def isTristate ( self ): return len(self._datas) == 5
|
|
def isBidir ( self ): return len(self._datas) == 6
|
|
|
|
def __repr__ ( self ):
|
|
s = '<IoPadConf %s pad:%s from:%s' % (self.padInstanceName,self.padNetName,self.fromCoreNet)
|
|
if self.isBidir():
|
|
s += ' to:%s en:%s' % (self.toCoreNet,self.enableNet)
|
|
s += '>'
|
|
return s
|
|
|
|
|
|
# -------------------------------------------------------------------
|
|
# Class : "Configuration.GaugeConf".
|
|
|
|
class GaugeConf ( object ):
|
|
|
|
HAccess = 0x0001
|
|
OffsetRight1 = 0x0002
|
|
OffsetTop1 = 0x0004
|
|
OffsetBottom1 = 0x0008
|
|
DeepDepth = 0x0010
|
|
UseContactWidth = 0x0020
|
|
ExpandWidth = 0x0040
|
|
|
|
def __init__ ( self ):
|
|
self.cellGauge = None
|
|
self.ioPadGauge = None
|
|
self.routingGauge = None
|
|
self.topLayerDepth = 0
|
|
self._plugToRp = { }
|
|
self._rpToAccess = { }
|
|
|
|
self._loadRoutingGauge()
|
|
return
|
|
|
|
def getSliceHeight ( self ): return self.cellGauge.getSliceHeight()
|
|
def getSliceStep ( self ): return self.cellGauge.getSliceStep()
|
|
def getIoPadHeight ( self ): return self.ioPadGauge.getSliceHeight()
|
|
def getIoPadStep ( self ): return self.ioPadGauge.getSliceStep()
|
|
def getIoPadPitch ( self ): return self.ioPadGauge.getPitch()
|
|
def getIoPadGauge ( self ): return self.ioPadGauge
|
|
def getHRoutingGauge ( self ): return self.routingGauge.getLayerGauge( self.horizontalDepth )
|
|
def getVRoutingGauge ( self ): return self.routingGauge.getLayerGauge( self.verticalDepth )
|
|
def getPitch ( self, layer ): return self.routingGauge.getPitch( layer )
|
|
|
|
def _loadRoutingGauge ( self ):
|
|
gaugeName = Cfg.getParamString('anabatic.routingGauge').asString()
|
|
self.cellGauge = CRL.AllianceFramework.get().getCellGauge( gaugeName )
|
|
self.routingGauge = CRL.AllianceFramework.get().getRoutingGauge( gaugeName )
|
|
|
|
topLayer = Cfg.getParamString('anabatic.topRoutingLayer').asString()
|
|
|
|
self.topLayerDepth = 0
|
|
for layerGauge in self.routingGauge.getLayerGauges():
|
|
if layerGauge.getLayer().getName() == topLayer:
|
|
self.topLayerDepth = layerGauge.getDepth()
|
|
break
|
|
if not self.topLayerDepth:
|
|
print WarningMessage( 'Gauge top layer not defined, using top of gauge (%d).' \
|
|
% self.routingGauge.getDepth() )
|
|
self.topLayerDepth = self.routingGauge.getDepth() - 1
|
|
|
|
self.horizontalDepth = -1
|
|
self.verticalDepth = -1
|
|
self.horizontalDeepDepth = -1
|
|
self.verticalDeepDepth = -1
|
|
for depth in range(0,self.topLayerDepth+1):
|
|
trace( 550, '\tdepth:%d\n' % depth )
|
|
trace( 550, '\t%s\n' % self.routingGauge.getLayerGauge(depth) )
|
|
|
|
if self.routingGauge.getLayerGauge(depth).getType() == RoutingLayerGauge.PinOnly:
|
|
continue
|
|
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
|
|
if self.horizontalDeepDepth < 0:
|
|
self.horizontalDeepDepth = depth
|
|
self.horizontalDepth = depth
|
|
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Vertical:
|
|
if self.verticalDeepDepth < 0:
|
|
self.verticalDeepDepth = depth
|
|
self.verticalDepth = depth
|
|
return
|
|
|
|
def _loadIoPadGauge ( self, ioPadGaugeName ):
|
|
self.ioPadGauge = CRL.AllianceFramework.get().getCellGauge( ioPadGaugeName )
|
|
if not self.ioPadGauge:
|
|
print WarningMessage( 'IO pad gauge "%s" not found.' % ioPadGaugeName )
|
|
return
|
|
|
|
def isHorizontal ( self, layer ):
|
|
mask = layer.getMask()
|
|
for lg in self.routingGauge.getLayerGauges():
|
|
if lg.getLayer().getMask() == mask:
|
|
if lg.getDirection() == RoutingLayerGauge.Horizontal: return True
|
|
return False
|
|
|
|
print ErrorMessage( 1, 'GaugeConf.isHorizontal(): Layer "%s" is not part of gauge "%s", cannot know preferred direction.' \
|
|
% (layer.getName(), self.routingGauge.getName()) )
|
|
return False
|
|
|
|
def isVertical ( self, layer ): return not self.isHorizontal( layer )
|
|
|
|
def _createContact ( self, net, x, y, flags ):
|
|
if flags & GaugeConf.DeepDepth: depth = self.horizontalDeepDepth
|
|
else: depth = self.horizontalDepth
|
|
|
|
if self.horizontalDepth > self.verticalDepth: depth -= 1
|
|
|
|
trace( 550, '\t%s, horizontalDepth:%d, gaugeDepth:%d\n'
|
|
% (self.routingGauge,self.horizontalDepth,self.routingGauge.getDepth()))
|
|
return Contact.create( net
|
|
, self.routingGauge.getContactLayer(depth)
|
|
, x, y
|
|
, self.routingGauge.getLayerGauge(depth).getViaWidth()
|
|
, self.routingGauge.getLayerGauge(depth).getViaWidth()
|
|
)
|
|
|
|
def _getNearestHorizontalTrack ( self, bb, y, flags ):
|
|
if flags & GaugeConf.DeepDepth: depth = self.horizontalDeepDepth
|
|
else: depth = self.horizontalDepth
|
|
|
|
index = self.routingGauge.getLayerGauge(depth).getTrackIndex( bb.getYMin(), bb.getYMax(), y, RoutingLayerGauge.Nearest )
|
|
return self.routingGauge.getLayerGauge(depth).getTrackPosition( bb.getYMin(), index )
|
|
|
|
def _getNearestVerticalTrack ( self, bb, x, flags ):
|
|
if flags & GaugeConf.DeepDepth: depth = self.verticalDeepDepth
|
|
else: depth = self.verticalDepth
|
|
|
|
index = self.routingGauge.getLayerGauge(depth).getTrackIndex( bb.getXMin(), bb.getXMax(), x, RoutingLayerGauge.Nearest )
|
|
return self.routingGauge.getLayerGauge(depth).getTrackPosition( bb.getXMin(), index )
|
|
|
|
def _createHorizontal ( self, source, target, y, flags ):
|
|
if flags & GaugeConf.DeepDepth: depth = self.horizontalDeepDepth
|
|
else: depth = self.horizontalDepth
|
|
|
|
layer = self.routingGauge.getRoutingLayer(depth)
|
|
|
|
if flags & GaugeConf.UseContactWidth: width = source.getBoundingBox(layer.getBasicLayer()).getHeight()
|
|
else: width = self.routingGauge.getLayerGauge(depth).getWireWidth()
|
|
if flags & GaugeConf.ExpandWidth: width += DbU.fromLambda( 1.0 )
|
|
|
|
segment = Horizontal.create( source, target, layer, y, width )
|
|
trace( 550, segment )
|
|
return segment
|
|
|
|
def _createVertical ( self, source, target, x, flags ):
|
|
if flags & GaugeConf.DeepDepth: depth = self.verticalDeepDepth
|
|
else: depth = self.verticalDepth
|
|
|
|
layer = self.routingGauge.getRoutingLayer(depth)
|
|
|
|
if flags & GaugeConf.UseContactWidth: width = source.getBoundingBox(layer.getBasicLayer()).getWidth()
|
|
else: width = self.routingGauge.getLayerGauge(depth).getWireWidth()
|
|
if flags & GaugeConf.ExpandWidth: width += DbU.fromLambda( 1.0 )
|
|
|
|
segment = Vertical.create( source, target, layer, x, width )
|
|
trace( 550, segment )
|
|
return segment
|
|
|
|
def _rpAccess ( self, rp, flags ):
|
|
trace( 550, ',+', '\t_rpAccess() %s\n' % str(rp) )
|
|
|
|
if self._rpToAccess.has_key(rp):
|
|
trace( 550, '-' )
|
|
return self._rpToAccess[rp]
|
|
|
|
if flags & GaugeConf.DeepDepth:
|
|
hdepth = self.horizontalDeepDepth
|
|
vdepth = self.verticalDeepDepth
|
|
else:
|
|
hdepth = self.horizontalDepth
|
|
vdepth = self.verticalDepth
|
|
|
|
hpitch = self.routingGauge.getLayerGauge(hdepth).getPitch()
|
|
hoffset = self.routingGauge.getLayerGauge(hdepth).getOffset()
|
|
contact1 = Contact.create( rp, self.routingGauge.getContactLayer(0), 0, 0 )
|
|
midSliceY = contact1.getY() - (contact1.getY() % self.cellGauge.getSliceHeight()) \
|
|
+ self.cellGauge.getSliceHeight() / 2
|
|
midTrackY = midSliceY - ((midSliceY - hoffset) % hpitch)
|
|
dy = midSliceY - contact1.getY()
|
|
|
|
if flags & GaugeConf.OffsetBottom1: dy += hpitch
|
|
if flags & GaugeConf.OffsetTop1: dy -= hpitch
|
|
contact1.setDy( dy )
|
|
|
|
trace( 550, contact1 )
|
|
|
|
if flags & GaugeConf.HAccess: stopDepth = hdepth
|
|
else: stopDepth = vdepth
|
|
trace( 550, '\tstopDepth:%d\n' % stopDepth )
|
|
|
|
for depth in range(1,stopDepth):
|
|
xoffset = 0
|
|
if flags & GaugeConf.OffsetRight1 and depth == 1:
|
|
xoffset = self.routingGauge.getLayerGauge(depth+1).getPitch()
|
|
contact2 = Contact.create( rp.getNet()
|
|
, self.routingGauge.getContactLayer(depth)
|
|
, contact1.getX() + xoffset
|
|
, contact1.getY()
|
|
, self.routingGauge.getLayerGauge(depth).getViaWidth()
|
|
, self.routingGauge.getLayerGauge(depth).getViaWidth()
|
|
)
|
|
trace( 550, contact2 )
|
|
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
|
|
segment = Horizontal.create( contact1
|
|
, contact2
|
|
, self.routingGauge.getRoutingLayer(depth)
|
|
, contact1.getY()
|
|
, self.routingGauge.getLayerGauge(depth).getWireWidth()
|
|
)
|
|
trace( 550, segment )
|
|
else:
|
|
segment = Vertical.create( contact1
|
|
, contact2
|
|
, self.routingGauge.getRoutingLayer(depth)
|
|
, contact1.getX()
|
|
, self.routingGauge.getLayerGauge(depth).getWireWidth()
|
|
)
|
|
trace( 550, segment )
|
|
contact1 = contact2
|
|
|
|
self._rpToAccess[rp] = contact1
|
|
|
|
trace( 550, '-' )
|
|
return contact1
|
|
|
|
def _rpByOccurrence ( self, occurrence, net ):
|
|
plug = occurrence.getEntity()
|
|
if self._plugToRp.has_key(plug):
|
|
rp = self._plugToRp[plug]
|
|
else:
|
|
rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea )
|
|
self._plugToRp[plug] = rp
|
|
|
|
return rp
|
|
|
|
def _rpAccessByOccurrence ( self, occurrence, net, flags ):
|
|
plug = occurrence.getEntity()
|
|
if self._plugToRp.has_key(plug):
|
|
rp = self._plugToRp[plug]
|
|
else:
|
|
rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea )
|
|
self._plugToRp[plug] = rp
|
|
|
|
return self._rpAccess( self._rpByOccurrence(occurrence,net), flags )
|
|
|
|
def _rpByPlug ( self, plug, net ):
|
|
if self._plugToRp.has_key(plug):
|
|
rp = self._plugToRp[plug]
|
|
else:
|
|
occurrence = Occurrence( plug, Path(net.getCell(),'') )
|
|
rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea )
|
|
self._plugToRp[plug] = rp
|
|
|
|
return rp
|
|
|
|
def _rpByPlugName ( self, instance, plugName, net ):
|
|
return self._rpByPlug( getPlugByName(instance,plugName), net )
|
|
|
|
def _rpAccessByPlug ( self, plug, net, flags ):
|
|
return self._rpAccess( self._rpByPlug(plug,net), flags )
|
|
|
|
def _rpAccessByPlugName ( self, instance, plugName, net, flags=0 ):
|
|
return self._rpAccess( self._rpByPlugName(instance,plugName,net), flags )
|
|
|
|
def _setStackPosition ( self, topContact, x, y ):
|
|
topContact.setX( x )
|
|
topContact.setY( y )
|
|
|
|
count = 0
|
|
for component in topContact.getSlaveComponents():
|
|
segment = component
|
|
count += 1
|
|
if count > 1:
|
|
raise ErrorMessage( 1, 'GaugeConf::_setStackPosition(): There must be exactly one segment connected to %s, not %d.' % (topContact,count) )
|
|
|
|
if count == 1:
|
|
if isinstance(segment,Horizontal):
|
|
segment.setY( y )
|
|
segment.getOppositeAnchor( topContact ).setY( y )
|
|
elif isinstance(segment,Vertical):
|
|
segment.setX( x )
|
|
segment.getOppositeAnchor( topContact ).setX( x )
|
|
return
|
|
|
|
|
|
# -------------------------------------------------------------------
|
|
# Class : "Configuration.ChipConf".
|
|
|
|
class ChipConf ( object ):
|
|
|
|
@staticmethod
|
|
def _toSymbolic ( u, rounding ):
|
|
oneLambda = DbU.fromLambda( 1.0 )
|
|
remainder = u % oneLambda
|
|
if remainder:
|
|
if rounding == chip.Superior: u = u + (oneLambda - remainder)
|
|
else: u = u - remainder
|
|
return u
|
|
|
|
|
|
@staticmethod
|
|
def toSymbolic ( v, rounding ):
|
|
if isinstance(v,long): return ChipConf._toSymbolic( v, rounding )
|
|
if isinstance(v,Box):
|
|
if rounding & chip.Inwards:
|
|
roundings = [ chip.Superior, chip.Superior, chip.Inferior, chip.Inferior ]
|
|
else:
|
|
roundings = [ chip.Inferior, chip.Inferior, chip.Superior, chip.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
|
|
|
|
|
|
@staticmethod
|
|
def _readChipSize( chipConfigDict ):
|
|
if not chipConfigDict.has_key('chip.size'): return Box()
|
|
chipSize = chipConfigDict['chip.size']
|
|
if not isinstance(chipSize,tuple):
|
|
print ErrorMessage( 1, 'The Chip size parameter is *not* a tuple.' )
|
|
return Box()
|
|
if len(chipSize) != 2:
|
|
print ErrorMessage( 1, 'The Chip size parameter is *not* a tuple of exactly two items.' )
|
|
return Box()
|
|
return Box( 0, 0, chipSize[0], chipSize[1] )
|
|
|
|
|
|
@staticmethod
|
|
def _readCoreSize( chipConfigDict ):
|
|
if not chipConfigDict.has_key('core.size'):
|
|
print ErrorMessage( 1, 'The Core size parameter is missing.' )
|
|
return Box()
|
|
coreSize = chipConfigDict['core.size']
|
|
if not isinstance(coreSize,tuple):
|
|
print ErrorMessage( 1, 'The Core size parameter is *not* a tuple.' )
|
|
return Box()
|
|
if len(coreSize) != 2:
|
|
print ErrorMessage( 1, 'The Core size parameter is *not* a tuple of exactly two items.' )
|
|
return Box()
|
|
return Box( 0, 0, coreSize[0], coreSize[1] )
|
|
|
|
|
|
@staticmethod
|
|
def _readClockTree( chipConfigDict ):
|
|
useClockTree = False
|
|
if chipConfigDict.has_key('chip.clockTree'):
|
|
if chipConfigDict['chip.clockTree']:
|
|
useClockTree = True
|
|
return useClockTree
|
|
|
|
|
|
@staticmethod
|
|
def _readChipName( chipConfigDict ):
|
|
if chipConfigDict.has_key('chip.name'): return chipConfigDict['chip.name']
|
|
return 'chip'
|
|
|
|
|
|
def _loadIoPadGauge ( self, chipConfigDict ):
|
|
if not chipConfigDict.has_key('pads.ioPadGauge'):
|
|
#raise ErrorMessage( 1, 'The IO pad gauge configuration parameter "pads.ioPadGauge" is missing.' )
|
|
return
|
|
self.gaugeConf._loadIoPadGauge( chipConfigDict['pads.ioPadGauge'] )
|
|
return
|
|
|
|
|
|
def _readPads ( self, chipConfigDict, keyword ):
|
|
if not chipConfigDict.has_key(keyword): return []
|
|
padConfList = chipConfigDict[keyword]
|
|
if not isinstance(padConfList,list):
|
|
raise ErrorMessage( 1, 'The "%s" entry is not a list.' )
|
|
return []
|
|
|
|
af = CRL.AllianceFramework.get()
|
|
padList = []
|
|
for i in range(len(padConfList)):
|
|
position = None
|
|
instanceName = None
|
|
if isinstance(padConfList[i],str):
|
|
instanceName = padConfList[i]
|
|
elif isinstance(padConfList[i],list):
|
|
self.padsHavePosition = True
|
|
if isinstance(padConfList[i][0],long) and isinstance(padConfList[i][1],str):
|
|
position = padConfList[i][0]
|
|
instanceName = padConfList[i][1]
|
|
|
|
if not instanceName:
|
|
raise ErrorMessage( 1, 'The element [%d] of list %s is neither a string nor a list "[pos,name]" (skipped).'
|
|
% (i,keyword) )
|
|
continue
|
|
|
|
padList.append( [ position, instanceName ] )
|
|
|
|
return padList
|
|
|
|
|
|
def _readPadInstances ( self, chipConfigDict ):
|
|
if not chipConfigDict.has_key('pads.instances'): return [ ]
|
|
|
|
padInstancesConf = chipConfigDict['pads.instances']
|
|
if not isinstance(padInstancesConf,list):
|
|
raise ErrorMessage( 1, 'The "%s" entry is not a list.' )
|
|
return [ ]
|
|
|
|
padInstances = [ ]
|
|
for entry in padInstancesConf:
|
|
padInstances.append( IoPadConf( entry ) )
|
|
return padInstances
|
|
|
|
|
|
def __init__ ( self, chipConfigDict, cell, viewer=None ):
|
|
trace( 550, '\tONE LAMBDA = %s\n' % DbU.getValueString(DbU.fromLambda(1.0)) )
|
|
|
|
if not isinstance(chipConfigDict,dict):
|
|
raise ErrorMessage( 1, 'The "chip" variable is not a dictionnary.' )
|
|
|
|
self.validated = True
|
|
self.gaugeConf = GaugeConf()
|
|
self.cell = cell
|
|
self.viewer = viewer
|
|
# Block Corona parameters.
|
|
self.railsNb = getParameter('chip','chip.block.rails.count' ).asInt()
|
|
self.hRailWidth = getParameter('chip','chip.block.rails.hWidth' ).asInt()
|
|
self.vRailWidth = getParameter('chip','chip.block.rails.vWidth' ).asInt()
|
|
self.hRailSpace = getParameter('chip','chip.block.rails.hSpacing').asInt()
|
|
self.vRailSpace = getParameter('chip','chip.block.rails.vSpacing').asInt()
|
|
# Global Net names.
|
|
self.blockageName = "blockagenet"
|
|
# Global Nets.
|
|
self.coronaVdd = None
|
|
self.coronaVss = None
|
|
self.coronaCk = None
|
|
self.blockageNet = None
|
|
self.coronas = []
|
|
self.cores = []
|
|
|
|
self._loadIoPadGauge( chipConfigDict )
|
|
|
|
self.padsHavePosition = False
|
|
self.padInstances = self._readPadInstances( chipConfigDict )
|
|
self.southPads = self._readPads( chipConfigDict, 'pads.south' )
|
|
self.northPads = self._readPads( chipConfigDict, 'pads.north' )
|
|
self.eastPads = self._readPads( chipConfigDict, 'pads.east' )
|
|
self.westPads = self._readPads( chipConfigDict, 'pads.west' )
|
|
self.coreSize = ChipConf._readCoreSize ( chipConfigDict )
|
|
self.chipSize = ChipConf._readChipSize ( chipConfigDict )
|
|
self.useClockTree = ChipConf._readClockTree( chipConfigDict )
|
|
self.chipName = ChipConf._readChipName ( chipConfigDict )
|
|
|
|
minHCorona = self.railsNb*(self.hRailWidth + self.hRailSpace) + self.hRailSpace
|
|
minVCorona = self.railsNb*(self.vRailWidth + self.vRailSpace) + self.vRailSpace
|
|
if minHCorona > minVCorona: self.minCorona = minHCorona*2
|
|
else: self.minCorona = minVCorona*2
|
|
|
|
return
|
|
|
|
|
|
def chipValidate ( self ):
|
|
self.checkPads()
|
|
self.checkCorona()
|
|
self.computeChipSize()
|
|
#self.checkChipSize()
|
|
self.findPowerAndClockNets()
|
|
return
|
|
|
|
|
|
@property
|
|
def icorona ( self ): return self.coronas[0]
|
|
|
|
@property
|
|
def corona ( self ): return self.coronas[0].getMasterCell()
|
|
|
|
@property
|
|
def icore ( self ): return self.cores[0]
|
|
|
|
@property
|
|
def core ( self ): return self.cores[0].getMasterCell()
|
|
|
|
@property
|
|
def chip ( self ): return self.cell
|
|
|
|
|
|
def getInstanceAb ( self, instance ):
|
|
ab = instance.getMasterCell().getAbutmentBox()
|
|
instance.getTransformation().applyOn( ab )
|
|
|
|
if instance.getCell() == self.cell: return ab
|
|
|
|
if instance.getCell() != self.corona:
|
|
raise ErrorMessage( 1, 'ChipConf.getInstanceAb(): Instance "%s" neither belong to chip or corona.' % instance.getName() )
|
|
return ab
|
|
|
|
self.icorona.getTransformation().applyOn( ab )
|
|
return ab
|
|
|
|
|
|
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() [%s %s] %s\n' \
|
|
% (DbU.getValueString(uMin), DbU.getValueString(uMax), layer) )
|
|
|
|
ab = self.corona.getAbutmentBox()
|
|
lg = None
|
|
mask = layer.getMask()
|
|
for layerGauge in self.gaugeConf.routingGauge.getLayerGauges():
|
|
if layerGauge.getLayer().getMask() == mask:
|
|
lg = layerGauge
|
|
trace( 550, '\tUsing layer gauge %s\n' % str(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.gaugeConf.routingGauge.isSymbolic():
|
|
oneLambda = DbU.fromLambda( 1.0 )
|
|
if axis % oneLambda:
|
|
axis -= oneLambda / 2
|
|
width -= oneLambda
|
|
|
|
trace( 550, '\t[%i %i]\n' % (iTrackMin, iTrackMax) )
|
|
trace( 550, '\taxis: %sl %s\n' % (DbU.toLambda(axis ), DbU.getValueString(axis )) )
|
|
trace( 550, '\twidth: %sl %s\n' % (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: %sl %s\n' % (DbU.toLambda(uCore), DbU.getValueString(uCore)) )
|
|
|
|
coronaAb = self.getInstanceAb( self.icorona )
|
|
lg = None
|
|
mask = layer.getMask()
|
|
for layerGauge in self.gaugeConf.routingGauge.getLayerGauges():
|
|
if layerGauge.getLayer().getMask() == mask:
|
|
lg = layerGauge
|
|
break
|
|
|
|
if not lg:
|
|
trace( 550, '-' )
|
|
return 0
|
|
|
|
trace( 550, '\t%s\n' % str(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: %sl %s\n' % (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: %sl %s\n' % (DbU.toLambda(uCorona), DbU.getValueString(uCorona)) )
|
|
trace( 550, '\ttoCoronaPitchInChip(): uCore: %sl %s\n' % (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(), chip.Superior )
|
|
dxMax = ChipConf.toSymbolic( chipXMax - coronaAb.getXMin(), chip.Inferior )
|
|
|
|
trace( 550, '\t| chipNet: %s %s\n' % (chipNet, layer) )
|
|
trace( 550, '\t| Real\n' )
|
|
trace( 550, '\t| axis: %10s\n' % DbU.getValueString(coronaY) )
|
|
trace( 550, '\t| width:%10s\n' % DbU.getValueString(width) )
|
|
trace( 550, '\t| dxMin:%10s (%sl)\n' \
|
|
% (DbU.getValueString(chipXMin - coronaAb.getXMin()), DbU.toLambda(chipXMin - coronaAb.getXMin()) ) )
|
|
trace( 550, '\t| dxMax:%10s\n' % 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: %10sl or %10s\n' % (DbU.toLambda(coronaY), DbU.getValueString(coronaY)) )
|
|
trace( 550, '\t| width:%10sl or %10s\n' % (DbU.toLambda(width) , DbU.getValueString(width)) )
|
|
trace( 550, '\t| dxMin:%10sl\n' % DbU.toLambda(dxMin) )
|
|
trace( 550, '\t| dxMax:%10sl\n' % DbU.toLambda(dxMax) )
|
|
|
|
h = Horizontal.create( coronaNet, layer, coronaY, width, dxMin, dxMax )
|
|
|
|
trace( 550, '\t| %s\n' % str(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(), chip.Superior )
|
|
dyMax = ChipConf.toSymbolic( chipYMax - coronaAb.getYMin(), chip.Inferior )
|
|
|
|
trace( 550, '\t| chipNet: %s %s\n' % (chipNet, layer) )
|
|
trace( 550, '\t| Real\n' )
|
|
trace( 550, '\t| axis: %s\n' % DbU.getValueString(coronaX) )
|
|
trace( 550, '\t| width:%s\n' % DbU.getValueString(width) )
|
|
|
|
coronaX, width = self.toRoutingGauge( coronaX - width/2, coronaX + width/2, layer )
|
|
|
|
trace( 550, '\t| On Grid\n' )
|
|
trace( 550, '\t| axis: %s or %s\n' % (DbU.toLambda(coronaX), DbU.getValueString(coronaX)) )
|
|
trace( 550, '\t| width:%s or %s\n' % (DbU.toLambda(width) , DbU.getValueString(width)) )
|
|
|
|
v = Vertical.create( coronaNet, layer, coronaX, width, dyMin, dyMax )
|
|
|
|
trace( 550, '\t| %s\n' % str(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: %s %s\n' % (chipNet, layer) )
|
|
trace( 550, '\t| Real\n' )
|
|
trace( 550, '\t| center: %12s %12s\n' % (DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
|
|
trace( 550, '\t| WxH: %12s %12s\n' % (DbU.getValueString(width ), DbU.getValueString(height )) )
|
|
|
|
topLayer = layer.getTop()
|
|
if self.gaugeConf.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 not (flags & chip.OnHorizontalPitch):
|
|
trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' )
|
|
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), chip.Superior )
|
|
if not (flags & chip.OnVerticalPitch ):
|
|
trace( 550, '\tNot on vertical routing pitch, X on lambda only.\n' )
|
|
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), chip.Superior )
|
|
|
|
trace( 550, '\t| On Grid\n' )
|
|
trace( 550, '\t| X axis: %12s or %12s\n' % (DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) )
|
|
trace( 550, '\t| Y axis: %12s or %12s\n' % (DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) )
|
|
trace( 550, '\t| center: %12s %12s\n' % (DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
|
|
trace( 550, '\t| WxH: %12s %12s\n' % (DbU.getValueString(width ), DbU.getValueString(height )) )
|
|
|
|
c = Contact.create( coronaNet
|
|
, layer
|
|
, coronaX
|
|
, coronaY
|
|
, width
|
|
, height
|
|
)
|
|
|
|
trace( 550, '\t| %s\n' % str(c) )
|
|
trace( 550, '-' )
|
|
return c
|
|
|
|
|
|
def coronaContactArray ( self, chipNet, layer, chipX, chipY, array, flags ):
|
|
trace( 550, ',+', '\tChipConf.coronaContactArray\n' )
|
|
|
|
# Should be read from the symbolic technology rules.
|
|
viaPitch = DbU.fromLambda( 4.0 )
|
|
|
|
coronaAb = self.getInstanceAb( self.icorona )
|
|
coronaNet = self.getCoronaNet( chipNet )
|
|
if not coronaNet: return None
|
|
|
|
trace( 550, '\t| chipNet: %s %s\n' % (chipNet, layer) )
|
|
|
|
coronaX = chipX - coronaAb.getXMin()
|
|
coronaY = chipY - coronaAb.getYMin()
|
|
|
|
topLayer = layer.getTop()
|
|
if self.gaugeConf.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 & chip.OnHorizontalPitch):
|
|
trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' )
|
|
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), chip.Superior )
|
|
if not (flags & chip.OnVerticalPitch ):
|
|
trace( 550, '\tNot on vertical routing pitch, X on lambda only.\n' )
|
|
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), chip.Superior )
|
|
|
|
contacts = []
|
|
xContact = coronaX - viaPitch * (array[0]-1)/2
|
|
yContact = coronaY - viaPitch * (array[1]-1)/2
|
|
contactSize = layer.getMinimalSize()
|
|
|
|
trace( 550, '\txContact:%sl yContact:%sl\n' % (DbU.toLambda(xContact),DbU.toLambda(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+ %s\n' % str(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: %s (%d) %s\n' % (chipNet, count, layer) )
|
|
trace( 550, '\t| Real\n' )
|
|
trace( 550, '\t| center: %s %s\n' % (DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
|
|
trace( 550, '\t| WxH: %s %s\n' % (DbU.getValueString(width ), DbU.getValueString(height )) )
|
|
|
|
topLayer = layer.getTop()
|
|
if self.gaugeConf.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(), chip.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(), chip.Superior )
|
|
|
|
trace( 550, '\t| On Grid\n' )
|
|
trace( 550, '\t| X axis: %s or %s\n' % (DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) )
|
|
trace( 550, '\t| Y axis: %s or %s\n' % (DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) )
|
|
trace( 550, '\t| center: %s %s\n' % (DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
|
|
trace( 550, '\t| WxH: %s %s\n' % (DbU.getValueString(width ), DbU.getValueString(height )) )
|
|
|
|
c = Pin.create( coronaNet
|
|
, '%s.%d' % (coronaNet.getName(),count)
|
|
, direction
|
|
, Pin.PlacementStatus.FIXED
|
|
, layer
|
|
, coronaX
|
|
, coronaY
|
|
, width
|
|
, height
|
|
)
|
|
|
|
trace( 550, '\t| %s\n' % str(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.gaugeConf.getIoPadHeight()):
|
|
raise ErrorMessage( 1, 'The pad [%d] %s (%s) on %s side is not an instance of a pad cell.'
|
|
% (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 [%d] (%s) of list %s do not exists in netlist (skipped).'
|
|
% (i,padList[i][1],side) )
|
|
return
|
|
|
|
|
|
af = CRL.AllianceFramework.get()
|
|
cellPads = []
|
|
for instance in self.cell.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.gaugeConf.getIoPadHeight()):
|
|
raise ErrorMessage( 1, 'Pad "%s" is not on any side (N/S/E/W).' % 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 "%s" have more than one corona:' % self.cell.getName() ]
|
|
for i in range(len(self.coronas)):
|
|
message.append( '%4d: %s' % (i,self.coronas[i].getName()) )
|
|
raise ErrorMessage( 1, message )
|
|
self.validated = False
|
|
|
|
if len(self.coronas) < 1:
|
|
raise ErrorMessage( 1, 'Chip "%s" doesn\'t seems to have a corona.' % self.cell.getName() )
|
|
self.validated = False
|
|
else:
|
|
for instance in self.corona.getInstances(): self.cores.append( instance )
|
|
|
|
if len(self.cores) > 1:
|
|
message = [ 'Chip "%s" have more than one core:' % self.cell.getName() ]
|
|
for i in range(len(self.cores)):
|
|
message.append( '%4d: %s' % (i,self.cores[i].getName()) )
|
|
raise ErrorMessage( 1, message )
|
|
self.validated = False
|
|
|
|
if len(self.cores) < 1:
|
|
raise ErrorMessage( 1, 'Chip "%s" doesn\'t seems to have a core.' % self.cell.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 "%s" at corona level.'
|
|
% masterNet.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 "%s" and "%s" at corona level.'
|
|
% (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 "%s" and "%s" at corona level.'
|
|
% (self.coronaVdd.getName(), net.getName()) )
|
|
self._validated = False
|
|
continue
|
|
else:
|
|
self.coronaVdd = net
|
|
|
|
if netType == Net.Type.CLOCK:
|
|
if self.coronaCk and self.coronaCk != net:
|
|
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple clock nets "%s" and "%s" at corona level.'
|
|
% (self.coronaCk.getName(), net.getName()) )
|
|
self._validated = False
|
|
continue
|
|
else:
|
|
self.coronaCk = net
|
|
|
|
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._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.cell.getNet( coronaNet.getName() )
|
|
|
|
if padNet:
|
|
if not netPads.has_key(padNet):
|
|
trace( 550, '\t%20s <-> %-20s\n' % (padNet.getName(),coronaNet.getName()) )
|
|
netPads[ padNet ] = coronaNet
|
|
else:
|
|
raise ErrorMessage( 1, 'ChipConf.checkCorona(): Corona nets "%s" and "%s" connected to the same pad net "%s".' \
|
|
% (coronaNet.getName(),netPads[padNet].getName(),padNet.getName()) )
|
|
self._validated = False
|
|
|
|
trace( 550, '-' )
|
|
return
|
|
|
|
|
|
def computeChipSize ( self ):
|
|
|
|
def getSideLength ( pads ):
|
|
sideLength = self.gaugeConf.getIoPadHeight() * 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 = Box( 0
|
|
, 0
|
|
, max( southPadsLength, northPadsLength )
|
|
, max( westPadsLength, eastPadsLength )
|
|
)
|
|
return
|
|
|
|
|
|
def setupCorona ( self, gapX1, gapY1, gapX2, gapY2 ):
|
|
ab = self.cell.getAbutmentBox()
|
|
ab.inflate ( -gapX1, -gapY1, -gapX2, -gapY2 )
|
|
ab.inflate ( - self.getIoPadHeight() )
|
|
ab.translate( - self.getIoPadHeight(), - self.getIoPadHeight())
|
|
ab = self.toSymbolic( ab, chip.Inwards )
|
|
|
|
self. corona.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
|
|
self.icorona.setTransformation(
|
|
Transformation( self.toSymbolic( self.getIoPadHeight() + ab.getXMin(), chip.Superior )
|
|
, self.toSymbolic( self.getIoPadHeight() + ab.getYMin(), chip.Superior )
|
|
, Transformation.Orientation.ID ) )
|
|
self.icorona.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
|
return
|
|
|
|
|
|
def setupCore ( self, gapX1, gapY1, gapX2, gapY2 ):
|
|
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, chip.Inwards )
|
|
|
|
trace( 550, '\tChipConf.setupCore(): Abutment box:%s\n' % str(ab) )
|
|
|
|
self.core.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
|
|
self.icore.setTransformation(
|
|
Transformation( ChipConf.toSymbolic(ab.getXMin(),chip.Inferior) - self.icorona.getTransformation().getTx()
|
|
, ChipConf.toSymbolic(ab.getYMin(),chip.Inferior) - self.icorona.getTransformation().getTy()
|
|
, Transformation.Orientation.ID ) )
|
|
self.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
|
return
|
|
|
|
|
|
@property
|
|
def cellGauge ( self ): return self.gaugeConf.cellGauge
|
|
|
|
@property
|
|
def routingGauge ( self ): return self.gaugeConf.routingGauge
|
|
|
|
@property
|
|
def verticalDepth ( self ): return self.gaugeConf.verticalDepth
|
|
|
|
@property
|
|
def horizontalDepth ( self ): return self.gaugeConf.horizontalDepth
|
|
|
|
def getSliceHeight ( self ): return self.gaugeConf.getSliceHeight()
|
|
def getSliceStep ( self ): return self.gaugeConf.getSliceStep()
|
|
def getIoPadHeight ( self ): return self.gaugeConf.getIoPadHeight()
|
|
def getIoPadStep ( self ): return self.gaugeConf.getIoPadStep()
|
|
def getIoPadPitch ( self ): return self.gaugeConf.getIoPadPitch()
|
|
def getIoPadGauge ( self ): return self.gaugeConf.getIoPadGauge()
|
|
def getHRoutingGauge ( self ): return self.gaugeConf.getHRoutingGauge()
|
|
def getVRoutingGauge ( self ): return self.gaugeConf.getVRoutingGauge()
|
|
|
|
def rpByOccurrence ( self, occurrence, net ):
|
|
return self.gaugeConf._rpByOccurrence ( occurrence, net )
|
|
|
|
def rpByPlugName ( self, instance, plugName, net ):
|
|
return self.gaugeConf._rpByPlugName ( instance, plugName, net )
|
|
|
|
def rpAccess ( self, rp, flags=0 ):
|
|
return self.gaugeConf._rpAccess( rp, flags )
|
|
|
|
def rpAccessByOccurrence ( self, occurrence, net, flags=0 ):
|
|
return self.gaugeConf._rpAccessByOccurrence ( occurrence, net, flags )
|
|
|
|
def rpAccessByPlugName ( self, instance, plugName, net, flags=0 ):
|
|
return self.gaugeConf._rpAccessByPlugName( instance, plugName, net, flags )
|
|
|
|
def createContact ( self, net, x, y, flags=0 ):
|
|
return self.gaugeConf._createContact( net, x, y, flags )
|
|
|
|
def createHorizontal ( self, source, target, y, flags=0 ):
|
|
return self.gaugeConf._createHorizontal( source, target, y, flags )
|
|
|
|
def createVertical ( self, source, target, x, flags=0 ):
|
|
return self.gaugeConf._createVertical( source, target, x, flags )
|
|
|
|
def getNearestHorizontalTrack ( self, bb, y, flags ):
|
|
return self.gaugeConf._getNearestHorizontalTrack ( bb, y, flags )
|
|
|
|
def getNearestVerticalTrack ( self, bb, x, flags ):
|
|
return self.gaugeConf._getNearestVerticalTrack( bb, x, flags )
|
|
|
|
def setStackPosition ( self, topContact, x, y ):
|
|
self.gaugeConf._setStackPosition( topContact, x, y )
|
|
|
|
|
|
def loadConfiguration ( cell, viewer=None ):
|
|
sys.path.append( os.getcwd() )
|
|
|
|
#confFile = cell.getName()+'_ioring'
|
|
confFile = 'ioring'
|
|
if not os.path.isfile(confFile+'.py'):
|
|
raise ErrorMessage( 1, 'ChipPlugin configuration file <%s.py> is missing.' % confFile )
|
|
|
|
confModule = __import__( confFile, globals(), locals(), confFile )
|
|
|
|
if not confModule.__dict__.has_key('chip'):
|
|
ErrorMessage( 1, 'Module <%s> do not provides the chip variable, skipped.' \
|
|
% confFile )
|
|
|
|
return ChipConf( confModule.__dict__['chip'], cell, viewer )
|