768 lines
49 KiB
Python
768 lines
49 KiB
Python
#!/usr/bin/python
|
|
|
|
import sys
|
|
from Hurricane import *
|
|
from CRL import *
|
|
import helpers
|
|
from helpers.io import ErrorMessage as Error
|
|
from helpers import trace
|
|
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.
|
|
# \image html Layout.png "Layout" width=.1\linewidth
|
|
# An elementary capacitor unit can be a part of C1 or C2 according to the matching scheme. However, to respect common-centroid layout specifications, for C1 and C2 to be equal, the matrix number of colums and number of rows must be both even. Addionnally, the number of elementary capacitors dedicated to C1 must be equal to those dedicated to C2. These two conditions are tested in one of the class methods. An exception is raised if at least one of the two is not respected.
|
|
|
|
|
|
class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks ):
|
|
|
|
rules = oroshi.getRules()
|
|
|
|
|
|
## A special method used to customize the class instance to an initial state in which :
|
|
# - the class attirbutes describing positions and dimensions of the layout are computed in dedicated class methods,
|
|
# - the attributes related to the capacitor matrix are copied from the \c CapacitorStack instance.
|
|
#
|
|
# Position and dimensions attributes, also refered by layout variables, in Figure 2, are defined below :
|
|
# \param device The Hurricane AMS device onto which the layout is drawn.
|
|
# \param capacitorInstance Instance of \c CapacitorStack class.
|
|
# \param capacitor A nested list containing the matrix elements, which are \c CapacitorUnit objects.
|
|
# \param matchingScheme A nested list, with equal dimensions as \c capacitor attribute, containing assignements of matrix elementary units to C1 and C2, identified by 1 and 2, respectively. Therefore, \c self.matchingScheme content is a succession of 1 and 2 values, defined as \ capacitor identifiers. For example, given a matrix of dimensions 2x2, the matching scheme can be \f$ [ [1,2], [1,2] ] or [ [2,1], [2,1] ] \f$. The first sub-list dictates that the first elementary capacitor, \f$ C_{00} \f$. The second element \f$ C_{01} \f$ is affected to C2 and so on. An immediate and obvious consequence to this, is that an error is raised if \c self.matchingSchem and \c self.capacitor dimensions are not identical or if \c self.matchingScheme content is different from supported capacitor identifiers, '1' and '2'.
|
|
#
|
|
# \param capacitorType Supported types of capacitors are MIM and PIP only. An exception is raised otherwise.
|
|
# \param abutmentBox The matrix's abutment box.
|
|
# \param matrxiDim The matrix dimensions, also equal to \c self.matchingScheme nested list dimensions.
|
|
# \param abutmentBox_spacing The spacing between elementary units in the matrix. It is computed in \c CapacitorStack and is reloaded in \c RoutMatchedCapacitor. \c self.abutmentBox_spacing includes, vertical routeing tracks width and minimum allowed spacing between two adjacent ones.
|
|
# \param hRoutingLayer_width The width of horizontal routeing layers in metal 2, which connect capacitors plates to vertical routeing tracks.
|
|
# \param vRoutingTrack_width The width of vertical routeing tracks in metal 3, which connects identical nets together ( ie : bottom plates of C1, top plates of C2, bottom plates of C2 and top plates of C2 ).
|
|
# \param hRoutingTrack_width The width of horizontal routeing tracks in metal 2, which connect identical vertical routeing tracks together.
|
|
# \param minSpacing_hRoutingTrack Minimum spacing between horizontal routeing tracks. Wide metal 2 specifications are considered since metal 2 dimensions may exceed 10 \f$ m\f$.
|
|
#
|
|
#\remark For more information about wide metal specifications, refer to ENG-183_rev8.pdf technology manual.
|
|
#
|
|
# \param minimumPosition The ordinate of the top plate's routeing layer's bottom extremity after stretching.
|
|
# \param maximumPosition The ordinate of the top plate's routeing layer's top extremity, also equivalent to the top plate's top extremity.
|
|
# \param vRoutingTrackXCenter A nested list of ordered dictionaries, with dimensions equal to \c self.matrixDim, containing abcissas of vertical routeing tracks. All sub-lists' lengths are identical and are equal to 2. The first and second elements describe position of top plate track and bottom plate track, respectively. For example, given a matrix of dimensions 2x2, \c self.vRoutingTrackXCenter can be [[0, 2], [4,6], [8,10]] \f$ \mu m\f$. Elements of this nested list have particular indexing as described in Figure 2.
|
|
#
|
|
# \param hRoutingtrackYCenter A nested dicitonary containing two keys, \c topTracks and \c bottomTracks. Each key contains as value a dictionary describing centers' ordinates of four parallel horizontal tracks. The reason why four tracks are needed on top and bottom positions of the matrix is that four nets are used, two for every capacitor \c Ci, were \c i is in [1,2].
|
|
# \param hRoutingLayerYCenter A nested dicitonary containing two keys, \c top and \c bottom. Each key contains as value a dictionary describing centers' ordinates of horizontal routeing layers.
|
|
# \param vRoutingTrackDict A dictionary of routeing tracks top and bottom extremities ordinates.
|
|
# \param topPlateStretching Since not only the same metal 2 layer is used to draw top/bottom plates connections to vertical tracks but also the two plates are superimposed, the top plate's routeing tracks is stretched. \c self.topPlateStretching is therefore the length added to top plate's routeing layer in order to avoid short circuits between top and bottom plates routeing to vertical tracks since the same metal is used for both.
|
|
|
|
def __init__( self, vRTInstance ) :
|
|
|
|
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.dummyRingVRLayersDict = {}
|
|
|
|
self.hRoutingLayer_width = 0
|
|
self.hRoutingTrack_width = vRTInstance.hRoutingTrack_width #gethRoutingTrack_width()
|
|
self.minSpacing_hRoutingTrack = 0
|
|
self.minimumPosition = 0
|
|
self.maximumPosition = 0
|
|
self.hRoutingtrackYCenter = { "topTracks" : {} , "bottomTracks" : {} }
|
|
self.hRoutingLayerYCenter = { "topPlate" : [] , "bottomPlate" : [] }
|
|
|
|
self.vRTInstance = vRTInstance
|
|
self.topPlateStretching = 0
|
|
|
|
return
|
|
|
|
|
|
|
|
## Draws the complete layout given the capacitor matrix. \c route method is succession of calls to user-defined methods inside a newly created \c Updatesession. The following tasks are excecuted :
|
|
# -# A nex \c UpdateSession is created,
|
|
# -# all required physical layers are loaded,
|
|
# -# technology rules are defined according to capacitor type,
|
|
# -# layout dimension parameters are computed,
|
|
# -# routeing tracks and layers are drawn,
|
|
# -# top plates are stretched,
|
|
# -# all required cuts are drawn,
|
|
# -# The \c UpdateSession is closed.
|
|
#
|
|
# Meanwhile, an exception is raised when the entered \c capacitor is not a capacitor matrix or if the capacitor type is unsupported.
|
|
|
|
def route( self, bbMode = False ):
|
|
|
|
UpdateSession.open ()
|
|
|
|
self.setRules ()
|
|
|
|
if not( self.capacitorInstance.__isUnitCap__() ):
|
|
|
|
if CapacitorStack.__isMatchingSchemeOK__(self):
|
|
|
|
layersDict = self.setLayers ()
|
|
bondingBox = self.computeDimensions( bbMode )
|
|
|
|
if not bbMode :
|
|
|
|
self.drawHRLayers ( layersDict["xPlateHRLayer" ] )
|
|
self.drawHRoutingTracks ( layersDict["hRoutingTracks" ] )
|
|
self.__stretchTopPlates__( self.capacitor , layersDict["xPlateRLayer" ] )
|
|
self.drawCuts ( layersDict["cut_hRoutingLayer_vRoutingTracks"] , layersDict["cut_hRoutingTracks_vRoutingTracks"], layersDict["cut_hRoutingLayer_topPlate"] )
|
|
if self.dummyRing == True:
|
|
self.routeDummyRing (layersDict ["xPlateVRLayer_dummyRing" ] , layersDict["cut_hRoutingTracks_vRoutingTracks"] )
|
|
|
|
else : raise Error( 1, 'drawHRLayers() : Invalid matching scheme : "%s".' % self.matchingScheme )
|
|
|
|
else : raise Error( 1,'An input matrix is required.' % self.matrixDim )
|
|
|
|
UpdateSession.close ()
|
|
|
|
return bondingBox
|
|
|
|
|
|
|
|
def routeDummyRing( self, routeingLayer, cutLayer ):
|
|
|
|
net = self.nets[-1][1]
|
|
bottomPlateRLayer_width = self.dummyRingCapacitor[0][0].getBotPlateRLayerWidth()
|
|
topPlateRLayer_width = self.dummyRingCapacitor[0][0].getTopPlateRLayerWidth()
|
|
self.computeDummyRingDimensions ()
|
|
self.routeLeftAndRightSides (net, routeingLayer, bottomPlateRLayer_width, topPlateRLayer_width )
|
|
self.routeTopOrBottomSide (net, "topSide" , routeingLayer , bottomPlateRLayer_width, topPlateRLayer_width)
|
|
self.routeTopOrBottomSide (net, "bottomSide" , routeingLayer , bottomPlateRLayer_width, topPlateRLayer_width)
|
|
self.drawDummyRing_hRTracks_Cuts (net, "topSide" , cutLayer )
|
|
self.drawDummyRing_hRTracks_Cuts (net, "bottomSide" , cutLayer )
|
|
|
|
return
|
|
|
|
|
|
|
|
def routeLeftAndRightSides( self, dummyNet, routeingLayer, bottomPlateRLayer_width, topPlateRLayer_width ) :
|
|
|
|
for i in range(0,2):
|
|
bottomPlateLeftRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateLeftRLayerXCenter()
|
|
bottomPlateRightRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateRightRLayerXCenter()
|
|
Vertical.create ( dummyNet, routeingLayer , bottomPlateLeftRLayerXCenter , bottomPlateRLayer_width , self.dummyRingVRLayersDict["YMin"] , self.dummyRingVRLayersDict["YMax"] )
|
|
Vertical.create ( dummyNet, routeingLayer , bottomPlateRightRLayerXCenter , bottomPlateRLayer_width , self.dummyRingVRLayersDict["YMin"] , self.dummyRingVRLayersDict["YMax"] )
|
|
|
|
for i in range(0,2):
|
|
topPlateRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].topPlateRLayerDict["XCenter"]
|
|
Vertical.create ( dummyNet, routeingLayer , topPlateRLayerXCenter , topPlateRLayer_width , self.dummyRingVRLayersDict["YMin"] , self.dummyRingVRLayersDict["YMax"] )
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
def routeTopOrBottomSide( self, dummyNet, side, routeingLayer, bottomPlateRLayer_width, topPlateRLayer_width):
|
|
|
|
if side == "topSide" :
|
|
dummyRingElement = self.dummyRingCapacitor[-1]
|
|
dyTarget = self.vRoutingTrackDict ["YMax"]
|
|
elif side == "bottomSide" :
|
|
dummyRingElement = self.dummyRingCapacitor[0]
|
|
dyTarget = self.vRoutingTrackDict ["YMin"]
|
|
else : raise Error(1,'routeTopOrBottomSide() : side parameter must be either "topSide" or "bottomSide" : %s' %side)
|
|
|
|
for j in range(1,len(self.dummyRingCapacitor[0])-1):
|
|
bottomPlateLeftRLayerXCenter = dummyRingElement[j].getBotPlateLeftRLayerXCenter()
|
|
bottomPlateRightRLayerXCenter = dummyRingElement[j].getBotPlateRightRLayerXCenter()
|
|
Vertical.create ( dummyNet, routeingLayer , bottomPlateLeftRLayerXCenter , bottomPlateRLayer_width , dummyRingElement[j].getBotPlateRLayerYMin() , dyTarget )
|
|
Vertical.create ( dummyNet, routeingLayer , bottomPlateRightRLayerXCenter , bottomPlateRLayer_width , dummyRingElement[j].getBotPlateRLayerYMin() , dyTarget )
|
|
|
|
topPlateRLayerXCenter = dummyRingElement[j].topPlateRLayerDict["XCenter"]
|
|
Vertical.create ( dummyNet, routeingLayer , topPlateRLayerXCenter , topPlateRLayer_width , dummyRingElement[j].getTopPlateRLayerYMin() , dyTarget )
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
## Defines technology rules used to draw the layout. Some of the rules, namely those describing routeing layers and tracks are applicable for both MIM and PIP capacitors. However, cuts rules are different. \remark All \c CapacitorStack class rules are also reloaded in this class. An exception is raised if the entered capacitor type is unsupported.
|
|
# \return a dictionary with rules labels as keys and rules content as values.
|
|
|
|
def setRules ( self ):
|
|
|
|
VerticalRoutingTracks.setRules ( self )
|
|
|
|
CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingLayer" , RoutMatchedCapacitor.rules.minSpacing_metbot )
|
|
CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingTrackCut" , RoutMatchedCapacitor.rules.minSpacing_cut2 )
|
|
CapacitorUnit.__setattr__ ( self, "minSpacing_vRoutingTrackCut" , RoutMatchedCapacitor.rules.minSpacing_cut2 )
|
|
CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingLayer_vRoutingTrack_cut" , RoutMatchedCapacitor.rules.minSpacing_cut2 )
|
|
|
|
if self.capacitorType == 'MIMCap':
|
|
|
|
CapacitorUnit.__setattr__( self, "minWidth_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minWidth_cut2 )
|
|
CapacitorUnit.__setattr__( self, "minSpacing_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minSpacing_cut2 )
|
|
CapacitorUnit.__setattr__( self, "minEnclosure_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minEnclosure_metal2_cut2 )
|
|
|
|
elif self.capacitorType == 'PIPCap' :
|
|
|
|
CapacitorUnit.__setattr__( self, "minWidth_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minWidth_cut1 )
|
|
CapacitorUnit.__setattr__( self, "minSpacing_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minSpacing_cut1 )
|
|
CapacitorUnit.__setattr__( self, "minEnclosure_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minEnclosure_metal2_cut1 )
|
|
|
|
else: raise Error( 1, 'setRules() : Unsupported capacitor type : %s.' %self.capacitorType )
|
|
|
|
return
|
|
|
|
|
|
|
|
## Defines all physical layers used to draw the layout. Layers are loaded using \c DataBase API. The same routeing layers are used for both capacitor types except cuts layers that connect top plates to vertical routeing tracks. Basicaly, metal 2, meta 3, cut 1 and cut 2 are the ones defined.
|
|
# \return a dictionary composed of layers labels as keys and layers as values.
|
|
|
|
def setLayers( self ):
|
|
|
|
layersDict = {}
|
|
|
|
layersDict["hRoutingTracks" ] = DataBase.getDB().getTechnology().getLayer("metal2" )
|
|
layersDict["xPlateHRLayer" ] = DataBase.getDB().getTechnology().getLayer("metal2" )
|
|
layersDict["xPlateRLayer" ] = CapacitorUnit.getLayers( self )["bottomPlateRLayer"]
|
|
layersDict["cut_hRoutingTracks_vRoutingTracks"] = DataBase.getDB().getTechnology().getLayer("cut2" )
|
|
layersDict["cut_hRoutingLayer_vRoutingTracks" ] = DataBase.getDB().getTechnology().getLayer("cut2" )
|
|
layersDict["cut_hRoutingLayer_topPlate" ] = DataBase.getDB().getTechnology().getLayer("cut2" ) if self.capacitorType == 'MIMCap' else DataBase.getDB().getTechnology().getLayer("cut1")
|
|
|
|
if self.dummyRing == True:
|
|
layersDict["xPlateVRLayer_dummyRing" ] = DataBase.getDB().getTechnology().getLayer("metal3" ) if self.capacitorType == 'MIMCap' else DataBase.getDB().getTechnology().getLayer("metal1")
|
|
|
|
return layersDict
|
|
|
|
|
|
## Computes, through simple instructions and functions calls, layout variables detailed in Figure 2.
|
|
|
|
def computeDimensions ( self, bbMode ) :
|
|
print 'routMatchedCapacitor.computeDimensions()'
|
|
|
|
bondingBoxDimensions = {}
|
|
self.hRoutingLayer_width = max( self.minWidth_hRoutingLayer, self.minWidth_hRoutingLayer_vRoutingTrack_cut + 2*self.minEnclosure_hRoutingLayer_vRoutingTrack_cut, self.minWidth_hRoutingLayer_topPlate_cut + 2*self.minEnclosure_hRoutingLayer_topPlate_cut )
|
|
|
|
self.abutmentBox_spacing = self.capacitorInstance.abutmentBox_spacing
|
|
self.vRoutingTrack_spacing = self.capacitorInstance.getVRoutingTrack_spacing()
|
|
|
|
abutmentBoxXMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["XMin"] #getAbutmentBox_spacing()
|
|
abutmentBoxYMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["YMin"] #getAbutmentBox_spacing()
|
|
abutmentBoxYMax = abutmentBoxYMin + self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["height"] #getAbutmentBox_spacing()
|
|
|
|
self.minimumPosition = self.vRTInstance.minimumPosition #abutmentBoxYMin - self.__setStretching__()
|
|
self.maximumPosition = self.vRTInstance.maximumPosition #abutmentBoxYMax + self.__setStretching__()
|
|
self.vRoutingTrackDict = self.vRTInstance.vRoutingTrackDict #self.minimumPosition - 4*self.hRoutingTrack_width - 4*self.minSpacing_hRoutingTrack
|
|
|
|
translation1 = self.vRoutingTrack_width/2 + self.vRoutingTrack_spacing
|
|
translation2 = translation1 + self.vRoutingTrack_width/2
|
|
|
|
self.vRoutingTrackXCenter = self.vRTInstance.vRoutingTrackXCenter #getvRoutingTrackXCenter()
|
|
|
|
if bbMode == True :
|
|
bondingBoxDimensions = self.computeBondingBoxDimInbbMode()
|
|
|
|
elif bbMode == False :
|
|
self.computeHRoutingTrackYCenter()
|
|
self.computeHRLayerYCenter()
|
|
|
|
else :raise Error(1, 'computeDimensions(): The bonding box mode parameter, "bbMode" must be either True or False : %s.' %bbMode )
|
|
|
|
print 'BOUNDING BOX:', bondingBoxDimensions
|
|
return bondingBoxDimensions
|
|
|
|
|
|
|
|
def computeBondingBoxDimInbbMode( self ):
|
|
|
|
bondingBoxDimensions = {}
|
|
|
|
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
|
|
|
|
if self.capacitorsNumber % 2 == 0 :
|
|
factor = self.capacitorsNumber
|
|
else :
|
|
factor = self.capacitorsNumber + 1 if self.matrixDim["columns"] % 2 == 0 else self.capacitorsNumber - 1
|
|
|
|
bondingBoxXMax = abutmentBoxXMax + factor*(self.vRoutingTrack_width + self.vRoutingTrack_spacing)
|
|
bondingBoxDimensions["YMin" ] = self.vRoutingTrackDict["YMin"]
|
|
bondingBoxYMax = self.vRoutingTrackDict["YMax"]
|
|
bondingBoxDimensions["width" ] = bondingBoxXMax - bondingBoxDimensions["XMin"]
|
|
bondingBoxDimensions["height" ] = bondingBoxYMax - bondingBoxDimensions["YMin"]
|
|
bondingBoxDimensions["surface"] = bondingBoxDimensions["width"]*bondingBoxDimensions["height"]
|
|
|
|
bondingBox = Box( bondingBoxDimensions["XMin"], bondingBoxDimensions["YMin"], bondingBoxXMax, bondingBoxYMax )
|
|
self.device.setAbutmentBox( bondingBox )
|
|
|
|
return bondingBoxDimensions
|
|
|
|
|
|
## Computes centers' ordinates of the eight horizontal routeing tracks. The tracks include four on top and four on bottom of the matrix. To do the computations, fist, center of the first bottom or top track, given in Figure 2, is computed. Then, all adjacent three centers are deduced by simples translation of the first one. Translation quantity is equal to the sum of distance between adjacent routeing tracks, self.hRoutingTracks_spacing, and half width of the routeing track itself, \c self.hRoutingTrack_width.
|
|
|
|
def computeHRoutingTrackYCenter( self ):
|
|
|
|
self.hRoutingtrackYCenter = { "topTracks" : {} , "bottomTracks" : {} }
|
|
self.hRoutingtrackYCenter["topTracks" ]["t0"] = self.maximumPosition + self.hRoutingTrack_width/2 + self.minSpacing_hRoutingTrack
|
|
self.hRoutingtrackYCenter["bottomTracks" ]["t0"] = self.minimumPosition - self.hRoutingTrack_width/2 - self.minSpacing_hRoutingTrack
|
|
|
|
|
|
keys = self.__setPlatesIds__()
|
|
print("key",keys)
|
|
print(" self.capacitorsNumber", self.capacitorsNumber)
|
|
# limit = 2*self.capacitorsNumber if self.dummyRing == False else 2*self.capacitorsNumber + 1
|
|
for k in range(1, len(keys)):
|
|
print('keysk',keys[k])
|
|
self.hRoutingtrackYCenter["topTracks" ][keys[k]] = self.hRoutingtrackYCenter["topTracks" ][keys[k-1]] + (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
|
|
self.hRoutingtrackYCenter["bottomTracks" ][keys[k]] = self.hRoutingtrackYCenter["bottomTracks"][keys[k-1]] - (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
|
|
print("keyskk",keys[k-1])
|
|
print("self.hRoutingtrackYCenter",self.hRoutingtrackYCenter)
|
|
# if self.dummyRing == True :
|
|
# self.hRoutingtrackYCenter["topTracks" ]["gnd"] = self.hRoutingtrackYCenter["topTracks" ][keys[k]] + (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
|
|
# self.hRoutingtrackYCenter["bottomTracks" ]["gnd"] = self.hRoutingtrackYCenter["bottomTracks"][keys[k]] - (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
|
|
|
|
print('self.hRoutingtrackYCenter',self.hRoutingtrackYCenter)
|
|
|
|
return
|
|
|
|
|
|
## Sets the stretching value of top plates. Then iteratively computes the centers of horizontal routeing layer regarding top and bottom plates.
|
|
|
|
def computeHRLayerYCenter ( self ):
|
|
|
|
shortCircuitLists = self.__findPossibleShortCircuits__()
|
|
self.topPlateStretching = self.__setStretching__( )
|
|
print(' shortCircuitLists', shortCircuitLists)
|
|
for i in range( 0,self.matrixDim["rows"] ):
|
|
print("i",i)
|
|
print("rows", self.matrixDim["rows"])
|
|
print("rowsCap", len(self.capacitor))
|
|
|
|
if shortCircuitLists[i][0] == 0 :
|
|
self.hRoutingLayerYCenter["bottomPlate"].append( [self.capacitor[i][0].getBottomPlateRightCutYMax ()] )
|
|
else :
|
|
bottomPlateYCenter0 = [(self.capacitor[i][0].getBottomPlateRightCutYMax () + self.capacitor[i][0].getBottomPlateRightCutYMin() ) /2 ]
|
|
self.hRoutingLayerYCenter["bottomPlate"].append(bottomPlateYCenter0)
|
|
|
|
topPlateYCenter = self.__setStretchingDySourceDyTarget__( self.capacitor[i][0], self.topPlateStretching )[1] + self.hRoutingLayer_width/2
|
|
self.hRoutingLayerYCenter["topPlate" ].append( [topPlateYCenter ] )
|
|
|
|
for j in range( 1,self.matrixDim["columns"] ):
|
|
topPlateYCenter = self.__setStretchingDySourceDyTarget__( self.capacitor[i][j], self.topPlateStretching )[1] + self.hRoutingLayer_width/2
|
|
if shortCircuitLists[i][j] == 0 :
|
|
self.hRoutingLayerYCenter["bottomPlate"][i].append( self.capacitor[i][j].getBottomPlateRightCutYMax () )
|
|
self.hRoutingLayerYCenter["topPlate" ][i].append( topPlateYCenter )
|
|
else :
|
|
bottomPlateYCenter = (self.capacitor[i][j].getBottomPlateRightCutYMax() + self.capacitor[i][j].getBottomPlateRightCutYMin()) /2
|
|
topPlateYCenter2 = topPlateYCenter + self.minSpacing_hRoutingLayer + self.hRoutingLayer_width
|
|
self.hRoutingLayerYCenter["bottomPlate"][i].append(bottomPlateYCenter)
|
|
self.hRoutingLayerYCenter["topPlate" ][i].append(topPlateYCenter2)
|
|
|
|
print('self.hRoutingLayerYCenter',self.hRoutingLayerYCenter)
|
|
return
|
|
|
|
def computeLayoutDimensionsInbbMode( self ):
|
|
|
|
bondingBoxDict = {}
|
|
bondingBoxDict["YMin" ] = self.hRoutingtrackYCenter["bottomTracks"]["botB"] - self.hRoutingTrack_width/2
|
|
bondingBoxDict["XMin" ] = self.vRoutingTrackXCenter[0 ][0] - self.vRoutingTrack_width/2
|
|
bondingBoxDict["height" ] = self.hRoutingtrackYCenter["topTracks" ]["botB"] + self.hRoutingTrack_width/2 - bondingBoxDict["YMin"]
|
|
bondingBoxDict["width" ] = self.vRoutingTrackXCenter[-1][1] + self.vRoutingTrack_width/2 - bondingBoxDict["XMin"]
|
|
|
|
self.bondingBox = Box( bondingBoxDict["XMin"], bondingBoxDict["YMin"], bondingBoxDict["XMin"] + bondingBoxDict["width"], bondingBoxDict["YMin"] + bondingBoxDict["height"] )
|
|
|
|
return bondingBoxDict
|
|
|
|
|
|
def computeDummyRingDimensions( self ):
|
|
|
|
for key in self.vRoutingTrackDict.keys():
|
|
self.dummyRingVRLayersDict[key] = self.vRoutingTrackDict[key]
|
|
return
|
|
|
|
|
|
|
|
## Iteratively draws horizontal routeing tracks on top and bottom positions of the matrix using physical layer \c routeingTracksLayer.
|
|
|
|
def drawHRoutingTracks( self , routeingTracksLayer ):
|
|
|
|
lastVRTId = self.vRoutingTrackXCenter[-1].keys()[-1]
|
|
firstVRTId = "t0"
|
|
# doDummyRing = 1 if self.dummyRing == True else 0
|
|
dxSource = self.vRoutingTrackXCenter[0][firstVRTId] - self.vRoutingTrack_width/2 if self.dummyRing == False else self.abutmentBox.getXMin()
|
|
dxTarget = self.vRoutingTrackXCenter[-1][lastVRTId] + self.vRoutingTrack_width/2 if self.dummyRing == False else self.abutmentBox.getXMax()
|
|
|
|
for i in self.hRoutingtrackYCenter.keys():
|
|
for j in self.hRoutingtrackYCenter[i].keys():
|
|
if j[0] == 't' :
|
|
net = self.nets[ int(j[1]) ][0]
|
|
elif j[0] == 'b' :
|
|
net = self.nets[ int(j[1]) ][1]
|
|
else :
|
|
print("hi")
|
|
net = self.nets[-1][1]
|
|
# net = self.nets[ int(j[1]) ][0] if j[0] == 't' else self.nets[ int(j[1]) ][1]
|
|
print('net',net)
|
|
Horizontal.create ( net , routeingTracksLayer, self.hRoutingtrackYCenter[i][j] , self.hRoutingTrack_width , dxSource , dxTarget )
|
|
return
|
|
|
|
|
|
## Iteratively draws the horizontal routeing layers starting with bottom left elementary capacitor \f$ C_{00} \f$.
|
|
|
|
def drawHRLayers( self, xPlateRLayer ) :
|
|
|
|
for i in range( 0,self.matrixDim["rows"] ):
|
|
for j in range( 0,self.matrixDim["columns"] ):
|
|
|
|
[ t , b ] = [ self.nets[self.matchingScheme[i][j]][0], self.nets[self.matchingScheme[i][j]][1] ]
|
|
dxDict = self.__computeConnections__( i,j, self.matchingScheme[i][j] )
|
|
|
|
Horizontal.create ( t, xPlateRLayer , self.hRoutingLayerYCenter["topPlate" ][i][j] , self.hRoutingLayer_width , dxDict["topPlate" ][ "source" ] , dxDict["topPlate" ][ "target" ] )
|
|
Horizontal.create ( b, xPlateRLayer , self.hRoutingLayerYCenter["bottomPlate"][i][j] , self.hRoutingLayer_width , dxDict["bottomPlate" ][ "source" ] , dxDict["bottomPlate" ][ "target" ] )
|
|
|
|
return
|
|
|
|
|
|
## Draws all required cuts using physical layers :
|
|
# - \c layer_hRTrack_hRLayer to connect bottom plates to vertical routeing tracks,
|
|
# - \c layer_tracksCut to connect vertical routeing tracks to horizontal ones,
|
|
# - \c layer_topPlateCut to connect top plates to vertical routeing tracks.
|
|
# ALso in \c drawCuts, nUmber of maximum cuts number on every layer is computed and cuts enclosure is adjusted according to layer's width.
|
|
|
|
def drawCuts( self, layer_hRTrack_hRLayer, layer_tracksCut, layer_topPlateCut ):
|
|
|
|
cutNumber = CapacitorUnit.cutMaxNumber( self, self.vRoutingTrack_width, self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut )
|
|
enclosure_hRoutingTrack_cut = (self.vRoutingTrack_width - cutNumber*self.minWidth_hRoutingTrackCut - (cutNumber - 1)*self.minSpacing_hRoutingTrackCut)/2
|
|
|
|
self.drawCuts_vRoutingTrack_HRLayer ( layer_hRTrack_hRLayer, cutNumber, enclosure_hRoutingTrack_cut )
|
|
self.drawCuts_vRoutingTrack_hRoutingTrack ( layer_tracksCut , cutNumber, enclosure_hRoutingTrack_cut )
|
|
self.drawCuts_stretchedTopPlate ( layer_topPlateCut )
|
|
|
|
return
|
|
|
|
|
|
|
|
def drawCuts_vRoutingTrack_HRLayer( self, cutLayer, cutNumber, enclosure_cut ):
|
|
|
|
[ vRoutingTrackXCenter, cutXMin ] = [{}, {}]
|
|
|
|
for i in range( 0, self.matrixDim["rows"] ):
|
|
for j in range( 0, self.matrixDim["columns"] ):
|
|
|
|
if ( j % 2 == 0 ):
|
|
leftVRTIds = self.capacitorIds[0:self.capacitorsNumber/2] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[0: int(self.capacitorsNumber/2+1)]
|
|
rightVRTIds = self.capacitorIds[self.capacitorsNumber/2 : self.capacitorsNumber] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[int(self.capacitorsNumber/2+1) : self.capacitorsNumber]
|
|
|
|
else:
|
|
leftVRTIds = self.capacitorIds[self.capacitorsNumber/2 : self.capacitorsNumber] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[int(self.capacitorsNumber/2+1) : self.capacitorsNumber]
|
|
rightVRTIds = self.capacitorIds[0:self.capacitorsNumber/2] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[0: int(self.capacitorsNumber/2+1)]
|
|
|
|
index1 = j if self.matchingScheme[i][j] in leftVRTIds else j+1
|
|
|
|
[topPlateLabel, bottomPlateLabel ] = [self.__setPlatesLabels__(i,j)["t"] , self.__setPlatesLabels__(i,j)["b"]]
|
|
vRoutingTrackXCenter["topPlate" ] = self.vRoutingTrackXCenter[index1][topPlateLabel + str( self.matchingScheme[i][j] )]
|
|
vRoutingTrackXCenter["bottomPlate"] = self.vRoutingTrackXCenter[index1][bottomPlateLabel + str( self.matchingScheme[i][j] )]
|
|
|
|
cutXMin["topPlate" ] = vRoutingTrackXCenter["topPlate" ] - self.vRoutingTrack_width/2 + enclosure_cut + self.minWidth_hRoutingTrackCut/2
|
|
cutXMin["bottomPlate"] = vRoutingTrackXCenter["bottomPlate"] - self.vRoutingTrack_width/2 + enclosure_cut + self.minWidth_hRoutingTrackCut/2
|
|
[ t , b ] = [ self.nets[self.matchingScheme[i][j]][0] , self.nets[self.matchingScheme[i][j]][1] ]
|
|
|
|
self.drawOneCut_vRoutingTrack_HRLayer( t, cutLayer, cutXMin["topPlate" ], self.hRoutingLayerYCenter["topPlate" ][i][j], cutNumber )
|
|
self.drawOneCut_vRoutingTrack_HRLayer( b, cutLayer, cutXMin["bottomPlate"], self.hRoutingLayerYCenter["bottomPlate"][i][j], cutNumber )
|
|
|
|
return
|
|
|
|
|
|
|
|
## Draws one cut, in layer \c cutLayer, in order to connect a vertical routeing track, at position \c cutXMin in metal 2, and a horizontal routeing track, at position \c cutYMin in metal 3.
|
|
def drawOneCut_vRoutingTrack_HRLayer( self, net, cutLayer, cutXMin, cutYMin, cutNumber ):
|
|
|
|
CapacitorUnit.cutLine(self,net,cutLayer,cutXMin,cutYMin,self.minWidth_hRoutingLayer_vRoutingTrack_cut,self.minWidth_hRoutingLayer_vRoutingTrack_cut,self.minSpacing_hRoutingLayer_vRoutingTrack_cut,cutNumber,'horizontal')
|
|
return
|
|
|
|
|
|
|
|
## Draws cuts to connect vertical routeing tracks in metal 2 and horizontal routeing tracks in metal 3.
|
|
def drawCuts_vRoutingTrack_hRoutingTrack( self,cutLayer, cutNumber, enclosure_cut ):
|
|
|
|
keysList = self.hRoutingtrackYCenter.keys()
|
|
|
|
for i in range(0, len(self.vRoutingTrackXCenter) ):
|
|
for k in self.vRoutingTrackXCenter[i]:
|
|
if self.vRoutingTrackXCenter[i][k] != None :
|
|
for l in range(0, 2) :
|
|
net = self.nets[ int(k[1]) ][0] if k[0] == 't' else self.nets[ int(k[1]) ][1]
|
|
cutXMin = self.vRoutingTrackXCenter[i][k] - self.vRoutingTrack_width/2 + enclosure_cut + self.minWidth_hRoutingTrackCut/2
|
|
CapacitorUnit.cutLine(self,net,cutLayer,cutXMin,self.hRoutingtrackYCenter[keysList[l]][k],self.minWidth_hRoutingTrackCut,self.minWidth_hRoutingTrackCut,self.minSpacing_hRoutingTrackCut,cutNumber,'horizontal')
|
|
|
|
return
|
|
|
|
|
|
|
|
# \param cutLayer
|
|
def drawCuts_stretchedTopPlate( self, cutLayer ):
|
|
|
|
layer_width = self.capacitor[0][0].getTopPlateRLayerWidth()
|
|
cutNumber = CapacitorUnit.cutMaxNumber( self, layer_width , self.minWidth_hRoutingLayer_topPlate_cut, self.minSpacing_hRoutingLayer_topPlate_cut , self.minEnclosure_hRoutingLayer_topPlate_cut )
|
|
enclosure_hRoutingTrack_cut = (layer_width - cutNumber*self.minWidth_hRoutingLayer_topPlate_cut - (cutNumber - 1)*self.minSpacing_hRoutingLayer_topPlate_cut)/2
|
|
|
|
for i in range(0, self.matrixDim["rows"] ):
|
|
for j in range(0, self.matrixDim["columns"] ):
|
|
|
|
tNet = self.nets[self.matchingScheme[i][j]][0]
|
|
cutXMin = self.capacitor[i][j].getTopPlateRLayerXMin() + enclosure_hRoutingTrack_cut + self.minWidth_hRoutingLayer_topPlate_cut/2
|
|
CapacitorUnit.cutLine( self, tNet, cutLayer, cutXMin , self.hRoutingLayerYCenter["topPlate"][i][j] , self.minWidth_hRoutingLayer_topPlate_cut, self.minWidth_hRoutingLayer_topPlate_cut, self.minSpacing_hRoutingLayer_topPlate_cut, cutNumber, 'horizontal' )
|
|
|
|
return
|
|
|
|
|
|
def drawDummyRing_hRTracks_Cuts( self, dummyNet, side, cutLayer ):
|
|
|
|
if side == "topSide" :
|
|
dummyRingElement = self.dummyRingCapacitor[-1]
|
|
key = "topTracks"
|
|
elif side == "bottomSide" :
|
|
dummyRingElement = self.dummyRingCapacitor[0]
|
|
key = "bottomTracks"
|
|
else : raise Error(1,'routeTopOrBottomSide() : side parameter must be either "topSide" or "bottomSide" : %s' %side)
|
|
|
|
topPlateLayer_width = dummyRingElement[0].getTopPlateRLayerWidth()
|
|
bottomPlateLayer_width = dummyRingElement[0].getBotPlateRLayerWidth()
|
|
|
|
topPlateCutNumber = CapacitorUnit.cutMaxNumber( self, topPlateLayer_width , self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut )
|
|
bottomPlateCutNumber = CapacitorUnit.cutMaxNumber( self, bottomPlateLayer_width, self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut )
|
|
|
|
topPlateCutEnclosure = (topPlateLayer_width - topPlateCutNumber *self.minWidth_vRoutingTrackCut - (topPlateCutNumber - 1)*self.minSpacing_vRoutingTrackCut)/2
|
|
# bottomPlateCutEnclosure = (bottomPlateLayer_width - bottomPlateCutNumber*self.minWidth_vRoutingTrackCut - (bottomPlateCutNumber - 1)*self.minSpacing_vRoutingTrackCut)/2
|
|
|
|
netsDistribution = self.__setPlatesIds__()
|
|
|
|
print("netsDistribution2",netsDistribution)
|
|
print("self.hRoutingtrackYCenter",self.hRoutingtrackYCenter)
|
|
for j in range(0,len(dummyRingElement)):
|
|
topPlateCutXCenter = dummyRingElement[j].getTopPlateRLayerXMin () + topPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2
|
|
bottomPlateLeftCutXCenter = dummyRingElement[j].getBottomPlateLeftCutXMin() #dummyRingElement[j].getBotPlateLeftRLayerXMin () + bottomPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2
|
|
bottomPlateRightCutXCenter = dummyRingElement[j].getBottomPlateRightCutXMin() #dummyRingElement[j].getBotPlateRightRLayerXMin() + bottomPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2f
|
|
|
|
CapacitorUnit.cutLine( self, dummyNet, cutLayer, topPlateCutXCenter , self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_vRoutingTrackCut,self.minWidth_vRoutingTrackCut,self.minSpacing_vRoutingTrackCut,topPlateCutNumber,'horizontal')
|
|
CapacitorUnit.cutLine( self, dummyNet, cutLayer, bottomPlateLeftCutXCenter , self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_vRoutingTrackCut,self.minWidth_vRoutingTrackCut,self.minSpacing_vRoutingTrackCut,bottomPlateCutNumber,'horizontal')
|
|
CapacitorUnit.cutLine( self, dummyNet, cutLayer, bottomPlateRightCutXCenter, self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_hRoutingTrackCut,self.minWidth_hRoutingTrackCut,self.minSpacing_hRoutingTrackCut,bottomPlateCutNumber,'horizontal')
|
|
|
|
return
|
|
|
|
|
|
|
|
## Iteratively performs top plates stretching for the capacitor matrix. Vertical segments are connected to top plate routeing layer.
|
|
# \param capacitor Capacitor matrix.
|
|
# \param rlayer Layer of the drawn vertical rectangle.
|
|
def __stretchTopPlates__( self, capacitor, rlayer ):
|
|
|
|
for i in range( 0, self.matrixDim["rows"] ):
|
|
for j in range( 0, self.matrixDim["columns"] ):
|
|
|
|
t = self.nets[self.matchingScheme[i][j]][0]
|
|
print('t',t)
|
|
self.__stretchTopPlateCompactCap__( t , capacitor[i][j], rlayer, j )
|
|
|
|
return
|
|
|
|
|
|
|
|
## Draws vertical stretched layers for a given elementary capacitor.
|
|
def __stretchTopPlateCompactCap__( self, net, capacitor, routeingLayer, j = 0 ):
|
|
|
|
topPlateRLayer_width = capacitor.getTopPlateRLayerWidth()
|
|
topPlateRLayerXCenter = capacitor.getTopPlateRLayerXCenter()
|
|
[ dySource , dyTarget ] = self.__setStretchingDySourceDyTarget__( capacitor, self.topPlateStretching )
|
|
|
|
Vertical.create ( net, routeingLayer , topPlateRLayerXCenter , topPlateRLayer_width , dySource , dyTarget )
|
|
|
|
return
|
|
|
|
|
|
|
|
## Sets the abcissas of the extremities of the vertical stretching to be applied to capacitor's top plates for a given elementary capacitor in the matrix.
|
|
# \param capacitor .values() Elementary unit capacitor.
|
|
# \param deltay Stretching value.
|
|
# \return A list that contains \c dySource and \dyTarget as top extremity and bottom extermity, respectively.
|
|
def __setStretchingDySourceDyTarget__( self, capacitor, deltay ):
|
|
|
|
dySource = capacitor.getTopPlateRLayerYMin()
|
|
dyTarget = dySource - deltay
|
|
|
|
return [ dySource , dyTarget ]
|
|
|
|
|
|
## Computes horizontal routeing layers source and target abcissas for top and bottom plates connections to its associated routeing track.
|
|
# \param (i,j) row and column indexes, respectively, in the matrix which describe the elementary capacitor position in the matrix.
|
|
# \param capacitorIdentifier equal to '1' if C1 and '2' if C2.
|
|
# \return A nested dicitionary. The overal dictionary is composed of keys equal to \c topPlate and \d bottomPlate and values equal to sub-dictionaries. The sub-dictionaries, are in their turn composed of two keys standing for the abcissa of the source and the abcissa of the target.
|
|
# \remark Naturally, an exception is raised if an unsupported capacitor identifier is given.
|
|
|
|
def __computeConnections__( self, i,j, capacitorIdentifier ):
|
|
|
|
if capacitorIdentifier in self.capacitorIds :
|
|
|
|
dxDict = { "bottomPlate": {}, "topPlate": {} }
|
|
|
|
if ( j % 2 == 0 ):
|
|
leftVRTIds = self.capacitorIds[0 :self.capacitorsNumber/2 ] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[0 : int(self.capacitorsNumber/2+1)]
|
|
rightVRTIds = self.capacitorIds[self.capacitorsNumber/2 : self.capacitorsNumber ] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[int(self.capacitorsNumber/2+1) : self.capacitorsNumber ]
|
|
|
|
else:
|
|
leftVRTIds = self.capacitorIds[self.capacitorsNumber/2 : self.capacitorsNumber ] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[int(self.capacitorsNumber/2+1) : self.capacitorsNumber ]
|
|
rightVRTIds = self.capacitorIds[0 : self.capacitorsNumber/2 ] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[0 : int(self.capacitorsNumber/2+1)]
|
|
|
|
|
|
[topPlateLabel, bottomPlateLabel ] = [self.__setPlatesLabels__(i,j)["t"] , self.__setPlatesLabels__(i,j)["b"]]
|
|
|
|
dxDict["topPlate" ][ "source" ] = self.capacitor[i][j].getTopPlateRLayerXMax () if self.matchingScheme[i][j] in leftVRTIds else self.capacitor[i][j].getTopPlateRLayerXMin()
|
|
dxDict["topPlate" ][ "target" ] = self.__findHRLDyTrarget__( i,j, topPlateLabel, leftVRTIds, rightVRTIds )
|
|
|
|
dxDict["bottomPlate" ][ "source" ] = self.capacitor[i][j].getBotPlateLeftRLayerXMax () if self.matchingScheme[i][j] in leftVRTIds else self.capacitor[i][j].getBotPlateRightRLayerXMin ()
|
|
# bottomPlateLabel = 'b' if self.dummyElement == False or not( self.__isCapacitorAdummy__(capacitorIdentifier) ) else 't'
|
|
print("bottomPlateLabel",bottomPlateLabel)
|
|
dxDict["bottomPlate" ][ "target" ] = self.__findHRLDyTrarget__( i, j, bottomPlateLabel, leftVRTIds, rightVRTIds )
|
|
|
|
else : raise Error(1, '__computeConnections__(): Unknown capacitor Id : %s.' %capacitorIdentifier )
|
|
|
|
print('dxDict',dxDict)
|
|
return dxDict
|
|
|
|
|
|
def __isCapacitorAdummy__( self, capacitorIdentifier ) :
|
|
|
|
state = False
|
|
if self.dummyElement == True :
|
|
if capacitorIdentifier == self.capacitorIds[-1] : state = True
|
|
else : raise Error(1,'The matrix contains no dummies because dummy element is "False".')
|
|
|
|
return state
|
|
|
|
|
|
|
|
def __setPlatesLabels__( self, i, j ):
|
|
|
|
platesLabels = {}
|
|
capacitorIdentifier = self.matchingScheme[i][j]
|
|
platesLabels["t"] = 't'
|
|
platesLabels["b"] = 'b' if self.dummyElement == False or not( self.__isCapacitorAdummy__(capacitorIdentifier) ) else 't'
|
|
|
|
return platesLabels
|
|
|
|
|
|
def __findHRLDyTrarget__( self, i,j, plateLabel, leftVRTIds, rightVRTIds ):
|
|
|
|
if plateLabel in ['t','b'] :
|
|
plateIndex = self.matchingScheme[i][j]
|
|
|
|
[ doLeft , doRight ] = [1,0] if self.matchingScheme[i][j] in leftVRTIds else [0,1]
|
|
xCenterList = leftVRTIds if [ doLeft , doRight ] == [1,0] else rightVRTIds
|
|
index1 = j if [ doLeft , doRight ] == [1,0] else j+1
|
|
|
|
for key in self.vRoutingTrackXCenter[index1].keys() :
|
|
if key == plateLabel + str(plateIndex) :
|
|
index2 = key
|
|
break
|
|
|
|
else : raise Error(1,'__findHRLDyTrarget__() : Plate label must be "t" for top plate and "b" for bottom plate. The given label is : %s.' %plateLabel)
|
|
|
|
return self.vRoutingTrackXCenter[index1][index2] - doLeft*self.vRoutingTrack_width/2 + doRight*self.vRoutingTrack_width/2
|
|
|
|
|
|
|
|
def __setPlatesIds__( self ):
|
|
|
|
keys = []
|
|
for k in range(0, len(self.nets)):
|
|
keys.append( 't' + str(k) )
|
|
keys.append( 'b' + str(k) )
|
|
|
|
if self.dummyRing == True or self.dummyElement == True : keys = keys[0:len(keys)-1]
|
|
|
|
return keys
|
|
|
|
|
|
def __findPossibleShortCircuits__( self ):
|
|
|
|
shortCircuitLists = []
|
|
self.vRTsDistribution = self.vRTInstance.vRTsDistribution
|
|
for i in range(0, self.matrixDim["rows"]):
|
|
shortCircuitLists.append([0])
|
|
|
|
for j in range(0, self.matrixDim["columns"]):
|
|
shortCircuitLists[i].append(0)
|
|
for i in range(0, self.matrixDim["rows"]):
|
|
for j in range(0, self.matrixDim["columns"]-1):
|
|
print('self.vRTsDistribution',self.vRTsDistribution)
|
|
if self.matchingScheme[i][j] in self.vRTsDistribution[j+1] and self.matchingScheme[i][j+1] in self.vRTsDistribution[j+1] and self.matchingScheme[i][j] > self.matchingScheme[i][j+1] : shortCircuitLists[i][j] = 1
|
|
|
|
return shortCircuitLists
|
|
|
|
|
|
|
|
|
|
def ScriptMain( **kw ):
|
|
|
|
editor = None
|
|
if kw.has_key('editor') and kw['editor']:
|
|
editor = kw['editor']
|
|
|
|
UpdateSession.open()
|
|
Device = AllianceFramework.get().createCell( 'capacitor' )
|
|
Device.setTerminal( True )
|
|
|
|
bottomPlate_net0 = Net.create( Device, 'b0' )
|
|
bottomPlate_net1 = Net.create( Device, 'b1' )
|
|
bottomPlate_net2 = Net.create( Device, 'b2' )
|
|
bottomPlate_net3 = Net.create( Device, 'b3' )
|
|
bottomPlate_net0.setExternal( True )
|
|
bottomPlate_net1.setExternal( True )
|
|
bottomPlate_net2.setExternal( True )
|
|
bottomPlate_net3.setExternal( True )
|
|
b0 = Device.getNet("b0")
|
|
b1 = Device.getNet("b1")
|
|
b2 = Device.getNet("b2")
|
|
b3 = Device.getNet("b3")
|
|
|
|
topPlate_net0 = Net.create( Device, 't0' )
|
|
topPlate_net1 = Net.create( Device, 't1' )
|
|
topPlate_net2 = Net.create( Device, 't2' )
|
|
topPlate_net3 = Net.create( Device, 't3' )
|
|
topPlate_net0.setExternal( True )
|
|
topPlate_net1.setExternal( True )
|
|
topPlate_net2.setExternal( True )
|
|
topPlate_net3.setExternal( True )
|
|
t0 = Device.getNet("t0")
|
|
t1 = Device.getNet("t1")
|
|
t2 = Device.getNet("t2")
|
|
t3 = Device.getNet("t3")
|
|
|
|
if editor:
|
|
UpdateSession.close()
|
|
editor.setCell( Device )
|
|
editor.fit()
|
|
UpdateSession.open()
|
|
|
|
nets = [[t0, b0] , [t1, b1], [t2, b2] ] # [t3, b3] ]
|
|
capacitorInstance = CapacitorStack( Device, [372,1116], 'MIMCap', [0,0], nets, unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ [1,1,1,0] , [0,1,1,1] , [1,1,1,0] , [0,1,1,1] ] , dummyRing = True )#dummyRing = True)
|
|
|
|
# capacitorInstance = CapacitorStack( Device, [279,1023, 186], 'MIMCap', [0,0], nets, unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ [1,1,1,0] , [0,1,2,1] , [1,1,1,0] , [2,1,1,1] ], dummyElement = True, dummyRing = True )#dummyRing = True)
|
|
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 50, matchingMode = True, matchingScheme = [ ['C2','C1','C2','C1','C1'] , ['C1','C2','C1','C2','C2'] , ['C1','C2','C2','C2', 'C1'] , ['C1','C2','C2','C1', 'C1'], ['C2','C2','C2','C2','C2'] ] )
|
|
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 93, matchingMode = True, matchingScheme = [ ['C2','C2','C2','C2'] , ['C1','C2','C2','C2'] , ['C1','C2','C2','C2'] , ['C1','C2','C2','C1'] ] )
|
|
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 93, matchingMode = True, matchingScheme = [ ['C2','C2','C1','C2'] , ['C1','C2','C2','C1'] , ['C1','C1','C2','C3'] , ['C1','C1','C2','C3'] ] )
|
|
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, matrixDim = [5,5] , matchingMode = True, matchingScheme = [ ['C2','C1','C2','C3','C1'] , ['C1','C2','C4','C3','C2'] , ['C4','C2','C2','C3', 'C1'] , ['C1','C2','C2','C1', 'C1'], ['C2','C2','C3','C2','C4'] ] )
|
|
|
|
capacitor = capacitorInstance.create()
|
|
print('capa',capacitor)
|
|
|
|
capWithVRT = VerticalRoutingTracks( capacitorInstance, capacitor, True )
|
|
capWithVRT.create()
|
|
|
|
routedCap = RoutMatchedCapacitor( capWithVRT )
|
|
surface = routedCap.route( )
|
|
print('routeMatchedCap bbMode', surface)
|
|
|
|
AllianceFramework.get().saveCell( Device, Catalog.State.Views )
|
|
|
|
return True
|
|
|