coriolis/oroshi/python/paramsmatrix.py

252 lines
8.8 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
Support for mixing real pads & symbolic core. Wrapper around s2r. * Change: In Hurricane::Error constructors disable the backtrace generation. (*very* slow). * Change: In Hurricane::Library::getHierarchicalname(), more compact naming. Remove the name of the root library. * New: In Hurricane::Net, new type "FUSED", for component with no net. More efficient than having one net for each. * Change: In CellViewer, BreakpointWidget, use Angry Birds icons. * Change: In CellWidget::State, use the hierarchical name (cached) as key to the state. This allow to load two cells with the same name but from different libraries in the widget history. * Change: In PyGraphics, export "isEnabled()" and "isHighDpi()" functions. * Change: In CRL/etc/symbolic/cmos/plugin.conf, and CRL/etc/common/plugin.conf use the physical dimensions converters. * Change: In CRL/etc/symbolic/cmos/technology.conf, make the GDS layer table coherent with the default Alliance cmos.rds. * New: CRL/python/helpers/io.py, put ErrorMessage new implementation here, along with a new ErrorWidget written in PyQt4. It seems finally that PyQt4 can be used alongside Coriolis Qt widgets. New ErrorMessage.catch() static function to manage all exceptions in except clauses. * Change: In CRL/python/helpers/, no longer use ErrorMessage.wrapPrint(), directly print it. Rewrite the utilities to display Python stack traces "textStacktrace()" and "showStacktrace()". * Change: In CRL::AllianceFramework, shorten the names of the libraries. * Change: In CRL::ApParser & CRL::ApDriver, more accurate translation between Alliance connectors (C record) and Hurricane::Pin objects. Pin are no longer made square but thin and oriented in the connecting direction. Use the new fused net for unnamed components. * New: In CRL::GdsParser, implementation of SREF parsing, i.e. instances. Due to the unordered nature of the GDS stream, instances creation are delayed until the whole stream has been parsed and only then are they created. For the sake of reading back Alliance s2r GDS, we assume that any TEXT following a boundary is the Net name the boundary (component) belongs to. Create abutment box for Cells, computed from the bounding box, so the Hurricane QuadTree could work properly. Make use of the fused net for unnamed components. * New: In Cumulus/plugins/chip, complete rewrite of the I/O pad management. Now we can mix real (foundry) pads and a symbolic core. To cleanly support the de-coupling between the real part and the symbolic one we introduce a new intermediary hierarchical level, the corona. We have now: Chip --> Pads + Corona --> Core. At chip level (and if we are using real pads) the layout is fully real (excepting the corona). The Corona contains everything that is symbolic. It has symbolic wires extending outward the abutment box to make contact with the real wires coming from the pads. In the pad ring we can use corners instances (or not), pad spacers or directly draw wires between connectors ring pads. Provide two flavors: placement only or full place & route. WARNING: If routing in a second step, *do not route* the *Chip* but the *Corona*. * Change: In Cumulus/plugins/clocktree, give the modified Cell an additional extension of "_cts" (Clock Tree Synthesis) instead of "_clocked", to follow the common convention. * New: In cumulus/plugins/S2R.py, encapsulate call to Alliance S2R and reload the translated Cell in the editor. * New: In cumulus/plugins/core2chip, provide an utility to automatically create a chip from a core. To work this plugins must have a basic understanding of the pad functionalities which may differs from foundry to foundry. So a base class CoreToChip is created, then for each supported pad foundry a derived class is added. Currently we support AMS c35b4 and Alliance symbolic cmos. * Bug: In Anabatic::Configuration, read the right configuration parameter "anabatic.topRoutinglayer" (Katana), and not the one for Katabatic... * Change: In Unicorn/cgt.py, process the plugins in alphabetical order to ensure a reproductible ordering of the menus...
2019-05-22 07:34:32 -05:00
from Hurricane import DataBase
from Hurricane import DbU
from Hurricane import Box
from Hurricane import Net
from helpers.io 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
First stage in analog capacitor integration * Bug: In Technology::getPhysicalRule(), if the named layerdo not exists, throw an exception instead of silently putting a NULL pointer inside a rule. * New: In Hurricane/Analog, new parameters classes for capacitor devices: - Analog::Matrix, a matrix of null or positives integers to encode capacitor matrix matching. - Analog::Capacities, a list of float values for all component of a multi-capacitor. * New: In Hurricane::Script, add a "getFileName()" method to get the full path name of the Python module. * Change: In Analog::LayoutGenerator, completly remove the logger utility as it is no longer used. Simply print error messages instead. * Change: In Analog::MetaCapacitor, rename top & bottom plate 'T' & 'B'. Accessors renamed in "getTopPlate()" & "getBottomPlate()". * New: In Analog::MultiCapacitor, complete rewrite. Makes use of the new parameters "capacities" and "matrix". Dynamically generates it's terminals as we do not know beforehand how many capacitors could be put in it. * Bug: In isobar/PyHurricane.h, in Type object definition, do not prepend a "Py" to class name (so the keep the C++ name). * Change: In CRL/etc/scn6m_deep_09/devices.py, add entry for the new capacitor generator. * New: In oroshi/python/ParamsMatrix, add a "family" entry in the [0,0] element to distinguish between transistor, capacitor and resistor. (this is the matrix of values returned to the LayoutGenerator after device generation). Now have one "setGlobalParams()" function per family. * New: In oroshi/python/Rules.py, added DTR rules needed by capacitors. Catch exceptions if something wrong append when we extract the rules from the technology. * New: In Bora, the devices are no longer *only* transistors, so the possibles configurations are no longer defined only by a number of fingers. We must be able to support any kind of range of configuration. So the explicit range of number of fingers is replaced by a base class ParameterRange, and it's derived classes: - Bora::StepParameterRange, to encode the possible number of fingers of a transistor (the former only possibility). - Bora::MatrixParameterRange, to encode all the possible matching scheme for a capacitor. As there is no way to compress it, this is a vector of Matrix (from Analog). * Change: In Bora::DSlicingNode::_place(), the ParameterRange has to be set on the right configuration (through the index) before being called. The generation parameters are taken from the active item in the ParameterRange. * Change: In Bora::NodeSets::create(), iterate over the ParameterRange to build all the configuration. Adjustement to the routing gauge pitchs are moved into the DBoxSet CTOR to save a lot of code. Semantic change: the index in the NodeSets is now the index in the associated ParameterRange and no longer the number of fingers of a transistor. Check that the ParameterRange dynamic class is consitent with the device family. * Change: In Bora::DBoxSet, same semantic change as for NodeSets, the number of finger become an index in ParameterRange. In DBoxSet::create(), now also perform the abutment box adjustement to the RoutingGauge, if possible. * New: In Karakaze/python/AnalogDesign.py, add support for Capacitor devices.
2019-11-07 10:05:49 -06:00
def setGlobalTransistorParams ( 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()
First stage in analog capacitor integration * Bug: In Technology::getPhysicalRule(), if the named layerdo not exists, throw an exception instead of silently putting a NULL pointer inside a rule. * New: In Hurricane/Analog, new parameters classes for capacitor devices: - Analog::Matrix, a matrix of null or positives integers to encode capacitor matrix matching. - Analog::Capacities, a list of float values for all component of a multi-capacitor. * New: In Hurricane::Script, add a "getFileName()" method to get the full path name of the Python module. * Change: In Analog::LayoutGenerator, completly remove the logger utility as it is no longer used. Simply print error messages instead. * Change: In Analog::MetaCapacitor, rename top & bottom plate 'T' & 'B'. Accessors renamed in "getTopPlate()" & "getBottomPlate()". * New: In Analog::MultiCapacitor, complete rewrite. Makes use of the new parameters "capacities" and "matrix". Dynamically generates it's terminals as we do not know beforehand how many capacitors could be put in it. * Bug: In isobar/PyHurricane.h, in Type object definition, do not prepend a "Py" to class name (so the keep the C++ name). * Change: In CRL/etc/scn6m_deep_09/devices.py, add entry for the new capacitor generator. * New: In oroshi/python/ParamsMatrix, add a "family" entry in the [0,0] element to distinguish between transistor, capacitor and resistor. (this is the matrix of values returned to the LayoutGenerator after device generation). Now have one "setGlobalParams()" function per family. * New: In oroshi/python/Rules.py, added DTR rules needed by capacitors. Catch exceptions if something wrong append when we extract the rules from the technology. * New: In Bora, the devices are no longer *only* transistors, so the possibles configurations are no longer defined only by a number of fingers. We must be able to support any kind of range of configuration. So the explicit range of number of fingers is replaced by a base class ParameterRange, and it's derived classes: - Bora::StepParameterRange, to encode the possible number of fingers of a transistor (the former only possibility). - Bora::MatrixParameterRange, to encode all the possible matching scheme for a capacitor. As there is no way to compress it, this is a vector of Matrix (from Analog). * Change: In Bora::DSlicingNode::_place(), the ParameterRange has to be set on the right configuration (through the index) before being called. The generation parameters are taken from the active item in the ParameterRange. * Change: In Bora::NodeSets::create(), iterate over the ParameterRange to build all the configuration. Adjustement to the routing gauge pitchs are moved into the DBoxSet CTOR to save a lot of code. Semantic change: the index in the NodeSets is now the index in the associated ParameterRange and no longer the number of fingers of a transistor. Check that the ParameterRange dynamic class is consitent with the device family. * Change: In Bora::DBoxSet, same semantic change as for NodeSets, the number of finger become an index in ParameterRange. In DBoxSet::create(), now also perform the abutment box adjustement to the RoutingGauge, if possible. * New: In Karakaze/python/AnalogDesign.py, add support for Capacitor devices.
2019-11-07 10:05:49 -06:00
self.matrix[0][0]['family' ] = 'Transistor'
return
def setGlobalCapacitorParams ( self, boundingBox ):
self.matrix[0][0]['box' ] = boundingBox
self.matrix[0][0]['family' ] = 'Capacitor'
return
def setGlobalResistorParams ( self, boundingBox ):
self.matrix[0][0]['box' ] = boundingBox
self.matrix[0][0]['family' ] = 'Resistor'
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