From e9ce33a8579050daf7ec1344304907f13d009a30 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Mon, 30 Mar 2020 12:40:29 +0200 Subject: [PATCH] Resistor integration. * New: In Isobar::PyResistor, manage type RPOLYH and RPOLY2PH. * Change: In Hurricane::Resistor, rename plate nets from "PIN1" and "PIN2" into "t1" and "t2" (try to respect uniform naming scheme). * New: In Karakaze/AnalogDesign.py, support for reading Resistor parameters. * New: In Orosshi, ResistorSnake.py imported from Mariam Tlili's work and associated Resistor.py to make parameter conversion. Currently we only uses vertical layout for resistors. Added METAL2 horizontal terminals for resistors. --- crlcore/python/helpers/io.py | 10 +- hurricane/src/analog/PyResistor.cpp | 6 +- hurricane/src/analog/Resistor.cpp | 22 +- karakaze/python/AnalogDesign.py | 61 +- oroshi/python/CMakeLists.txt | 1 + oroshi/python/Resistor.py | 80 ++ oroshi/python/ResistorSnake.py | 1537 ++++++++++++++++++++++++++- oroshi/python/capacitor.ap | 4 - 8 files changed, 1635 insertions(+), 86 deletions(-) create mode 100644 oroshi/python/Resistor.py delete mode 100644 oroshi/python/capacitor.ap diff --git a/crlcore/python/helpers/io.py b/crlcore/python/helpers/io.py index f21f72ca..0f8bda02 100644 --- a/crlcore/python/helpers/io.py +++ b/crlcore/python/helpers/io.py @@ -248,17 +248,17 @@ class ErrorMessage ( Exception ): def catch ( errorObject ): if isinstance(errorObject,ErrorMessage): - em = errorObject + em = errorObject else: - em = ErrorMessage( 2, errorObject ) - em.trace = traceback.extract_tb( sys.exc_info()[2] ) - #em.scriptPath = __file__ + em = ErrorMessage( 2, errorObject ) + em.trace = traceback.extract_tb( sys.exc_info()[2] ) + #em.scriptPath = __file__ print em print helpers.textStackTrace( em.trace, True, em.scriptPath ) if Viewer.Graphics.get().isEnabled(): - tryCont = ErrorWidget( em ).exec_() + tryCont = ErrorWidget( em ).exec_() if UpdateSession.getStackSize() > 0: UpdateSession.close() return diff --git a/hurricane/src/analog/PyResistor.cpp b/hurricane/src/analog/PyResistor.cpp index 42019587..6c11b943 100644 --- a/hurricane/src/analog/PyResistor.cpp +++ b/hurricane/src/analog/PyResistor.cpp @@ -62,9 +62,11 @@ extern "C" { } switch ( pyType ) { case Resistor::LOWRES: - case Resistor::HIRES: break; + case Resistor::HIRES: + case Resistor::RPOLYH: + case Resistor::RPOLY2PH: break; default: - PyErr_SetString ( ConstructorError, "Resistor.create(): Type argument is neither LOWRES nor HIRES." ); + PyErr_SetString ( ConstructorError, "Resistor.create(): Type argument is neither LOWRES, HIRES, RPOLYH nor RPOLY2PH." ); return NULL; } diff --git a/hurricane/src/analog/Resistor.cpp b/hurricane/src/analog/Resistor.cpp index 9bd2c674..4830fb40 100644 --- a/hurricane/src/analog/Resistor.cpp +++ b/hurricane/src/analog/Resistor.cpp @@ -54,21 +54,21 @@ namespace Analog { void Resistor::createConnections () { - Net* pin1 = Net::create( this, Name("PIN1") ); - pin1->setExternal(true); + Net* t1 = Net::create( this, Name("t1") ); + t1->setExternal(true); - Net* pin2 = Net::create( this, Name("PIN2") ); - pin2->setExternal(true); + Net* t2 = Net::create( this, Name("t2") ); + t2->setExternal(true); _metaResistor = MetaResistor::create( getSubDevicesLibrary(), Name("R1") ); Instance* metaResistorIns = Instance::create( this, Name("R1Instance"), _metaResistor ); setReferenceResistor( _metaResistor ); - Plug* mrPin1Plug = metaResistorIns->getPlug( _metaResistor->getPin1() ); - mrPin1Plug->setNet( pin1 ); - Plug* mrPin2Plug = metaResistorIns->getPlug( _metaResistor->getPin2() ); - mrPin2Plug->setNet( pin2 ); + Plug* mrT1Plug = metaResistorIns->getPlug( _metaResistor->getPin1() ); + mrT1Plug->setNet( t1 ); + Plug* mrT2Plug = metaResistorIns->getPlug( _metaResistor->getPin2() ); + mrT2Plug->setNet( t2 ); } @@ -88,14 +88,14 @@ namespace Analog { unsigned int west = 0; unsigned int east = 2; unsigned int south = 4; - unsigned int north = 6; + unsigned int north = 8; unsigned int rule = 0; if (net->getName() == namePin1) { - rule = (yes << south) | (yes << east) | (yes << west); + rule = (yes << east) | (yes << west); } else { if (net->getName() == namePin2) { - rule = (yes << north) | (yes << east) | (yes << west); + rule = (yes << east) | (yes << west); } else { cerr << Error( "Resistor::getRestriction(): Resistor device do not have Net named \"%s\"." , getString(net->getName()).c_str() diff --git a/karakaze/python/AnalogDesign.py b/karakaze/python/AnalogDesign.py index 7434d3f1..423a02ac 100644 --- a/karakaze/python/AnalogDesign.py +++ b/karakaze/python/AnalogDesign.py @@ -54,25 +54,27 @@ import Katana import Bora -#helpers.setTraceLevel( 110 ) +helpers.setTraceLevel( 100 ) -NMOS = Transistor.NMOS -PMOS = Transistor.PMOS -PIP = CapacitorFamily.PIP -MIM = CapacitorFamily.MIM -MOM = CapacitorFamily.MOM -LOWRES = ResistorFamily.LOWRES -HIRES = ResistorFamily.HIRES -Center = SlicingNode.AlignCenter -Left = SlicingNode.AlignLeft -Right = SlicingNode.AlignRight -Top = SlicingNode.AlignTop -Bottom = SlicingNode.AlignBottom -Unknown = SlicingNode.AlignBottom -VNode = 1 -HNode = 2 -DNode = 3 +NMOS = Transistor.NMOS +PMOS = Transistor.PMOS +PIP = CapacitorFamily.PIP +MIM = CapacitorFamily.MIM +MOM = CapacitorFamily.MOM +LOWRES = ResistorFamily.LOWRES +HIRES = ResistorFamily.HIRES +RPOLYH = ResistorFamily.RPOLYH +RPOLY2PH = ResistorFamily.RPOLY2PH +Center = SlicingNode.AlignCenter +Left = SlicingNode.AlignLeft +Right = SlicingNode.AlignRight +Top = SlicingNode.AlignTop +Bottom = SlicingNode.AlignBottom +Unknown = SlicingNode.AlignBottom +VNode = 1 +HNode = 2 +DNode = 3 def toDbU ( value ): return DbU.fromPhysical( value, DbU.UnitPowerMicro ) @@ -265,7 +267,7 @@ class AnalogDesign ( object ): specSize = 0 if isderived(dspec[0],TransistorFamily): specSize = 12 elif isderived(dspec[0], CapacitorFamily): specSize = 7 - elif isderived(dspec[0], ResistorFamily): specSize = 5 + elif isderived(dspec[0], ResistorFamily): specSize = 8 else: raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], has unsupported device type.' \ % (count) @@ -282,7 +284,7 @@ class AnalogDesign ( object ): raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [2] (layout style) is *not* a string.' % count , '%s' % str(dspec) ]) - if specSize == 12: + if isderived(dspec[0],TransistorFamily): if dspec[3] not in [NMOS, PMOS]: raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [3] (type) must be either NMOS or PMOS.' % count , '%s' % str(dspec) ]) @@ -315,7 +317,7 @@ class AnalogDesign ( object ): raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [11] (bulk connected) is *not* a boolean.' % count , '%s' % str(dspec) ]) - elif specSize == 7: + elif isderived(dspec[0], CapacitorFamily): if dspec[3] not in [PIP, MIM, MOM]: raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [3] (type) must be either PIP, MIM or MOM.' % count , '%s' % str(dspec) ]) @@ -325,11 +327,11 @@ class AnalogDesign ( object ): raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [4] (Cs) should either be *one* float or a *list* of floats.' % count , '%s' % str(dspec) ]) - elif specSize == 5: - if dspec[3] not in [LOWRES, HIRES]: - raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [3] (type) must be either LOWRES or HIRES.' % count + elif isderived(dspec[0],ResistorFamily): + if dspec[3] not in [RPOLYH, RPOLY2PH]: + raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [3] (type) must be either RPOLYH or RPOLY2PH.' % count , '%s' % str(dspec) ]) - if isinstance(dspec[4],float): pass + if isinstance(dspec[5],float): pass else: raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [4] (resistance) must be a float.' % count , '%s' % str(dspec) ]) @@ -435,9 +437,15 @@ class AnalogDesign ( object ): device.getParameter( 'capacities' ).setValue( i, capaValues[i] ) elif isderived(dspec[0],ResistorFamily): + print dspec device = dspec[0].create( self.library, dspec[1], dspec[3] ) - device.getParameter( 'Layout Styles' ).setValue ( dspec[2] ) - device.getParameter( 'Resistance' ).setMatrix( dspec[4] ) + device.getParameter( 'R' ).setValue( dspec[4] ) + device.getParameter( 'W' ).setValue( toDbU(dspec[5]) ) + device.getParameter( 'L' ).setValue( toDbU(dspec[6]) ) + device.getParameter( 'bends' ).setValue( dspec[7] ) + trace( 100, '\tW:{0}\n'.format(dspec[5]) ) + trace( 100, '\tpW:{0}\n'.format(device.getParameter('W')) ) + trace( 100, '\tbends:{0}\n'.format(dspec[7]) ) else: raise ErrorMessage( 1, 'AnalogDesign.doDevice(): Unknown/unsupported device "%s".' % str(dspec[0]) ) @@ -450,6 +458,7 @@ class AnalogDesign ( object ): , Instance.PlacementStatus.UNPLACED ) self.__dict__[ dspec[1] ] = instance + trace( 100, '\tAdd Instance:{0}\n'.format(dspec[1]) ) return diff --git a/oroshi/python/CMakeLists.txt b/oroshi/python/CMakeLists.txt index 25392870..0646c54c 100644 --- a/oroshi/python/CMakeLists.txt +++ b/oroshi/python/CMakeLists.txt @@ -15,6 +15,7 @@ CapacitorRoutedSingle.py MultiCapacitor.py ResistorSnake.py + Resistor.py ) install( FILES ${pythonFiles} DESTINATION ${PYTHON_SITE_PACKAGES}/oroshi ) diff --git a/oroshi/python/Resistor.py b/oroshi/python/Resistor.py new file mode 100644 index 00000000..21a300dd --- /dev/null +++ b/oroshi/python/Resistor.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- + +from Hurricane import DataBase +from Hurricane import UpdateSession +from Hurricane import DbU +from Hurricane import Box +from Hurricane import Net +import helpers +import helpers.io +from helpers import trace + +helpers.setTraceLevel( 100 ) + +import Analog +import ParamsMatrix +import oroshi +from Analog import Device +from ResistorSnake import Resistor + + + +def checkCoherency ( device, bbMode ): + message = 'Resistor.checkCoherency(): device "%s".\n' % device.getName() + + techno = DataBase.getDB().getTechnology() + rules = oroshi.getRules() + + resistance = device.getParameter( 'R' ) + if resistance is None: + message += ' Missing "resistance" parameter on %s' % str(device) + return (False, message) + + return (True, "") + + +def layout ( device, bbMode ): + + trace( 100, ',+', '\tResistor.layout() called for "%s".\n' % device.getName()) + + paramsMatrix = ParamsMatrix.ParamsMatrix() + + try: + resistance = device.getParameter( 'R' ).getValue() + width = device.getParameter( 'W' ).getValue() + length = device.getParameter( 'L' ).getValue() + bends = device.getParameter( 'bends' ).getValue() + + trace( 100, '\tpW:{0}\n'.format(device.getParameter('W')) ) + trace( 100, '\tresistance:{0}, width:{1}, length:{2}\n'.format(resistance,width,length) ) + + typeArg = 'UnknownType' + if device.isRPOLYH(): typeArg = 'RPOLYH' + if device.isRPOLY2PH(): typeArg = 'RPOLY2PH' + + netsArg = [ device.getNet('t1'), device.getNet('t2') ] + + resistor = Resistor( device + , netsArg + , typeArg + , resistance + , resDim={ 'width':width, 'length':length } + , direction='vertical' + , bends=bends + , shape=135 + ) + resistor.create() + + for net in netsArg: + device.setRestrictions( net, Device.SouthBlocked|Device.NorthBlocked ) + + paramsMatrix.setGlobalCapacitorParams( device.getAbutmentBox() ) + trace( 100, '++' ) + #paramsMatrix.trace() + + except Exception, e: + helpers.io.catch( e ) + + trace( 100, '---' ) + + return paramsMatrix.getMatrix() diff --git a/oroshi/python/ResistorSnake.py b/oroshi/python/ResistorSnake.py index 81e09ebc..fe5b794a 100644 --- a/oroshi/python/ResistorSnake.py +++ b/oroshi/python/ResistorSnake.py @@ -1,57 +1,1518 @@ -# -*- coding: utf-8 -*- +#!/usr/bin/python -from Hurricane import DataBase -from Hurricane import UpdateSession -from Hurricane import DbU -from Hurricane import Box +import sys +from Hurricane import * +from CRL import * +import Constant +from math import sqrt, ceil import helpers -import helpers.io -from helpers import trace, u - -helpers.setTraceLevel( 1000 ) - -import Analog -import ParamsMatrix +from helpers.io import ErrorMessage as Error +from helpers import trace, u import oroshi -def checkCoherency ( device, bbMode ): - valid = True - message = 'ResistorSnake.checkCoherency():\n' +def doBreak( level, message ): + UpdateSession.close() + Breakpoint.stop( level, message ) + UpdateSession.open() + +def toDbU ( l ): return DbU.fromPhysical( l, DbU.UnitPowerMicro ) +def toPhy ( l ): return DbU.toPhysical ( l, DbU.UnitPowerMicro ) + +def toFoundryGrid ( l ): + twoGrid = DbU.fromGrid( 2.0 ) + return l + (twoGrid - (l % twoGrid)) + +def isNearNorth ( y, ab ): return ab.getYMax() - y < y - ab.getYMin() + + +class Resistor ( object ): + + rules = oroshi.getRules() + + def __init__( self, device, nets, resistorType, resistance = 0, resDim = { "width" : 10, "length" : 0 }, direction = "horizontal", bends = 0, shape = 90 ): + + self.device = device + self.nets = nets + + trace( 100, '\twidth:{0}, length:{1}, bends:{2}\n'.format(resDim['width'],resDim['length'],bends) ) + + #resDim["width" ] = toDbU(resDim["width" ]) + #resDim["length"] = toDbU(resDim["length"]) + + self.__initArgs__ ( resistorType, direction, bends, shape ) + self.setRules() + self.__initResDim__( resistance , resDim) + + if self.snakeMode: + self.snakeSegmentDict = {} + self.resPlateExtrimity1 = {} + self.resPlateExtrimity2 = {} + self.resPlateExtension1 = {} + self.resPlateExtension2 = {} + self.snakeCornerDict = {} + if self.shape == 135 : + self.rightCorPointsVector = [] + self.leftCorPointsVector = [] + + self.resPlateExtensions = {} + self.resPlateExtrimities = {} + + self.resistorPlateDict = {} + self.abutmentBoxDict = { "XMin" : 0, "YMin" : 0 } + self.abutmentBox = Box () + self.terminal1Box = Box() + self.terminal2Box = Box() + + self.t1cutsEnclosure = {} + self.t2cutsEnclosure = {} + + self.t1CutCenterDict = {} + self.t2CutCenterDict = {} + + if self.resistorType == "RPOLYH" : + self.pImplant_layerDict = {} + self.hresLayerDict = {} + if self.resistorType == "RPOLY2PH" : + self.restrmLayerDict = {} + + self.resdefLayerDict = {} + self.enclosure_resistor_abutmentBox = {} + + return + + + + def __initArgs__( self, resistorType, direction, bends, shape ): + + 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 bends >= 0 : + if bends == 0 : [ self.bends, self.snakeMode ] = [ bends , False ] + elif bends > 0 and shape in [90, 135] : [ self.bends, self.snakeMode, self.shape ] = [ bends , True, shape ] + else : raise Error(1,'__initArgs__() : Resistor shape must be either 90 or 135 degrees : shape = %s.' %shape) + else : raise Error(1,'__initArgs__() : Bends number must not be negative : bends = %s.' %bends) + + return + + + def __initContactsNumber__( self, resDim ): + + layer_minWidth = Resistor.rules.minWidth_cut0 + 2*Resistor.rules.minEnclosure_poly2_cut0 + layerWidth = self.resPlateExtensions_minWidth if resDim["width"] < layer_minWidth else resDim["width"] + + self.contactsNumber = self.cutMaxNumber(layerWidth, Resistor.rules.minWidth_cut0, Resistor.rules.minSpacing_cut0, Resistor.rules.minEnclosure_poly2_cut0) + + return + + - techno = DataBase.getDB().getTechnology() - rules = oroshi.getRules() + def __initResDim__( self, resistance, resDim ): - bends = device.getParameter( 'bends' ) - if bends is None: - message += ' Missing "bends" parameter on %s' % str(device) - print message - return (False, message) + if self.__isDimOk__( resDim, "width" ) : + + self.__initContactsNumber__(resDim) + print("contacts",self.contactsNumber) - if not valid: return (False, message) + if resistance > 0 and resDim["length"] > 0 : + + if resistance - resistance/1000 <= self.__computeResistance__( resDim, self.resistorType ) <= resistance + resistance/1000 and self.__isDimOk__( resDim, "length" ): + self.resDim = resDim + else : + raise Error(1,'__initResDim__() : No compatibiliy between resistance value, %s, and resistor dimensions, "width" : %s, "length" : %s.' %(resistance, toPhy(resDim["width"]), toPhy(resDim["length"]))) + + elif resistance > 0 and resDim["length"] == 0 : + print("resistance0",resistance) + 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 setSidesDimRules( self ): + + if self.resistorType == "RPOLYH" : + self.__setattr__( "minWidth_resistorPlate" , Resistor.rules.minWidth_rpolyh ) + if self.resistorType == "RPOLY2PH" : + self.__setattr__( "minWidth_resistorPlate" , Resistor.rules.minWidthHighPrec_rpolyh ) + self.__setattr__ ( "minLength_resistorPlate" , Resistor.rules.minRpolyhSquares ) + + return + + + def __isDimOk__( self, resdim, side ) : + + self.setSidesDimRules() + + if resdim.keys() == ["width","length"] and side in ["width","length"]: + + if side == "width" : + rule = self.minWidth_resistorPlate + if side == "length" : + print("test0",resdim["width"]) + rule = toDbU( self.minLength_resistorPlate*toPhy(resdim["width"]) ) + + state = True if resdim[side] >= rule else False + if state == False : raise Error(1,'__isDimOk__() : Resistor or bend side dimension, %s = %s, is below the minimal limit, %s.' + % (side, toPhy(resdim[side]), toPhy(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 ): + + resistancePart1 = self.__getSheetResistance__( resistorType, "resistorPlate" )*toPhy(resDim["length"])/toPhy(resDim["width"]) + resistancePart2 = 2*self.__getSheetResistance__( resistorType, "contact" )/self.contactsNumber + print("computedRes",resistancePart1 + resistancePart2) + return resistancePart1 + resistancePart2 + + + + def __computeResDim__( self, resistance, resistorType, resDim ): + + contactsResistance = self.__getSheetResistance__( resistorType, "contact" )/self.contactsNumber + print("contactsResistance",contactsResistance) + wl_ratio = (resistance - 2*contactsResistance)/self.__getSheetResistance__( resistorType, "resistorPlate" ) + width = toPhy(resDim["width"]) + length = wl_ratio*width + + resDim["length"] = toFoundryGrid( toDbU(length) ) + print('length0',length) + if self.__isDimOk__(resDim, "width") and self.__isDimOk__(resDim, "length") : + return resDim + + + def __getSheetResistance__( self, resistorType, material ): + + if material == 'resistorPlate': + if resistorType == "RPOLYH" : resistance = Resistor.rules.RPOLYHSheetRes + elif resistorType == "RPOLY2PH": resistance = Resistor.rules.RPOLY2PHSheetRes + else : raise Error( 1, '__getSheetResistance__() : Unsupported resistor type : %s.' % resistorType ) + + elif material == "contact" : + resistance = Resistor.rules.MET1RPOLYHContRes + + return resistance + + + + def __computeSnakeCornerDim__( self ): + + self.snakeCornerDict["width" ] = self.resDim["width"] + self.snakeCornerDict["length"] = 2*self.resDim["width"] + self.minSpacing_resistorPlate + + return + + + + def __getCornerResistanceCorrectionFactor__( self ): + + if self.shape not in [90, 135] : raise Error(1,'__getCornerResistanceCorrectionFactor__() : Invalid shape : %s.' %shape) + if self.shape == 135 : correctionFactor = Resistor.rules.corrFactor135 + if self.shape == 90 : correctionFactor = Resistor.rules.corrFactor90 + + print(correctionFactor) + return correctionFactor + + + + + def setRules( self ): + trace( 101, '+,', '\tResistor.setRules()\n' ) + + self.minSpacing_resistorPlate = Resistor.rules.minSpacing_rpolyh + self.minWidth_contact = Resistor.rules.minWidth_cut0 + self.minHeight_contact = Resistor.rules.minWidth_cut0 + self.minSpacing_contact = Resistor.rules.minSpacing_cut0 + self.minEnclosure_resistorPlate_contact = Resistor.rules.minEnclosure_poly2_cut0 + self.minEnclosure_routingLayer_contact = Resistor.rules.minEnclosure_metal1_cut0 + self.minEnclosure_metal1_cut0 = Resistor.rules.minEnclosure_metal1_cut0 + self.minEnclosure_metal1_cut1 = Resistor.rules.minEnclosure_metal1_cut1 + self.minWidth_cut1 = Resistor.rules.minWidth_cut1 + self.minSpacing_cut1 = Resistor.rules.minSpacing_cut1 + + if self.resistorType == "RPOLYH": + self.minWidth_pImplantLayer = Resistor.rules.minWidth_pImplant + self.minSpacing_pImplantLayer = Resistor.rules.minSpacing_pImplant + self.minSpacing_resistorPlate_pImplantLayer = Resistor.rules.minSpacing_rpolyh_pImplant + self.minEnclosure_pImplantLayer_contact = Resistor.rules.minEnclosure_pImplant_poly2con + self.minEnclosure_hres_poly2 = Resistor.rules.minEnclosure_hres_poly2 + self.minWidth_hres = Resistor.rules.minWidth_hres + self.minSpacing_hres = Resistor.rules.minSpacing_hres + self.minSpacing_hres_poly1 = Resistor.rules.minSpacing_hres_poly1 + self.minSpacing_hres_poly2 = Resistor.rules.minSpacing_hres_poly2 + self.minSpacing_hres_active = Resistor.rules.minSpacing_hres_active + + self.resPlateExtensions_minWidth = self.minWidth_contact + 2*self.minEnclosure_resistorPlate_contact + + # Get the METAL 1/2/3 layers. + self.cut1 = DataBase.getDB().getTechnology().getLayer( 'cut1' ) + self.metal1 = DataBase.getDB().getTechnology().getLayer( 'metal1' ) + self.metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' ) + self.metal3 = DataBase.getDB().getTechnology().getLayer( 'metal3' ) + # Get the symbolic pitch. + rg = AllianceFramework.get().getRoutingGauge() + self.METAL2Pitch = rg.getHorizontalPitch() + self.METAL3Pitch = rg.getVerticalPitch() + self.isVH = rg.isVH() + + foundHor = False + foundVer = False + for depth in range(rg.getDepth()): + rlg = rg.getLayerGauge(depth) + if rlg.getLayer().getMask() == self.metal2.getMask(): self.metal2Width = rlg.getWireWidth() + if rlg.getLayer().getMask() == self.metal3.getMask(): self.metal3Width = rlg.getWireWidth() + + if rlg.getType() == Constant.PinOnly: continue + if rlg.getDirection() == Constant.Horizontal and not foundHor: + trace( 101, '\tself.hpitch set\n' ) + self.hpitch = rlg.getPitch() + foundHor = True + if rlg.getDirection() == Constant.Vertical and not foundVer: + trace( 101, '\tself.vpitch set\n' ) + self.vpitch = rlg.getPitch() + foundVer = True + + trace( 101, '-,' ) + return + + + def getLayers( self ): + + technology = DataBase.getDB().getTechnology() + self.layers = {} + + self.layers["resistorPlate"] = technology.getLayer( "poly2" ) + self.layers["contacts" ] = technology.getLayer( "cut0" ) + self.layers["routingLayer" ] = technology.getLayer( "metal1" ) + self.layers["metal2" ] = technology.getLayer( "metal2" ) + self.layers["pImplant" ] = technology.getLayer( "pImplant" ) + self.layers["resdef" ] = technology.getLayer( "resdef" ) + + if self.resistorType == "RPOLYH" : self.layers["hres" ] = technology.getLayer( "hres" ) + if self.resistorType == "RPOLY2PH" : self.layers["restrm"] = technology.getLayer( "restrm" ) + + return self.layers + + + def create( self, bbMode = False ): + + UpdateSession.open() + + layerDict = self.getLayers() + self.computeDimensions(bbMode) + self.drawAbutmentBox () + self.device.setAbutmentBox( self.abutmentBox ) + + if bbMode == False : + + if self.resistorType == "RPOLYH" : self.drawLayer("hres", layerDict["hres"]) #self.drawHRESLayer( layerDict["hres"] ) + + self.drawLayer ("resistorPlate", layerDict["resistorPlate"]) + + self.drawResPlateExtrimities( layerDict["resistorPlate"], layerDict["pImplant"] ) + if self.snakeMode : self.drawCorners(layerDict["resistorPlate"]) + + self.drawContacts( layerDict["contacts"]) + self.drawRoutingLayer(layerDict["routingLayer"]) + if self.resistorType == "RPOLY2PH" : self.drawRestrmLayer(layerDict["restrm"]) + + self.drawResdefLayer(layerDict["resdef"]) + self.drawTerminals() + + UpdateSession.close() + + return self.abutmentBoxDict + + + + def computeDimensions( self, bbMode ): + + if self.snakeMode : + self.__computeSnakeCornerDim__ () + self.computeSnakeSegmentDimensions() + if self.resistorType == "RPOLYH" : self.snakeSegments_spacing = max(self.minSpacing_resistorPlate_pImplantLayer, self.minSpacing_resistorPlate) + if self.resistorType == "RPOLY2PH" : self.snakeSegments_spacing = self.minSpacing_resistorPlate + + self.computeAbutmentBoxDimensions() + + if bbMode == False : + if not self.snakeMode : + self.computeResistorPlateDimensions() + if self.snakeMode : + self.computeFirstSnakeSegmentPosition() + + return + + + + def computePImplantLayerDim ( self ): + + pImplantLayer_width = max(self.minWidth_pImplantLayer, 2*self.minEnclosure_pImplantLayer_contact + self.minWidth_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 + + + ## extensions2 refers to a part of the corner + def computeResPlateExtensionsDim( self ): + + self.resPlateExtensions_minWidth = self.minWidth_contact + 2*self.minEnclosure_resistorPlate_contact + 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 + print("self.resPlateExtensions['length']",self.resPlateExtensions["length"]) + if self.snakeMode : + self.resPlateExtension1 = self.resPlateExtensions + self.resPlateExtension2["width" ] = self.snakeSegmentDict["width"] + self.resPlateExtension2["length"] = self.snakeSegmentDict["width"] + + 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.pImplant_layerDict + + if self.resistorType == "RPOLY2PH" : + for key in self.resPlateExtensions.keys(): self.resPlateExtrimities [key] = self.resPlateExtensions [key] + + if self.snakeMode : + for key in self.resPlateExtrimities.keys(): self.resPlateExtrimity1 [key] = self.resPlateExtrimities [key] + + if self.resistorType == "RPOLYH" : + self.resPlateExtrimity2["width" ] = self.resPlateExtension2 ["width" ] + 2*self.enclosure_resistor_hres + self.resPlateExtrimity2["length"] = self.resPlateExtension2 ["length"] + self.enclosure_resistor_hres + + if self.resistorType == "RPOLY2PH" : + for key in self.resPlateExtension2.keys() : self.resPlateExtrimity2 [key] = self.resPlateExtension2[key] + + for key in self.resPlateExtrimity1.keys() : self.resPlateExtrimities[key] = max(self.resPlateExtrimity1[key] , self.resPlateExtrimity2[key]) + + return + + + + + def computeAbutmentBoxDimensions( self ): + + if self.resistorType == "RPOLYH" : self.enclosure_resistor_abutmentBox = self.minSpacing_hres + if self.resistorType == "RPOLY2PH" : self.enclosure_resistor_abutmentBox = self.minSpacing_resistorPlate + + self.computeResPlateExtensionsDim() + + print("self.resPlateExtensionsabt0['length']",toPhy(self.resPlateExtensions["length"])) + if not self.snakeMode : layerWidth = self.resPlateExtensions["width"] + if self.snakeMode : layerWidth = self.resPlateExtension1["width"] + + self.contactsNumber = self.cutMaxNumber( layerWidth, self.minHeight_contact, self.minSpacing_contact, self.minEnclosure_resistorPlate_contact ) + + if self.resistorType == "RPOLYH" : + self.computePImplantLayerDim() + self.computeHRESLayerDimensions() + + self.computeResPlateExtrimitiesDim() + + if not self.snakeMode : + abutmentBoxSide1 = self.resPlateExtrimities["width" ] + 2*self.enclosure_resistor_abutmentBox + abutmentBoxSide2 = self.resDim ["length"] + 2*self.resPlateExtrimities["length"] + 2*self.enclosure_resistor_abutmentBox + + if self.snakeMode : + if self.resistorType == "RPOLYH" : resistor_width = self.hresLayerDict.values()[0] + if self.resistorType == "RPOLY2PH" : resistor_width = (self.bends+1)*self.snakeSegmentDict["width"] + self.bends*self.snakeSegments_spacing + + abutmentBoxSide1 = resistor_width + 2*self.enclosure_resistor_abutmentBox #width + if self.bends > 1 : + abutmentBoxSide2 = self.snakeSegmentDict["length"] + 2*self.resPlateExtrimities["length"] + 2*self.enclosure_resistor_abutmentBox + if self.bends == 1 : + abutmentBoxSide2 = self.snakeSegmentDict["length"] + self.resPlateExtrimity1["length"] + self.resPlateExtrimity2["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 + + return + + + + def computeHRESLayerDimensions( self ): + + self.enclosure_resistor_hres = self.minEnclosure_hres_poly2 + if not self.snakeMode : hresLayerSide1 = max(self.minWidth_hres, self.pImplant_layerDict["width" ] + 2*self.enclosure_resistor_hres) + if self.snakeMode : hresLayerSide1 = max(self.minWidth_hres, (self.bends+1)*self.snakeSegmentDict["width"] + self.bends*self.snakeSegments_spacing + 2*self.enclosure_resistor_hres) + + if self.direction == "vertical" : + self.hresLayerDict["length"] = hresLayerSide1 + + if self.direction == "horizontal" : + self.hresLayerDict["width" ] = hresLayerSide1 + + + return + + + + def computeResistorPlateDimensions( self ): + + self.resistorPlateDict["width" ] = self.resDim["width" ] + self.resistorPlateDict["length" ] = self.resDim["length"] + + if self.direction == "vertical" : keysList = ["XCenter","YMin","YMax","XMin","width" ] + if self.direction == "horizontal" : keysList = ["YCenter","XMin","XMax","YMin","height"] + + self.resistorPlateDict[ keysList[0] ] = self.abutmentBoxDict [keysList[3]] + self.abutmentBoxDict [keysList[4]]/2 + self.resistorPlateDict[ keysList[1] ] = self.abutmentBoxDict [keysList[1]] + self.enclosure_resistor_abutmentBox + self.resPlateExtrimities["length"] + self.resistorPlateDict[ keysList[2] ] = self.resistorPlateDict[keysList[1]] + self.resistorPlateDict["length"] + + + return + + + ## The first bend is the lowest one (horizontally) + def computeSnakeSegmentDimensions( self ): + + snakeSegmentDict = {} + snakeSegmentDict["width" ] = toPhy(self.resDim["width" ]) + totalResLength = toPhy(self.resDim["length"]) + correctionFactor = self.__getCornerResistanceCorrectionFactor__() + + snakeSegmentDict["length"] = (totalResLength- self.bends*( snakeSegmentDict["width"]*(correctionFactor+1) + toPhy(self.minSpacing_resistorPlate) )) / (self.bends + 1) + snakeSegmentDict ["length"] = toFoundryGrid( toDbU(snakeSegmentDict["length"]) ) + snakeSegmentDict ["width" ] = toFoundryGrid( toDbU(snakeSegmentDict["width" ]) ) + print("snakesegW",snakeSegmentDict["width" ] ) + if self.__isDimOk__(snakeSegmentDict, "length") : + self.snakeSegmentDict["width" ] = snakeSegmentDict["width" ] + self.snakeSegmentDict["length" ] = snakeSegmentDict["length"] + + return + + + ## The first bend is the lowest one (horizontally) + def computeFirstSnakeSegmentPosition( self ) : + + if self.direction == "vertical" : + + if self.bends > 1 : firstExtrimity_width = self.resPlateExtrimities["width"] + if self.bends == 1 : firstExtrimity_width = self.resPlateExtrimity1 ["width"] + + if self.resistorType == "RPOLYH" : + self.snakeSegmentDict["XCenter"] = self.abutmentBoxDict["XMin"] + self.enclosure_resistor_abutmentBox + self.snakeSegmentDict["width"]/2 + self.enclosure_resistor_hres + self.snakeSegmentDict["YMin" ] = self.abutmentBoxDict["YMin"] + self.enclosure_resistor_abutmentBox + firstExtrimity_width #length + + if self.resistorType == "RPOLY2PH" : + self.snakeSegmentDict["XCenter"] = self.abutmentBoxDict["XMin"] + self.enclosure_resistor_abutmentBox + self.snakeSegmentDict["width"]/2 + self.snakeSegmentDict["YMin" ] = self.abutmentBoxDict["YMin"] + self.enclosure_resistor_abutmentBox + firstExtrimity_width + + self.snakeSegmentDict ["YMax" ] = self.snakeSegmentDict["YMin"] + self.snakeSegmentDict["length"] + + + if self.direction == "horizontal" : + + if self.bends > 1 : firstExtrimity_length = self.resPlateExtrimities["length"] + if self.bends == 1 : firstExtrimity_length = self.resPlateExtrimity1 ["length"] + + if self.resistorType == "RPOLYH" : + self.snakeSegmentDict["YCenter"] = self.abutmentBoxDict["YMin"] + self.enclosure_resistor_abutmentBox + self.snakeSegmentDict["width"]/2 + self.enclosure_resistor_hres + self.snakeSegmentDict["XMin" ] = self.abutmentBoxDict["XMin"] + self.enclosure_resistor_abutmentBox + firstExtrimity_length + + if self.resistorType == "RPOLY2PH" : + self.snakeSegmentDict["YCenter"] = self.abutmentBoxDict["YMin"] + self.enclosure_resistor_abutmentBox + self.snakeSegmentDict["width"]/2 + self.snakeSegmentDict["XMin" ] = self.abutmentBoxDict["XMin"] + self.enclosure_resistor_abutmentBox + firstExtrimity_length + + self.snakeSegmentDict ["XMax" ] = self.snakeSegmentDict["XMin"] + self.snakeSegmentDict["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, layerLabel, layer): + + thiknessKey = "width" + maxIterations = 1 + centerTranslation = 0 + + if layerLabel not in ["hres","resistorPlate"] : raise Error(1,'drawLayer() : Supported layer labels "hres" or "resistorPlate".') + + if layerLabel == "hres" : + self.computeHRESLayerPosition() + positionParams = self.hresLayerDict + if self.direction == "vertical" : thiknessKey = "length" + + if layerLabel == "resistorPlate" : + + if not self.snakeMode : + positionParams = self.resistorPlateDict + + if self.snakeMode : + positionParams = self.snakeSegmentDict + maxIterations = self.bends + 1 + centerTranslation = self.snakeSegmentDict["width"] + self.snakeSegments_spacing + + if self.direction == "vertical" : + for i in range(0, maxIterations) : + print self.nets[0], layer \ + , positionParams["XCenter" ] + i*centerTranslation \ + , positionParams[thiknessKey] \ + , positionParams["YMin" ] \ + , positionParams["YMax" ] + Vertical.create ( self.nets[0], layer + , positionParams["XCenter" ] + i*centerTranslation + , positionParams[thiknessKey] + , positionParams["YMin" ] + , positionParams["YMax" ] + ) + + if self.direction == "horizontal" : + for i in range(0, maxIterations) : + Horizontal.create( self.nets[0], layer + , positionParams["YCenter" ] + i*centerTranslation + , positionParams[thiknessKey] + , positionParams["XMin" ] + , positionParams["XMax" ] + ) + return + + + + def drawResdefLayer( self, layer ): + + self.computeResDefDimensions () + if not self.snakeMode : + self.drawResdefForResistorPlate( layer ) + if self.snakeMode : + self.drawResdefForSnakeSegments( layer ) + self.drawResdefForCorners ( layer ) + + + return + + + def drawResdefForResistorPlate( self, layer ): + + if self.direction == "vertical" : + Vertical.create ( self.nets[0], layer + , self.resdefLayerDict["XCenter"] + , self.resdefLayerDict["width" ] + , self.resdefLayerDict["YMin" ] + , self.resdefLayerDict["YMax" ] + ) + + if self.direction == "horizontal" : + Horizontal.create( self.nets[0], layer + , self.resdefLayerDict["YCenter"] + , self.resdefLayerDict["width" ] + , self.resdefLayerDict["XMin" ] + , self.resdefLayerDict["XMax" ] + ) + print("self.resdefLayerDict['width' ]",self.resdefLayerDict["width" ]) + print("self.resistorPlateDict['width' ]",self.resistorPlateDict["width" ]) + + return + + + def drawResdefForSnakeSegments( self, layer ): + + if not self.snakeMode : centerTranslation = 0 + if self.snakeMode : centerTranslation = self.snakeSegmentDict["width"] + self.snakeSegments_spacing + + if self.resistorType == "RPOLYH" : extrimityTranslation = 0 + if self.resistorType == "RPOLY2PH" : extrimityTranslation = self.minWidth_contact/4 + + if self.direction == "vertical" : + + for i in range(0, self.bends + 1) : + if self.resistorType == "RPOLYH" : factor0, factor1 = 1,1 + if self.resistorType == "RPOLY2PH" : + factor0 = 0 if ( i == self.bends and self.bends % 2 == 0 ) else 1 + factor1 = 0 if ( i == self.bends and self.bends % 2 != 0 ) or i == 0 else 1 + Vertical.create ( self.nets[0], layer + , self.resdefLayerDict["XCenter"] + i*centerTranslation + , self.resdefLayerDict["width" ] + , self.resdefLayerDict["YMin" ] + factor0*extrimityTranslation + , self.resdefLayerDict["YMax" ] - factor1*extrimityTranslation + ) + + if self.direction == "horizontal" : + + for i in range(0, self.bends + 1) : + if self.resistorType == "RPOLYH" : factor0, factor1 = 1, 1 + if self.resistorType == "RPOLY2PH" : + factor0 = 0 if i == 0 or (i == self.bends and self.bends % 2 != 0) else 1 + factor1 = 0 if i == self.bends and self.bends % 2 == 0 else 1 + Horizontal.create( self.nets[0], layer + , self.resdefLayerDict["YCenter"] + i*centerTranslation + , self.resdefLayerDict["width" ] + , self.resdefLayerDict["XMin" ] + factor0*extrimityTranslation + , self.resdefLayerDict["XMax" ] - factor1*extrimityTranslation + ) + return + + + + def drawResdefForCorners( self, layer ): + + k,factor = 0,0 + if self.shape == 135 : + factor = 1 + self.computeFirstSnakeCornerPosition90() + + translation = self.snakeSegmentDict ["width" ] + self.snakeSegments_spacing + centersTranslationConst = self.snakeSegmentDict ["width" ] + self.snakeSegmentDict["length"] + + if self.shape == 90 : widthExtension = self.minWidth_contact/2 + if self.shape == 135 : widthExtension = self.minWidth_contact/4 + toDbU(0.2) + + if self.direction == "vertical" : + snakeCornersYCenters = [ self.snakeCornerDict["YCenter"] - factor*( toDbU(0.2)/2 + self.minWidth_contact/8 ) + , self.snakeCornerDict["YCenter"] + factor*( toDbU(0.2)/2 + self.minWidth_contact/8 ) + centersTranslationConst ] + + for i in range(0,self.bends) : + Horizontal.create( self.nets[0], layer + , snakeCornersYCenters[k] + , self.snakeCornerDict["width"] + widthExtension + , self.snakeCornerDict["XMin" ] - self.minWidth_contact/4 + i*translation + , self.snakeCornerDict["XMax" ] + self.minWidth_contact/4 + i*translation + ) + k = k+1 if k<1 else 0 + + if self.direction == "horizontal" : + snakeCornersXCenters = [ self.snakeCornerDict["XCenter"] + factor*( toDbU(0.2)/2 + self.minWidth_contact/8 ) + , self.snakeCornerDict["XCenter"] - factor*( toDbU(0.2)/2 + self.minWidth_contact/8 ) - centersTranslationConst ] + + for i in range(0,self.bends) : + Vertical.create ( self.nets[0], layer + , snakeCornersXCenters[k] + , self.snakeCornerDict["width"] + widthExtension + , self.snakeCornerDict["YMin" ] - self.minWidth_contact/4 + i*translation + , self.snakeCornerDict["YMax" ] + self.minWidth_contact/4 + i*translation + ) + k = k+1 if k<1 else 0 + + return + + + + def drawSnakeSegments( self, layer ): + + translation = self.snakeSegmentDict["width"] + self.snakeSegments_spacing + + if self.direction == "vertical" : + + for i in range(0, self.bends + 1) : + Vertical.create ( self.nets[0], layer + , self.snakeSegmentDict["XCenter"] + i*translation + , self.snakeSegmentDict["width" ] + , self.snakeSegmentDict["YMin" ] + , self.snakeSegmentDict["YMax" ] + ) + + if self.direction == "horizontal" : + + for i in range(0, self.bends + 1) : + Horizontal.create( self.nets[0], layer + , self.snakeSegmentDict["YCenter"] + i*translation + , self.snakeSegmentDict["width" ] + , self.snakeSegmentDict["XMin" ] + , self.snakeSegmentDict["XMax" ] + ) + return + + + + def drawAbutmentBox( self ): + + ab = Box( self.abutmentBoxDict["XMin" ] + , self.abutmentBoxDict["YMin" ] + , self.abutmentBoxDict["width" ] + , self.abutmentBoxDict["height"] + ) + + height = ab.getHeight() + heightAdjust = height % (2*self.hpitch) + if heightAdjust: + heightAdjust = 2*self.hpitch - heightAdjust + ab.inflate( 0, heightAdjust/2 ) + + width = ab.getWidth() + widthAdjust = width % (2*self.vpitch) + if widthAdjust: + widthAdjust = 2*self.vpitch - widthAdjust + ab.inflate( widthAdjust/2, 0 ) + + self.abutmentBox = ab + return + + + + + def drawResPlateExtrimities( self, resPlateLayer, pImplantLayer ): + + self.drawResPlateExtensions(resPlateLayer) + if self.resistorType == "RPOLYH" : + self.drawPImplantLayer(pImplantLayer) + + return + + ## extension1 is on the right side of the resistor (if direction == horizontal) and the bottom side otherwhise + def computeResPlateExtensionsPosition( self ): + + self.resPlateExtensions["ex1"] = {} + + if self.direction == "vertical" : + + if not self.snakeMode : self.resPlateExtensions["ex1"]["XMin"] = self.abutmentBox.getXCenter() - self.resPlateExtensions["width" ]/2 + if self.snakeMode : self.resPlateExtensions["ex1"]["XMin"] = self.abutmentBox.getXCenter() + (self.bends*(self.snakeSegmentDict["width"] + self.snakeSegments_spacing))/2 - self.resPlateExtensions["width"]/2 + + if not self.snakeMode : translation = self.resPlateExtensions["length"] + self.resDim["length"]/2 + if self.snakeMode and self.bends % 2 == 0 : translation = self.resPlateExtensions["length"] + self.snakeSegmentDict["length"]/2 + if self.snakeMode and self.bends % 2 != 0 : translation = self.snakeSegmentDict ["length"]/2 + print("self.resPlateExtensions5['length']",toPhy(self.resPlateExtensions["length"])) +# print("self.snakeSegmentDict['length']/2",toPhy(self.snakeSegmentDict["length"]/2)) +# print("translation",toPhy(self.resPlateExtensions['length'] + self.snakeSegmentDict["length"]/2)) + print("self.abutmentBox.getYCenter(",toPhy(self.abutmentBox.getYCenter())) + if not self.snakeMode or self.snakeMode and self.bends % 2 == 0 : self.resPlateExtensions["ex1"]["YMin"] = self.abutmentBox.getYCenter() - translation + if self.snakeMode and self.bends % 2 != 0 : self.resPlateExtensions["ex1"]["YMin"] = self.abutmentBox.getYCenter() + translation + + print("self.resPlateExtensions['ex1']['YMin']",toPhy(self.resPlateExtensions["ex1"]["YMin"])) + 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" : + + if not self.snakeMode : resistorLength = self.resDim ["length"] + if self.snakeMode : resistorLength = self.snakeSegmentDict["length"] + + self.resPlateExtensions["ex1"]["XMin"] = self.abutmentBox.getXCenter() - self.resPlateExtensions["length"] - resistorLength/2 + + if not self.snakeMode : self.resPlateExtensions["ex1"]["YMin"] = self.abutmentBox.getYCenter() - self.resPlateExtensions["width" ]/2 + if self.snakeMode : self.resPlateExtensions["ex1"]["YMin"] = self.snakeSegmentDict["YCenter"] - self.resPlateExtensions["width" ]/2 + + self.resPlateExtensions["ex1"]["XMax"] = self.resPlateExtensions["ex1"]["XMin"] + self.resPlateExtensions["length"] +# print("self.resPlateExtensions['length']",toPhy(self.resPlateExtension2["length"])) + self.resPlateExtensions["ex1"]["YMax"] = self.resPlateExtensions["ex1"]["YMin"] + self.resPlateExtensions["width" ] + + return + + + + def drawResPlateExtensions( self, layer ): - return (True, "") + self.computeResPlateExtensionsPosition() + if not self.snakeMode : resistorLength = self.resDim ["length"] + if self.snakeMode : resistorLength = self.snakeSegmentDict["length"] + + translation1 = resistorLength + self.resPlateExtensions["length"] + if self.snakeMode : translation2 = self.bends*(self.snakeSegmentDict["width"] + self.snakeSegments_spacing) #- self.resPlateExtensions["width"] + + if self.direction == "vertical" : + + if not self.snakeMode : [ hTranslation , vTranslation ] = [ 0 , translation1 ] + if self.snakeMode and self.bends % 2 == 0 : [ hTranslation , vTranslation ] = [ translation2 , translation1 ] + if self.snakeMode and self.bends % 2 != 0 : [ hTranslation , vTranslation ] = [ translation2 , 0 ] + + 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"] - hTranslation + , self.resPlateExtensions["ex1"]["YMin"] + vTranslation + , self.resPlateExtensions["ex1"]["XMax"] - hTranslation + , self.resPlateExtensions["ex1"]["YMax"] + vTranslation + ) + + if self.direction == "horizontal" : + + if not self.snakeMode : [ hTranslation , vTranslation ] = [ translation1 , 0 ] + if self.snakeMode and self.bends % 2 == 0 : [ hTranslation , vTranslation ] = [ translation1 , translation2 ] + if self.snakeMode and self.bends % 2 != 0 : [ hTranslation , vTranslation ] = [ 0 , translation2 ] + + print("vTranslation",vTranslation) + print("hTranslation",hTranslation) + + 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"] + hTranslation + , self.resPlateExtensions["ex1"]["YMin"] + vTranslation + , self.resPlateExtensions["ex1"]["XMax"] + hTranslation + , self.resPlateExtensions["ex1"]["YMax"] + vTranslation + ) + + terminal1Pad = Pad.create(self.nets[0], layer, self.terminal1Box) + terminal2Pad = Pad.create(self.nets[1], layer, self.terminal2Box) + + return -def layout ( device, bbMode ): - trace( 100, ',+', '\tResistorSnake.layout() called.\n' ) + def computePImplantLayerPosition( self ): - paramsMatrix = ParamsMatrix.ParamsMatrix() + factor1 = factor2 = -1 + if not self.snakeMode : centerTranslation = 0 + if self.snakeMode : centerTranslation = self.bends*(self.snakeSegments_spacing + self.snakeSegmentDict["width"])/2 - try: - bends = device.getParameter( 'bends' ) - print 'bends = ', bends + if self.direction == "vertical" : + keysList = ["YCenter","XMin","XMax","YMin"] + functionsList = [self.abutmentBox.getYCenter(), self.abutmentBox.getXCenter()] + if self.snakeMode and self.bends % 2 != 0 : factor1 = 1 + if self.snakeMode : factor2 = 1 - device.setAbutmentBox( Box( u(0.0), u(0.0), u(10.0), u((bends.getValue()+1)*10.0)) ) + if self.direction == "horizontal" : + keysList = ["XCenter","YMin","YMax","XMin"] + functionsList = [self.abutmentBox.getXCenter(), self.abutmentBox.getYCenter()] - paramsMatrix.setGlobalResistorParams( device.getAbutmentBox() ) - trace( 100, '++' ) - #paramsMatrix.trace() + if not self.snakeMode : resistorLength = self.resDim ["length"] + if self.snakeMode : resistorLength = self.snakeSegmentDict["length"] + + self.pImplant_layerDict[ keysList[0] ] = functionsList[0] + factor1*( resistorLength/2 + self.pImplant_layerDict["length"]/2 ) + self.pImplant_layerDict[ keysList[1] ] = functionsList[1] + factor2*centerTranslation - self.pImplant_layerDict["width" ]/2 #- centerTranslation - self.pImplant_layerDict["width" ]/2 + self.pImplant_layerDict[ keysList[2] ] = self.pImplant_layerDict[keysList[1]] + self.pImplant_layerDict["width" ] - except Exception, e: - helpers.io.catch( e ) + return - trace( 100, '---' ) + + def drawPImplantLayer( self, layer ): + + self.computePImplantLayerPosition() + if not self.snakeMode : resistorLength = self.resDim ["length"] + if self.snakeMode : resistorLength = self.snakeSegmentDict["length"] + + if not self.snakeMode or self.snakeMode and self.bends % 2 == 0 : centerTranslation = resistorLength + self.pImplant_layerDict["length"] + if self.snakeMode and self.bends % 2 != 0 : centerTranslation = 0 + if not self.snakeMode : extrimitiesTranslation = 0 + if self.snakeMode : extrimitiesTranslation = self.bends*(self.snakeSegments_spacing + self.snakeSegmentDict["width"]) #+ self.pImplant_layerDict["width"]/2 + + if self.direction == "vertical" : + for i in [0,1] : Horizontal.create( self.nets[i], layer + , self.pImplant_layerDict["YCenter"] + i*centerTranslation + , self.pImplant_layerDict["length" ] + , self.pImplant_layerDict["XMin" ] - i*extrimitiesTranslation + , self.pImplant_layerDict["XMax" ] - i*extrimitiesTranslation + ) + + if self.direction == "horizontal" : + for i in [0,1] : Vertical.create ( self.nets[i], layer + , self.pImplant_layerDict["XCenter"] + i*centerTranslation + , self.pImplant_layerDict["length" ] + , self.pImplant_layerDict["YMin" ] + i*extrimitiesTranslation + , self.pImplant_layerDict["YMax" ] + i*extrimitiesTranslation + + ) + + return + + ## t1Cut connected to terminal1 (on the right side/bottom side of rectangular) + def computecenterTranslationDimensions( self ): + + enclosure1 = ( self.resPlateExtensions["width"] - (self.contactsNumber*self.minHeight_contact + (self.contactsNumber -1)*self.minSpacing_contact) )/2 + enclosure2 = self.minEnclosure_resistorPlate_contact + + if self.resistorType == "RPOLYH" : enclosure3 = self.minEnclosure_pImplantLayer_contact + if self.resistorType == "RPOLY2PH" : enclosure3 = 0 + + if self.direction == "vertical": + + self.t1cutsEnclosure["horizontal"] = enclosure1 + if not self.snakeMode or self.snakeMode and self.bends % 2 == 0 : self.t1cutsEnclosure["vertical"] = enclosure2 + if self.snakeMode and self.bends % 2 != 0 : self.t1cutsEnclosure["vertical"] = enclosure3 + + self.t2cutsEnclosure["horizontal"] = enclosure1 + self.t2cutsEnclosure["vertical" ] = enclosure3 + + if self.direction == "horizontal" : + + self.t1cutsEnclosure["horizontal"] = enclosure2 + self.t1cutsEnclosure["vertical" ] = enclosure1 + + if not self.snakeMode or self.snakeMode and self.bends % 2 == 0 : self.t2cutsEnclosure["horizontal"] = enclosure3 + if self.snakeMode and self.bends % 2 != 0 : self.t2cutsEnclosure["horizontal"] = enclosure2 + #self.t2cutsEnclosure["horizontal"] = enclosure3 + + self.t2cutsEnclosure["vertical" ] = enclosure1 + + self.t1CutCenterDict ["XCenter" ] = self.terminal1Box.getXMin() + self.t1cutsEnclosure ["horizontal"] + self.minWidth_contact/2 + self.t1CutCenterDict ["YCenter" ] = self.terminal1Box.getYMin() + self.t1cutsEnclosure ["vertical" ] + self.minHeight_contact/2 + + self.t2CutCenterDict ["XCenter" ] = self.terminal2Box.getXMin() + self.t2cutsEnclosure ["horizontal"] + self.minWidth_contact/2 + self.t2CutCenterDict ["YCenter" ] = self.terminal2Box.getYMin() + self.t2cutsEnclosure ["vertical" ] + self.minHeight_contact/2 + + return + + + + def drawContacts( self, layer ): + + self.computecenterTranslationDimensions() + + if self.direction == "vertical" : cutLineDirection = "horizontal" + if self.direction == "horizontal" : cutLineDirection = "vertical" + + self.cutLine ( self.nets[0], layer + , self.t1CutCenterDict["XCenter"] + , self.t1CutCenterDict["YCenter"] + , self.minWidth_contact + , self.minHeight_contact + , self.minSpacing_contact + , self.contactsNumber + , cutLineDirection + ) + + self.cutLine ( self.nets[1], layer + , self.t2CutCenterDict["XCenter"] + , self.t2CutCenterDict["YCenter"] + , self.minWidth_contact + , self.minHeight_contact + , self.minSpacing_contact + , self.contactsNumber + , cutLineDirection + ) + + return + + + def drawRoutingLayer( self, layer ): + + layer_width = self.minWidth_contact + 2*self.minEnclosure_routingLayer_contact + layer_height = self.contactsNumber*self.minWidth_contact + (self.contactsNumber-1)*self.minSpacing_contact + 2*self.minEnclosure_routingLayer_contact + + if self.direction == "vertical" : key = "XCenter" + if self.direction == "horizontal" : key = "YCenter" + + source1 = self.t1CutCenterDict[key] - self.minWidth_contact/2 - self.minEnclosure_routingLayer_contact + target1 = source1 + layer_height + + source2 = self.t2CutCenterDict[key] - self.minWidth_contact/2 - self.minEnclosure_routingLayer_contact + target2 = source2 + layer_height + + + if self.direction == "vertical" : + Horizontal.create( self.nets[0] + , layer, self.t1CutCenterDict["YCenter"] + , layer_width + , source1 + , target1 ) + Horizontal.create( self.nets[1] + , layer + , self.t2CutCenterDict["YCenter"] + , layer_width + , source2 + , target2) + + trace( 101, '\tIN PAD self.t1CutCenterDict["XCenter"] = {0}\n'.format(DbU.getValueString(self.t1CutCenterDict["XCenter"])) ) + trace( 101, '\tIN PAD source1 = {0}\n'.format(DbU.getValueString(source1)) ) + trace( 101, '\tIN PAD target1 = {0}\n'.format(DbU.getValueString(target1)) ) + + #h = Horizontal.create( self.nets[0] + # , self.layers['metal2'] + # , self.t1CutCenterDict["YCenter"] + # , layer_width + # , source1 + # , target1 ) + #NetExternalComponents.setExternal( h ) + # + #h = Horizontal.create( self.nets[1] + # , self.layers['metal2'] + # , self.t2CutCenterDict["YCenter"] + # , layer_width + # , source2 + # , target2 ) + #NetExternalComponents.setExternal( h ) + + if self.direction == "horizontal" : + Vertical.create (self.nets[0], layer, self.t1CutCenterDict["XCenter"], layer_width, source1, target1) + Vertical.create (self.nets[1], layer, self.t2CutCenterDict["XCenter"], layer_width, source2, target2) + + return + + + + def drawRestrmLayer( self, layer ): + + self.computeRestrmLayerPosition() + if not self.snakeMode : resistorLength = self.resDim ["length"] + if self.snakeMode : resistorLength = self.snakeSegmentDict["length"] + + if not self.snakeMode or self.snakeMode and self.bends % 2 == 0 : centerTranslation = resistorLength + self.restrmLayerDict["width"] + if self.snakeMode and self.bends % 2 != 0 : centerTranslation = 0 + + if not self.snakeMode : extrimitiesTranslation = 0 + if self.snakeMode : extrimitiesTranslation = self.bends*(self.snakeSegments_spacing + self.snakeSegmentDict["width"]) + + if self.direction == "vertical" : + for i in [0,1]: Horizontal.create( self.nets[i], layer + , self.restrmLayerDict["YCenter"] + i*centerTranslation + , self.restrmLayerDict["width" ] + , self.restrmLayerDict["XMin" ] - i*extrimitiesTranslation + , self.restrmLayerDict["XMax" ] - i*extrimitiesTranslation + ) + + if self.direction == "horizontal" : + for i in [0,1]: Vertical.create ( self.nets[i], layer + , self.restrmLayerDict["XCenter"] + i*centerTranslation + , self.restrmLayerDict["width" ] + , self.restrmLayerDict["YMin" ] + i*extrimitiesTranslation + , self.restrmLayerDict["YMax" ] + i*extrimitiesTranslation + ) + + return + + + + def computeRestrmLayerPosition( self ): + + self.restrmLayerDict["width"] = self.minWidth_contact/2 + factor = 1 + + if self.direction == "vertical" : + keysList = ["YCenter","XMin","XMax"] +# if not self.snakeMode or self.snakeMode and self.bends % 2 == 0 : factor = 1 + if self.snakeMode and self.bends % 2 != 0 : factor = -1 + if self.direction == "horizontal" : + keysList = ["XCenter","YMin","YMax"] + + self.restrmLayerDict[ keysList[0] ] = self.t1CutCenterDict [ keysList[0] ] + factor*self.restrmLayerDict["width"]/2 + self.restrmLayerDict[ keysList[1] ] = self.resPlateExtensions["ex1"][ keysList[1] ] - self.restrmLayerDict["width"] + self.restrmLayerDict[ keysList[2] ] = self.resPlateExtensions["ex1"][ keysList[2] ] + self.restrmLayerDict["width"] + + return + + + + def computeResDefDimensions( self ): + + if self.direction == "vertical" : keysList = ["YMin","YMax","XCenter","width"] + if self.direction == "horizontal" : keysList = ["XMin","XMax","YCenter","width"] + + if not self.snakeMode : resistorElement = self.resistorPlateDict + if self.snakeMode : resistorElement = self.snakeSegmentDict + + if self.resistorType == "RPOLYH" : factor = 0 + if self.resistorType == "RPOLY2PH" : factor = 1 + + self.resdefLayerDict[keysList[0]] = resistorElement[keysList[0]] - factor*self.minWidth_contact/4 + self.resdefLayerDict[keysList[1]] = resistorElement[keysList[1]] + factor*self.minWidth_contact/4 + self.resdefLayerDict[keysList[2]] = resistorElement[keysList[2]] + self.resdefLayerDict[keysList[3]] = resistorElement[keysList[3]] + + if self.resDim["width"] >= self.resPlateExtensions_minWidth : + self.resdefLayerDict[keysList[3]] = self.resdefLayerDict[keysList[3]] + self.minWidth_contact/2 + + return + + + def computeFirstSnakeCornerPosition90( self ): + + if self.direction == "vertical" : + + self.snakeCornerDict["YCenter"] = self.snakeSegmentDict["YMin" ] - self.snakeCornerDict ["width" ]/2 + self.snakeCornerDict["XMin" ] = self.snakeSegmentDict["XCenter"] - self.snakeSegmentDict["width" ]/2 + self.snakeCornerDict["XMax" ] = self.snakeCornerDict ["XMin" ] + self.snakeCornerDict ["length"] + + if self.direction == "horizontal" : + + self.snakeCornerDict["XCenter"] = self.snakeSegmentDict["XMax" ] + self.snakeCornerDict ["width" ]/2 + self.snakeCornerDict["YMin" ] = self.snakeSegmentDict["YCenter"] - self.snakeSegmentDict["width" ]/2 + self.snakeCornerDict["YMax" ] = self.snakeCornerDict ["YMin" ] + self.snakeCornerDict ["length"] + + return + + + + def drawCorners90( self, layer ): + + self.computeFirstSnakeCornerPosition90() + k = 0 + translation = self.snakeSegmentDict["width"] + self.snakeSegments_spacing + centersTranslationConst = self.snakeSegmentDict["width"] + self.snakeSegmentDict["length"] + + if self.direction == "vertical" : + + snakeCornersYCenters = [ self.snakeCornerDict["YCenter"] + , self.snakeCornerDict["YCenter"] + centersTranslationConst] + + for i in range(0,self.bends) : + Horizontal.create( self.nets[0], layer + , snakeCornersYCenters[k] + , self.snakeCornerDict["width"] + , self.snakeCornerDict["XMin" ] + i*translation + , self.snakeCornerDict["XMax" ] + i*translation + ) + k = k+1 if k<1 else 0 + + if self.direction == "horizontal" : + + snakeCornersXCenters = [ self.snakeCornerDict["XCenter"] + , self.snakeCornerDict["XCenter"] - centersTranslationConst ] + + for i in range(0,self.bends) : + Vertical.create ( self.nets[0], layer + , snakeCornersXCenters[k] + , self.snakeCornerDict["width"] + , self.snakeCornerDict["YMin" ] + i*translation + , self.snakeCornerDict["YMax" ] + i*translation + ) + k = k+1 if k<1 else 0 + + return + + + + def computeFirstSnakeCornerPosition135( self ): + + param1 = (self.snakeSegmentDict["width"]*42/100)/2 + param2 = toDbU(0.2) + param3 = self.snakeSegmentDict["width"] + param2 + param4 = param3 - param1 + + if self.direction == "vertical" : + + rx0 = self.snakeSegmentDict["XCenter"] - self.snakeSegmentDict["width"]/2 + ry0 = self.snakeSegmentDict["YMin" ] + rx1 = rx0 + ry1 = ry0 - param1 + rx2 = rx0 + param4 + ry2 = ry1 - param4 + rx3 = rx0 + 2*self.snakeSegmentDict["width"] + self.snakeSegments_spacing - param4 + ry3 = ry2 + rx4 = rx3 + param4 + ry4 = ry1 + rx5 = rx4 + ry5 = ry0 + rx6 = rx5 - self.snakeSegmentDict["width"] + ry6 = ry0 + rx7 = rx0 + self.snakeSegmentDict["width"] + self.snakeSegments_spacing - param2 + ry7 = ry0 - param2 + rx8 = rx0 + self.snakeSegmentDict["width"] + param2 + ry8 = ry7 + rx9 = rx0 + self.snakeSegmentDict["width"] + ry9 = ry0 + + if self.direction == "horizontal" : + + rx0 = self.snakeSegmentDict["XMax" ] + ry0 = self.snakeSegmentDict["YCenter"] - self.snakeSegmentDict["width"]/2 + rx1 = rx0 + param1 + ry1 = ry0 + rx2 = rx1 + (self.snakeSegmentDict["width"] + param2) - param1 + ry2 = ry1 + (self.snakeSegmentDict["width"] + param2) - param1 + rx3 = rx2 + ry3 = ry2 + (2*self.snakeSegmentDict["width"] + self.snakeSegments_spacing) - 2*(self.snakeSegmentDict["width"] + param2 - param1) + rx4 = rx1 + ry4 = ry1 + 2*self.snakeSegmentDict["width"] + self.snakeSegments_spacing + rx5 = rx0 + ry5 = ry0 + 2*self.snakeSegmentDict["width"] + self.snakeSegments_spacing + rx6 = rx0 + ry6 = ry0 + self.snakeSegmentDict["width"] + self.snakeSegments_spacing + rx7 = rx0 + param2 + ry7 = ry6 - param2 + rx8 = rx7 + ry8 = ry0 + self.snakeSegmentDict["width"] + param2 + rx9 = rx0 + ry9 = ry0 + self.snakeSegmentDict["width"] + + rightCorCordinatesList = [ [rx0 , ry0 ] , [rx1, ry1 ] + , [rx2 , ry2 ] , [rx3, ry3 ] + , [rx4 , ry4 ] , [rx5, ry5 ] + , [rx6 , ry6 ] , [rx7, ry7 ] + , [rx8 , ry8 ] , [rx9, ry9 ] + ] + for p in rightCorCordinatesList : + self.rightCorPointsVector.append(Point(p[0],p[1])) + self.leftCorPointsVector.append (Point(p[0],p[1])) + + translationList = [ self.snakeSegmentDict["length"] + , self.snakeSegmentDict["length"] + 2*param1 + , self.snakeSegmentDict["length"] + 2*param3 + , self.snakeSegmentDict["length"] + 2*param3 + , self.snakeSegmentDict["length"] + 2*param1 + , self.snakeSegmentDict["length"] + , self.snakeSegmentDict["length"] + , self.snakeSegmentDict["length"] + 2*param2 + , self.snakeSegmentDict["length"] + 2*param2 + , self.snakeSegmentDict["length"] + ] + + if self.direction == "vertical" : + for i in range(0, len(self.leftCorPointsVector)) : self.leftCorPointsVector[i].translate( 0 , translationList[i] ) + if self.direction == "horizontal" : + for i in range(0, len(self.leftCorPointsVector)) : self.leftCorPointsVector[i].translate( - translationList[i] , 0) + + return + + + def drawCorners135( self, layer ): + + self.computeFirstSnakeCornerPosition135() + if self.bends % 2 == 0 : [ rightCornersNum, leftCornersNum ] = [ self.bends/2 , self.bends/2 ] + if self.bends % 2 != 0 : [ rightCornersNum, leftCornersNum ] = [ (self.bends+1)/2 , (self.bends-1)/2 ] + + translationFactor = 2*(self.snakeSegmentDict["width"] + self.snakeSegments_spacing) + + if self.direction == "vertical" : [dxTranslation, dyTranslation] = [ translationFactor, 0 ] + if self.direction == "horizontal" : [dxTranslation, dyTranslation] = [ 0 , translationFactor ] + + for i in range(0, rightCornersNum) : + Rectilinear.create( self.nets[0], layer, self.rightCorPointsVector ).translate(i*dxTranslation, i*dyTranslation) + + for i in range(0, leftCornersNum ) : + if i == 0 : + if self.direction == "vertical" : Rectilinear.create(self.nets[0], layer, self.leftCorPointsVector).translate(dxTranslation/2,dyTranslation) + if self.direction == "horizontal": Rectilinear.create(self.nets[0], layer, self.leftCorPointsVector).translate(dxTranslation,dyTranslation/2) + + if i != 0 : + if self.direction == "vertical" : Rectilinear.create(self.nets[0], layer, self.leftCorPointsVector).translate(i*3*dxTranslation/2,dyTranslation) + if self.direction == "horizontal": Rectilinear.create(self.nets[0], layer, self.leftCorPointsVector).translate(dxTranslation,i*3*dyTranslation/2) + + return + + + def drawCorners( self, layer): + + if self.shape == 90 : self.drawCorners90 (layer) + if self.shape == 135 : self.drawCorners135(layer) + + return + + +# def drawResDefLayer( self, layer ): - return paramsMatrix.getMatrix() +# self.computeResDefDimensions() +# if self.direction == "vertical" : Vertical.create ( self.nets[0], layer, self.resdefLayerDict["XCenter"], self.resdefLayerDict["width"], self.resdefLayerDict["YMin"], self.resdefLayerDict["YMax"] ) +# if self.direction == "horizontal" : Horizontal.create ( self.nets[0], layer, self.resdefLayerDict["YCenter"], self.resdefLayerDict["width"], self.resdefLayerDict["XMin"], self.resdefLayerDict["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 drawTerminals ( self ): + VIA1overhang = self.minWidth_cut1/2 + self.minEnclosure_metal1_cut1 + + t1net = self.device.getNet('t1') + t2net = self.device.getNet('t2') + t1metal1 = None + t2metal1 = None + + for component in t1net.getComponents(): + if isinstance(component,Horizontal) and component.getLayer() == self.metal1: + t1metal1 = component + break + + for component in t2net.getComponents(): + if isinstance(component,Horizontal) and component.getLayer() == self.metal1: + t2metal1 = component + break + + ab = self.device.getAbutmentBox() + t1OnNorth = isNearNorth( t1metal1.getY(), ab ) + t2OnNorth = isNearNorth( t2metal1.getY(), ab ) + + if t1OnNorth and t2OnNorth: + t1YM2 = ab.getYMax() - self.hpitch*2 + t2YM2 = ab.getYMax() - self.hpitch + elif t1OnNorth: + t1YM2 = ab.getYMax() - self.hpitch + t2YM2 = ab.getYMin() + self.hpitch + elif t2OnNorth: + t1YM2 = ab.getYMin() + self.hpitch + t2YM2 = ab.getYMax() - self.hpitch + else: + t1YM2 = ab.getYMin() + self.hpitch*2 + t2YM2 = ab.getYMin() + self.hpitch + + m1Width = self.contactsNumber *self.minWidth_contact \ + + (self.contactsNumber-1)*self.minSpacing_contact \ + + 2*self.minEnclosure_routingLayer_contact + edgeDelta = self.minWidth_contact/2 + self.minEnclosure_metal1_cut0 + + if t1OnNorth: + t1BoxM1 = Box( 0 + , self.t1CutCenterDict["YCenter"] - edgeDelta + , m1Width + , t1YM2 + VIA1overhang + ) + else: + t1BoxM1 = Box( 0 + , t1YM2 - VIA1overhang + , m1Width + , self.t1CutCenterDict["YCenter"] + edgeDelta + ) + t1BoxM1.translate( self.t1CutCenterDict["XCenter"] - edgeDelta, 0 ) + + if t2OnNorth: + t2BoxM1 = Box( 0 + , self.t2CutCenterDict["YCenter"] - edgeDelta + , m1Width + , t2YM2 + VIA1overhang + ) + else: + t2BoxM1 = Box( 0 + , t2YM2 - VIA1overhang + , m1Width + , self.t2CutCenterDict["YCenter"] + edgeDelta + ) + t2BoxM1.translate( self.t2CutCenterDict["XCenter"] - edgeDelta, 0 ) + + self.drawM2Terminal( t1net, t1BoxM1, t1YM2 ) + self.drawM2Terminal( t2net, t2BoxM1, t2YM2 ) + + return + + + def drawM2Terminal ( self, net, boxM1, axisM2 ): + ab = self.device.getAbutmentBox() + + minBoxM1 = Box( boxM1.getCenter().getX(), axisM2 ) + minBoxM1.inflate( self.minWidth_cut1/2 + self.minEnclosure_metal1_cut1 ) + boxM1.merge( minBoxM1 ) + + h = Horizontal.create( net + , self.metal2 + , axisM2 + , self.metal2Width + , ab.getXMin() + , ab.getXMax() ) + NetExternalComponents.setExternal( h ) + + Vertical.create( net + , self.metal1 + , boxM1.getCenter().getX() + , boxM1.getWidth() + , boxM1.getYMin() + , boxM1.getYMax() + ) + + cutNumber = ((boxM1.getWidth() - 2*self.minEnclosure_metal1_cut1 - self.minWidth_cut1) \ + / (self.minSpacing_cut1 + self.minWidth_cut1)) + if cutNumber <= 0: cutNumber = 1 + centering = (boxM1.getWidth() - 2*self.minEnclosure_metal1_cut1 \ + - cutNumber * self.minWidth_cut1 \ + - (cutNumber-1) * self.minSpacing_cut1) / 2 + xcut1 = boxM1.getXMin() + centering \ + + self.minEnclosure_metal1_cut1 + self.minWidth_cut1/2 + + trace( 101, '\tcutNumber = {0}\n'.format(cutNumber) ) + for i in range(cutNumber): + trace( 101, '\t[{0}]\n'.format(i) ) + Contact.create( net + , self.cut1 + , xcut1 + , axisM2 + , self.minWidth_cut1 + , self.minWidth_cut1 + ) + xcut1 += self.minWidth_cut1 + self.minSpacing_cut1 + + return + + + +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", bends = 0 ): + #resistor = Resistor( device, nets, "RPOLY2PH", 50, direction = "vertical" ) + #resistor = Resistor( device, nets, "RPOLY2PH", 200, direction = "horizontal", resDim = { "width" : 0.8, "length" : 0 } ) #w >= 2 dogBone not possible in 0.35 um (used only in test) + #resistor = Resistor( device, nets, "RPOLY2PH", 800, direction = "vertical", resDim = { "width" : 0.8, "length" : 0 }, bends = 4 ) #w >= 2 dogBone not possible + #resistor = Resistor( device, nets, "RPOLYH", 4800, direction = "vertical", resDim = { "width" : 0.8, "length" : 0 } ) #w = 0.8 dogBone + #resistor = Resistor( device, nets, "RPOLYH", 48000, direction = "horizontal", resDim = { "width" : 0.8, "length" : 0 }, bends = 3 ) #w = 0.8 dogBone + + #resistor = Resistor( device, nets, "RPOLY2PH", 200, direction = "horizontal") #RPOLY2PH normal + #resistor = Resistor( device, nets, "RPOLYH", 7000, direction = "horizontal", resDim = { "width" : 10, "length" : 0 }) #RPOLYH normal + + #resistor = Resistor( device, nets, "RPOLYH", 20000, direction = "vertical", bends = 1, shape = 135 ) #RPOLYH snake + resistor = Resistor( device, nets, "RPOLY2PH", 2000, resDim = { "width" : 2.5, "length" : 0 }, direction = "vertical", bends = 1, shape = 90 ) #RPOLY2PH snake + + abutmentBoxDim = resistor.create() + print("abutmentBoxDim",abutmentBoxDim) + + AllianceFramework.get().saveCell( device, Catalog.State.Views ) + + return True + diff --git a/oroshi/python/capacitor.ap b/oroshi/python/capacitor.ap deleted file mode 100644 index 20e9b8c1..00000000 --- a/oroshi/python/capacitor.ap +++ /dev/null @@ -1,4 +0,0 @@ -V ALLIANCE : 6 -H capacitor,P,12/12/2019,100 -A 0,0,27184,27184 -EOF