From a12d88040a8440872ec21bb196c1019772fd5d30 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sun, 15 Mar 2020 17:56:09 +0100 Subject: [PATCH] Capacitor support, at last. * Change: In Hurricane::DbU::setGridPerLambdas(), allow the grid per lambda to be even. Needed when using nsxlib libraries that are drawn using a "half lambda" (two lambdas to get an Alliance lambda). * New: In Oroshi/python, integrated capacitors. Modifications and correction from Mariam's code: * No need to redefine __setattr__() on CapacitorUnit. * Pitch horizontally & vertically (symbolic routing tracks) the devices. * Put the horizontal access tracks on the routing pitch. * Sets the horitontal metal2 wires as external components and NOT the capacitor plates themselves. * Makes the size (plates) of the unit capacitor a multiple of the foundry grid, not a floating number... * Correct the net ownership of horizontal tracks in drawHRoutingTracks(). * Simplification & put error management directly inside of __isCapacitorUnitOK__(). * New: In Karakaze/python/AnalogDesign, capacitor spec now include the dummy parameter. --- bora/src/NodeSets.cpp | 3 - bora/src/SlicingPlotWidget.cpp | 2 - hurricane/src/analog/MultiCapacitor.cpp | 18 +- .../analog/hurricane/analog/MultiCapacitor.h | 1 + hurricane/src/hurricane/DataBase.cpp | 13 +- hurricane/src/hurricane/DbU.cpp | 3 +- karakaze/python/AnalogDesign.py | 32 +- karakaze/python/Oceane.py | 2 +- oroshi/python/CapacitorMatrix.py | 165 ++++---- oroshi/python/CapacitorRouted.py | 353 +++++++++++------ oroshi/python/CapacitorRoutedSingle.py | 358 +++++++++++------- oroshi/python/CapacitorUnit.py | 234 +++++++----- oroshi/python/CapacitorVRTracks.py | 104 +++-- oroshi/python/MultiCapacitor.py | 112 ++++-- 14 files changed, 864 insertions(+), 536 deletions(-) diff --git a/bora/src/NodeSets.cpp b/bora/src/NodeSets.cpp index 354e2e04..00c7bcd3 100644 --- a/bora/src/NodeSets.cpp +++ b/bora/src/NodeSets.cpp @@ -113,8 +113,6 @@ namespace Bora { layoutGenerator->setDevice( mcapacitor ); layoutGenerator->drawLayout(); - //cerr << " Create BoxSet for Capacitor " << matrixRange->getValue() << endl; - cerr << " Create BoxSet for Capacitor " << endl; nodeset->push_back( DBoxSet::create( mcapacitor, matrixRange->getIndex(), rg ) ); matrixRange->progress(); @@ -341,7 +339,6 @@ namespace Bora { if (find(boxSet) == NULL) _boxSets.push_back( boxSet ); else { find( boxSet )->incrementCpt(); - cerr << "NodeSets::push_back(): do not add current BoxSet, already exists." << endl; boxSet->destroy(); } } diff --git a/bora/src/SlicingPlotWidget.cpp b/bora/src/SlicingPlotWidget.cpp index 6de7adb7..c3418bec 100644 --- a/bora/src/SlicingPlotWidget.cpp +++ b/bora/src/SlicingPlotWidget.cpp @@ -396,11 +396,9 @@ namespace Bora { for( Instance* iInstance : instances ) { Cell* model = iInstance->getMasterCell(); Device* device = dynamic_cast(model); - cerr << "device:" << device << endl; if (device) { TransistorFamily* tf = dynamic_cast( device ); - cerr << "tf:" << tf << endl; if (tf) { _gridLabel[i+5]->setDynamicText ( QString("%1" ).arg( tf->getNfing() ) ); i++; diff --git a/hurricane/src/analog/MultiCapacitor.cpp b/hurricane/src/analog/MultiCapacitor.cpp index cce68e58..d271784e 100644 --- a/hurricane/src/analog/MultiCapacitor.cpp +++ b/hurricane/src/analog/MultiCapacitor.cpp @@ -90,7 +90,23 @@ namespace Analog { } } } - + + + unsigned int MultiCapacitor::getRestriction ( Net* net ) const + { + unsigned int ok = 0x1; + unsigned int yes = 0x2; + + unsigned int west = 0; + unsigned int east = 2; + unsigned int south = 4; + unsigned int north = 6; + unsigned int rule = 0; + + rule |= (ok << east) | (ok << west); + return rule; + } + Name MultiCapacitor::getDeviceName () const { return _capacitorName; } diff --git a/hurricane/src/analog/hurricane/analog/MultiCapacitor.h b/hurricane/src/analog/hurricane/analog/MultiCapacitor.h index 1ffe9c39..239ea00a 100644 --- a/hurricane/src/analog/hurricane/analog/MultiCapacitor.h +++ b/hurricane/src/analog/hurricane/analog/MultiCapacitor.h @@ -47,6 +47,7 @@ namespace Analog { , size_t ); virtual void _postCreate ( const Hurricane::Name& deviceName ); virtual void createConnections (); + virtual unsigned int getRestriction ( Hurricane::Net* ) const; public: virtual std::string _getTypeName () const; private: diff --git a/hurricane/src/hurricane/DataBase.cpp b/hurricane/src/hurricane/DataBase.cpp index 7c7c2e07..b77cb469 100644 --- a/hurricane/src/hurricane/DataBase.cpp +++ b/hurricane/src/hurricane/DataBase.cpp @@ -175,12 +175,13 @@ Record* DataBase::_getRecord() const { Record* record = Inherit::_getRecord(); if (record) { - record->add(getSlot("_technology" , _technology )); - record->add(getSlot("_rootLibrary" , _rootLibrary )); - record->add(getSlot("DbU::precision" , DbU::getPrecision())); - record->add(getSlot("DbU::resolution" , DbU::db(1) )); - record->add( DbU::getValueSlot("DbU::polygonStep", &DbU::_polygonStep )); - //record->add(getSlot("GridStep", getValueString(getGridStep()))); + record->add(getSlot("_technology" , _technology )); + record->add(getSlot("_rootLibrary" , _rootLibrary )); + record->add(getSlot("DbU::precision" , DbU::getPrecision() )); + record->add(getSlot("DbU::resolution" , DbU::db(1) )); + record->add(getSlot("DbU::getGridsPerLambda" , DbU::getGridsPerLambda())); + record->add( DbU::getValueSlot("DbU::polygonStep", &DbU::_polygonStep )); + //record->add(getSlot("GridStep", getValueString(getGridStep()))); } return record; } diff --git a/hurricane/src/hurricane/DbU.cpp b/hurricane/src/hurricane/DbU.cpp index 29e91517..55518464 100644 --- a/hurricane/src/hurricane/DbU.cpp +++ b/hurricane/src/hurricane/DbU.cpp @@ -201,8 +201,7 @@ namespace Hurricane { void DbU::setGridsPerLambda ( double gridsPerLambda, unsigned int flags ) { - if ( ( rint(gridsPerLambda) != gridsPerLambda ) - || ( remainder(gridsPerLambda,2.0) != 0.0 ) ) + if ((rint(gridsPerLambda) != gridsPerLambda) /*or (remainder(gridsPerLambda,2.0) != 0.0)*/) throw Error ( "DbU::Unit::setGridPerLambdas(): \"gridsPerLambda\" (%f) must be an even integer." , gridsPerLambda ); diff --git a/karakaze/python/AnalogDesign.py b/karakaze/python/AnalogDesign.py index b55bd167..7434d3f1 100644 --- a/karakaze/python/AnalogDesign.py +++ b/karakaze/python/AnalogDesign.py @@ -54,7 +54,7 @@ import Katana import Bora -helpers.setTraceLevel( 110 ) +#helpers.setTraceLevel( 110 ) NMOS = Transistor.NMOS @@ -264,7 +264,7 @@ class AnalogDesign ( object ): specSize = 0 if isderived(dspec[0],TransistorFamily): specSize = 12 - elif isderived(dspec[0], CapacitorFamily): specSize = 6 + elif isderived(dspec[0], CapacitorFamily): specSize = 7 elif isderived(dspec[0], ResistorFamily): specSize = 5 else: raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], has unsupported device type.' \ @@ -315,7 +315,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 == 6: + elif specSize == 7: 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) ]) @@ -361,7 +361,6 @@ class AnalogDesign ( object ): if not Cparameters: raise Error( 3, [ 'AnalogDesign.readParameters(): Missing parameters for capacity \"%s\".' % Cname ] ) continue - print dspec[5] dspec[4] = Cparameters.C * 1e+12 trace( 110, '\t- \"%s\" : C:%fpF\n' % (Cname ,dspec[4]) ) else: @@ -387,17 +386,24 @@ class AnalogDesign ( object ): self.checkDSpecDigital( count, dspec ) if isinstance( dspec[0], str ): masterCell = CRL.AllianceFramework.get().getCell( dspec[0], CRL.Catalog.State.Views ) - instance = Instance.create( self.cell, dspec[1], masterCell, Transformation() ) - instance.setPlacementStatus( Instance.PlacementStatus.UNPLACED ) + instance = Instance.create( self.cell + , dspec[1] + , masterCell + , Transformation() + , Instance.PlacementStatus.UNPLACED ) self.__dict__[ dspec[1] ] = instance else: masterCell = dspec[0] - instance = Instance.create( self.cell, dspec[1], masterCell, Transformation() ) - instance.setPlacementStatus( Instance.PlacementStatus.UNPLACED ) + instance = Instance.create( self.cell + , dspec[1] + , masterCell + , Transformation() + , Instance.PlacementStatus.UNPLACED ) self.__dict__[ dspec[1] ] = instance else: self.checkDSpec( count, dspec ) + trace( 110, '\t==============================================================\n' ) trace( 110, '\tBuilding \"%s\"\n' % dspec[1] ) if isderived(dspec[0],TransistorFamily): device = dspec[0].create( self.library, dspec[1], dspec[3], dspec[11] ) @@ -418,13 +424,13 @@ class AnalogDesign ( object ): if isinstance(dspec[4],float): capaValues = (dspec[4],) elif isinstance(dspec[4],tuple): capaValues = dspec[4] else: - raise ErrorMessage( 1, 'AnalogDesign.doDevice(): Invalid type for capacities values "%s".' \ - % str(dspec[4]) ) + raise ErrorMessage( 1, 'AnalogDesign.doDevice(): Invalid type for capacities values "%s".' \ + % str(dspec[4]) ) device = dspec[0].create( self.library, dspec[1], dspec[3], len(capaValues) ) device.getParameter( 'Layout Styles' ).setValue( dspec[2] ) - print device.getParameter( 'matrix' ) - device.getParameter( 'matrix' ).setMatrix( dspec[5] ) + device.getParameter( 'matrix' ).setMatrix( dspec[5] ) + device.setDummy( dspec[6] ) for i in range(len(capaValues)): device.getParameter( 'capacities' ).setValue( i, capaValues[i] ) @@ -614,7 +620,7 @@ class AnalogDesign ( object ): del self.stack[-1] return - def addDevice ( self, name, align, parameter, index=0 ): + def addDevice ( self, name, align, parameter=None, index=0 ): node = DSlicingNode.create( name, self.cell, parameter, self.rg ) node.setAlignment( align ) if index != 0: node.setBoxSetIndex( index ) diff --git a/karakaze/python/Oceane.py b/karakaze/python/Oceane.py index ab73f48d..56da7952 100644 --- a/karakaze/python/Oceane.py +++ b/karakaze/python/Oceane.py @@ -75,7 +75,7 @@ class Parameters ( object ): if self.capacitors.has_key(lname): print 'Duplicated capacitor "%s" (ignored).' % lname else: - print 'Add capacitor "%s"' % lname + #print 'Add capacitor "%s"' % lname self.capacitors[ lname ] = Parameters.Capacitor( lname ) self.capacitors[ lname ].C = value diff --git a/oroshi/python/CapacitorMatrix.py b/oroshi/python/CapacitorMatrix.py index b054c891..46388790 100644 --- a/oroshi/python/CapacitorMatrix.py +++ b/oroshi/python/CapacitorMatrix.py @@ -1,7 +1,5 @@ #!/usr/bin/python -print "SOURCE CapacitorMatrix" - import sys from Hurricane import * from CRL import * @@ -39,51 +37,60 @@ class CapacitorStack( CapacitorUnit ): # \param rowNumber Number of rows in the matrix of capacitors. # \param columnNumber Number of columns in the matrix of capacitors. - def __init__( self, device, capacitance, capacitorType, abutmentBoxPosition, nets, unitCap = 0, matrixDim = [1,1], matchingMode = False, matchingScheme = [], dummyRing = False, dummyElement = False ): - print 'CapacitorStack.__init__()' - print 'matrixDim:', matrixDim - - self.device = device - self.capacitorType = capacitorType + def __init__( self, device + , capacitance + , capacitorType + , abutmentBoxPosition + , nets + , unitCap = 0 + , matrixDim = [1,1] + , matchingMode = False + , matchingScheme = [] + , dummyRing = False + , dummyElement = False ): + self.device = device + self.capacitorType = capacitorType self.matrixDim = { "columns" : matrixDim[1], "rows" : matrixDim[0] } - self.unitCapDim = self.__computeCapDim__( unitCap , capacitorType ) + self.unitCapDim = self.__computeCapDim__( unitCap, capacitorType ) - self.doMatrix = False - self.abutmentBox = Box() + self.doMatrix = False + self.abutmentBox = Box() self.abutmentBoxPosition = { "XMin" : abutmentBoxPosition[0], "YMin" : abutmentBoxPosition[1] } - self.nets = nets - self.matchingMode = matchingMode - self.dummyRing = dummyRing - self.dummyElement = dummyElement + self.nets = nets + self.matchingMode = matchingMode + self.dummyRing = dummyRing + self.dummyElement = dummyElement - self.capacitorsNumber = len(capacitance) + self.capacitorsNumber = len(capacitance) - self.matchingScheme = matchingScheme - self.dummyRingPosition = {} - self.abutmentBox_spacing = 0 - self.vRoutingTrack_width = 0 + self.matchingScheme = matchingScheme + self.dummyRingPosition = {} + self.abutmentBox_spacing = 0 + self.vRoutingTrack_width = 0 - if self.__areInputDataOK__(capacitance) == True : - print 'Input data are OK' - if self.matchingMode == False : - self.compactCapDim = self.__computeCapDim__( capacitance[0] , capacitorType ) + if self.__areInputDataOK__(capacitance): + if not self.matchingMode: + self.compactCapDim = self.__computeCapDim__( capacitance[0] , capacitorType ) - if unitCap == 0 : - self.__initGivenZeroUnitCap__( capacitance[0] ) + if unitCap == 0: + self.__initGivenZeroUnitCap__( capacitance[0] ) + elif unitCap <> 0 and CapacitorUnit.__isCapacitorUnitOK__( self, self.unitCapDim ): + self.__initGivenNonZeroUnitCap__( capacitance[0], unitCap ) + else: + raise Error( 1, [ 'CapacitorStack.__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small.' + , '(width:{0} height:{1})'.format( DbU.getValueString(self.unitCapDim[width ]) + , DbU.getValueString(self.unitCapDim[height]) ) ] ) - elif unitCap <> 0 and CapacitorUnit.__isCapacitorUnitOK__( self, self.unitCapDim ) : - self.__initGivenNonZeroUnitCap__( capacitance[0], unitCap ) + else: + if unitCap == 0: + self.__initGivenZeroUnitCapInMatchingMode__( capacitance ) - else : raise Error( 1, '__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim ) - - else : - if unitCap == 0 : - self.__initGivenZeroUnitCapInMatchingMode__( capacitance ) - - elif unitCap <> 0 and CapacitorUnit.__isCapacitorUnitOK__( self, self.unitCapDim ) : - self.__initGivenNonZeroUnitCapInMatchingMode__( capacitance, unitCap ) - - else : raise Error( 1, '__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim ) + elif unitCap <> 0 and CapacitorUnit.__isCapacitorUnitOK__( self, self.unitCapDim ): + self.__initGivenNonZeroUnitCapInMatchingMode__( capacitance, unitCap ) + else: + raise Error( 1, [ 'CapacitorStack.__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small.' + , '(width:{0} height:{1})'.format( DbU.getValueString(self.unitCapDim[width ]) + , DbU.getValueString(self.unitCapDim[height]) ) ] ) return @@ -91,27 +98,20 @@ class CapacitorStack( CapacitorUnit ): def setRules( self ) : - CapacitorUnit.setRules ( self ) + CapacitorUnit.setRules( self ) - CapacitorUnit.__setattr__ ( self, "minWidth_vRoutingTrack" , CapacitorStack.rules.minWidth_metal3 ) - CapacitorUnit.__setattr__ ( self, "minSpacing_vRoutingTrack" , CapacitorStack.rules.minSpacingWide1_metal3 ) - - CapacitorUnit.__setattr__ ( self, "minWidth_vRoutingTrackCut" , CapacitorStack.rules.minWidth_cut2 ) - CapacitorUnit.__setattr__ ( self, "minSpacing_vRoutingTrackCut" , CapacitorStack.rules.minSpacing_cut2 ) - CapacitorUnit.__setattr__ ( self, "minEnclosure_vRoutingTrackCut" , CapacitorStack.rules.minEnclosure_metal3_cut2 ) + self.minWidth_vRoutingTrack = CapacitorStack.rules.minWidth_metal3 + self.minSpacing_vRoutingTrack = CapacitorStack.rules.minSpacingWide1_metal3 + self.minWidth_vRoutingTrackCut = CapacitorStack.rules.minWidth_cut2 + self.minSpacing_vRoutingTrackCut = CapacitorStack.rules.minSpacing_cut2 + self.minEnclosure_vRoutingTrackCut = CapacitorStack.rules.minEnclosure_metal3_cut2 if self.capacitorType == 'MIMCap': - - CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minWidth_cut2 ) - CapacitorUnit.__setattr__ ( self, "minEnclosure_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minEnclosure_metal2_cut2 ) - - elif self.capacitorType == 'PIPCap' : - - CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minWidth_cut1 ) - CapacitorUnit.__setattr__ ( self, "minEnclosure_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minEnclosure_metal2_cut1 ) - - - else: raise Error( 1, 'setRules() : Unsupported capacitor type : %s.' %self.capacitorType ) + self.minWidth_hRoutingLayer_topPlate_cut = CapacitorStack.rules.minWidth_cut2 + self.minEnclosure_hRoutingLayer_topPlate_cut = CapacitorStack.rules.minEnclosure_metal2_cut2 + elif self.capacitorType == 'PIPCap': + self.minWidth_hRoutingLayer_topPlate_cut = CapacitorStack.rules.minWidth_cut1 + self.minEnclosure_hRoutingLayer_topPlate_cut = CapacitorStack.rules.minEnclosure_metal2_cut1 return @@ -137,29 +137,24 @@ class CapacitorStack( CapacitorUnit ): def __initGivenZeroUnitCap__( self, capacitance ): - print '__initGivenZeroUnitCap__' - print self.matrixDim.values() - - if ( self.matrixDim.values() == [1,1] and CapacitorUnit.__isCapacitorUnitOK__(self, self.compactCapDim) ): - print 'Case 1' - [ self.capacitance , self.unitCapDim ] = [ capacitance , self.compactCapDim ] - - elif ( self.matrixDim.values() == [1,1] and not(CapacitorUnit.__isCapacitorUnitOK__( self, self.compactCapDim)) ): - raise Error(1, '__init__(): Impossible to draw the capacitor, dimensions are either too large or too small, "%s".' % self.compactCapDim ) #com2 : use to physical - - elif ( self.matrixDim["columns"]>1 or self.matrixDim["rows"]>1) : - unitCapacitance = capacitance / (self.matrixDim["columns"]*self.matrixDim["rows"]) - unitCapDim = self.__computeCapDim__( unitCapacitance, self.capacitorType ) - - if CapacitorUnit.__isCapacitorUnitOK__(self, unitCapDim) == True : - print 'This is a mutlicapacitor' - self.unitCapDim = unitCapDim - [ self.unitCapacitance , self.capacitance, self.doMatrix ] = [ unitCapacitance , capacitance, True ] - else: - print 'This is a capacitor unit' + if not self.matrixDim['columns']: + raise Error( 1, 'CapacitorStack.__initGivenZeroUnitCap__(): Requested matrix of *zero* columns.' ) + if not self.matrixDim['rows']: + raise Error( 1, 'CapacitorStack.__initGivenZeroUnitCap__(): Requested matrix of *zero* rows.' ) + if self.matrixDim.values() == [1,1]: + self.__isCapacitorUnitOK__( self.compactCapDim ) + self.capacitance = capacitance + self.unitCapDim = self.compactCapDim else: - raise Error( 1, '__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim ) #com2 : use to physical + unitCapacitance = capacitance / (self.matrixDim['columns'] * self.matrixDim['rows']) + unitCapDim = self.__computeCapDim__( unitCapacitance, self.capacitorType ) + + self.__isCapacitorUnitOK__( unitCapDim ) + self.unitCapDim = unitCapDim + self.unitCapacitance = unitCapacitance + self.capacitance = capacitance + self.doMatrix = True return @@ -188,7 +183,7 @@ class CapacitorStack( CapacitorUnit ): def __initGivenZeroUnitCapInMatchingMode__( self, capacitance ): - print '__initGivenZeroUnitCapInMatchingMode__' + #print '__initGivenZeroUnitCapInMatchingMode__' if self.matrixDim.values() == [1,1] or (self.matrixDim["columns"] == len(self.matchingScheme[0]) and self.matrixDim["rows"] == len(self.matchingScheme)) : @@ -245,10 +240,10 @@ class CapacitorStack( CapacitorUnit ): for k in range(0, self.capacitorsNumber): unitCapList.append( capacitance[k]/self.capacitorIdOccurence(k) ) - print self.capacitorsNumber - print 'capacitance', capacitance - print 'unitCapList', unitCapList - print '=============' + #print self.capacitorsNumber + #print 'capacitance', capacitance + #print 'unitCapList', unitCapList + #print '=============' return unitCapList @@ -289,7 +284,6 @@ class CapacitorStack( CapacitorUnit ): if ( True in comparaison ) and ( matchingSchemeDim != matrixDim ) : state = False - return state @@ -314,7 +308,10 @@ class CapacitorStack( CapacitorUnit ): [ matchingSchemeCapIds , capacitanceIds ] = [ list( numpy.unique(self.matchingScheme) ) , range(0,self.capacitorsNumber) ] if (self.matchingScheme != [] and set(matchingSchemeCapIds) == set(capacitanceIds) ) or (self.matchingScheme == [] and len(capacitance) == 1) : - if (len(self.nets) == self.capacitorsNumber + 1 and self.dummyElement == False and self.dummyRing == True ) or (len(self.nets) == self.capacitorsNumber and self.dummyElement == False and self.dummyRing == False) or (len(self.nets) == self.capacitorsNumber and self.dummyElement == True and self.dummyRing == True) or (len(self.nets) == self.capacitorsNumber and self.dummyElement == True and self.dummyRing == False ): + if (len(self.nets) == self.capacitorsNumber + 1 and self.dummyElement == False and self.dummyRing == True ) \ + or (len(self.nets) == self.capacitorsNumber and self.dummyElement == False and self.dummyRing == False) \ + or (len(self.nets) == self.capacitorsNumber and self.dummyElement == True and self.dummyRing == True ) \ + or (len(self.nets) == self.capacitorsNumber and self.dummyElement == True and self.dummyRing == False): if ( self.matchingMode == True and self.__isMatchingSchemeOK__() ) or ( self.matchingMode == False and self.matchingScheme == [] ): state = True diff --git a/oroshi/python/CapacitorRouted.py b/oroshi/python/CapacitorRouted.py index 6d0123d7..ae54799d 100644 --- a/oroshi/python/CapacitorRouted.py +++ b/oroshi/python/CapacitorRouted.py @@ -41,26 +41,51 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks # Position and dimensions attributes, also refered by layout variables, in Figure 2, are defined below : # \param device The Hurricane AMS device onto which the layout is drawn. # \param capacitorInstance Instance of \c CapacitorStack class. - # \param capacitor A nested list containing the matrix elements, which are \c CapacitorUnit objects. + # \param capacitor A nested list containing the matrix elements, which are \c CapacitorUnit objects. # \param matchingScheme A nested list, with equal dimensions as \c capacitor attribute, containing assignements of matrix elementary units to C1 and C2, identified by 1 and 2, respectively. Therefore, \c self.matchingScheme content is a succession of 1 and 2 values, defined as \ capacitor identifiers. For example, given a matrix of dimensions 2x2, the matching scheme can be \f$ [ [1,2], [1,2] ] or [ [2,1], [2,1] ] \f$. The first sub-list dictates that the first elementary capacitor, \f$ C_{00} \f$. The second element \f$ C_{01} \f$ is affected to C2 and so on. An immediate and obvious consequence to this, is that an error is raised if \c self.matchingSchem and \c self.capacitor dimensions are not identical or if \c self.matchingScheme content is different from supported capacitor identifiers, '1' and '2'. # # \param capacitorType Supported types of capacitors are MIM and PIP only. An exception is raised otherwise. - # \param abutmentBox The matrix's abutment box. + # \param abutmentBox The matrix's abutment box. # \param matrxiDim The matrix dimensions, also equal to \c self.matchingScheme nested list dimensions. - # \param abutmentBox_spacing The spacing between elementary units in the matrix. It is computed in \c CapacitorStack and is reloaded in \c RoutMatchedCapacitor. \c self.abutmentBox_spacing includes, vertical routing tracks width and minimum allowed spacing between two adjacent ones. + # \param abutmentBox_spacing The spacing between elementary units in the matrix. + # It is computed in \c CapacitorStack and is reloaded + # in \c RoutMatchedCapacitor. \c self.abutmentBox_spacing + # includes, vertical routing tracks width and minimum + # allowed spacing between two adjacent ones. # \param hRoutingLayer_width The width of horizontal routing layers in metal 2, which connect capacitors plates to vertical routing tracks. # \param vRoutingTrack_width The width of vertical routing tracks in metal 3, which connects identical nets together ( ie : bottom plates of C1, top plates of C2, bottom plates of C2 and top plates of C2 ). # \param hRoutingTrack_width The width of horizontal routing tracks in metal 2, which connect identical vertical routing tracks together. - # \param minSpacing_hRoutingTrack Minimum spacing between horizontal routing tracks. Wide metal 2 specifications are considered since metal 2 dimensions may exceed 10 \f$ m\f$. + # \param minSpacing_hRoutingTrack Minimum spacing between horizontal routing tracks. + # Wide metal 2 specifications are considered since metal 2 + # dimensions may exceed 10 \f$ m\f$. # - #\remark For more information about wide metal specifications, refer to ENG-183_rev8.pdf technology manual. + # \remark For more information about wide metal specifications, refer to ENG-183_rev8.pdf technology manual. # - # \param minimumPosition The ordinate of the top plate's routing layer's bottom extremity after stretching. - # \param maximumPosition The ordinate of the top plate's routing layer's top extremity, also equivalent to the top plate's top extremity. - # \param vRoutingTrackXCenter A nested list of ordered dictionaries, with dimensions equal to \c self.matrixDim, containing abcissas of vertical routing tracks. All sub-lists' lengths are identical and are equal to 2. The first and second elements describe position of top plate track and bottom plate track, respectively. For example, given a matrix of dimensions 2x2, \c self.vRoutingTrackXCenter can be [[0, 2], [4,6], [8,10]] \f$ \mu m\f$. Elements of this nested list have particular indexing as described in Figure 2. + # \param minimumPosition The ordinate of the top plate's routing layer's + # bottom extremity after stretching. + # \param maximumPosition The ordinate of the top plate's routing layer's + # top extremity, also equivalent to the top plate's + # top extremity. + # \param vRoutingTrackXCenter A nested list of ordered dictionaries, with dimensions + # equal to \c self.matrixDim, containing abcissas of vertical + # routing tracks. All sub-lists' lengths are identical and + # are equal to 2. The first and second elements describe + # position of top plate track and bottom plate track, + # respectively. For example, given a matrix of dimensions + # 2x2, \c self.vRoutingTrackXCenter can be + # [[0, 2], [4,6], [8,10]] \f$ \mu m\f$. + # Elements of this nested list have particular indexing as + # described in Figure 2. # - # \param hRoutingtrackYCenter A nested dicitonary containing two keys, \c topTracks and \c bottomTracks. Each key contains as value a dictionary describing centers' ordinates of four parallel horizontal tracks. The reason why four tracks are needed on top and bottom positions of the matrix is that four nets are used, two for every capacitor \c Ci, were \c i is in [1,2]. - # \param hRoutingLayerYCenter A nested dicitonary containing two keys, \c top and \c bottom. Each key contains as value a dictionary describing centers' ordinates of horizontal routing layers. + # \param hRoutingtrackYCenter A nested dictonary containing two keys, \c topTracks + # and \c bottomTracks. Each key contains as value a dictionary + # describing centers' ordinates of four parallel horizontal + # tracks. The reason why four tracks are needed on top and + # bottom positions of the matrix is that four nets are used, + # two for every capacitor \c Ci, were \c i is in [1,2]. + # \param hRoutingLayerYCenter A nested dicitonary containing two keys, \c top and + # \c bottom. Each key contains as value a dictionary + # describing centers' ordinates of horizontal routing layers. # \param vRoutingTrackDict A dictionary of routing tracks top and bottom extremities ordinates. # \param topPlateStretching Since not only the same metal 2 layer is used to draw top/bottom plates connections to vertical tracks but also the two plates are superimposed, the top plate's routing tracks is stretched. \c self.topPlateStretching is therefore the length added to top plate's routing layer in order to avoid short circuits between top and bottom plates routing to vertical tracks since the same metal is used for both. @@ -75,7 +100,7 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks self.capacitor.append(vRTInstance.capacitor[i][1:len(vRTInstance.capacitor[1])-1]) self.dummyRingCapacitor = [ vRTInstance.capacitor[0], vRTInstance.capacitor[-1] ] - self.dummyRingVRLayersDict = {} + #self.dummyRingVRLayersDict = {} self.hRoutingLayer_width = 0 self.hRoutingTrack_width = vRTInstance.hRoutingTrack_width @@ -92,7 +117,9 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks - ## Draws the complete layout given the capacitor matrix. \c route method is succession of calls to user-defined methods inside a newly created \c Updatesession. The following tasks are excecuted : + ## Draws the complete layout given the capacitor matrix. \c route method is succession + # of calls to user-defined methods inside a newly created \c Updatesession. + # The following tasks are excecuted : # -# A nex \c UpdateSession is created, # -# all required physical layers are loaded, # -# technology rules are defined according to capacitor type, @@ -102,33 +129,70 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks # -# all required cuts are drawn, # -# The \c UpdateSession is closed. # - # Meanwhile, an exception is raised when the entered \c capacitor is not a capacitor matrix or if the capacitor type is unsupported. + # Meanwhile, an exception is raised when the entered \c capacitor is not a + # capacitor matrix or if the capacitor type is unsupported. - def route( self, bbMode = False ): + def route( self, bbMode=False ): - UpdateSession.open () + UpdateSession.open() - self.setRules () + self.setRules() - if not( self.capacitorInstance.__isUnitCap__() ): + if not self.capacitorInstance.__isUnitCap__(): + if CapacitorStack.__isMatchingSchemeOK__(self): + layersDict = self.setLayers () + bondingBox = self.computeDimensions( bbMode ) - if CapacitorStack.__isMatchingSchemeOK__(self): + ab = self.device.getAbutmentBox() + trackNb = len(self.hRoutingtrackYCenter["topTracks"].keys()) + dY = self.hpitch * trackNb - layersDict = self.setLayers () - bondingBox = self.computeDimensions( bbMode ) + trace( 101, '\tHeight before tracks enclosure: {0}\n'.format( DbU.getValueString(self.maximumPosition - self.minimumPosition) )) + trace( 101, '\tHeight before tracks enclosure: {0}\n'.format( DbU.getValueString(ab.getHeight()) )) + trace( 101, '\tminimum before adjust: {0}\n'.format( DbU.getValueString(self.minimumPosition) )) + trace( 101, '\tdY: {0}\n'.format( DbU.getValueString(dY) )) - if not bbMode : + firstVRTId = "t0" + lastVRTId = self.vRoutingTrackXCenter[-1].keys()[-1] + if self.dummyRing: + xMin = self.abutmentBox.getXMin() + xMax = self.abutmentBox.getXMax() + else: + trackSpacing = (self.vRoutingTrack_width + self.vpitch + self.metal3Width)/2 + xMin = self.vRoutingTrackXCenter[ 0][firstVRTId] - trackSpacing + xMax = self.vRoutingTrackXCenter[-1][ lastVRTId] + trackSpacing - self.drawHRLayers ( layersDict["xPlateHRLayer" ] ) - self.drawHRoutingTracks ( layersDict["hRoutingTracks" ] ) - self.__stretchTopPlates__( self.capacitor , layersDict["xPlateRLayer" ] ) - self.drawCuts ( layersDict["cut_hRoutingLayer_vRoutingTracks"] , layersDict["cut_hRoutingTracks_vRoutingTracks"], layersDict["cut_hRoutingLayer_topPlate"] ) - if self.dummyRing == True: - self.routeDummyRing (layersDict ["xPlateVRLayer_dummyRing" ] , layersDict["cut_hRoutingTracks_vRoutingTracks"] ) + width = xMax - xMin + widthAdjust = width % (2*self.vpitch) + if widthAdjust: + widthAdjust = 2*self.vpitch - widthAdjust + xMax += widthAdjust/2 + xMin -= widthAdjust/2 + + self.device.setAbutmentBox( Box( xMin + , self.minimumPosition - dY + , xMax + , self.maximumPosition + dY ) ) + trace( 101, '\tHeight after tracks enclosure: {0}\n'.format( DbU.getValueString(self.device.getAbutmentBox().getHeight()) )) - else : raise Error( 1, 'drawHRLayers() : Invalid matching scheme : "%s".' % self.matchingScheme ) + if not bbMode : + self.drawHRLayers ( layersDict["xPlateHRLayer" ] ) + self.drawHRoutingTracks ( layersDict["hRoutingTracks"] ) + self.__stretchTopPlates__( self.capacitor + , layersDict["xPlateRLayer" ] ) + self.drawCuts ( layersDict["cut_hRoutingLayer_vRoutingTracks" ] + , layersDict["cut_hRoutingTracks_vRoutingTracks"] + , layersDict["cut_hRoutingLayer_topPlate" ] ) + if self.dummyRing: + self.routeDummyRing( layersDict ["xPlateVRLayer_dummyRing" ] + , layersDict["cut_hRoutingTracks_vRoutingTracks"] ) + else: + raise Error( 1, [ 'RouteMatchedCapacitor.route(): Invalid matching scheme.' + , '(${0})'.format( self.matchingScheme ) ] ) - else : raise Error( 1,'An input matrix is required.' % self.matrixDim ) + else: + raise Error( 1, [ 'RouteMatchedCapacitor.route(): Input matrix parameter is incorrect.' + , '({0})'.format( self.matrixDim ) ] ) UpdateSession.close () @@ -141,7 +205,7 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks net = self.nets[-1][1] bottomPlateRLayer_width = self.dummyRingCapacitor[0][0].getBotPlateRLayerWidth() topPlateRLayer_width = self.dummyRingCapacitor[0][0].getTopPlateRLayerWidth() - self.computeDummyRingDimensions () + #self.computeDummyRingDimensions () self.routeLeftAndRightSides (net, routingLayer, bottomPlateRLayer_width, topPlateRLayer_width ) self.routeTopOrBottomSide (net, "topSide" , routingLayer , bottomPlateRLayer_width, topPlateRLayer_width) self.routeTopOrBottomSide (net, "bottomSide" , routingLayer , bottomPlateRLayer_width, topPlateRLayer_width) @@ -155,14 +219,29 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks def routeLeftAndRightSides( self, dummyNet, routingLayer, bottomPlateRLayer_width, topPlateRLayer_width ) : for i in range(0,2): - bottomPlateLeftRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateLeftRLayerXCenter() - bottomPlateRightRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateRightRLayerXCenter() - Vertical.create ( dummyNet, routingLayer , bottomPlateLeftRLayerXCenter , bottomPlateRLayer_width , self.dummyRingVRLayersDict["YMin"] , self.dummyRingVRLayersDict["YMax"] ) - Vertical.create ( dummyNet, routingLayer , bottomPlateRightRLayerXCenter , bottomPlateRLayer_width , self.dummyRingVRLayersDict["YMin"] , self.dummyRingVRLayersDict["YMax"] ) - + bottomPlateLeftRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateLeftRLayerXCenter() + bottomPlateRightRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateRightRLayerXCenter() + Vertical.create( dummyNet + , routingLayer + , bottomPlateLeftRLayerXCenter + , bottomPlateRLayer_width + , self.getVTrackYMin() + , self.getVTrackYMax() ) + Vertical.create( dummyNet + , routingLayer + , bottomPlateRightRLayerXCenter + , bottomPlateRLayer_width + , self.getVTrackYMin() + , self.getVTrackYMax() ) + for i in range(0,2): - topPlateRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].topPlateRLayerDict["XCenter"] - Vertical.create ( dummyNet, routingLayer , topPlateRLayerXCenter , topPlateRLayer_width , self.dummyRingVRLayersDict["YMin"] , self.dummyRingVRLayersDict["YMax"] ) + topPlateRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].topPlateRLayerDict["XCenter"] + Vertical.create( dummyNet + , routingLayer + , topPlateRLayerXCenter + , topPlateRLayer_width + , self.getVTrackYMin() + , self.getVTrackYMax() ) return @@ -173,56 +252,71 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks if side == "topSide" : dummyRingElement = self.dummyRingCapacitor[-1] - dyTarget = self.vRoutingTrackDict ["YMax"] + dyTarget = self.getVTrackYMax() elif side == "bottomSide" : dummyRingElement = self.dummyRingCapacitor[0] - dyTarget = self.vRoutingTrackDict ["YMin"] + dyTarget = self.getVTrackYMin() else : raise Error(1,'routeTopOrBottomSide() : side parameter must be either "topSide" or "bottomSide" : %s' %side) for j in range(1,len(self.dummyRingCapacitor[0])-1): - bottomPlateLeftRLayerXCenter = dummyRingElement[j].getBotPlateLeftRLayerXCenter() - bottomPlateRightRLayerXCenter = dummyRingElement[j].getBotPlateRightRLayerXCenter() - Vertical.create ( dummyNet, routingLayer , bottomPlateLeftRLayerXCenter , bottomPlateRLayer_width , dummyRingElement[j].getBotPlateRLayerYMin() , dyTarget ) - Vertical.create ( dummyNet, routingLayer , bottomPlateRightRLayerXCenter , bottomPlateRLayer_width , dummyRingElement[j].getBotPlateRLayerYMin() , dyTarget ) + bottomPlateLeftRLayerXCenter = dummyRingElement[j].getBotPlateLeftRLayerXCenter() + bottomPlateRightRLayerXCenter = dummyRingElement[j].getBotPlateRightRLayerXCenter() + Vertical.create( dummyNet + , routingLayer + , bottomPlateLeftRLayerXCenter + , bottomPlateRLayer_width + , dummyRingElement[j].getBotPlateRLayerYMin() + , dyTarget ) + Vertical.create( dummyNet + , routingLayer + , bottomPlateRightRLayerXCenter + , bottomPlateRLayer_width + , dummyRingElement[j].getBotPlateRLayerYMin() + , dyTarget ) - topPlateRLayerXCenter = dummyRingElement[j].topPlateRLayerDict["XCenter"] - Vertical.create ( dummyNet, routingLayer , topPlateRLayerXCenter , topPlateRLayer_width , dummyRingElement[j].getTopPlateRLayerYMin() , dyTarget ) + topPlateRLayerXCenter = dummyRingElement[j].topPlateRLayerDict["XCenter"] + Vertical.create( dummyNet + , routingLayer + , topPlateRLayerXCenter + , topPlateRLayer_width + , dummyRingElement[j].getTopPlateRLayerYMin() + , dyTarget ) return - ## Defines technology rules used to draw the layout. Some of the rules, namely those describing routing layers and tracks are applicable for both MIM and PIP capacitors. However, cuts rules are different. \remark All \c CapacitorStack class rules are also reloaded in this class. An exception is raised if the entered capacitor type is unsupported. + ## Defines technology rules used to draw the layout. Some of the rules, + # namely those describing routing layers and tracks are applicable for + # both MIM and PIP capacitors. However, cuts rules are different. + # + # \remark All \c CapacitorStack class rules are also reloaded in this class. + # An exception is raised if the entered capacitor type is unsupported. + # # \return a dictionary with rules labels as keys and rules content as values. def setRules ( self ): - VerticalRoutingTracks.setRules ( self ) + VerticalRoutingTracks.setRules( self ) - CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingLayer" , RoutMatchedCapacitor.rules.minSpacing_metbot ) - CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingTrackCut" , RoutMatchedCapacitor.rules.minSpacing_cut2 ) - CapacitorUnit.__setattr__ ( self, "minSpacing_vRoutingTrackCut" , RoutMatchedCapacitor.rules.minSpacing_cut2 ) - CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingLayer_vRoutingTrack_cut" , RoutMatchedCapacitor.rules.minSpacing_cut2 ) + self.minSpacing_hRoutingLayer = RoutMatchedCapacitor.rules.minSpacing_metbot + self.minSpacing_hRoutingTrackCut = RoutMatchedCapacitor.rules.minSpacing_cut2 + self.minSpacing_vRoutingTrackCut = RoutMatchedCapacitor.rules.minSpacing_cut2 + self.minSpacing_hRoutingLayer_vRoutingTrack_cut = RoutMatchedCapacitor.rules.minSpacing_cut2 if self.capacitorType == 'MIMCap': - - CapacitorUnit.__setattr__( self, "minWidth_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minWidth_cut2 ) - CapacitorUnit.__setattr__( self, "minSpacing_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minSpacing_cut2 ) - CapacitorUnit.__setattr__( self, "minEnclosure_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minEnclosure_metal2_cut2 ) - - elif self.capacitorType == 'PIPCap' : - - CapacitorUnit.__setattr__( self, "minWidth_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minWidth_cut1 ) - CapacitorUnit.__setattr__( self, "minSpacing_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minSpacing_cut1 ) - CapacitorUnit.__setattr__( self, "minEnclosure_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minEnclosure_metal2_cut1 ) - - else: raise Error( 1, 'setRules() : Unsupported capacitor type : %s.' %self.capacitorType ) + self.minWidth_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minWidth_cut2 + self.minSpacing_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minSpacing_cut2 + self.minEnclosure_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minEnclosure_metal2_cut2 + elif self.capacitorType == 'PIPCap': + self.minWidth_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minWidth_cut1 + self.minSpacing_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minSpacing_cut1 + self.minEnclosure_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minEnclosure_metal2_cut1 return - ## Defines all physical layers used to draw the layout. Layers are loaded using \c DataBase API. The same routing layers are used for both capacitor types except cuts layers that connect top plates to vertical routing tracks. Basicaly, metal 2, meta 3, cut 1 and cut 2 are the ones defined. # \return a dictionary composed of layers labels as keys and layers as values. @@ -265,7 +359,7 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks translation2 = translation1 + self.vRoutingTrack_width/2 self.vRoutingTrackXCenter = self.vRTInstance.vRoutingTrackXCenter #getvRoutingTrackXCenter() - print("vRoutingTrackXCenter",self.vRoutingTrackXCenter) + #print("vRoutingTrackXCenter",self.vRoutingTrackXCenter) if bbMode == True : bondingBoxDimensions = self.computeBondingBoxDimInbbMode() @@ -275,7 +369,7 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks else :raise Error(1, 'computeDimensions(): The bonding box mode parameter, "bbMode" must be either True or False : %s.' %bbMode ) - print 'BOUNDING BOX:', bondingBoxDimensions + #print 'BOUNDING BOX:', bondingBoxDimensions return bondingBoxDimensions @@ -307,30 +401,38 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks return bondingBoxDimensions - ## Computes centers' ordinates of the eight horizontal routing tracks. The tracks include four on top and four on bottom of the matrix. To do the computations, fist, center of the first bottom or top track, given in Figure 2, is computed. Then, all adjacent three centers are deduced by simples translation of the first one. Translation quantity is equal to the sum of distance between adjacent routing tracks, self.hRoutingTracks_spacing, and half width of the routing track itself, \c self.hRoutingTrack_width. + ## Computes centers' ordinates of the eight horizontal routing tracks. + # The tracks include four on top and four on bottom of the matrix. + # To do the computations, fist, center of the first bottom or top track, + # given in Figure 2, is computed. Then, all adjacent three centers are + # deduced by simples translation of the first one. Translation quantity + # is equal to the sum of distance between adjacent routing tracks, + # self.hRoutingTracks_spacing, and half width of the routing track itself, + # \c self.hRoutingTrack_width. def computeHRoutingTrackYCenter( self ): self.hRoutingtrackYCenter = { "topTracks" : {} , "bottomTracks" : {} } - self.hRoutingtrackYCenter["topTracks" ]["t0"] = self.maximumPosition + self.hRoutingTrack_width/2 + self.minSpacing_hRoutingTrack - self.hRoutingtrackYCenter["bottomTracks" ]["t0"] = self.minimumPosition - self.hRoutingTrack_width/2 - self.minSpacing_hRoutingTrack - + #self.hRoutingtrackYCenter["topTracks" ]["t0"] = self.maximumPosition \ + # + self.hRoutingTrack_width/2 + self.minSpacing_hRoutingTrack + #self.hRoutingtrackYCenter["bottomTracks" ]["t0"] = self.minimumPosition \ + # - self.hRoutingTrack_width/2 - self.minSpacing_hRoutingTrack + self.hRoutingtrackYCenter["topTracks" ]["t0"] = self.maximumPosition + self.hRoutingtrackYCenter["bottomTracks" ]["t0"] = self.minimumPosition keys = self.__setPlatesIds__() - print("key",keys) - print(" self.capacitorsNumber", self.capacitorsNumber) -# limit = 2*self.capacitorsNumber if self.dummyRing == False else 2*self.capacitorsNumber + 1 for k in range(1, len(keys)): - print('keysk',keys[k]) - self.hRoutingtrackYCenter["topTracks" ][keys[k]] = self.hRoutingtrackYCenter["topTracks" ][keys[k-1]] + (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack) - self.hRoutingtrackYCenter["bottomTracks" ][keys[k]] = self.hRoutingtrackYCenter["bottomTracks"][keys[k-1]] - (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack) - print("keyskk",keys[k-1]) - print("self.hRoutingtrackYCenter",self.hRoutingtrackYCenter) -# if self.dummyRing == True : -# self.hRoutingtrackYCenter["topTracks" ]["gnd"] = self.hRoutingtrackYCenter["topTracks" ][keys[k]] + (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack) -# self.hRoutingtrackYCenter["bottomTracks" ]["gnd"] = self.hRoutingtrackYCenter["bottomTracks"][keys[k]] - (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack) - - print('self.hRoutingtrackYCenter',self.hRoutingtrackYCenter) + trace( 101, '\tkeys[{0}] = {1}\n'.format( k, keys[k] )) + #self.hRoutingtrackYCenter["topTracks"][keys[k]] \ + # = self.hRoutingtrackYCenter["topTracks"][keys[k-1]] \ + # + (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack) + #self.hRoutingtrackYCenter["bottomTracks" ][keys[k]] \ + # = self.hRoutingtrackYCenter["bottomTracks"][keys[k-1]] \ + # - (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack) + self.hRoutingtrackYCenter["topTracks"][keys[k]] \ + = self.hRoutingtrackYCenter["topTracks"][keys[k-1]] + self.hpitch + self.hRoutingtrackYCenter["bottomTracks" ][keys[k]] \ + = self.hRoutingtrackYCenter["bottomTracks"][keys[k-1]] - self.hpitch return @@ -341,11 +443,11 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks shortCircuitLists = self.__findPossibleShortCircuits__() self.topPlateStretching = self.__setStretching__( ) - print(' shortCircuitLists', shortCircuitLists) + #print(' shortCircuitLists', shortCircuitLists) for i in range( 0,self.matrixDim["rows"] ): - print("i",i) - print("rows", self.matrixDim["rows"]) - print("rowsCap", len(self.capacitor)) + #print("i",i) + #print("rows", self.matrixDim["rows"]) + #print("rowsCap", len(self.capacitor)) if shortCircuitLists[i][0] == 0 : self.hRoutingLayerYCenter["bottomPlate"].append( [self.capacitor[i][0].getBottomPlateRightCutYMax ()] ) @@ -367,7 +469,7 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks self.hRoutingLayerYCenter["bottomPlate"][i].append(bottomPlateYCenter) self.hRoutingLayerYCenter["topPlate" ][i].append(topPlateYCenter2) - print('self.hRoutingLayerYCenter',self.hRoutingLayerYCenter) + #print('self.hRoutingLayerYCenter',self.hRoutingLayerYCenter) return def computeLayoutDimensionsInbbMode( self ): @@ -383,36 +485,38 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks return bondingBoxDict - def computeDummyRingDimensions( self ): - - for key in self.vRoutingTrackDict.keys(): - self.dummyRingVRLayersDict[key] = self.vRoutingTrackDict[key] - return + #def computeDummyRingDimensions( self ): + # for key in self.vRoutingTrackDict.keys(): + # self.dummyRingVRLayersDict[key] = self.vRoutingTrackDict[key] + # return - - ## Iteratively draws horizontal routing tracks on top and bottom positions of the matrix using physical layer \c routingTracksLayer. + ## Iteratively draws horizontal routing tracks on top and bottom positions of the matrix + # using physical layer \c routingTracksLayer. def drawHRoutingTracks( self , routingTracksLayer ): lastVRTId = self.vRoutingTrackXCenter[-1].keys()[-1] firstVRTId = "t0" -# doDummyRing = 1 if self.dummyRing == True else 0 - dxSource = self.vRoutingTrackXCenter[0][firstVRTId] - self.vRoutingTrack_width/2 if self.dummyRing == False else self.abutmentBox.getXMin() - dxTarget = self.vRoutingTrackXCenter[-1][lastVRTId] + self.vRoutingTrack_width/2 if self.dummyRing == False else self.abutmentBox.getXMax() + #doDummyRing = 1 if self.dummyRing == True else 0 + #dxSource = self.vRoutingTrackXCenter[0][firstVRTId] - self.vRoutingTrack_width/2 if not self.dummyRing else self.abutmentBox.getXMin() + #dxTarget = self.vRoutingTrackXCenter[-1][lastVRTId] + self.vRoutingTrack_width/2 if not self.dummyRing else self.abutmentBox.getXMax() + dxSource = self.device.getAbutmentBox().getXMin() + dxTarget = self.device.getAbutmentBox().getXMax() for i in self.hRoutingtrackYCenter.keys(): - for j in self.hRoutingtrackYCenter[i].keys(): - if j[0] == 't' : - net = self.nets[ int(j[1]) ][0] - elif j[0] == 'b' : - net = self.nets[ int(j[1]) ][1] - else : - print("hi") - net = self.nets[-1][1] -# net = self.nets[ int(j[1]) ][0] if j[0] == 't' else self.nets[ int(j[1]) ][1] - print('net',net) - Horizontal.create ( net , routingTracksLayer, self.hRoutingtrackYCenter[i][j] , self.hRoutingTrack_width , dxSource , dxTarget ) + for j in self.hRoutingtrackYCenter[i].keys(): + if j[0] == 't' : net = self.nets[ int(j[1]) ][ 0 ] + elif j[0] == 'b' : net = self.nets[ int(j[1]) ][ 1 ] + else: net = self.nets[ -1 ][ 1 ] + + horizontal = Horizontal.create( net + , routingTracksLayer + , self.hRoutingtrackYCenter[i][j] + , self.hRoutingTrack_width + , dxSource + , dxTarget ) + NetExternalComponents.setExternal( horizontal ) return @@ -546,8 +650,8 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks netsDistribution = self.__setPlatesIds__() - print("netsDistribution2",netsDistribution) - print("self.hRoutingtrackYCenter",self.hRoutingtrackYCenter) + #print("netsDistribution2",netsDistribution) + #print("self.hRoutingtrackYCenter",self.hRoutingtrackYCenter) for j in range(0,len(dummyRingElement)): topPlateCutXCenter = dummyRingElement[j].getTopPlateRLayerXMin () + topPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2 bottomPlateLeftCutXCenter = dummyRingElement[j].getBottomPlateLeftCutXMin() #dummyRingElement[j].getBotPlateLeftRLayerXMin () + bottomPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2 @@ -561,7 +665,8 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks - ## Iteratively performs top plates stretching for the capacitor matrix. Vertical segments are connected to top plate routing layer. + ## Iteratively performs top plates stretching for the capacitor matrix. + # Vertical segments are connected to top plate routing layer. # \param capacitor Capacitor matrix. # \param rlayer Layer of the drawn vertical rectangle. def __stretchTopPlates__( self, capacitor, rlayer ): @@ -570,7 +675,7 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks for j in range( 0, self.matrixDim["columns"] ): t = self.nets[self.matchingScheme[i][j]][0] - print('t',t) + #print('t',t) self.__stretchTopPlateCompactCap__( t , capacitor[i][j], rlayer, j ) return @@ -584,8 +689,12 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks topPlateRLayerXCenter = capacitor.getTopPlateRLayerXCenter() [ dySource , dyTarget ] = self.__setStretchingDySourceDyTarget__( capacitor, self.topPlateStretching ) - Vertical.create ( net, routingLayer , topPlateRLayerXCenter , topPlateRLayer_width , dySource , dyTarget ) - + Vertical.create( net + , routingLayer + , topPlateRLayerXCenter + , topPlateRLayer_width + , dySource + , dyTarget ) return @@ -630,12 +739,12 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks dxDict["bottomPlate" ][ "source" ] = self.capacitor[i][j].getBotPlateLeftRLayerXMax () if self.matchingScheme[i][j] in leftVRTIds else self.capacitor[i][j].getBotPlateRightRLayerXMin () # bottomPlateLabel = 'b' if self.dummyElement == False or not( self.__isCapacitorAdummy__(capacitorIdentifier) ) else 't' - print("bottomPlateLabel",bottomPlateLabel) + #print("bottomPlateLabel",bottomPlateLabel) dxDict["bottomPlate" ][ "target" ] = self.__findHRLDyTrarget__( i, j, bottomPlateLabel, leftVRTIds, rightVRTIds ) else : raise Error(1, '__computeConnections__(): Unknown capacitor Id : %s.' %capacitorIdentifier ) - print('dxDict',dxDict) + #print('dxDict',dxDict) return dxDict @@ -703,7 +812,7 @@ class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks shortCircuitLists[i].append(0) for i in range(0, self.matrixDim["rows"]): for j in range(0, self.matrixDim["columns"]-1): - print('self.vRTsDistribution',self.vRTsDistribution) + #print('self.vRTsDistribution',self.vRTsDistribution) if self.matchingScheme[i][j] in self.vRTsDistribution[j+1] and self.matchingScheme[i][j+1] in self.vRTsDistribution[j+1] and self.matchingScheme[i][j] > self.matchingScheme[i][j+1] : shortCircuitLists[i][j] = 1 return shortCircuitLists @@ -763,16 +872,16 @@ def ScriptMain( **kw ): # capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, matrixDim = [5,5] , matchingMode = True, matchingScheme = [ ['C2','C1','C2','C3','C1'] , ['C1','C2','C4','C3','C2'] , ['C4','C2','C2','C3', 'C1'] , ['C1','C2','C2','C1', 'C1'], ['C2','C2','C3','C2','C4'] ] ) capacitor = capacitorInstance.create() - print('capa',capacitor) + #print('capa',capacitor) capWithVRT = VerticalRoutingTracks( capacitorInstance, capacitor, True ) capWithVRT.create() routedCap = RoutMatchedCapacitor( capWithVRT ) surface = routedCap.route() - print('routeMatchedCap bbMode', surface) - print('width', toPhY(surface["width"])) - print('height', toPhY(surface["height"])) + #print('routeMatchedCap bbMode', surface) + #print('width', toPhY(surface["width"])) + #print('height', toPhY(surface["height"])) AllianceFramework.get().saveCell( Device, Catalog.State.Views ) diff --git a/oroshi/python/CapacitorRoutedSingle.py b/oroshi/python/CapacitorRoutedSingle.py index 65cf0388..051600e0 100644 --- a/oroshi/python/CapacitorRoutedSingle.py +++ b/oroshi/python/CapacitorRoutedSingle.py @@ -1,7 +1,5 @@ #!/usr/bin/python -print "SOURCE RouteCapacitorSingle" - import sys import numpy from Hurricane import * @@ -14,7 +12,11 @@ import oroshi from CapacitorUnit import CapacitorUnit from CapacitorMatrix 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. + +## Route 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. # The dummyRing mode is not yet supported. @@ -26,31 +28,44 @@ def doBreak( level, message ): Breakpoint.stop( level, message ) UpdateSession.open() -helpers.staticInitialization( True ) -class RouteCapacitorSingle( CapacitorUnit ): +class RouteCapacitorSingle ( 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. + ## 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 are given in \c function. - def __init__( self, capacitorInstance, capacitor, dummyMode = False, tracksNumbers = [1,1], topPlateWSpec = [1,0] , bottomPlateWSpec = [0,1] ): + def __init__ ( self, capacitorInstance, capacitor, dummyMode = False, tracksNumbers = [1,1], topPlateWSpec = [1,0] , bottomPlateWSpec = [0,1] ): + + if capacitorInstance.matchingMode: + raise Error( 1, [ 'RouteCapacitorSingle.__init__(): This class is only dedicated to route matrices equivalent to one capacitor.' + , 'In case of a matched matrix of capacitors, please use .' ] ) - 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 @@ -101,68 +116,72 @@ class RouteCapacitorSingle( CapacitorUnit ): # - the capacitor type (ie., cuts2 if MIMCAP, cut1 if PIPCAP ) # - routing tracks layers according to the designer specifications. - def route( self, bbMode = False ): - - UpdateSession.open () + def route ( self, bbMode=False ): + UpdateSession.open() bondingBox = {} - self.setRules () - self.computeDimensions ( bbMode ) + self.setRules () + self.computeDimensions( bbMode ) if bbMode : - bondingBox = self.computeLayoutDimensionsInbbMode() + bondingBox = self.computeLayoutDimensionsInbbMode() if not bbMode: - routingTracksLayer = DataBase.getDB().getTechnology().getLayer("metal2") - bottomPlateRLayer = CapacitorUnit.getLayers( self )["bottomPlateRLayer"] - topPlateRLayer = bottomPlateRLayer + 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") + if self.capacitorType == 'MIMCap': + topbottomCutLayer = DataBase.getDB().getTechnology().getLayer("cut2") + elif self.capacitorType == 'PIPCap': + topbottomCutLayer = DataBase.getDB().getTechnology().getLayer("cut1") + else: + raise Error( 1, 'RouteCapacitorSingle.route(): Unsupported capacitor type "{0}".'.format( self.capacitorType )) - else : raise Error( 1,'route() : 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"] ) + ab = self.device.getAbutmentBox() + trace( 101, '\tAB before tracks: {0}\n'.format( ab )) + trace( 101, '\tBottom track numbers: {0}\n'.format( self.tracksNumbers['bottom'] )) + dyTop = self.tracksNumbers['top' ] * self.hpitch + dyBot = self.tracksNumbers['bottom'] * self.hpitch + self.device.setAbutmentBox( ab.inflate( 0, dyBot, 0, dyTop ) ) + trace( 101, '\tAB after tracks: {0}\n'.format( ab )) - 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 () + UpdateSession.close() return bondingBox - ## Builds and returns a dictionary of the needed technological rules to rout the capacitor. + ## Builds and returns a dictionary of the needed technological rules to route + # 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. + # 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 ) + self.minSpacing_routingTrackMetal = RouteCapacitorSingle.rules.minSpacing_metal2 - CapacitorUnit.setRules ( self ) - CapacitorUnit.__setattr__ ( self, "minSpacing_routingTrackMetal" , RouteCapacitorSingle.rules.minSpacing_metal2 ) - - if self.capacitorType == 'MIMCap' : - CapacitorUnit.__setattr__( self, "minHeight_routingTrackcut" , RouteCapacitorSingle.rules.minWidth_cut2 ) - CapacitorUnit.__setattr__( self, "minSpacing_routingTrackcut" , RouteCapacitorSingle.rules.minSpacing_cut2 ) - CapacitorUnit.__setattr__( self, "minWidth_routingTrackcut" , RouteCapacitorSingle.rules.minWidth_cut2 ) - - elif self.capacitorType == 'PIPCap' : - CapacitorUnit.__setattr__( self, "minHeight_routingTrackcut" , RouteCapacitorSingle.rules.minWidth_cut1 ) - CapacitorUnit.__setattr__( self, "minSpacing_routingTrackcut" , RouteCapacitorSingle.rules.minSpacing_cut1 ) - CapacitorUnit.__setattr__( self, "minWidth_routingTrackcut" , RouteCapacitorSingle.rules.minWidth_cut1 ) - - else : raise Error(1, 'setRules() : Unsupported capacitor type "%s".' % self.capacitorType ) + if self.capacitorType == 'MIMCap' : + self.minHeight_routingTrackcut = RouteCapacitorSingle.rules.minWidth_cut2 + self.minSpacing_routingTrackcut = RouteCapacitorSingle.rules.minSpacing_cut2 + self.minWidth_routingTrackcut = RouteCapacitorSingle.rules.minWidth_cut2 + elif self.capacitorType == 'PIPCap': + self.minHeight_routingTrackcut = RouteCapacitorSingle.rules.minWidth_cut1 + self.minSpacing_routingTrackcut = RouteCapacitorSingle.rules.minSpacing_cut1 + self.minWidth_routingTrackcut = RouteCapacitorSingle.rules.minWidth_cut1 return @@ -171,7 +190,8 @@ class RouteCapacitorSingle( CapacitorUnit ): # \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. + # \param possibleRoutingSchemes A list of the possible connections computed according + # to routing tracks specifications. def __isWiringSpecOK__ ( self, topPlateWiringSpec, bottomPlateWiringSpec, possibleRoutingSchemes ): @@ -231,31 +251,62 @@ class RouteCapacitorSingle( CapacitorUnit ): # - the routing tracks def computeDimensions( self, bbMode ): - self.computeRLayersDimensions ( bbMode ) - self.computeHRoutingTrackDimensions( ) + self.computeRLayersDimensions( bbMode ) + + routingTracksLayer = DataBase.getDB().getTechnology().getLayer("metal2") + bottomPlateRLayer = CapacitorUnit.getLayers( self )["bottomPlateRLayer"] + topPlateRLayer = bottomPlateRLayer + + ab = self.device.getAbutmentBox() + #plateSpacing1 = self.minSpacing_botPlate + #plateSpacing2 = self.hpitch - (self.metal2Width + self.routingTrack_width)/2 + #plateSpacing = max( plateSpacing1, plateSpacing2 ) + self.metal2Width/2 + plateSpacing = self.minSpacing_botPlate + self.metal2Width/2 + trace( 101, '\tAB height before plate inflate: {0}\n'.format( DbU.getValueString(ab.getHeight()) )) + trace( 101, '\tminSpacing_botPlate: {0}\n'.format( DbU.getValueString(self.minSpacing_botPlate) )) + trace( 101, '\tplateSpacing: {0}\n'.format( DbU.getValueString(plateSpacing) )) + ab.inflate( 0, plateSpacing ) + self.device.setAbutmentBox( ab ) + trace( 101, '\tAB height after plate inflate: {0} {1}\n'.format( DbU.getValueString(ab.getHeight()), ab.getHeight() )) + + height = ab.getHeight() + heightAdjust = height % (2*self.hpitch) + if heightAdjust: + trace( 101, '\tAB height before V-adjust: {0}\n'.format( DbU.getValueString(ab.getHeight()) )) + heightAdjust = 2*self.hpitch - heightAdjust + trace( 101, '\tAB height adjust: {0}\n'.format( DbU.getValueString(heightAdjust) )) + self.device.setAbutmentBox( ab.inflate( 0, heightAdjust/2 )) + trace( 101, '\tAB after V-adjust: {0}\n'.format( ab )) + trace( 101, '\tAB height after V-adjust: {0}\n'.format( DbU.getValueString(ab.getHeight()) )) + + width = ab.getWidth() + widthAdjust = width % (2*self.vpitch) + if widthAdjust: + widthAdjust = 2*self.vpitch - widthAdjust + self.device.setAbutmentBox( ab.inflate( widthAdjust/2, 0 )) + + self.abutmentBox = ab + self.computeHRoutingTrackDimensions() return - def computeRLayersDimensions( self, bbMode ): - - self.routingTrack_width = 2*self.minEnclo_routingTrackMetal_cut + self.minWidth_routingTrackcut + 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() + 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 ): - + def computeRLayersDimensionsCompactCap ( self ): self.bordersRLayerXMin = [ self.capacitor.getBottomPlateLeftCutXMin(), self.capacitor.getBottomPlateRightCutXMin() ] self.xPlateRLayer_width ["bottomBorders"] = self.capacitor.getBotPlateRLayerWidth () self.xPlateRLayer_width ["bottom" ] = [] @@ -263,13 +314,11 @@ class RouteCapacitorSingle( CapacitorUnit ): 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 : + 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() ] @@ -298,61 +347,91 @@ class RouteCapacitorSingle( CapacitorUnit ): ## Actual function that computes routing tracks dimensions and positions. def computeHRoutingTrackDimensions( self ): + trace( 101, ',+', '\tcomputeHRoutingTrackDimensions(): ab {0}\n'.format(self.device.getAbutmentBox()) ) - self.routingTracksXMinXMax = { "XMin" : self.abutmentBox.getXMin() , "XMax" : self.abutmentBox.getXMax() } + self.routingTracksXMinXMax = { "XMin" : self.abutmentBox.getXMin() + , "XMax" : self.abutmentBox.getXMax() } - if self.dummyMode == True: + if self.dummyMode: + if self.connectToTopTracksOnly(): + yTL = self.abutmentBox.getYMax() - 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} + self.routingTrackYCenter["top"]["lower"] = yTL - 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} + self.topLowerTrackDict = { "YMin" : yTL - self.routingTrack_width/2 + , "YMax" : yTL + self.routingTrack_width/2 } - else : + elif self.connectToBottomTracksOnly(): + yBU = self.abutmentBox.getYMin() - 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} + self.routingTrackYCenter["bottom"]["upper"] = yBU - elif self.dummyMode == False: + self.bottomUpperTrackDict = { "YMin" : yBU - self.routingTrack_width/2 + , "YMax" : yBU + self.routingTrack_width/2 } + else: + yTL = self.abutmentBox.getYMax() + yBU = self.abutmentBox.getYMin() - if self.connectToTopTracksOnly () : + self.routingTrackYCenter["top" ]["lower"] = yTL + self.routingTrackYCenter["bottom"]["upper"] = yBU - 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} + self.topLowerTrackDict = { "YMin" : yTL - self.routingTrack_width/2 + , "YMax" : yTL + self.routingTrack_width/2 } + self.bottomUpperTrackDict = { "YMin" : yBU - self.routingTrack_width/2 + , "YMax" : yBU + self.routingTrack_width/2 } - elif self.connectToBottomTracksOnly () : + else: + if self.connectToTopTracksOnly() : + yTL = self.abutmentBox.getYMax() + yTU = yTL + self.hpitch - 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} + self.routingTrackYCenter["top"]["lower"] = yTL + self.routingTrackYCenter["top"]["upper"] = yTU - elif self.connectToTopAndBottomTracks() : + self.topLowerTrackDict = { "YMin" : yTL - self.routingTrack_width/2 + , "YMax" : yTL + self.routingTrack_width/2 } + self.topUpperTrackDict = { "YMin" : yTU - self.routingTrack_width/2 + , "YMax" : yTU + self.routingTrack_width/2} - 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.connectToBottomTracksOnly(): + yBU = self.abutmentBox.getYMin() + yBL = yBU - self.hpitch - else : raise Error( 1, ' computeHRoutingTrackDimensions() : Wrong number or values for routing tracks, top : "%s", bottom : "%s". ' %(self.tracksNumbers["top"], self.tracksNumbers["bottom"]) ) + self.routingTrackYCenter["bottom"]["upper"] = yBU + self.routingTrackYCenter["bottom"]["lower"] = yBL - else : raise Error( 1, 'computeHRoutingTrackDimensions() : The dummy mode must be either "True" or "False", "%s". ' % self.dummyMode ) + self.bottomUpperTrackDict = { "YMin" : yBU - self.routingTrack_width/2 + , "YMax" : yBU + self.routingTrack_width/2 } + self.bottomLowerTrackDict = { "YMin" : yBL - self.routingTrack_width/2 + , "YMax" : yBL + self.routingTrack_width/2 } + elif self.connectToTopAndBottomTracks(): + yTL = self.abutmentBox.getYMax() + yBU = self.abutmentBox.getYMin() + + trace( 101, '\tyBU: {0}\n'.format( DbU.getValueString(yBU) )) + + self.routingTrackYCenter["top" ]["lower"] = yTL + self.routingTrackYCenter["bottom"]["upper"] = yBU + + self.topLowerTrackDict = { "YMin" : yTL - self.routingTrack_width/2 + , "YMax" : yTL + self.routingTrack_width/2 } + self.bottomUpperTrackDict = { "YMin" : yBU - self.routingTrack_width/2 + , "YMax" : yBU + self.routingTrack_width/2 } + + else: + raise Error( 1, [ 'RouteCapacitorSingle.computeHRoutingTrackDimensions(): Wrong number or values for routing tracks.' + , 'Top : {0}, bottom : {1}.'.format( self.tracksNumbers["top"], self.tracksNumbers["bottom"]) ] ) + + trace( 101, '-' ) return def computeLayoutDimensionsInbbMode( self ): - bondingBoxDict = {} - bondingBoxDict ["width" ] = self.routingTracksXMinXMax["XMax"] - self.routingTracksXMinXMax["XMin"] - bondingBoxDict["XMin" ] = self.routingTracksXMinXMax["XMin"] + bondingBoxDict = {} + bondingBoxDict["width" ] = self.routingTracksXMinXMax["XMax"] - self.routingTracksXMinXMax["XMin"] + bondingBoxDict["XMin" ] = self.routingTracksXMinXMax["XMin"] if self.dummyMode == True : @@ -404,31 +483,44 @@ class RouteCapacitorSingle( CapacitorUnit ): def drawTopOrBottomRoutingTracks ( self, tracksPosition, routingTracksLayer ) : - + trace( 101, ',+', '\tRouteCapacitorSingle.drawTopOrBottomRoutingTracks()\n' ) 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) - + attribut = [ "lower", "upper" ] + nets = self.__setNetsDistributionHRTs__() + for i in range( 0, self.tracksNumbers[tracksPosition] ): + index = i if tracksPosition == "top" else i-1 + netindex = i-1 if tracksPosition == "top" else i + trace( 101, '\ttrackPos={0}, index={1}, attribute={2}\n'.format( tracksPosition + , index + , attribut[index] )) + routingtrackYCenter = self.routingTrackYCenter[tracksPosition][attribut[index]] + horizontal = Horizontal.create( nets[netindex] + , routingTracksLayer + , routingtrackYCenter + , self.routingTrack_width + , self.routingTracksXMinXMax["XMin"] + , self.routingTracksXMinXMax["XMax"] ) + NetExternalComponents.setExternal( horizontal ) + trace( 101, '\t{0}\n'.format( horizontal )) + else: + raise Error( 1, 'RouteCapacitorSingle.drawOneRoutingTrack(): The track position must be either "top" or "bottom" ("{0}").'.format(tracksPosition)) + trace( 101, '-' ) 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 - + trace( 101, ',+', '\tRouteCapacitorSingle.__setNetsDistributionHRTs__()\n' ) + if self.dummyMode: + trace( 1010, '\tDummy mode\n' ) + netsDistribution = self.nets + else: + if (self.topPlateWSpec, self.bottomPlateWSpec) == ([1,0], [0,1]): + netsDistribution = self.nets + else: + netsDistribution = [ self.nets[1], self.nets[0] ] + trace( 101, '\tnetsDistribution = [ {0}, {1} ]\n'.format( netsDistribution[0].getName() + , netsDistribution[1].getName() )) + trace( 101, '-' ) return netsDistribution @@ -500,7 +592,7 @@ class RouteCapacitorSingle( CapacitorUnit ): - ## 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. + ## 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. @@ -518,7 +610,7 @@ class RouteCapacitorSingle( CapacitorUnit ): if not( self.capacitorInstance.__isUnitCap__() ) or ( self.capacitorInstance.__isUnitCap__() and doTop ) : - print("xPlateRLayer_width",xPlateRLayer_width) + #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 diff --git a/oroshi/python/CapacitorUnit.py b/oroshi/python/CapacitorUnit.py index e6880ceb..258cc86f 100644 --- a/oroshi/python/CapacitorUnit.py +++ b/oroshi/python/CapacitorUnit.py @@ -4,21 +4,21 @@ import sys import numpy from Hurricane import * from CRL import * +import Constant from math import sqrt, ceil import helpers from helpers.io import ErrorMessage as Error from helpers import trace import oroshi -def toDbU ( l ): return DbU.fromPhysical( l, DbU.UnitPowerMicro ) -def toPhY ( l ): return DbU.toPhysical ( l, DbU.UnitPowerMicro ) +def toDbU ( l ): return DbU.fromPhysical( l, DbU.UnitPowerMicro ) +def toPhY ( l ): return DbU.toPhysical ( l, DbU.UnitPowerMicro ) def doBreak( level, message ): UpdateSession.close() Breakpoint.stop( level, message ) UpdateSession.open() -helpers.staticInitialization( True ) ## Draws a capacitor of type Poly-Poly or Metal-Metal in 350 nm AMS CMOS technology. # PIP and MIM capacitors are the result of surface superposition between poly1 and poly2 or metal2 and metalcap layers, respectively. @@ -31,8 +31,6 @@ class CapacitorUnit(): rules = oroshi.getRules() - - ## This is the class constructor. Few of the class attributes final values are computed in this level. Most of attributes are only initialized to zero or empty values. Then, it is computed in dedicated class method. Input parameters are : # \param device Hurricane AMS device into which layout is drawn. # \param capacitance Capacitor value, expressed in \f$ femto Farad (fF) \f$. @@ -67,7 +65,7 @@ class CapacitorUnit(): self.device = device self.capacitorType = capacitorType -# self.capDim = self.__computeCapDim__( capacitance, capacitorType ) +# self.capDim = self.__computeCapDim__( capacitance, capacitorType ) self.enclosure_botPlate_abtBox = 0 self.__initCapDim__( capacitance, capDim ) @@ -97,25 +95,20 @@ class CapacitorUnit(): def __initCapDim__( self, capacitance, capDim ): - - if capacitance != 0 and capDim.values() != [] : - if self.__computeCapacitance__( capDim, self.capacitorType ) == capacitance : - self.capDim = capDim - else : raise Error(1,'__initCapDim__() : Please check compatibility between capacitance value, %s, and the given capacitor dimensions, %s.' %(capacitance, capDim)) - - elif capacitance == 0 and capDim.values() != [] : - self.capDim = capDim - capacitance = self.__computeCapacitance__( capDim, self.capacitorType ) - print("capacitance", capacitance) - + if capacitance != 0 and capDim.values() != []: + if self.__computeCapacitance__( capDim, self.capacitorType ) == capacitance : + self.capDim = capDim + else: + raise Error( 1, [ 'CapacitorUnit.__initCapDim__(): Please check compatibility between capacitance value {0},'.format(capacitance) + , 'and the given capacitor dimensions {0}.'.format(capDim) ] ) + elif capacitance == 0 and capDim.values() != []: + self.capDim = capDim + capacitance = self.__computeCapacitance__( capDim, self.capacitorType ) elif capacitance != 0 and capDim.values() == [] : - print("self.capacitorType ",self.capacitorType ) - self.capDim = self.__computeCapDim__( capacitance, self.capacitorType ) - print("self.capDim",self.capDim) - - else : raise Error(1, '__initCapDim__() : Invalid capacitance and/or capacitance dimensions (%s, %s). Please provide at least one valid parameter.' - %(capacitance, capDim)) - + self.capDim = self.__computeCapDim__( capacitance, self.capacitorType ) + else: + raise Error( 1, [ 'CapacitorUnit.__initCapDim__(): Invalid capacitance and/or capacitance dimensions {0}, {1}.'.format(capacitance, capDim) + , 'Please provide at least one valid parameter.' ] ) return @@ -124,7 +117,7 @@ class CapacitorUnit(): # \remarks An exception is raised if the entered capacitor type is unknown. def __setCapacitorPerUnit__( self, capacitorType ) : - print("self.capacitorType",self.capacitorType) + #print("self.capacitorType",self.capacitorType) if capacitorType == 'MIMCap': [ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = [ CapacitorUnit.rules.MIMCap , CapacitorUnit.rules.MIMPerimeterCap @@ -141,21 +134,30 @@ class CapacitorUnit(): return [ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] - ## Computes width and length of the capacitor. Given \c capacitance value as well as the permiter and area capacitances, a quadratic equation is solved where the unknown parameter is the width ( also equivalent to the length ). - # \return a dictionary containing width and length. - # \remark The capacitor is square. Thus, length and width are equal. + ## Computes width and length of the capacitor. Given \c capacitance value as well as + # the permiter and area capacitances, a quadratic equation is solved where the + # unknown parameter is the width (also equivalent to the length). + # \return a dictionary containing width and length. + # \remark The capacitor is square. Thus, length and width are equal. def __computeCapDim__( self, capacitance, capacitorType ) : - print("capacitorType",capacitorType) - [a, b, c ] = [ self.__setCapacitorPerUnit__( capacitorType )[0] - , 4*self.__setCapacitorPerUnit__( capacitorType )[1] - , - capacitance - ] + trace( 101, ',+', '\tCapacitorUnit.__computeCapDim__()\n' ) + + [a, b, c] = [ self.__setCapacitorPerUnit__( capacitorType )[0] + , 4 * self.__setCapacitorPerUnit__( capacitorType )[1] + , - capacitance + ] delta = (b**2) - 4*a*c - c1 = ( -b + sqrt(delta) ) / (2*a) + c1 = ( -b + sqrt(delta) ) / (2*a) - return { "width" : toDbU(c1), "height" : toDbU(c1) } + twoGrid = DbU.fromGrid( 2.0 ) + trace( 101, '\tc1 = {0}, 2*Grid Unit = {1}\n'.format( c1, twoGrid )) + c1 = toDbU( c1 ) + c1 = c1 + (twoGrid - (c1 % twoGrid)) + + trace( 101, '-' ) + return { "width" : c1, "height" : c1 } def __computeCapacitance__( self, capDim, capacitorType ): @@ -173,33 +175,48 @@ class CapacitorUnit(): # \remark Maximum poly2 layer dimensions for PIP capacitor are not specified in technology rules. Thus, only minimum limit condition is checked. def __isCapacitorUnitOK__( self, capDim ): + errors = [] + capaName = 'PIP' + minSide = self.getMinimumCapWidth() + maxSide = None + if self.capacitorType == 'MIMCap': + capaName = 'MIM' + maxSide = self.getMaximumCapWidth() - print 'capDim:', DbU.getValueString(capDim['width']), DbU.getValueString(capDim['height']) - print 'min / max:', DbU.getValueString(self.getMinimumCapWidth() ), DbU.getValueString(self.getMaximumCapWidth() ) + trace( 101, '\tcapDim = [ {0}, {1} ]\n'.format( DbU.getValueString(capDim['width' ]) + , DbU.getValueString(capDim['height']) )) + trace( 101, '\tCapacity type: {0}\n'.format( capaName )) + trace( 101, '\t* Minimum side: {0}\n'.format( DbU.getValueString(minSide) )) + if maxSide: trace( 101, '\t* Maximum side: {0}\n'.format( DbU.getValueString(maxSide) )) + else: trace( 101, '\t* Maximum side: N/A\n' ) - state = False - if ( self.capacitorType == 'MIMCap' \ - and CapacitorUnit.getMinimumCapWidth(self) < capDim["width" ] < self.getMaximumCapWidth() \ - and CapacitorUnit.getMinimumCapWidth(self) < capDim["height"] < self.getMaximumCapWidth() ) \ - or ( self.capacitorType == 'PIPCap' \ - and self.getMinimumCapWidth() < capDim["width" ] \ - and self.getMinimumCapWidth() < capDim["height"] ): - state = True - - print '__isCapacitorUnitOK__:', state - return state - + if capDim['width' ] < minSide: + errors.append( '* Width {0} too small, minimum size for {2} capacitors is {1}.' \ + .format( DbU.getValueString(capDim['width']) + , DbU.getValueString(minSide ) + , capaName ) ) + if maxSide and capDim['width' ] > maxSide: + errors.append( '* Width {0} too big, maximum size for {2} capacitors is {1}.' \ + .format( DbU.getValueString(capDim['width']) + , DbU.getValueString(maxSide ) + , capaName ) ) + if capDim['height' ] < minSide: + errors.append( '* Height {0} too small, minimum size for {2} capacitors is {1}.' \ + .format( DbU.getValueString(capDim['height']) + , DbU.getValueString(minSide ) + , capaName ) ) + if maxSide and capDim['height' ] > maxSide: + errors.append( '* Height {0} too big, maximum size for {2} capacitors is {1}.' \ + .format( DbU.getValueString(capDim['height']) + , DbU.getValueString(maxSide ) + , capaName ) ) + if errors: + errors.insert( 0, 'CapacitorUnit.__isCapacitorUnitOK__():' ) + raise Error( 1, errors ) - ## Redefines technological rules as object attributes of the class. For example, class attributes \c CapacitorUnit.rules.minWidth_metcap becomes \c self.minWidth_topPlate and \c CapacitorUnit.rules.minSpacing_cut2_metcap becomes \c self.minSpacing_botPlateCut_topPlat. This obviously helps using shorter names for the attributes. \c __setattr__() is declared in all \c Capacitor \c Generator classes, also in Hurricane and oroshi databases. - - def __setattr__( self, attribute, value ) : - - self.__dict__[attribute] = value - - return - + return True ## Selects technological rules according to the capacitor type. @@ -208,58 +225,78 @@ class CapacitorUnit(): # - minimum spacing between cuts or metals, # - minimum width of a plate, a cut or a routing metal. # - etc. - # Every rule takes two possible value according to the capacitor type (MIM or PIP). Therefore, dictionary keys are generic and its values are specific to the capacitor type. + # Every rule takes two possible value according to the capacitor type (MIM or PIP). + # Therefore, dictionary keys are generic and its values are specific to the capacitor + # type. # \remark An exception is raised if the entered capacitor type is unknown. def setRules ( self ): - if self.capacitorType == 'MIMCap': + self.minWidth_topPlate = CapacitorUnit.rules.minWidth_metcap + self.minWidth_botRMetal = CapacitorUnit.rules.minWidth_metal3 + self.minWidth_topRMetal = CapacitorUnit.rules.minWidth_metal1 + self.minWidth_topPlatecut = CapacitorUnit.rules.minWidth_cut2 + self.minWidth_botPlatecut = CapacitorUnit.rules.minWidth_cut2 + self.minWidth_routingTrackcut = CapacitorUnit.rules.minWidth_cut2 - self.__setattr__( "minWidth_topPlate" , CapacitorUnit.rules.minWidth_metcap ) - self.__setattr__( "minWidth_botRMetal" , CapacitorUnit.rules.minWidth_metal3 ) - self.__setattr__( "minWidth_topRMetal" , CapacitorUnit.rules.minWidth_metal1 ) - self.__setattr__( "minWidth_topPlatecut" , CapacitorUnit.rules.minWidth_cut2 ) - self.__setattr__( "minWidth_botPlatecut" , CapacitorUnit.rules.minWidth_cut2 ) - self.__setattr__( "minWidth_routingTrackcut" , CapacitorUnit.rules.minWidth_cut2 ) + self.minSpacing_botPlate = CapacitorUnit.rules.minSpacing_metbot + self.minSpacing_botPlateCut_topPlate = CapacitorUnit.rules.minSpacing_cut2_metcap + self.minSpacingOnBotPlate_cut = CapacitorUnit.rules.minSpacingOnMetBot_cut2 + self.minSpacingOnTopPlate_cut = CapacitorUnit.rules.minSpacingOnMetCap_cut2 - self.__setattr__( "minSpacing_botPlate" , CapacitorUnit.rules.minSpacing_metbot ) - self.__setattr__( "minSpacing_botPlateCut_topPlate" , CapacitorUnit.rules.minSpacing_cut2_metcap ) - self.__setattr__( "minSpacingOnBotPlate_cut" , CapacitorUnit.rules.minSpacingOnMetBot_cut2 ) - self.__setattr__( "minSpacingOnTopPlate_cut" , CapacitorUnit.rules.minSpacingOnMetCap_cut2 ) - - self.__setattr__( "minEnclo_botPlate_botPlateCut" , CapacitorUnit.rules.minEnclosure_metbot_cut2 ) - self.__setattr__( "minEnclo_topPlate_topPlateCut" , CapacitorUnit.rules.minEnclosure_metcap_cut2 ) - self.__setattr__( "minEnclo_topPlateRMetal_topPlateCut" , CapacitorUnit.rules.minEnclosure_metal3_cut2 ) - self.__setattr__( "minEnclo_botPlateRMetal_botPlateCut" , CapacitorUnit.rules.minEnclosure_metal3_cut2 ) - self.__setattr__( "minEnclo_routingTrackMetal_cut" , CapacitorUnit.rules.minEnclosure_metal3_cut2 ) - + self.minEnclo_botPlate_botPlateCut = CapacitorUnit.rules.minEnclosure_metbot_cut2 + self.minEnclo_topPlate_topPlateCut = CapacitorUnit.rules.minEnclosure_metcap_cut2 + self.minEnclo_topPlateRMetal_topPlateCut = CapacitorUnit.rules.minEnclosure_metal3_cut2 + self.minEnclo_botPlateRMetal_botPlateCut = CapacitorUnit.rules.minEnclosure_metal3_cut2 + self.minEnclo_routingTrackMetal_cut = CapacitorUnit.rules.minEnclosure_metal3_cut2 elif self.capacitorType == 'PIPCap': + self.minWidth_topPlate = CapacitorUnit.rules.minWidth_cpoly + self.minWidth_botRMetal = CapacitorUnit.rules.minWidth_metal1 + self.minWidth_topRMetal = CapacitorUnit.rules.minWidth_metal1 + self.minWidth_topPlatecut = CapacitorUnit.rules.minWidth_cut0 + self.minWidth_botPlatecut = CapacitorUnit.rules.minWidth_cut0 + self.minWidth_routingTrackcut = CapacitorUnit.rules.minWidth_cut1 - self.__setattr__( "minWidth_topPlate" , CapacitorUnit.rules.minWidth_cpoly ) - self.__setattr__( "minWidth_botRMetal" , CapacitorUnit.rules.minWidth_metal1 ) - self.__setattr__( "minWidth_topRMetal" , CapacitorUnit.rules.minWidth_metal1 ) - self.__setattr__( "minWidth_topPlatecut" , CapacitorUnit.rules.minWidth_cut0 ) - self.__setattr__( "minWidth_botPlatecut" , CapacitorUnit.rules.minWidth_cut0 ) - self.__setattr__( "minWidth_routingTrackcut" , CapacitorUnit.rules.minWidth_cut1 ) + self.minSpacing_botPlate = CapacitorUnit.rules.minSpacing_poly + self.minSpacing_botPlateCut_topPlate = CapacitorUnit.rules.minSpacing_cut0_cpoly + self.minSpacingOnBotPlate_cut = CapacitorUnit.rules.minSpacing_cut0 + self.minSpacingOnTopPlate_cut = CapacitorUnit.rules.minSpacing_cut0 - self.__setattr__( "minSpacing_botPlate" , CapacitorUnit.rules.minSpacing_poly ) - self.__setattr__( "minSpacing_botPlateCut_topPlate" , CapacitorUnit.rules.minSpacing_cut0_cpoly ) - self.__setattr__( "minSpacingOnBotPlate_cut" , CapacitorUnit.rules.minSpacing_cut0 ) - self.__setattr__( "minSpacingOnTopPlate_cut" , CapacitorUnit.rules.minSpacing_cut0 ) - - self.__setattr__( "minEnclo_botPlate_botPlateCut" , CapacitorUnit.rules.minEnclosure_poly_cut0 ) - self.__setattr__( "minEnclo_topPlate_topPlateCut" , CapacitorUnit.rules.minEnclosure_cpoly_cut0 ) - self.__setattr__( "minEnclo_topPlateRMetal_topPlateCut" , CapacitorUnit.rules.minEnclosure_metal1_cut1 ) - self.__setattr__( "minEnclo_botPlateRMetal_botPlateCut" , CapacitorUnit.rules.minEnclosure_metal1_cut0 ) - self.__setattr__( "minEnclo_routingTrackMetal_cut" , CapacitorUnit.rules.minEnclosure_metal1_cut1 ) - - else : - raise Error( 1, 'setRules() : Unsupported capacitor type : %s.' % self.capacitorType ) + self.minEnclo_botPlate_botPlateCut = CapacitorUnit.rules.minEnclosure_poly_cut0 + self.minEnclo_topPlate_topPlateCut = CapacitorUnit.rules.minEnclosure_cpoly_cut0 + self.minEnclo_topPlateRMetal_topPlateCut = CapacitorUnit.rules.minEnclosure_metal1_cut1 + self.minEnclo_botPlateRMetal_botPlateCut = CapacitorUnit.rules.minEnclosure_metal1_cut0 + self.minEnclo_routingTrackMetal_cut = CapacitorUnit.rules.minEnclosure_metal1_cut1 + else: + raise Error( 1, 'CapacitorUnit.setRules(): Unsupported capacitor type {0}.'.format( self.capacitorType )) self.minheight_topPlatecut = self.minWidth_topPlatecut - return + # Get the METAL 2/3 layers. + metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' ) + 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() == metal2.getMask(): self.metal2Width = rlg.getWireWidth() + if rlg.getLayer().getMask() == metal3.getMask(): self.metal3Width = rlg.getWireWidth() + if rlg.getType() == Constant.PinOnly: continue + if rlg.getDirection() == Constant.Horizontal and not foundHor: + self.hpitch = rlg.getPitch() + foundHor = True + if rlg.getDirection() == Constant.Vertical and not foundVer: + self.vpitch = rlg.getPitch() + foundVer = True + + return ## \return capacitor type \c 'MIMCap' or \c 'PIPCap'. @@ -577,8 +614,7 @@ class CapacitorUnit(): , boxDimensions["XMin"] + boxDimensions["width" ] , boxDimensions["YMin"] + boxDimensions["height"] ) - platePad = Pad.create( net, layer, outputPlateBox ) - NetExternalComponents.setExternal( platePad ) + platePad = Pad.create( net, layer, outputPlateBox ) return outputPlateBox @@ -818,7 +854,7 @@ def ScriptMain( **kw ): capacitor = CapacitorUnit ( device, 'MIMCap', [0,0], capacitance = 129.56) # square: capacitance : 129.56 , capDim = {"width" : 39650L , "height" : 39650L } # rectangular capDim = {"width" : 78919L , "height" : 118378L } abutmentBoxDim = capacitor.create( b, t, bbMode = True, vEnclosure_botPlate_abtBox = 1.5, hEnclosure_botPlate_abtBox = 0.9) - print(abutmentBoxDim) + #print(abutmentBoxDim) AllianceFramework.get().saveCell( device, Catalog.State.Views ) diff --git a/oroshi/python/CapacitorVRTracks.py b/oroshi/python/CapacitorVRTracks.py index 6775d230..494e1042 100644 --- a/oroshi/python/CapacitorVRTracks.py +++ b/oroshi/python/CapacitorVRTracks.py @@ -12,12 +12,33 @@ from collections import OrderedDict import numpy -## Routs two matched capacitors, C1 and C2, drawn in a capacitor matrix. Connections are put in place with reference to a given matching scheme. Elementary capacitor units are connected to horizontal and vertical routeing tracks that represent top plates and bottom plates nets of C1 and C2 . Supported types of capacitors are Poly-Poly and Metal-Metal. Technologycal rules are provided by 350 nm AMS CMOS technology with three-four metal layers. Metal layers that are used for routeing are placed similarly to horziontal-vertical (HV) symbolic Alliance CAD tool routeer, where horizontal metal channels are drawn in metal 2 and the vertical ones are in metal 3. Given a matrix of dimensions \f$ R*C \f$, the total number of vertical tracks is \f$ 2C+2 \f$ equivalent to \f$ C+1 \f$ couples, ensuring that every elementary capacitor is positioned between four vertical tracks, two from each side. In fact, every adjacent couple of these tracks represent top plates and bottom plates of C1 or C2 as shown in Figure 1. +## Route two matched capacitors, C1 and C2, drawn in a capacitor matrix. +# Connections are put in place with reference to a given matching scheme. +# Elementary capacitor units are connected to horizontal and vertical routing +# tracks that represent top plates and bottom plates nets of C1 and C2. +# Supported types of capacitors are Poly-Poly and Metal-Metal. +# Technologycal rules are provided by 350 nm AMS CMOS technology with +# three-four metal layers. Metal layers that are used for routeing are +# placed similarly to horziontal-vertical (HV) symbolic Alliance CAD tool router, +# where horizontal metal channels are drawn in metal 2 and the vertical ones are +# in metal 3. Given a matrix of dimensions \f$ R*C \f$, the total number of +# vertical tracks is \f$ 2C+2 \f$ equivalent to \f$ C+1 \f$ couples, +# ensuring that every elementary capacitor is positioned between four +# vertical tracks, two from each side. In fact, every adjacent couple of these +# tracks represent top plates and bottom plates of C1 or C2 as shown in Figure 1. +# # \image html Layout.png "Layout" width=.1\linewidth -# An elementary capacitor unit can be a part of C1 or C2 according to the matching scheme. However, to respect common-centroid layout specifications, for C1 and C2 to be equal, the matrix number of colums and number of rows must be both even. Addionnally, the number of elementary capacitors dedicated to C1 must be equal to those dedicated to C2. These two conditions are tested in one of the class methods. An exception is raised if at least one of the two is not respected. +# +# An elementary capacitor unit can be a part of C1 or C2 according to the +# matching scheme. However, to respect common-centroid layout specifications, +# for C1 and C2 to be equal, the matrix number of colums and number of rows +# must be both even. Addionnally, the number of elementary capacitors dedicated +# to C1 must be equal to those dedicated to C2. These two conditions are tested +# in one of the class methods. An exception is raised if at least one of the two +# is not respected. -class VerticalRoutingTracks( CapacitorUnit, CapacitorStack ): +class VerticalRoutingTracks ( CapacitorUnit, CapacitorStack ): rules = oroshi.getRules() @@ -47,6 +68,11 @@ class VerticalRoutingTracks( CapacitorUnit, CapacitorStack ): return + + def getVTrackYMin ( self ): return self.vRoutingTrackDict["YMin"] - self.hRoutingTrack_width/2 + def getVTrackYMax ( self ): return self.vRoutingTrackDict["YMax"] + self.hRoutingTrack_width/2 + + ## Sets vertical stretching value considering spacing between elementary capacitors in the matrix. # \return stratching value. def __setStretching__( self ): return self.minSpacing_botPlate + self.abutmentBox_spacing/2 @@ -55,17 +81,15 @@ class VerticalRoutingTracks( CapacitorUnit, CapacitorStack ): # \return a dictionary with rules labels as keys and rules content as values. def setRules ( self ): + CapacitorStack.setRules( self ) - CapacitorStack.setRules ( self ) - - CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingTrackCut" , VerticalRoutingTracks.rules.minWidth_cut2 ) - CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingLayer_vRoutingTrack_cut" , VerticalRoutingTracks.rules.minWidth_cut2 ) - CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingTrack" , VerticalRoutingTracks.rules.minWidth_metal2 ) - CapacitorUnit.__setattr__ ( self, "minEnclosure_hRoutingLayer_vRoutingTrack_cut" , VerticalRoutingTracks.rules.minEnclosure_metal2_cut2 ) - CapacitorUnit.__setattr__ ( self, "minEnclosure_hRoutingTrackCut" , VerticalRoutingTracks.rules.minEnclosure_metal2_cut2 ) - CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingLayer" , VerticalRoutingTracks.rules.minWidth_metal2 ) - CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingTrack" , VerticalRoutingTracks.rules.minSpacing_metbot ) - + self.minWidth_hRoutingTrackCut = VerticalRoutingTracks.rules.minWidth_cut2 + self.minWidth_hRoutingLayer_vRoutingTrack_cut = VerticalRoutingTracks.rules.minWidth_cut2 + self.minWidth_hRoutingTrack = VerticalRoutingTracks.rules.minWidth_metal2 + self.minEnclosure_hRoutingLayer_vRoutingTrack_cut = VerticalRoutingTracks.rules.minEnclosure_metal2_cut2 + self.minEnclosure_hRoutingTrackCut = VerticalRoutingTracks.rules.minEnclosure_metal2_cut2 + self.minWidth_hRoutingLayer = VerticalRoutingTracks.rules.minWidth_metal2 + self.minSpacing_hRoutingTrack = VerticalRoutingTracks.rules.minSpacing_metbot return @@ -75,8 +99,8 @@ class VerticalRoutingTracks( CapacitorUnit, CapacitorStack ): self.setRules () vRoutingTracksLayer = DataBase.getDB().getTechnology().getLayer("metal3" ) - print 'self.capacitorInstance.doMatrix:', self.capacitorInstance.doMatrix - print 'self.capacitorsNumber:', self.capacitorsNumber + #print 'self.capacitorInstance.doMatrix:', self.capacitorInstance.doMatrix + #print 'self.capacitorsNumber:', self.capacitorsNumber if self.capacitorInstance.doMatrix == True and self.capacitorsNumber > 1 : self.minimizeVRTs() @@ -88,35 +112,57 @@ class VerticalRoutingTracks( CapacitorUnit, CapacitorStack ): return - ## Iteratively draws vertical routing tracks given the physical layer \c vRoutingTracksLayer. Every elementary capacitor is consequently positioned between four routing tracks, two from each side. Each couple of adjacent routeing tracks represent top plate and bottom plate nets of Ci, where i is in [1,2]. As given in Figure 2, capacitor \f$ C_{ij} \f$ with an even j value situated in even columns have and inversily for odd columns numbers. + ## Iteratively draws vertical routing tracks given the physical layer + # \c vRoutingTracksLayer. Every elementary capacitor is consequently + # positioned between four routing tracks, two from each side. + # Each couple of adjacent routeing tracks represent top plate and + # bottom plate nets of Ci, where i is in [1,2]. As given in Figure 2, + # capacitor \f$ C_{ij} \f$ with an even j value situated in even columns + # have and inversely for odd columns numbers. def drawVRoutingTracks ( self, vRoutingTracksLayer ) : - netsDistribution = self.__setNetsDistribution__() k = 0 for j in range( 0, self.matrixDim["columns"] + 1 ): - for key in self.vRoutingTrackXCenter[j]: - if self.vRoutingTrackXCenter[j][key] != None: - Vertical.create( netsDistribution[j][k] , vRoutingTracksLayer , self.vRoutingTrackXCenter[j][key] , self.vRoutingTrack_width , self.vRoutingTrackDict["YMin"] , self.vRoutingTrackDict["YMax"] ) - k = k + 1 if k < len(key)-1 else 0 + for key in self.vRoutingTrackXCenter[j]: + if self.vRoutingTrackXCenter[j][key] is not None: + Vertical.create( netsDistribution[j][k] + , vRoutingTracksLayer + , self.vRoutingTrackXCenter[j][key] + , self.vRoutingTrack_width + , self.getVTrackYMin() + , self.getVTrackYMax() ) + k = k + 1 if k < len(key)-1 else 0 return - def computeVRTDimensions( self ) : + def computeVRTDimensions ( self ) : - - self.hRoutingTrack_width = max( self.minWidth_hRoutingTrack, self.minWidth_hRoutingTrackCut + 2*self.minEnclosure_hRoutingTrackCut ) - abutmentBoxXMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing) ["XMin"] + self.hRoutingTrack_width = max( self.minWidth_hRoutingTrack, self.minWidth_hRoutingTrackCut + 2*self.minEnclosure_hRoutingTrackCut ) abutmentBoxYMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["YMin"] abutmentBoxYMax = abutmentBoxYMin + self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["height"] - self.minimumPosition = abutmentBoxYMin - self.__setStretching__() - self.maximumPosition = abutmentBoxYMax + self.__setStretching__() + self.minimumPosition = abutmentBoxYMin - self.__setStretching__() - self.hpitch + self.metal2Width + self.maximumPosition = abutmentBoxYMax + self.__setStretching__() + self.hpitch - self.metal2Width + + height = self.maximumPosition - self.minimumPosition + heightAdjust = height % (2*self.hpitch) + if heightAdjust: + heightAdjust = 2*self.hpitch - heightAdjust + trace( 101, '\tAdjust height: {0}\n'.format( DbU.getValueString(heightAdjust) )) + trace( 101, '\tHeight before adjust: {0}\n'.format( DbU.getValueString(self.maximumPosition - self.minimumPosition) )) + trace( 101, '\tminimum before adjust: {0}\n'.format( DbU.getValueString(self.minimumPosition) )) + self.maximumPosition += heightAdjust/2 + self.minimumPosition -= heightAdjust/2 + trace( 101, '\tHeight after adjust: {0}\n'.format( DbU.getValueString(self.maximumPosition - self.minimumPosition) )) + trace( 101, '\tminimum after adjust: {0}\n'.format( DbU.getValueString(self.minimumPosition) )) vRTsNumber = self.__computeVRTsNumber__() - self.vRoutingTrackDict["YMin"] = self.minimumPosition - vRTsNumber*(self.hRoutingTrack_width + self.minSpacing_hRoutingTrack) - self.vRoutingTrackDict["YMax"] = self.maximumPosition + vRTsNumber*(self.hRoutingTrack_width + self.minSpacing_hRoutingTrack) + #self.vRoutingTrackDict["YMin"] = self.minimumPosition - vRTsNumber*(self.hRoutingTrack_width + self.minSpacing_hRoutingTrack) + #self.vRoutingTrackDict["YMax"] = self.maximumPosition + vRTsNumber*(self.hRoutingTrack_width + self.minSpacing_hRoutingTrack) + self.vRoutingTrackDict["YMin"] = self.minimumPosition - (vRTsNumber-1)*self.hpitch + self.vRoutingTrackDict["YMax"] = self.maximumPosition + (vRTsNumber-1)*self.hpitch self.__setPlatesDistribution__() self.computeXCenters() diff --git a/oroshi/python/MultiCapacitor.py b/oroshi/python/MultiCapacitor.py index bc2c38a9..3f93a969 100644 --- a/oroshi/python/MultiCapacitor.py +++ b/oroshi/python/MultiCapacitor.py @@ -4,15 +4,17 @@ 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( 1000 ) +#helpers.setTraceLevel( 100 ) import Analog import ParamsMatrix import oroshi +from Analog import Device from CapacitorUnit import CapacitorUnit from CapacitorMatrix import CapacitorStack from CapacitorVRTracks import VerticalRoutingTracks @@ -37,7 +39,7 @@ def toMatrixArgs ( matrix ): def checkCoherency ( device, bbMode ): - message = 'CapacitorMatrix.checkCoherency():\n' + message = 'CapacitorMatrix.checkCoherency(): device "%s".\n' % device.getName() techno = DataBase.getDB().getTechnology() rules = oroshi.getRules() @@ -54,41 +56,65 @@ def checkCoherency ( device, bbMode ): valid = True if pmatrix: - print 'MultiCapacitor.checkCoherency(): Matrix:' rows = pmatrix.getRows () columns = pmatrix.getColumns() for row in range(rows): - print ' [', + #print ' [', for column in range(columns): capaIndex = pmatrix.getValue(row,column) - print '%2d' % capaIndex, + #print '%2d' % capaIndex, if capaIndex >= capacities.getCount(): valid = False message += ' element [%d,%d] == %d is out of range, must be in [0..%d]\n' \ % (row,column,capaIndex,capacities.getCount()-1) - print ']' + #print ']' if not valid: return (False, message) return (True, "") +def addDummyNets ( device ): + if not device.hasDummy(): return + + i = device.getParameter( 'capacities' ).getCount() + topName = 't%d'%i + botName = 'b%d'%i + + topNet = device.getNet( topName ) + if not topNet: + topNet = Net.create( device, topName ) + topNet.setExternal( True ) + + botNet = device.getNet( botName ) + if not botNet: + botNet = Net.create( device, botName ) + botNet.setExternal( True ) + return + + def layout ( device, bbMode ): - trace( 100, ',+', '\tCapacitorMatrix.layout() called.\n' ) + trace( 100, ',+', '\tMultiCapacitor.layout() called for "%s".\n' % device.getName()) paramsMatrix = ParamsMatrix.ParamsMatrix() try: - capacities = device.getParameter( 'capacities' ) - print 'Capacities = ', capacities - - capValuesArg = [] + capacities = device.getParameter( 'capacities' ) + dummyArg = device.hasDummy() + capaValuesArg = [] vTrackNetsArg = [] + + addDummyNets( device ) + for i in range(capacities.getCount()): - capValuesArg .append( capacities.getValue(i) ) + capaValuesArg.append( capacities.getValue(i)*1000.0 ) + vTrackNetsArg.append( [ device.getNet('t%d'%i), device.getNet("b%d"%i) ] ) + + if dummyArg: + i = device.getParameter( 'capacities' ).getCount() vTrackNetsArg.append( [ device.getNet('t%d'%i), device.getNet("b%d"%i) ] ) matrixSizeArg, matchingSchemeArg = toMatrixArgs( device.getParameter('matrix') ) @@ -98,40 +124,44 @@ def layout ( device, bbMode ): if device.isMIM(): typeArg = 'MIMCap' if device.isMOM(): typeArg = 'MOMCap' - print 'matrixSizeArg', matrixSizeArg - #capaGenerator = CapacitorStack( device - # , capValuesArg - # , typeArg - # , matrixSizeArg - # , vTrackNetsArg - # , matrixDim =matrixSizeArg - # , matchingMode =True - # , matchingScheme=matchingSchemeArg - # , dummyRing =False - # ) - capaGenerator = CapacitorStack( device - , capValuesArg - , typeArg - , [0,0] # AB position. - , vTrackNetsArg - #, matrixDim =matrixSizeArg - #, matchingMode =True - #, matchingScheme=matchingSchemeArg - , dummyRing =False - ) - capaMatrix = capaGenerator.create() - if hasattr(capaMatrix,'doMatrix') and capaMatrix.doMatrix: + if len(capaValuesArg) == 1: + # One capa, multiple units. + capaGenerator = CapacitorStack( device + , capaValuesArg # (fF). + , typeArg + , [0,0] # AB position. + , vTrackNetsArg + , matrixDim =matrixSizeArg + , dummyRing =dummyArg + ) + capaMatrix = capaGenerator.create() + capaSingle = RouteCapacitorSingle( capaGenerator + , capaMatrix + , topPlateWSpec=[1,0] + , bottomPlateWSpec=[0,1] ) + capaSingle.route() + else: + # Two capa, multiple units. + capaGenerator = CapacitorStack( device + , capaValuesArg # [ 240, 720 ] # capaValuesArg (fF). + , typeArg + , [0,0] # AB position. + , vTrackNetsArg + , matrixDim =matrixSizeArg + , matchingMode =True + , matchingScheme=matchingSchemeArg + , dummyRing =dummyArg + ) + capaMatrix = capaGenerator.create() capaTracks = VerticalRoutingTracks( capaGenerator, capaMatrix, True ) capaTracks.create() capaRouted = RoutMatchedCapacitor( capaTracks ) capaRouted.route() - else: - capaSingle = RouteCapacitorSingle( capaGenerator - , capaMatrix - , topPlateWSpec=[0,1] - , bottomPlateWSpec=[1,0] ) - capaSingle.route() + + for pair in vTrackNetsArg: + for net in pair: + device.setRestrictions( net, Device.NorthBlocked|Device.SouthBlocked ) paramsMatrix.setGlobalCapacitorParams( device.getAbutmentBox() ) trace( 100, '++' )