257 lines
7.8 KiB
Python
257 lines
7.8 KiB
Python
#!/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 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 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 'editor' in kw 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
|
|
|