coriolis/cumulus/src/plugins/chip/Configuration.py

684 lines
25 KiB
Python

# -*- explicit-buffer-name: "Configuration.py<cumulus/src/plugins/chip>" -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) UPMC 2014-2014, 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 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 Contact
from Hurricane import Horizontal
from Hurricane import Vertical
from Hurricane import Plug
from Hurricane import Instance
import CRL
from CRL import RoutingLayerGauge
from helpers import trace
from helpers import ErrorMessage
from helpers import WarningMessage
from plugins import getParameter
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 : "Configuration.GaugeConf".
class GaugeConf ( object ):
HAccess = 0x0001
OffsetRight1 = 0x0002
OffsetTop1 = 0x0004
OffsetBottom1 = 0x0008
def __init__ ( self ):
self._cellGauge = None
self._routingGauge = None
self._topLayerDepth = 0
self._plugToRp = { }
self._loadRoutingGauge()
return
def getSliceHeight ( self ): return self._cellGauge.getSliceHeight()
def getSliceStep ( self ): return self._cellGauge.getSliceStep()
def _loadRoutingGauge ( self ):
self._cellGauge = CRL.AllianceFramework.get().getCellGauge()
self._routingGauge = CRL.AllianceFramework.get().getRoutingGauge()
topLayer = Cfg.getParamString('katabatic.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()
self._horizontalDepth = 0
self._verticalDepth = 0
for depth in range(0,self._topLayerDepth+1):
if self._routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
self._horizontalDepth = depth
if self._routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Vertical:
self._verticalDepth = depth
return
def _createContact ( self, net, x, y ):
return Contact.create( net
, self._routingGauge.getContactLayer(self._horizontalDepth)
, x, y
, self._routingGauge.getLayerGauge(self._horizontalDepth).getViaWidth()
, self._routingGauge.getLayerGauge(self._horizontalDepth).getViaWidth()
)
def _createHorizontal ( self, source, target, y ):
segment = Horizontal.create( source
, target
, self._routingGauge.getRoutingLayer(self._horizontalDepth)
, y
, self._routingGauge.getLayerGauge(self._horizontalDepth).getWireWidth()
)
trace( 550, segment )
return segment
def _createVertical ( self, source, target, x ):
segment = Vertical.create( source
, target
, self._routingGauge.getRoutingLayer(self._verticalDepth)
, x
, self._routingGauge.getLayerGauge(self._verticalDepth).getWireWidth()
)
trace( 550, segment )
return segment
def _rpAccess ( self, rp, flags ):
trace( 550, ',+', '\t_rpAccess() %s\n' % str(rp) )
hpitch = self._routingGauge.getLayerGauge(self._horizontalDepth).getPitch()
hoffset = self._routingGauge.getLayerGauge(self._horizontalDepth).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 = self._horizontalDepth
else: stopDepth = self._verticalDepth
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
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 )
# -------------------------------------------------------------------
# Class : "Configuration.GaugeConfWrapper".
class GaugeConfWrapper ( object ):
def __init__ ( self, conf ):
#print id(conf), type(conf)
#if not isinstance(conf,GaugeConf):
# raise ErrorMessage( 1, 'Attempt to create a GaugeConfWrapper() from non-GaugeConf object.' )
self._gaugeConf = conf
return
@property
def gaugeConf ( self ): return self._gaugeConf
@property
def routingGauge ( self ): return self._gaugeConf._routingGauge
@property
def topLayerDepth ( self ): return self._gaugeConf._topLayerDepth
@property
def horizontalDepth ( self ): return self._gaugeConf._horizontalDepth
@property
def verticalDepth ( self ): return self._gaugeConf._verticalDepth
def loadRoutingGauge ( self ): self._gaugeConf._loadRoutingGauge()
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 ):
return self._gaugeConf._createContact( net, x, y )
def createHorizontal ( self, source, target, y ):
return self._gaugeConf._createHorizontal( source, target, y )
def createVertical ( self, source, target, x ):
return self._gaugeConf._createVertical( source, target, x )
# -------------------------------------------------------------------
# Class : "Configuration.ChipConf".
class ChipConf ( object ):
@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, DbU.fromLambda(chipSize[0]), DbU.fromLambda(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, DbU.fromLambda(coreSize[0]), DbU.fromLambda(coreSize[1]) )
@staticmethod
def _readClockTree( chipConfigDict ):
useClockTree = False
if chipConfigDict.has_key('chip.clockTree'):
if chipConfigDict['chip.clockTree']:
useClockTree = True
return useClockTree
def _readPads ( self, chipConfigDict, keyword ):
if not chipConfigDict.has_key(keyword): return []
padNameList = chipConfigDict[keyword]
if not isinstance(padNameList,list):
print ErrorMessage( 1, 'The "%s" entry is not a list.' )
return []
af = CRL.AllianceFramework.get()
padList = []
for i in range(len(padNameList)):
if not isinstance(padNameList[i],str):
print ErrorMessage( 1, 'The element [%d] of list %s is *not* a string (skipped).'
% (i,keyword) )
continue
instance = self._cell.getInstance( padNameList[i] )
if not instance:
print ErrorMessage( 1, 'The pad [%d] (%s) of list %s do not exists in netlist (skipped).'
% (i,padNameList[i],keyword) )
continue
if (not af.isPad(instance.getMasterCell().getName())):
print ErrorMessage( 1, 'The pad [%d] (%s) of list %s is not an instance of a pad cell (skipped).'
% (i,padNameList[i],keyword) )
continue
padList.append( instance )
if not self._clockPad and instance.getMasterCell().getName() == self._pckName:
self._clockPad = instance
if not self._powerPad and instance.getMasterCell().getName() == self._pvddickName:
self._powerPad = instance
return padList
def _guessGlobalNet ( self, name, net ):
if name == self._vddeName: self._vdde = net
if name == self._vddiName: self._vddi = net
if name == self._vsseName: self._vsse = net
if name == self._vssiName: self._vssi = net
if name == self._ckiName: self._cki = net
if name == self._ckoName: self._cko = net
if name == self._ckName: self._ck = net
return
def __init__ ( self, chipConfigDict, cell ):
if not isinstance(chipConfigDict,dict):
raise ErrorMessage( 1, 'The "chip" variable is not a dictionnary.' )
self._validated = True
self._cell = cell
# Block Corona parameters.
self._railsNb = getParameter('chip','chip.block.rails.count').asInt()
self._hRailWidth = DbU.fromLambda( getParameter('chip','chip.block.rails.hWidth' ).asInt() )
self._vRailWidth = DbU.fromLambda( getParameter('chip','chip.block.rails.vWidth' ).asInt() )
self._hRailSpace = DbU.fromLambda( getParameter('chip','chip.block.rails.hSpacing').asInt() )
self._vRailSpace = DbU.fromLambda( getParameter('chip','chip.block.rails.vSpacing').asInt() )
# Global Pad names.
self._pckName = getParameter('chip', 'chip.pad.pck' ).asString()
self._pvddickName = getParameter('chip', 'chip.pad.pvddick').asString()
self._pvssickName = getParameter('chip', 'chip.pad.pvssick').asString()
self._pvddeckName = getParameter('chip', 'chip.pad.pvddeck').asString()
self._pvsseckName = getParameter('chip', 'chip.pad.pvsseck').asString()
# Global Net names.
self._vddeName = "vdde"
self._vddiName = "vddi"
self._vsseName = "vsse"
self._vssiName = "vssi"
self._ckiName = "ck"
self._ckoName = "cko"
self._ckName = "pad"
# Global Nets.
self._vdde = None
self._vddi = None
self._vsse = None
self._vssi = None
self._cki = None
self._cko = None
self._ck = None
self._clockPad = None
self._powerPad = None
self._cores = []
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._padWidth = 0
self._padHeight = 0
self._useClockTree = ChipConf._readClockTree( 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
self.checkPads()
self.computeChipSize()
self.findPowerAndClockNets()
return
def checkPads ( self ):
af = CRL.AllianceFramework.get()
cellPads = []
for instance in self._cell.getInstances():
if (af.isPad(instance.getMasterCell().getName())):
cellPads.append( instance )
else:
self._cores.append( instance )
for pad in cellPads:
if pad in self._southPads: continue
if pad in self._northPads: continue
if pad in self._eastPads: continue
if pad in self._westPads: continue
print ErrorMessage( 1, 'Pad "%s" is not on any side (N/S/E/W).' % pad.getName() )
self._validated = False
if len(self._cores) < 1:
print ErrorMessage( 1, 'Chip "%s" doesn\'t seems to have a core.' % self._cell.getName() )
self._validated = False
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()) )
print ErrorMessage( 1, message )
self._validated = False
return
def findPowerAndClockNets ( self ):
if self._powerPad:
for plug in self._powerPad.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._cell.getNet( masterNet.getName() )
if not net:
print ErrorMessage( 1, 'Missing global net <%s> at chip level.' % masterNet.getName() )
self._validated = False
continue
self._guessGlobalNet( masterNet.getName(), net )
if self._clockPad:
for plug in self._powerPad.getPlugs():
masterNet = plug.getMasterNet()
netType = masterNet.getType()
net = plug.getNet()
if not net:
net = self._cell.getNet( masterNet.getName() )
if not net:
print ErrorMessage( 1, 'Missing global net <%s> at chip level.' % masterNet.getName() )
self._validated = False
continue
if masterNet.getName() == self._ckName:
self._guessGlobalNet( masterNet.getName(), net )
return
def computeChipSize ( self ):
if not self._clockPad:
print ErrorMessage( 1, 'There must be at least one pad of model "%s" to be used as reference.' \
% self._pckName )
self._validated = False
return False
self._padHeight = self._clockPad.getMasterCell().getAbutmentBox().getHeight()
self._padWidth = self._clockPad.getMasterCell().getAbutmentBox().getWidth()
if not self._chipSize.isEmpty(): return
horizontalPads = max( len(self._southPads), len(self._northPads) )
verticalPads = max( len(self._eastPads ), len(self._westPads ) )
self._chipSize = Box( 0
, 0
, self._padWidth * horizontalPads + 2*self._padHeight
, self._padWidth * verticalPads + 2*self._padHeight
)
return
def getSpecialNetRoot ( self, net ):
if net.getName() == self._vddeName: return self._vdde
if net.getName() == self._vsseName: return self._vsse
if net.getType() == Net.Type.POWER: return self._vddi
if net.getType() == Net.Type.GROUND: return self._vssi
return None
# -------------------------------------------------------------------
# Class : "Configuration.ChipConfWrapper".
class ChipConfWrapper ( GaugeConfWrapper ):
def __init__ ( self, gaugeConf, chipConf ):
GaugeConfWrapper.__init__( self, gaugeConf )
#if not isinstance(chipConf,ChipConf):
# raise ErrorMessage( 1, 'Attempt to create a ChipConfWrapper() from non-ChipConf object.' )
self._chipConf = chipConf
return
def isValid ( self ): return self._chipConf._validated
@property
def chipConf ( self ): return self._chipConf
def getSliceHeight ( self ): return self._gaugeConf.getSliceHeight()
def getSliceStep ( self ): return self._gaugeConf.getSliceStep()
@property
def cell ( self ): return self._chipConf._cell
# Global Pad names.
@property
def pvddeckName ( self ): return self._chipConf._pvddeckName
@property
def pvsseckName ( self ): return self._chipConf._pvsseckName
@property
def pvddickName ( self ): return self._chipConf._pvddickName
@property
def pvssickName ( self ): return self._chipConf._pvssickName
@property
def pckName ( self ): return self._chipConf._pckName
# Global Net names.
@property
def vddeName ( self ): return self._chipConf._vddeName
@property
def vsseName ( self ): return self._chipConf._vsseName
@property
def vddiName ( self ): return self._chipConf._vddiName
@property
def vssiName ( self ): return self._chipConf._vssiName
@property
def ckiName ( self ): return self._chipConf._ckiName
@property
def ckoName ( self ): return self._chipConf._ckoName
@property
def ckName ( self ): return self._chipConf._ckName
# Global Nets.
@property
def vdde ( self ): return self._chipConf._vdde
@property
def vsse ( self ): return self._chipConf._vsse
@property
def vddi ( self ): return self._chipConf._vddi
@property
def vssi ( self ): return self._chipConf._vssi
@property
def cki ( self ): return self._chipConf._cki
@property
def cko ( self ): return self._chipConf._cko
@property
def ck ( self ): return self._chipConf._ck
# Various.
@property
def clockPad ( self ): return self._chipConf._clockPad
@property
def powerPad ( self ): return self._chipConf._powerPad
@property
def cores ( self ): return self._chipConf._cores
@property
def southPads ( self ): return self._chipConf._southPads
@property
def northPads ( self ): return self._chipConf._northPads
@property
def eastPads ( self ): return self._chipConf._eastPads
@property
def westPads ( self ): return self._chipConf._westPads
@property
def coreSize ( self ): return self._chipConf._coreSize
@coreSize.setter
def coreSize ( self, ab ): self._chipConf._coreSize = ab
@property
def chipSize ( self ): return self._chipConf._chipSize
@property
def minCorona ( self ): return self._chipConf._minCorona
@property
def padWidth ( self ): return self._chipConf._padWidth
@property
def padHeight ( self ): return self._chipConf._padHeight
@property
def useClockTree ( self ): return self._chipConf._useClockTree
def loadConfiguration ( cell ):
sys.path.append( os.getcwd() )
confFile = cell.getName()+'_chip'
confModule = __import__( confFile, globals(), locals(), confFile )
if not confModule.__dict__.has_key('chip'):
raise WarningMessage( 'Module <%s> do not provides the chip variable, skipped.' \
% confFile )
return ChipConfWrapper( GaugeConf()
, ChipConf ( confModule.__dict__['chip'], cell ) )