coriolis/oroshi/python/dtr.py

223 lines
8.1 KiB
Python

# -*- coding: utf-8 -*-
from ..Hurricane import DbU, DataBase
from ..helpers import trace
from ..helpers.io import ErrorMessage as Error
class Rules ( object ):
"""
The Rules object provides an easier access to the design rules stored
in the Technology databse. Instead of having to perform a function call
like:
.. code:: Python
tech = DataBase.getDB().getTechnology()
value = tech.getPhysicalRule( 'minEnclosure', 'pImplant', 'active' )
We can write access the rule as an attribute of the ``rule`` object.
.. code:: Python
import oroshi
value = oroshi.rules.minEnclosure_pImplant_active
Only the rules defined in the Rules.ruleSet list will be loaded.
"""
ruleSet = [ 'minSpacing_nWell'
, 'minWidth_pImplant'
, 'minSpacing_pImplant'
, 'minSpacing_rpolyh_pImplant'
, 'minEnclosure_pImplant_poly2con'
, 'minEnclosure_nImplant_active'
, 'minEnclosure_pImplant_active'
, 'minSpacing_nImplant_pImplant'
, 'minSpacing_cut0'
, 'minWidth_cut0'
, 'minWidth_active'
, 'minEnclosure_active_cut0'
, 'transistorMinL'
, 'transistorMinW'
, 'minSpacing_poly'
, 'minGateSpacing_poly'
, 'minSpacing_poly_active'
, 'minExtension_active_poly'
, 'minExtension_poly_active'
, 'minEnclosure_poly_cut0'
, 'minSpacing_cut0_poly'
, 'minWidth_cut0'
, 'minSpacing_cut0_active'
, 'minWidth_metal1'
, 'minSpacing_metal1'
, 'minEnclosure_metal1_cut0'
, 'minEnclosure_metal1_cut1'
, 'minWidth_cut1'
, 'minSpacing_cut1'
, 'minWidth_metal2'
, 'minSpacing_metal2'
, 'minEnclosure_metal2_cut1'
, 'minEnclosure_metal2_cut2'
, 'minWidth_cut2'
, 'minSpacing_cut2'
, 'minWidth_cut1'
, 'minSpacing_cut1'
, 'minWidth_metal3'
, 'minSpacing_metal3'
, 'minSpacingWide1_metal3'
, 'minEnclosure_metal3_cut2'
, 'minSpacingOnMetBot_cut2'
, 'minSpacingOnMetCap_cut2'
, 'maxWidth_metcap'
, 'minSpacing_metbot'
, 'minSpacing_cut1_metcap'
, 'minSpacing_cut2_metcap'
, 'minEnclosure_metbot_metcap'
, 'minEnclosure_metbot_cut1'
, 'minEnclosure_metbot_cut2'
, 'minEnclosure_metcap_cut2'
, 'minWidth_metcap'
, 'minWidth_metcapdum'
, 'minWidth_cpoly'
, 'minWidth_poly2'
, 'minWidth_rpolyh'
, 'minWidthHighPrec_rpolyh'
, 'minSpacing_cpoly'
, 'minSpacing_poly2'
, 'minSpacing_rpolyh'
, 'minSpacing_cut0_cpoly'
, 'minSpacing_diff_poly2'
, 'minSpacing_poly_poly2'
, 'minEnclosure_poly_cpoly'
, 'minEnclosure_cpoly_cut0'
, 'minEnclosure_poly2_cut0'
, 'MIMCap'
, 'PIPCap'
, 'MIMPerimeterCap'
, 'PIPPerimeterCap'
, 'RPOLYHSheetRes'
, 'RPOLY2PHSheetRes'
, 'MET1RPOLYHContRes'
, 'minWidth_hres'
, 'minSpacing_hres'
, 'minEnclosure_hres_poly2'
, 'minSpacing_hres_poly1'
, 'minSpacing_hres_poly2'
, 'minSpacing_hres_active'
, 'corrFactor90'
, 'corrFactor135'
, 'minRpolyhSquares'
]
def __init__ ( self ):
"""
Create an empty rule set. The rules must be loaded afterwards by calling
``Rules.load()``.
"""
trace( 100, '\tRules.__init__()\n' )
self.dtr = None
def isLoaded ( self ):
"""Tells if the rules have already been loaded."""
return self.dtr is not None
def load ( self, dtr ):
"""
Load the rule set from the technology into the Rules object.
.. note:: The ``dtr`` parameter is just another name for the currently
used Hurricane::Technology.
"""
trace( 100, '\tRules.load()\n' )
if self.dtr:
print( Error( 1, 'Rules.load(): Attempt to load rules from DTR a second time (ignored).' ))
return
self.dtr = dtr
for rule in Rules.ruleSet: self.addAttr(rule)
def getRealLayer ( self, stdName ):
"""
Get a Layer object by it's name. The alias translation from generic
names is used to return the real technology name.
For example:
================== ===================
Generic Layer Name SkyWater 130nm Name
================== ===================
nWell nwm
active difftap
pImplant psdm
cut0 licon
metal1 li
cut1 via
metal2 metal1
================== ===================
"""
return self.dtr.getLayer( stdName )
def attrTranslate ( self, attribute ):
"""
Translate a rule complete name, given in ``attribute``, using the *generic*
layer names into another string, using the target technology layer names.
For example, for SkyWater 130nm: ::
minEnclosure_pImplant_active => minSpacing_psdm_difftap
"""
words = attribute.split( '_' )
translateds = [ words[0] ]
for word in words[1:]:
realLayer = self.getRealLayer( word )
if realLayer is None:
print( Error( 1, 'rules.attrTranslate(): Unable to translate generic layer "{}".' \
.format( word )))
realLayerName = word
else:
realLayerName = realLayer.getName()
translateds.append( realLayerName )
return '_'.join( translateds )
def addAttr ( self, attribute ):
"""
Add a new attribute into the dictionnary of rule set. The attribute fields,
separated by '_' are broken down to get the corresponding rule in the
technology and be set as value of said attribute.
The attribute is the concatenation of the rule name and the various layers
it applies on. For example: ::
(minEnclosure, pImplant, active) => 'minEnclosure_pImplant_active'
"""
techAttribute = self.attrTranslate( attribute )
if attribute in self.__dict__: return
#print( 'Rules.addAttr(): {} -> {}'.format( attribute, techAttribute ))
value = None
words = techAttribute.split( '_' )
try:
if len(words) == 1:
if words[0].endswith('Cap' ): value = self.dtr.getUnitRule( words[0] ).getDoubleValue()
elif words[0].endswith('ContRes' ): value = self.dtr.getUnitRule( words[0] ).getDoubleValue()
elif words[0].endswith('Res' ): value = self.dtr.getUnitRule( words[0] ).getDoubleValue()
elif words[0].endswith('ctor90' ): value = self.dtr.getUnitRule( words[0] ).getDoubleValue()
elif words[0].endswith('ctor135' ): value = self.dtr.getUnitRule( words[0] ).getDoubleValue()
elif words[0].endswith('quares' ): value = self.dtr.getUnitRule( words[0] ).getDoubleValue()
if (value is None) and len(words) < 4:
rule = self.dtr.getPhysicalRule( *tuple(words) )
if rule.isDouble():
value = rule.getDoubleValue()
#print( 'Accessed value (Unit):{}'.format(value) )
else:
value = rule.getValue()
#print( 'Accessed value (DbU):{}'.format(DbU.getValueString(value)) )
except Exception as e:
print( e )
if not value is None:
self.__dict__[attribute] = value
return