coriolis/karakaze/python/analogdesign.py

764 lines
39 KiB
Python

# -*- Mode:Python -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) Sorbonne Université 2016-2023, All Rights Reserved
#
# +-----------------------------------------------------------------+
# | C O R I O L I S |
# | B o r a - A n a l o g S l i c i n g T r e e |
# | |
# | Author : Jean-Paul Chaput |
# | E-mail : Jean-Paul.Chaput@lip6.fr |
# | =============================================================== |
# | Python : "./karakaze/AnalogDesign.py" |
# +-----------------------------------------------------------------+
from ..Hurricane import *
from ..Hurricane import DataBase
from .. import CRL
from ..helpers import isderived, setTraceLevel, trace
from ..helpers.io import ErrorMessage as Error
from ..Analog import Device, TransistorFamily, Transistor, \
CommonDrain, CommonGatePair, CommonSourcePair, \
CrossCoupledPair, DifferentialPair, LevelShifter, \
SimpleCurrentMirror, CapacitorFamily, \
MultiCapacitor, CapacitorFamily, MultiCapacitor, \
ResistorFamily, Resistor, LayoutGenerator, \
Matrix
from ..Bora import ParameterRange, StepParameterRange, \
MatrixParameterRange, SlicingNode, HSlicingNode, \
VSlicingNode, DSlicingNode, RHSlicingNode, \
RVSlicingNode
from . import oceane
from .. import Anabatic, Katana, Bora
#setTraceLevel( 100 )
NMOS = Transistor.NMOS
PMOS = Transistor.PMOS
PIP = CapacitorFamily.PIP
MIM = CapacitorFamily.MIM
MOM = CapacitorFamily.MOM
LOWRES = ResistorFamily.LOWRES
HIRES = ResistorFamily.HIRES
RPOLYH = ResistorFamily.RPOLYH
RPOLY2PH = ResistorFamily.RPOLY2PH
Center = SlicingNode.AlignCenter
Left = SlicingNode.AlignLeft
Right = SlicingNode.AlignRight
Top = SlicingNode.AlignTop
Bottom = SlicingNode.AlignBottom
Unknown = SlicingNode.AlignBottom
VNode = 1
HNode = 2
DNode = 3
def toDbU ( value ): return DbU.fromPhysical( value, DbU.UnitPowerMicro )
def toLength ( value ): return float(value) * 1e+6
def readMatrix ( rows ):
if not isinstance(rows,list):
print( '[ERROR] readMatrix(): First level is not a list.' )
sys.exit( 1 )
rowCount = len(rows)
for row in range(len(rows)):
column = rows[row]
if not isinstance(column,list):
print( '[ERROR] readMatrix(): Column {} is not a list.'.format(row) )
sys.exit( 1 )
if row == 0:
columnCount = len(column)
matrix = Matrix( rowCount, columnCount )
else:
if columnCount != len(column):
print( '[ERROR] readMatrix(): Column {} size discrepency (sould be {}).'.format(len(column),columnCount))
sys.exit( 1 )
for column in range(len(column)):
matrix.setValue( row, column, rows[row][column] )
return matrix
class AnalogDesign ( object ):
SPEC_CLASS = 0
SPEC_INSTANCE = 1
SPEC_STYLE = 2
SPEC_TYPE = 3
SPEC_TRANS_W = 4
SPEC_TRANS_L = 5
SPEC_TRANS_M = 6
SPEC_TRANS_MINT = 7
SPEC_TRANS_DUMMY = 8
SPEC_TRANS_SFIRST = 9
SPEC_TRANS_BULK = 10
SPEC_TRANS_BULK_CONN = 11
SPEC_CAPA_C = 4
SPEC_CAPA_MATRIX = 5
SPEC_CAPA_DUMMY = 6
def __init__ ( self ):
self.cellName = None
self.netCache = {}
self.rg = None
self.library = None
self.cell = None
self.netCache = {}
self.slicingTree = None
self.stack = []
self.stack2 = []
self.toleranceRatioH = 0
self.toleranceRatioW = 0
self.toleranceBandH = 0
self.toleranceBandW = 0
self.parameters = oceane.Parameters()
return
def setCellName ( self, name ):
self.cellName = name
return
def beginCell ( self, cellName ):
self.setCellName( cellName )
UpdateSession.open()
self.rg = CRL.AllianceFramework.get().getRoutingGauge()
self.cell = CRL.AllianceFramework.get().createCell( self.cellName )
self.library = Library.create( DataBase.getDB().getRootLibrary(), 'AnalogRootLibrary' )
self.generator = LayoutGenerator()
return
def endCell ( self ):
UpdateSession.close()
return
def checkBeginCell ( self, function ):
if not self.cell:
raise Error( 3, [ 'AnalogDesign: \"AnalogDevice.beginCell()\" must be called *before* \"%s\".' \
% function
] )
return
def checkConnexion ( self, count, net, connexion ):
if not isinstance(connexion,tuple):
raise Error( 3, [ 'AnalogDesign.doNets(): \"self.netSpecs\" in \"%s\", connexion [%d] is *not* a tuple.' \
% (net.getName(),count)
, '%s' % str(connexion) ] )
if len(connexion) != 2:
raise Error( 3, [ 'AnalogDesign.doNets(): \"self.devicesSpecs\" in \"%s\", connexion [%d] has %d items instead of 2 .' \
% (net.getName(),count,len(connexion))
, '%s' % str(connexion) ] )
if not isinstance(connexion[0],str):
raise Error( 3, [ 'AnalogDesign.doNets(): \"self.devicesSpecs\" in \"%s\", connexion [%d], field [0] (instance) is *not* a string.' \
% (net.getName(),count)
, '%s' % str(connexion) ] )
if not isinstance(connexion[1],str):
raise Error( 3, [ 'AnalogDesign.doNets(): \"self.devicesSpecs\" in \"%s\", connexion [%d], field [1] (terminal) is *not* a string.' \
% (net.getName(),count)
, '%s' % str(connexion) ] )
return
def checkRail( self, net, metal, npitch, cellName, instanceName ):
#Net verification missing
if not isinstance(metal,str):
raise Error( 3, [ 'AnalogDesign.checkRail(): \"metal\" is *not* a string.' ] )
if not isinstance(npitch,int):
raise Error( 3, [ 'AnalogDesign.checkRail(): \"NPitch\" is *not* an int.' ] )
if not isinstance(cellName,str):
raise Error( 3, [ 'AnalogDesign.checkRail(): \"cellName\" is *not* a string.' ] )
if not isinstance(instanceName,str):
raise Error( 3, [ 'AnalogDesign.checkRail(): \"instanceName\" is *not* a string.' ] )
return
def connect ( self, instanceName, masterNetName, net ):
instance = getattr( self, instanceName )
masterNet = instance.getMasterCell().getNet( masterNetName )
instance.getPlug( masterNet ).setNet( net )
state = NetRoutingExtension.get(net)
device = instance.getMasterCell()
if masterNetName=='B':
device.getParameter('B.w').setValue(int(state.getWPitch()))
if masterNetName=='G':
device.getParameter('G.w').setValue(int(state.getWPitch()))
if masterNetName=='G1':
device.getParameter('G1.w').setValue(int(state.getWPitch()))
if masterNetName=='G2':
device.getParameter('G2.w').setValue(int(state.getWPitch()))
if masterNetName=='D':
device.getParameter('D.w').setValue(int(state.getWPitch()))
if masterNetName=='D1':
device.getParameter('D1.w').setValue(int(state.getWPitch()))
if masterNetName=='D2':
device.getParameter('D2.w').setValue(int(state.getWPitch()))
if masterNetName=='S':
device.getParameter('S.w').setValue(int(state.getWPitch()))
return
def getNet ( self, netName, create=True ):
net = None
if netName in self.netCache:
net = self.netCache[netName]
elif create:
net = Net.create( self.cell, netName )
self.netCache[ netName ] = net
return net
def doNets ( self ):
self.checkBeginCell( 'AnalogDesign.doNets()' )
if not hasattr(self,'netSpecs'):
raise Error( 3, 'AnalogDesign.doNets(): Mandatory attribute \"self.netSpecs\" has not been defined.' )
if not isinstance(self.netSpecs,dict):
raise Error( 3, 'AnalogDesign.doNets(): Attribute \"self.netSpecs\" *must* be a Python dict.' )
for netName, netType in self.netTypes.items():
if not isinstance(netName,str):
raise Error( 3, 'AnalogDesign.doNets(): Dict key (net name) of \"self.netTypes\" *must* be a string (%s).' % str(netName) )
net = self.getNet( netName )
isExternal = False
if 'isExternal' in netType: isExternal = netType['isExternal']
for netName, connexions in self.netSpecs.items():
if not isinstance(netName,str):
raise Error( 3, 'AnalogDesign.doNets(): Dict key (net name) of \"self.netSpecs\" *must* be a string (%s).' % str(netName) )
net = self.getNet( netName )
state = NetRoutingExtension.create( net, NetRoutingState.AutomaticGlobalRoute|NetRoutingState.Analog )
count = 1
for connexion in connexions:
if isinstance(connexion,tuple):
self.checkConnexion( count, net, connexion )
self.connect( connexion[0], connexion[1], net )
count += 1
else:
if isinstance(connexion,dict): state.setWPitch(long(connexion['W']))
return
def checkDSpec ( self, count, dspec ):
if not isinstance(dspec,list):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], is *not* a list.' % count
, '%s' % str(dspec) ])
if not isderived(dspec[0],Device):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [0] is *not* a Device class.' % count
, '%s' % str(dspec) ])
specSize = 0
if isderived(dspec[0],TransistorFamily): specSize = 12
elif isderived(dspec[0], CapacitorFamily): specSize = 7
elif isderived(dspec[0], ResistorFamily): specSize = 8
else:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], has unsupported device type.' \
% (count)
, '%s' % str(dspec) ])
if len(dspec) < specSize:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], has %d items instead of 12 .' \
% (count,len(dspec))
, '%s' % str(dspec) ])
if not isinstance(dspec[1],str):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [1] (model name) is *not* a string.' % count
, '%s' % str(dspec) ])
if not isinstance(dspec[2],str):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [2] (layout style) is *not* a string.' % count
, '%s' % str(dspec) ])
if isderived(dspec[0],TransistorFamily):
if dspec[3] not in [NMOS, PMOS]:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [3] (type) must be either NMOS or PMOS.' % count
, '%s' % str(dspec) ])
if not isinstance(dspec[4],float):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [4] (WE) is *not* a float.' % count
, '%s' % str(dspec) ])
if not isinstance(dspec[5],float):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [5] (LE) is *not* a float.' % count
, '%s' % str(dspec) ])
if not isinstance(dspec[6],int):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [6] (M) is *not* an int.' % count
, '%s' % str(dspec) ])
if (not dspec[7] is None) and (not isinstance(dspec[7],int)):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [7] (Mint) is neither an int nor None.' % count
, '%s' % str(dspec) ])
if not isinstance(dspec[8],int):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [8] (external dummies) is *not* an int.' % count
, '%s' % str(dspec) ])
if not isinstance(dspec[9],bool):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [9] (source first) is *not* a boolean.' % count
, '%s' % str(dspec) ])
if not isinstance(dspec[10],int):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [10] (bulk) is *not* an int.' % count
, '%s' % str(dspec) ])
else:
if dspec[10] > 0xf:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [10] (bulk) is greater than 0xf.' % count
, '%s' % str(dspec) ])
if not isinstance(dspec[11],bool):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [11] (bulk connected) is *not* a boolean.' % count
, '%s' % str(dspec) ])
elif isderived(dspec[0], CapacitorFamily):
if dspec[3] not in [PIP, MIM, MOM]:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [3] (type) must be either PIP, MIM or MOM.' % count
, '%s' % str(dspec) ])
if isinstance(dspec[4],float): pass
elif isinstance(dspec[4],tuple): pass
else:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [4] (Cs) should either be *one* float or a *list* of floats.' % count
, '%s' % str(dspec) ])
elif isderived(dspec[0],ResistorFamily):
if dspec[3] not in [RPOLYH, RPOLY2PH]:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [3] (type) must be either RPOLYH or RPOLY2PH.' % count
, '%s' % str(dspec) ])
if isinstance(dspec[5],float): pass
else:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [4] (resistance) must be a float.' % count
, '%s' % str(dspec) ])
else:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], spec list do not match any known pattern.' % count
, '%s' % str(dspec) ])
return
def checkDSpecDigital ( self, count, dspec ):
# if not isinstance(dspec[0],str):
# raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [0] (model name) is *not* a string.' % count
# , '%s' % str(dspec) ])
if not isinstance(dspec[1],str):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [1] (model name) is *not* a string.' % count
, '%s' % str(dspec) ])
return
def getCommonDSpec ( self, instanceName, specIndex ):
for dspec in self.devicesSpecs:
if dspec[AnalogDesign.SPEC_INSTANCE] == instanceName:
if specIndex < len(dspec):
return dspec[specIndex]
raise Error( 3, [ 'AnalogDesign.getDSpec(): Instance "{}" has not entry index {}' \
.format( instanceName, specIndex )
, '%s' % str(dspec) ])
raise Error( 3, [ 'AnalogDesign.getDSpec(): No instance "{}"'.format( instanceName ) ])
def getTransDSpec ( self, instanceName, specIndex ):
for dspec in self.devicesSpecs:
if dspec[AnalogDesign.SPEC_INSTANCE] == instanceName:
if not isderived(dspec[0],TransistorFamily):
raise Error( 3, [ 'AnalogDesign.getTransDSpec(): Instance "{}" is *not* a transistor ({})' \
.format( instanceName, type(dspec[0]).__name__ ) ])
if specIndex < len(dspec):
return dspec[specIndex]
raise Error( 3, [ 'AnalogDesign.getTransDSpec(): Instance "{}" has not entry index {}' \
.format( instanceName, specIndex )
, '%s' % str(dspec) ])
raise Error( 3, [ 'AnalogDesign.getTransDSpec(): No instance "{}"'.format( instanceName ) ])
def getCapasDSpec ( self, instanceName, specIndex ):
for dspec in self.devicesSpecs:
if dspec[AnalogDesign.SPEC_INSTANCE] == instanceName:
if not isderived(dspec[0],CapacitorFamily):
raise Error( 3, [ 'AnalogDesign.getCapaDSpec(): Instance "{}" is *not* a capacitor ({})' \
.format( instanceName, type(dspec[0]).__name__ ) ])
if specIndex < len(dspec):
return dspec[specIndex]
raise Error( 3, [ 'AnalogDesign.getCapaDSpec(): Instance "{}" has not entry index {}' \
.format( instanceName, specIndex )
, '%s' % str(dspec) ])
raise Error( 3, [ 'AnalogDesign.getCapaDSpec(): No instance "{}"'.format( instanceName ) ])
def getClass ( self, instName ): return self.getCommonDSpec( instName, AnalogDesign.SPEC_CLASS )
def getInstance ( self, instName ): return self.getCommonDSpec( instName, AnalogDesign.SPEC_INSTANCE )
def getStyle ( self, instName ): return self.getCommonDSpec( instName, AnalogDesign.SPEC_STYLE )
def getType ( self, instName ): return self.getCommonDSpec( instName, AnalogDesign.SPEC_TYPE )
def getTransW ( self, instName ): return self.getTransDSpec ( instName, AnalogDesign.SPEC_TRANS_W )
def getTransL ( self, instName ): return self.getTransDSpec ( instName, AnalogDesign.SPEC_TRANS_L )
def getTransM ( self, instName ): return self.getTransDSpec ( instName, AnalogDesign.SPEC_TRANS_M )
def getTransMInt ( self, instName ): return self.getTransDSpec ( instName, AnalogDesign.SPEC_TRANS_MINT )
def getTransDummy ( self, instName ): return self.getTransDSpec ( instName, AnalogDesign.SPEC_TRANS_DUMMY )
def getTransSFirst ( self, instName ): return self.getTransDSpec ( instName, AnalogDesign.SPEC_TRANS_SFIRST )
def getTransBulk ( self, instName ): return self.getTransDSpec ( instName, AnalogDesign.SPEC_TRANS_BULK )
def getTransBulk_Conn ( self, instName ): return self.getTransDSpec ( instName, AnalogDesign.SPEC_TRANS_BULK_CONN )
def getCapaC ( self, instName ): return self.getCapaDSpec ( instName, AnalogDesign.SPEC_CAPA_C )
def getCapaMatrix ( self, instName ): return self.getCapaDSpec ( instName, AnalogDesign.SPEC_CAPA_MATRIX )
def getCapaDummy ( self, instName ): return self.getCapaDSpec ( instName, AnalogDesign.SPEC_CAPA_DUMMY )
def getDTransParam ( self, instName, paramName ):
inst = self.cell.getInstance( instName )
if not inst:
raise Error( 3, [ 'AnalogDesign.getDTransParam(): No device "{}"'.format( instName ) ])
device = inst.getMasterCell()
if not issubclass(type(device),TransistorFamily):
raise Error( 3, [ 'AnalogDesign.getDTransParam(): Device "{}" is *not* a transistor ({})' \
.format( instName, type(device).__name__ ) ])
param = device.getParameter( paramName )
if not param:
raise Error( 3, [ 'AnalogDesign.getDTransParam(): Device "{}" has no parameter "{}"' \
.format( instName, paramName ) ])
return param
def getDCapaParam ( self, instName, paramName ):
inst = self.cell.getInstance( instName )
if not inst:
raise Error( 3, [ 'AnalogDesign.getDCapaParam(): No device "{}"'.format( instName ) ])
device = inst.getMasterCell()
if not issubclass(type(device),CapacitorFamily):
raise Error( 3, [ 'AnalogDesign.getDCapaParam(): Device "{}" is *not* a capaitor ({})' \
.format( instName, type(device).__name__ ) ])
param = device.getParameter( paramName )
if not param:
raise Error( 3, [ 'AnalogDesign.getDCapaParam(): Device "{}" has no parameter "{}"' \
.format( instName, paramName ) ])
return param
def getDTransW ( self, instName ): return self.getDTransParam( instName, 'W' )
def getDTransL ( self, instName ): return self.getDTransParam( instName, 'L' )
def getDTransM ( self, instName ): return self.getDTransParam( instName, 'M' )
def getDCapaC ( self, instName ): return self.getDCapaParam( instName, 'capacities' )
def getDCapaMatrix ( self, instName ): return self.getDCapaParam( instName, 'matrix' )
def getDevice ( self, instanceName ):
inst = self.cell.getInstance( instanceName )
if not inst:
raise Error( 3, [ 'AnalogDesign.getDevice(): No instance "{}"'.format( instanceName ) ])
return inst.getMasterCell()
def readParameters ( self, path ):
trace( 110, ',+', '\tReading Oceane parameters from \"%s\"\n' % path )
if not path: return
self.parameters.read( path );
for dspec in self.devicesSpecs:
if isinstance(dspec[0],Cell):
pass
elif issubclass(dspec[0],TransistorFamily):
Tname = dspec[1].split('_')[0]
Tparameters = self.parameters.getTransistor( Tname )
if not Tparameters:
raise Error( 3, [ 'AnalogDesign.readParameters(): Missing parameters for \"%s\".' % Tname ] )
continue
dspec[4] = toLength( Tparameters.W )
dspec[5] = toLength( Tparameters.L )
dspec[6] = Tparameters.M
trace( 110, '\t- \"%s\" : W:%f L:%f M:%d\n' % (Tname
,dspec[4]
,dspec[5]
,dspec[6]) )
elif issubclass(dspec[0],CapacitorFamily):
Cname = dspec[1]
Cparameters = self.parameters.getCapacitor( Cname )
if not Cparameters:
raise Error( 3, [ 'AnalogDesign.readParameters(): Missing parameters for capacity \"%s\".' % Cname ] )
continue
dspec[4] = Cparameters.C * 1e+12
trace( 110, '\t- \"%s\" : C:%fpF\n' % (Cname ,dspec[4]) )
elif issubclass(dspec[0],ResistorFamily):
print( WarningMessage( 'Resistor devices are not supported yet by Oceane parser (instance:"{}").'.format(dspec[1]) ))
else:
print( WarningMessage( 'Unsupported analog device type {0} (instance:"{1}").'.format(dspec[0],dspec[1]) ))
trace( 110, '-,' )
return
def doDevice ( self, count, dspec ):
self.checkBeginCell( 'AnalogDesign.doDevice()' )
if len(dspec) == 2:
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.PlacementStatus.UNPLACED )
self.__dict__[ dspec[1] ] = instance
else:
masterCell = dspec[0]
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] )
device.getParameter( 'Layout Styles' ).setValue( dspec[2] )
device.getParameter( 'W' ).setValue( toDbU(dspec[4]) )
device.getParameter( 'L' ).setValue( toDbU(dspec[5]) )
device.getParameter( 'M' ).setValue( dspec[6] )
device.setSourceFirst( dspec[9] )
device.setBulkType ( dspec[10] )
if (len(dspec) > 12): device.getParameter( 'NERC' ).setValue(int (dspec[12]))
if (len(dspec) > 13): device.getParameter( 'NIRC' ).setValue(int (dspec[13]))
if (len(dspec) > 14):
for wiringSpec in dspec[14].split(' '):
fields = wiringSpec.split('.')
if len(fields) > 1:
device.getParameter( fields[0]+'.t' ).setValue( fields[1] )
if not (dspec[7] is None): device.setMint ( dspec[7] )
if dspec[8]: device.setExternalDummy( dspec[8] )
elif isderived(dspec[0],CapacitorFamily):
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]) )
device = dspec[0].create( self.library, dspec[1], dspec[3], len(capaValues) )
device.getParameter( 'Layout Styles' ).setValue( dspec[2] )
device.getParameter( 'matrix' ).setMatrix( dspec[5] )
device.setDummy( dspec[6] )
for i in range(len(capaValues)):
device.getParameter( 'capacities' ).setValue( i, capaValues[i] )
elif isderived(dspec[0],ResistorFamily):
print( dspec )
device = dspec[0].create( self.library, dspec[1], dspec[3] )
device.getParameter( 'R' ).setValue( dspec[4] )
device.getParameter( 'W' ).setValue( toDbU(dspec[5]) )
device.getParameter( 'L' ).setValue( toDbU(dspec[6]) )
device.getParameter( 'bends' ).setValue( dspec[7] )
trace( 100, '\tW:{0}\n'.format(dspec[5]) )
trace( 100, '\tpW:{0}\n'.format(device.getParameter('W')) )
trace( 100, '\tbends:{0}\n'.format(dspec[7]) )
else:
raise ErrorMessage( 1, 'AnalogDesign.doDevice(): Unknown/unsupported device "%s".' % str(dspec[0]) )
self.generator.setDevice ( device )
self.generator.drawLayout()
instance = Instance.create( self.cell
, dspec[1]
, device
, Transformation()
, Instance.PlacementStatus.UNPLACED )
self.__dict__[ dspec[1] ] = instance
trace( 100, '\tAdd Instance:{0}\n'.format(dspec[1]) )
return
def doDevices ( self ):
trace( 110, ',+', '\tAnalogDesign.doDevices()\n' )
if not hasattr(self,'devicesSpecs'):
raise Error( 3, 'AnalogDesign.doDevices(): Mandatory attribute \"self.devicesSpecs\" has not been defined.' )
if not isinstance(self.devicesSpecs,list):
raise Error( 3, 'AnalogDesign.doDevices(): Attribute \"self.devicesSpecs\" *must* be a Python list.' )
count = 1
for dspec in self.devicesSpecs:
self.doDevice( count, dspec )
count += 1
trace( 110, '-,' )
return
def showNode ( self, node ):
lines = [ '{' ]
for key, value in node.items():
if key == 'children':
lines += [ "%20s { ... }" % "'children':" ]
else:
skey = "'%s':" % str(key)
lines += [ "%20s %s" % (skey,str(value)) ]
lines += [ '}' ]
return lines
def checkNode ( self, node, isRoot ):
if not isinstance(node,dict):
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): Node element is *not* a dict.'
] + self.showNode(node) )
if not 'type' in node:
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): Missing mandatory \"type\" key/element.'
] + self.showNode(node) )
nodeType = node['type']
if nodeType not in [VNode, HNode, DNode]:
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): \"type\" must be one of VNode, HNode or DNode.'
] + self.showNode(node) )
if nodeType == DNode:
if not 'device' in node:
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): Missing mandatory \"device\" key/element.'
] + self.showNode(node) )
if not isinstance(node['device'],str):
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): \"device\" value *must* be of type str.'
] + self.showNode(node) )
if not 'span' in node:
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): Missing mandatory \"span\" key/element.'
] + self.showNode(node) )
if not isinstance(node['span'],tuple) \
or len(node['span']) != 3 \
or not isinstance(node['span'][0],float) \
or not isinstance(node['span'][1],float) \
or not isinstance(node['span'][2],float):
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): \"span\" value *must* be a tuple of 3 floats.'
] + self.showNode(node) )
if not 'NF' in node:
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): Missing mandatory \"NF\" key/element.'
] + self.showNode(node) )
if not isinstance(node['NF'],int):
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): \"NF\" value *must* be of type int.'
] + self.showNode(node) )
else:
if isRoot:
if not 'toleranceRatioH' in node:
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): Missing mandatory \"toleranceRationH\" key/element in root node.'
] + self.showNode(node) )
if not 'toleranceRatioW' in node:
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): Missing mandatory \"toleranceRationW\" key/element in root node.'
] + self.showNode(node) )
if not 'toleranceBandH' in node:
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): Missing mandatory \"toleranceBandH\" key/element in root node.'
] + self.showNode(node) )
if not 'toleranceBandW' in node:
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): Missing mandatory \"toleranceBandW\" key/element in root node.'
] + self.showNode(node) )
if not 'children' in node:
print( Error( 3, [ 'AnalogDesign.doSlicingTree(): Suspicious root node without children.'
] + self.showNode(node) ))
if 'children' in node:
if not isinstance(node['children'],list):
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): \"children\" value *must* be of type list.' ]
+ self.showNode(node) )
if 'symmetries' in node:
symmetries = node['symmetries']
if not isinstance(symmetries,list):
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): \"symmetries\" value *must* be of type list.'
] + self.showNode(node) )
for i in range(len(symmetries)):
if not isinstance(symmetries[i],tuple) \
or len(symmetries[i]) != 2 \
or not isinstance(symmetries[i][0],int) \
or not isinstance(symmetries[i][1],int):
raise Error( 3, [ 'AnalogDesign.doSlicingTree(): \"symmetries\" entry [%d] *must* be a tuple of 2 int.' % i ]
+ self.showNode(node) )
return
def beginSlicingTree ( self ):
trace( 110, ',+', '\tAnalogDesign.beginSlicingTree()\n' )
return
def topNode ( self ): return self.stack[-1][0]
def topSymmetries ( self ): return self.stack[-1][1]
def topSymmetriesNet ( self ): return self.stack[-1][2]
def setToleranceRatioH ( self, u ): self.toleranceRatioH = toDbU(u)
def setToleranceRatioW ( self, u ): self.toleranceRatioW = toDbU(u)
def setToleranceBandH ( self, u ): self.toleranceBandH = toDbU(u)
def setToleranceBandW ( self, u ): self.toleranceBandW = toDbU(u)
def dupTolerances ( self, node ):
node.setToleranceRatioH( self.toleranceRatioH )
node.setToleranceRatioW( self.toleranceRatioW )
node.setToleranceBandH ( self.toleranceBandH )
node.setToleranceBandW ( self.toleranceBandW )
return
def pushNode ( self, node ):
trace( 110, ',+', '\tSlicingTree.pushNode() %s ' % str(node) )
parent = None
if len(self.stack):
parent = self.topNode()
parent.push_back( node )
trace( 110, '(parent id:%d)\n' % parent.getId() )
else:
trace( 110, '(Root)\n' )
self.slicingTree = node
node.setCell( self.cell )
self.stack.append( (node,[],[]) )
self.dupTolerances( node )
node.setRoutingGauge( self.rg )
#node.cprint()
return
def pushVNode ( self, alignment ):
self.pushNode( VSlicingNode.create( alignment ) )
return
def pushHNode ( self, alignment ):
self.pushNode( HSlicingNode.create( alignment ) )
return
def popNode ( self ):
for childIndex, copyIndex in self.topSymmetries():
self.topNode().addSymmetry( childIndex, copyIndex )
for type, net1, net2 in self.topSymmetriesNet():
if (net2 == None):
self.topNode().addSymmetryNet( type, net1 )
else:
self.topNode().addSymmetryNet( type, net1, net2 )
trace( 110, '-,', '\tSlicingTree.popNode() %s\n' % str(self.topNode()) )
if len(self.stack) == 1:
trace( 110, '\tAnalogDesign.endSlicingTree()\n' )
trace( 110, '-,', '\tSlicingTree %s stack size:%d\n' % (self.cell.getName(), len(self.stack)) )
#self.topNode().setCell( self.cell )
self.topNode().updateNetConstraints()
self.topNode().updateGlobalSize()
del self.stack[-1]
return
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 )
self.topNode().push_back( node )
trace( 110, '\tSlicingTree.addDevice() %s (parent id:%d)\n' % (str(node),self.topNode().getId()) )
#node.cprint()
return
def addHRail ( self, net, metal, npitch, cellName, instanceName ):
self.checkRail( net, metal, npitch, cellName, instanceName )
node = RHSlicingNode.create( net, DataBase.getDB().getTechnology().getLayer(metal), npitch, cellName, instanceName)
self.topNode().push_back( node )
trace( 110, '\tSlicingTree.addHRail() to %s\n' % (str(self.topNode())) )
#node.cprint()
return
def addVRail ( self, net, metal, npitch, cellName, instanceName ):
self.checkRail( net, metal, npitch, cellName, instanceName )
node = RVSlicingNode.create( net, DataBase.getDB().getTechnology().getLayer(metal), npitch, cellName, instanceName)
self.topNode().push_back( node )
trace( 110, '\tSlicingTree.addVRail() to %s\n' % (str(self.topNode())) )
#node.cprint()
return
def addSymmetry ( self, childIndex, copyIndex ):
self.topSymmetries().append( (childIndex,copyIndex) )
return
def addSymmetryNet ( self, type, net1, net2=None ):
self.topSymmetriesNet().append( (type, net1, net2) )
return
def endSlicingTree ( self ):
self.slicingTree.updateGlobalSize()
#bora = Bora.BoraEngine.get( self.cell )
#if not bora: bora = Bora.BoraEngine.create( self.cell )
#bora.updateSlicingTree()
return
def updatePlacement ( self, *args ):
if self.slicingTree:
bora = Bora.BoraEngine.get( self.cell )
if not bora: bora = Bora.BoraEngine.create( self.cell )
signatureMatched = True
if len(args) == 2: bora.updatePlacement( toDbU(args[0]), toDbU(args[1]) )
elif len(args) == 1: bora.updatePlacement( args[0] )
else: signatureMatched = False
#if signatureMatched:
# katana = Katana.KatanaEngine.get( self.cell )
# if katana:
# katana.loadGlobalRouting( Anabatic.EngineLoadGrByNet )
# katana.runNegociate( Katana.Flags.PairSymmetrics );
# #katana.destroy()
return