Fix some typos in documentation and a number of whitespace issues

This commit is contained in:
Rob Taylor 2023-11-17 19:33:26 +00:00 committed by Rob Taylor
parent 205a21aaf0
commit 3163b5ee45
4 changed files with 480 additions and 480 deletions

View File

@ -1,6 +1,6 @@
#!/usr/bin/python
import sys
import sys
from math import sqrt, ceil
import numpy
from ..Hurricane import *
@ -13,22 +13,22 @@ from . import getRules
def toPhY ( l ): return DbU.toPhysical ( l, DbU.UnitPowerMicro )
## Draws the layout of a compact capacitor or a matrix of adjacent identical capacitors. The matrix can be composed of one type of capacitors, either Poly-Poly or Metal-Metal in 350 nm AMS CMOS technology.
# When matching mode is off, every adjacent plates of any consecutive elementary capacitors are connected to each other using vertical routing layers.
## Draws the layout of a compact capacitor or a matrix of adjacent identical capacitors. The matrix can be composed of one type of capacitors, either Poly-Poly or Metal-Metal in 350 nm AMS CMOS technology.
# When matching mode is off, every adjacent plates of any consecutive elementary capacitors are connected to each other using vertical routing layers.
# Otherwise, when matching mode is on, any of elementary capacitors can belong to, \f$ C_1 \f$ or \f$ C_2 \f$ according to the entered matching scheme. Thus, routing is not done in this class.
# In both modes, the complete routing process is done using the \c RoutCapacitor class.
class CapacitorStack( CapacitorUnit ):
rules = getRules()
## This is the class constructor. Basically, the class there are three categories of attributes. There are the ones related to the capacitor caracteristics, its type, dimensions. Also, there are attributes to parametrize the class into matching mode or not and there are other attributes realted to the layout varibales. The class has defaut input values, thus, in this constructor, there are two "sub-constructors" according to the entered input parameters. The class attributes are :
#
# \param device The Hurricane AMS device into which the layout is drawn.
# \param device The Hurricane AMS device into which the layout is drawn.
# \param capacitance The value of the capacitor, expressed in femto Farad (fF).
# \param capacitorType Can be MIM or PIP type capacitor.
# \param abutmentPosition Refers to the abscissa (XMin) of the bottom left corner of the abutment Box.
# \param abutmentPosition Refers to the abscissa (XMin) of the bottom left corner of the abutment Box.
# \param abutmentBoxYMin Refers to the ordinate (YMin) of the bottom left corner of the abutment Box.
#
# Except the two last arguments, all the parameters are common with the CapacitorUnit class because the \c CapacitorStack constructor calls the mother class constructor to create either a compact capacitor of \c capacitance value or \c rowNumber* \c columnNumber unity capacitors.
@ -49,7 +49,7 @@ class CapacitorStack( CapacitorUnit ):
, dummyElement = False ):
self.device = device
self.capacitorType = capacitorType
self.matrixDim = { "columns" : matrixDim[1], "rows" : matrixDim[0] }
self.matrixDim = { "columns" : matrixDim[1], "rows" : matrixDim[0] }
self.unitCapDim = self.__computeCapDim__( unitCap, capacitorType )
self.doMatrix = False
@ -58,7 +58,7 @@ class CapacitorStack( CapacitorUnit ):
self.nets = nets
self.matchingMode = matchingMode
self.dummyRing = dummyRing
self.dummyElement = dummyElement
self.dummyElement = dummyElement
self.capacitorsNumber = len(capacitance)
@ -68,8 +68,8 @@ class CapacitorStack( CapacitorUnit ):
self.vRoutingTrack_width = 0
if self.__areInputDataOK__(capacitance):
if not self.matchingMode:
self.compactCapDim = self.__computeCapDim__( capacitance[0] , capacitorType )
if not self.matchingMode:
self.compactCapDim = self.__computeCapDim__( capacitance[0] , capacitorType )
if unitCap == 0:
self.__initGivenZeroUnitCap__( capacitance[0] )
@ -108,11 +108,11 @@ class CapacitorStack( CapacitorUnit ):
if self.capacitorType == 'MIMCap':
self.minWidth_hRoutingLayer_topPlate_cut = CapacitorStack.rules.minWidth_cut2
self.minEnclosure_hRoutingLayer_topPlate_cut = CapacitorStack.rules.minEnclosure_metal2_cut2
elif self.capacitorType == 'PIPCap':
elif self.capacitorType == 'PIPCap':
self.minWidth_hRoutingLayer_topPlate_cut = CapacitorStack.rules.minWidth_cut1
self.minEnclosure_hRoutingLayer_topPlate_cut = CapacitorStack.rules.minEnclosure_metal2_cut1
return
return
@ -120,9 +120,9 @@ class CapacitorStack( CapacitorUnit ):
def __initMatchingMode__( self ) :
self.vRoutingTrack_width = max( self.minWidth_vRoutingTrack, 2*self.minEnclosure_vRoutingTrackCut + self.minWidth_vRoutingTrackCut,self.minWidth_hRoutingLayer_topPlate_cut + 2*self.minEnclosure_hRoutingLayer_topPlate_cut )
if ( self.capacitorsNumber % 2 == 0 ) : [factor1 , factor2 ] = [ self.capacitorsNumber , (self.capacitorsNumber +1) ]
if ( self.capacitorsNumber % 2 != 0 ) : [factor1 , factor2 ] = [ self.capacitorsNumber +1 , self.capacitorsNumber +2 ]
self.abutmentBox_spacing = factor1*self.vRoutingTrack_width + factor2*self.minSpacing_vRoutingTrack
if ( self.capacitorsNumber % 2 == 0 ) : [factor1 , factor2 ] = [ self.capacitorsNumber , (self.capacitorsNumber +1) ]
if ( self.capacitorsNumber % 2 != 0 ) : [factor1 , factor2 ] = [ self.capacitorsNumber +1 , self.capacitorsNumber +2 ]
self.abutmentBox_spacing = factor1*self.vRoutingTrack_width + factor2*self.minSpacing_vRoutingTrack
return
@ -154,7 +154,7 @@ class CapacitorStack( CapacitorUnit ):
self.unitCapacitance = unitCapacitance
self.capacitance = capacitance
self.doMatrix = True
return
@ -162,10 +162,10 @@ class CapacitorStack( CapacitorUnit ):
def __initGivenNonZeroUnitCap__( self, capacitance, unitCap ):
if ( self.matrixDim["columns"]>1 or self.matrixDim["rows"]>1 ) : # jai donne les dim de la matrice
if self.matrixDim.values()[0]*self.matrixDim.values()[1] == capacitance/unitCap :
if self.matrixDim.values()[0]*self.matrixDim.values()[1] == capacitance/unitCap :
self.__initMatrixMode__( capacitance, unitCap )
else : raise Error( 1, '__init__() : Matrix dimensions and unit capacitance are not compatible : "capacitance %d divides by unit capacitance %s != columns %d * rows %d ".' %( capacitance, unitCap, self.matrixDim["columns"], self.matrixDim["rows"] ) )
else : raise Error( 1, '__init__() : Matrix dimensions and unit capacitance are not compatible : "capacitance %d divides by unit capacitance %s != columns %d * rows %d ".' %( capacitance, unitCap, self.matrixDim["columns"], self.matrixDim["rows"] ) )
else : # self.matrixDim.values() == [1,1] : # jai donne ou jai ps donne
@ -176,7 +176,7 @@ class CapacitorStack( CapacitorUnit ):
self.matrixDim = {"columns" : int(sqrt(capacitance/unitCap)), "rows" : int(sqrt(capacitance/unitCap)) } # ici mettre toutes les combi si matching mode = [] sinon utiliser la meme combi que matching scheme
else : raise Error( 1,'__initGivenNonZeroUnitCap__ : capacitance must be multiple of unit capacitance' )
return
@ -186,14 +186,14 @@ class CapacitorStack( CapacitorUnit ):
if self.matrixDim.values() == [1,1] or (self.matrixDim["columns"] == len(self.matchingScheme[0]) and self.matrixDim["rows"] == len(self.matchingScheme)) :
unitCapList = self.computeUnitCap(capacitance)
unitCapList = self.computeUnitCap(capacitance)
if len( list(numpy.unique(unitCapList)) ) == 1 :
if len( list(numpy.unique(unitCapList)) ) == 1 :
unitCapDim = self.__computeCapDim__( unitCapList[0], self.capacitorType )
if CapacitorUnit.__isCapacitorUnitOK__(self, unitCapDim) == True :
if CapacitorUnit.__isCapacitorUnitOK__(self, unitCapDim) == True :
self.unitCapDim = unitCapDim
self.__initMatrixMode__( capacitance, unitCapList[0] )
if self.matrixDim.values() == [1,1] : self.matrixDim = {"columns" : len(self.matchingScheme[0]) , "rows" : len(self.matchingScheme) }
@ -211,10 +211,10 @@ class CapacitorStack( CapacitorUnit ):
def __initGivenNonZeroUnitCapInMatchingMode__( self, capacitance, unitCap ):
if CapacitorUnit.__isCapacitorUnitOK__(self, self.unitCapDim) == True :
if CapacitorUnit.__isCapacitorUnitOK__(self, self.unitCapDim) == True :
if self.matrixDim.values() == [1,1] or (self.matrixDim["columns"] == len(self.matchingScheme[0]) and self.matrixDim["rows"] == len(self.matchingScheme)) :
if self.evaluateUnitCap( capacitance, unitCap ) == True :
self.__initMatrixMode__( capacitance, unitCap )
if self.matrixDim.values() == [1,1] : self.matrixDim = {"columns" : len(self.matchingScheme[0]) , "rows" : len(self.matchingScheme) }
@ -252,45 +252,45 @@ class CapacitorStack( CapacitorUnit ):
for k in range(0, self.capacitorsNumber):
#print('self.capacitorIdOccurence( k )',self.capacitorIdOccurence( k ))
factor = capacitance[k]/unitCap
if factor != self.capacitorIdOccurence( k ) : state = False
if factor != self.capacitorIdOccurence( k ) : state = False
return state
## \return True if the drawn capacitor is a compact one. This function is useful when an instance is called in another class. \b Example : when the matrix or the compact capacitors are to be fully routed.
def __isUnitCap__( self ): return True if not self.doMatrix else False
## \return \c True if the matching scheme specifications are correct. Specifications are :
# - Similar number of elements as total number of elementary capacitor in the matrix.
## \return \c True if the matching scheme specifications are correct. Specifications are :
# - Similar number of elements as total number of elementary capacitor in the matrix.
# - Equal number of affected capacitors to C1 as to C2.
# - Capacitor identifiers equal to '1' or '2' only.
# - Otherwise, the function returns \c False.
# - Otherwise, the function returns \c False.
def __isMatchingSchemeOK__ ( self ):
state = True
columsElementsNumber = [ len(self.matchingScheme[k]) for k in range(0,len(self.matchingScheme)) ]
columsElementsNumber = [ len(self.matchingScheme[k]) for k in range(0,len(self.matchingScheme)) ]
if len( list(numpy.unique(columsElementsNumber)) ) > 1 :
state = False
else :
if len( list(numpy.unique(columsElementsNumber)) ) > 1 :
state = False
else :
[ matrixDim , matchingSchemeDim ] = [ self.matrixDim["columns"]*self.matrixDim["rows"] , len(self.matchingScheme)*len(self.matchingScheme[0]) ]
comparaison = [ self.matrixDim[key]>1 for key in self.matrixDim.keys() ]
if ( True in comparaison ) and ( matchingSchemeDim != matrixDim ) : state = False
return state
return state
## \return occurence of capacitor identifier in the entered matching scheme. This is useful to verify that \c self.matchingScheme is correct.
def capacitorIdOccurence ( self, capacitorIdentifier ):
occurence = sum( element.count(capacitorIdentifier) for element in self.matchingScheme )
occurence = sum( element.count(capacitorIdentifier) for element in self.matchingScheme )
return occurence
@ -311,9 +311,9 @@ class CapacitorStack( CapacitorUnit ):
or (len(self.nets) == self.capacitorsNumber and self.dummyElement == True and self.dummyRing == True ) \
or (len(self.nets) == self.capacitorsNumber and self.dummyElement == True and self.dummyRing == False):
if ( self.matchingMode == True and self.__isMatchingSchemeOK__() ) or ( self.matchingMode == False and len(self.matchingScheme) == 0 ):
state = True
else: raise Error(1, '__areInputDataOK__(): Please check compatibility of the entered parameters (Matching mode, matching scheme, capacitance). It must be either equal to (False, [], one capacitance value) or ( True, matching scheme, capacitance values as much as there are capacitor ids in matching scheme ). The entered parameters are (%s, %s, %s).' %(self.matchingMode, self.matchingScheme, capacitance) ) #com2 : tester
if ( self.matchingMode == True and self.__isMatchingSchemeOK__() ) or ( self.matchingMode == False and len(self.matchingScheme) == 0 ):
state = True
else: raise Error(1, '__areInputDataOK__(): Please check compatibility of the entered parameters (Matching mode, matching scheme, capacitance). It must be either equal to (False, [], one capacitance value) or ( True, matching scheme, capacitance values as much as there are capacitor ids in matching scheme ). The entered parameters are (%s, %s, %s).' %(self.matchingMode, self.matchingScheme, capacitance) ) #com2 : tester
else : raise Error(1,'__areInputDataOK__() : Nets number, %s, is incompatible with number of capacitors to be drawn, %s.' %(len(self.nets), self.capacitorsNumber))
@ -332,26 +332,26 @@ class CapacitorStack( CapacitorUnit ):
def create( self, bbMode = False ):
UpdateSession.open()
UpdateSession.open()
drawnCapacitor = {}
self.setRules()
if self.matchingMode == True :
if self.matchingMode == True :
self.__initMatchingMode__()
self.drawAbutmentBox( self.abutmentBox_spacing )
if bbMode == True:
output = self.computeBondingBoxDimensions()
elif bbMode == False :
elif bbMode == False :
drawnCapacitor = self.drawCapacitorStack( )
output = drawnCapacitor
else:
raise Error(1, 'create(): The bonding box mode parameter, "bbMode" must be either True or False : %s.' %bbMode )
UpdateSession.close ()
return output
@ -361,10 +361,10 @@ class CapacitorStack( CapacitorUnit ):
bottomPlateRLayer = CapacitorUnit.getLayers( self )["bottomPlateRLayer"]
topPlateRLayer = CapacitorUnit.getLayers( self )["topPlateRLayer" ]
if self.doMatrix == True :
drawnCapacitor = self.capacitorMatrix ( self.abutmentBox_spacing )
if self.doMatrix == True :
drawnCapacitor = self.capacitorMatrix ( self.abutmentBox_spacing )
if self.matchingMode == False :
if self.matchingMode == False :
if self.dummyRing == True:
drawnActiveCapacitor = [drawnCapacitor[1][1:len(drawnCapacitor[1])-1]]
for i in range(2,self.matrixDim["rows"]+1):
@ -373,10 +373,10 @@ class CapacitorStack( CapacitorUnit ):
else : drawnActiveCapacitor = drawnCapacitor
self.drawBottomPlatesRLayers( bottomPlateRLayer, drawnActiveCapacitor )
self.drawTopPlatesRLayers ( topPlateRLayer , drawnActiveCapacitor )
self.drawTopPlatesRLayers ( topPlateRLayer , drawnActiveCapacitor )
else:
drawnCapacitor = CapacitorUnit( self.device, self.capacitorType, [self.abutmentBoxPosition["XMin"], self.abutmentBoxPosition["YMin"]], self.capacitance )
drawnCapacitor = CapacitorUnit( self.device, self.capacitorType, [self.abutmentBoxPosition["XMin"], self.abutmentBoxPosition["YMin"]], self.capacitance )
drawnCapacitor.create( self.nets[0][0], self.nets[0][1] )
return drawnCapacitor
@ -387,41 +387,41 @@ class CapacitorStack( CapacitorUnit ):
## Iteratively draws a horizontal or vertical line of capacitors according to the \c direction parameter. An exception is raised if the specified direction is different from \c {'horizontal','vertical'}. At every iteration, an instance of the CapacitorUnit class is created and its layout is drawn.
# \return a list containing the drawn capacitors.
# \param dy the vertical position of the first cut in cut line.
# \param dy the vertical position of the first cut in cut line.
# \remarks An exception is raised if the specified direction is different from \c {'horizontal','vertical'}
def capacitorLine( self, dy, abutmentBox_spacing , matchingSchemeRowIndex = 0 ):
line = [ CapacitorUnit( self.device, self.capacitorType, [self.abutmentBoxPosition["XMin"], dy], capacitance = self.unitCapacitance ) ]
self.createElementInCapacitorLine( line, matchingSchemeRowIndex,0 )
self.createElementInCapacitorLine( line, matchingSchemeRowIndex,0 )
limit = self.matrixDim["columns"] + 2 if self.dummyRing == True else self.matrixDim["columns"]
for j in range(1, limit ) :
line.append( CapacitorUnit( self.device, self.capacitorType, [line[j-1].abutmentBox.getXMax() + abutmentBox_spacing, dy], capacitance = self.unitCapacitance ) )
self.createElementInCapacitorLine( line, matchingSchemeRowIndex,j )
self.createElementInCapacitorLine( line, matchingSchemeRowIndex,j )
return line
def createElementInCapacitorLine( self, capacitorList, matchingSchemeRowIndex,capListIndex ):
if self.matchingMode == False :
capacitorList[capListIndex].create( self.nets[0][0], self.nets[0][1] )
else :
if self.dummyRing == True:
if (matchingSchemeRowIndex == 0 or matchingSchemeRowIndex == self.matrixDim["rows"] + 1 or capListIndex == 0 or capListIndex == self.matrixDim["columns"] + 1) :
if (matchingSchemeRowIndex == 0 or matchingSchemeRowIndex == self.matrixDim["rows"] + 1 or capListIndex == 0 or capListIndex == self.matrixDim["columns"] + 1) :
[ t , b ] = [ self.nets[-1][0] , self.nets[-1][1] ]
else :
k = self.matchingScheme[matchingSchemeRowIndex-1][capListIndex-1]
[ t , b ] = [ self.nets[k][0] , self.nets[k][1] ]
else :
else :
k = self.matchingScheme[matchingSchemeRowIndex][capListIndex]
[ t , b ] = [ self.nets[k][0] , self.nets[k][1] ]
capacitorList[capListIndex].create( t, b )
capacitorList[capListIndex].create( t, b )
return
return
## Draws a matrix of identical capacitors. The matrix is iterativelly constructed. At every iteration, a new horizontal line of capacitors is drawn.
## Draws a matrix of identical capacitors. The matrix is iterativelly constructed. At every iteration, a new horizontal line of capacitors is drawn.
# \return a nested list of elementary capacitors.
def capacitorMatrix( self, abutmentBox_spacing = 0 ):
@ -442,12 +442,12 @@ class CapacitorStack( CapacitorUnit ):
if direction == 'vertical':
for i in range(1, self.matrixDim["rows"] + 2):
dummyList.append( CapacitorUnit( self.device, self.capacitorType, [dx, dummyList[i-1].abutmentBox.getYMax() + self.abutmentBox_spacing], capacitance = self.unitCapacitance ) )
dummyList[i].create(self.nets[-1][0], self.nets[-1][1])
dummyList[i].create(self.nets[-1][0], self.nets[-1][1])
elif direction == 'horizontal':
for j in range(1, self.matrixDim["columns"] + 2):
dummyList.append( CapacitorUnit( self.device, self.capacitorType, [dummyList[j-1].abutmentBox.getXMax() + self.abutmentBox_spacing, dy], capacitance = self.unitCapacitance ) )
dummyList[j].create(self.nets[-1][0], self.nets[-1][1])
dummyList[j].create(self.nets[-1][0], self.nets[-1][1])
else : raise Error(1,'dummyLine() : Direction must be either "horizontal" or "vertical".' %direction)
@ -459,20 +459,20 @@ class CapacitorStack( CapacitorUnit ):
def computeAbutmentBoxDimensions( self, abutmentBox_spacing ):
abutmentBoxDimensions = {}
capDim = self.getCapDim()
capDim = self.getCapDim()
[widthFactor1 , widthFactor2 ] = [self.matrixDim["columns"] , (self.matrixDim["columns"] - 1)] if self.dummyRing == False else [self.matrixDim["columns"] + 2, (self.matrixDim["columns"] + 1)]
[heightFactor1, heightFactor2] = [self.matrixDim["rows" ] , (self.matrixDim["rows" ] - 1)] if self.dummyRing == False else [self.matrixDim["rows" ] + 2, (self.matrixDim["rows" ] + 1)]
abutmentBoxDimElement = CapacitorUnit.computeAbutmentBoxDimensions(self, capDim)
abutmentBoxDimElement = CapacitorUnit.computeAbutmentBoxDimensions(self, capDim)
abutmentBoxWidth = widthFactor1 *abutmentBoxDimElement["width" ] + widthFactor2 *abutmentBox_spacing
abutmentBoxHeight = heightFactor1*abutmentBoxDimElement["height"] + heightFactor2*abutmentBox_spacing
abutmentBoxHeight = heightFactor1*abutmentBoxDimElement["height"] + heightFactor2*abutmentBox_spacing
abutmentBoxDimensions = { "XMin" : self.abutmentBoxPosition["XMin"], "YMin" : self.abutmentBoxPosition["YMin"], "width" : abutmentBoxWidth , "height" : abutmentBoxHeight, "surface" : abutmentBoxWidth*abutmentBoxHeight}
return abutmentBoxDimensions
## Draws the abutment box of the matrix or campact capacitor.
## Draws the abutment box of the matrix or campact capacitor.
def drawAbutmentBox( self, abutmentBox_spacing = 0 ):
@ -481,7 +481,7 @@ class CapacitorStack( CapacitorUnit ):
self.abutmentBox = Box(self.abutmentBoxPosition["XMin"],self.abutmentBoxPosition["YMin"],abutmentBoxDimensions["width"]+self.abutmentBoxPosition["XMin"],abutmentBoxDimensions["height"]+self.abutmentBoxPosition["YMin"])
self.device.setAbutmentBox( self.abutmentBox )
return
return
def computeBondingBoxDimensions( self ):
@ -493,51 +493,51 @@ class CapacitorStack( CapacitorUnit ):
return bondingBoxDimensions
## Draws the routing layers connecting the bottom plate in the matrix of capacitors. First, the relative positions of the routing layer is of the is extracted from the elementary capacitor instance. Then, its width is computed in a way to connect adjacent plates. Then, the routing layers are iterativelly drawn.
# The two borders are .
# The two borders are .
def drawBottomPlatesRLayers( self, bottomPlateRLayer, drawnCapacitor ):
[ dySourceBottom, dyTargetBottom ] = [ drawnCapacitor[0][0].getBotPlateRLayerYMin (), drawnCapacitor[-1][0].getBotPlateRLayerYMax() ]
[ dySourceBottom, dyTargetBottom ] = [ drawnCapacitor[0][0].getBotPlateRLayerYMin (), drawnCapacitor[-1][0].getBotPlateRLayerYMax() ]
if ( self.matrixDim["columns"] > 1 ) :
bottomPlateRLayer_width = ( drawnCapacitor[0][1].getBotPlateLeftRLayerXMax() - drawnCapacitor[0][0].getBotPlateRightRLayerXMin() )
bottomPlateRLayer_width = ( drawnCapacitor[0][1].getBotPlateLeftRLayerXMax() - drawnCapacitor[0][0].getBotPlateRightRLayerXMin() )
bottomMetalXCenters = []
for j in range( 0,self.matrixDim["columns"]-1 ):
bottomMetalXCenters.append( drawnCapacitor[0][j].getBotPlateRightRLayerXMin() + bottomPlateRLayer_width/2 )
Vertical.create ( self.nets[0][1], bottomPlateRLayer, bottomMetalXCenters[j], bottomPlateRLayer_width, dySourceBottom, dyTargetBottom )
Vertical.create ( self.nets[0][1], bottomPlateRLayer, bottomMetalXCenters[j], bottomPlateRLayer_width, dySourceBottom, dyTargetBottom )
bordersXMin = [ drawnCapacitor[0][0].getBottomPlateLeftCutXMin(), drawnCapacitor[0][-1].getBottomPlateRightCutXMin() ]
for j in range( 0,2):
Vertical.create ( self.nets[0][1], bottomPlateRLayer , bordersXMin[j], drawnCapacitor[0][0].getBotPlateRLayerWidth(), dySourceBottom, dyTargetBottom )
Vertical.create ( self.nets[0][1], bottomPlateRLayer , bordersXMin[j], drawnCapacitor[0][0].getBotPlateRLayerWidth(), dySourceBottom, dyTargetBottom )
return
## Draws the routing layers connecting the top plates in the matrix of capacitors. First, the relative positions of the routing layers is of the is extracted from the elementary capacitor instance. Then, its width is computed in a way to connect adjacent plates. Then, the routing layers are iterativelly drawn.
# The two borders are .
## Draws the routing layers connecting the top plates in the matrix of capacitors. First, the relative positions of the routing layers is of the is extracted from the elementary capacitor instance. Then, its width is computed in a way to connect adjacent plates. Then, the routing layers are iterativelly drawn.
# The two borders are .
# \remarks An exception is raised if the number of rows in the matrix is lower than 2.
def drawTopPlatesRLayers( self, topPlateRLayer, drawnCapacitor):
if ( self.matrixDim["rows"] > 1 ) :
for j in range( 0,self.matrixDim["columns"] ):
Vertical.create ( self.nets[0][0], topPlateRLayer , drawnCapacitor[0][j].getTopPlateRLayerXCenter(), drawnCapacitor[0][j].getTopPlateRLayerWidth() , drawnCapacitor[0][0].getTopPlateRLayerYMin(), drawnCapacitor[-1][0].getTopPlateRLayerYMax() )
Vertical.create ( self.nets[0][0], topPlateRLayer , drawnCapacitor[0][j].getTopPlateRLayerXCenter(), drawnCapacitor[0][j].getTopPlateRLayerWidth() , drawnCapacitor[0][0].getTopPlateRLayerYMin(), drawnCapacitor[-1][0].getTopPlateRLayerYMax() )
#else : print('The matrix does not contain enough rows') #com4 verify if this else is needed
#else : print('The matrix does not contain enough rows') #com4 verify if this else is needed
return
## \return The width of the vertical routing tracks in matching mode.
# \remark This function is useful in matching mode, ie., in \C RoutCapacitor class, when routing the two capacitors.
## \return The width of the vertical routing tracks in matching mode.
# \remark This function is useful in matching mode, ie., in \c RoutCapacitor class, when routing the two capacitors.
def getVerticalRoutingTrack_width ( self ) : return self.vRoutingTrack_width
def getAbutmentBox_spacing ( self ) : return self.abutmentBox_spacing
## \return A dictionary contaning capacitor matrix's dimensions
def getMatrixDim ( self ) : return self.matrixDim
def getMatrixDim ( self ) : return self.matrixDim
def getCapDim ( self ) : return self.unitCapDim if self.doMatrix == True else self.compactCapDim
@ -550,7 +550,7 @@ class CapacitorStack( CapacitorUnit ):
def getvRoutingTrack_width ( self ) : return self.vRoutingTrack_width
## \return the matching scheme. The function is useful in \c RoutMatchedCapacitor class to load \c self.matchingScheme attribute.
def getMatchingScheme ( self ) : return self.matchingScheme
def getMatchingScheme ( self ) : return self.matchingScheme
def scriptMain( **kw ):
@ -567,10 +567,10 @@ def scriptMain( **kw ):
bottomPlate_net1 = Net.create( device, 'b1' )
bottomPlate_net2 = Net.create( device, 'b2' )
bottomPlate_net3 = Net.create( device, 'b3' )
bottomPlate_net0.setExternal( True )
bottomPlate_net1.setExternal( True )
bottomPlate_net2.setExternal( True )
bottomPlate_net3.setExternal( True )
bottomPlate_net0.setExternal( True )
bottomPlate_net1.setExternal( True )
bottomPlate_net2.setExternal( True )
bottomPlate_net3.setExternal( True )
b0 = device.getNet("b0")
b1 = device.getNet("b1")
b2 = device.getNet("b2")
@ -580,10 +580,10 @@ def scriptMain( **kw ):
topPlate_net1 = Net.create( device, 't1' )
topPlate_net2 = Net.create( device, 't2' )
topPlate_net3 = Net.create( device, 't3' )
topPlate_net0.setExternal( True )
topPlate_net1.setExternal( True )
topPlate_net2.setExternal( True )
topPlate_net3.setExternal( True )
topPlate_net0.setExternal( True )
topPlate_net1.setExternal( True )
topPlate_net2.setExternal( True )
topPlate_net3.setExternal( True )
t0 = device.getNet("t0")
t1 = device.getNet("t1")
t2 = device.getNet("t2")
@ -591,7 +591,7 @@ def scriptMain( **kw ):
if editor:
UpdateSession.close()
editor.setCell( device )
editor.fit()
editor.fit()
UpdateSession.open()
nets = [[t0, b0] , [t1, b1] , [t2, b2] ] # [t3, b3] ]
capacitorInstance = CapacitorStack( device, [750,750], 'MIMCap', [0,0], nets,unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ [1,0,1,0] , [0,1,0,1] , [1,0,1,0] , [0,1,0,1] ], dummyRing = True)
@ -600,8 +600,8 @@ def scriptMain( **kw ):
#capacitorInstance = CapacitorStack( device, {"C1" : 558, "C2" : 558, "C3" : 186, "C4" : 186}, 'MIMCap', [0,0], nets, unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ ['C2','C1','C2','C1'] , ['C1','C2','C1','C2'] , ['C2','C1','C2','C1'] , ['C3','C3','C4','C4'] ])
capacitor = capacitorInstance.create()
#print(toPhY(capacitor["width"]))
#print(toPhY(capacitor["height"]))
#print(toPhY(capacitor["width"]))
#print(toPhY(capacitor["height"]))
AllianceFramework.get().saveCell( device, Catalog.State.Views )

