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.
This commit is contained in:
Jean-Paul Chaput 2020-03-15 17:56:09 +01:00
parent 2152811005
commit a12d88040a
14 changed files with 864 additions and 536 deletions

View File

@ -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();
}
}

View File

@ -396,11 +396,9 @@ namespace Bora {
for( Instance* iInstance : instances ) {
Cell* model = iInstance->getMasterCell();
Device* device = dynamic_cast<Device*>(model);
cerr << "device:" << device << endl;
if (device) {
TransistorFamily* tf = dynamic_cast<TransistorFamily*>( device );
cerr << "tf:" << tf << endl;
if (tf) {
_gridLabel[i+5]->setDynamicText ( QString("%1" ).arg( tf->getNfing() ) );
i++;

View File

@ -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; }

View File

@ -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:

View File

@ -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;
}

View File

@ -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
);

View File

@ -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 )

View File

@ -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

View File

@ -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

View File

@ -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 )

View File

@ -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 <RoutMatchedCapacitor>.' ] )
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 <RoutMatchedCapacitor>.')
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 <Invalid-specifictions > \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

View File

@ -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 )

View File

@ -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()

View File

@ -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, '++' )