First integration of Resistors (straight & snake).

This commit is contained in:
Mariam Tlili 2019-12-12 14:23:35 +01:00
parent 5ee4487d95
commit e1389f501a
7 changed files with 1088 additions and 128 deletions

View File

@ -1,5 +1,7 @@
#!/usr/bin/python
print "SOURCE CapacitorMatrix"
import sys
from Hurricane import *
from CRL import *
@ -40,10 +42,11 @@ class CapacitorStack( CapacitorUnit ):
self.device = device
self.capacitorType = capacitorType
print("self.capacitorType0",self.capacitorType)
self.matrixDim = { "columns" : matrixDim[1], "rows" : matrixDim[0] }
self.unitCapDim = self.__computeCapDim__( unitCap , capacitorType )
self.unitCapDim = self.__computeCapDim__( unitCap , capacitorType )
self.doMatrix = False
self.doMatrix = False
self.abutmentBox = Box()
self.abutmentBoxPosition = { "XMin" : abutmentBoxPosition[0], "YMin" : abutmentBoxPosition[1] }
self.nets = nets
@ -59,7 +62,7 @@ class CapacitorStack( CapacitorUnit ):
self.vRoutingTrack_width = 0
if self.__areInputDataOK__(capacitance) == True :
if self.matchingMode == False :
if self.matchingMode == False :
self.compactCapDim = self.__computeCapDim__( capacitance[0] , capacitorType )
if unitCap == 0 :
@ -115,10 +118,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 )
[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
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
@ -137,7 +139,8 @@ class CapacitorStack( CapacitorUnit ):
[ 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.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) :
@ -300,14 +303,15 @@ class CapacitorStack( CapacitorUnit ):
[ 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) :
print("len(self.nets)",len(self.nets))
print("self.capacitorsNumber + 1",self.capacitorsNumber + 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__() : Nets number, %s, is incompatible with number of capacitors to be drawn, %s.' %(self.netsNumber, self.capacitorsNumber))
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) )
@ -384,11 +388,12 @@ class CapacitorStack( CapacitorUnit ):
def capacitorLine( self, dy, abutmentBox_spacing , matchingSchemeRowIndex = 0 ):
line = [ CapacitorUnit( self.device, self.unitCapacitance, self.capacitorType, [self.abutmentBoxPosition["XMin"], dy] ) ]
print("self.capacitorType",self.capacitorType)
line = [ CapacitorUnit( self.device, self.capacitorType, [self.abutmentBoxPosition["XMin"], dy], capacitance = self.unitCapacitance ) ]
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] ) )
line.append( CapacitorUnit( self.device, self.capacitorType, [line[j-1].abutmentBox.getXMax() + abutmentBox_spacing, dy], capacitance = self.unitCapacitance ) )
self.createElementInCapacitorLine( line, matchingSchemeRowIndex,j )
return line
@ -430,18 +435,18 @@ class CapacitorStack( CapacitorUnit ):
def dummyLine( self, direction, dx, dy ):
dummyList = [ CapacitorUnit( self.device, self.unitCapacitance, self.capacitorType, [dx, dy] ) ]
dummyList = [ CapacitorUnit( self.device, self.capacitorType, [dx, dy], capacitance = self.unitCapacitance ) ]
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.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])
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.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])
else : raise Error(1,'dummyLine() : Direction must be either "horizontal" or "vertical".' %direction)
@ -588,7 +593,7 @@ def ScriptMain( **kw ):
editor.setCell( device )
editor.fit()
UpdateSession.open()
nets = [[t0, b0]]# , [t1, b1], [t2, b2] ] # [t3, b3] ]
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'] ])

View File

@ -10,7 +10,6 @@ import oroshi
from CapacitorUnit import CapacitorUnit
from CapacitorMatrix import CapacitorStack
from CapacitorVRTracks import VerticalRoutingTracks
#from collections import OrderedDict
## Routs two matched capacitors, C1 and C2, drawn in a capacitor matrix. Connections are put in place with reference to a given matching scheme. Elementary capacitor units are connected to horizontal and vertical routeing tracks that represent top plates and bottom plates nets of C1 and C2 . Supported types of capacitors are Poly-Poly and Metal-Metal. Technologycal rules are provided by 350 nm AMS CMOS technology with three-four metal layers. Metal layers that are used for routeing are placed similarly to horziontal-vertical (HV) symbolic Alliance CAD tool routeer, where horizontal metal channels are drawn in metal 2 and the vertical ones are in metal 3. Given a matrix of dimensions \f$ R*C \f$, the total number of vertical tracks is \f$ 2C+2 \f$ equivalent to \f$ C+1 \f$ couples, ensuring that every elementary capacitor is positioned between four vertical tracks, two from each side. In fact, every adjacent couple of these tracks represent top plates and bottom plates of C1 or C2 as shown in Figure 1.
@ -58,15 +57,16 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks
VerticalRoutingTracks.__init__( self, vRTInstance.capacitorInstance, vRTInstance.capacitor )
if self.dummyRing == True :
self.capacitor = [vRTInstance.capacitor[1][1:len(vRTInstance.capacitor[1])-1]]
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 #gethRoutingTrack_width()
self.hRoutingTrack_width = vRTInstance.hRoutingTrack_width
self.minSpacing_hRoutingTrack = 0
self.minimumPosition = 0
self.maximumPosition = 0
@ -276,7 +276,7 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks
abutmentBoxXMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["XMin"]
abutmentBoxXMax = abutmentBoxXMin + self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["width" ]
bondingBoxDimensions["XMin" ] = self.vRoutingTrackXCenter[0 ]["t1"] - self.vRoutingTrack_width/2
bondingBoxDimensions["XMin" ] = self.vRoutingTrackXCenter[0]["t1"] - self.vRoutingTrack_width/2
if self.capacitorsNumber % 2 == 0 :
factor = self.capacitorsNumber
@ -758,7 +758,7 @@ def ScriptMain( **kw ):
capWithVRT.create()
routedCap = RoutMatchedCapacitor( capWithVRT )
surface = routedCap.route( )
surface = routedCap.route(True)
print('routeMatchedCap bbMode', surface)
AllianceFramework.get().saveCell( Device, Catalog.State.Views )

View File