View File

@ -1,6 +1,6 @@
#!/usr/bin/python
import sys
import sys
from ..Hurricane import *
from ..CRL import *
from ..helpers.io import ErrorMessage as Error
@ -35,34 +35,34 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
# - the class attirbutes describing positions and dimensions of the layout are computed in dedicated class methods,
# - the attributes related to the capacitor matrix are copied from the \c CapacitorStack instance.
#
# Position and dimensions attributes, also refered by layout variables, in Figure 2, are defined below :
# \param device The Hurricane AMS device onto which the layout is drawn.
# Position and dimensions attributes, also refered by layout variables, in Figure 2, are defined below :
# \param device The Hurricane AMS device onto which the layout is drawn.
# \param capacitorInstance Instance of \c CapacitorStack class.
# \param capacitor A nested list containing the matrix elements, which are \c CapacitorUnit objects.
# \param capacitor A nested list containing the matrix elements, which are \c CapacitorUnit objects.
# \param matchingScheme A nested list, with equal dimensions as \c capacitor attribute, containing assignements of matrix elementary units to C1 and C2, identified by 1 and 2, respectively. Therefore, \c self.matchingScheme content is a succession of 1 and 2 values, defined as \ capacitor identifiers. For example, given a matrix of dimensions 2x2, the matching scheme can be \f$ [ [1,2], [1,2] ] or [ [2,1], [2,1] ] \f$. The first sub-list dictates that the first elementary capacitor, \f$ C_{00} \f$. The second element \f$ C_{01} \f$ is affected to C2 and so on. An immediate and obvious consequence to this, is that an error is raised if \c self.matchingSchem and \c self.capacitor dimensions are not identical or if \c self.matchingScheme content is different from supported capacitor identifiers, '1' and '2'.
#
# \param capacitorType Supported types of capacitors are MIM and PIP only. An exception is raised otherwise.
# \param abutmentBox The matrix's abutment box.
# \param matrxiDim The matrix dimensions, also equal to \c self.matchingScheme nested list dimensions.
# \param matrxiDim The matrix dimensions, also equal to \c self.matchingScheme nested list dimensions.
# \param abutmentBox_spacing The spacing between elementary units in the matrix.
# It is computed in \c CapacitorStack and is reloaded
# in \c RoutMatchedCapacitor. \c self.abutmentBox_spacing
# includes, vertical routing tracks width and minimum
# allowed spacing between two adjacent ones.
# \param hRoutingLayer_width The width of horizontal routing layers in metal 2, which connect capacitors plates to vertical routing tracks.
# \param vRoutingTrack_width The width of vertical routing tracks in metal 3, which connects identical nets together ( ie : bottom plates of C1, top plates of C2, bottom plates of C2 and top plates of C2 ).
# \param hRoutingTrack_width The width of horizontal routing tracks in metal 2, which connect identical vertical routing tracks together.
# \param hRoutingLayer_width The width of horizontal routing layers in metal 2, which connect capacitors plates to vertical routing tracks.
# \param vRoutingTrack_width The width of vertical routing tracks in metal 3, which connects identical nets together ( ie : bottom plates of C1, top plates of C2, bottom plates of C2 and top plates of C2 ).
# \param hRoutingTrack_width The width of horizontal routing tracks in metal 2, which connect identical vertical routing tracks together.
# \param minSpacing_hRoutingTrack Minimum spacing between horizontal routing tracks.
# Wide metal 2 specifications are considered since metal 2
# dimensions may exceed 10 \f$ m\f$.
#
# \remark For more information about wide metal specifications, refer to ENG-183_rev8.pdf technology manual.
# dimensions may exceed 10 \f$ m\f$.
#
# \remark For more information about wide metal specifications, refer to ENG-183_rev8.pdf technology manual.
#
# \param minimumPosition The ordinate of the top plate's routing layer's
# bottom extremity after stretching.
# bottom extremity after stretching.
# \param maximumPosition The ordinate of the top plate's routing layer's
# top extremity, also equivalent to the top plate's
# top extremity.
# top extremity.
# \param vRoutingTrackXCenter A nested list of ordered dictionaries, with dimensions
# equal to \c self.matrixDim, containing abcissas of vertical
# routing tracks. All sub-lists' lengths are identical and
@ -72,18 +72,18 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
# 2x2, \c self.vRoutingTrackXCenter can be
# [[0, 2], [4,6], [8,10]] \f$ \mu m\f$.
# Elements of this nested list have particular indexing as
# described in Figure 2.
# described in Figure 2.
#
# \param hRoutingtrackYCenter A nested dictonary containing two keys, \c topTracks
# and \c bottomTracks. Each key contains as value a dictionary
# describing centers' ordinates of four parallel horizontal
# tracks. The reason why four tracks are needed on top and
# bottom positions of the matrix is that four nets are used,
# two for every capacitor \c Ci, were \c i is in [1,2].
# two for every capacitor \c Ci, were \c i is in [1,2].
# \param hRoutingLayerYCenter A nested dicitonary containing two keys, \c top and
# \c bottom. Each key contains as value a dictionary
# describing centers' ordinates of horizontal routing layers.
# \param vRoutingTrackDict A dictionary of routing tracks top and bottom extremities ordinates.
# describing centers' ordinates of horizontal routing layers.
# \param vRoutingTrackDict A dictionary of routing tracks top and bottom extremities ordinates.
# \param topPlateStretching Since not only the same metal 2 layer is used to draw top/bottom plates connections to vertical tracks but also the two plates are superimposed, the top plate's routing tracks is stretched. \c self.topPlateStretching is therefore the length added to top plate's routing layer in order to avoid short circuits between top and bottom plates routing to vertical tracks since the same metal is used for both.
def __init__( self, vRTInstance ) :
@ -96,16 +96,16 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
for i in range(2,self.matrixDim["rows"]+1):
self.capacitor.append(vRTInstance.capacitor[i][1:len(vRTInstance.capacitor[1])-1])
self.dummyRingCapacitor = [ vRTInstance.capacitor[0], vRTInstance.capacitor[-1] ]
self.dummyRingCapacitor = [ vRTInstance.capacitor[0], vRTInstance.capacitor[-1] ]
#self.dummyRingVRLayersDict = {}
self.hRoutingLayer_width = 0
self.hRoutingTrack_width = vRTInstance.hRoutingTrack_width
self.minSpacing_hRoutingTrack = 0
self.hRoutingLayer_width = 0
self.hRoutingTrack_width = vRTInstance.hRoutingTrack_width
self.minSpacing_hRoutingTrack = 0
self.minimumPosition = 0
self.maximumPosition = 0
self.hRoutingtrackYCenter = { "topTracks" : {} , "bottomTracks" : {} }
self.hRoutingLayerYCenter = { "topPlate" : [] , "bottomPlate" : [] }
self.hRoutingLayerYCenter = { "topPlate" : [] , "bottomPlate" : [] }
self.vRTInstance = vRTInstance
self.topPlateStretching = 0
@ -119,20 +119,20 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
# The following tasks are excecuted :
# -# A nex \c UpdateSession is created,
# -# all required physical layers are loaded,
# -# technology rules are defined according to capacitor type,
# -# technology rules are defined according to capacitor type,
# -# layout dimension parameters are computed,
# -# routing tracks and layers are drawn,
# -# routing tracks and layers are drawn,
# -# top plates are stretched,
# -# all required cuts are drawn,
# -# The \c UpdateSession is closed.
#
# Meanwhile, an exception is raised when the entered \c capacitor is not a
# capacitor matrix or if the capacitor type is unsupported.
# capacitor matrix or if the capacitor type is unsupported.
def route( self, bbMode=False ):
UpdateSession.open()
self.setRules()
if not self.capacitorInstance.__isUnitCap__():
@ -175,7 +175,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
widthAdjust = 2*self.vpitch - widthAdjust
xMax += widthAdjust//2
xMin -= widthAdjust//2
self.device.setAbutmentBox( Box( int(xMin)
, int(self.minimumPosition - dY)
, int(xMax)
@ -186,7 +186,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
self.drawHRLayers ( layersDict["xPlateHRLayer" ] )
self.drawHRoutingTracks ( layersDict["hRoutingTracks"] )
self.__stretchTopPlates__( self.capacitor
, layersDict["xPlateRLayer" ] )
, layersDict["xPlateRLayer" ] )
self.drawCuts ( layersDict["cut_hRoutingLayer_vRoutingTracks" ]
, layersDict["cut_hRoutingTracks_vRoutingTracks"]
, layersDict["cut_hRoutingLayer_topPlate" ] )
@ -208,10 +208,10 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
def routeDummyRing( self, routingLayer, cutLayer ):
net = self.nets[-1][1]
bottomPlateRLayer_width = self.dummyRingCapacitor[0][0].getBotPlateRLayerWidth()
topPlateRLayer_width = self.dummyRingCapacitor[0][0].getTopPlateRLayerWidth()
bottomPlateRLayer_width = self.dummyRingCapacitor[0][0].getBotPlateRLayerWidth()
topPlateRLayer_width = self.dummyRingCapacitor[0][0].getTopPlateRLayerWidth()
#self.computeDummyRingDimensions ()
self.routeLeftAndRightSides (net, routingLayer, bottomPlateRLayer_width, topPlateRLayer_width )
self.routeTopOrBottomSide (net, "topSide" , routingLayer , bottomPlateRLayer_width, topPlateRLayer_width)
@ -226,21 +226,21 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
def routeLeftAndRightSides( self, dummyNet, routingLayer, bottomPlateRLayer_width, topPlateRLayer_width ) :
for i in range(0,2):
bottomPlateLeftRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateLeftRLayerXCenter()
bottomPlateRightRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateRightRLayerXCenter()
bottomPlateLeftRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateLeftRLayerXCenter()
bottomPlateRightRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateRightRLayerXCenter()
Vertical.create( dummyNet
, routingLayer
, bottomPlateLeftRLayerXCenter
, bottomPlateRLayer_width
, self.getVTrackYMin()
, self.getVTrackYMax() )
, self.getVTrackYMax() )
Vertical.create( dummyNet
, routingLayer
, bottomPlateRightRLayerXCenter
, bottomPlateRLayer_width
, self.getVTrackYMin()
, self.getVTrackYMax() )
, self.getVTrackYMax() )
for i in range(0,2):
topPlateRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].topPlateRLayerDict["XCenter"]
Vertical.create( dummyNet
@ -248,7 +248,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
, topPlateRLayerXCenter
, topPlateRLayer_width
, self.getVTrackYMin()
, self.getVTrackYMax() )
, self.getVTrackYMax() )
return
@ -257,29 +257,29 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
def routeTopOrBottomSide( self, dummyNet, side, routingLayer, bottomPlateRLayer_width, topPlateRLayer_width):
if side == "topSide" :
if side == "topSide" :
dummyRingElement = self.dummyRingCapacitor[-1]
dyTarget = self.getVTrackYMax()
elif side == "bottomSide" :
elif side == "bottomSide" :
dummyRingElement = self.dummyRingCapacitor[0]
dyTarget = self.getVTrackYMin()
else : raise Error(1,'routeTopOrBottomSide() : side parameter must be either "topSide" or "bottomSide" : %s' %side)
for j in range(1,len(self.dummyRingCapacitor[0])-1):
bottomPlateLeftRLayerXCenter = dummyRingElement[j].getBotPlateLeftRLayerXCenter()
bottomPlateRightRLayerXCenter = dummyRingElement[j].getBotPlateRightRLayerXCenter()
bottomPlateLeftRLayerXCenter = dummyRingElement[j].getBotPlateLeftRLayerXCenter()
bottomPlateRightRLayerXCenter = dummyRingElement[j].getBotPlateRightRLayerXCenter()
Vertical.create( dummyNet
, routingLayer
, bottomPlateLeftRLayerXCenter
, bottomPlateRLayer_width
, dummyRingElement[j].getBotPlateRLayerYMin()
, dyTarget )
, dyTarget )
Vertical.create( dummyNet
, routingLayer
, bottomPlateRightRLayerXCenter
, bottomPlateRLayer_width
, dummyRingElement[j].getBotPlateRLayerYMin()
, dyTarget )
, dyTarget )
topPlateRLayerXCenter = dummyRingElement[j].topPlateRLayerDict["XCenter"]
Vertical.create( dummyNet
@ -287,7 +287,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
, topPlateRLayerXCenter
, topPlateRLayer_width
, dummyRingElement[j].getTopPlateRLayerYMin()
, dyTarget )
, dyTarget )
return
@ -299,7 +299,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
# both MIM and PIP capacitors. However, cuts rules are different.
#
# \remark All \c CapacitorStack class rules are also reloaded in this class.
# An exception is raised if the entered capacitor type is unsupported.
# An exception is raised if the entered capacitor type is unsupported.
#
# \return a dictionary with rules labels as keys and rules content as values.
@ -316,7 +316,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
self.minWidth_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minWidth_cut2
self.minSpacing_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minSpacing_cut2
self.minEnclosure_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minEnclosure_metal2_cut2
elif self.capacitorType == 'PIPCap':
elif self.capacitorType == 'PIPCap':
self.minWidth_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minWidth_cut1
self.minSpacing_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minSpacing_cut1
self.minEnclosure_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minEnclosure_metal2_cut1
@ -324,7 +324,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
return
## Defines all physical layers used to draw the layout. Layers are loaded using \c DataBase API. The same routing layers are used for both capacitor types except cuts layers that connect top plates to vertical routing tracks. Basicaly, metal 2, meta 3, cut 1 and cut 2 are the ones defined.
## Defines all physical layers used to draw the layout. Layers are loaded using \c DataBase API. The same routing layers are used for both capacitor types except cuts layers that connect top plates to vertical routing tracks. Basicaly, metal 2, meta 3, cut 1 and cut 2 are the ones defined.
# \return a dictionary composed of layers labels as keys and layers as values.
def setLayers( self ):
@ -344,14 +344,14 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
return layersDict
## Computes, through simple instructions and functions calls, layout variables detailed in Figure 2.
## Computes, through simple instructions and functions calls, layout variables detailed in Figure 2.
def computeDimensions ( self, bbMode ) :
bondingBoxDimensions = {}
self.hRoutingLayer_width = max( self.minWidth_hRoutingLayer, self.minWidth_hRoutingLayer_vRoutingTrack_cut + 2*self.minEnclosure_hRoutingLayer_vRoutingTrack_cut, self.minWidth_hRoutingLayer_topPlate_cut + 2*self.minEnclosure_hRoutingLayer_topPlate_cut )
self.abutmentBox_spacing = self.capacitorInstance.abutmentBox_spacing
self.abutmentBox_spacing = self.capacitorInstance.abutmentBox_spacing
self.vRoutingTrack_spacing = self.capacitorInstance.getVRoutingTrack_spacing()
abutmentBoxXMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["XMin"] #getAbutmentBox_spacing()
@ -363,12 +363,12 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
self.vRoutingTrackDict = self.vRTInstance.vRoutingTrackDict #self.minimumPosition - 4*self.hRoutingTrack_width - 4*self.minSpacing_hRoutingTrack
translation1 = self.vRoutingTrack_width/2 + self.vRoutingTrack_spacing
translation2 = translation1 + self.vRoutingTrack_width/2
translation2 = translation1 + self.vRoutingTrack_width/2
self.vRoutingTrackXCenter = self.vRTInstance.vRoutingTrackXCenter #getvRoutingTrackXCenter()
#print("vRoutingTrackXCenter",self.vRoutingTrackXCenter)
if bbMode == True :
bondingBoxDimensions = self.computeBondingBoxDimInbbMode()
bondingBoxDimensions = self.computeBondingBoxDimInbbMode()
elif bbMode == False :
self.computeHRoutingTrackYCenter()
@ -391,7 +391,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
bondingBoxDimensions["XMin" ] = self.vRoutingTrackXCenter[0]["t0"] - self.vRoutingTrack_width/2
if self.capacitorsNumber % 2 == 0 :
factor = self.capacitorsNumber
factor = self.capacitorsNumber
if self.capacitorsNumber % 2 != 0 :
factor = self.capacitorsNumber + 1 if self.matrixDim["columns"] % 2 == 0 else self.capacitorsNumber - 1
@ -399,7 +399,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
bondingBoxDimensions["YMin" ] = self.vRoutingTrackDict["YMin"]
bondingBoxYMax = self.vRoutingTrackDict["YMax"]
bondingBoxDimensions["width" ] = bondingBoxXMax - bondingBoxDimensions["XMin"]
bondingBoxDimensions["height" ] = bondingBoxYMax - bondingBoxDimensions["YMin"]
bondingBoxDimensions["height" ] = bondingBoxYMax - bondingBoxDimensions["YMin"]
bondingBoxDimensions["surface"] = bondingBoxDimensions["width"]*bondingBoxDimensions["height"]
#bondingBox = Box( bondingBoxDimensions["XMin"], bondingBoxDimensions["YMin"], bondingBoxXMax, bondingBoxYMax )
@ -415,24 +415,24 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
# deduced by simples translation of the first one. Translation quantity
# is equal to the sum of distance between adjacent routing tracks,
# self.hRoutingTracks_spacing, and half width of the routing track itself,
# \c self.hRoutingTrack_width.
# \c self.hRoutingTrack_width.
def computeHRoutingTrackYCenter( self ):
self.hRoutingtrackYCenter = { "topTracks" : {} , "bottomTracks" : {} }
#self.hRoutingtrackYCenter["topTracks" ]["t0"] = self.maximumPosition \
# + self.hRoutingTrack_width/2 + self.minSpacing_hRoutingTrack
# + self.hRoutingTrack_width/2 + self.minSpacing_hRoutingTrack
#self.hRoutingtrackYCenter["bottomTracks" ]["t0"] = self.minimumPosition \
# - self.hRoutingTrack_width/2 - self.minSpacing_hRoutingTrack
self.hRoutingtrackYCenter["topTracks" ]["t0"] = self.maximumPosition
self.hRoutingtrackYCenter["bottomTracks" ]["t0"] = self.minimumPosition
keys = self.__setPlatesIds__()
for k in range(1, len(keys)):
trace( 101, '\tkeys[{0}] = {1}\n'.format( k, keys[k] ))
#self.hRoutingtrackYCenter["topTracks"][keys[k]] \
# = self.hRoutingtrackYCenter["topTracks"][keys[k-1]] \
# + (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
# + (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
#self.hRoutingtrackYCenter["bottomTracks" ][keys[k]] \
# = self.hRoutingtrackYCenter["bottomTracks"][keys[k-1]] \
# - (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
@ -456,23 +456,23 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
#print("rows", self.matrixDim["rows"])
#print("rowsCap", len(self.capacitor))
if shortCircuitLists[i][0] == 0 :
self.hRoutingLayerYCenter["bottomPlate"].append( [self.capacitor[i][0].getBottomPlateRightCutYMax ()] )
else :
bottomPlateYCenter0 = [(self.capacitor[i][0].getBottomPlateRightCutYMax () + self.capacitor[i][0].getBottomPlateRightCutYMin() ) /2 ]
self.hRoutingLayerYCenter["bottomPlate"].append(bottomPlateYCenter0)
if shortCircuitLists[i][0] == 0 :
self.hRoutingLayerYCenter["bottomPlate"].append( [self.capacitor[i][0].getBottomPlateRightCutYMax ()] )
else :
bottomPlateYCenter0 = [(self.capacitor[i][0].getBottomPlateRightCutYMax () + self.capacitor[i][0].getBottomPlateRightCutYMin() ) /2 ]
self.hRoutingLayerYCenter["bottomPlate"].append(bottomPlateYCenter0)
topPlateYCenter = self.__setStretchingDySourceDyTarget__( self.capacitor[i][0], self.topPlateStretching )[1] + self.hRoutingLayer_width/2
self.hRoutingLayerYCenter["topPlate" ].append( [topPlateYCenter ] )
for j in range( 1,self.matrixDim["columns"] ):
topPlateYCenter = self.__setStretchingDySourceDyTarget__( self.capacitor[i][j], self.topPlateStretching )[1] + self.hRoutingLayer_width/2
if shortCircuitLists[i][j] == 0 :
topPlateYCenter = self.__setStretchingDySourceDyTarget__( self.capacitor[i][j], self.topPlateStretching )[1] + self.hRoutingLayer_width/2
if shortCircuitLists[i][j] == 0 :
self.hRoutingLayerYCenter["bottomPlate"][i].append( self.capacitor[i][j].getBottomPlateRightCutYMax () )
self.hRoutingLayerYCenter["topPlate" ][i].append( topPlateYCenter )
else :
bottomPlateYCenter = (self.capacitor[i][j].getBottomPlateRightCutYMax() + self.capacitor[i][j].getBottomPlateRightCutYMin()) /2
topPlateYCenter2 = topPlateYCenter + self.minSpacing_hRoutingLayer + self.hRoutingLayer_width
topPlateYCenter2 = topPlateYCenter + self.minSpacing_hRoutingLayer + self.hRoutingLayer_width
self.hRoutingLayerYCenter["bottomPlate"][i].append(bottomPlateYCenter)
self.hRoutingLayerYCenter["topPlate" ][i].append(topPlateYCenter2)
@ -484,7 +484,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
bondingBoxDict = {}
bondingBoxDict["YMin" ] = self.hRoutingtrackYCenter["bottomTracks"]["botB"] - self.hRoutingTrack_width/2
bondingBoxDict["XMin" ] = self.vRoutingTrackXCenter[0 ][0] - self.vRoutingTrack_width/2
bondingBoxDict["height" ] = self.hRoutingtrackYCenter["topTracks" ]["botB"] + self.hRoutingTrack_width/2 - bondingBoxDict["YMin"]
bondingBoxDict["height" ] = self.hRoutingtrackYCenter["topTracks" ]["botB"] + self.hRoutingTrack_width/2 - bondingBoxDict["YMin"]
bondingBoxDict["width" ] = self.vRoutingTrackXCenter[-1][1] + self.vRoutingTrack_width/2 - bondingBoxDict["XMin"]
self.bondingBox = Box( bondingBoxDict["XMin"], bondingBoxDict["YMin"], bondingBoxDict["XMin"] + bondingBoxDict["width"], bondingBoxDict["YMin"] + bondingBoxDict["height"] )
@ -499,7 +499,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
## Iteratively draws horizontal routing tracks on top and bottom positions of the matrix
# using physical layer \c routingTracksLayer.
# using physical layer \c routingTracksLayer.
def drawHRoutingTracks( self , routingTracksLayer ):
@ -526,15 +526,15 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
NetExternalComponents.setExternal( horizontal )
return
## Iteratively draws the horizontal routing layers starting with bottom left elementary capacitor \f$ C_{00} \f$.
def drawHRLayers( self, xPlateRLayer ) :
## Iteratively draws the horizontal routing layers starting with bottom left elementary capacitor \f$ C_{00} \f$.
def drawHRLayers( self, xPlateRLayer ) :
for i in range( 0,self.matrixDim["rows"] ):
for j in range( 0,self.matrixDim["columns"] ):
[ t , b ] = [ self.nets[self.matchingScheme[i][j]][0], self.nets[self.matchingScheme[i][j]][1] ]
[ t , b ] = [ self.nets[self.matchingScheme[i][j]][0], self.nets[self.matchingScheme[i][j]][1] ]
dxDict = self.__computeConnections__( i,j, self.matchingScheme[i][j] )
Horizontal.create ( t
@ -542,27 +542,27 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
, int(self.hRoutingLayerYCenter["topPlate" ][i][j])
, int(self.hRoutingLayer_width)
, int(dxDict["topPlate" ][ "source" ])
, int(dxDict["topPlate" ][ "target" ]) )
, int(dxDict["topPlate" ][ "target" ]) )
Horizontal.create ( b
, xPlateRLayer
, int(self.hRoutingLayerYCenter["bottomPlate"][i][j])
, int(self.hRoutingLayer_width)
, int(dxDict["bottomPlate" ][ "source" ])
, int(dxDict["bottomPlate" ][ "target" ]) )
, int(dxDict["bottomPlate" ][ "target" ]) )
return
## Draws all required cuts using physical layers :
## Draws all required cuts using physical layers :
# - \c layer_hRTrack_hRLayer to connect bottom plates to vertical routing tracks,
# - \c layer_tracksCut to connect vertical routing tracks to horizontal ones,
# - \c layer_tracksCut to connect vertical routing tracks to horizontal ones,
# - \c layer_topPlateCut to connect top plates to vertical routing tracks.
# ALso in \c drawCuts, nUmber of maximum cuts number on every layer is computed and cuts enclosure is adjusted according to layer's width.
def drawCuts( self, layer_hRTrack_hRLayer, layer_tracksCut, layer_topPlateCut ):
cutNumber = CapacitorUnit.cutMaxNumber( self, self.vRoutingTrack_width, self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut )
enclosure_hRoutingTrack_cut = (self.vRoutingTrack_width - cutNumber*self.minWidth_hRoutingTrackCut - (cutNumber - 1)*self.minSpacing_hRoutingTrackCut)/2
enclosure_hRoutingTrack_cut = (self.vRoutingTrack_width - cutNumber*self.minWidth_hRoutingTrackCut - (cutNumber - 1)*self.minSpacing_hRoutingTrackCut)/2
self.drawCuts_vRoutingTrack_HRLayer ( layer_hRTrack_hRLayer, cutNumber, enclosure_hRoutingTrack_cut )
self.drawCuts_vRoutingTrack_hRoutingTrack ( layer_tracksCut , cutNumber, enclosure_hRoutingTrack_cut )
@ -604,15 +604,15 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
## Draws one cut, in layer \c cutLayer, in order to connect a vertical routing track, at position \c cutXMin in metal 2, and a horizontal routing track, at position \c cutYMin in metal 3.
## Draws one cut, in layer \c cutLayer, in order to connect a vertical routing track, at position \c cutXMin in metal 2, and a horizontal routing track, at position \c cutYMin in metal 3.
def drawOneCut_vRoutingTrack_HRLayer( self, net, cutLayer, cutXMin, cutYMin, cutNumber ):
CapacitorUnit.cutLine(self,net,cutLayer,cutXMin,cutYMin,self.minWidth_hRoutingLayer_vRoutingTrack_cut,self.minWidth_hRoutingLayer_vRoutingTrack_cut,self.minSpacing_hRoutingLayer_vRoutingTrack_cut,cutNumber,'horizontal')
CapacitorUnit.cutLine(self,net,cutLayer,cutXMin,cutYMin,self.minWidth_hRoutingLayer_vRoutingTrack_cut,self.minWidth_hRoutingLayer_vRoutingTrack_cut,self.minSpacing_hRoutingLayer_vRoutingTrack_cut,cutNumber,'horizontal')
return
## Draws cuts to connect vertical routing tracks in metal 2 and horizontal routing tracks in metal 3.
## Draws cuts to connect vertical routing tracks in metal 2 and horizontal routing tracks in metal 3.
def drawCuts_vRoutingTrack_hRoutingTrack( self,cutLayer, cutNumber, enclosure_cut ):
keysList = list(self.hRoutingtrackYCenter.keys())
@ -620,50 +620,50 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
for i in range(0, len(self.vRoutingTrackXCenter) ):
for k in self.vRoutingTrackXCenter[i]:
if self.vRoutingTrackXCenter[i][k] != None :
for l in range(0, 2) :
for l in range(0, 2) :
net = self.nets[ int(k[1]) ][0] if k[0] == 't' else self.nets[ int(k[1]) ][1]
cutXMin = self.vRoutingTrackXCenter[i][k] - self.vRoutingTrack_width/2 + enclosure_cut + self.minWidth_hRoutingTrackCut/2
CapacitorUnit.cutLine(self,net,cutLayer,cutXMin,self.hRoutingtrackYCenter[keysList[l]][k],self.minWidth_hRoutingTrackCut,self.minWidth_hRoutingTrackCut,self.minSpacing_hRoutingTrackCut,cutNumber,'horizontal')
CapacitorUnit.cutLine(self,net,cutLayer,cutXMin,self.hRoutingtrackYCenter[keysList[l]][k],self.minWidth_hRoutingTrackCut,self.minWidth_hRoutingTrackCut,self.minSpacing_hRoutingTrackCut,cutNumber,'horizontal')
return
# \param cutLayer
# \param cutLayer
def drawCuts_stretchedTopPlate( self, cutLayer ):
layer_width = self.capacitor[0][0].getTopPlateRLayerWidth()
cutNumber = CapacitorUnit.cutMaxNumber( self, layer_width , self.minWidth_hRoutingLayer_topPlate_cut, self.minSpacing_hRoutingLayer_topPlate_cut , self.minEnclosure_hRoutingLayer_topPlate_cut )
enclosure_hRoutingTrack_cut = (layer_width - cutNumber*self.minWidth_hRoutingLayer_topPlate_cut - (cutNumber - 1)*self.minSpacing_hRoutingLayer_topPlate_cut)/2
enclosure_hRoutingTrack_cut = (layer_width - cutNumber*self.minWidth_hRoutingLayer_topPlate_cut - (cutNumber - 1)*self.minSpacing_hRoutingLayer_topPlate_cut)/2
for i in range(0, self.matrixDim["rows"] ):
for j in range(0, self.matrixDim["columns"] ):
tNet = self.nets[self.matchingScheme[i][j]][0]
cutXMin = self.capacitor[i][j].getTopPlateRLayerXMin() + enclosure_hRoutingTrack_cut + self.minWidth_hRoutingLayer_topPlate_cut/2
CapacitorUnit.cutLine( self, tNet, cutLayer, cutXMin , self.hRoutingLayerYCenter["topPlate"][i][j] , self.minWidth_hRoutingLayer_topPlate_cut, self.minWidth_hRoutingLayer_topPlate_cut, self.minSpacing_hRoutingLayer_topPlate_cut, cutNumber, 'horizontal' )
tNet = self.nets[self.matchingScheme[i][j]][0]
cutXMin = self.capacitor[i][j].getTopPlateRLayerXMin() + enclosure_hRoutingTrack_cut + self.minWidth_hRoutingLayer_topPlate_cut/2
CapacitorUnit.cutLine( self, tNet, cutLayer, cutXMin , self.hRoutingLayerYCenter["topPlate"][i][j] , self.minWidth_hRoutingLayer_topPlate_cut, self.minWidth_hRoutingLayer_topPlate_cut, self.minSpacing_hRoutingLayer_topPlate_cut, cutNumber, 'horizontal' )
return
def drawDummyRing_hRTracks_Cuts( self, dummyNet, side, cutLayer ):
if side == "topSide" :
if side == "topSide" :
dummyRingElement = self.dummyRingCapacitor[-1]
key = "topTracks"
elif side == "bottomSide" :
elif side == "bottomSide" :
dummyRingElement = self.dummyRingCapacitor[0]
key = "bottomTracks"
else : raise Error(1,'routeTopOrBottomSide() : side parameter must be either "topSide" or "bottomSide" : %s' %side)
topPlateLayer_width = dummyRingElement[0].getTopPlateRLayerWidth()
bottomPlateLayer_width = dummyRingElement[0].getBotPlateRLayerWidth()
topPlateCutNumber = CapacitorUnit.cutMaxNumber( self, topPlateLayer_width , self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut )
bottomPlateCutNumber = CapacitorUnit.cutMaxNumber( self, bottomPlateLayer_width, self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut )
topPlateCutEnclosure = (topPlateLayer_width - topPlateCutNumber *self.minWidth_vRoutingTrackCut - (topPlateCutNumber - 1)*self.minSpacing_vRoutingTrackCut)/2
# bottomPlateCutEnclosure = (bottomPlateLayer_width - bottomPlateCutNumber*self.minWidth_vRoutingTrackCut - (bottomPlateCutNumber - 1)*self.minSpacing_vRoutingTrackCut)/2
topPlateCutEnclosure = (topPlateLayer_width - topPlateCutNumber *self.minWidth_vRoutingTrackCut - (topPlateCutNumber - 1)*self.minSpacing_vRoutingTrackCut)/2
# bottomPlateCutEnclosure = (bottomPlateLayer_width - bottomPlateCutNumber*self.minWidth_vRoutingTrackCut - (bottomPlateCutNumber - 1)*self.minSpacing_vRoutingTrackCut)/2
netsDistribution = self.__setPlatesIds__()
@ -672,37 +672,37 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
for j in range(0,len(dummyRingElement)):
topPlateCutXCenter = dummyRingElement[j].getTopPlateRLayerXMin () + topPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2
bottomPlateLeftCutXCenter = dummyRingElement[j].getBottomPlateLeftCutXMin() #dummyRingElement[j].getBotPlateLeftRLayerXMin () + bottomPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2
bottomPlateRightCutXCenter = dummyRingElement[j].getBottomPlateRightCutXMin() #dummyRingElement[j].getBotPlateRightRLayerXMin() + bottomPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2f
bottomPlateRightCutXCenter = dummyRingElement[j].getBottomPlateRightCutXMin() #dummyRingElement[j].getBotPlateRightRLayerXMin() + bottomPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2f
CapacitorUnit.cutLine( self, dummyNet, cutLayer, topPlateCutXCenter , self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_vRoutingTrackCut,self.minWidth_vRoutingTrackCut,self.minSpacing_vRoutingTrackCut,topPlateCutNumber,'horizontal')
CapacitorUnit.cutLine( self, dummyNet, cutLayer, bottomPlateLeftCutXCenter , self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_vRoutingTrackCut,self.minWidth_vRoutingTrackCut,self.minSpacing_vRoutingTrackCut,bottomPlateCutNumber,'horizontal')
CapacitorUnit.cutLine( self, dummyNet, cutLayer, bottomPlateRightCutXCenter, self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_hRoutingTrackCut,self.minWidth_hRoutingTrackCut,self.minSpacing_hRoutingTrackCut,bottomPlateCutNumber,'horizontal')
CapacitorUnit.cutLine( self, dummyNet, cutLayer, topPlateCutXCenter , self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_vRoutingTrackCut,self.minWidth_vRoutingTrackCut,self.minSpacing_vRoutingTrackCut,topPlateCutNumber,'horizontal')
CapacitorUnit.cutLine( self, dummyNet, cutLayer, bottomPlateLeftCutXCenter , self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_vRoutingTrackCut,self.minWidth_vRoutingTrackCut,self.minSpacing_vRoutingTrackCut,bottomPlateCutNumber,'horizontal')
CapacitorUnit.cutLine( self, dummyNet, cutLayer, bottomPlateRightCutXCenter, self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_hRoutingTrackCut,self.minWidth_hRoutingTrackCut,self.minSpacing_hRoutingTrackCut,bottomPlateCutNumber,'horizontal')
return
## Iteratively performs top plates stretching for the capacitor matrix.
# Vertical segments are connected to top plate routing layer.
# \param capacitor Capacitor matrix.
# \param rlayer Layer of the drawn vertical rectangle.
# Vertical segments are connected to top plate routing layer.
# \param capacitor Capacitor matrix.
# \param rlayer Layer of the drawn vertical rectangle.
def __stretchTopPlates__( self, capacitor, rlayer ):
for i in range( 0, self.matrixDim["rows"] ):
for j in range( 0, self.matrixDim["columns"] ):
t = self.nets[self.matchingScheme[i][j]][0]
#print('t',t)
self.__stretchTopPlateCompactCap__( t , capacitor[i][j], rlayer, j )
self.__stretchTopPlateCompactCap__( t , capacitor[i][j], rlayer, j )
return
## Draws vertical stretched layers for a given elementary capacitor.
## Draws vertical stretched layers for a given elementary capacitor.
def __stretchTopPlateCompactCap__( self, net, capacitor, routingLayer, j = 0 ):
topPlateRLayer_width = capacitor.getTopPlateRLayerWidth()
topPlateRLayer_width = capacitor.getTopPlateRLayerWidth()
topPlateRLayerXCenter = capacitor.getTopPlateRLayerXCenter()
[ dySource , dyTarget ] = self.__setStretchingDySourceDyTarget__( capacitor, self.topPlateStretching )
@ -711,7 +711,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
, int(topPlateRLayerXCenter)
, int(topPlateRLayer_width)
, int(dySource)
, int(dyTarget) )
, int(dyTarget) )
return
@ -719,20 +719,20 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
## Sets the abcissas of the extremities of the vertical stretching to be applied to capacitor's top plates for a given elementary capacitor in the matrix.
# \param capacitor .values() Elementary unit capacitor.
# \param deltay Stretching value.
# \return A list that contains \c dySource and \dyTarget as top extremity and bottom extermity, respectively.
# \return A list that contains \c dySource and \c dyTarget as top extremity and bottom extermity, respectively.
def __setStretchingDySourceDyTarget__( self, capacitor, deltay ):
dySource = capacitor.getTopPlateRLayerYMin()
dyTarget = dySource - deltay
dySource = capacitor.getTopPlateRLayerYMin()
dyTarget = dySource - deltay
return [ dySource , dyTarget ]
## Computes horizontal routing layers source and target abcissas for top and bottom plates connections to its associated routing track.
## Computes horizontal routing layers source and target abcissas for top and bottom plates connections to its associated routing track.
# \param (i,j) row and column indexes, respectively, in the matrix which describe the elementary capacitor position in the matrix.
# \param capacitorIdentifier equal to '1' if C1 and '2' if C2.
# \return A nested dicitionary. The overal dictionary is composed of keys equal to \c topPlate and \d bottomPlate and values equal to sub-dictionaries. The sub-dictionaries, are in their turn composed of two keys standing for the abcissa of the source and the abcissa of the target.
# \remark Naturally, an exception is raised if an unsupported capacitor identifier is given.
# \return A nested dicitionary. The overal dictionary is composed of keys equal to \c topPlate and \d bottomPlate and values equal to sub-dictionaries. The sub-dictionaries, are in their turn composed of two keys standing for the abcissa of the source and the abcissa of the target.
# \remark Naturally, an exception is raised if an unsupported capacitor identifier is given.
def __computeConnections__( self, i,j, capacitorIdentifier ):
@ -748,17 +748,17 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
leftVRTIds = self.capacitorIds[self.capacitorsNumber//2 : self.capacitorsNumber ] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[int(self.capacitorsNumber//2+1) : self.capacitorsNumber ]
rightVRTIds = self.capacitorIds[0 : self.capacitorsNumber//2 ] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[0 : int(self.capacitorsNumber//2+1)]
[topPlateLabel, bottomPlateLabel ] = [self.__setPlatesLabels__(i,j)["t"] , self.__setPlatesLabels__(i,j)["b"]]
dxDict["topPlate" ][ "source" ] = self.capacitor[i][j].getTopPlateRLayerXMax () if self.matchingScheme[i][j] in leftVRTIds else self.capacitor[i][j].getTopPlateRLayerXMin()
dxDict["topPlate" ][ "source" ] = self.capacitor[i][j].getTopPlateRLayerXMax () if self.matchingScheme[i][j] in leftVRTIds else self.capacitor[i][j].getTopPlateRLayerXMin()
dxDict["topPlate" ][ "target" ] = self.__findHRLDyTrarget__( i,j, topPlateLabel, leftVRTIds, rightVRTIds )
dxDict["bottomPlate" ][ "source" ] = self.capacitor[i][j].getBotPlateLeftRLayerXMax () if self.matchingScheme[i][j] in leftVRTIds else self.capacitor[i][j].getBotPlateRightRLayerXMin ()
dxDict["bottomPlate" ][ "source" ] = self.capacitor[i][j].getBotPlateLeftRLayerXMax () if self.matchingScheme[i][j] in leftVRTIds else self.capacitor[i][j].getBotPlateRightRLayerXMin ()
# bottomPlateLabel = 'b' if self.dummyElement == False or not( self.__isCapacitorAdummy__(capacitorIdentifier) ) else 't'
#print("bottomPlateLabel",bottomPlateLabel)
dxDict["bottomPlate" ][ "target" ] = self.__findHRLDyTrarget__( i, j, bottomPlateLabel, leftVRTIds, rightVRTIds )
else : raise Error(1, '__computeConnections__(): Unknown capacitor Id : %s.' %capacitorIdentifier )
#print('dxDict',dxDict)
@ -767,7 +767,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
def __isCapacitorAdummy__( self, capacitorIdentifier ) :
state = False
state = False
if self.dummyElement == True :
if capacitorIdentifier == self.capacitorIds[-1] : state = True
else : raise Error(1,'The matrix contains no dummies because dummy element is "False".')
@ -779,7 +779,7 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
def __setPlatesLabels__( self, i, j ):
platesLabels = {}
capacitorIdentifier = self.matchingScheme[i][j]
capacitorIdentifier = self.matchingScheme[i][j]
platesLabels["t"] = 't'
platesLabels["b"] = 'b' if self.dummyElement == False or not( self.__isCapacitorAdummy__(capacitorIdentifier) ) else 't'
@ -791,13 +791,13 @@ class RoutMatchedCapacitor( VerticalRoutingTracks ):
if plateLabel in ['t','b'] :
plateIndex = self.matchingScheme[i][j]
[ doLeft , doRight ] = [1,0] if self.matchingScheme[i][j] in leftVRTIds else [0,1]
xCenterList = leftVRTIds if [ doLeft , doRight ] == [1,0] else rightVRTIds
[ doLeft , doRight ] = [1,0] if self.matchingScheme[i][j] in leftVRTIds else [0,1]
xCenterList = leftVRTIds if [ doLeft , doRight ] == [1,0] else rightVRTIds
index1 = j if [ doLeft , doRight ] == [1,0] else j+1
for key in self.vRoutingTrackXCenter[index1].keys() :
if key == plateLabel + str(plateIndex) :
index2 = key
index2 = key
break
else : raise Error(1,'__findHRLDyTrarget__() : Plate label must be "t" for top plate and "b" for bottom plate. The given label is : %s.' %plateLabel)
@ -851,10 +851,10 @@ def scriptMain( **kw ):
bottomPlate_net1 = Net.create( Device, 'b1' )
bottomPlate_net2 = Net.create( Device, 'b2' )
bottomPlate_net3 = Net.create( Device, 'b3' )
bottomPlate_net0.setExternal( True )
bottomPlate_net1.setExternal( True )
bottomPlate_net2.setExternal( True )
bottomPlate_net3.setExternal( True )
bottomPlate_net0.setExternal( True )
bottomPlate_net1.setExternal( True )
bottomPlate_net2.setExternal( True )
bottomPlate_net3.setExternal( True )
b0 = Device.getNet("b0")
b1 = Device.getNet("b1")
b2 = Device.getNet("b2")
@ -864,10 +864,10 @@ def scriptMain( **kw ):
topPlate_net1 = Net.create( Device, 't1' )
topPlate_net2 = Net.create( Device, 't2' )
topPlate_net3 = Net.create( Device, 't3' )
topPlate_net0.setExternal( True )
topPlate_net1.setExternal( True )
topPlate_net2.setExternal( True )
topPlate_net3.setExternal( True )
topPlate_net0.setExternal( True )
topPlate_net1.setExternal( True )
topPlate_net2.setExternal( True )
topPlate_net3.setExternal( True )
t0 = Device.getNet("t0")
t1 = Device.getNet("t1")
t2 = Device.getNet("t2")
@ -876,7 +876,7 @@ def scriptMain( **kw ):
if editor:
UpdateSession.close()
editor.setCell( Device )
editor.fit()
editor.fit()
UpdateSession.open()
nets = [[t0, b0] , [t1, b1], [t2, b2] ] # [t3, b3] ]
@ -888,14 +888,14 @@ def scriptMain( **kw ):
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 93, matchingMode = True, matchingScheme = [ ['C2','C2','C1','C2'] , ['C1','C2','C2','C1'] , ['C1','C1','C2','C3'] , ['C1','C1','C2','C3'] ] )
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, matrixDim = [5,5] , matchingMode = True, matchingScheme = [ ['C2','C1','C2','C3','C1'] , ['C1','C2','C4','C3','C2'] , ['C4','C2','C2','C3', 'C1'] , ['C1','C2','C2','C1', 'C1'], ['C2','C2','C3','C2','C4'] ] )
capacitor = capacitorInstance.create()
capacitor = capacitorInstance.create()
#print('capa',capacitor)
capWithVRT = VerticalRoutingTracks( capacitorInstance, capacitor, True )
capWithVRT = VerticalRoutingTracks( capacitorInstance, capacitor, True )
capWithVRT.create()
routedCap = RoutMatchedCapacitor( capWithVRT )
surface = routedCap.route()
surface = routedCap.route()
#print('routeMatchedCap bbMode', surface)
#print('width', toPhY(surface["width"]))
#print('height', toPhY(surface["height"]))

