682 lines
33 KiB
Python
682 lines
33 KiB
Python
|
|
# This file is part of the Coriolis Software.
|
|
# Copyright (c) SU 2014-2020, 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" |
|
|
# +-----------------------------------------------------------------+
|
|
|
|
from __future__ import print_function
|
|
import sys
|
|
import os.path
|
|
import Cfg
|
|
from Hurricane import Breakpoint
|
|
from Hurricane import DbU
|
|
from Hurricane import Box
|
|
from Hurricane import Transformation
|
|
from Hurricane import Box
|
|
from Hurricane import Path
|
|
from Hurricane import Layer
|
|
from Hurricane import Occurrence
|
|
from Hurricane import Net
|
|
from Hurricane import 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.utils import classdecorator
|
|
from helpers.overlay import UpdateSession
|
|
from helpers.io import ErrorMessage
|
|
from helpers.io import WarningMessage
|
|
from helpers.io import catch
|
|
from plugins import getParameter
|
|
import plugins.chip
|
|
from plugins.alpha.block.configuration import BlockConf
|
|
|
|
|
|
plugins.alpha.chip.importConstants( globals() )
|
|
|
|
|
|
# -------------------------------------------------------------------
|
|
# 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,long): 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()) )
|
|
print( super(ChipConf,self).__init__ )
|
|
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.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.coronaCk = None
|
|
self.blockageNet = None
|
|
self.padsHavePosition = False
|
|
trace( 550, '-' )
|
|
|
|
@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 ):
|
|
if self.useClockTree:
|
|
trace( 550, '\tcomputeCoronaBorder() useClockTree: {}\n'.format(self.useClockTree) )
|
|
self.railsCount = self.cfg.chip.block.rails.count + 1
|
|
trace( 550, '\tself.railsCount: {}\n'.format(self.railsCount) )
|
|
self.minHCorona = self.railsCount*(self.hRailWidth + self.hRailSpace) + self.hRailSpace + self.sliceHeight
|
|
self.minVCorona = self.railsCount*(self.vRailWidth + self.vRailSpace) + self.vRailSpace + 10*self.sliceStep
|
|
|
|
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() ) )
|
|
trace( 550, '\tCORE ab:{}\n'.format(self.coreAb) )
|
|
coreX = (self.coronaAb.getWidth () - self.coreAb.getWidth ()) / 2
|
|
coreY = (self.coronaAb.getHeight() - self.coreAb.getHeight()) / 2
|
|
coreX = coreX - (coreX % self.sliceStep)
|
|
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():
|
|
oneLambda = DbU.fromLambda( 1.0 )
|
|
if axis % oneLambda:
|
|
axis -= oneLambda / 2
|
|
width -= oneLambda
|
|
trace( 550, '\t[{} {}]\n'.format(iTrackMin, iTrackMax) )
|
|
trace( 550, '\taxis: {}l {}\n'.format(DbU.toLambda(axis ), DbU.getValueString(axis )) )
|
|
trace( 550, '\twidth: {}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: {}l %s\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: {}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: {}l %s\n'.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) )
|
|
trace( 550, '\ttoCoronaPitchInChip(): uCore: {}l %s\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:{} ({}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: {}l or {}\n'.format(DbU.toLambda(coronaY), DbU.getValueString(coronaY)) )
|
|
trace( 550, '\t| width:{}l or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) )
|
|
trace( 550, '\t| dxMin:{}l\n'.format(DbU.toLambda(dxMin)) )
|
|
trace( 550, '\t| dxMax:{}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: {} or {}\n'.format(DbU.toLambda(coronaX), DbU.getValueString(coronaX)) )
|
|
trace( 550, '\t| width:{} 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()
|
|
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 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} or {:>12}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) )
|
|
trace( 550, '\t| Y axis: {:>12} 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 coronaContactArray ( self, chipNet, layer, chipX, chipY, array, flags ):
|
|
trace( 550, ',+', '\tChipConf.coronaContactArray\n' )
|
|
viaPitch = layer.getMinimalSize() + layer.getMinimalSpacing()
|
|
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:{}l yContact:{}l\n'.format(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+ {}\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: {} or {}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) )
|
|
trace( 550, '\t| Y axis: {} 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
|
|
|
|
af = CRL.AllianceFramework.get()
|
|
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 self.coronaCk and self.coronaCk != net:
|
|
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple clock nets "{}" and "{}" at corona level.' \
|
|
.format(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 ):
|
|
print( 'checkChipSize' )
|
|
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 netPads.has_key(padNet):
|
|
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 )
|
|
|
|
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, '-' )
|