Merge branch 'devel' of ssh://bop-t/users/largo2/git/coriolis into devel
This commit is contained in:
commit
41a49809d2
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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'] ])
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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 )
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
V ALLIANCE : 6
|
||||
H capacitor,P,12/12/2019,100
|
||||
A 0,0,27184,27184
|
||||
EOF
|
|
@ -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;
|
||||
|
Loading…
Reference in New Issue