#!/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 .') 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 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 \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