View File

@ -1,6 +1,6 @@
#!/usr/bin/python
import sys
import sys
import numpy
from math import sqrt, ceil
from ..Hurricane import *
@ -14,7 +14,7 @@ from .capacitormatrix import CapacitorStack
## Route a compact or a matrix of capacitors by connecting it to routing tracks.
# For a fixed instance, only one type of capacitor is supported at a time,
# either the Poly-Poly type or Metal-Metal in 350 nm AMS CMOS technology.
# either the Poly-Poly type or Metal-Metal in 350 nm AMS CMOS technology.
#
# The dummy mode is also supported.
# The dummyRing mode is not yet supported.
@ -33,8 +33,8 @@ class RouteCapacitorSingle ( CapacitorUnit ):
rules = getRules()
## The constructor computes some of the class attributes and initialises others which
# will be computed later inside some of the class methods.
# \param device The Hurricane AMS device into which the layout is drawn.
# will be computed later inside some of the class methods.
# \param device The Hurricane AMS device into which the layout is drawn.
# \param capacitorInstance Instance of the class CapacitorMatrix.
# \param capacitor A nested list containing a compact capacitor
# (in the first element) or elementary capacitors of
@ -43,21 +43,21 @@ class RouteCapacitorSingle ( CapacitorUnit ):
# \param capacitorType Can be MIM or PIP type capacitor.
# \param abutmentBox The abutment box of the compact or matrix capacitor.
# \param routingTrackYCenter A nested dictionary containing the ordinates of top and
# bottom ( including upper and lower) routing tracks.
# \param xPlateRLayerXCenter A nested dictionary containing
# bottom ( including upper and lower) routing tracks.
# \param xPlateRLayerXCenter A nested dictionary containing
# \param xPlateRLayer_width A dictionary containing the widths of the top and bottom
# plates routing layers.
# \param routingTrack_width The width of a routing track. Is fixed according to
# technological parameters.
# \param tracksNumbers A dictionary containing the number of top and bottom tracks.
# The allowed maximum total number of tracks is two.
# The allowed maximum total number of tracks is two.
# \param topPlateWSpec Routing specifications for the top plates.
# \param bottomPlateWSpec Routing specifications for the bottom plates.
#
# \remarks An exception is raised if the entered routing specifications are invalid.
# Invalidity can be due to a wrong total number of tracks or bad wiring
# specifications of top and bottom tracks. More information about the valid
# specifications are given in \c function.
# specifications are given in \c function.
def __init__ ( self, capacitorInstance, capacitor, dummyMode = False, tracksNumbers = [1,1], topPlateWSpec = [1,0] , bottomPlateWSpec = [0,1] ):
@ -75,9 +75,9 @@ class RouteCapacitorSingle ( CapacitorUnit ):
self.abutmentBox_spacing = self.capacitorInstance.getAbutmentBox_spacing ()
self.bondingBox = Box()
self.capacitorType = capacitorInstance.capacitorType
self.nets = capacitorInstance.nets[0]
self.nets = capacitorInstance.nets[0]
self.routingTracksXMinXMax = {}
self.routingTracksXMinXMax = {}
self.routingTrackYCenter = { "top": {}, "bottom": {} }
self.xPlateRLayerXCenter = { "top": [], "bottom": [], "bottomBorders" : [] }
self.xPlateRLayer_width = {}
@ -93,11 +93,11 @@ class RouteCapacitorSingle ( CapacitorUnit ):
if self.connectToTopTracksOnly() :
self.topPlateWSpec = [1,0]
elif self.connectToBottomTracksOnly() :
elif self.connectToBottomTracksOnly() :
self.topPlateWSpec = [0,1]
else :
self.topPlateWSpec = [1,1]
else :
self.topPlateWSpec = [1,1]
self.bottomPlateWSpec = self.topPlateWSpec
@ -105,7 +105,7 @@ class RouteCapacitorSingle ( CapacitorUnit ):
self.topPlateWSpec = topPlateWSpec
self.bottomPlateWSpec = bottomPlateWSpec
else : raise Error(1,'__init__() : Invalid routing specifications in terms of number, format or routing scheme.')
else : raise Error(1,'__init__() : Invalid routing specifications in terms of number, format or routing scheme.')
else : raise Error(1,' __init__() : One routing track on one or both sides of the capacitor is allowed in dummy mode. Otherwise, routing tracks can be drawn one on each side or two on one side : (top trak number : %s, bottom track number : %s and dummy mode is %s). ' %( tracksNumbers[0], tracksNumbers[1], dummyMode )) #com verify the difference between a simple print and the dicitionary self.trackingNumber
@ -163,17 +163,17 @@ class RouteCapacitorSingle ( CapacitorUnit ):
# - the minimum spacing between the routing tracks according to their metal layer,
# - the minimum width of a plate, a cut or a routing metal,
# - the minimum width, height and spacing between the cuts on the routing track.
# - etc.
# - etc.
#
# At the exception of the minimum spacing between routing tracks, every rule has
# two possible values according to the capacitor type.
# \remarks An exception is raised if the entered capacitor type is unsupported.
def setRules ( self ):
CapacitorUnit.setRules( self )
CapacitorUnit.setRules( self )
self.minSpacing_routingTrackMetal = RouteCapacitorSingle.rules.minSpacing_metal2
if self.capacitorType == 'MIMCap' :
if self.capacitorType == 'MIMCap' :
self.minHeight_routingTrackcut = RouteCapacitorSingle.rules.minWidth_cut2
self.minSpacing_routingTrackcut = RouteCapacitorSingle.rules.minSpacing_cut2
self.minWidth_routingTrackcut = RouteCapacitorSingle.rules.minWidth_cut2
@ -185,14 +185,14 @@ class RouteCapacitorSingle ( CapacitorUnit ):
return
## Checks if the wiring specifications are compatible with the possible routing schemes.
## Checks if the wiring specifications are compatible with the possible routing schemes.
# \return \c "True" if all conditions are satisfied.
# \param topWiringSpec The desired connection of the top plate.
# \param bottomWiringSpec The desired connection of the top plate.
# \param topWiringSpec The desired connection of the top plate.
# \param bottomWiringSpec The desired connection of the top plate.
# \param possibleRoutingSchemes A list of the possible connections computed according
# to routing tracks specifications.
# to routing tracks specifications.
def __isWiringSpecOK__ ( self, topPlateWiringSpec, bottomPlateWiringSpec, possibleRoutingSchemes ):
def __isWiringSpecOK__ ( self, topPlateWiringSpec, bottomPlateWiringSpec, possibleRoutingSchemes ):
state = False
if len(topPlateWiringSpec ) == len( bottomPlateWiringSpec ) == 2 and [ topPlateWiringSpec, bottomPlateWiringSpec ] in possibleRoutingSchemes :
@ -204,10 +204,10 @@ class RouteCapacitorSingle ( CapacitorUnit ):
## Builds and retuns a list containing the possible routing schemes according to routing tracks specifications. All the possibilities are summarized in Table 1.
# \param topTrackNumber The specified number of top routing tracks. Two tracks are defined : the lower and upper ones. Considering a maximum number of top and bottom tracks equal to two, \c topTracksNumber takes 0, 1, 2 when \c bottomTrackNumber is equal to 2, 1, 0, respectively.
## Builds and returns a list containing the possible routing schemes according to routing tracks specifications. All the possibilities are summarized in Table 1.
# \param topTrackNumber The specified number of top routing tracks. Two tracks are defined : the lower and upper ones. Considering a maximum number of top and bottom tracks equal to two, \c topTracksNumber takes 0, 1, 2 when \c bottomTrackNumber is equal to 2, 1, 0, respectively.
# \param bottomTrackNumber The specified number of bottom routing tracks. The same rules and specifications as top tracks apply to bottom tracks.
# \param possibleRoutingSchemes A list of the possible connections computed according to routing tracks specifications.
# \param possibleRoutingSchemes A list of the possible connections computed according to routing tracks specifications.
def __setPossibleRoutingSchemes__( self, tracksNumbers ):
@ -220,19 +220,19 @@ class RouteCapacitorSingle ( CapacitorUnit ):
## Checks if the tracks numbers are valid. The requirements which must be satifsied are :
# - A maximum number of total tracks equal to two (ie., the sum of bottom tracks number and top tracks number must be equal to 2).
# - The specified numbers for top and bottom tracks belong to the set \c {0,1,2}. Therefore, if the sum is equal to two and one or both numbers are not in {0,1,2}, this is considered as invalid.
## Checks if the tracks numbers are valid. The requirements which must be satifsied are :
# - A maximum number of total tracks equal to two (ie., the sum of bottom tracks number and top tracks number must be equal to 2).
# - The specified numbers for top and bottom tracks belong to the set \c {0,1,2}. Therefore, if the sum is equal to two and one or both numbers are not in {0,1,2}, this is considered as invalid.
# \return \c "True" if all conditions are satisfied.
# \param topTrackNumber The specified number for top tracks.
# \param topTrackNumber The specified number for bottom tracks.
# \throw <object> Wrong values for routing tracks
def __isRoutingTracksNumberOK__ ( self, tracksNumbers ):
# \throw <object> Wrong values for routing tracks
def __isRoutingTracksNumberOK__ ( self, tracksNumbers ):
[topTrackNumber , bottomTrackNumber] = [tracksNumbers[0] , tracksNumbers[1]]
state = False
if self.dummyMode == True:
if ( bottomTrackNumber == 1 and topTrackNumber == 0 or bottomTrackNumber == 0 and topTrackNumber == 1 or bottomTrackNumber == 1 and topTrackNumber == 1 ) :
if ( bottomTrackNumber == 1 and topTrackNumber == 0 or bottomTrackNumber == 0 and topTrackNumber == 1 or bottomTrackNumber == 1 and topTrackNumber == 1 ) :
state = True
elif self.dummyMode == False:
@ -267,7 +267,7 @@ class RouteCapacitorSingle ( CapacitorUnit ):
ab.inflate( 0, plateSpacing )
self.device.setAbutmentBox( ab )
trace( 101, '\tAB height after plate inflate: {0} {1}\n'.format( DbU.getValueString(ab.getHeight()), ab.getHeight() ))
height = ab.getHeight()
heightAdjust = height % (2*self.hpitch)
if heightAdjust:
@ -295,8 +295,8 @@ class RouteCapacitorSingle ( CapacitorUnit ):
self.routingTrack_width = 2 * self.minEnclo_routingTrackMetal_cut \
+ self.minWidth_routingTrackcut
if not bbMode :
self.xPlateRLayer_width["top"] = self.capacitor.getTopPlateRLayerWidth() if self.capacitorInstance.matrixDim.values() == [1,1] else self.capacitor[0][0].getTopPlateRLayerWidth()
if not bbMode :
self.xPlateRLayer_width["top"] = self.capacitor.getTopPlateRLayerWidth() if self.capacitorInstance.matrixDim.values() == [1,1] else self.capacitor[0][0].getTopPlateRLayerWidth()
if self.capacitorInstance.__isUnitCap__() :
self.computeRLayersDimensionsCompactCap ()
@ -311,17 +311,17 @@ class RouteCapacitorSingle ( CapacitorUnit ):
self.xPlateRLayer_width ["bottom" ] = []
self.xPlateRLayerXCenter["bottom" ] = []
self.xPlateRLayerXCenter["top" ].append( self.capacitor.getTopPlateRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor.getBotPlateLeftRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor.getBotPlateRightRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor.getBotPlateLeftRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor.getBotPlateRightRLayerXCenter () )
return
def computeRLayersDimensionsMatrixCap( self ):
if self.capacitorInstance.matrixDim["columns"] > 1 :
if self.capacitorInstance.matrixDim["columns"] > 1 :
self.xPlateRLayer_width["bottom"] = ( self.capacitor[0][1].getBotPlateLeftRLayerXMax() - self.capacitor[0][0].getBotPlateRightRLayerXMin() )
self.bordersRLayerXMin = [ self.capacitor[0][0].getBottomPlateLeftCutXMin(), self.capacitor[0][-1].getBottomPlateRightCutXMin() ]
elif self.capacitorInstance.matrixDim["columns"] == 1 :
elif self.capacitorInstance.matrixDim["columns"] == 1 :
self.bordersRLayerXMin = [ self.capacitor[0][0].getBottomPlateLeftCutXMin(), self.capacitor[0][0].getBottomPlateRightCutXMin() ]
else : raise Error( 1, 'computeRLayersDimensionsMatrixCap() : Negative number of columns in the matrix "%s".' % self.capacitorInstance.matrixDim["columns"] )
@ -334,23 +334,23 @@ class RouteCapacitorSingle ( CapacitorUnit ):
self.xPlateRLayerXCenter["bottom"].append( self.capacitor[0][i].getBotPlateRightRLayerXMin() + self.xPlateRLayer_width["bottom"]/2 )
if self.capacitorInstance.matrixDim["columns"] > 1 :
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][ 0].getBotPlateLeftRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][-1].getBotPlateRightRLayerXCenter() )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][ 0].getBotPlateLeftRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][-1].getBotPlateRightRLayerXCenter() )
else :
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][0].getBotPlateLeftRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][0].getBotPlateRightRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][0].getBotPlateLeftRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][0].getBotPlateRightRLayerXCenter () )
return
## Actual function that computes routing tracks dimensions and positions.
## Actual function that computes routing tracks dimensions and positions.
def computeHRoutingTrackDimensions( self ):
trace( 101, ',+', '\tcomputeHRoutingTrackDimensions(): ab {0}\n'.format(self.device.getAbutmentBox()) )
self.routingTracksXMinXMax = { "XMin" : self.abutmentBox.getXMin()
, "XMax" : self.abutmentBox.getXMax() }
if self.dummyMode:
if self.connectToTopTracksOnly():
yTL = self.abutmentBox.getYMax()
@ -380,7 +380,7 @@ class RouteCapacitorSingle ( CapacitorUnit ):
, "YMax" : yBU + self.routingTrack_width/2 }
else:
if self.connectToTopTracksOnly() :
if self.connectToTopTracksOnly() :
yTL = self.abutmentBox.getYMax()
yTU = yTL + self.hpitch
@ -392,7 +392,7 @@ class RouteCapacitorSingle ( CapacitorUnit ):
self.topUpperTrackDict = { "YMin" : yTU - self.routingTrack_width/2
, "YMax" : yTU + self.routingTrack_width/2}
elif self.connectToBottomTracksOnly():
elif self.connectToBottomTracksOnly():
yBU = self.abutmentBox.getYMin()
yBL = yBU - self.hpitch
@ -404,7 +404,7 @@ class RouteCapacitorSingle ( CapacitorUnit ):
self.bottomLowerTrackDict = { "YMin" : yBL - self.routingTrack_width/2
, "YMax" : yBL + self.routingTrack_width/2 }
elif self.connectToTopAndBottomTracks():
elif self.connectToTopAndBottomTracks():
yTL = self.abutmentBox.getYMax()
yBU = self.abutmentBox.getYMin()
@ -429,38 +429,38 @@ class RouteCapacitorSingle ( CapacitorUnit ):
def computeLayoutDimensionsInbbMode( self ):
bondingBoxDict = {}
bondingBoxDict["width" ] = self.routingTracksXMinXMax["XMax"] - self.routingTracksXMinXMax["XMin"]
bondingBoxDict["width" ] = self.routingTracksXMinXMax["XMax"] - self.routingTracksXMinXMax["XMin"]
bondingBoxDict["XMin" ] = self.routingTracksXMinXMax["XMin"]
if self.dummyMode == True :
if self.connectToTopTracksOnly () :
if self.connectToTopTracksOnly () :
bondingBoxDict["height" ] = self.topLowerTrackDict["YMax"] - self.abutmentBox.getYMin()
bondingBoxDict["YMin" ] = self.abutmentBox.getYMin()
elif self.connectoToBottomTracksOnly() :
elif self.connectoToBottomTracksOnly() :
bondingBoxDict["height" ] = self.abutmentBox.getYMax() - self.bottomUpperTrackDict["YMin"]
bondingBoxDict["YMin" ] = self.bottomUpperTrackDict["YMin"]
else :
else :
bondingBoxDict["height" ] = self.topLowerTrackDict["YMax"] - self.abutmentBox.getYMin()
bondingBoxDict["YMin" ] = self.bottomUpperTrackDict["YMin"]
elif self.dummyMode == False:
if self.connectToTopTracksOnly () :
if self.connectToTopTracksOnly () :
bondingBoxDict["height" ] = self.topUpperTrackDict["YMax"] - self.abutmentBox.getYMin()
bondingBoxDict["YMin" ] = self.abutmentBox.getYMin()
elif self.connectoToBottomTracksOnly() :
elif self.connectoToBottomTracksOnly() :
bondingBoxDict["height" ] = self.abutmentBox.getYMax() - self.bottomLowerTrackDict["YMin"]
bondingBoxDict["YMin" ] = self.bottomLowerTrackDict["YMin"]
else:
else:
bondingBoxDict["height" ] = self.topLowerTrackDict["YMax"] - self.bottomUpperTrackDict["YMin"]
bondingBoxDict["YMin" ] = self.bottomUpperTrackDict["YMin"]
else : raise Error( 1, 'computeLayoutDimensionsInbbMode() : The dummy mode must be either "True" or "False", "%s". ' % self.dummyMode )
else : raise Error( 1, 'computeLayoutDimensionsInbbMode() : The dummy mode must be either "True" or "False", "%s". ' % self.dummyMode )
bondingBoxDict["surface"] = bondingBoxDict["width"]*bondingBoxDict["height"]
@ -469,14 +469,14 @@ class RouteCapacitorSingle ( CapacitorUnit ):
return bondingBoxDict
## Draws routing tracks, above and/or below the capacitor. A maximum total number of two tracks is drawn. In dummy mode, one track is drawn.
## Draws routing tracks, above and/or below the capacitor. A maximum total number of two tracks is drawn. In dummy mode, one track is drawn.
# \param routingTracksLayer Layer of the routing track.
# \remark All routing tracks, top and bottom (upper and lower), are drawn using the same layer.
def drawRoutingTracks( self , routingTracksLayer ):
self.drawTopOrBottomRoutingTracks ( "top" , routingTracksLayer )
self.drawTopOrBottomRoutingTracks ( "bottom", routingTracksLayer )
self.drawTopOrBottomRoutingTracks ( "top" , routingTracksLayer )
self.drawTopOrBottomRoutingTracks ( "bottom", routingTracksLayer )
return
@ -484,7 +484,7 @@ class RouteCapacitorSingle ( CapacitorUnit ):
def drawTopOrBottomRoutingTracks ( self, tracksPosition, routingTracksLayer ) :
trace( 101, ',+', '\tRouteCapacitorSingle.drawTopOrBottomRoutingTracks()\n' )
if tracksPosition in ["top","bottom"] :
attribut = [ "lower", "upper" ]
attribut = [ "lower", "upper" ]
nets = self.__setNetsDistributionHRTs__()
for i in range( 0, self.tracksNumbers[tracksPosition] ):
index = i if tracksPosition == "top" else i-1
@ -492,7 +492,7 @@ class RouteCapacitorSingle ( CapacitorUnit ):
trace( 101, '\ttrackPos={0}, index={1}, attribute={2}\n'.format( tracksPosition
, index
, attribut[index] ))
routingtrackYCenter = self.routingTrackYCenter[tracksPosition][attribut[index]]
routingtrackYCenter = self.routingTrackYCenter[tracksPosition][attribut[index]]
horizontal = Horizontal.create( nets[netindex]
, routingTracksLayer
, routingtrackYCenter
@ -515,7 +515,7 @@ class RouteCapacitorSingle ( CapacitorUnit ):
else:
if (self.topPlateWSpec, self.bottomPlateWSpec) == ([1,0], [0,1]):
netsDistribution = self.nets
else:
else:
netsDistribution = [ self.nets[1], self.nets[0] ]
trace( 101, '\tnetsDistribution = [ {0}, {1} ]\n'.format( netsDistribution[0].getName()
, netsDistribution[1].getName() ))
@ -528,8 +528,8 @@ class RouteCapacitorSingle ( CapacitorUnit ):
# \param Plate The capacitor's plate to be routed (ie., top, bottom).
# \paramx PlateRLayer Routing layer.
# \param PlateWSpec Connection specifications of the plate.
# \param xPlateRLayerXCenter Horizontal position of the routing layer.
# \param xPlateRLayer_width Width of the routing layer.
# \param xPlateRLayerXCenter Horizontal position of the routing layer.
# \param xPlateRLayer_width Width of the routing layer.
# \throw < plate-name > \c Undefined \c plate
# \throw < specification > \c Invalid \c routing \c specifications
@ -545,8 +545,8 @@ class RouteCapacitorSingle ( CapacitorUnit ):
if ( Plate == 'topPlate' ) :
YMinDict = {
"toTopToUpper" : firstElementInCapacitor.getTopPlateRLayerYMin(),
"toTopToLower" : firstElementInCapacitor.getTopPlateRLayerYMin(),
"toBottomToUpper" : lastElementInCapacitor.getTopPlateRLayerYMax(),
"toTopToLower" : firstElementInCapacitor.getTopPlateRLayerYMin(),
"toBottomToUpper" : lastElementInCapacitor.getTopPlateRLayerYMax(),
"toBottomToLower" : lastElementInCapacitor.getTopPlateRLayerYMax()
}
net = self.nets[0]
@ -555,8 +555,8 @@ class RouteCapacitorSingle ( CapacitorUnit ):
elif ( Plate == 'bottomPlate' ) :
YMinDict = {
"toTopToUpper" : firstElementInCapacitor.getBotPlateRLayerYMin(),
"toTopToLower" : firstElementInCapacitor.getBotPlateRLayerYMin(),
"toBottomToUpper" : lastElementInCapacitor.getBotPlateRLayerYMax(),
"toTopToLower" : firstElementInCapacitor.getBotPlateRLayerYMin(),
"toBottomToUpper" : lastElementInCapacitor.getBotPlateRLayerYMax(),
"toBottomToLower" : lastElementInCapacitor.getBotPlateRLayerYMax()
}
net = self.nets[1]
@ -565,13 +565,13 @@ class RouteCapacitorSingle ( CapacitorUnit ):
else : raise Error( 1, 'drawPlatesVRLayers() : Undefined plate, "%s".' % Plate )
if ( self.connectToTopTracksOnly () and self.connectToUpper( PlateWSpec ) ) :
[ dySource, dyTarget ] = [ YMinDict["toTopToUpper" ] , self.topUpperTrackDict["YMax"] ]
[ dySource, dyTarget ] = [ YMinDict["toTopToUpper" ] , self.topUpperTrackDict["YMax"] ]
elif ( self.connectToTopTracksOnly () and self.connectToLower( PlateWSpec ) ) or ( self.connectToTopAndBottomTracks () and self.connectToUpper( PlateWSpec ) ) :
dyTarget = self.topLowerTrackDict ["YMax"]
dyTarget = self.topLowerTrackDict ["YMax"]
dySource = self.bottomUpperTrackDict["YMin"] if self.dummyMode == True and self.connectToTopAndBottomTracks () else YMinDict["toTopToLower" ]
elif ( self.connectToBottomTracksOnly() and self.connectToUpper( PlateWSpec ) ) or ( self.connectToTopAndBottomTracks () and self.connectToLower( PlateWSpec ) ) :
[ dySource, dyTarget ] = [ YMinDict["toBottomToUpper"] , self.bottomUpperTrackDict["YMin"] ]
[ dySource, dyTarget ] = [ YMinDict["toBottomToUpper"] , self.bottomUpperTrackDict["YMin"] ]
elif ( self.connectToBottomTracksOnly() and self.connectToLower( PlateWSpec ) ) :
[ dySource, dyTarget ] = [ YMinDict["toBottomToLower"] , self.bottomLowerTrackDict["YMin"] ]
@ -579,11 +579,11 @@ class RouteCapacitorSingle ( CapacitorUnit ):
else : raise Error( 1, 'drawPlatesVRLayers() : Invalid routing specifications "%s".' % PlateWSpec )
for i in range( 0, self.matrixDim["columns"] - doBottom ):
Vertical.create ( net, xPlateRLayer, xPlateRLayerXCenter[i], xPlateRLayer_width, dySource, dyTarget )
Vertical.create ( net, xPlateRLayer, xPlateRLayerXCenter[i], xPlateRLayer_width, dySource, dyTarget )
if doBottom :
if doBottom :
for i in range( 0,2):
Vertical.create ( self.nets[1], xPlateRLayer , self.xPlateRLayerXCenter["bottomBorders"][i], self.xPlateRLayer_width["bottomBorders"], dySource, dyTarget )
Vertical.create ( self.nets[1], xPlateRLayer , self.xPlateRLayerXCenter["bottomBorders"][i], self.xPlateRLayer_width["bottomBorders"], dySource, dyTarget )
return
@ -591,9 +591,9 @@ class RouteCapacitorSingle ( CapacitorUnit ):
## Draws one or multiple cuts between a routing track and a routing layer to connect the capacitor plate to the track. The function supports cuts for top and bottom plates. First, using wiring specifications, he position of the cuts is identified. Second, the maximum nupmber of cuts is computed, then, its enclosure in the routing layer is adjusted. Third, the cuts are iteratively drawn on every intersection between the routing track and the plate's routing layer.
# \remark Since in the special case of bottom plate, routing layers on matrix borders are thinner than the intermediate ones, two extra steps are excecuted to draw cuts connecting border routing layers to the routing track. The two steps are computing the maximum number of cuts, which is lower than intermediate cuts, and ajusting its enclosure.
# \throw <Invalid-specifictions > \c Not \c possible \c to \c compute cuts vertical position due to invalid routing specifications
## Draws one or multiple cuts between a routing track and a routing layer to connect the capacitor plate to the track. The function supports cuts for top and bottom plates. First, using wiring specifications, he position of the cuts is identified. Second, the maximum nupmber of cuts is computed, then, its enclosure in the routing layer is adjusted. Third, the cuts are iteratively drawn on every intersection between the routing track and the plate's routing layer.
# \remark Since in the special case of bottom plate, routing layers on matrix borders are thinner than the intermediate ones, two extra steps are excecuted to draw cuts connecting border routing layers to the routing track. The two steps are computing the maximum number of cuts, which is lower than intermediate cuts, and ajusting its enclosure.
# \throw <Invalid-specifictions > \c Not \c possible \c to \c compute cuts vertical position due to invalid routing specifications
# \remak The number of cuts is maximized according to the track's width.
# \param net Net of the Hurricane Device to which the cuts will be connected.
# \param Plate Capacitor's plate, top or bottom.
@ -605,21 +605,21 @@ class RouteCapacitorSingle ( CapacitorUnit ):
def drawCuts( self, net, Plate, PlateWSpec, layer, xPlateRLayer_width, xPlateRLayerXCenter ):
[ doTop, doBottom ] = [1, 0] if Plate == 'topPlate' else [0, 1]
cutsYCenter = self. __setCutsYCenter__( PlateWSpec )
cutsYCenter = self. __setCutsYCenter__( PlateWSpec )
if not( self.capacitorInstance.__isUnitCap__() ) or ( self.capacitorInstance.__isUnitCap__() and doTop ) :
if not( self.capacitorInstance.__isUnitCap__() ) or ( self.capacitorInstance.__isUnitCap__() and doTop ) :
#print("xPlateRLayer_width",xPlateRLayer_width)
cutsNumber = CapacitorUnit.cutMaxNumber( self, xPlateRLayer_width, self.minWidth_routingTrackcut, self.minSpacing_routingTrackcut, self.minEnclo_routingTrackMetal_cut )
enclosure_RLayer_cut = ( xPlateRLayer_width - cutsNumber*self.minWidth_routingTrackcut - ( cutsNumber - 1 )*self.minSpacing_routingTrackcut ) / 2
for i in range( 0, self.matrixDim["columns"] - doBottom ):
for i in range( 0, self.matrixDim["columns"] - doBottom ):
cutXCenter = xPlateRLayerXCenter[i] - xPlateRLayer_width/2 + enclosure_RLayer_cut + self.minWidth_routingTrackcut/2
CapacitorUnit.cutLine( self, net, layer, cutXCenter, cutsYCenter, self.minWidth_routingTrackcut, self.minHeight_routingTrackcut, self.minSpacing_routingTrackcut, cutsNumber , 'horizontal' )
if self.dummyMode == True and self.connectToTopAndBottomTracks() :
CapacitorUnit.cutLine( self, net, layer, cutXCenter, self.routingTrackYCenter["bottom"]["upper"], self.minWidth_routingTrackcut, self.minHeight_routingTrackcut, self.minSpacing_routingTrackcut, cutsNumber , 'horizontal' )
if doBottom :
if doBottom :
borderscutsNumber = CapacitorUnit.cutMaxNumber( self, self.xPlateRLayer_width["bottomBorders"], self.minWidth_routingTrackcut, self.minSpacing_routingTrackcut, self.minEnclo_routingTrackMetal_cut )
enclosure_RLayer_cut = ( self.xPlateRLayer_width["bottomBorders"] - borderscutsNumber*self.minWidth_routingTrackcut - ( borderscutsNumber - 1 )*self.minSpacing_routingTrackcut ) / 2
@ -631,19 +631,19 @@ class RouteCapacitorSingle ( CapacitorUnit ):
def __setCutsYCenter__( self, PlateWSpec ):
def __setCutsYCenter__( self, PlateWSpec ):
if ( self.connectToTopTracksOnly () and self.connectToLower( PlateWSpec ) ) or ( self.connectToTopAndBottomTracks() and self.connectToUpper( PlateWSpec ) ) :
cutsYCenter = self.routingTrackYCenter["top"]["lower"]
elif ( self.connectToTopTracksOnly () and self.connectToUpper( PlateWSpec ) ) :
cutsYCenter = self.routingTrackYCenter["top"]["upper"]
cutsYCenter = self.routingTrackYCenter["top"]["upper"]
elif ( self.connectToBottomTracksOnly() ) and ( self.connectToUpper( PlateWSpec ) ) or ( self.connectToTopAndBottomTracks() and self.connectToLower( PlateWSpec ) ) :
cutsYCenter = self.routingTrackYCenter["bottom"]["upper"]
elif ( self.connectToBottomTracksOnly() and self.connectToLower( PlateWSpec ) ) :
cutsYCenter = self.routingTrackYCenter["bottom"]["lower"]
cutsYCenter = self.routingTrackYCenter["bottom"]["lower"]
else : raise Error( 1, '__setCutsYCenter__() : Not possible to compute cuts vertical position due to invalid routing specifications "%s".' % PlateWSpec )
@ -653,12 +653,12 @@ class RouteCapacitorSingle ( CapacitorUnit ):
## \return \c True if the plate is to be connected to one of the two top tracks.
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
def connectToTopTracksOnly (self) : return True if self.tracksNumbers["top"] == 2 and self.tracksNumbers["bottom"] == 0 and self.dummyMode == False or self.tracksNumbers["top"] == 1 and self.tracksNumbers["bottom"] == 0 and self.dummyMode == True else False
## \return \c True if the plate is to be connected to one of the two bottom tracks.
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
def connectToBottomTracksOnly (self) : return True if self.tracksNumbers["top"] == 0 and self.tracksNumbers["bottom"] == 2 and self.dummyMode == False or self.tracksNumbers["top"] == 0 and self.tracksNumbers["bottom"] == 1 and self.dummyMode == True else False
@ -666,12 +666,12 @@ class RouteCapacitorSingle ( CapacitorUnit ):
## \return \c True if the plate is to be connected to the upper track of top or bottom tracks.
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
def connectToUpper( self, plateWiringSpec ) : return True if plateWiringSpec [1] == 1 else False
## \return \c True if the plate is to be connected to the lower track of top or bottom tracks.
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
def connectToLower( self, plateWiringSpec ) : return True if plateWiringSpec [0] == 1 else False
@ -687,12 +687,12 @@ def scriptMain( **kw ):
Device.setTerminal( True )
bottomPlate_net0 = Net.create( Device, 'b0' )
bottomPlate_net0.setExternal( True )
bottomPlate_net0.setExternal( True )
b0 = Device.getNet("b0")
doBreak( 1, 'Done building bottomPlate')
topPlate_net0 = Net.create( Device, 't0' )
topPlate_net0.setExternal( True )
topPlate_net0.setExternal( True )
t0 = Device.getNet("t0")
doBreak( 1, 'Done building topPlate')
@ -700,35 +700,35 @@ def scriptMain( **kw ):
if editor:
UpdateSession.close()
editor.setCell( Device )
editor.fit()
editor.fit()
UpdateSession.open()
nets = [[t0,b0]]
nets = [[t0,b0]]
## A matrix of unit capacitors (all are active or all are dummy capacitors)
## A matrix of unit capacitors (all are active or all are dummy capacitors)
# capacitance = [1600]
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets,unitCap = 400)
# capacitor = capacitorInstance.create()
#
# routedCap = RouteCapacitorSingle( capacitorInstance, capacitor, dummyMode = True, tracksNumbers = [1,0] )
# routedCap = RouteCapacitorSingle( capacitorInstance, capacitor, tracksNumbers = [2,0], topPlateWSpec = [0,1] , bottomPlateWSpec = [1,0] )
# routedCap = RouteCapacitorSingle( capacitorInstance, capacitor, dummyMode = False , tracksNumbers = [1,1], topPlateWSpec = [0,1] , bottomPlateWSpec = [1,0])
# routedCap = RouteCapacitorSingle( capacitorInstance, capacitor, dummyMode = True, tracksNumbers = [1,0] )
# routedCap = RouteCapacitorSingle( capacitorInstance, capacitor, tracksNumbers = [2,0], topPlateWSpec = [0,1] , bottomPlateWSpec = [1,0] )
# routedCap = RouteCapacitorSingle( capacitorInstance, capacitor, dummyMode = False , tracksNumbers = [1,1], topPlateWSpec = [0,1] , bottomPlateWSpec = [1,0])
## Unit capacitor ( an active capacitor )
capacitance = [600]
capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets,unitCap = 600)
capacitor = capacitorInstance.create()
routedCap = RouteCapacitorSingle( capacitorInstance, capacitor, topPlateWSpec = [0,1] , bottomPlateWSpec = [1,0] )
routedCap = RouteCapacitorSingle( capacitorInstance, capacitor, topPlateWSpec = [0,1] , bottomPlateWSpec = [1,0] )
## Unit capacitor ( a dummy capacitor )
# capacitance = [600]
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets,unitCap = 600)
# capacitor = capacitorInstance.create()
# routedCap = RouteCapacitorSingle( capacitorInstance, capacitor, dummyMode = True, tracksNumbers = [1,0] )
# routedCap = RouteCapacitorSingle( capacitorInstance, capacitor, dummyMode = True, tracksNumbers = [1,0] )
bondingBox = routedCap.route()
bondingBox = routedCap.route()
AllianceFramework.get().saveCell( Device, Catalog.State.Views )

