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 DataBase
|
||||
from Hurricane import Layer
|
||||
from helpers.io import ErrorMessage
|
||||
from helpers.io import catch, ErrorMessage, WarningMessage
|
||||
|
||||
|
||||
tech = None
|
||||
technoFile = '<technoFile has not been set>'
|
||||
Length = 0x0001
|
||||
Area = 0x0002
|
||||
|
@ -135,8 +136,36 @@ def _loadAnalogTechno ( techno, ruleTable ):
|
|||
|
||||
def loadAnalogTechno ( table, fromFile ):
|
||||
global technoFile
|
||||
global tech
|
||||
if not tech:
|
||||
tech = DataBase.getDB().getTechnology()
|
||||
technoFile = fromFile
|
||||
techno = DataBase.getDB().getTechnology()
|
||||
|
||||
_loadAnalogTechno( techno, table )
|
||||
_loadAnalogTechno( tech, table )
|
||||
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);
|
||||
} catch ( Error& e ) {
|
||||
if ( e.what() != "[ERROR] ApParser processed" )
|
||||
if ( e.what() != "[ERROR] ApParser processed" ) {
|
||||
cerr << e.what() << endl;
|
||||
cerr << "[ERROR] ApParser(): file " << _cellPath << ", line: " << _lineNumber << "." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
Go::enableAutoMaterialization();
|
||||
|
|
|
@ -182,7 +182,10 @@ namespace {
|
|||
defrSetSNetCbk ( _snetCbk );
|
||||
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
|
||||
char* defFile = NULL;
|
||||
long flags = 0;
|
||||
|
||||
if (PyArg_ParseTuple( args, "s:DefImport.load", &defFile )) {
|
||||
cell = DefImport::load( defFile, 0 );
|
||||
if (PyArg_ParseTuple( args, "s|l:DefImport.load", &defFile, &flags )) {
|
||||
cell = DefImport::load( defFile, flags );
|
||||
} else {
|
||||
PyErr_SetString ( ConstructorError, "DefImport.load(): Bad type or bad number of parameters." );
|
||||
return NULL;
|
||||
|
|
|
@ -137,6 +137,7 @@ namespace Hurricane {
|
|||
, _name (name)
|
||||
, _layerMap ()
|
||||
, _layerMaskMap ()
|
||||
, _layerAliases ()
|
||||
, _unitRules ()
|
||||
, _noLayerRules ()
|
||||
, _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);
|
||||
return (layer and dynamic_cast<BasicLayer*>(layer)) ? (BasicLayer*)layer : NULL;
|
||||
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::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
|
||||
{
|
||||
Layer* layer = getLayer(name);
|
||||
return (layer and dynamic_cast<RegularLayer*>(layer)) ? (RegularLayer*)layer : NULL;
|
||||
}
|
||||
{ return dynamic_cast<RegularLayer*>(getLayer( name )); }
|
||||
|
||||
|
||||
ViaLayer* Technology::getViaLayer ( const Name& name ) const
|
||||
{
|
||||
Layer* layer = getLayer(name);
|
||||
return (layer and dynamic_cast<ViaLayer*>(layer)) ? (ViaLayer*)layer : NULL;
|
||||
}
|
||||
{ return dynamic_cast<ViaLayer*>(getLayer( name )); }
|
||||
|
||||
|
||||
BasicLayers Technology::getBasicLayers () const
|
||||
|
@ -199,19 +216,6 @@ namespace Hurricane {
|
|||
{ 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
|
||||
{
|
||||
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()
|
||||
{
|
||||
Super::_postCreate();
|
||||
|
@ -623,9 +646,10 @@ namespace Hurricane {
|
|||
PhysicalRules& rules = ilayer->second;
|
||||
PhysicalRule search ( rule->getName(), "" );
|
||||
if (rules.find(&search) != rules.end()) {
|
||||
string ruleName = getString( rule->getName() );
|
||||
delete rule;
|
||||
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 );
|
||||
}
|
||||
|
@ -655,6 +679,15 @@ namespace Hurricane {
|
|||
const Layer* layer2 = getLayer(layer2Name);
|
||||
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 );
|
||||
TwoLayersRules::iterator ilp = _twoLayersRules.find( layerPair );
|
||||
if (ilp == _twoLayersRules.end()) {
|
||||
|
@ -667,7 +700,9 @@ namespace Hurricane {
|
|||
PhysicalRule search ( ruleName, "" );
|
||||
if (rules.find(&search) != rules.end()) {
|
||||
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 );
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ namespace Hurricane {
|
|||
typedef std::set<PhysicalRule* , RuleNameCompare> PhysicalRules;
|
||||
typedef std::map<const Hurricane::Layer* , PhysicalRules> OneLayerRules;
|
||||
typedef std::map<LayerPair , PhysicalRules> TwoLayersRules;
|
||||
typedef std::map<const Name , Hurricane::Layer*> LayerAliases;
|
||||
|
||||
public:
|
||||
// Sub-class : LayerMap.
|
||||
|
@ -100,11 +101,11 @@ namespace Hurricane {
|
|||
inline bool isMetal ( const Layer* ) const;
|
||||
inline DataBase* getDataBase () const;
|
||||
inline const Name& getName () const;
|
||||
inline Layer* getLayer ( const Name& ) const;
|
||||
Layer* getLayer ( const Name& ) const;
|
||||
BasicLayer* getBasicLayer ( const Name& ) const;
|
||||
RegularLayer* getRegularLayer ( const Name& ) const;
|
||||
ViaLayer* getViaLayer ( const Name& ) const;
|
||||
inline Layers getLayers () const;
|
||||
Layers getLayers () const;
|
||||
BasicLayers getBasicLayers () const;
|
||||
BasicLayers getBasicLayers ( const Layer::Mask& ) const;
|
||||
RegularLayers getRegularLayers () const;
|
||||
|
@ -137,6 +138,7 @@ namespace Hurricane {
|
|||
void setName ( const Name& );
|
||||
bool setSymbolicLayer ( const Name& );
|
||||
bool setSymbolicLayer ( const Layer* );
|
||||
bool addLayerAlias ( const Name& reference, const Name& alias );
|
||||
DeviceDescriptor* addDeviceDescriptor ( const Name& );
|
||||
ModelDescriptor* addModelDescriptor ( const Name& name
|
||||
, const Name& simul
|
||||
|
@ -181,6 +183,7 @@ namespace Hurricane {
|
|||
LayerMaskMap _layerMaskMap;
|
||||
Layer::Mask _cutMask;
|
||||
Layer::Mask _metalMask;
|
||||
LayerAliases _layerAliases;
|
||||
DeviceDescriptors _deviceDescriptors;
|
||||
ModelDescriptors _modelDescriptors;
|
||||
UnitRules _unitRules;
|
||||
|
@ -200,7 +203,6 @@ namespace Hurricane {
|
|||
inline bool Technology::isMetal ( const Layer* layer ) const { return _metalMask.contains(layer->getMask()); }
|
||||
inline DataBase* Technology::getDataBase () const { return _dataBase; }
|
||||
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 Technology::ModelDescriptors& Technology::getModelDescriptors () { return _modelDescriptors; }
|
||||
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 ) {
|
||||
cdebug_log(20,0) << "Technology.setSymbolicLayer()" << endl;
|
||||
|
||||
|
@ -443,6 +465,8 @@ extern "C" {
|
|||
, "Returns the collection of all RegularLayers." }
|
||||
, { "getViaLayers" , (PyCFunction)PyTechnology_getViaLayers , METH_NOARGS
|
||||
, "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
|
||||
, "Returns the metal layer immediatly above this one." }
|
||||
, { "getMetalBelow" , (PyCFunction)PyTechnology_getMetalBelow , METH_VARARGS
|
||||
|
|
|
@ -1,10 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Hurricane import DbU
|
||||
from Hurricane import 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'
|
||||
|
@ -91,18 +113,78 @@ class Rules ( object ):
|
|||
]
|
||||
|
||||
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' )
|
||||
self.dtr = dtr
|
||||
self.dtr = dtr
|
||||
|
||||
for rule in Rules.ruleSet: self.addAttr(rule)
|
||||
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 ):
|
||||
"""
|
||||
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) )
|
||||
#print( 'Rules.addAttr(): {} -> {}'.format( attribute, techAttribute ))
|
||||
value = None
|
||||
words = attribute.split( '_' )
|
||||
words = techAttribute.split( '_' )
|
||||
try:
|
||||
if len(words) == 1:
|
||||
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 Analog import Device
|
||||
import oroshi
|
||||
import oroshi.dtr
|
||||
|
||||
#helpers.setTraceLevel( 100 )
|
||||
|
||||
|
@ -212,13 +213,13 @@ class Bulk ( object ):
|
|||
|
||||
|
||||
def doLayout ( self ):
|
||||
active = DataBase.getDB().getTechnology().getLayer( 'active' )
|
||||
metal1 = DataBase.getDB().getTechnology().getLayer( 'metal1' )
|
||||
metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' )
|
||||
metal3 = DataBase.getDB().getTechnology().getLayer( 'metal3' )
|
||||
cut0 = DataBase.getDB().getTechnology().getLayer( 'cut0' )
|
||||
cut1 = DataBase.getDB().getTechnology().getLayer( 'cut1' )
|
||||
cut2 = DataBase.getDB().getTechnology().getLayer( 'cut2' )
|
||||
active = oroshi.rules.getRealLayer( 'active' )
|
||||
metal1 = oroshi.rules.getRealLayer( 'metal1' )
|
||||
metal2 = oroshi.rules.getRealLayer( 'metal2' )
|
||||
metal3 = oroshi.rules.getRealLayer( 'metal3' )
|
||||
cut0 = oroshi.rules.getRealLayer( 'cut0' )
|
||||
cut1 = oroshi.rules.getRealLayer( 'cut1' )
|
||||
cut2 = oroshi.rules.getRealLayer( 'cut2' )
|
||||
bulkNet = self.stack.bulkNet
|
||||
|
||||
self.computeContacts()
|
||||
|
@ -604,13 +605,13 @@ class Stack ( object ):
|
|||
if bulkType & 0x0008: self.flags |= Stack.WestBulk
|
||||
|
||||
if self.isNmos():
|
||||
self.tImplantLayer = DataBase.getDB().getTechnology().getLayer( 'nImplant' )
|
||||
self.bImplantLayer = DataBase.getDB().getTechnology().getLayer( 'pImplant' )
|
||||
self.tImplantLayer = oroshi.rules.getRealLayer( 'nImplant' )
|
||||
self.bImplantLayer = oroshi.rules.getRealLayer( 'pImplant' )
|
||||
self.wellLayer = None
|
||||
else:
|
||||
self.tImplantLayer = DataBase.getDB().getTechnology().getLayer( 'pImplant' )
|
||||
self.bImplantLayer = DataBase.getDB().getTechnology().getLayer( 'nImplant' )
|
||||
self.wellLayer = DataBase.getDB().getTechnology().getLayer( 'pWell' )
|
||||
self.tImplantLayer = oroshi.rules.getRealLayer( 'pImplant' )
|
||||
self.bImplantLayer = oroshi.rules.getRealLayer( 'nImplant' )
|
||||
self.wellLayer = oroshi.rules.getRealLayer( 'pWell' )
|
||||
|
||||
return
|
||||
|
||||
|
@ -1132,8 +1133,8 @@ class Stack ( object ):
|
|||
capSpacing = self.minSpacing_metal2 + self.minWidth_metal2//2
|
||||
capSpacing = max( capSpacing, self.minSpacing_metal3 + self.minWidth_metal3//2 )
|
||||
|
||||
metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' )
|
||||
metal3 = DataBase.getDB().getTechnology().getLayer( 'metal3' )
|
||||
metal2 = oroshi.rules.getRealLayer( 'metal2' )
|
||||
metal3 = oroshi.rules.getRealLayer( 'metal3' )
|
||||
trackNb = 0
|
||||
if self.topTracks: trackNb = len(self.topTracks)
|
||||
for i in range(trackNb):
|
||||
|
@ -1193,7 +1194,7 @@ class Stack ( object ):
|
|||
if not tImplantNet: tImplantNet = Net.create( self.device, 'nImplant' )
|
||||
tImplantNet.setAutomatic( True )
|
||||
|
||||
active = DataBase.getDB().getTechnology().getLayer( 'active' )
|
||||
active = oroshi.rules.getRealLayer( 'active' )
|
||||
width = self.w
|
||||
length = (self.NFs - 1) * self.gatePitch + 2*self.sideActiveWidth
|
||||
axis = width // 2
|
||||
|
@ -1225,13 +1226,13 @@ class Stack ( object ):
|
|||
def drawGate ( self, axis, wiring ):
|
||||
trace( 100, '\tStack.drawGate(): %s\n' % wiring )
|
||||
|
||||
gate = DataBase.getDB().getTechnology().getLayer( 'poly' )
|
||||
cut0 = DataBase.getDB().getTechnology().getLayer( 'cut0' )
|
||||
cut1 = DataBase.getDB().getTechnology().getLayer( 'cut1' )
|
||||
cut2 = DataBase.getDB().getTechnology().getLayer( 'cut2' )
|
||||
metal1 = DataBase.getDB().getTechnology().getLayer( 'metal1' )
|
||||
metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' )
|
||||
metal3 = DataBase.getDB().getTechnology().getLayer( 'metal3' )
|
||||
gate = oroshi.rules.getRealLayer( 'poly' )
|
||||
cut0 = oroshi.rules.getRealLayer( 'cut0' )
|
||||
cut1 = oroshi.rules.getRealLayer( 'cut1' )
|
||||
cut2 = oroshi.rules.getRealLayer( 'cut2' )
|
||||
metal1 = oroshi.rules.getRealLayer( 'metal1' )
|
||||
metal2 = oroshi.rules.getRealLayer( 'metal2' )
|
||||
metal3 = oroshi.rules.getRealLayer( 'metal3' )
|
||||
width = self.L
|
||||
|
||||
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' \
|
||||
% (wiring, DbU.getValueString(axis), DbU.getValueString(width), cols ) )
|
||||
|
||||
metal1 = DataBase.getDB().getTechnology().getLayer( 'metal1' )
|
||||
metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' )
|
||||
metal3 = DataBase.getDB().getTechnology().getLayer( 'metal3' )
|
||||
cut0 = DataBase.getDB().getTechnology().getLayer( 'cut0' )
|
||||
cut1 = DataBase.getDB().getTechnology().getLayer( 'cut1' )
|
||||
cut2 = DataBase.getDB().getTechnology().getLayer( 'cut2' )
|
||||
metal1 = oroshi.rules.getRealLayer( 'metal1' )
|
||||
metal2 = oroshi.rules.getRealLayer( 'metal2' )
|
||||
metal3 = oroshi.rules.getRealLayer( 'metal3' )
|
||||
cut0 = oroshi.rules.getRealLayer( 'cut0' )
|
||||
cut1 = oroshi.rules.getRealLayer( 'cut1' )
|
||||
cut2 = oroshi.rules.getRealLayer( 'cut2' )
|
||||
rows = max( 1, (self.w - 2*self.minEnclosure_active_cut0) // self.contactDiffPitch )
|
||||
ypitch = self.w // rows
|
||||
yoffset = self.activeOffsetY + ypitch//2
|
||||
|
@ -1332,7 +1333,7 @@ class Stack ( object ):
|
|||
xoffset = axis - (self.contactDiffPitch * (cols - 1))//2
|
||||
|
||||
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.inflate( self.minWidth_cut0 + self.minEnclosure_active_cut0 )
|
||||
|
|
Loading…
Reference in New Issue