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:
Jean-Paul Chaput 2023-01-05 16:58:49 +01:00
parent da56189d2e
commit 2501688dd1
9 changed files with 249 additions and 70 deletions

View File

@ -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

View File

@ -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();

View File

@ -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;
}
} }

View File

@ -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;

View File

@ -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 );
} }

View File

@ -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; }

View File

@ -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

View File

@ -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()

View File

@ -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 )