Merge branch 'devel' of ssh://bop-t/users/largo2/git/coriolis into devel

This commit is contained in:
Jean-Paul Chaput 2019-12-15 20:16:58 +01:00
commit 41a49809d2
10 changed files with 1975 additions and 128 deletions

View File

@ -7,10 +7,12 @@
WIP_Transistor.py
WIP_DP.py
WIP_CSP.py
NonUnitCapacitor.py
CapacitorUnit.py
CapacitorMatrix.py
CapacitorVRTracks.py
CapacitorRouted.py
CapacitorRoutedSingle.py
MultiCapacitor.py
ResistorSnake.py
)

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

@ -0,0 +1,629 @@
#!/usr/bin/python
import sys
from Hurricane import *
from CRL import *
from math import sqrt, ceil
import helpers
from helpers import ErrorMessage as Error
from helpers import trace
import oroshi
from CapacitorFinal6 import CapacitorUnit
from CapacitorMatrix20 import CapacitorStack
## Routs a compact or a matrix of capacitors by connecting it to routing tracks. For a fixed instance, only one type of capacitor is supported at a time, either the Poly-Poly type or Metal-Metal in 350 nm AMS CMOS technology.
# The dummy mode is also supported.
def toDbU ( l ): return DbU.fromPhysical( l, DbU.UnitPowerMicro )
def doBreak( level, message ):
UpdateSession.close()
Breakpoint.stop( level, message )
UpdateSession.open()
helpers.staticInitialization( True )
class RoutCapacitor( CapacitorUnit ):
rules = oroshi.getRules()
## The constructor computes some of the class attributes and initialises others which will be computed later inside some of the class methods.
# \param device The Hurricane AMS device into which the layout is drawn.
# \param capacitorInstance Instance of the class CapacitorMatrix.
# \param capacitor A nested list containing a compact capacitor (in the first element) or elementary capacitors of a matrix of capacitors (each row in a list).
# \param dummyMode is \c "True" when dummy capacitor is drawn.
# \param capacitorType Can be MIM or PIP type capacitor.
# \param abutmentBox The abutment box of the compact or matrix capacitor.
# \param routingTrackYCenter A nested dictionary containing the ordinates of top and bottom ( including upper and lower) routing tracks.
# \param xPlateRLayerXCenter A nested dictionary containing
# \param xPlateRLayer_width A dictionary containing the widths of the top and bottom plates routing layers.
# \param routingTrack_width The width of a routing track. Is fixed according to technological parameters.
# \param tracksNumbers A dictionary containing the number of top and bottom tracks. The allowed maximum total number of tracks is two.
# \param topPlateWSpec Routing specifications for the top plates.
# \param bottomPlateWSpec Routing specifications for the bottom plates.
# \remarks An exception is raised if the entered routing specifications are invalid. Invalidity can be due to a wrong total number of tracks or bad wiring specifications of top and bottom tracks. More information about the valid specifications is given in \c function.
def __init__( self, capacitorInstance, capacitor, dummyMode = False, tracksNumbers = [1,1], topPlateWSpec = [1,0] , bottomPlateWSpec = [0,1] ):
if (capacitorInstance.matchingMode == True) : raise Error(1,'__init__() : This class is only dedicated to route matrices equivalent to one capacitor. In case of a matched matrix of capacitors, please use <RoutMatchedCapacitor>.')
self.device = capacitorInstance.device
self.capacitorInstance = capacitorInstance
self.capacitor = capacitor
self.dummyMode = dummyMode
self.capacitorType = capacitorInstance.capacitorType
self.matrixDim = capacitorInstance.matrixDim
self.abutmentBox = capacitorInstance.abutmentBox
self.abutmentBox_spacing = self.capacitorInstance.getAbutmentBox_spacing ()
self.bondingBox = Box()
self.capacitorType = capacitorInstance.capacitorType
self.nets = capacitorInstance.nets[0]
self.routingTracksXMinXMax = {}
self.routingTrackYCenter = { "top": {}, "bottom": {} }
self.xPlateRLayerXCenter = { "top": [], "bottom": [], "bottomBorders" : [] }
self.xPlateRLayer_width = {}
self.routingTrack_width = 0
if ( self.__isRoutingTracksNumberOK__( tracksNumbers ) ):
self.tracksNumbers = { "top" : tracksNumbers[0] ,"bottom" : tracksNumbers[1] }
possibleRoutingSchemes = self.__setPossibleRoutingSchemes__( tracksNumbers )
if dummyMode == True :
if self.connectToTopTracksOnly() :
self.topPlateWSpec = [1,0]
elif self.connectToBottomTracksOnly() :
self.topPlateWSpec = [0,1]
else :
self.topPlateWSpec = [1,1]
self.bottomPlateWSpec = self.topPlateWSpec
elif ( dummyMode == False and self.__isWiringSpecOK__(topPlateWSpec, bottomPlateWSpec, possibleRoutingSchemes) ) :
self.topPlateWSpec = topPlateWSpec
self.bottomPlateWSpec = bottomPlateWSpec
else : raise Error(1,'__init__() : Invalid routing specifications in terms of number, format or routing scheme.')
else : raise Error(1,' __init__() : One routing track on one or both sides of the capacitor is allowed in dummy mode. Otherwise, routing tracks can be drawn one on each side or two on one side : (top trak number : %s, bottom track number : %s and dummy mode is %s). ' %( tracksNumbers[0], tracksNumbers[1], dummyMode )) #com verify the difference between a simple print and the dicitionary self.trackingNumber
return
## Using functions calls and the entered parameters, This function draws the routing tracks, then, connects the compact or matrix of capacitors to routing tracks using routing layers and adequate cuts. \c rout function also initialises: cuts layers according to :
# - the capacitor type (ie., cuts2 if MIMCAP, cut1 if PIPCAP )
# - routing tracks layers according to the designer specifications.
def rout( self, bbMode = False ):
UpdateSession.open ()
bondingBox = {}
self.setRules ()
self.computeDimensions ( bbMode )
if bbMode :
bondingBox = self.computeLayoutDimensionsInbbMode()
if not bbMode:
routingTracksLayer = DataBase.getDB().getTechnology().getLayer("metal2")
bottomPlateRLayer = CapacitorUnit.getLayers( self )["bottomPlateRLayer"]
topPlateRLayer = bottomPlateRLayer
if self.capacitorType == 'MIMCap' :
topbottomCutLayer = DataBase.getDB().getTechnology().getLayer("cut2")
elif self.capacitorType == 'PIPCap' :
topbottomCutLayer = DataBase.getDB().getTechnology().getLayer("cut1")
else : raise Error( 1,'rout() : Unsupported capacitor type : %s.' %self.capacitorType )
self.drawRoutingTracks ( routingTracksLayer )
self.drawPlatesVRLayers ( 'topPlate' , topPlateRLayer , self.topPlateWSpec , self.xPlateRLayerXCenter["top" ], self.xPlateRLayer_width["top" ] )
self.drawPlatesVRLayers ( 'bottomPlate' , bottomPlateRLayer , self.bottomPlateWSpec, self.xPlateRLayerXCenter["bottom"], self.xPlateRLayer_width["bottom" ] )
self.drawCuts ( self.nets[0], 'topPlate' , self.topPlateWSpec , topbottomCutLayer , self.xPlateRLayer_width ["top" ], self.xPlateRLayerXCenter["top" ] )
self.drawCuts ( self.nets[1], 'bottomPlate' , self.bottomPlateWSpec, topbottomCutLayer , self.xPlateRLayer_width ["bottom"], self.xPlateRLayerXCenter["bottom"] )
UpdateSession.close ()
return bondingBox
## Builds and returns a dictionary of the needed technological rules to rout the capacitor.
# The significant rules are :
# - the minimum spacing between the routing tracks according to their metal layer,
# - the minimum width of a plate, a cut or a routing metal,
# - the minimum width, height and spacing between the cuts on the routing track.
# - etc.
#
# At the exception of the minimum spacing between routing tracks, every rule has two possible values according to the capacitor type.
# \remarks An exception is raised if the entered capacitor type is unsupported.
def setRules ( self ):
CapacitorUnit.setRules ( self )
CapacitorUnit.__setattr__ ( self, "minSpacing_routingTrackMetal" , RoutCapacitor.rules.minSpacing_metal2 )
if self.capacitorType == 'MIMCap' :
CapacitorUnit.__setattr__( self, "minHeight_routingTrackcut" , RoutCapacitor.rules.minWidth_cut2 )
CapacitorUnit.__setattr__( self, "minSpacing_routingTrackcut" , RoutCapacitor.rules.minSpacing_cut2 )
CapacitorUnit.__setattr__( self, "minWidth_routingTrackcut" , RoutCapacitor.rules.minWidth_cut2 )
elif self.capacitorType == 'PIPCap' :
CapacitorUnit.__setattr__( self, "minHeight_routingTrackcut" , RoutCapacitor.rules.minWidth_cut1 )
CapacitorUnit.__setattr__( self, "minSpacing_routingTrackcut" , RoutCapacitor.rules.minSpacing_cut1 )
CapacitorUnit.__setattr__( self, "minWidth_routingTrackcut" , RoutCapacitor.rules.minWidth_cut1 )
else : raise Error(1, 'setRules() : Unsupported capacitor type "%s".' % self.capacitorType )
return
## Checks if the wiring specifications are compatible with the possible routing schemes.
# \return \c "True" if all conditions are satisfied.
# \param topWiringSpec The desired connection of the top plate.
# \param bottomWiringSpec The desired connection of the top plate.
# \param possibleRoutingSchemes A list of the possible connections computed according to routing tracks specifications.
def __isWiringSpecOK__ ( self, topPlateWiringSpec, bottomPlateWiringSpec, possibleRoutingSchemes ):
state = False
if len(topPlateWiringSpec ) == len( bottomPlateWiringSpec ) == 2 and [ topPlateWiringSpec, bottomPlateWiringSpec ] in possibleRoutingSchemes :
state = True
else : raise Error(1, '__isWiringSpecOK__() : Invalid wiring specifications for top and/or bottom plates, %s and/or %s, respectively. The possible wiring schemes are : %s. ' %(topPlateWiringSpec, bottomPlateWiringSpec, possibleRoutingSchemes) )
return state
## Builds and retuns a list containing the possible routing schemes according to routing tracks specifications. All the possibilities are summarized in Table 1.
# \param topTrackNumber The specified number of top routing tracks. Two tracks are defined : the lower and upper ones. Considering a maximum number of top and bottom tracks equal to two, \c topTracksNumber takes 0, 1, 2 when \c bottomTrackNumber is equal to 2, 1, 0, respectively.
# \param bottomTrackNumber The specified number of bottom routing tracks. The same rules and specifications as top tracks apply to bottom tracks.
# \param possibleRoutingSchemes A list of the possible connections computed according to routing tracks specifications.
def __setPossibleRoutingSchemes__( self, tracksNumbers ):
[topTrackNumber , bottomTrackNumber] = [tracksNumbers[0] , tracksNumbers[1]]
possibleRoutingSchemes = None
if self.dummyMode == False: possibleRoutingSchemes = [ [[0,1],[1,0]], [[1,0],[0,1]] ]
return possibleRoutingSchemes
## Checks if the tracks numbers are valid. The requirements which must be satifsied are :
# - A maximum number of total tracks equal to two (ie., the sum of bottom tracks number and top tracks number must be equal to 2).
# - The specified numbers for top and bottom tracks belong to the set \c {0,1,2}. Therefore, if the sum is equal to two and one or both numbers are not in {0,1,2}, this is considered as invalid.
# \return \c "True" if all conditions are satisfied.
# \param topTrackNumber The specified number for top tracks.
# \param topTrackNumber The specified number for bottom tracks.
# \throw <object> Wrong values for routing tracks
def __isRoutingTracksNumberOK__ ( self, tracksNumbers ):
[topTrackNumber , bottomTrackNumber] = [tracksNumbers[0] , tracksNumbers[1]]
state = False
if self.dummyMode == True:
if ( bottomTrackNumber == 1 and topTrackNumber == 0 or bottomTrackNumber == 0 and topTrackNumber == 1 or bottomTrackNumber == 1 and topTrackNumber == 1 ) :
state = True
elif self.dummyMode == False:
if ( bottomTrackNumber == 1 and topTrackNumber == 1 or bottomTrackNumber == 0 and topTrackNumber == 2 or bottomTrackNumber == 2 and topTrackNumber == 0 ) :
state = True
else : raise Error( 1, '__isRoutingTracksNumberOK__() : Wrong values for routing tracks "%s , %s". ' %(bottomTrackNumber, topTrackNumber) ) #com test this
return state
## Computes relevant attributes (layout parameters) by calling two functions to compute properties and dimensions of :
# - the routing layers of top and bottom plates
# - the routing tracks
def computeDimensions( self, bbMode ):
self.computeRLayersDimensions ( bbMode )
self.computeHRoutingTrackDimensions( )
return
def computeRLayersDimensions( self, bbMode ):
self.routingTrack_width = 2*self.minEnclo_routingTrackMetal_cut + self.minWidth_routingTrackcut
if not bbMode :
print(self.capacitor)
self.xPlateRLayer_width["top"] = self.capacitor.getTopPlateRLayerWidth() if self.capacitorInstance.matrixDim.values() == [1,1] else self.capacitor[0][0].getTopPlateRLayerWidth()
if self.capacitorInstance.__isUnitCap__() :
self.computeRLayersDimensionsCompactCap ()
else : self.computeRLayersDimensionsMatrixCap()
return
def computeRLayersDimensionsCompactCap( self ):
self.bordersRLayerXMin = [ self.capacitor.getBottomPlateLeftCutXMin(), self.capacitor.getBottomPlateRightCutXMin() ]
self.xPlateRLayer_width ["bottomBorders"] = self.capacitor.getBotPlateRLayerWidth ()
self.xPlateRLayer_width ["bottom" ] = []
self.xPlateRLayerXCenter["bottom" ] = []
self.xPlateRLayerXCenter["top" ].append( self.capacitor.getTopPlateRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor.getBotPlateLeftRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor.getBotPlateRightRLayerXCenter () )
return
def computeRLayersDimensionsMatrixCap( self ):
if self.capacitorInstance.matrixDim["columns"] > 1 :
self.xPlateRLayer_width["bottom"] = ( self.capacitor[0][1].getBotPlateLeftRLayerXMax() - self.capacitor[0][0].getBotPlateRightRLayerXMin() )
self.bordersRLayerXMin = [ self.capacitor[0][0].getBottomPlateLeftCutXMin(), self.capacitor[0][-1].getBottomPlateRightCutXMin() ]
elif self.capacitorInstance.matrixDim["columns"] == 1 :
self.bordersRLayerXMin = [ self.capacitor[0][0].getBottomPlateLeftCutXMin(), self.capacitor[0][0].getBottomPlateRightCutXMin() ]
else : raise Error( 1, 'computeRLayersDimensionsMatrixCap() : Negative number of columns in the matrix "%s".' % self.capacitorInstance.matrixDim["columns"] )
self.xPlateRLayer_width["bottomBorders"] = self.capacitor[0][0].getBotPlateRLayerWidth()
for i in range( 0, self.matrixDim["columns"] ):
self.xPlateRLayerXCenter["top"].append( self.capacitor[0][i].getTopPlateRLayerXCenter() )
for i in range( 0,self.matrixDim["columns"] -1 ):
self.xPlateRLayerXCenter["bottom"].append( self.capacitor[0][i].getBotPlateRightRLayerXMin() + self.xPlateRLayer_width["bottom"]/2 )
if self.capacitorInstance.matrixDim["columns"] > 1 :
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][ 0].getBotPlateLeftRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][-1].getBotPlateRightRLayerXCenter() )
else :
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][0].getBotPlateLeftRLayerXCenter () )
self.xPlateRLayerXCenter["bottomBorders"].append( self.capacitor[0][0].getBotPlateRightRLayerXCenter () )
return
## Actual function that computes routing tracks dimensions and positions.
def computeHRoutingTrackDimensions( self ):
self.routingTracksXMinXMax = { "XMin" : self.abutmentBox.getXMin() , "XMax" : self.abutmentBox.getXMax() }
if self.dummyMode == True:
if self.connectToTopTracksOnly () :
self.routingTrackYCenter["top" ]["lower"] = self.abutmentBox.getYMax() + self.minSpacing_botPlate + self.routingTrack_width/2
self.topLowerTrackDict = {"YMin" : self.routingTrackYCenter["top" ]["lower"] - self.routingTrack_width/2, "YMax" : self.routingTrackYCenter["top" ]["lower"] + self.routingTrack_width/2}
elif self.connectToBottomTracksOnly () :
self.routingTrackYCenter["bottom"]["upper"] = self.abutmentBox.getYMin() - self.minSpacing_botPlate - self.routingTrack_width/2
self.bottomUpperTrackDict = {"YMin" : self.routingTrackYCenter["bottom"]["upper"] - self.routingTrack_width/2, "YMax" : self.routingTrackYCenter["bottom"]["upper"] + self.routingTrack_width/2}
else :
self.routingTrackYCenter["top" ]["lower"] = self.abutmentBox.getYMax() + self.minSpacing_botPlate + self.routingTrack_width/2
self.routingTrackYCenter["bottom"]["upper"] = self.abutmentBox.getYMin() - self.minSpacing_botPlate - self.routingTrack_width/2
self.topLowerTrackDict = {"YMin" : self.routingTrackYCenter["top" ]["lower"] - self.routingTrack_width/2, "YMax" : self.routingTrackYCenter["top" ]["lower"] + self.routingTrack_width/2}
self.bottomUpperTrackDict = {"YMin" : self.routingTrackYCenter["bottom"]["upper"] - self.routingTrack_width/2, "YMax" : self.routingTrackYCenter["bottom"]["upper"] + self.routingTrack_width/2}
elif self.dummyMode == False:
if self.connectToTopTracksOnly () :
self.routingTrackYCenter["top" ]["lower"] = self.abutmentBox.getYMax() + self.minSpacing_botPlate + self.routingTrack_width/2
self.routingTrackYCenter["top" ]["upper"] = self.routingTrackYCenter["top"]["lower"] + self.minSpacing_routingTrackMetal + self.routingTrack_width
self.topLowerTrackDict = {"YMin" : self.routingTrackYCenter["top" ]["lower"] - self.routingTrack_width/2, "YMax" : self.routingTrackYCenter["top" ]["lower"] + self.routingTrack_width/2}
self.topUpperTrackDict = {"YMin" : self.routingTrackYCenter["top" ]["upper"] - self.routingTrack_width/2, "YMax" : self.routingTrackYCenter["top" ]["upper"] + self.routingTrack_width/2}
elif self.connectToBottomTracksOnly () :
self.routingTrackYCenter["bottom"]["upper"] = self.abutmentBox.getYMin() - self.minSpacing_botPlate - self.routingTrack_width/2
self.routingTrackYCenter["bottom"]["lower"] = self.routingTrackYCenter["bottom"]["upper"] - self.minSpacing_routingTrackMetal - self.routingTrack_width
self.bottomUpperTrackDict = {"YMin" : self.routingTrackYCenter["bottom"]["upper"] - self.routingTrack_width/2, "YMax" : self.routingTrackYCenter["bottom"]["upper"] + self.routingTrack_width/2}
self.bottomLowerTrackDict = {"YMin" : self.routingTrackYCenter["bottom"]["lower"] - self.routingTrack_width/2, "YMax" : self.routingTrackYCenter["bottom"]["lower"] + self.routingTrack_width/2}
elif self.connectToTopAndBottomTracks() :
self.routingTrackYCenter["top" ]["lower"] = self.abutmentBox.getYMax() + self.minSpacing_botPlate + self.routingTrack_width/2
self.routingTrackYCenter["bottom"]["upper"] = self.abutmentBox.getYMin() - self.minSpacing_botPlate - self.routingTrack_width/2
self.topLowerTrackDict = {"YMin" : self.routingTrackYCenter["top" ]["lower"] - self.routingTrack_width/2, "YMax" : self.routingTrackYCenter["top" ]["lower"] + self.routingTrack_width/2}
self.bottomUpperTrackDict = {"YMin" : self.routingTrackYCenter["bottom"]["upper"] - self.routingTrack_width/2, "YMax" : self.routingTrackYCenter["bottom"]["upper"] + self.routingTrack_width/2}
else : raise Error( 1, ' computeHRoutingTrackDimensions() : Wrong number or values for routing tracks, top : "%s", bottom : "%s". ' %(self.tracksNumbers["top"], self.tracksNumbers["bottom"]) )
else : raise Error( 1, 'computeHRoutingTrackDimensions() : The dummy mode must be either "True" or "False", "%s". ' % self.dummyMode )
return
def computeLayoutDimensionsInbbMode( self ):
bondingBoxDict = {}
bondingBoxDict ["width" ] = self.routingTracksXMinXMax["XMax"] - self.routingTracksXMinXMax["XMin"]
bondingBoxDict["XMin" ] = self.routingTracksXMinXMax["XMin"]
if self.dummyMode == True :
if self.connectToTopTracksOnly () :
bondingBoxDict["height" ] = self.topLowerTrackDict["YMax"] - self.abutmentBox.getYMin()
bondingBoxDict["YMin" ] = self.abutmentBox.getYMin()
elif self.connectoToBottomTracksOnly() :
bondingBoxDict["height" ] = self.abutmentBox.getYMax() - self.bottomUpperTrackDict["YMin"]
bondingBoxDict["YMin" ] = self.bottomUpperTrackDict["YMin"]
else :
bondingBoxDict["height" ] = self.topLowerTrackDict["YMax"] - self.abutmentBox.getYMin()
bondingBoxDict["YMin" ] = self.bottomUpperTrackDict["YMin"]
elif self.dummyMode == False:
if self.connectToTopTracksOnly () :
bondingBoxDict["height" ] = self.topUpperTrackDict["YMax"] - self.abutmentBox.getYMin()
bondingBoxDict["YMin" ] = self.abutmentBox.getYMin()
elif self.connectoToBottomTracksOnly() :
bondingBoxDict["height" ] = self.abutmentBox.getYMax() - self.bottomLowerTrackDict["YMin"]
bondingBoxDict["YMin" ] = self.bottomLowerTrackDict["YMin"]
else:
bondingBoxDict["height" ] = self.topLowerTrackDict["YMax"] - self.bottomUpperTrackDict["YMin"]
bondingBoxDict["YMin" ] = self.bottomUpperTrackDict["YMin"]
else : raise Error( 1, 'computeLayoutDimensionsInbbMode() : The dummy mode must be either "True" or "False", "%s". ' % self.dummyMode )
bondingBoxDict["surface"] = bondingBoxDict["width"]*bondingBoxDict["height"]
self.bondingBox = Box( bondingBoxDict["XMin"], bondingBoxDict["YMin"], bondingBoxDict["XMin"] + bondingBoxDict["width"] , bondingBoxDict["YMin"] + bondingBoxDict["height"] )
return bondingBoxDict
## Draws routing tracks, above and/or below the capacitor. A maximum total number of two tracks is drawn. In dummy mode, one track is drawn.
# \param routingTracksLayer Layer of the routing track.
# \remark All routing tracks, top and bottom (upper and lower), are drawn using the same layer.
def drawRoutingTracks( self , routingTracksLayer ):
self.drawTopOrBottomRoutingTracks ( "top" , routingTracksLayer )
self.drawTopOrBottomRoutingTracks ( "bottom", routingTracksLayer )
return
def drawTopOrBottomRoutingTracks ( self, tracksPosition, routingTracksLayer ) :
if tracksPosition in ["top","bottom"] :
attribut = ["lower","upper"]
nets = self.__setNetsDistributionHRTs__()
for i in range( 0, self.tracksNumbers[tracksPosition] ):
index = i if tracksPosition == "top" else i-1
routingtrackYCenter = self.routingTrackYCenter[tracksPosition][attribut[index]]
Horizontal.create ( nets[i] , routingTracksLayer, routingtrackYCenter , self.routingTrack_width , self.routingTracksXMinXMax["XMin"], self.routingTracksXMinXMax["XMax"] )
print("netsi",nets[i])
else : raise Error(1,'drawOneRoutingTrack() : The track position must be either "top" or "bottom" : %s.' %tracksPosition)
return
def __setNetsDistributionHRTs__( self ):
if self.dummyMode == False :
netsDistribution = self.nets if [self.topPlateWSpec, self.bottomPlateWSpec] == [[1,0],[0,1]] else [self.nets[1], self.nets[0]]
else : netsDistribution = self.nets
return netsDistribution
## Draws the routing layers connecting top and bottom plates to the associated routing track.
# \param Plate The capacitor's plate to be routed (ie., top, bottom).
# \paramx PlateRLayer Routing layer.
# \param PlateWSpec Connection specifications of the plate.
# \param xPlateRLayerXCenter Horizontal position of the routing layer.
# \param xPlateRLayer_width Width of the routing layer.
# \throw < plate-name > \c Undefined \c plate
# \throw < specification > \c Invalid \c routing \c specifications
def drawPlatesVRLayers( self, Plate, xPlateRLayer, PlateWSpec, xPlateRLayerXCenter, xPlateRLayer_width ):
if self.capacitorInstance.__isUnitCap__() :
[firstElementInCapacitor , lastElementInCapacitor] = [self.capacitor , self.capacitor]
elif not( self.capacitorInstance.__isUnitCap__() ):
[firstElementInCapacitor , lastElementInCapacitor] = [self.capacitor[0][0] , self.capacitor[-1][0]]
[ doTop, doBottom ] = [1, 0] if Plate == 'topPlate' else [0, 1]
if ( Plate == 'topPlate' ) :
YMinDict = {
"toTopToUpper" : firstElementInCapacitor.getTopPlateRLayerYMin(),
"toTopToLower" : firstElementInCapacitor.getTopPlateRLayerYMin(),
"toBottomToUpper" : lastElementInCapacitor.getTopPlateRLayerYMax(),
"toBottomToLower" : lastElementInCapacitor.getTopPlateRLayerYMax()
}
net = self.nets[0]
xMetalXCenter = self.xPlateRLayerXCenter["top"]
elif ( Plate == 'bottomPlate' ) :
YMinDict = {
"toTopToUpper" : firstElementInCapacitor.getBotPlateRLayerYMin(),
"toTopToLower" : firstElementInCapacitor.getBotPlateRLayerYMin(),
"toBottomToUpper" : lastElementInCapacitor.getBotPlateRLayerYMax(),
"toBottomToLower" : lastElementInCapacitor.getBotPlateRLayerYMax()
}
net = self.nets[1]
xMetalXCenter = self.xPlateRLayerXCenter["bottom"]
else : raise Error( 1, 'drawPlatesVRLayers() : Undefined plate, "%s".' % Plate )
if ( self.connectToTopTracksOnly () and self.connectToUpper( PlateWSpec ) ) :
[ dySource, dyTarget ] = [ YMinDict["toTopToUpper" ] , self.topUpperTrackDict["YMax"] ]
elif ( self.connectToTopTracksOnly () and self.connectToLower( PlateWSpec ) ) or ( self.connectToTopAndBottomTracks () and self.connectToUpper( PlateWSpec ) ) :
dyTarget = self.topLowerTrackDict ["YMax"]
dySource = self.bottomUpperTrackDict["YMin"] if self.dummyMode == True and self.connectToTopAndBottomTracks () else YMinDict["toTopToLower" ]
elif ( self.connectToBottomTracksOnly() and self.connectToUpper( PlateWSpec ) ) or ( self.connectToTopAndBottomTracks () and self.connectToLower( PlateWSpec ) ) :
[ dySource, dyTarget ] = [ YMinDict["toBottomToUpper"] , self.bottomUpperTrackDict["YMin"] ]
elif ( self.connectToBottomTracksOnly() and self.connectToLower( PlateWSpec ) ) :
[ dySource, dyTarget ] = [ YMinDict["toBottomToLower"] , self.bottomLowerTrackDict["YMin"] ]
else : raise Error( 1, 'drawPlatesVRLayers() : Invalid routing specifications "%s".' % PlateWSpec )
for i in range( 0, self.matrixDim["columns"] - doBottom ):
Vertical.create ( net, xPlateRLayer, xPlateRLayerXCenter[i], xPlateRLayer_width, dySource, dyTarget )
if doBottom :
for i in range( 0,2):
Vertical.create ( self.nets[1], xPlateRLayer , self.xPlateRLayerXCenter["bottomBorders"][i], self.xPlateRLayer_width["bottomBorders"], dySource, dyTarget )
return
## Draws one or multiple cuts between a routing track and a routing layer to connect the capacitor plate to the track. The function supports cuts for top and bottom plates. First, using wiring specifications, he position of the cuts is identified. Second, the maximum nupmber of cuts is computed, then, its enclosure in the routing layer is adjusted. Third, the cuts are iteratively drawn on every intersection between the routing track and the plate's routing layer.
# \remark Since in the special case of bottom plate, routing layers on matrix borders are thinner than the intermediate ones, two extra steps are excecuted to draw cuts connecting border routing layers to the routing track. The two steps are computing the maximum number of cuts, which is lower than intermediate cuts, and ajusting its enclosure.
# \throw <Invalid-specifictions > \c Not \c possible \c to \c compute cuts vertical position due to invalid routing specifications
# \remak The number of cuts is maximized according to the track's width.
# \param net Net of the Hurricane Device to which the cuts will be connected.
# \param Plate Capacitor's plate, top or bottom.
# \param PlateWSpec Wiring specifications of the plate. It is useful to identify the track on which the cuts are to draw.
# \param layer Cut's layer.
# \param xPlateRLayer_width Width of the plate's routing layer. It is useful to compute the maximum number of cuts.
# \param xPlateRLayerXCenter Hrizontal position of the plate's routing layer, which also defines the cut's position.
def drawCuts( self, net, Plate, PlateWSpec, layer, xPlateRLayer_width, xPlateRLayerXCenter ):
[ doTop, doBottom ] = [1, 0] if Plate == 'topPlate' else [0, 1]
cutsYCenter = self. __setCutsYCenter__( PlateWSpec )
if not( self.capacitorInstance.__isUnitCap__() ) or ( self.capacitorInstance.__isUnitCap__() and doTop ) :
print("xPlateRLayer_width",xPlateRLayer_width)
cutsNumber = CapacitorUnit.cutMaxNumber( self, xPlateRLayer_width, self.minWidth_routingTrackcut, self.minSpacing_routingTrackcut, self.minEnclo_routingTrackMetal_cut )
enclosure_RLayer_cut = ( xPlateRLayer_width - cutsNumber*self.minWidth_routingTrackcut - ( cutsNumber - 1 )*self.minSpacing_routingTrackcut ) / 2
for i in range( 0, self.matrixDim["columns"] - doBottom ):
cutXCenter = xPlateRLayerXCenter[i] - xPlateRLayer_width/2 + enclosure_RLayer_cut + self.minWidth_routingTrackcut/2
CapacitorUnit.cutLine( self, net, layer, cutXCenter, cutsYCenter, self.minWidth_routingTrackcut, self.minHeight_routingTrackcut, self.minSpacing_routingTrackcut, cutsNumber , 'horizontal' )
if self.dummyMode == True and self.connectToTopAndBottomTracks() :
CapacitorUnit.cutLine( self, net, layer, cutXCenter, self.routingTrackYCenter["bottom"]["upper"], self.minWidth_routingTrackcut, self.minHeight_routingTrackcut, self.minSpacing_routingTrackcut, cutsNumber , 'horizontal' )
if doBottom :
borderscutsNumber = CapacitorUnit.cutMaxNumber( self, self.xPlateRLayer_width["bottomBorders"], self.minWidth_routingTrackcut, self.minSpacing_routingTrackcut, self.minEnclo_routingTrackMetal_cut )
enclosure_RLayer_cut = ( self.xPlateRLayer_width["bottomBorders"] - borderscutsNumber*self.minWidth_routingTrackcut - ( borderscutsNumber - 1 )*self.minSpacing_routingTrackcut ) / 2
for i in range( 0,2):
CapacitorUnit.cutLine( self, net, layer, self.xPlateRLayerXCenter["bottomBorders"][i], cutsYCenter, self.minWidth_routingTrackcut, self.minHeight_routingTrackcut, self.minSpacing_routingTrackcut, borderscutsNumber , 'horizontal' )
if self.dummyMode == True and self.connectToTopAndBottomTracks() :
CapacitorUnit.cutLine( self, net, layer, self.xPlateRLayerXCenter["bottomBorders"][i], self.routingTrackYCenter["bottom"]["upper"], self.minWidth_routingTrackcut, self.minHeight_routingTrackcut, self.minSpacing_routingTrackcut, borderscutsNumber , 'horizontal' )
return
def __setCutsYCenter__( self, PlateWSpec ):
if ( self.connectToTopTracksOnly () and self.connectToLower( PlateWSpec ) ) or ( self.connectToTopAndBottomTracks() and self.connectToUpper( PlateWSpec ) ) :
cutsYCenter = self.routingTrackYCenter["top"]["lower"]
elif ( self.connectToTopTracksOnly () and self.connectToUpper( PlateWSpec ) ) :
cutsYCenter = self.routingTrackYCenter["top"]["upper"]
elif ( self.connectToBottomTracksOnly() ) and ( self.connectToUpper( PlateWSpec ) ) or ( self.connectToTopAndBottomTracks() and self.connectToLower( PlateWSpec ) ) :
cutsYCenter = self.routingTrackYCenter["bottom"]["upper"]
elif ( self.connectToBottomTracksOnly() and self.connectToLower( PlateWSpec ) ) :
cutsYCenter = self.routingTrackYCenter["bottom"]["lower"]
else : raise Error( 1, '__setCutsYCenter__() : Not possible to compute cuts vertical position due to invalid routing specifications "%s".' % PlateWSpec )
return cutsYCenter
## \return \c True if the plate is to be connected to one of the two top tracks.
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
def connectToTopTracksOnly (self) : return True if self.tracksNumbers["top"] == 2 and self.tracksNumbers["bottom"] == 0 and self.dummyMode == False or self.tracksNumbers["top"] == 1 and self.tracksNumbers["bottom"] == 0 and self.dummyMode == True else False
## \return \c True if the plate is to be connected to one of the two bottom tracks.
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
def connectToBottomTracksOnly (self) : return True if self.tracksNumbers["top"] == 0 and self.tracksNumbers["bottom"] == 2 and self.dummyMode == False or self.tracksNumbers["top"] == 0 and self.tracksNumbers["bottom"] == 1 and self.dummyMode == True else False
def connectToTopAndBottomTracks( self ) : return True if self.tracksNumbers["top"] == 1 and self.tracksNumbers["bottom"] == 1 else False
## \return \c True if the plate is to be connected to the upper track of top or bottom tracks.
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
def connectToUpper( self, plateWiringSpec ) : return True if plateWiringSpec [1] == 1 else False
## \return \c True if the plate is to be connected to the lower track of top or bottom tracks.
# \param WiringSpecChain Wiring specifications of a capacitor's top or bottom plate
def connectToLower( self, plateWiringSpec ) : return True if plateWiringSpec [0] == 1 else False
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_net0.setExternal( True )
b0 = Device.getNet("b0")
doBreak( 1, 'Done building bottomPlate')
topPlate_net0 = Net.create( Device, 't0' )
topPlate_net0.setExternal( True )
t0 = Device.getNet("t0")
doBreak( 1, 'Done building topPlate')
if editor:
UpdateSession.close()
editor.setCell( Device )
editor.fit()
UpdateSession.open()
nets = [[t0,b0]]
capacitance = [400]
capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets,unitCap = 400)
# capacitorInstance = CapacitorStack( Device, 400, 'MIMCap', [0,0], unitCap = 100 )
capacitor = capacitorInstance.create()
print(capacitor)
# routedCap = RoutCapacitor( capacitorInstance, capacitor , tracksNumbers = [2,0], topPlateWSpec = [0,1] , bottomPlateWSpec = [1,0] )
# routedCap = RoutCapacitor( capacitorInstance, capacitor, dummyMode = False , tracksNumbers = [1,1], topPlateWSpec = [0,1] , bottomPlateWSpec = [1,0] )
routedCap = RoutCapacitor( capacitorInstance, capacitor, dummyMode = True, tracksNumbers = [1,0] ) #, topPlateWSpec = [0,1] , bottomPlateWSpec = [1,0] )
# routedCap = RoutCapacitor( capacitorInstance, capacitor, dummyMode = True , tracksNumbers = [1,0]) #, topPlateWSpec = [1,0] , bottomPlateWSpec = [1,0] )
bondingBox = routedCap.rout()
print(bondingBox)
AllianceFramework.get().saveCell( Device, Catalog.State.Views )
return True

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 )

