coriolis/oroshi/python/CapacitorMatrix.py

603 lines
31 KiB
Python

#!/usr/bin/python
import sys
from Hurricane import *
from CRL import *
from math import sqrt, ceil
from helpers.io import ErrorMessage as Error
from helpers import trace
from CapacitorUnit import CapacitorUnit
import helpers
import oroshi
import numpy
## 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 = oroshi.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 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 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.
#
# \param rowNumber Number of rows in the matrix of capacitors.
# \param columnNumber Number of columns in the matrix of capacitors.
def __init__( self, device, capacitance, capacitorType, abutmentBoxPosition, nets, unitCap = 0, matrixDim = [1,1], matchingMode = False, matchingScheme = [], dummyRing = False, dummyElement = False ):
self.device = device
self.capacitorType = capacitorType
self.matrixDim = { "columns" : matrixDim[1], "rows" : matrixDim[0] }
self.unitCapDim = self.__computeCapDim__( unitCap , capacitorType )
self.doMatrix = False
self.abutmentBox = Box()
self.abutmentBoxPosition = { "XMin" : abutmentBoxPosition[0], "YMin" : abutmentBoxPosition[1] }
self.nets = nets
self.matchingMode = matchingMode
self.dummyRing = dummyRing
self.dummyElement = dummyElement
self.capacitorsNumber = len(capacitance)
self.matchingScheme = matchingScheme
self.dummyRingPosition = {}
self.abutmentBox_spacing = 0
self.vRoutingTrack_width = 0
if self.__areInputDataOK__(capacitance) == True :
if self.matchingMode == False :
self.compactCapDim = self.__computeCapDim__( capacitance[0] , capacitorType )
if unitCap == 0 :
self.__initGivenZeroUnitCap__( capacitance[0] )
elif unitCap <> 0 and CapacitorUnit.__isCapacitorUnitOK__( self, self.unitCapDim ) :
self.__initGivenNonZeroUnitCap__( capacitance[0], unitCap )
else : raise Error( 1, '__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim )
else :
if unitCap == 0 :
self.__initGivenZeroUnitCapInMatchingMode__( capacitance )
elif unitCap <> 0 and CapacitorUnit.__isCapacitorUnitOK__( self, self.unitCapDim ) :
self.__initGivenNonZeroUnitCapInMatchingMode__( capacitance, unitCap )
else : raise Error( 1, '__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim )
return
def setRules( self ) :
CapacitorUnit.setRules ( self )
CapacitorUnit.__setattr__ ( self, "minWidth_vRoutingTrack" , CapacitorStack.rules.minWidth_metal3 )
CapacitorUnit.__setattr__ ( self, "minSpacing_vRoutingTrack" , CapacitorStack.rules.minSpacingWide1_metal3 )
CapacitorUnit.__setattr__ ( self, "minWidth_vRoutingTrackCut" , CapacitorStack.rules.minWidth_cut2 )
CapacitorUnit.__setattr__ ( self, "minSpacing_vRoutingTrackCut" , CapacitorStack.rules.minSpacing_cut2 )
CapacitorUnit.__setattr__ ( self, "minEnclosure_vRoutingTrackCut" , CapacitorStack.rules.minEnclosure_metal3_cut2 )
if self.capacitorType == 'MIMCap':
CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minWidth_cut2 )
CapacitorUnit.__setattr__ ( self, "minEnclosure_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minEnclosure_metal2_cut2 )
elif self.capacitorType == 'PIPCap' :
CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minWidth_cut1 )
CapacitorUnit.__setattr__ ( self, "minEnclosure_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minEnclosure_metal2_cut1 )
else: raise Error( 1, 'setRules() : Unsupported capacitor type : %s.' %self.capacitorType )
return
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 )
[factor1 , factor2 ] = [ self.capacitorsNumber , (self.capacitorsNumber +1) ] if ( self.capacitorsNumber % 2 == 0 ) else [ self.capacitorsNumber +1 , self.capacitorsNumber +2 ]
# if self.dummyElement == True : [factor1 , factor2 ] = [factor1 + 1 , factor2 + 1 ]
self.abutmentBox_spacing = factor1*self.vRoutingTrack_width + factor2*self.minSpacing_vRoutingTrack
return
def __initMatrixMode__( self, capacitance, unitCap ) :
[ self.capacitance, self.unitCapacitance , self.doMatrix ] = [ capacitance , unitCap , True ]
return
def __initGivenZeroUnitCap__( self, capacitance ):
if ( self.matrixDim.values() == [1,1] and CapacitorUnit.__isCapacitorUnitOK__(self, self.compactCapDim) ):
[ self.capacitance , self.unitCapDim ] = [ capacitance , self.compactCapDim ]
elif ( self.matrixDim.values() == [1,1] and not(CapacitorUnit.__isCapacitorUnitOK__( self, self.compactCapDim)) ): raise Error(1, '__init__(): Impossible to draw the capacitor, dimensions are either too large or too small, "%s".' % self.compactCapDim ) #com2 : use to physical
elif ( self.matrixDim["columns"]>1 or self.matrixDim["rows"]>1) :
unitCapacitance = capacitance / (self.matrixDim["columns"]*self.matrixDim["rows"])
unitCapDim = self.__computeCapDim__( unitCapacitance, self.capacitorType )
if CapacitorUnit.__isCapacitorUnitOK__(self, unitCapDim) == True :
self.unitCapDim = unitCapDim
[ self.unitCapacitance , self.capacitance, self.doMatrix ] = [ unitCapacitance , capacitance, True ]
else : raise Error( 1, '__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim ) #com2 : use to physical
return
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 :
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 : # self.matrixDim.values() == [1,1] : # jai donne ou jai ps donne
if capacitance == unitCap : #compact
[ self.capacitance , self.unitCapDim ] = [ capacitance , self.compactCapDim ]
print("capa",capacitance)
elif capacitance <> unitCap : #matrice
self.__initMatrixMode__( capacitance, unitCap )
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
def __initGivenZeroUnitCapInMatchingMode__( self, capacitance ):
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)
if len( list(numpy.unique(unitCapList)) ) == 1 :
unitCapDim = self.__computeCapDim__( unitCapList[0], self.capacitorType )
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) }
else : raise Error(1,'__initGivenZeroUnitCapInMatchingMode__() : Impossible to draw unit capacitor, dimensions are either too large or too small, "%s".' % unitCapDim)
else : raise Error(1,'__initGivenZeroUnitCapInMatchingMode__() : Not all capacitances are multiple of the unit capacitor.')
else : raise Error(1,'__initGivenZeroUnitCapInMatchingMode__() : Please check compatibility between matrix dimensions and matching scheme dimensions. Both must be equal.')
return
def __initGivenNonZeroUnitCapInMatchingMode__( self, capacitance, unitCap ):
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) }
else: raise Error(1,'__initGivenNonZeroUnitCapInMatchingMode__() : Non valid unit capacitor value considering the entered matching scheme. Please make sure that capacitors values are all multiples of unit capacitor.')
else: raise Error(1,'__initGivenNonZeroUnitCapInMatchingMode__() : Please check compatibility between matrix dimensions and matching scheme dimensions. Both must be equal.')
else: raise Error(1,'__initGivenNonZeroUnitCapInMatchingMode__() : Impossible to draw unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim)
return
def __areMatrixDimOK__( self ): return True if self.matrixDim.values() > 0 else False
def computeUnitCap( self, capacitance ):
unitCapList = []
for k in range(0, self.capacitorsNumber):
unitCapList.append( capacitance[k]/self.capacitorIdOccurence(k) )
return unitCapList
def evaluateUnitCap( self, capacitance, unitCap ):
state = True
for k in range(0, self.capacitorsNumber):
print('self.capacitorIdOccurence( k )',self.capacitorIdOccurence( k ))
factor = capacitance[k]/unitCap
print('factor',factor)
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.
# - Equal number of affected capacitors to C1 as to C2.
# - Capacitor identifiers equal to '1' or '2' only.
# - Otherwise, the function returns \c False.
def __isMatchingSchemeOK__ ( self ):
state = True
columsElementsNumber = [ len(self.matchingScheme[k]) for k in range(0,len(self.matchingScheme)) ]
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 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 )
return occurence
def __areInputDataOK__( self, capacitance ) :
state = False
if ( self.__areMatrixDimOK__() == True ) :
if self.matchingMode in [False, True] and self.dummyRing in [False,True] and self.dummyElement in [False,True]:
[ matchingSchemeCapIds , capacitanceIds ] = [ list( numpy.unique(self.matchingScheme) ) , range(0,self.capacitorsNumber) ]
if (self.matchingScheme != [] and set(matchingSchemeCapIds) == set(capacitanceIds) ) or (self.matchingScheme == [] and len(capacitance) == 1) :
if (len(self.nets) == self.capacitorsNumber + 1 and self.dummyElement == False and self.dummyRing == True ) or (len(self.nets) == self.capacitorsNumber and self.dummyElement == False and self.dummyRing == False) 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 self.matchingScheme == [] ):
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 is incompatible with number of capacitors to be drawn.')
else : raise Error(1, '__areInputDataOK__() : Please check compatibility between matching scheme elements, %s, and capacitance indexes, %s. They must be identical. Otherwise, when matching scheme is "False", capacitance indexes must be [0].' %(matchingSchemeCapIds, capacitanceIds) )
else : raise Error(1,'__areInputDataOK__() : Matching mode, %s, dummy ring, %s, and dummy element, %s, must be all either "True" or "False".' %(self.matchingMode, self.dummyRing, self.dummyElement))
else : raise Error(1,'__areInputDataOK__(): Both matrix dimensions "%s" must be positive.' % self.matrixDim.keys())
return state
## Draw the compact or matrix of capacitors. First, . Second, . Finally, .
def create( self, bbMode = False ):
UpdateSession.open()
drawnCapacitor = {}
self.setRules()
if self.matchingMode == True :
self.__initMatchingMode__()
self.drawAbutmentBox( self.abutmentBox_spacing )
if bbMode == True:
output = self.computeBondingBoxDimensions()
print('output',output)
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
def drawCapacitorStack( self ):
drawnCapacitor = []
bottomPlateRLayer = CapacitorUnit.getLayers( self )["bottomPlateRLayer"]
topPlateRLayer = CapacitorUnit.getLayers( self )["topPlateRLayer" ]
if self.doMatrix == True :
drawnCapacitor = self.capacitorMatrix ( self.abutmentBox_spacing )
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):
drawnActiveCapacitor.append(drawnCapacitor[i][1:len(drawnCapacitor[1])-1])
else : drawnActiveCapacitor = drawnCapacitor
self.drawBottomPlatesRLayers( bottomPlateRLayer, drawnActiveCapacitor )
self.drawTopPlatesRLayers ( topPlateRLayer , drawnActiveCapacitor )
else:
drawnCapacitor = CapacitorUnit( self.device, self.capacitance, self.capacitorType, [self.abutmentBoxPosition["XMin"], self.abutmentBoxPosition["YMin"]] )
drawnCapacitor.create( self.nets[0][0], self.nets[0][1] )
return drawnCapacitor
## 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.
# \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.unitCapacitance, self.capacitorType, [self.abutmentBoxPosition["XMin"], dy] ) ]
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.unitCapacitance, self.capacitorType, [line[j-1].abutmentBox.getXMax() + abutmentBox_spacing, dy] ) )
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) :
[ 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 :
k = self.matchingScheme[matchingSchemeRowIndex][capListIndex]
[ t , b ] = [ self.nets[k][0] , self.nets[k][1] ]
capacitorList[capListIndex].create( t, b )
return
## 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 ):
#print("capMatrix", nets)
matrix = [ self.capacitorLine( self.abutmentBoxPosition["YMin"], abutmentBox_spacing,0 ) ]
limit = self.matrixDim["rows"] + 2 if self.dummyRing == True else self.matrixDim["rows"]
for i in range( 1, limit ):
matrix.append( self.capacitorLine( matrix[i-1][-1].abutmentBox.getYMax() + abutmentBox_spacing, abutmentBox_spacing, i) )
return matrix
def dummyLine( self, direction, dx, dy ):
dummyList = [ CapacitorUnit( self.device, self.unitCapacitance, self.capacitorType, [dx, dy] ) ]
dummyList[0].create( self.nets[-1][0], self.nets[-1][1] )
if direction == 'vertical':
for i in range(1, self.matrixDim["rows"] + 2):
dummyList.append( CapacitorUnit( self.device, self.unitCapacitance, self.capacitorType, [dx, dummyList[i-1].abutmentBox.getYMax() + self.abutmentBox_spacing] ) )
dummyList[i].create(self.nets[-1][0], self.nets[-1][1])
elif direction == 'horizontal':
for j in range(1, self.matrixDim["columns"] + 2):
print('j',j)
dummyList.append( CapacitorUnit( self.device, self.unitCapacitance, self.capacitorType, [dummyList[j-1].abutmentBox.getXMax() + self.abutmentBox_spacing, dy]) )
dummyList[j].create(self.nets[-1][0], self.nets[-1][1])
else : raise Error(1,'dummyLine() : Direction must be either "horizontal" or "vertical".' %direction)
return dummyList
def computeAbutmentBoxDimensions( self, abutmentBox_spacing ):
abutmentBoxDimensions = {}
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)
abutmentBoxWidth = widthFactor1 *abutmentBoxDimElement["width" ] + widthFactor2 *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.
def drawAbutmentBox( self, abutmentBox_spacing = 0 ):
abutmentBoxDimensions = self.computeAbutmentBoxDimensions(abutmentBox_spacing)
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
def computeBondingBoxDimensions( self ):
bondingBoxDimensions = {}
abutmentBoxDimensions = self.computeAbutmentBoxDimensions( self.abutmentBox_spacing )
for key in abutmentBoxDimensions:
if key != "XMin" and key != "YMin" : bondingBoxDimensions[key] = abutmentBoxDimensions[key]
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 .
def drawBottomPlatesRLayers( self, bottomPlateRLayer, drawnCapacitor ):
[ 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() )
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 )
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 )
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 .
# \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() )
#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.
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 getCapDim ( self ) : return self.unitCapDim if self.doMatrix == True else self.compactCapDim
# def getMatchingMode ( self ) : return self.matchingMode
def getVRoutingTrack_spacing ( self ) : return self.minSpacing_vRoutingTrack
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 ScriptMain( **kw ):
editor = None
if kw.has_key('editor') and kw['editor']:
editor = kw['editor']
UpdateSession.open()
device = AllianceFramework.get().createCell( 'capacitor' )
device.setTerminal( True )
bottomPlate_net0 = Net.create( device, 'b0' )
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 )
b0 = device.getNet("b0")
b1 = device.getNet("b1")
b2 = device.getNet("b2")
b3 = device.getNet("b3")
topPlate_net0 = Net.create( device, 't0' )
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 )
t0 = device.getNet("t0")
t1 = device.getNet("t1")
t2 = device.getNet("t2")
t3 = device.getNet("t3")
if editor:
UpdateSession.close()
editor.setCell( device )
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)
#capacitorInstance = CapacitorStack( device, [1488], 'MIMCap', [0,0], nets,unitCap = 93, matrixDim = [4,4], dummyRing = True)
#capacitorInstance = CapacitorStack( device, {"C1" : 558, "C2" : 558, "C3" : 372}, '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','C3','C3'] ])
#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(capacitor)
AllianceFramework.get().saveCell( device, Catalog.State.Views )
return True