@ -2,16 +2,23 @@
import sys
import numpy
from Hurricane import *
from CRL import *
from math import sqrt, ceil
from Hurricane import *
from CRL import *
from math import sqrt, ceil
import helpers
from helpers.io import ErrorMessage as Error
from helpers import trace
from helpers.io import ErrorMessage as Error
from helpers import trace
import oroshi
def toDbU ( l ): return DbU.fromPhysical( l, DbU.UnitPowerMicro )
def toDbU ( l ): return DbU.fromPhysical( l, DbU.UnitPowerMicro )
def toPhY ( l ): return DbU.toPhysical ( l, DbU.UnitPowerMicro )
def doBreak( level, message ):
UpdateSession.close()
Breakpoint.stop( level, message )
UpdateSession.open()
helpers.staticInitialization( True )
## 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.
@ -23,6 +30,9 @@ class CapacitorUnit():
rules = oroshi.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 capacitance Capacitor value, expressed in \f$ femto Farad (fF) \f$.
@ -50,13 +60,17 @@ class CapacitorUnit():
# \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, capacitance, capacitorType, abutmentBoxPosition ):
def __init__( self, device, capacitorType, abutmentBoxPosition, capacitance = 0, capDim = {} ):
self.device = device
self.capacitorType = capacitorType
self.capDim = self.__computeCapDim__( capacitance, capacitorType )
# self.capDim = self.__computeCapDim__( capacitance, capacitorType )
self.enclosure_botPlate_abtBox = 0
self.__initCapDim__( capacitance, capDim )
self.abutmentBoxDict = { "XMin" : abutmentBoxPosition[0], "YMin" : abutmentBoxPosition[1] }
self.abutmentBox = Box ()
@ -72,29 +86,54 @@ class CapacitorUnit():
self.topCutLineDict = {}
self.topPlateRLayerDict = {}
self.bottomPlateRLayerDict = {}
self.topCutLineNumber = {}
self.enclosure_botPlate_topPlate = 0
self.minheight_topPlatecut = 0
self.topCutLineNumber = 0
self.bottomCutLineNumber = 0
# self.nets = { "bNet" : bNet, "tNet" : tNet }
return
def __initCapDim__( self, capacitance, capDim ):
if capacitance != 0 and capDim.values() != [] :
if self.__computeCapacitance__( capDim, self.capacitorType ) == capacitance :
self.capDim = capDim
else : raise Error(1,'__initCapDim__() : Please check compatibility between capacitance value, %s, and the given capacitor dimensions, %s.' %(capacitance, capDim))
elif capacitance == 0 and capDim.values() != [] :
self.capDim = capDim
capacitance = self.__computeCapacitance__( capDim, self.capacitorType )
print("capacitance", capacitance)
elif capacitance != 0 and capDim.values() == [] :
print("self.capacitorType ",self.capacitorType )
self.capDim = self.__computeCapDim__( capacitance, self.capacitorType )
print("self.capDim",self.capDim)
else : raise Error(1, '__initCapDim__() : Invalid capacitance and/or capacitance dimensions (%s, %s). Please provide at least one valid parameter.'
%(capacitance, capDim))
return
## 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':
[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = [ CapacitorUnit.rules.MIMCap, CapacitorUnit.rules.MIMPerimeterCap ]
[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = [ CapacitorUnit.rules.MIMCap
, CapacitorUnit.rules.MIMPerimeterCap
]
elif capacitorType == 'PIPCap':
[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = [ CapacitorUnit.rules.PIPCap, CapacitorUnit.rules.PIPPerimeterCap ]
[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = [ CapacitorUnit.rules.PIPCap
, CapacitorUnit.rules.PIPPerimeterCap
]
else:
raise Error( 1, 'setCapacitorPerUnit() : Unsupported capacitor type : %s.' % capacitorType )
@ -107,33 +146,51 @@ class CapacitorUnit():
# \remark The capacitor is square. Thus, length and width are equal.
def __computeCapDim__( self, capacitance, capacitorType ) :
print("capacitorType",capacitorType)
[a, b, c ] = [ self.__setCapacitorPerUnit__( capacitorType )[0]
, 4*self.__setCapacitorPerUnit__( capacitorType )[1]
, - capacitance
]
[a, b, c ] = [ self.__setCapacitorPerUnit__( capacitorType )[0], 4*self.__setCapacitorPerUnit__( capacitorType )[1], -capacitance ]
delta = (b**2) - 4*a*c
c1 = ( -b + sqrt(delta) ) / (2*a)
return { "width" : toDbU(c1), "height" : toDbU(c1) }
def __computeCapacitance__( self, capDim, capacitorType ):
[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = self.__setCapacitorPerUnit__( capacitorType )
areaCapacitance = toPhY(capDim["width"]) * toPhY(capDim["height"]) *areaCapacitorPerUnit
perimeterCapacitance = ( toPhY(capDim["width"]) + toPhY(capDim["height"]) )*perimeterCapacitorPerUnit
capacitance = areaCapacitance + perimeterCapacitance
return capacitance
## Checks if the computed capacitor dimensions exceed or are less than maximum and minimum limits, respectively, as specified in technology rules.
## \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 ):
if ( self.capacitorType == 'MIMCap' and CapacitorUnit.getMinimumCapWidth( self ) < capDim["width"] < self.getMaximumCapWidth()) or self.capacitorType == 'PIPCap' and self.getMinimumCapWidth() < capDim["width"]:
return True
state = False
if ( self.capacitorType == 'MIMCap' and CapacitorUnit.getMinimumCapWidth( self ) < capDim["width"] < self.getMaximumCapWidth() and CapacitorUnit.getMinimumCapWidth( self ) < capDim["height"] < self.getMaximumCapWidth() ) or ( self.capacitorType == 'PIPCap' and self.getMinimumCapWidth() < capDim["width"] and self.getMinimumCapWidth() < capDim["height"] ) :
state = True
return state
## Redefines technological rules as object attributes of the class. For example, class attributes \c CapacitorUnit.rules.minWidth_metcap becomes \c self.minWidth_topPlate and \c CapacitorUnit.rules.minSpacing_cut2_metcap becomes \c self.minSpacing_botPlateCut_topPlat. This obviously helps using shorter names for the attributes. \c __setattr__() is declared in all \c Capacitor \c Generator classes, also in Hurricane and oroshi databases.
def __setattr__( self, attribute, value ):
def __setattr__( self, attribute, value ) :
self.__dict__[attribute] = value
return
return
## Selects technological rules according to the capacitor type.
@ -245,8 +302,8 @@ class CapacitorUnit():
def getLayers( self ):
technology = DataBase.getDB().getTechnology()
layerDict = {}
technology = DataBase.getDB().getTechnology()
layerDict = {}
if self.capacitorType == 'MIMCap':
@ -272,27 +329,29 @@ class CapacitorUnit():
## 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 ( tNet , bNet ) nets of top and bottom plates, respectively
# \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, tNet, bNet, bbMode = False ):
#
def create( self, t, b, bbMode = False, vEnclosure_botPlate_abtBox = None, hEnclosure_botPlate_abtBox = None ):
UpdateSession.open()
abutmentBoxDimensions = None
self.setRules ()
self.setRules ()
if self.__isCapacitorUnitOK__( self.capDim ) == True :
self.computeDimensions ( self.capDim )
self.computeDimensions ( self.capDim, vEnclosure_botPlate_abtBox, hEnclosure_botPlate_abtBox )
self.drawAbutmentBox ()
self.device.setAbutmentBox( self.abutmentBox )
#self.device.setAbutmentBox( self.abutmentBox )
if bbMode == True :
abutmentBoxDimensions = self.abutmentBoxDict
elif bbMode == False :
layerDict = self.getLayers()
self.drawCapacitor( layerDict, tNet, bNet )
self.drawCapacitor( layerDict, t, b )
else :raise Error(1, 'drawCapacitor(): The bonding box mode parameter, "bbMode" must be either True or False : %s.' %bbMode )
@ -306,16 +365,17 @@ class CapacitorUnit():
## 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 ( tNet , bNet ) nets of top and bottom plates, respectively
def drawCapacitor( self, layerDict, tNet, bNet ):
# \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
#
def drawCapacitor( self, layerDict, t, b ):
self.bottomPlateBox = self.drawOnePlate( layerDict["bottomPlateLayer" ] , bNet , self.bottomPlateBoxDict )
self.topPlateBox = self.drawOnePlate( layerDict["topPlateLayer" ] , tNet , self.topPlateBoxDict )
self.drawBottomPlateCut ( layerDict["topBottomcutsLayer"] , bNet )
self.drawTopPlateCut ( layerDict["topBottomcutsLayer"] , tNet )
self.drawRoutingLayers ( layerDict["bottomPlateRLayer" ] , layerDict["topPlateRLayer"] , tNet , bNet )
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
@ -329,16 +389,22 @@ class CapacitorUnit():
# - 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.
#
def computeBottomPlateCuts( self ):
self.bottomCutLineNumber = self.cutMaxNumber( self.bottomPlateBoxDict["height"], self.minheight_topPlatecut, self.minSpacingOnBotPlate_cut, self.minEnclo_botPlate_botPlateCut )
self.bottomCutLineNumber = self.cutMaxNumber( self.bottomPlateBoxDict["height"]
, self.minheight_topPlatecut
, self.minSpacingOnBotPlate_cut
, self.minEnclo_botPlate_botPlateCut
)
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.cutLeftLineDict ["YMin"] = self.bottomPlateBoxDict["YMin" ] + self.minheight_topPlatecut/2 + enclosure_botPlate_botPlateCut
self.cutRightLineDict["YMin"] = self.cutLeftLineDict ["YMin" ]
return
@ -351,25 +417,37 @@ class CapacitorUnit():
# - 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.
def computeTopPlateCuts( self ):
self.topCutLineNumber = self.cutMaxNumber( self.topPlateBoxDict["height"], self.minheight_topPlatecut, self.minSpacingOnTopPlate_cut, self.minEnclo_topPlate_topPlateCut )
enclosure_topPlate_topPlateCut = ( self.topPlateBoxDict["height"] - (self.topCutLineNumber *self.minheight_topPlatecut + (self.topCutLineNumber -1)*self.minSpacingOnTopPlate_cut) )/2
enclosure_topPlate_topPlateCut = {}
self.topCutLineNumber["vertical"] = self.cutMaxNumber( self.topPlateBoxDict["height"]
, self.minheight_topPlatecut
, self.minSpacingOnTopPlate_cut
, self.minEnclo_topPlate_topPlateCut
)
enclosure_topPlate_topPlateCut["vertical"] = ( self.topPlateBoxDict["height"] - (self.topCutLineNumber["vertical"] *self.minheight_topPlatecut + (self.topCutLineNumber["vertical"] -1)*self.minSpacingOnTopPlate_cut) )/2
if self.capacitorType == 'MIMCap':
self.cut2MatrixDict[ "Width" ] = (self.topCutLineNumber - 2)*self.minWidth_topPlatecut + (self.topCutLineNumber - 1) * self.minSpacingOnTopPlate_cut
cut2MatrixAttribute = ["XMin", "YMin" ]
topPlateBoxCordinates = [self.topPlateBoxDict["XMin"], self.topPlateBoxDict["YMin"]]
self.topCutLineNumber["horizontal"] = self.cutMaxNumber( self.topPlateBoxDict["width"]
, self.minWidth_topPlatecut
, self.minSpacingOnTopPlate_cut
, self.minEnclo_topPlate_topPlateCut
)
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" ] ]
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
topPlateCutTab = [ self.minWidth_topPlatecut , self.minheight_topPlatecut ]
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["YMin"] = self.topPlateBoxDict["YMin"] + self.minheight_topPlatecut/2 + enclosure_topPlate_topPlateCut
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 )
@ -378,23 +456,31 @@ class CapacitorUnit():
return
def computeRoutingLayersDimensions( self ):
if self.capacitorType == 'MIMCap' :
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) ) ]
[ 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
elif self.capacitorType == 'PIPCap' :
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) )
width_topMetal = max( self.minWidth_botRMetal
, (self.minWidth_topPlatecut + 2*self.minEnclo_topPlateRMetal_topPlateCut)
, ( self.minWidth_routingTrackcut + 2*self.minEnclo_routingTrackMetal_cut)
)
width_bottomMetal = width_topMetal
else :
raise Error( 1, 'drawRoutingLayers() : Unsupported capacitor type : %s. Routing layers parameters cannot be computed. ' % self.capacitorType ) #com verirfy the two next lines are after else or before
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"] ]
@ -405,15 +491,31 @@ class CapacitorUnit():
return
def setBottomPlateAbtBoxEnclosure( self, vEnclosure_botPlate_abtBox, hEnclosure_botPlate_abtBox ):
def computeAbutmentBoxDimensions( self, capDim ) :
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 :
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 :
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
self.enclosure_botPlate_topPlate = self.minEnclo_botPlate_botPlateCut + self.minWidth_topPlatecut + self.minSpacing_botPlateCut_topPlate
abutmentBoxDimensions = {}
for key in capDim.keys():
abutmentBoxDimensions[key] = 2*self.enclosure_botPlate_topPlate + capDim[key] + 2*self.minSpacing_botPlate
abutmentBoxDimensions["surface"] = numpy.prod(abutmentBoxDimensions.values())
def computeAbutmentBoxDimensions( self, capDim, vEnclosure_botPlate_abtBox = None, hEnclosure_botPlate_abtBox = None ) :
self.setBottomPlateAbtBoxEnclosure(vEnclosure_botPlate_abtBox, hEnclosure_botPlate_abtBox)
self.enclosure_botPlate_topPlate = self.minEnclo_botPlate_botPlateCut + self.minWidth_topPlatecut + self.minSpacing_botPlateCut_topPlate
abutmentBoxDimensions = {}
abutmentBoxDimensions["width" ] = 2*self.enclosure_botPlate_topPlate + capDim["width" ] + 2*self.hEnclosure_botPlate_abtBox
abutmentBoxDimensions["height" ] = 2*self.enclosure_botPlate_topPlate + capDim["height"] + 2*self.vEnclosure_botPlate_abtBox
#abutmentBoxDimensions["surface"] = numpy.prod(abutmentBoxDimensions.values())
return abutmentBoxDimensions
@ -422,31 +524,34 @@ class CapacitorUnit():
def drawAbutmentBox( self ):
self.abutmentBox = Box(self.abutmentBoxDict["XMin"],self.abutmentBoxDict["YMin"],self.abutmentBoxDict["width"]+self.abutmentBoxDict["XMin"],self.abutmentBoxDict["height"]+self.abutmentBoxDict["YMin"])
self.abutmentBox = Box(self.abutmentBoxDict["XMin" ]
,self.abutmentBoxDict["YMin" ]
,self.abutmentBoxDict["width" ] + self.abutmentBoxDict["XMin"]
,self.abutmentBoxDict["height"] + self.abutmentBoxDict["YMin"]
)
return
def computeOnePlateBoxDimensions( self, inputBoxDimensions, enclosure ):
def computeOnePlateBoxDimensions( self, inputBoxDimensions, vEnclosure, hEnclosure ):
outputboxDimensions = {}
outputboxDimensions["XMin" ] = inputBoxDimensions["XMin" ] + enclosure
outputboxDimensions["YMin" ] = inputBoxDimensions["YMin" ] + enclosure
outputboxDimensions["width" ] = inputBoxDimensions["width" ] - 2*enclosure
outputboxDimensions["height"] = inputBoxDimensions["height"] - 2*enclosure
outputboxDimensions["XMin" ] = inputBoxDimensions["XMin" ] + hEnclosure
outputboxDimensions["YMin" ] = inputBoxDimensions["YMin" ] + vEnclosure
outputboxDimensions["width" ] = inputBoxDimensions["width" ] - 2*hEnclosure
outputboxDimensions["height"] = inputBoxDimensions["height"] - 2*vEnclosure
return outputboxDimensions
def computeDimensions( self, capDim ):
def computeDimensions( self, capDim, vEnclosure, hEnclosure ):
abutmentBoxDimensions = self.computeAbutmentBoxDimensions(capDim)
abutmentBoxDimensions = self.computeAbutmentBoxDimensions(capDim, vEnclosure, hEnclosure )
for key in abutmentBoxDimensions.keys():
self.abutmentBoxDict[key] = abutmentBoxDimensions[key]
self.bottomPlateBoxDict = self.computeOnePlateBoxDimensions( self.abutmentBoxDict , self.minSpacing_botPlate )
self.topPlateBoxDict = self.computeOnePlateBoxDimensions( self.bottomPlateBoxDict, self.enclosure_botPlate_topPlate )
self.bottomPlateBoxDict = self.computeOnePlateBoxDimensions( self.abutmentBoxDict , self.vEnclosure_botPlate_abtBox, self.hEnclosure_botPlate_abtBox )
self.topPlateBoxDict = self.computeOnePlateBoxDimensions( self.bottomPlateBoxDict, self.enclosure_botPlate_topPlate, self.enclosure_botPlate_topPlate )
self.computeBottomPlateCuts()
self.computeTopPlateCuts()
self.computeRoutingLayersDimensions()
@ -456,19 +561,13 @@ class CapacitorUnit():
## 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, inputPlateBox, depth ):
# outputPlateBox = Box( inputPlateBox.getXMin(), inputPlateBox.getYMin(), inputPlateBox.getXMax(), inputPlateBox.getYMax() ).inflate( -depth )
# platePad = Pad.create( net, layer, outputPlateBox )
# NetExternalComponents.setExternal( platePad )
# return outputPlateBox
def drawOnePlate( self, layer, net, boxDimensions) :
outputPlateBox = Box( boxDimensions["XMin"], boxDimensions["YMin"], boxDimensions["XMin"] + boxDimensions["width"], boxDimensions["YMin"] + boxDimensions["height"] )
print("outputPlate",outputPlateBox)
print("net",net)
outputPlateBox = Box( boxDimensions["XMin"]
, boxDimensions["YMin"]
, boxDimensions["XMin"] + boxDimensions["width" ]
, boxDimensions["YMin"] + boxDimensions["height"]
)
platePad = Pad.create( net, layer, outputPlateBox )
NetExternalComponents.setExternal( platePad )
@ -478,37 +577,76 @@ class CapacitorUnit():
## Draws the required cuts to connect the bottom plate. First, the maximal possible number of cuts that can be drawn is computed. Second, using the computed number, the enclosure of this cuts in the bottom plate's layer is adjusted while the minimal enclosure is respected. Third, the relative positions of the cuts on both sides of the plate are computed. Finally, two vertical lines of cuts are drawns.
# \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, bNet ):
def drawBottomPlateCut( self, layer, b ):
self.cutLine( bNet, layer, self.cutLeftLineDict ["XMin"], self.cutLeftLineDict ["YMin"], self.minWidth_botPlatecut, self.minheight_topPlatecut, self.minSpacingOnBotPlate_cut, self.bottomCutLineNumber , 'vertical' )
self.cutLine( bNet, layer, self.cutRightLineDict["XMin"], self.cutRightLineDict["YMin"], self.minWidth_botPlatecut, self.minheight_topPlatecut, self.minSpacingOnBotPlate_cut, self.bottomCutLineNumber , 'vertical' )
self.cutLine( b, layer
, self.cutLeftLineDict ["XMin"]
, self.cutLeftLineDict ["YMin"]
, self.minWidth_botPlatecut
, self.minheight_topPlatecut
, self.minSpacingOnBotPlate_cut
, self.bottomCutLineNumber
, 'vertical'
)
self.cutLine( b, layer
, self.cutRightLineDict["XMin"]
, self.cutRightLineDict["YMin"]
, self.minWidth_botPlatecut
, self.minheight_topPlatecut
, 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.
def drawTopPlateCut( self, layer, tNet ):
def drawTopPlateCut( self, layer, t ):
if self.capacitorType == 'MIMCap':
self.cutMatrix(tNet,layer,self.cut2MatrixDict["XMin"],self.cut2MatrixDict["YMin"],self.minWidth_topPlatecut,self.minheight_topPlatecut,self.minSpacingOnTopPlate_cut,self.topCutLineNumber,self.topCutLineNumber)
self.cutMatrix(t,layer
,self.cut2MatrixDict["XMin"]
,self.cut2MatrixDict["YMin"]
,self.minWidth_topPlatecut
,self.minheight_topPlatecut
,self.minSpacingOnTopPlate_cut
,self.topCutLineNumber["horizontal"]
,self.topCutLineNumber["vertical" ]
)
else : self.cutLine (tNet,layer,self.topCutLineDict["XMin"],self.topCutLineDict["YMin"],self.minWidth_topPlatecut,self.minheight_topPlatecut,self.minSpacingOnTopPlate_cut,self.topCutLineNumber,'vertical')
else : self.cutLine(t,layer
,self.topCutLineDict["XMin"]
,self.topCutLineDict["YMin"]
,self.minWidth_topPlatecut
,self.minheight_topPlatecut
,self.minSpacingOnTopPlate_cut
,self.topCutLineNumber["vertical"]
,'vertical'
)
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 crucual for routing. this of putting it in a second function
## 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, tNet, bNet ):
def drawRoutingLayers( self, bottomPlateLayer, topPlateLayer, t, b ):
Vertical.create ( tNet, topPlateLayer, self.topPlateRLayerDict["XCenter"], self.topPlateRLayerDict["width"], self.topPlateRLayerDict["YMin"], self.topPlateRLayerDict["YMax"] )
Vertical.create ( t, topPlateLayer
, self.topPlateRLayerDict["XCenter"]
, self.topPlateRLayerDict["width" ]
, self.topPlateRLayerDict["YMin" ]
, self.topPlateRLayerDict["YMax" ]
)
cutLinesXMins = [ self.cutLeftLineDict["XMin"], self.cutRightLineDict["XMin"] ]
for i in range(2):
Vertical.create ( bNet, bottomPlateLayer, cutLinesXMins[i] , self.bottomPlateRLayerDict["width"], self.bottomPlateRLayerDict["YMin"], self.bottomPlateRLayerDict["YMax"] )
Vertical.create ( b, bottomPlateLayer
, cutLinesXMins[i]
, self.bottomPlateRLayerDict["width"]
, self.bottomPlateRLayerDict["YMin" ]
, self.bottomPlateRLayerDict["YMax" ]
)
return
@ -566,7 +704,7 @@ class CapacitorUnit():
## \return the ordinate of the highest cut of the bottom plate's left line of cuts.
def getBottomPlateLeftCutYMax ( self ) : return self.cutLeftLineDict ["YMin" ] + ( self.topCutLineNumber - 1 )*( self.minSpacingOnBotPlate_cut + self.minWidth_botPlatecut )
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.
@ -653,13 +791,15 @@ def ScriptMain( **kw ):
device = AllianceFramework.get().createCell( 'capacitor' )
device.setTerminal( True )
bottomPlate_net = Net.create( device, 'bNet' )
bottomPlate_net = Net.create( device, 'b' )
bottomPlate_net.setExternal( True )
bNet = device.getNet("bNet")
b = device.getNet("b")
doBreak( 1, 'Done building bottomPlate')
topPlate_net = Net.create( device, 'tNet' )
topPlate_net = Net.create( device, 't' )
topPlate_net.setExternal( True )
tNet = device.getNet("tNet")
t = device.getNet("t")
doBreak( 1, 'Done building t')
if editor:
UpdateSession.close( )
@ -667,9 +807,9 @@ def ScriptMain( **kw ):
editor.fit ( )
UpdateSession.open ( )
capacitor = CapacitorUnit ( device,500, 'MIMCap', [0,0] ) # 129.56
surface = capacitor.create( bNet, tNet )
print(surface)
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 )