View File

@ -1,6 +1,6 @@
#!/usr/bin/python
import sys
import sys
import numpy
from math import sqrt, ceil
from ..Hurricane import *
@ -19,54 +19,54 @@ def doBreak( level, message ):
UpdateSession.open()
## Draws a capacitor of type Poly-Poly or Metal-Metal in 350 nm AMS CMOS technology.
## Draws a capacitor of type Poly-Poly or Metal-Metal in 350 nm AMS CMOS technology.
# PIP and MIM capacitors are the result of surface superposition between poly1 and poly2 or metal2 and metalcap layers, respectively.
# Given the capacitor value, layout dimensions are computed, then, capacitor layers are drawn. Capacitor value, \f$C\f$, is given in the expression below, where \f$ C_{a}, C_{p}, A \f$ and \f$ P \f$ are, area capacitance, perimeter capacitance, area and permiter of the capacitor, respectively :
# \f[ C = C_{a}A + C_{p}P \f]
# The drawn layout shape is square. Thus, metcap or poly2 length and width are equal and are computed using the capacitor expression. Furthermore, given \f$ C_{a} \f$, \f$ C_{p} \f$ and enclosure technological rules, dimensions and positions of the abutment box as well as the bottom plate are computed. Layouts with dimensions that exceed technological limits cannot be drawn.
class CapacitorUnit():
rules = getRules()
## This is the class constructor. Few of the class attributes final values are computed in this level. Most of attributes are only initialized to zero or empty values. Then, it is computed in dedicated class method. Input parameters are :
# \param device Hurricane AMS device into which layout is drawn.
# \param device Hurricane AMS device into which layout is drawn.
# \param capacitance Capacitor value, expressed in \f$ femto Farad (fF) \f$.
# \param abutmentBoxPosition A list containing abscissa and ordinate of the bottom left corner of the abutment box.
#
# Class attributes are described in the list below. Most of class attributes refer to layout dimensions. Dictionaries are used to group attributes related to the same layout varibale. Layout dimensions and variables are described in Figure 1.
# Class attributes are described in the list below. Most of class attributes refer to layout dimensions. Dictionaries are used to group attributes related to the same layout varibale. Layout dimensions and variables are described in Figure 1.
#
# \param device Hurricane AMS device into which layout is drawn.
# \param device Hurricane AMS device into which layout is drawn.
# \param capacitance Capacitor value, expressed in \f$ femto Farad (fF) \f$.
# \param capacitorType Can be 'MIMCap' or 'PIPCap' as capacitor type.
# \param abutmentBoxDict A dictionary containing abscissa and ordinate of the bottom left corner of the abutment box, (XMin) and (YMin), respectively.
# \param abutmentBox Abutment box drawn square. It is an object of type \c Box.
# \param capacitorType Can be 'MIMCap' or 'PIPCap' as capacitor type.
# \param abutmentBoxDict A dictionary containing abscissa and ordinate of the bottom left corner of the abutment box, (XMin) and (YMin), respectively.
# \param abutmentBox Abutment box drawn square. It is an object of type \c Box.
# \param bottomPlateBox Bottom plate drawn square. It is an object of type \c Box.
# \param topPlateBox Top plate drawn square. It is an object of type \c Box.
# \param cut2MatrixDict A dictionary containing center position of the left bottom, which is cut the first to be drawn in the matrix of cuts. Initially, the dictionary is empty. It is only updated when \c self.capacitorType is equal to \c 'MIMCap'.
# \param cut2MatrixDict A dictionary containing center position of the left bottom, which is cut the first to be drawn in the matrix of cuts. Initially, the dictionary is empty. It is only updated when \c self.capacitorType is equal to \c 'MIMCap'.
#
# \param cutLeftLineDict A dictionary containing abcissa and ordinate of the bottom cut in the left line of cuts to be drawn on bottom plate's layer.
# \param cutLeftLineDict A dictionary containing abcissa and ordinate of the bottom cut in the left line of cuts to be drawn on bottom plate's layer.
# \param cutRightLineDict A dictionary containing abcissa and ordinate of the bottom cut in the right line of cuts to be drawn on bottom plate's layer.
# \param topCutLineDict A dictionary containing abcissa and ordinate of the bottom cut in the right line of cuts to be drawn on top plate's layer. Initially, the dictionary is empty. It is only updated when \c self.capacitorType is equal to \c 'PIPCap'.
# \param topCutLineDict A dictionary containing abcissa and ordinate of the bottom cut in the right line of cuts to be drawn on top plate's layer. Initially, the dictionary is empty. It is only updated when \c self.capacitorType is equal to \c 'PIPCap'.
#
# \param topPlateRLayerDict A dictionary containing position information of the top plate's routing layer. The dictionary includes ordinates of the layer's top and bottom extremities, \c 'XMin' and \c 'YMin', respectively, the abcissa of it's center, \c 'XCenter' and its width, \c 'width'.
# \param topPlateRLayerDict A dictionary containing position information of the top plate's routing layer. The dictionary includes ordinates of the layer's top and bottom extremities, \c 'XMin' and \c 'YMin', respectively, the abcissa of it's center, \c 'XCenter' and its width, \c 'width'.
#
# \param bottomPlateRLayerDict A dictionary containing
# \param enclosure_botPlate_topPlate Top plate's layer encolusre in bottom plate's layer.
# \param minheight_topPlatecut Minimum height of cuts for top plate connection to other metal layer.
# \param topCutLineNumber Maximum possible number cuts to be drawn for top plate's connection.
# \param bottomCutLineNumber Maximum possible number cuts to be drawn for top plate's connection.
#
#
# \remark Abutment box must be defined as an attribute because the position of dummy capacitor in \c NonUnitCapacitor class must be precisely defined.
def __init__( self, device, capacitorType, abutmentBoxPosition, capacitance = 0, capDim = {} ):
self.device = device
self.capacitorType = capacitorType
# self.capDim = self.__computeCapDim__( capacitance, capacitorType )
self.enclosure_botPlate_abtBox = 0
# self.capDim = self.__computeCapDim__( capacitance, capacitorType )
self.enclosure_botPlate_abtBox = 0
self.__initCapDim__( capacitance, capDim )
self.abutmentBoxDict = { "XMin" : abutmentBoxPosition[0], "YMin" : abutmentBoxPosition[1] }
@ -77,13 +77,13 @@ class CapacitorUnit():
self.bottomPlateBoxDict = {}
self.topPlateBoxDict = {}
self.cut2MatrixDict = {}
self.cutLeftLineDict = {}
self.cut2MatrixDict = {}
self.cutLeftLineDict = {}
self.cutRightLineDict = {}
self.topCutLineDict = {}
self.topCutLineDict = {}
self.topPlateRLayerDict = {}
self.bottomPlateRLayerDict = {}
self.topCutLineNumber = {}
self.topCutLineNumber = {}
self.enclosure_botPlate_topPlate = 0
self.minheight_topPlatecut = 0
@ -100,11 +100,11 @@ class CapacitorUnit():
else:
raise Error( 1, [ 'CapacitorUnit.__initCapDim__(): Please check compatibility between capacitance value {0},'.format(capacitance)
, 'and the given capacitor dimensions {0}.'.format(capDim) ] )
elif capacitance == 0 and len(capDim.values()):
self.capDim = capDim
elif capacitance == 0 and len(capDim.values()):
self.capDim = capDim
capacitance = self.__computeCapacitance__( capDim, self.capacitorType )
elif capacitance != 0 and len(capDim.values()) == 0 :
self.capDim = self.__computeCapDim__( capacitance, self.capacitorType )
self.capDim = self.__computeCapDim__( capacitance, self.capacitorType )
else:
raise Error( 1, [ 'CapacitorUnit.__initCapDim__(): Invalid capacitance and/or capacitance dimensions {0}, {1}.'.format(capacitance, capDim)
, 'Please provide at least one valid parameter.' ] )
@ -114,7 +114,7 @@ class CapacitorUnit():
## Sets the area and perimeter capacitances as specified in 350 nm AMS technology and according to \c capacitorType (MIM or PIP).
# \return a list containing the area and perimeter capacitances.
# \remarks An exception is raised if the entered capacitor type is unknown.
def __setCapacitorPerUnit__( self, capacitorType ) :
#print("self.capacitorType",self.capacitorType)
if capacitorType == 'MIMCap':
@ -128,7 +128,7 @@ class CapacitorUnit():
]
else:
raise Error( 1, 'setCapacitorPerUnit() : Unsupported capacitor type : %s.' % capacitorType )
raise Error( 1, 'setCapacitorPerUnit() : Unsupported capacitor type : %s.' % capacitorType )
return [ areaCapacitorPerUnit, perimeterCapacitorPerUnit ]
@ -139,7 +139,7 @@ class CapacitorUnit():
# \return a dictionary containing width and length.
# \remark The capacitor is square. Thus, length and width are equal.
def __computeCapDim__( self, capacitance, capacitorType ) :
def __computeCapDim__( self, capacitance, capacitorType ) :
trace( 101, ',+', '\tCapacitorUnit.__computeCapDim__()\n' )
[a, b, c] = [ self.__setCapacitorPerUnit__( capacitorType )[0]
@ -163,7 +163,7 @@ class CapacitorUnit():
[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = self.__setCapacitorPerUnit__( capacitorType )
areaCapacitance = toPhY(capDim["width"]) * toPhY(capDim["height"]) *areaCapacitorPerUnit
perimeterCapacitance = ( toPhY(capDim["width"]) + toPhY(capDim["height"]) )*perimeterCapacitorPerUnit
capacitance = areaCapacitance + perimeterCapacitance
capacitance = areaCapacitance + perimeterCapacitance
return capacitance
@ -171,7 +171,7 @@ class CapacitorUnit():
## \return \c True if all rules are respected.
# \remark Maximum poly2 layer dimensions for PIP capacitor are not specified in technology rules. Thus, only minimum limit condition is checked.
def __isCapacitorUnitOK__( self, capDim ):
def __isCapacitorUnitOK__( self, capDim ):
errors = []
capaName = 'PIP'
minSide = self.getMinimumCapWidth()
@ -216,12 +216,12 @@ class CapacitorUnit():
return True
## Selects technological rules according to the capacitor type.
# \return a dictionary with rules labels as keys and rules as values.
## Selects technological rules according to the capacitor type.
# \return a dictionary with rules labels as keys and rules as values.
# Example of technology rules are :
# - minimum spacing between cuts or metals,
# - minimum width of a plate, a cut or a routing metal.
# - etc.
# - etc.
# Every rule takes two possible value according to the capacitor type (MIM or PIP).
# Therefore, dictionary keys are generic and its values are specific to the capacitor
# type.
@ -236,7 +236,7 @@ class CapacitorUnit():
self.minWidth_botPlatecut = CapacitorUnit.rules.minWidth_cut2
self.minWidth_routingTrackcut = CapacitorUnit.rules.minWidth_cut2
self.minSpacing_botPlate = CapacitorUnit.rules.minSpacing_metbot
self.minSpacing_botPlate = CapacitorUnit.rules.minSpacing_metbot
self.minSpacing_botPlateCut_topPlate = CapacitorUnit.rules.minSpacing_cut2_metcap
self.minSpacingOnBotPlate_cut = CapacitorUnit.rules.minSpacingOnMetBot_cut2
self.minSpacingOnTopPlate_cut = CapacitorUnit.rules.minSpacingOnMetCap_cut2
@ -254,7 +254,7 @@ class CapacitorUnit():
self.minWidth_botPlatecut = CapacitorUnit.rules.minWidth_cut0
self.minWidth_routingTrackcut = CapacitorUnit.rules.minWidth_cut1
self.minSpacing_botPlate = CapacitorUnit.rules.minSpacing_poly
self.minSpacing_botPlate = CapacitorUnit.rules.minSpacing_poly
self.minSpacing_botPlateCut_topPlate = CapacitorUnit.rules.minSpacing_cut0_cpoly
self.minSpacingOnBotPlate_cut = CapacitorUnit.rules.minSpacing_cut0
self.minSpacingOnTopPlate_cut = CapacitorUnit.rules.minSpacing_cut0
@ -265,7 +265,7 @@ class CapacitorUnit():
self.minEnclo_botPlateRMetal_botPlateCut = CapacitorUnit.rules.minEnclosure_metal1_cut0
self.minEnclo_routingTrackMetal_cut = CapacitorUnit.rules.minEnclosure_metal1_cut1
else:
raise Error( 1, 'CapacitorUnit.setRules(): Unsupported capacitor type {0}.'.format( self.capacitorType ))
raise Error( 1, 'CapacitorUnit.setRules(): Unsupported capacitor type {0}.'.format( self.capacitorType ))
self.minheight_topPlatecut = self.minWidth_topPlatecut
@ -277,7 +277,7 @@ class CapacitorUnit():
self.METAL2Pitch = rg.getHorizontalPitch()
self.METAL3Pitch = rg.getVerticalPitch()
self.isVH = rg.isVH()
foundHor = False
foundVer = False
for depth in range(rg.getDepth()):
@ -296,18 +296,18 @@ class CapacitorUnit():
return
## \return capacitor type \c 'MIMCap' or \c 'PIPCap'.
# \remarks \c getCapacitorType() is especially useful when an instance of \c CapacitorUnit class is called in another classes instances to identify the capacitor's type.
## \return capacitor type \c 'MIMCap' or \c 'PIPCap'.
# \remarks \c getCapacitorType() is especially useful when an instance of \c CapacitorUnit class is called in another classes instances to identify the capacitor's type.
def getCapacitorType ( self ) : return self.capacitorType
## \retun maximum size of capacitor's top plate. \c getMaximumCapWidth() is called to check if capacitor dimensions are within acceptable technological limits.
## \return maximum size of capacitor's top plate. \c getMaximumCapWidth() is called to check if capacitor dimensions are within acceptable technological limits.
# An exception is raised if the entered capacitor type is unknown.
# \remarks 1. This function is especially usefull in drawing the layout of a unity capacitor, where it is important to garantee that the capacitor size does not exeed the maximum possible value. It is also useful when drawing a matrix of capacitors to make sure that also the unity capacitor respects the maximal values specified. \remarks 2. The maximum value of the poly2 size in PIP capacitor is not specified. Thus, it is not considered in \c getMaximumCapWidth()
# \remarks 1. This function is especially usefull in drawing the layout of a unity capacitor, where it is important to garantee that the capacitor size does not exeed the maximum possible value. It is also useful when drawing a matrix of capacitors to make sure that also the unity capacitor respects the maximal values specified. \remarks 2. The maximum value of the poly2 size in PIP capacitor is not specified. Thus, it is not considered in \c getMaximumCapWidth()
def getMaximumCapWidth ( self ) :
def getMaximumCapWidth ( self ) :
if self.capacitorType == 'MIMCap':
maximumCapWidth = CapacitorUnit.rules.maxWidth_metcap
@ -316,15 +316,15 @@ class CapacitorUnit():
maximumCapWidth = None #CapacitorUnit.rules.maxWidth_cpoly
else:
raise Error( 1, 'getMaximumCapWidth() : Unsupported capacitor type : %s.' % self.capacitorType )
raise Error( 1, 'getMaximumCapWidth() : Unsupported capacitor type : %s.' % self.capacitorType )
return maximumCapWidth
## \return The minimum size of the capacitor's top plate. An exception is raised if the entered capacitor type is unknown.
## \return The minimum size of the capacitor's top plate. An exception is raised if the entered capacitor type is unknown.
# \remarks This function is especially usefull in drawing the layout of a matrix of capacitors where it is important to ensure that the unity capacitor respects the minimal values specified. \remarks An exception is raised if the entered capacitor type is unknown.
def getMinimumCapWidth ( self ) :
def getMinimumCapWidth ( self ) :
if self.capacitorType == 'MIMCap':
minimumCapWidth = CapacitorUnit.rules.minWidth_metcap
@ -333,14 +333,14 @@ class CapacitorUnit():
minimumCapWidth = CapacitorUnit.rules.minWidth_cpoly
else:
raise Error( 1, 'getMinimumCapWidth() : Unsupported capacitor type : %s.' % self.capacitorType )
raise Error( 1, 'getMinimumCapWidth() : Unsupported capacitor type : %s.' % self.capacitorType )
return minimumCapWidth
## Loads the technology file then extracts the adequate layers according to the capacitor type (MIM or PIP).
## Loads the technology file then extracts the adequate layers according to the capacitor type (MIM or PIP).
#
# \return a dictionary containing the layer labels as attributes and its values.
# \return a dictionary containing the layer labels as attributes and its values.
# \remarks An exception is raised if the entered capacitor type is unknown.
def getLayers( self ):
@ -353,7 +353,7 @@ class CapacitorUnit():
layerDict["topPlateLayer" ] = technology.getLayer( "metcap" )
layerDict["bottomPlateLayer" ] = technology.getLayer( "metal2" )
layerDict["topPlateRLayer" ] = technology.getLayer( "metal3" )
layerDict["bottomPlateRLayer" ] = technology.getLayer( "metal3" )
layerDict["bottomPlateRLayer" ] = technology.getLayer( "metal3" )
layerDict["topBottomcutsLayer" ] = technology.getLayer( "cut2" )
elif self.capacitorType == 'PIPCap':
@ -361,36 +361,36 @@ class CapacitorUnit():
layerDict["topPlateLayer" ] = technology.getLayer( "poly2" )
layerDict["bottomPlateLayer" ] = technology.getLayer( "poly" )
layerDict["topPlateRLayer" ] = technology.getLayer( "metal1" )
layerDict["bottomPlateRLayer" ] = technology.getLayer( "metal1" )
layerDict["bottomPlateRLayer" ] = technology.getLayer( "metal1" )
layerDict["topBottomcutsLayer" ] = technology.getLayer( "cut0" )
else :
raise Error( 1, 'getLayers() : Unsupported capacitor type : %s.' % self.capacitorType )
else :
raise Error( 1, 'getLayers() : Unsupported capacitor type : %s.' % self.capacitorType )
return layerDict
## When bonding box mode is activated, the function draws all layout physical layers of the capacitor after checking its dimensions. All functions are excecuted in a new Update Session. In the contrary, only an exact estimation of layout dimensions is given. An error is raised when dimensions reach technological limits for MIM and PIP capacitors or when \c bbMode parameters is other than \c True or \c False.
#
#
# \param ( t , b ) nets of top and bottom plates, respectively
# \param bbMode activates bonding box dimensions computing when set to \c True
#
def create( self, t, b, bbMode = False, vEnclosure_botPlate_abtBox = None, hEnclosure_botPlate_abtBox = None ):
UpdateSession.open()
UpdateSession.open()
abutmentBoxDimensions = None
self.setRules ()
if self.__isCapacitorUnitOK__( self.capDim ) == True :
if self.__isCapacitorUnitOK__( self.capDim ) == True :
self.computeDimensions ( self.capDim, vEnclosure_botPlate_abtBox, hEnclosure_botPlate_abtBox )
self.drawAbutmentBox ()
#self.device.setAbutmentBox( self.abutmentBox )
if bbMode == True :
abutmentBoxDimensions = self.abutmentBoxDict
abutmentBoxDimensions = self.abutmentBoxDict
elif bbMode == False :
layerDict = self.getLayers()
@ -401,12 +401,12 @@ class CapacitorUnit():
else : raise Error(1, 'creat(): Impossible to draw the capacitor, dimensions are either too large or too small, "%s".' % self.capDim )
UpdateSession.close()
return abutmentBoxDimensions
## Draws all layout physicial layers of the capacitor.
## Draws all layout physicial layers of the capacitor.
#
# \param layerDict a dictionary containing a description of the required physical layers according to capacitor type
# \param ( t , b ) nets of top and bottom plates, respectively
@ -414,24 +414,24 @@ class CapacitorUnit():
def drawCapacitor( self, layerDict, t, b ):
self.bottomPlateBox = self.drawOnePlate( layerDict["bottomPlateLayer" ] , b , self.bottomPlateBoxDict )
self.topPlateBox = self.drawOnePlate( layerDict["topPlateLayer" ] , t , self.topPlateBoxDict )
self.bottomPlateBox = self.drawOnePlate( layerDict["bottomPlateLayer" ] , b , self.bottomPlateBoxDict )
self.topPlateBox = self.drawOnePlate( layerDict["topPlateLayer" ] , t , self.topPlateBoxDict )
self.drawBottomPlateCut ( layerDict["topBottomcutsLayer"] , b )
self.drawTopPlateCut ( layerDict["topBottomcutsLayer"] , t )
self.drawRoutingLayers ( layerDict["bottomPlateRLayer" ] , layerDict["topPlateRLayer"] , t , b )
return
return
## Computes needed parameters to draw bottom plate cuts in its exact position, including :
#
# - maximum number of cuts to draw on both sides of bottom plate,
# - adjusted enclosure of
# - adjusted enclosure of
# - abcissas of the two bottom cuts on left and right sides of bottom plate,
# - ordinate of the same two cuts.
#
# Given parameters described above, it is possible to draw the entire lines of cuts on both sides of bottom plate using \c cutLine function.
# Given parameters described above, it is possible to draw the entire lines of cuts on both sides of bottom plate using \c cutLine function.
#
def computeBottomPlateCuts( self ):
@ -443,11 +443,11 @@ class CapacitorUnit():
)
enclosure_botPlate_botPlateCut = ( self.bottomPlateBoxDict["height"] - (self.bottomCutLineNumber * self.minheight_topPlatecut + (self.bottomCutLineNumber -1) * self.minSpacingOnBotPlate_cut) )/2
self.cutLeftLineDict ["XMin"] = self.topPlateBoxDict ["XMin" ] - self.minSpacing_botPlateCut_topPlate - self.minWidth_topPlatecut/2
self.cutRightLineDict["XMin"] = self.topPlateBoxDict ["XMin" ] + self.topPlateBoxDict["width"] + self.minSpacing_botPlateCut_topPlate + self.minWidth_topPlatecut/2
self.cutLeftLineDict ["XMin"] = self.topPlateBoxDict ["XMin" ] - self.minSpacing_botPlateCut_topPlate - self.minWidth_topPlatecut/2
self.cutRightLineDict["XMin"] = self.topPlateBoxDict ["XMin" ] + self.topPlateBoxDict["width"] + self.minSpacing_botPlateCut_topPlate + self.minWidth_topPlatecut/2
self.cutLeftLineDict ["YMin"] = self.bottomPlateBoxDict["YMin" ] + self.minheight_topPlatecut/2 + enclosure_botPlate_botPlateCut
self.cutRightLineDict["YMin"] = self.cutLeftLineDict ["YMin" ]
self.cutRightLineDict["YMin"] = self.cutLeftLineDict ["YMin" ]
return
@ -455,11 +455,11 @@ class CapacitorUnit():
## Computes needed parameters to draw top plate cuts in its exact position, including :
#
# - maximum number of cuts to draw on both sides of top plate,
# - adjusted enclosure of
# - adjusted enclosure of
# - abcissas of the two top cuts on left and right sides of top plate,
# - ordinate of the same two cuts.
#
# Given parameters described above, it is possible to draw the entire lines of cuts on both sides of bottom plate using \c cutLine function.
# Given parameters described above, it is possible to draw the entire lines of cuts on both sides of bottom plate using \c cutLine function.
def computeTopPlateCuts( self ):
@ -480,20 +480,20 @@ class CapacitorUnit():
)
enclosure_topPlate_topPlateCut["horizontal"] = ( self.topPlateBoxDict["width"] - (self.topCutLineNumber["horizontal"] *self.minheight_topPlatecut + (self.topCutLineNumber["horizontal"] -1)*self.minSpacingOnTopPlate_cut) )/2
self.cut2MatrixDict [ "Width" ] = (self.topCutLineNumber["horizontal"]- 2)*self.minWidth_topPlatecut + (self.topCutLineNumber["horizontal"] - 1) * self.minSpacingOnTopPlate_cut
[ cut2MatrixAttribute , enclosure_attribute ] = [ ["XMin", "YMin" ] , [ "horizontal" , "vertical" ] ]
self.cut2MatrixDict [ "Width" ] = (self.topCutLineNumber["horizontal"]- 2)*self.minWidth_topPlatecut + (self.topCutLineNumber["horizontal"] - 1) * self.minSpacingOnTopPlate_cut
[ cut2MatrixAttribute , enclosure_attribute ] = [ ["XMin", "YMin" ] , [ "horizontal" , "vertical" ] ]
topPlateBoxCordinates = [self.topPlateBoxDict["XMin"], self.topPlateBoxDict["YMin"]]
for i in range(2):
topPlateCutTab = [ self.minWidth_topPlatecut , self.minheight_topPlatecut ]
self.cut2MatrixDict[ cut2MatrixAttribute[i] ] = topPlateBoxCordinates[i] + topPlateCutTab[i] /2 + enclosure_topPlate_topPlateCut[enclosure_attribute[i]]
self.cut2MatrixDict[ cut2MatrixAttribute[i] ] = topPlateBoxCordinates[i] + topPlateCutTab[i] /2 + enclosure_topPlate_topPlateCut[enclosure_attribute[i]]
elif self.capacitorType == 'PIPCap':
self.topCutLineDict["XMin"] = self.topPlateBoxDict["XMin"] + self.topPlateBoxDict["width"] - self.minEnclo_topPlate_topPlateCut - self.minWidth_topPlatecut/2
self.topCutLineDict["XMin"] = self.topPlateBoxDict["XMin"] + self.topPlateBoxDict["width"] - self.minEnclo_topPlate_topPlateCut - self.minWidth_topPlatecut/2
self.topCutLineDict["YMin"] = self.topPlateBoxDict["YMin"] + self.minheight_topPlatecut/2 + enclosure_topPlate_topPlateCut["vertical"]
else :
raise Error( 1, 'computeTopPlateCuts() : Unsupported capacitor type : %s. Cuts cannot be drawn. ' % self.capacitorType )
else :
raise Error( 1, 'computeTopPlateCuts() : Unsupported capacitor type : %s. Cuts cannot be drawn. ' % self.capacitorType )
return
@ -502,31 +502,31 @@ class CapacitorUnit():
def computeRoutingLayersDimensions( self ):
if self.capacitorType == 'MIMCap' :
if self.capacitorType == 'MIMCap' :
self.cut2MatrixDict ["XMax"] = self.cut2MatrixDict["XMin"] + self.cut2MatrixDict["Width"] + self.minWidth_topPlatecut
self.cut2MatrixDict ["XMax"] = self.cut2MatrixDict["XMin"] + self.cut2MatrixDict["Width"] + self.minWidth_topPlatecut
[ topmetalXMin,topmetalXMax ] = [ self.cut2MatrixDict["XMin"] - self.minEnclo_topPlateRMetal_topPlateCut - self.minWidth_topPlatecut/2
, self.cut2MatrixDict["XMax"] + self.minEnclo_topPlateRMetal_topPlateCut + self.minWidth_topPlatecut/2
]
[ width_topMetal, width_bottomMetal ] = [ topmetalXMax - topmetalXMin
, max( self.minWidth_botRMetal, (self.minWidth_botPlatecut + 2*self.minEnclo_botPlateRMetal_botPlateCut) )
]
topMetalXCenter = self.abutmentBoxDict["XMin"] + self.abutmentBoxDict["width"]/2
topMetalXCenter = self.abutmentBoxDict["XMin"] + self.abutmentBoxDict["width"]/2
elif self.capacitorType == 'PIPCap' :
topMetalXCenter = self.topCutLineDict["XMin"]
topMetalXCenter = self.topCutLineDict["XMin"]
width_topMetal = max( self.minWidth_botRMetal
, (self.minWidth_topPlatecut + 2*self.minEnclo_topPlateRMetal_topPlateCut)
, ( self.minWidth_routingTrackcut + 2*self.minEnclo_routingTrackMetal_cut)
, ( self.minWidth_routingTrackcut + 2*self.minEnclo_routingTrackMetal_cut)
)
width_bottomMetal = width_topMetal
else :
raise Error( 1, 'computeRoutingLayersDimensions() : Unsupported capacitor type : %s. Routing layers parameters cannot be computed. ' % self.capacitorType )
width_bottomMetal = width_topMetal
else :
raise Error( 1, 'computeRoutingLayersDimensions() : Unsupported capacitor type : %s. Routing layers parameters cannot be computed. ' % self.capacitorType )
[ dySourceTop , dyTargetTop ] = [ self.bottomPlateBoxDict["YMin"], self.topPlateBoxDict["YMin"] + self.topPlateBoxDict["height"] ]
[ dySourceBottom, dyTargetBottom ] = [ self.bottomPlateBoxDict["YMin"], self.bottomPlateBoxDict["YMin"]+self.bottomPlateBoxDict["height"] ]
[ dySourceBottom, dyTargetBottom ] = [ self.bottomPlateBoxDict["YMin"], self.bottomPlateBoxDict["YMin"]+self.bottomPlateBoxDict["height"] ]
self.topPlateRLayerDict = { "YMin" : dySourceTop, "YMax" : dyTargetTop, "XCenter" : topMetalXCenter , "width" : width_topMetal }
self.bottomPlateRLayerDict = { "left" : {"XMin": self.cutLeftLineDict["XMin"] - ( self.minEnclo_botPlate_botPlateCut + self.minWidth_botPlatecut/2 ), "XMax": self.cutLeftLineDict["XMin"] + ( self.minEnclo_botPlate_botPlateCut + self.minWidth_botPlatecut/2 )} , "right" : {"XMin": self.cutRightLineDict["XMin"] - ( self.minEnclo_botPlate_botPlateCut + self.minWidth_botPlatecut/2 )}, "YMin": dySourceBottom, "YMax": dyTargetBottom, "width": width_bottomMetal }
@ -538,19 +538,19 @@ class CapacitorUnit():
if vEnclosure_botPlate_abtBox == None : self.vEnclosure_botPlate_abtBox = self.minSpacing_botPlate
elif vEnclosure_botPlate_abtBox >= toPhY(self.minSpacing_botPlate) : self.vEnclosure_botPlate_abtBox = toDbU(vEnclosure_botPlate_abtBox)
else :
else :
raise Error(1,'setBottomPlateAbtBoxEnclosure() : Bottom plate vertical enclosure in abutment box must be equal or higher than the minimal limit %s um.'
%toPhY(self.minSpacing_botPlate))
if hEnclosure_botPlate_abtBox == None : self.hEnclosure_botPlate_abtBox = self.minSpacing_botPlate
elif hEnclosure_botPlate_abtBox >= toPhY(self.minSpacing_botPlate) : self.hEnclosure_botPlate_abtBox = toDbU(hEnclosure_botPlate_abtBox)
else :
else :
raise Error(1,'setBottomPlateAbtBoxEnclosure() : Bottom plate horizontal enclosure in abutment box must be equal or higher than the minimal limit %s um.' %toPhY(self.minSpacing_botPlate))
return
def computeAbutmentBoxDimensions( self, capDim, vEnclosure_botPlate_abtBox = None, hEnclosure_botPlate_abtBox = None ) :
self.setBottomPlateAbtBoxEnclosure(vEnclosure_botPlate_abtBox, hEnclosure_botPlate_abtBox)
@ -578,9 +578,9 @@ class CapacitorUnit():
def computeOnePlateBoxDimensions( self, inputBoxDimensions, vEnclosure, hEnclosure ):
outputboxDimensions = {}
outputboxDimensions["XMin" ] = inputBoxDimensions["XMin" ] + hEnclosure
outputboxDimensions["YMin" ] = inputBoxDimensions["YMin" ] + vEnclosure
outputboxDimensions["width" ] = inputBoxDimensions["width" ] - 2*hEnclosure
outputboxDimensions["XMin" ] = inputBoxDimensions["XMin" ] + hEnclosure
outputboxDimensions["YMin" ] = inputBoxDimensions["YMin" ] + vEnclosure
outputboxDimensions["width" ] = inputBoxDimensions["width" ] - 2*hEnclosure
outputboxDimensions["height"] = inputBoxDimensions["height"] - 2*vEnclosure
return outputboxDimensions
@ -601,17 +601,17 @@ class CapacitorUnit():
return
## Draws the top or bottom plate through inflation of the Box under it. These boxes are the abutment box in the case of the bottom plate and the bottom plate's box in the case of the top plate. This function also creates a a net for the drawn plate and sets it as external.
## Draws the top or bottom plate through inflation of the Box under it. These boxes are the abutment box in the case of the bottom plate and the bottom plate's box in the case of the top plate. This function also creates a a net for the drawn plate and sets it as external.
# \return The drawn box.
def drawOnePlate( self, layer, net, boxDimensions) :
def drawOnePlate( self, layer, net, boxDimensions) :
outputPlateBox = Box( boxDimensions["XMin"]
, boxDimensions["YMin"]
, boxDimensions["XMin"] + boxDimensions["width" ]
, boxDimensions["YMin"] + boxDimensions["height"]
)
platePad = Pad.create( net, layer, outputPlateBox )
)
platePad = Pad.create( net, layer, outputPlateBox )
return outputPlateBox
@ -620,7 +620,7 @@ class CapacitorUnit():
# \remark The relative positions describe the cordinates of the first bottom cut in every line of cuts. Then, knowing the spacing and width specifications of these cuts the rest of the line is easilly constructed.
def drawBottomPlateCut( self, layer, b ):
self.cutLine( b, layer
, self.cutLeftLineDict ["XMin"]
, self.cutLeftLineDict ["YMin"]
@ -628,7 +628,7 @@ class CapacitorUnit():
, self.minheight_topPlatecut
, self.minSpacingOnBotPlate_cut
, self.bottomCutLineNumber
, 'vertical'
, 'vertical'
)
self.cutLine( b, layer
, self.cutRightLineDict["XMin"]
@ -638,11 +638,11 @@ class CapacitorUnit():
, self.minSpacingOnBotPlate_cut
, self.bottomCutLineNumber , 'vertical'
)
return
## Draws the top plate's cuts after computing the maximal number of cuts that can be placed and its exact enclosure in the top plate.
## Draws the top plate's cuts after computing the maximal number of cuts that can be placed and its exact enclosure in the top plate.
def drawTopPlateCut( self, layer, t ):
@ -656,7 +656,7 @@ class CapacitorUnit():
,self.topCutLineNumber["horizontal"]
,self.topCutLineNumber["vertical" ]
)
else : self.cutLine(t,layer
,self.topCutLineDict["XMin"]
,self.topCutLineDict["YMin"]
@ -670,7 +670,7 @@ class CapacitorUnit():
return
## Draws the routing layers of both bottom and top plates after computing widths and the exact position of these layers. Also computes positions if rlayers that are crucial for routing.
## Draws the routing layers of both bottom and top plates after computing widths and the exact position of these layers. Also computes positions if rlayers that are crucial for routing.
def drawRoutingLayers( self, bottomPlateLayer, topPlateLayer, t, b ):
@ -678,8 +678,8 @@ class CapacitorUnit():
, int(self.topPlateRLayerDict["XCenter"])
, int(self.topPlateRLayerDict["width" ])
, int(self.topPlateRLayerDict["YMin" ])
, int(self.topPlateRLayerDict["YMax" ])
)
, int(self.topPlateRLayerDict["YMax" ])
)
cutLinesXMins = [ self.cutLeftLineDict["XMin"], self.cutRightLineDict["XMin"] ]
for i in range(2):
@ -689,15 +689,15 @@ class CapacitorUnit():
, int(self.bottomPlateRLayerDict["YMin" ])
, int(self.bottomPlateRLayerDict["YMax" ])
)
return
return
## Computes the maximal number of cuts to be placed on a layer of width \c width_layer considering specifications such as the spacing between the cuts, its width and its enclosure in the layer.
def cutMaxNumber( self, width_layer, width_cut, spacing_cut, enclosure_cut ):
def cutMaxNumber( self, width_layer, width_cut, spacing_cut, enclosure_cut ):
cutNumber = int( (width_layer - 2*enclosure_cut + spacing_cut) / (width_cut + spacing_cut) )
if cutNumber > 0 :
if cutNumber > 0 :
return cutNumber
else : raise Error (1,"cutMaxNumber() : Zero number of cuts found. Layer width is too tight." )
@ -705,8 +705,8 @@ class CapacitorUnit():
## Creates a horizontal or vertical line of contacts according to the specified direction.
def cutLine( self, net, layer, firstCutXCenter, firstCutYCenter, width_cut, height_cut, spacing_cut, cutNumber, direction ):
def cutLine( self, net, layer, firstCutXCenter, firstCutYCenter, width_cut, height_cut, spacing_cut, cutNumber, direction ):
for i in range( cutNumber) :
if direction == 'horizontal':
segment = Contact.create( net, layer
@ -727,12 +727,12 @@ class CapacitorUnit():
#
# \param net net to which the cuts belong
# \param layer cuts physical layer
# \param firstCutXCenter center's abcissa of the bottom left cut ( that is the first cut to be drawn in the matrix )
# \param firstCutXCenter center's abcissa of the bottom left cut ( that is the first cut to be drawn in the matrix )
# \param firstCutYCenter center's abcissa of the bottom left cut
# \param (width_cut,height_cut,spacing_cut) cuts dimenions
# \param (width_cut,height_cut,spacing_cut) cuts dimenions
# \param (cutColumnNumber,cutRowNumber) matrix dimensions
#
# \remarks The matrix can have any dimensions zero or negative one.
# \remarks The matrix can have any dimensions zero or negative one.
def cutMatrix( self, net, layer, firstCutXCenter, firstCutYCenter, width_cut, height_cut, spacing_cut, cutColumnNumber, cutRowNumber ):
@ -744,23 +744,23 @@ class CapacitorUnit():
## \return the ordinate of the bottom plate's highest end-point ( that is equivalent to \c dySource of the bottom plate's box ) .
## \return the ordinate of the bottom plate's highest end-point ( that is equivalent to \c dySource of the bottom plate's box ) .
def getBottomPlateYMax ( self ) : return self.bottomPlateBoxDict["YMin"] + self.bottomPlateBoxDict["height"]
## \return the abcissa of the bottom plate's left line of cuts.
def getBottomPlateLeftCutXMin ( self ) : return self.cutLeftLineDict ["XMin" ]
## \return the abcissa of the bottom plate's left line of cuts.
def getBottomPlateLeftCutXMin ( self ) : return self.cutLeftLineDict ["XMin" ]
## \return the ordinate of the first ( or bottom) cut in the left line of cuts on the bottom plate.
def getBottomPlateLeftCutYMin ( self ) : return self.cutLeftLineDict ["YMin" ]
## \return the ordinate of the highest cut of the bottom plate's left line of cuts.
## \return the ordinate of the highest cut of the bottom plate's left line of cuts.
def getBottomPlateLeftCutYMax ( self ) : return self.cutLeftLineDict ["YMin" ] + ( self.bottomCutLineNumber - 1 )*( self.minSpacingOnBotPlate_cut + self.minWidth_botPlatecut )
## \return the absissa of the bottom plate's right line of cuts.
## \return the absissa of the bottom plate's right line of cuts.
def getBottomPlateRightCutXMin ( self ) : return self.cutRightLineDict ["XMin" ]
@ -777,16 +777,16 @@ class CapacitorUnit():
## \return the position of the bottom plate's right cuts on the horitontal axis (also applicable to left cuts).
def getBottomPlateRightCutYCenter (self ) : return (self.getBottomPlateRightCutYMax() - self.getBottomPlateRightCutYMin())/2
def getBottomPlateRightCutYCenter (self ) : return (self.getBottomPlateRightCutYMax() - self.getBottomPlateRightCutYMin())/2
## \return the position of the bottom plate's right cuts on the horitontal axis.
def getBotPlateRightRLayerXMin ( self ) : return self.bottomPlateRLayerDict ["right" ]["XMin" ]
## \return the position of the bottom plate's left cuts on the horitontal axis.
def getBotPlateLeftRLayerXMin ( self ) : return self.bottomPlateRLayerDict ["left" ]["XMin" ]
## \return the position of bottom plate's left cuts on the horitontal axis.
def getBotPlateRLayerYMin ( self ) : return self.bottomPlateRLayerDict ["YMin" ]
@ -831,7 +831,7 @@ class CapacitorUnit():
## \return the abscissa of the bottom-right end-point of the top plate routing layer.
def getTopPlateRLayerXMax ( self ) : return self.topPlateRLayerDict ["XCenter"] + self.topPlateRLayerDict ["width"]/2
def scriptMain( **kw ):
@ -845,46 +845,46 @@ def scriptMain( **kw ):
device.setTerminal( True )
bottomPlate_net = Net.create( device, 'b' )
bottomPlate_net.setExternal( True )
bottomPlate_net.setExternal( True )
b = device.getNet("b")
doBreak( 1, 'Done building bottomPlate')
topPlate_net = Net.create( device, 't' )
topPlate_net.setExternal( True )
topPlate_net.setExternal( True )
t = device.getNet("t")
doBreak( 1, 'Done building t')
if editor:
UpdateSession.close( )
editor.setCell ( device )
editor.fit ( )
UpdateSession.open ( )
capacitor = CapacitorUnit ( device, 'MIMCap', [0,0], capacitance = 129.56) # square: capacitance : 129.56 , capDim = {"width" : 39650L , "height" : 39650L } # rectangular capDim = {"width" : 78919L , "height" : 118378L }
abutmentBoxDim = capacitor.create( b, t, bbMode = True, vEnclosure_botPlate_abtBox = 1.5, hEnclosure_botPlate_abtBox = 0.9)
editor.setCell ( device )
editor.fit ( )
UpdateSession.open ( )
capacitor = CapacitorUnit ( device, 'MIMCap', [0,0], capacitance = 129.56) # square: capacitance : 129.56 , capDim = {"width" : 39650L , "height" : 39650L } # rectangular capDim = {"width" : 78919L , "height" : 118378L }
abutmentBoxDim = capacitor.create( b, t, bbMode = True, vEnclosure_botPlate_abtBox = 1.5, hEnclosure_botPlate_abtBox = 0.9)
#print(abutmentBoxDim)
AllianceFramework.get().saveCell( device, Catalog.State.Views )
return True