Add support for layers alias names. Bug in _addPhysicalrule().
* New: In Technology, in order to support symbolic technology on top of a real technology using non-generic layer names, it comes in handy to be able to define layer alias names. Generic *real* layer names could be defined as alias over the technology specific ones. Then, we can build the symbolic layers upon the generic names (so *that* part of the init code can be shared between techs). Adds Technology::addLayerAlias() The semantic of Technology::getLayer() changes a little, it return the techno layer associtated to the name *or* the aliased name. * Bug: In Technology::_addPhysicalRule(), in case of a rule redefinition, we were using it's name *after* the deletion of the rule object. Nasty crash. Improve the error message by giving the name of the conflicting rule. * In CRL/helpers.analogtechno, add an addDevice() function to load analogic devices descriptors (copied from the old init system). * In CRL/ApParser, if an exception is catched, tells in which file and line it did occur. * In Oroshi/dtr.Rules, add a translation step to get the rule names from the technology. From generic names to actual technology layer names. Add some documentation. * In Oroshi/stack.Stack, get the layers names through dtr.Rules to get the layers names translated.
This commit is contained in:
parent
da56189d2e
commit
2501688dd1
|
@ -22,9 +22,10 @@ import Hurricane
|
||||||
from Hurricane import DbU
|
from Hurricane import DbU
|
||||||
from Hurricane import DataBase
|
from Hurricane import DataBase
|
||||||
from Hurricane import Layer
|
from Hurricane import Layer
|
||||||
from helpers.io import ErrorMessage
|
from helpers.io import catch, ErrorMessage, WarningMessage
|
||||||
|
|
||||||
|
|
||||||
|
tech = None
|
||||||
technoFile = '<technoFile has not been set>'
|
technoFile = '<technoFile has not been set>'
|
||||||
Length = 0x0001
|
Length = 0x0001
|
||||||
Area = 0x0002
|
Area = 0x0002
|
||||||
|
@ -135,8 +136,36 @@ def _loadAnalogTechno ( techno, ruleTable ):
|
||||||
|
|
||||||
def loadAnalogTechno ( table, fromFile ):
|
def loadAnalogTechno ( table, fromFile ):
|
||||||
global technoFile
|
global technoFile
|
||||||
|
global tech
|
||||||
|
if not tech:
|
||||||
|
tech = DataBase.getDB().getTechnology()
|
||||||
technoFile = fromFile
|
technoFile = fromFile
|
||||||
techno = DataBase.getDB().getTechnology()
|
_loadAnalogTechno( tech, table )
|
||||||
|
|
||||||
_loadAnalogTechno( techno, table )
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def addDevice ( **kw ):
|
||||||
|
global tech
|
||||||
|
if not tech:
|
||||||
|
tech = DataBase.getDB().getTechnology()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if 'name' in kw:
|
||||||
|
devDesc = tech.addDeviceDescriptor( kw['name'] )
|
||||||
|
if 'spice' in kw: devDesc.setSpiceFilePath( kw['spice'] )
|
||||||
|
if 'connectors' in kw:
|
||||||
|
for connector in kw['connectors']:
|
||||||
|
devDesc.addConnector( connector )
|
||||||
|
else:
|
||||||
|
print( WarningMessage( 'common.addDevice(): Missing connectors on device "{}".' \
|
||||||
|
.format(kw['name'])))
|
||||||
|
if 'layouts' in kw:
|
||||||
|
for layout in kw['layouts']:
|
||||||
|
devDesc.addLayout( layout[0], layout[1] )
|
||||||
|
else:
|
||||||
|
print( WarningMessage( 'common.addDevice(): Missing layouts on device "{}".' \
|
||||||
|
.format( kw['name'] )))
|
||||||
|
except Exception as e:
|
||||||
|
catch( e )
|
||||||
|
return
|
||||||
|
|
||||||
|
|
|
@ -846,8 +846,10 @@ namespace {
|
||||||
|
|
||||||
placeNets(_cell);
|
placeNets(_cell);
|
||||||
} catch ( Error& e ) {
|
} catch ( Error& e ) {
|
||||||
if ( e.what() != "[ERROR] ApParser processed" )
|
if ( e.what() != "[ERROR] ApParser processed" ) {
|
||||||
cerr << e.what() << endl;
|
cerr << e.what() << endl;
|
||||||
|
cerr << "[ERROR] ApParser(): file " << _cellPath << ", line: " << _lineNumber << "." << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Go::enableAutoMaterialization();
|
Go::enableAutoMaterialization();
|
||||||
|
|
|
@ -182,7 +182,10 @@ namespace {
|
||||||
defrSetSNetCbk ( _snetCbk );
|
defrSetSNetCbk ( _snetCbk );
|
||||||
defrSetPathCbk ( _pathCbk );
|
defrSetPathCbk ( _pathCbk );
|
||||||
|
|
||||||
if (DataBase::getDB()->getTechnology()->getName() == "Sky130") _flags |= Sky130;
|
if (DataBase::getDB()->getTechnology()->getName() == "Sky130") {
|
||||||
|
cmess1 << " - Enabling SkyWater 130nm harness hacks." << endl;
|
||||||
|
_flags |= Sky130;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -63,9 +63,10 @@ extern "C" {
|
||||||
|
|
||||||
HTRY
|
HTRY
|
||||||
char* defFile = NULL;
|
char* defFile = NULL;
|
||||||
|
long flags = 0;
|
||||||
|
|
||||||
if (PyArg_ParseTuple( args, "s:DefImport.load", &defFile )) {
|
if (PyArg_ParseTuple( args, "s|l:DefImport.load", &defFile, &flags )) {
|
||||||
cell = DefImport::load( defFile, 0 );
|
cell = DefImport::load( defFile, flags );
|
||||||
} else {
|
} else {
|
||||||
PyErr_SetString ( ConstructorError, "DefImport.load(): Bad type or bad number of parameters." );
|
PyErr_SetString ( ConstructorError, "DefImport.load(): Bad type or bad number of parameters." );
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -137,6 +137,7 @@ namespace Hurricane {
|
||||||
, _name (name)
|
, _name (name)
|
||||||
, _layerMap ()
|
, _layerMap ()
|
||||||
, _layerMaskMap ()
|
, _layerMaskMap ()
|
||||||
|
, _layerAliases ()
|
||||||
, _unitRules ()
|
, _unitRules ()
|
||||||
, _noLayerRules ()
|
, _noLayerRules ()
|
||||||
, _oneLayerRules ()
|
, _oneLayerRules ()
|
||||||
|
@ -162,25 +163,41 @@ namespace Hurricane {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BasicLayer* Technology::getBasicLayer ( const Name& name ) const
|
Layer* Technology::getLayer ( const Layer::Mask& mask, bool useSymbolic ) const
|
||||||
{
|
{
|
||||||
Layer* layer = getLayer(name);
|
Layer* layer = NULL;
|
||||||
return (layer and dynamic_cast<BasicLayer*>(layer)) ? (BasicLayer*)layer : NULL;
|
LayerMaskMap::const_iterator lb = _layerMaskMap.lower_bound( mask );
|
||||||
|
LayerMaskMap::const_iterator ub = _layerMaskMap.upper_bound( mask );
|
||||||
|
for ( ; lb != ub ; lb++ ) {
|
||||||
|
layer = lb->second;
|
||||||
|
if (not useSymbolic or layer->isSymbolic()) return layer;
|
||||||
|
}
|
||||||
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Layer* Technology::getLayer ( const Name& name ) const
|
||||||
|
{
|
||||||
|
Layer* layer = _layerMap.getElement(name);
|
||||||
|
if (layer) return layer;
|
||||||
|
|
||||||
|
auto ialias = _layerAliases.find( name );
|
||||||
|
if (ialias != _layerAliases.end()) return ialias->second;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BasicLayer* Technology::getBasicLayer ( const Name& name ) const
|
||||||
|
{ return dynamic_cast<BasicLayer*>(getLayer( name )); }
|
||||||
|
|
||||||
|
|
||||||
RegularLayer* Technology::getRegularLayer ( const Name& name ) const
|
RegularLayer* Technology::getRegularLayer ( const Name& name ) const
|
||||||
{
|
{ return dynamic_cast<RegularLayer*>(getLayer( name )); }
|
||||||
Layer* layer = getLayer(name);
|
|
||||||
return (layer and dynamic_cast<RegularLayer*>(layer)) ? (RegularLayer*)layer : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ViaLayer* Technology::getViaLayer ( const Name& name ) const
|
ViaLayer* Technology::getViaLayer ( const Name& name ) const
|
||||||
{
|
{ return dynamic_cast<ViaLayer*>(getLayer( name )); }
|
||||||
Layer* layer = getLayer(name);
|
|
||||||
return (layer and dynamic_cast<ViaLayer*>(layer)) ? (ViaLayer*)layer : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BasicLayers Technology::getBasicLayers () const
|
BasicLayers Technology::getBasicLayers () const
|
||||||
|
@ -199,19 +216,6 @@ namespace Hurricane {
|
||||||
{ return SubTypeCollection<Layer*, ViaLayer*>(getLayers()); }
|
{ return SubTypeCollection<Layer*, ViaLayer*>(getLayers()); }
|
||||||
|
|
||||||
|
|
||||||
Layer* Technology::getLayer ( const Layer::Mask& mask, bool useSymbolic ) const
|
|
||||||
{
|
|
||||||
Layer* layer = NULL;
|
|
||||||
LayerMaskMap::const_iterator lb = _layerMaskMap.lower_bound( mask );
|
|
||||||
LayerMaskMap::const_iterator ub = _layerMaskMap.upper_bound( mask );
|
|
||||||
for ( ; lb != ub ; lb++ ) {
|
|
||||||
layer = lb->second;
|
|
||||||
if (not useSymbolic or layer->isSymbolic()) return layer;
|
|
||||||
}
|
|
||||||
return layer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Layer* Technology::getMetalAbove ( const Layer* layer, bool useSymbolic ) const
|
Layer* Technology::getMetalAbove ( const Layer* layer, bool useSymbolic ) const
|
||||||
{
|
{
|
||||||
if (not layer) return NULL;
|
if (not layer) return NULL;
|
||||||
|
@ -338,6 +342,25 @@ namespace Hurricane {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Technology::addLayerAlias ( const Name& reference, const Name& alias )
|
||||||
|
{
|
||||||
|
if (getLayer(alias)) {
|
||||||
|
cerr << Error( "Technology::addAlias(): Alias name \"%s\" already defined."
|
||||||
|
, getString(alias).c_str() ) << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Layer* referenceLayer = getLayer( reference );
|
||||||
|
if (not referenceLayer) {
|
||||||
|
cerr << Error( "Technology::addAlias(): Reference layer \"%s\" does not exists (yet?)."
|
||||||
|
, getString(reference).c_str() ) << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_layerAliases.insert( make_pair( alias, referenceLayer ));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Technology::_postCreate()
|
void Technology::_postCreate()
|
||||||
{
|
{
|
||||||
Super::_postCreate();
|
Super::_postCreate();
|
||||||
|
@ -623,9 +646,10 @@ namespace Hurricane {
|
||||||
PhysicalRules& rules = ilayer->second;
|
PhysicalRules& rules = ilayer->second;
|
||||||
PhysicalRule search ( rule->getName(), "" );
|
PhysicalRule search ( rule->getName(), "" );
|
||||||
if (rules.find(&search) != rules.end()) {
|
if (rules.find(&search) != rules.end()) {
|
||||||
|
string ruleName = getString( rule->getName() );
|
||||||
delete rule;
|
delete rule;
|
||||||
throw Error( "Technology::addPhysicalRule(): Attempt to redefine rule \"%s\" for layer \"%s\"."
|
throw Error( "Technology::addPhysicalRule(): Attempt to redefine rule \"%s\" for layer \"%s\"."
|
||||||
, getString(rule->getName()).c_str(), layerStr.c_str() );
|
, ruleName.c_str(), layerStr.c_str() );
|
||||||
}
|
}
|
||||||
rules.insert( rule );
|
rules.insert( rule );
|
||||||
}
|
}
|
||||||
|
@ -655,6 +679,15 @@ namespace Hurricane {
|
||||||
const Layer* layer2 = getLayer(layer2Name);
|
const Layer* layer2 = getLayer(layer2Name);
|
||||||
LayerPair layerPair ( layer1, layer2 );
|
LayerPair layerPair ( layer1, layer2 );
|
||||||
|
|
||||||
|
if (not layer1)
|
||||||
|
throw Error( "Technology::addPhysicalRule(): Unknown layer1 rule \"%s\" for (\"%s\",\"%s\")."
|
||||||
|
, ruleNameStr.c_str(), layer1Str.c_str(), layer2Str.c_str()
|
||||||
|
);
|
||||||
|
if (not layer2)
|
||||||
|
throw Error( "Technology::addPhysicalRule(): Unknown layer2 rule \"%s\" for (\"%s\",\"%s\")."
|
||||||
|
, ruleNameStr.c_str(), layer1Str.c_str(), layer2Str.c_str()
|
||||||
|
);
|
||||||
|
|
||||||
PhysicalRule* rule = new PhysicalRule ( ruleName, reference );
|
PhysicalRule* rule = new PhysicalRule ( ruleName, reference );
|
||||||
TwoLayersRules::iterator ilp = _twoLayersRules.find( layerPair );
|
TwoLayersRules::iterator ilp = _twoLayersRules.find( layerPair );
|
||||||
if (ilp == _twoLayersRules.end()) {
|
if (ilp == _twoLayersRules.end()) {
|
||||||
|
@ -667,7 +700,9 @@ namespace Hurricane {
|
||||||
PhysicalRule search ( ruleName, "" );
|
PhysicalRule search ( ruleName, "" );
|
||||||
if (rules.find(&search) != rules.end()) {
|
if (rules.find(&search) != rules.end()) {
|
||||||
delete rule;
|
delete rule;
|
||||||
throw Error( "Technology::addPhysicalRule(): Attempt to redefine rule \"%s\"." , ruleNameStr.c_str() );
|
throw Error( "Technology::addPhysicalRule(): Attempt to redefine rule \"%s\" for (\"%s\",\"%s\")."
|
||||||
|
, ruleNameStr.c_str(), layer1Str.c_str(), layer2Str.c_str()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
rules.insert( rule );
|
rules.insert( rule );
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ namespace Hurricane {
|
||||||
typedef std::set<PhysicalRule* , RuleNameCompare> PhysicalRules;
|
typedef std::set<PhysicalRule* , RuleNameCompare> PhysicalRules;
|
||||||
typedef std::map<const Hurricane::Layer* , PhysicalRules> OneLayerRules;
|
typedef std::map<const Hurricane::Layer* , PhysicalRules> OneLayerRules;
|
||||||
typedef std::map<LayerPair , PhysicalRules> TwoLayersRules;
|
typedef std::map<LayerPair , PhysicalRules> TwoLayersRules;
|
||||||
|
typedef std::map<const Name , Hurricane::Layer*> LayerAliases;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Sub-class : LayerMap.
|
// Sub-class : LayerMap.
|
||||||
|
@ -100,11 +101,11 @@ namespace Hurricane {
|
||||||
inline bool isMetal ( const Layer* ) const;
|
inline bool isMetal ( const Layer* ) const;
|
||||||
inline DataBase* getDataBase () const;
|
inline DataBase* getDataBase () const;
|
||||||
inline const Name& getName () const;
|
inline const Name& getName () const;
|
||||||
inline Layer* getLayer ( const Name& ) const;
|
Layer* getLayer ( const Name& ) const;
|
||||||
BasicLayer* getBasicLayer ( const Name& ) const;
|
BasicLayer* getBasicLayer ( const Name& ) const;
|
||||||
RegularLayer* getRegularLayer ( const Name& ) const;
|
RegularLayer* getRegularLayer ( const Name& ) const;
|
||||||
ViaLayer* getViaLayer ( const Name& ) const;
|
ViaLayer* getViaLayer ( const Name& ) const;
|
||||||
inline Layers getLayers () const;
|
Layers getLayers () const;
|
||||||
BasicLayers getBasicLayers () const;
|
BasicLayers getBasicLayers () const;
|
||||||
BasicLayers getBasicLayers ( const Layer::Mask& ) const;
|
BasicLayers getBasicLayers ( const Layer::Mask& ) const;
|
||||||
RegularLayers getRegularLayers () const;
|
RegularLayers getRegularLayers () const;
|
||||||
|
@ -137,6 +138,7 @@ namespace Hurricane {
|
||||||
void setName ( const Name& );
|
void setName ( const Name& );
|
||||||
bool setSymbolicLayer ( const Name& );
|
bool setSymbolicLayer ( const Name& );
|
||||||
bool setSymbolicLayer ( const Layer* );
|
bool setSymbolicLayer ( const Layer* );
|
||||||
|
bool addLayerAlias ( const Name& reference, const Name& alias );
|
||||||
DeviceDescriptor* addDeviceDescriptor ( const Name& );
|
DeviceDescriptor* addDeviceDescriptor ( const Name& );
|
||||||
ModelDescriptor* addModelDescriptor ( const Name& name
|
ModelDescriptor* addModelDescriptor ( const Name& name
|
||||||
, const Name& simul
|
, const Name& simul
|
||||||
|
@ -181,6 +183,7 @@ namespace Hurricane {
|
||||||
LayerMaskMap _layerMaskMap;
|
LayerMaskMap _layerMaskMap;
|
||||||
Layer::Mask _cutMask;
|
Layer::Mask _cutMask;
|
||||||
Layer::Mask _metalMask;
|
Layer::Mask _metalMask;
|
||||||
|
LayerAliases _layerAliases;
|
||||||
DeviceDescriptors _deviceDescriptors;
|
DeviceDescriptors _deviceDescriptors;
|
||||||
ModelDescriptors _modelDescriptors;
|
ModelDescriptors _modelDescriptors;
|
||||||
UnitRules _unitRules;
|
UnitRules _unitRules;
|
||||||
|
@ -200,7 +203,6 @@ namespace Hurricane {
|
||||||
inline bool Technology::isMetal ( const Layer* layer ) const { return _metalMask.contains(layer->getMask()); }
|
inline bool Technology::isMetal ( const Layer* layer ) const { return _metalMask.contains(layer->getMask()); }
|
||||||
inline DataBase* Technology::getDataBase () const { return _dataBase; }
|
inline DataBase* Technology::getDataBase () const { return _dataBase; }
|
||||||
inline const Name& Technology::getName () const { return _name; }
|
inline const Name& Technology::getName () const { return _name; }
|
||||||
inline Layer* Technology::getLayer ( const Name& name ) const { return _layerMap.getElement(name); }
|
|
||||||
inline Layers Technology::getLayers () const { return getCollection(&_layerMaskMap); }
|
inline Layers Technology::getLayers () const { return getCollection(&_layerMaskMap); }
|
||||||
inline Technology::ModelDescriptors& Technology::getModelDescriptors () { return _modelDescriptors; }
|
inline Technology::ModelDescriptors& Technology::getModelDescriptors () { return _modelDescriptors; }
|
||||||
inline Technology::LayerMap& Technology::_getLayerMap () { return _layerMap; }
|
inline Technology::LayerMap& Technology::_getLayerMap () { return _layerMap; }
|
||||||
|
|
|
@ -190,6 +190,28 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject* PyTechnology_addLayerAlias ( PyTechnology *self, PyObject* args )
|
||||||
|
{
|
||||||
|
cdebug_log(20,0) << "Technology.addLayerAlias()" << endl;
|
||||||
|
|
||||||
|
METHOD_HEAD("Technology.addLayerAlias()")
|
||||||
|
bool rvalue = false;
|
||||||
|
HTRY
|
||||||
|
char* reference = NULL;
|
||||||
|
char* alias = NULL;
|
||||||
|
if (PyArg_ParseTuple(args,"ss:Technology.addLayerAlias", &reference, &alias)) {
|
||||||
|
rvalue = techno->addLayerAlias( reference, alias );
|
||||||
|
} else {
|
||||||
|
PyErr_SetString( ConstructorError, "Hurricane.addLayerAlias(str,str): Bad parameter(s) type." );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
HCATCH
|
||||||
|
|
||||||
|
if (rvalue) Py_RETURN_TRUE;
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject* PyTechnology_setSymbolicLayer ( PyTechnology *self, PyObject* args ) {
|
static PyObject* PyTechnology_setSymbolicLayer ( PyTechnology *self, PyObject* args ) {
|
||||||
cdebug_log(20,0) << "Technology.setSymbolicLayer()" << endl;
|
cdebug_log(20,0) << "Technology.setSymbolicLayer()" << endl;
|
||||||
|
|
||||||
|
@ -443,6 +465,8 @@ extern "C" {
|
||||||
, "Returns the collection of all RegularLayers." }
|
, "Returns the collection of all RegularLayers." }
|
||||||
, { "getViaLayers" , (PyCFunction)PyTechnology_getViaLayers , METH_NOARGS
|
, { "getViaLayers" , (PyCFunction)PyTechnology_getViaLayers , METH_NOARGS
|
||||||
, "Returns the collection of all BasicLayers." }
|
, "Returns the collection of all BasicLayers." }
|
||||||
|
, { "addLayerAlias" , (PyCFunction)PyTechnology_addLayerAlias , METH_VARARGS
|
||||||
|
, "Add an alias name to a layer." }
|
||||||
, { "getMetalAbove" , (PyCFunction)PyTechnology_getMetalAbove , METH_VARARGS
|
, { "getMetalAbove" , (PyCFunction)PyTechnology_getMetalAbove , METH_VARARGS
|
||||||
, "Returns the metal layer immediatly above this one." }
|
, "Returns the metal layer immediatly above this one." }
|
||||||
, { "getMetalBelow" , (PyCFunction)PyTechnology_getMetalBelow , METH_VARARGS
|
, { "getMetalBelow" , (PyCFunction)PyTechnology_getMetalBelow , METH_VARARGS
|
||||||
|
|
|
@ -1,10 +1,32 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from Hurricane import DbU
|
from Hurricane import DbU
|
||||||
|
from Hurricane import DataBase
|
||||||
from helpers import trace
|
from helpers import trace
|
||||||
|
from helpers.io import ErrorMessage as Error
|
||||||
|
|
||||||
|
|
||||||
class Rules ( object ):
|
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'
|
ruleSet = [ 'minSpacing_nWell'
|
||||||
, 'minWidth_pImplant'
|
, 'minWidth_pImplant'
|
||||||
|
@ -91,18 +113,78 @@ class Rules ( object ):
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__ ( self, dtr ):
|
def __init__ ( self, dtr ):
|
||||||
|
"""
|
||||||
|
Load the rule set from the technology into the Rules object.
|
||||||
|
|
||||||
|
.. note:: The ``dtr`` parameter is just aother name for the currently
|
||||||
|
used Hurricane::Technology.
|
||||||
|
"""
|
||||||
trace( 100, '\tRules.__init__()\n' )
|
trace( 100, '\tRules.__init__()\n' )
|
||||||
self.dtr = dtr
|
self.dtr = dtr
|
||||||
|
|
||||||
for rule in Rules.ruleSet: self.addAttr(rule)
|
for rule in Rules.ruleSet: self.addAttr(rule)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
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 ):
|
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
|
if attribute in self.__dict__: return
|
||||||
|
|
||||||
#print( 'Rules.addAttr(): {}'.format(attribute) )
|
#print( 'Rules.addAttr(): {} -> {}'.format( attribute, techAttribute ))
|
||||||
value = None
|
value = None
|
||||||
words = attribute.split( '_' )
|
words = techAttribute.split( '_' )
|
||||||
try:
|
try:
|
||||||
if len(words) == 1:
|
if len(words) == 1:
|
||||||
if words[0].endswith('Cap' ): value = self.dtr.getUnitRule( words[0] ).getDoubleValue()
|
if words[0].endswith('Cap' ): value = self.dtr.getUnitRule( words[0] ).getDoubleValue()
|
||||||
|
|
|
@ -19,6 +19,7 @@ from helpers.io import ErrorMessage as Error
|
||||||
from helpers import trace
|
from helpers import trace
|
||||||
from Analog import Device
|
from Analog import Device
|
||||||
import oroshi
|
import oroshi
|
||||||
|
import oroshi.dtr
|
||||||
|
|
||||||
#helpers.setTraceLevel( 100 )
|
#helpers.setTraceLevel( 100 )
|
||||||
|
|
||||||
|
@ -212,13 +213,13 @@ class Bulk ( object ):
|
||||||
|
|
||||||
|
|
||||||
def doLayout ( self ):
|
def doLayout ( self ):
|
||||||
active = DataBase.getDB().getTechnology().getLayer( 'active' )
|
active = oroshi.rules.getRealLayer( 'active' )
|
||||||
metal1 = DataBase.getDB().getTechnology().getLayer( 'metal1' )
|
metal1 = oroshi.rules.getRealLayer( 'metal1' )
|
||||||
metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' )
|
metal2 = oroshi.rules.getRealLayer( 'metal2' )
|
||||||
metal3 = DataBase.getDB().getTechnology().getLayer( 'metal3' )
|
metal3 = oroshi.rules.getRealLayer( 'metal3' )
|
||||||
cut0 = DataBase.getDB().getTechnology().getLayer( 'cut0' )
|
cut0 = oroshi.rules.getRealLayer( 'cut0' )
|
||||||
cut1 = DataBase.getDB().getTechnology().getLayer( 'cut1' )
|
cut1 = oroshi.rules.getRealLayer( 'cut1' )
|
||||||
cut2 = DataBase.getDB().getTechnology().getLayer( 'cut2' )
|
cut2 = oroshi.rules.getRealLayer( 'cut2' )
|
||||||
bulkNet = self.stack.bulkNet
|
bulkNet = self.stack.bulkNet
|
||||||
|
|
||||||
self.computeContacts()
|
self.computeContacts()
|
||||||
|
@ -604,13 +605,13 @@ class Stack ( object ):
|
||||||
if bulkType & 0x0008: self.flags |= Stack.WestBulk
|
if bulkType & 0x0008: self.flags |= Stack.WestBulk
|
||||||
|
|
||||||
if self.isNmos():
|
if self.isNmos():
|
||||||
self.tImplantLayer = DataBase.getDB().getTechnology().getLayer( 'nImplant' )
|
self.tImplantLayer = oroshi.rules.getRealLayer( 'nImplant' )
|
||||||
self.bImplantLayer = DataBase.getDB().getTechnology().getLayer( 'pImplant' )
|
self.bImplantLayer = oroshi.rules.getRealLayer( 'pImplant' )
|
||||||
self.wellLayer = None
|
self.wellLayer = None
|
||||||
else:
|
else:
|
||||||
self.tImplantLayer = DataBase.getDB().getTechnology().getLayer( 'pImplant' )
|
self.tImplantLayer = oroshi.rules.getRealLayer( 'pImplant' )
|
||||||
self.bImplantLayer = DataBase.getDB().getTechnology().getLayer( 'nImplant' )
|
self.bImplantLayer = oroshi.rules.getRealLayer( 'nImplant' )
|
||||||
self.wellLayer = DataBase.getDB().getTechnology().getLayer( 'pWell' )
|
self.wellLayer = oroshi.rules.getRealLayer( 'pWell' )
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -1132,8 +1133,8 @@ class Stack ( object ):
|
||||||
capSpacing = self.minSpacing_metal2 + self.minWidth_metal2//2
|
capSpacing = self.minSpacing_metal2 + self.minWidth_metal2//2
|
||||||
capSpacing = max( capSpacing, self.minSpacing_metal3 + self.minWidth_metal3//2 )
|
capSpacing = max( capSpacing, self.minSpacing_metal3 + self.minWidth_metal3//2 )
|
||||||
|
|
||||||
metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' )
|
metal2 = oroshi.rules.getRealLayer( 'metal2' )
|
||||||
metal3 = DataBase.getDB().getTechnology().getLayer( 'metal3' )
|
metal3 = oroshi.rules.getRealLayer( 'metal3' )
|
||||||
trackNb = 0
|
trackNb = 0
|
||||||
if self.topTracks: trackNb = len(self.topTracks)
|
if self.topTracks: trackNb = len(self.topTracks)
|
||||||
for i in range(trackNb):
|
for i in range(trackNb):
|
||||||
|
@ -1193,7 +1194,7 @@ class Stack ( object ):
|
||||||
if not tImplantNet: tImplantNet = Net.create( self.device, 'nImplant' )
|
if not tImplantNet: tImplantNet = Net.create( self.device, 'nImplant' )
|
||||||
tImplantNet.setAutomatic( True )
|
tImplantNet.setAutomatic( True )
|
||||||
|
|
||||||
active = DataBase.getDB().getTechnology().getLayer( 'active' )
|
active = oroshi.rules.getRealLayer( 'active' )
|
||||||
width = self.w
|
width = self.w
|
||||||
length = (self.NFs - 1) * self.gatePitch + 2*self.sideActiveWidth
|
length = (self.NFs - 1) * self.gatePitch + 2*self.sideActiveWidth
|
||||||
axis = width // 2
|
axis = width // 2
|
||||||
|
@ -1225,13 +1226,13 @@ class Stack ( object ):
|
||||||
def drawGate ( self, axis, wiring ):
|
def drawGate ( self, axis, wiring ):
|
||||||
trace( 100, '\tStack.drawGate(): %s\n' % wiring )
|
trace( 100, '\tStack.drawGate(): %s\n' % wiring )
|
||||||
|
|
||||||
gate = DataBase.getDB().getTechnology().getLayer( 'poly' )
|
gate = oroshi.rules.getRealLayer( 'poly' )
|
||||||
cut0 = DataBase.getDB().getTechnology().getLayer( 'cut0' )
|
cut0 = oroshi.rules.getRealLayer( 'cut0' )
|
||||||
cut1 = DataBase.getDB().getTechnology().getLayer( 'cut1' )
|
cut1 = oroshi.rules.getRealLayer( 'cut1' )
|
||||||
cut2 = DataBase.getDB().getTechnology().getLayer( 'cut2' )
|
cut2 = oroshi.rules.getRealLayer( 'cut2' )
|
||||||
metal1 = DataBase.getDB().getTechnology().getLayer( 'metal1' )
|
metal1 = oroshi.rules.getRealLayer( 'metal1' )
|
||||||
metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' )
|
metal2 = oroshi.rules.getRealLayer( 'metal2' )
|
||||||
metal3 = DataBase.getDB().getTechnology().getLayer( 'metal3' )
|
metal3 = oroshi.rules.getRealLayer( 'metal3' )
|
||||||
width = self.L
|
width = self.L
|
||||||
|
|
||||||
if wiring.isTop(): ytarget = self.getTopTrackY( wiring.topTrack )
|
if wiring.isTop(): ytarget = self.getTopTrackY( wiring.topTrack )
|
||||||
|
@ -1318,12 +1319,12 @@ class Stack ( object ):
|
||||||
trace( 100, '\tStack.drawSourceDrain(): %s @%s width:%s NRC=%d\n' \
|
trace( 100, '\tStack.drawSourceDrain(): %s @%s width:%s NRC=%d\n' \
|
||||||
% (wiring, DbU.getValueString(axis), DbU.getValueString(width), cols ) )
|
% (wiring, DbU.getValueString(axis), DbU.getValueString(width), cols ) )
|
||||||
|
|
||||||
metal1 = DataBase.getDB().getTechnology().getLayer( 'metal1' )
|
metal1 = oroshi.rules.getRealLayer( 'metal1' )
|
||||||
metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' )
|
metal2 = oroshi.rules.getRealLayer( 'metal2' )
|
||||||
metal3 = DataBase.getDB().getTechnology().getLayer( 'metal3' )
|
metal3 = oroshi.rules.getRealLayer( 'metal3' )
|
||||||
cut0 = DataBase.getDB().getTechnology().getLayer( 'cut0' )
|
cut0 = oroshi.rules.getRealLayer( 'cut0' )
|
||||||
cut1 = DataBase.getDB().getTechnology().getLayer( 'cut1' )
|
cut1 = oroshi.rules.getRealLayer( 'cut1' )
|
||||||
cut2 = DataBase.getDB().getTechnology().getLayer( 'cut2' )
|
cut2 = oroshi.rules.getRealLayer( 'cut2' )
|
||||||
rows = max( 1, (self.w - 2*self.minEnclosure_active_cut0) // self.contactDiffPitch )
|
rows = max( 1, (self.w - 2*self.minEnclosure_active_cut0) // self.contactDiffPitch )
|
||||||
ypitch = self.w // rows
|
ypitch = self.w // rows
|
||||||
yoffset = self.activeOffsetY + ypitch//2
|
yoffset = self.activeOffsetY + ypitch//2
|
||||||
|
@ -1332,7 +1333,7 @@ class Stack ( object ):
|
||||||
xoffset = axis - (self.contactDiffPitch * (cols - 1))//2
|
xoffset = axis - (self.contactDiffPitch * (cols - 1))//2
|
||||||
|
|
||||||
if self.w < 2*self.minEnclosure_active_cut0 + self.minWidth_cut0:
|
if self.w < 2*self.minEnclosure_active_cut0 + self.minWidth_cut0:
|
||||||
active = DataBase.getDB().getTechnology().getLayer( 'active' )
|
active = oroshi.rules.getRealLayer( 'active' )
|
||||||
|
|
||||||
box = Box( xoffset, yoffset, xoffset + (cols-1)*xpitch, yoffset )
|
box = Box( xoffset, yoffset, xoffset + (cols-1)*xpitch, yoffset )
|
||||||
box.inflate( self.minWidth_cut0 + self.minEnclosure_active_cut0 )
|
box.inflate( self.minWidth_cut0 + self.minEnclosure_active_cut0 )
|
||||||
|
|
Loading…
Reference in New Issue