758
oroshi/python/Resistor1.py Normal file
View File

@ -0,0 +1,758 @@
#!/usr/bin/python
import sys
from Hurricane import *
from CRL import *
from math import sqrt, ceil
import helpers
from helpers.io import ErrorMessage as Error
from helpers import trace, u
import oroshi
#from CapacitorUnit import CapacitorUnit
def toDbU ( l ): return DbU.fromPhysical( l, DbU.UnitPowerMicro )
def toPhY ( l ): return DbU.toPhysical ( l, DbU.UnitPowerMicro )
def doBreak( level, message ):
UpdateSession.close()
Breakpoint.stop( level, message )
UpdateSession.open()
helpers.staticInitialization( True )
class Resistor():
rules = oroshi.getRules()
def __init__( self, device, nets, resistorType, resistance = 0, resDim = { "width" : 0.8, "length" : 0 }, direction = "horizontal", snakeMode = False, bends = 0 ):
self.device = device
self.nets = nets
self.__initArgs__ ( resistorType, direction, snakeMode, bends )
[ resDim["width" ], resDim["length"] ] = [ toDbU(resDim["width" ]), toDbU(resDim["length"]) ]
self.__initResDim__( resistance, resDim )
if self.snakeMode :
self.bendDim = self.__computeBendDim__( self )
self.snakeSegmentDict = {}
self.resistorPlateDict = {}
self.abutmentBoxDict = { "XMin" : 0, "YMin" : 0 }
self.abutmentBox = Box ()
self.terminal1Box = Box()
self.terminal2Box = Box()
self.contactsNumber = 0
self.resPlateExtensions_minWidth = 0
self.cutsEnclosure = {}
self.t1CutsDict = {}
self.t2CutsDict = {}
if self.resistorType == "RPOLYH" :
self.pImplant_layerDict = {}
self.hresLayerDict = {}
if self.resistorType == "RPOLY2PH" :
self.restrmLayerDict = {}
self.enclosure_resistor_abutmentBox = {}
self.resPlateExtensions = {}
self.resPlateExtrimities = {}
return
def __initArgs__( self, resistorType, direction, snakeMode, bends ):
if resistorType == "RPOLYH" or resistorType == "RPOLY2PH" : self.resistorType = resistorType
else : raise Error(1,'__initArgs__() : Unsupported resistor type : %s.' % resistorType)
if direction in ["horizontal", "vertical"] : self.direction = direction
else : raise Error(1,'__initDirection__() : Direction must be either "horizontal" or "vertical".')
if snakeMode in [True, False] :
if snakeMode == False and bends == 0 or snakeMode == False and bends > 0 : self.snakeMode = snakeMode
else : raise Error(1,'__initDirection__() : Please check compatibility between snake mode, %s, and bends number, %s.' % (snakeMode, bends))
else : raise Error(1,'__initDirection__() : Snake mode must be either "True" or "False".')
return
def __initResDim__( self, resistance, resDim ):
if self.__isDimOk__( resDim, "width" ) :
if resistance > 0 and resDim["length"] > 0 :
if self.__computeResistance__( resDim, self.resistorType ) == resistance and self.__isDimOk__( resDim, "length" ):
self.resDim = resDim
else :
raise Error(1,'__initResDim__() : Non compatibiliy between resistance value, %s, and the given resistor dimensions, %s, or invalid length, %s.' %(resistance, resDim))
elif resistance > 0 and resDim["length"] == 0 :
self.resDim = self.__computeResDim__( resistance, self.resistorType, resDim )
elif resistance == 0 and resDim["width"] > 0 and resDim["length"] > 0 and self.__isDimOk__( resDim, "length" ):
self.resDim = resDim
else : raise Error(1, '__initResDim__() : Invalid input parameters : resistance and/or resistor dimensions (%s, %s). Please provide at least one valid parameter.' %(resistance, resDim))
return
def __isDimOk__( self, resdim, side ) :
if resdim.keys() == ["width","length"] and side in ["width","length"]:
if side == ["width"]: rule = Resistor.rules.minWidth_rpolyh
else : rule = Resistor.rules.minWidth_rpolyh # Resistor.rules.minLength_rpolyh if self.resistorType == "RPOLYH" else Resistor.rules.minLength_rpolyh
state = True if resdim[side] >= rule else False
if state == False : raise Error(1,'__isDimOk__() : Resistor or bend side dimension exceeds the minimal limit : (side dimension, minimal limit) = (%s ,%s).' % (resdim[side], rule))
else : raise Error(1,'__isDimOk__() : The resistor or bend dimensions and the specified side, %s and %s, must be either "width" or "length".' %(resdim,side))
return state
def __computeResistance__( self, resDim, resistorType ): return self.__getResistorMaterial__( resistorType, "resistorPlate" )*toPhY(resDim["length"])*toPhY(resDim["width"])
def __computeResDim__( self, resistance, resistorType, resDim ):
wl_ratio = resistance/self.__getResistorMaterial__( resistorType, "resistorPlate" )
width = toPhY(resDim["width"])
length = wl_ratio*width
resDim["length"] = toDbU(length)
print('length',length)
if self.__isDimOk__(resDim, "width") and self.__isDimOk__(resDim, "length") :
return resDim
def __getResistorMaterial__( self, resistorType, material ):
if material == 'resistorPlate':
if resistorType == "RPOLYH" : resistance = Resistor.rules.RPOLYHSheetRes
elif resistorType == "RPOLY2PH": resistance = Resistor.rules.RPOLY2PHSheetRes
else : raise Error( 1, '__getResistorMaterial__() : Unsupported resistor type : %s.' % resistorType )
elif material == "contact" :
resistance = Resistor.rules.MET1RPOLYHContRes
return resistance
def __computeBendDim__( self ):
length = 0
if self.__isDimOk__(self.bendDim, "length") : bendDim = { "width" : self.resDim["width"], "length" : toDbU(length) }
return bendDim
def setRules( self ):
self.__setattr__ ( "minSpacing_resistorPlate" , Resistor.rules.minSpacing_rpolyh )
self.__setattr__ ( "minWidth_contact" , Resistor.rules.minWidth_cut0 )
self.__setattr__ ( "minHeight_contact" , Resistor.rules.minWidth_cut0 )
self.__setattr__ ( "minSpacing_contact" , Resistor.rules.minSpacing_cut0 )
self.__setattr__ ( "minEnclosure_resistorPlate_contact" , Resistor.rules.minEnclosure_poly2_cut0 )
if self.resistorType == "RPOLYH":
self.__setattr__( "minWidth_resistorPlate" , Resistor.rules.minWidth_rpolyh )
self.__setattr__( "minWidth_pImplantLayer" , Resistor.rules.minWidth_pImplant )
self.__setattr__( "minSpacing_pImplantLayer" , Resistor.rules.minSpacing_pImplant )
self.__setattr__( "minSpacing_resistorPlate_pImplantLayer" , Resistor.rules.minSpacing_rpolyh_pImplant )
self.__setattr__( "minEnclosure_pImplantLayer_contact" , Resistor.rules.minEnclosure_pImplant_poly2con )
self.__setattr__( "minEnclosure_hres_poly2" , Resistor.rules.minEnclosure_hres_poly2 )
self.__setattr__( "minWidth_hres" , Resistor.rules.minWidth_hres )
self.__setattr__( "minSpacing_hres" , Resistor.rules.minSpacing_hres )
self.__setattr__( "minSpacing_hres_poly1" , Resistor.rules.minSpacing_hres_poly1 )
self.__setattr__( "minSpacing_hres_poly2" , Resistor.rules.minSpacing_hres_poly2 )
self.__setattr__( "minSpacing_hres_active" , Resistor.rules.minSpacing_hres_active )
# self.__setattr__( "minLength_resistorPlate" , Resistor.rules.minLength_rpolyh )
elif self.resistorType == "RPOLY2PH":
self.__setattr__( "minWidth_resistorPlate" , Resistor.rules.minWidth_rpolyh )
# self.__setattr__( "minLength_resistorPlate" , Resistor.rules.minLength_rpoly2ph )
else : raise Error( 1, 'setRules() : Unsupported resistor type : %s.' % resistorType )
return
def __setattr__( self, attribute, value ):
self.__dict__[attribute] = value
return
def getLayers( self ):
technology = DataBase.getDB().getTechnology()
layerDict = {}
layerDict["resistorPlate"] = technology.getLayer( "poly2" )
layerDict["contacts" ] = technology.getLayer( "cut0" )
layerDict["pImplant" ] = technology.getLayer( "pImplant" )
layerDict["resdef" ] = technology.getLayer( "resdef" )
if self.resistorType == "RPOLYH" : layerDict["hres" ] = technology.getLayer( "hres" )
if self.resistorType == "RPOLY2PH" : layerDict["restrm"] = technology.getLayer( "restrm" )
return layerDict
def create( self ):
UpdateSession.open()
self.setRules()
layerDict = self.getLayers()
self.computeDimensions()
self.drawAbutmentBox ()
self.device.setAbutmentBox( self.abutmentBox )
if self.resistorType == "RPOLYH" : self.drawHRESLayer( layerDict["hres"] )
if self.snakeMode == False :
self.drawRectangularResistorPlate( layerDict["resistorPlate"] )
self.drawResPlateExtrimities ( layerDict["resistorPlate"], layerDict["pImplant"] )
# elif :
# pass
self.drawContacts( layerDict["contacts"])
if self.resistorType == "RPOLY2PH" : self.drawRestrmLayer(layerDict["restrm"])
self.drawResDefLayer(layerDict["resdef"])
UpdateSession.close()
return
def computeDimensions( self ):
self.computeAbutmentBoxDimensions2()
if self.snakeMode == False :
self.computeResistorPlateDimensions()
# else : self.computeBendDimensions()
return
def computePImplantLayerDim ( self ):
pImplantLayer_width = max(self.minWidth_pImplantLayer, 2*self.minEnclosure_pImplantLayer_contact + self.minWidth_contact)
# self.pImplant_layerDict["width"] = pImplantLayer_width if self.resDim["width"] < pImplantLayer_width else self.contactsNumber*self.minWidth_contact + (self.contactsNumber-1)*self.minSpacing_contact + 2*self.minEnclosure_pImplantLayer_contact
self.pImplant_layerDict["width" ] = self.contactsNumber*self.minWidth_contact + (self.contactsNumber-1)*self.minSpacing_contact + 2*self.minEnclosure_pImplantLayer_contact
self.pImplant_layerDict["length"] = pImplantLayer_width
return
def computeResPlateExtensionsDim( self ):
self.resPlateExtensions_minWidth = self.minWidth_contact + 2*self.minEnclosure_resistorPlate_contact
print("self.resDim['width']",self.resDim['width'])
print("self.resPlateExtensions_minWidth",self.resPlateExtensions_minWidth)
self.resPlateExtensions["width"] = self.resPlateExtensions_minWidth if self.resDim["width"] < self.resPlateExtensions_minWidth else self.resDim["width"]
if self.resistorType == "RPOLYH" : self.resPlateExtensions["length"] = self.minWidth_contact + self.minEnclosure_resistorPlate_contact + self.minEnclosure_pImplantLayer_contact
if self.resistorType == "RPOLY2PH" : self.resPlateExtensions["length"] = self.minWidth_contact + self.minEnclosure_resistorPlate_contact
return
def computeResPlateExtrimitiesDim( self ):
if self.resistorType == "RPOLYH" :
self.resPlateExtrimities["width" ] = self.pImplant_layerDict["width" ] + 2*self.enclosure_resistor_hres
self.resPlateExtrimities["length"] = self.pImplant_layerDict["length"] + self.enclosure_resistor_hres # self.hresLayerDict #self.pImplant_layerDict
if self.resistorType == "RPOLY2PH" :
self.resPlateExtrimities = self.resPlateExtensions
print("self.resPlateExtrimities['length']ExtrimDim",toPhY(self.resPlateExtrimities["length"]))
return
def computeAbutmentBoxDimensions( self ):
if self.resistorType == "RPOLYH" : self.enclosure_resistor_abutmentBox = max(self.minSpacing_hres, self.minSpacing_hres_poly1, self.minSpacing_hres_poly2, self.minSpacing_hres_active) #max(self.minSpacing_resistorPlate, self.minSpacing_pImplantLayer, self.minSpacing_resistorPlate_pImplantLayer)
if self.resistorType == "RPOLY2PH" : self.enclosure_resistor_abutmentBox = self.minSpacing_resistorPlate
if self.snakeMode == False:
self.computeResPlateExtensionsDim()
self.contactsNumber = self.cutMaxNumber( self.resPlateExtensions["width"], self.minHeight_contact, self.minSpacing_contact, self.minEnclosure_resistorPlate_contact )
if self.resistorType == "RPOLYH" :
self.computePImplantLayerDim()
self.computeResPlateExtrimitiesDim()
abutmentBoxSide1 = self.resPlateExtrimities["width"] + 2*self.enclosure_resistor_abutmentBox
abutmentBoxSide2 = self.resDim["length"] + 2*self.resPlateExtrimities["length"] + 2*self.enclosure_resistor_abutmentBox
if self.direction == "vertical" :
self.abutmentBoxDict["width" ] = abutmentBoxSide1
self.abutmentBoxDict["height"] = abutmentBoxSide2
if self.direction == "horizontal" :
self.abutmentBoxDict["width" ] = abutmentBoxSide2
self.abutmentBoxDict["height"] = abutmentBoxSide1
if self.snakeMode == True : print("hi")
return
def computeAbutmentBoxDimensions2( self ):
if self.resistorType == "RPOLYH" : self.enclosure_resistor_abutmentBox = self.minSpacing_hres #max(self.minSpacing_resistorPlate, self.minSpacing_pImplantLayer, self.minSpacing_resistorPlate_pImplantLayer)
if self.resistorType == "RPOLY2PH" : self.enclosure_resistor_abutmentBox = self.minSpacing_resistorPlate
if self.snakeMode == False:
self.computeResPlateExtensionsDim()
self.contactsNumber = self.cutMaxNumber( self.resPlateExtensions["width"], self.minHeight_contact, self.minSpacing_contact, self.minEnclosure_resistorPlate_contact )
if self.resistorType == "RPOLYH" :
self.computePImplantLayerDim()
self.computeHRESLayerDimensions()
self.computeResPlateExtrimitiesDim()
print("self.resPlateEtrimities['length']abtBoxDim2",toPhY(self.resPlateExtrimities['length']))
abutmentBoxSide1 = self.resPlateExtrimities["width"] + 2*self.enclosure_resistor_abutmentBox
print("self.resPlateExtrimities",self.resPlateExtrimities)
abutmentBoxSide2 = self.resDim["length"] + 2*self.resPlateExtrimities["length"] + 2*self.enclosure_resistor_abutmentBox
print("self.resDim['length']2",toPhY(self.resDim["length"]))
print("self.enclosure_resistor_abutmentBox2",toPhY(self.enclosure_resistor_abutmentBox))
print("self.resPlateEtrimities['length']2",toPhY(self.resPlateExtrimities['length']))
# if self.resistorType == "RPOLYH" : abutmentBoxSide2 = self.resPlateExtrimities["length"]+ 2*self.enclosure_resistor_abutmentBox
# if self.resistorType == "RPOLY2PH" : abutmentBoxSide2 = self.resDim["length"] + 2*self.resPlateExtrimities["length"] + 2*self.enclosure_resistor_abutmentBox
print("abutmentBoxSide2",toPhY(abutmentBoxSide2))
if self.direction == "vertical" :
self.abutmentBoxDict["width" ] = abutmentBoxSide1
self.abutmentBoxDict["height"] = abutmentBoxSide2
if self.direction == "horizontal" :
self.abutmentBoxDict["width" ] = abutmentBoxSide2
self.abutmentBoxDict["height"] = abutmentBoxSide1
if self.snakeMode == True : print("hi")
return
def computeHRESLayerDimensions( self ):
self.enclosure_resistor_hres = self.minEnclosure_hres_poly2
hresLayerSide1 = max(self.minWidth_hres, self.pImplant_layerDict["width" ] + 2*self.enclosure_resistor_hres)
#hresLayerSide2 = max(self.minWidth_hres, 2*self.pImplant_layerDict["length"] + 2*self.enclosure_resistor_hres + self.resDim["length"])
if self.direction == "vertical" :
#self.hresLayerDict["width" ] = hresLayerSide2
self.hresLayerDict["length"] = hresLayerSide1
if self.direction == "horizontal" :
self.hresLayerDict["width" ] = hresLayerSide1
#self.hresLayerDict["length"] = hresLayerSide2
return
def computeResistorPlateDimensions( self ):
self.resistorPlateDict["width" ] = self.resDim["width" ]
self.resistorPlateDict["length" ] = self.resDim["length"]
if self.direction == "vertical" :
self.resistorPlateDict["XCenter"] = self.abutmentBoxDict ["XMin"] + self.abutmentBoxDict ["width"]/2
self.resistorPlateDict["YMin" ] = self.abutmentBoxDict ["YMin"] + self.enclosure_resistor_abutmentBox + self.resPlateExtrimities["length"]
self.resistorPlateDict["YMax" ] = self.resistorPlateDict["YMin"] + self.resistorPlateDict["length"]
if self.direction == "horizontal" :
print("self.abutmentBoxDict ['XMin']",toPhY(self.abutmentBoxDict ["XMin"]))
print("self.enclosure_resistor_abutmentBox",toPhY(self.enclosure_resistor_abutmentBox))
print("self.resPlateExtrimities['length']",toPhY(self.resPlateExtrimities["length"]
))
self.resistorPlateDict["YCenter"] = self.abutmentBoxDict ["YMin"] + self.abutmentBoxDict ["height"]/2
self.resistorPlateDict["XMin" ] = self.abutmentBoxDict ["XMin"] + self.enclosure_resistor_abutmentBox + self.resPlateExtrimities["length"]
print("self.resistorPlateDict['XMin' ]",toPhY(self.resistorPlateDict["XMin" ]))
self.resistorPlateDict["XMax" ] = self.resistorPlateDict["XMin"] + self.resistorPlateDict["length"]
return
def computeHRESLayerPosition( self ):
if self.direction == "vertical" :
self.hresLayerDict["XCenter"] = self.abutmentBox.getXCenter()
self.hresLayerDict["YMin" ] = self.abutmentBox.getYMin() + self.enclosure_resistor_abutmentBox
self.hresLayerDict["YMax" ] = self.abutmentBox.getYMax() - self.enclosure_resistor_abutmentBox
if self.direction == "horizontal" :
self.hresLayerDict["YCenter"] = self.abutmentBox.getYCenter()
self.hresLayerDict["XMin" ] = self.abutmentBox.getXMin() + self.enclosure_resistor_abutmentBox
self.hresLayerDict["XMax" ] = self.abutmentBox.getXMax() - self.enclosure_resistor_abutmentBox
return
def drawLayer( self, layer, positionParams ):
if self.direction == "vertical" : positionParamsKeys = ["XCenter","width","YMin","YMax"]
if self.direction == "horizontal" : positionParamsKeys = ["YCenter","width","XMin","XMax"]
if type(positionParams) is dict :
for key in positionParams.keys() :
if key not in positionParams : raise Error(1,'drawLayer() : %s must contain all following keys : %s.' %(positionParams, positionParams))
else : raise Error(1,'drawLayer() : %s must be a dictionary of %s keys.' %(positionParams, positionParams) )
if layer == 1: self.computeHRESLayerPosition()
if layer == 1: self.computeResDefDimensions()
if self.direction == "vertical" : Vertical.create ( self.nets[0], layer, positionParams["XCenter"], positionParams["width"], positionParams["YMin"], positionParams["YMax"] )
if self.direction == "horizontal" : Horizontal.create( self.nets[0], layer, positionParams["YCenter"], positionParams["width"], positionParams["XMin"], positionParams["XMax"] )
return
def drawHRESLayer( self, layer ):
print("layer",layer)
self.computeHRESLayerPosition()
if self.direction == "vertical" : Vertical.create ( self.nets[0], layer, self.hresLayerDict["XCenter"], self.hresLayerDict["length"], self.hresLayerDict["YMin"], self.hresLayerDict["YMax"] )
if self.direction == "horizontal" : Horizontal.create ( self.nets[0], layer, self.hresLayerDict["YCenter"], self.hresLayerDict["width" ], self.hresLayerDict["XMin"], self.hresLayerDict["XMax"] )
return
def drawAbutmentBox( self ):
self.abutmentBox = Box(self.abutmentBoxDict["XMin"], self.abutmentBoxDict["YMin"], self.abutmentBoxDict["width"], self.abutmentBoxDict["height"])
return
def drawRectangularResistorPlate( self, layer ):
if self.direction == "vertical" : Vertical.create ( self.nets[0], layer, self.resistorPlateDict["XCenter"], self.resistorPlateDict["width"], self.resistorPlateDict["YMin"], self.resistorPlateDict["YMax"] )
if self.direction == "horizontal" : Horizontal.create( self.nets[0], layer, self.resistorPlateDict["YCenter"], self.resistorPlateDict["width"], self.resistorPlateDict["XMin"], self.resistorPlateDict["XMax"] )
return
def drawResPlateExtrimities( self, resPlateLayer, pImplantLayer ):
self.drawResPlateExtensions(resPlateLayer)
if self.resistorType == "RPOLYH" : self.drawPImplantLayer(pImplantLayer)
return
def computeResPlateExtensionsPosition( self ):
self.resPlateExtensions["ex1"] = {}
if self.direction == "vertical" :
self.resPlateExtensions["ex1"]["XMin"] = self.abutmentBox.getXCenter() - self.resPlateExtensions["width" ]/2
self.resPlateExtensions["ex1"]["YMin"] = self.abutmentBox.getYCenter() - self.resPlateExtensions["length"] - self.resDim["length"]/2
self.resPlateExtensions["ex1"]["XMax"] = self.resPlateExtensions["ex1"]["XMin"] + self.resPlateExtensions["width" ]
self.resPlateExtensions["ex1"]["YMax"] = self.resPlateExtensions["ex1"]["YMin"] + self.resPlateExtensions["length"]
if self.direction == "horizontal" :
self.resPlateExtensions["ex1"]["XMin"] = self.abutmentBox.getXCenter() - self.resPlateExtensions["length"] - self.resDim["length"]/2
self.resPlateExtensions["ex1"]["YMin"] = self.abutmentBox.getYCenter() - self.resPlateExtensions["width" ]/2
self.resPlateExtensions["ex1"]["XMax"] = self.resPlateExtensions["ex1"]["XMin"] + self.resPlateExtensions["length"]
self.resPlateExtensions["ex1"]["YMax"] = self.resPlateExtensions["ex1"]["YMin"] + self.resPlateExtensions["width" ]
return
def drawResPlateExtensions( self, layer ):
self.computeResPlateExtensionsPosition()
translation = self.resDim["length"] + self.resPlateExtensions["length"]
if self.direction == "vertical" :
self.terminal1Box = Box(self.resPlateExtensions["ex1"]["XMin"], self.resPlateExtensions["ex1"]["YMin"], self.resPlateExtensions["ex1"]["XMax"], self.resPlateExtensions["ex1"]["YMax"])
self.terminal2Box = Box(self.resPlateExtensions["ex1"]["XMin"], self.resPlateExtensions["ex1"]["YMin"] + translation, self.resPlateExtensions["ex1"]["XMax"], self.resPlateExtensions["ex1"]["YMax"] + translation)
if self.direction == "horizontal" :
self.terminal1Box = Box(self.resPlateExtensions["ex1"]["XMin"], self.resPlateExtensions["ex1"]["YMin"], self.resPlateExtensions["ex1"]["XMax"], self.resPlateExtensions["ex1"]["YMax"])
self.terminal2Box = Box(self.resPlateExtensions["ex1"]["XMin"] + translation, self.resPlateExtensions["ex1"]["YMin"], self.resPlateExtensions["ex1"]["XMax"] + translation, self.resPlateExtensions["ex1"]["YMax"])
terminal1Pad = Pad.create(self.nets[0], layer, self.terminal1Box)
terminal2Pad = Pad.create(self.nets[1], layer, self.terminal2Box)
return
def computePImplantLayerPosition( self ):
if self.direction == "vertical" :
self.pImplant_layerDict["YCenter"] = self.abutmentBoxDict ["YMin"] + self.enclosure_resistor_abutmentBox + self.enclosure_resistor_hres + self.pImplant_layerDict["length"]/2
self.pImplant_layerDict["XMin" ] = self.abutmentBox.getXCenter() - self.pImplant_layerDict["width"]/2
self.pImplant_layerDict["XMax" ] = self.pImplant_layerDict["XMin"] + self.pImplant_layerDict["width"]
if self.direction == "horizontal" :
self.pImplant_layerDict["XCenter"] = self.abutmentBoxDict ["XMin"] + self.enclosure_resistor_abutmentBox + self.enclosure_resistor_hres + self.pImplant_layerDict["length"]/2 #self.minWidth_contact + self.minEnclosure_resistorPlate_contact)/2
self.pImplant_layerDict["YMin" ] = self.abutmentBox.getYCenter() - self.pImplant_layerDict["width"]/2 #self.abutmentBoxDict ["YMin"] + self.enclosure_resistor_abutmentBox
self.pImplant_layerDict["YMax" ] = self.pImplant_layerDict["YMin"] + self.pImplant_layerDict["width"]
return
def drawPImplantLayer( self, layer ):
self.computePImplantLayerPosition()
translation = self.resDim["length"] + self.pImplant_layerDict["length"]
if self.direction == "vertical" :
Horizontal.create( self.nets[0], layer, self.pImplant_layerDict["YCenter"] , self.pImplant_layerDict["length"], self.pImplant_layerDict["XMin"], self.pImplant_layerDict["XMax"] )
Horizontal.create( self.nets[0], layer, self.pImplant_layerDict["YCenter"] + translation, self.pImplant_layerDict["length"], self.pImplant_layerDict["XMin"], self.pImplant_layerDict["XMax"] )
if self.direction == "horizontal" :
Vertical.create ( self.nets[0], layer, self.pImplant_layerDict["XCenter"] , self.pImplant_layerDict["length"], self.pImplant_layerDict["YMin"], self.pImplant_layerDict["YMax"] )
Vertical.create ( self.nets[1], layer, self.pImplant_layerDict["XCenter"] + translation, self.pImplant_layerDict["length"], self.pImplant_layerDict["YMin"], self.pImplant_layerDict["YMax"] )
return
def computeCutsDimensions( self ):
if self.direction == "vertical":
self.cutsEnclosure ["horizontal"] = ( self.resPlateExtensions["width"] - (self.contactsNumber*self.minHeight_contact + (self.contactsNumber -1)*self.minSpacing_contact) )/2
self.cutsEnclosure ["vertical" ] = self.minEnclosure_resistorPlate_contact
if self.direction == "horizontal" :
self.cutsEnclosure["horizontal"] = self.minEnclosure_resistorPlate_contact
self.cutsEnclosure["vertical" ] = ( self.resPlateExtensions["width"] - (self.contactsNumber*self.minHeight_contact + (self.contactsNumber -1)*self.minSpacing_contact) )/2
self.t1CutsDict["XCenter"] = self.terminal1Box.getXMin() + self.cutsEnclosure ["horizontal"] + self.minWidth_contact/2
self.t1CutsDict["YCenter"] = self.terminal1Box.getYMin() + self.cutsEnclosure ["vertical" ] + self.minHeight_contact/2
if self.resistorType == "RPOLYH" : translation = self.resDim["length"] + self.minWidth_contact + 2*self.minEnclosure_pImplantLayer_contact
if self.resistorType == "RPOLY2PH" : translation = self.resDim["length"] + self.minWidth_contact
if self.direction == "vertical":
self.t2CutsDict["XCenter"] = self.t1CutsDict["XCenter"]
self.t2CutsDict["YCenter"] = self.t1CutsDict["YCenter"] + translation
if self.direction == "horizontal" :
self.t2CutsDict["XCenter"] = self.t1CutsDict["XCenter"] + translation
self.t2CutsDict["YCenter"] = self.t1CutsDict["YCenter"]
return
def drawContacts( self, layer ):
self.computeCutsDimensions()
if self.direction == "vertical" : cutLineDirection = "horizontal"
if self.direction == "horizontal" : cutLineDirection = "vertical"
self.cutLine( self.nets[0], layer, self.t1CutsDict["XCenter"], self.t1CutsDict["YCenter"], self.minWidth_contact, self.minHeight_contact, self.minSpacing_contact, self.contactsNumber , cutLineDirection )
self.cutLine( self.nets[1], layer, self.t2CutsDict["XCenter"], self.t2CutsDict["YCenter"], self.minWidth_contact, self.minHeight_contact, self.minSpacing_contact, self.contactsNumber , cutLineDirection )
return
def drawRestrmLayer( self, layer ):
self.computeRestrmLayerPosition()
translation = self.resDim["length"] + self.restrmLayerDict["width"]
if self.direction == "vertical" :
Horizontal.create( self.nets[0], layer, self.restrmLayerDict["YCenter"] , self.restrmLayerDict["width"], self.restrmLayerDict["XMin"], self.restrmLayerDict["XMax"] )
Horizontal.create( self.nets[1], layer, self.restrmLayerDict["YCenter"]+translation, self.restrmLayerDict["width"], self.restrmLayerDict["XMin"], self.restrmLayerDict["XMax"] )
if self.direction == "horizontal" :
Vertical.create ( self.nets[0], layer, self.restrmLayerDict["XCenter"] , self.restrmLayerDict["width"], self.restrmLayerDict["YMin"], self.restrmLayerDict["YMax"] )
Vertical.create ( self.nets[1], layer, self.restrmLayerDict["XCenter"]+translation, self.restrmLayerDict["width"], self.restrmLayerDict["YMin"], self.restrmLayerDict["YMax"] )
return
def computeRestrmLayerPosition( self ):
self.restrmLayerDict["width"] = self.minWidth_contact/2
if self.direction == "vertical" :
self.restrmLayerDict["YCenter"] = self.t1CutsDict["YCenter"] + self.restrmLayerDict["width"]/2
self.restrmLayerDict["XMin" ] = self.resPlateExtensions["ex1"]["XMin"] - self.restrmLayerDict["width"]
self.restrmLayerDict["XMax" ] = self.resPlateExtensions["ex1"]["XMax"] + self.restrmLayerDict["width"]
if self.direction == "horizontal" :
self.restrmLayerDict["XCenter"] = self.t1CutsDict["XCenter"] + self.restrmLayerDict["width"]/2
self.restrmLayerDict["YMin" ] = self.resPlateExtensions["ex1"]["YMin"] - self.restrmLayerDict["width"]
self.restrmLayerDict["YMax" ] = self.resPlateExtensions["ex1"]["YMax"] + self.restrmLayerDict["width"]
return
def computeResDefDimensions( self ):
self.resdefDict = self.resistorPlateDict
if self.resistorType == "RPOLY2PH" :
if self.direction == "vertical" : keysList = ["YMin","YMax","width"]
if self.direction == "horizontal" : keysList = ["XMin","XMax","width"]
self.resdefDict[keysList[0]] = self.resdefDict[keysList[0]] - self.minWidth_contact/4
self.resdefDict[keysList[1]] = self.resdefDict[keysList[1]] + self.minWidth_contact/4
if self.resDim["width"] > self.resPlateExtensions_minWidth :
self.resdefDict[keysList[2]] = self.resdefDict[keysList[2]] + self.minWidth_contact/2
return
def drawResDefLayer( self, layer ):
self.computeResDefDimensions()
if self.direction == "vertical" : Vertical.create ( self.nets[0], layer, self.resdefDict["XCenter"], self.resdefDict["width"], self.resdefDict["YMin"], self.resdefDict["YMax"] )
if self.direction == "horizontal" : Horizontal.create ( self.nets[0], layer, self.resdefDict["YCenter"], self.resdefDict["width"], self.resdefDict["XMin"], self.resdefDict["XMax"] )
return
## 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 ):
for i in range(0, cutNumber) :
segment = Contact.create( net, layer, firstCutXCenter + i*(width_cut + spacing_cut), firstCutYCenter, width_cut, height_cut ) if direction == 'horizontal' else Contact.create( net, layer, firstCutXCenter, firstCutYCenter + i*(height_cut + spacing_cut), width_cut, height_cut )
return segment
## 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 ):
cutNumber = int( (width_layer - 2*enclosure_cut + spacing_cut) / (width_cut + spacing_cut) )
if cutNumber > 0 :
return cutNumber
else : raise Error (1,"cutMaxNumber() : Zero number of cuts found. Layer width is too tight." )
def ScriptMain( **kw ):
editor = None
if kw.has_key('editor') and kw['editor']:
editor = kw['editor']
UpdateSession.open()
device = AllianceFramework.get().createCell( 'resistor' )
device.setTerminal( True )
t_1 = Net.create( device, 't1' )
t_1.setExternal( True )
t1 = device.getNet("t1")
doBreak( 1, 'Done building terminal 1 net')
t_2 = Net.create( device, 't2' )
t_2.setExternal( True )
t2 = device.getNet("t2")
doBreak( 1, 'Done building terminal 1 net')
if editor:
UpdateSession.close( )
editor.setCell ( device )
editor.fit ( )
UpdateSession.open ( )
nets = [t1,t2]
#( device, resistorType, resistance = 0, resDim = { "width" : 10, "length" : 0 }, direction = "vertical", snakeMode = False, bends = 0 ):
#resistor = Resistor( device, nets, "RPOLY2PH", 50, direction = "vertical" )
resistor = Resistor( device, nets, "RPOLY2PH", 50, direction = "horizontal" ) #l = 0.8 dogBone
# resistor = Resistor( device, nets, "RPOLYH", 2000, direction = "horizontal" ) #RPOLYH normal
# resistor = Resistor( device, nets, "RPOLY2PH", 100, direction = "horizontal" ) #RPOLY2PH normal
# resistor = Resistor( device, nets, "RPOLY2PH", 25, direction = "vertical" ) #L=w/2
resistor.create()
AllianceFramework.get().saveCell( device, Catalog.State.Views )
return True

