239 lines
8.4 KiB
Python
239 lines
8.4 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
from Hurricane import DataBase
|
||
|
from Hurricane import DbU
|
||
|
from Hurricane import Box
|
||
|
from Hurricane import Net
|
||
|
from helpers import ErrorMessage as Error
|
||
|
from helpers import trace
|
||
|
|
||
|
|
||
|
# Rows are stacks.
|
||
|
# Columns are metaTransistors.
|
||
|
#
|
||
|
# There must be the exact same number of metaTransistors in each stack.
|
||
|
# Storage is matrix[row][col] ie matrix[stack][metaTransistor]
|
||
|
|
||
|
NoFlags = 0x0000
|
||
|
Top = 0x0001
|
||
|
Left = 0x0002
|
||
|
|
||
|
class ParamsMatrix ( object ):
|
||
|
|
||
|
@staticmethod
|
||
|
def gateToId ( gateName ):
|
||
|
if len(gateName) == 1: return None
|
||
|
return int( gateName[1:] )
|
||
|
|
||
|
@staticmethod
|
||
|
def idToGate ( index ):
|
||
|
if index is None: return 'G'
|
||
|
return 'G'+str(index)
|
||
|
|
||
|
@staticmethod
|
||
|
def idToTran ( index ):
|
||
|
if index is None: return 'T'
|
||
|
return 'T'+str(index)
|
||
|
|
||
|
|
||
|
def __init__ ( self ):
|
||
|
self.matrix = [ [ {} ] ]
|
||
|
self.rows = 1
|
||
|
self.columns = 1
|
||
|
return
|
||
|
|
||
|
|
||
|
def getMatrix ( self ): return self.matrix
|
||
|
|
||
|
|
||
|
def setGlobalParams ( self, w, L, M, boundingBox ):
|
||
|
self.matrix[0][0]['L' ] = L
|
||
|
self.matrix[0][0]['W' ] = w
|
||
|
self.matrix[0][0]['M' ] = M
|
||
|
self.matrix[0][0]['box' ] = boundingBox
|
||
|
self.matrix[0][0]['globalActiveBox' ] = Box()
|
||
|
return
|
||
|
|
||
|
|
||
|
def setStacks ( self, stacks ):
|
||
|
if not isinstance(stacks,list):
|
||
|
print Error( 3, 'ParamsMatrix::setGlobalParams(): <stack> argument must be of <list> type.' )
|
||
|
return
|
||
|
|
||
|
if not len(stacks):
|
||
|
print Error( 3, 'ParamsMatrix::setGlobalParams(): There must be at least one Stack.' )
|
||
|
return
|
||
|
|
||
|
mtIds = []
|
||
|
if len(stacks[0].metaTransistors) == 0:
|
||
|
print Error( 3, 'ParamsMatrix::setGlobalParams(): Stack without any meta-transistor.' )
|
||
|
return
|
||
|
else:
|
||
|
for gateName in stacks[0].metaTransistors.keys():
|
||
|
mtIds.append( ParamsMatrix.gateToId(gateName) )
|
||
|
mtIds.sort()
|
||
|
|
||
|
for i in range(1,len(stacks)):
|
||
|
if len(stacks[0].metaTransistors) != len(stacks[i].metaTransistors):
|
||
|
print Error( 3, 'ParamsMatrix::setGlobalParams(): Stacks %d and %d' \
|
||
|
' have different numbers of meta-transistor.' % (0,i) )
|
||
|
return
|
||
|
|
||
|
for id in mtIds:
|
||
|
gateName = ParamsMatrix.idToGate( id )
|
||
|
if not stacks[i].metaTransistors.has_key(gateName):
|
||
|
print Error( 3, 'ParamsMatrix::setGlobalParams(): Stack %d ' \
|
||
|
' is missing meta-transistor "%s".' % (i,gateName) )
|
||
|
return
|
||
|
|
||
|
# Thoses parameters must be the same in all the stacks.
|
||
|
self.matrix[0][0]['DMCG'] = stacks[0].DMCG
|
||
|
self.matrix[0][0]['DMCI'] = stacks[0].DMCI
|
||
|
self.matrix[0][0]['DGG' ] = stacks[0].DGG
|
||
|
self.matrix[0][0]['DGI' ] = stacks[0].DGI
|
||
|
|
||
|
for iStack in range(len(stacks)):
|
||
|
activeBox = stacks[iStack].activeBox
|
||
|
stackMTs = [ { 'activeBox':activeBox } ]
|
||
|
self.matrix[0][0]['globalActiveBox'].merge( activeBox )
|
||
|
|
||
|
for iMT in range(len(mtIds)):
|
||
|
gateName = ParamsMatrix.idToGate( mtIds[iMT] )
|
||
|
tranName = ParamsMatrix.idToTran( mtIds[iMT] )
|
||
|
mt = stacks[iStack].metaTransistors[ gateName ]
|
||
|
|
||
|
stackMTs.append( { 'name':tranName } )
|
||
|
for key, value in mt.items():
|
||
|
stackMTs[-1][ key.split('.')[-1] ] = value
|
||
|
|
||
|
if iStack == 0:
|
||
|
self.matrix[0].append( { 'name':tranName } )
|
||
|
for key in stackMTs[-1].keys():
|
||
|
if key == 'name' or key == 'style.geomod': continue
|
||
|
if key.startswith('stress.'):
|
||
|
self.matrix[0][-1][key] = stackMTs[-1][key] / len(stacks)
|
||
|
else:
|
||
|
self.matrix[0][-1][key] = stackMTs[-1][key]
|
||
|
else:
|
||
|
for key in stackMTs[-1].keys():
|
||
|
if key == 'name' or key == 'style.geomod': continue
|
||
|
if key.startswith('stress.'):
|
||
|
self.matrix[0][-1][key] += stackMTs[-1][key] / len(stacks)
|
||
|
else:
|
||
|
self.matrix[0][-1][key] += stackMTs[-1][key]
|
||
|
|
||
|
self.matrix.append( stackMTs )
|
||
|
|
||
|
return
|
||
|
|
||
|
|
||
|
def stackHeader ( self, lines, iStack ):
|
||
|
for i in range(28):
|
||
|
if i in [1, 2, 3, 4]:
|
||
|
if i == 1:
|
||
|
lines.append( '+-----------------------+' )
|
||
|
self.toBoxDatasheet( lines, self.matrix[iStack][0]['activeBox'], 'Active Box', Left )
|
||
|
continue
|
||
|
|
||
|
if i == 0: lines.append( '|{0:^23s}'.format( 'Stack %d'%iStack ) )
|
||
|
elif i == 27: lines.append( '+-----------------------' )
|
||
|
else: lines.append( '| ' )
|
||
|
|
||
|
if i in [1, 14, 21, 27]: lines[-1] += '+'
|
||
|
else: lines[-1] += '|'
|
||
|
return
|
||
|
|
||
|
|
||
|
def toMtDatasheet ( self, lines, mt, comment, flags ):
|
||
|
if flags & Top: lines[-29] += '-----------------------+'
|
||
|
|
||
|
lines[-28] += '{0:^23s}|'.format( mt['name']+comment )
|
||
|
lines[-27] += '-----------------------+'
|
||
|
lines[-26] += ' BSIM4 |'
|
||
|
lines[-25] += ' NSint %7s |' % mt['NSint']
|
||
|
lines[-24] += ' NDint %7s |' % mt['NDint']
|
||
|
lines[-23] += ' NSend %7s |' % mt['NSend']
|
||
|
lines[-22] += ' NDend %7s |' % mt['NDend']
|
||
|
lines[-21] += ' SAeff %7.2g m |' % mt['SAeff_Bsim4']
|
||
|
lines[-20] += ' SBeff %7.2g m |' % mt['SBeff_Bsim4']
|
||
|
lines[-19] += ' SAinv %7.2g 1/m |' % mt['SBinv_Bsim4']
|
||
|
lines[-18] += ' SBinv %7.2g 1/m |' % mt['SBinv_Bsim4']
|
||
|
lines[-17] += ' alpha %7.2g m |' % mt['alpha' ]
|
||
|
lines[-16] += ' alphaInv %7.2g 1/m |' % mt['alphaInv' ]
|
||
|
lines[-15] += ' LODeffect %7.2g 1/m |' % mt['alphaInv' ]
|
||
|
lines[-14] += '-----------------------+'
|
||
|
lines[-13] += ' Crolles |'
|
||
|
lines[-12] += ' SAeff %7.2g m |' % mt['SAeff_Crolles']
|
||
|
lines[-11] += ' SBeff %7.2g m |' % mt['SBeff_Crolles']
|
||
|
lines[-10] += ' SAinv %7.2g 1/m |' % mt['SBinv_Crolles']
|
||
|
lines[- 9] += ' SBinv %7.2g 1/m |' % mt['SBinv_Crolles']
|
||
|
lines[- 8] += ' po2actEff %7.2g m |' % mt['po2actEff_Crolles']
|
||
|
lines[- 7] += '-----------------------+'
|
||
|
lines[- 6] += ' Layout Parasitics |'
|
||
|
lines[- 5] += ' ASeff %11.2g m2 |' % mt['ASeff']
|
||
|
lines[- 4] += ' PSeff %11.2g m |' % mt['PSeff']
|
||
|
lines[- 3] += ' ADeff %11.2g m2 |' % mt['ADeff']
|
||
|
lines[- 2] += ' PDeff %11.2g m |' % mt['PDeff']
|
||
|
lines[- 1] += '-----------------------+'
|
||
|
return
|
||
|
|
||
|
|
||
|
def toBoxDatasheet ( self, lines, box, comment, flags ):
|
||
|
if flags & Left:
|
||
|
for i in range(3): lines.append( '|' )
|
||
|
|
||
|
lines[-3] += '{0:^23s}|'.format( comment )
|
||
|
lines[-2] += ' bl %8s %8s |' % (DbU.getValueString(box.getXMin()), DbU.getValueString(box.getYMin()))
|
||
|
lines[-1] += ' tr %8s %8s |' % (DbU.getValueString(box.getXMax()), DbU.getValueString(box.getYMax()))
|
||
|
return
|
||
|
|
||
|
|
||
|
def toDatasheet ( self ):
|
||
|
lines = []
|
||
|
# Matrix element [0,0]
|
||
|
lines.append( '+-----------------------+' )
|
||
|
lines.append( '| Device Datas |' )
|
||
|
lines.append( '+-----------------------+' )
|
||
|
lines.append( '| L %14.2g m |' % self.matrix[0][0]['L'] )
|
||
|
lines.append( '| wF %14.2g m |' % self.matrix[0][0]['W'] )
|
||
|
lines.append( '| M %14.2g |' % self.matrix[0][0]['M'] )
|
||
|
lines.append( '| DMCG %14.2g m |' % self.matrix[0][0]['DMCG'] )
|
||
|
lines.append( '| DMCI %14.2g m |' % self.matrix[0][0]['DMCI'] )
|
||
|
lines.append( '| DGG %14.2g m |' % self.matrix[0][0]['DGG'] )
|
||
|
lines.append( '| DGI %14.2g m |' % self.matrix[0][0]['DGI'] )
|
||
|
lines.append( '+-----------------------+' )
|
||
|
self.toBoxDatasheet( lines, self.matrix[0][0]['box'], 'Bounding Box', Left )
|
||
|
lines.append( '+-----------------------+' )
|
||
|
self.toBoxDatasheet( lines, self.matrix[0][0]['globalActiveBox'], 'Active Box', Left )
|
||
|
lines[-3] = lines[-3][0:-1] + '+'
|
||
|
for i in range(len(lines),28):
|
||
|
lines.append( '| ' )
|
||
|
if i in [0, 2, 15, 22, 28]: lines[-1] += '+'
|
||
|
else: lines[-1] += '|'
|
||
|
lines.append( '+-----------------------+' )
|
||
|
|
||
|
# Row 0: Meta-Transistors aggregated parameters.
|
||
|
mts = self.matrix[0]
|
||
|
for iMT in range(1,len(mts)):
|
||
|
self.toMtDatasheet( lines, mts[iMT], ' (meta)', Top )
|
||
|
|
||
|
# Rows 1+: One stack and its's meta-transistors.
|
||
|
for iStack in range(1,len(self.matrix)):
|
||
|
self.stackHeader( lines, iStack )
|
||
|
for iMT in range(1,len(self.matrix[iStack])):
|
||
|
self.toMtDatasheet( lines, self.matrix[iStack][iMT], '', NoFlags )
|
||
|
|
||
|
return lines
|
||
|
|
||
|
|
||
|
def __str__ ( self ):
|
||
|
s = ''
|
||
|
for line in self.toDatasheet(): s += line + '\n'
|
||
|
return s
|
||
|
|
||
|
|
||
|
def trace( self ):
|
||
|
for line in self.toDatasheet():
|
||
|
trace( 100, '\t%s\n' % line )
|
||
|
return
|