View File

@ -0,0 +1,256 @@
#!/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
import oroshi
from CapacitorFinal7 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 NonUnitCapacitor(CapacitorUnit):
rules = oroshi.getRules()
def __init__( self, device, capacitorType, direction, capacitance, capacitorUnit, abutmentBoxPosition, capUnitTopPlates_spacing = -1 ):
self.device = device
self.capacitorType = capacitorType
self.direction = direction
self.capacitance = capacitance
self.capacitorUnit = capacitorUnit
self.abutmentBoxPosition = abutmentBoxPosition
self.capUnitTopPlates_spacing = capUnitTopPlates_spacing
self.unitCapDim = CapacitorUnit.__computeCapDim__( self, capacitorUnit, capacitorType )
if self.__isDirectionOk__(direction):
self.nonUnitCapDim = {"width" : self.unitCapDim["width"] , "height" : 0 } if direction == "vertical" else {"width" : 0 , "height" : self.unitCapDim["width"] }
self.nonUnitCapDim_sideLimit = 0
self.dummyCapDim = {}
return
def __isDirectionOk__( self, direction ):
state = True if direction in ["horizontal","vertical"] else False
if state == False : raise Error(1,'__isDirectionOk__() : The direction must be either "vertical" or "horizontal" : %s.' % direction)
return state
def setRules( self ):
CapacitorUnit.setRules(self)
if self.capacitorType == 'MIMCap':
self.__setattr__( "minWidth_dummyTopPlate" , CapacitorUnit.rules.minWidth_metcapdum )
elif self.capacitorType == 'PIPCap':
self.__setattr__( "minWidth_dummyTopPlate" , CapacitorUnit.rules.minWidth_cpoly )
return
def create( self, b, t ) :
UpdateSession.open()
self.setRules()
self.computeDimensions()
if self.__isCapacitorOk__() :
print('drawing capacitor')
activeCapacitor = CapacitorUnit ( self.device, self.capacitorType, self.abutmentBoxPosition, capDim = self.nonUnitCapDim )
activeCapacitor.create( b, t )
side = "height" if self.direction == "vertical" else "width"
if self.__isNonUnitCapSideOk__( side ) :
print("drawing dummy too")
# activeCapacitor = CapacitorUnit ( self.device, activeCapacitance, self.capacitorType, self.abutmentBoxPosition )
dummyAbutmentBoxPosition = [ self.abutmentBoxPosition[0], self.abutmentBoxPosition[1] - CapacitorUnit.computeAbutmentBoxDimensions( self, self.dummyCapDim )["height"] ] if self.direction == "vertical" else [ self.abutmentBoxPosition[0] + CapacitorUnit.computeAbutmentBoxDimensions( self, self.nonUnitCapDim )["width"] , self.abutmentBoxPosition[1] ]
dummyCapacitor = CapacitorUnit( self.device, self.capacitorType, dummyAbutmentBoxPosition, capDim = self.dummyCapDim )
# activeCapacitor.create( b, t )
dummyCapacitor.create ( b, t )
else : print("not drawing dummy")
# abutmentBoxDimensions = self.computeAbutmentBoxDimensions(capDim)
# CapacitorUnit.drawAbutmentBox( self )
else : raise Error(1,'create() : Impossible to draw capacitor in the defined geometric limits.')
UpdateSession.close()
return
def __isCapacitorOk__( self ):
capacitorMax = self.computeCapacitorMax()
print("CMax",capacitorMax)
print("self.capacitance",self.capacitance)
print("self.capUnitTopPlates_spacing",toPhy(self.capUnitTopPlates_spacing))
return True if self.capacitance < capacitorMax else False
def computeDimensions( self ):
if self.capUnitTopPlates_spacing == -1 :
CapacitorUnit.computeAbutmentBoxDimensions(self, self.unitCapDim )
self.capUnitTopPlates_spacing = 2*(self.minSpacing_botPlate + self.enclosure_botPlate_topPlate)
self.nonUnitCapDim_sideLimit = 2*self.unitCapDim["width"] - self.minWidth_dummyTopPlate
if self.direction == "vertical":
self.nonUnitCapDim["height"] = self.computeNonUnitCapheight()
else : self.nonUnitCapDim["width"] = self.computeNonUnitCapheight()
print("sideLimit",toPhy(self.nonUnitCapDim_sideLimit))
print("self.capUnitTopPlates_spacing",toPhy(self.capUnitTopPlates_spacing))
print('self.nonUnitCapDim["width"]',toPhy(self.nonUnitCapDim["width"]))
print('self.nonUnitCapDim["height"]',toPhy(self.nonUnitCapDim["height"]))
nonUnitCapDim_sideMax = 2*self.unitCapDim["width"] + self.capUnitTopPlates_spacing
self.dummyCapDim["width" ] = self.unitCapDim["width" ] if self.direction == "vertical" else nonUnitCapDim_sideMax - self.capUnitTopPlates_spacing - self.nonUnitCapDim["width"]
self.dummyCapDim["height"] = nonUnitCapDim_sideMax - self.capUnitTopPlates_spacing - self.nonUnitCapDim["height"] if self.direction == "vertical" else self.unitCapDim["width" ]
print("self.dummyCapDim",toPhy(self.dummyCapDim["width" ]))
print("self.dummyCapDim",toPhy(self.dummyCapDim["height" ]))
return
def computeCapacitorMax( self ):
[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = CapacitorUnit.__setCapacitorPerUnit__(self, self.capacitorType)
capUnit_width = toPhy( self.unitCapDim["width"] )
topPlates_spacing = toPhy( self.capUnitTopPlates_spacing )
print("[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ]",[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ])
print("width",capUnit_width)
CMax = ( 2*capUnit_width + topPlates_spacing )*capUnit_width*areaCapacitorPerUnit + ( 3*capUnit_width + topPlates_spacing )*perimeterCapacitorPerUnit
return CMax
def computeNonUnitCapheight( self ):
[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = CapacitorUnit.__setCapacitorPerUnit__(self, self.capacitorType)
width = toPhy( self.unitCapDim["width"] )
height = self.capacitance/( (width*areaCapacitorPerUnit + perimeterCapacitorPerUnit) + width*perimeterCapacitorPerUnit )
print("height",height)
return toDbU(height)
def __isNonUnitCapSideOk__( self, side ):
if side in ["width","height"]:
state = True if self.nonUnitCapDim[side] < self.nonUnitCapDim_sideLimit else False
else : raise Error(1,'__isNonUnitCapSideOk__() : The side must be either "width" or "height" : %s.' % side)
return state
def ScriptMain( **kw ):
editor = None
if kw.has_key('editor') and kw['editor']:
editor = kw['editor']
UpdateSession.open()
device = AllianceFramework.get().createCell( 'nonUnitCapacitor' )
device.setTerminal( True )
bottomPlate_net = Net.create( device, 'b' )
bottomPlate_net.setExternal( True )
b = device.getNet("b")
doBreak( 1, 'Done building bottomPlate')
topPlate_net = Net.create( device, 't' )
topPlate_net.setExternal( True )
t = device.getNet("t")
doBreak( 1, 'Done building tNet')
if editor:
UpdateSession.close( )
editor.setCell ( device )
editor.fit ( )
UpdateSession.open ( )
nonUnitCapacitor = NonUnitCapacitor ( device, 'PIPCap', 'horizontal', 65, 50, [0,0] )
nonUnitCapacitor.create(b,t)
AllianceFramework.get().saveCell( device, Catalog.State.Views )
return True

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;