View File

@ -6,6 +6,10 @@ from helpers import trace
class Rules ( object ):
ruleSet = [ 'minSpacing_nWell'
, 'minWidth_pImplant'
, 'minSpacing_pImplant'
, 'minSpacing_rpolyh_pImplant'
, 'minEnclosure_pImplant_poly2con'
, 'minEnclosure_nImplant_active'
, 'minEnclosure_pImplant_active'
, 'minSpacing_nImplant_pImplant'
@ -57,6 +61,7 @@ class Rules ( object ):
, 'minWidth_cpoly'
, 'minWidth_poly2'
, 'minWidth_rpolyh'
, 'minWidthHighPrec_rpolyh'
, 'minSpacing_cpoly'
, 'minSpacing_poly2'
, 'minSpacing_rpolyh'
@ -70,6 +75,18 @@ class Rules ( object ):
, 'PIPCap'
, 'MIMPerimeterCap'
, 'PIPPerimeterCap'
, 'RPOLYHSheetRes'
, 'RPOLY2PHSheetRes'
, 'MET1RPOLYHContRes'
, 'minWidth_hres'
, 'minSpacing_hres'
, 'minEnclosure_hres_poly2'
, 'minSpacing_hres_poly1'
, 'minSpacing_hres_poly2'
, 'minSpacing_hres_active'
, 'corrFactor90'
, 'corrFactor135'
, 'minRpolyhSquares'
]
def __init__ ( self, dtr ):
@ -86,8 +103,15 @@ class Rules ( object ):
value = None
words = attribute.split( '_' )
try:
if len(words) == 1 and words[0].endswith('Cap'): value = self.dtr.getUnitRule( words[0] ).getValue()
elif len(words) < 4: value = self.dtr.getPhysicalRule( *tuple(words) ).getValue()
if len(words) == 1:
if words[0].endswith('Cap' ): value = self.dtr.getUnitRule( words[0] ).getValue()
if words[0].endswith('ContRes' ): value = self.dtr.getUnitRule( words[0] ).getValue()
if words[0].endswith('Res' ): value = self.dtr.getUnitRule( words[0] ).getValue()
if words[0].endswith('ctor90' ): value = self.dtr.getUnitRule( words[0] ).getValue()
if words[0].endswith('ctor135' ): value = self.dtr.getUnitRule( words[0] ).getValue()
if words[0].endswith('quares' ): value = self.dtr.getUnitRule( words[0] ).getValue()
elif len(words) < 4:
value = self.dtr.getPhysicalRule( *tuple(words) ).getValue()
except Exception, e:
print e

View File

@ -0,0 +1,4 @@
V ALLIANCE : 6
H capacitor,P,12/12/2019,100
A 0,0,27184,27184
EOF

View File

@ -0,0 +1,29 @@
-- =======================================================================
-- Coriolis Structural VHDL Driver
-- Generated on Dec 12, 2019, 11:42
--
-- To be interoperable with Alliance, it uses it's special VHDL subset.
-- ("man vhdl" under Alliance for more informations)
-- =======================================================================
entity capacitor is
port ( b0 : linkage bit
; b1 : linkage bit
; b2 : linkage bit
; b3 : linkage bit
; t0 : linkage bit
; t1 : linkage bit
; t2 : linkage bit
; t3 : linkage bit
);
end capacitor;
architecture structural of capacitor is
begin
end structural;