First stage in analog capacitor integration

* Bug: In Technology::getPhysicalRule(), if the named layerdo not exists,
    throw an exception instead of silently putting a NULL pointer inside
    a rule.
* New: In Hurricane/Analog, new parameters classes for capacitor devices:
    - Analog::Matrix, a matrix of null or positives integers to encode
      capacitor matrix matching.
    - Analog::Capacities, a list of float values for all component of a
      multi-capacitor.
* New: In Hurricane::Script, add a "getFileName()" method to get the full
    path name of the Python module.
* Change: In Analog::LayoutGenerator, completly remove the logger utility
    as it is no longer used. Simply print error messages instead.
* Change: In Analog::MetaCapacitor, rename top & bottom plate 'T' & 'B'.
    Accessors renamed in "getTopPlate()" & "getBottomPlate()".
* New: In Analog::MultiCapacitor, complete rewrite. Makes use of the
    new parameters "capacities" and "matrix". Dynamically generates it's
    terminals as we do not know beforehand how many capacitors could be
    put in it.
* Bug: In isobar/PyHurricane.h, in Type object definition, do not prepend
    a "Py" to class name (so the keep the C++ name).
* Change: In CRL/etc/scn6m_deep_09/devices.py, add entry for the new
    capacitor generator.
* New: In oroshi/python/ParamsMatrix, add a "family" entry in the [0,0]
    element to distinguish between transistor, capacitor and resistor.
    (this is the matrix of values returned to the LayoutGenerator after
     device generation).
      Now have one "setGlobalParams()" function per family.
* New: In oroshi/python/Rules.py, added DTR rules needed by capacitors.
    Catch exceptions if something wrong append when we extract the rules
    from the technology.
* New: In Bora, the devices are no longer *only* transistors, so the
    possibles configurations are no longer defined only by a number of
    fingers. We must be able to support any kind of range of configuration.
      So the explicit range of number of fingers is replaced by a base
    class ParameterRange, and it's derived classes:
      - Bora::StepParameterRange, to encode the possible number of fingers
        of a transistor (the former only possibility).
      - Bora::MatrixParameterRange, to encode all the possible matching
        scheme for a capacitor. As there is no way to compress it, this
	is a vector of Matrix (from Analog).
* Change: In Bora::DSlicingNode::_place(), the ParameterRange has to be set
    on the right configuration (through the index) before being called.
      The generation parameters are taken from the active item in the
    ParameterRange.
* Change: In Bora::NodeSets::create(), iterate over the ParameterRange
    to build all the configuration. Adjustement to the routing gauge
    pitchs are moved into the DBoxSet CTOR to save a lot of code.
      Semantic change: the index in the NodeSets is now the index in
    the associated ParameterRange and no longer the number of fingers
    of a transistor.
      Check that the ParameterRange dynamic class is consitent with the
    device family.
* Change: In Bora::DBoxSet, same semantic change as for NodeSets, the
    number of finger become an index in ParameterRange.
      In DBoxSet::create(), now also perform the abutment box adjustement
    to the RoutingGauge, if possible.
* New: In Karakaze/python/AnalogDesign.py, add support for Capacitor
    devices.
This commit is contained in:
Jean-Paul Chaput 2019-11-07 17:05:49 +01:00
parent ef0f6f771a
commit 8035b31f27
57 changed files with 4583 additions and 613 deletions

View File

@ -16,6 +16,8 @@
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
#include "hurricane/Cell.h"
#include "crlcore/RoutingGauge.h"
#include "bora/BoxSet.h"
@ -84,6 +86,13 @@ namespace Bora {
}
size_t BoxSet::getIndex () const
{
cerr << Warning( "BoxSet::getIndex(): Only DBoxSet has parameter range indexes." ) << endl;
return 0;
}
void BoxSet::destroy()
{ delete this; }
@ -265,9 +274,9 @@ namespace Bora {
int DBoxSet::_countAll = 0;
DBoxSet::DBoxSet ( DbU::Unit height, DbU::Unit width, int nfing )
DBoxSet::DBoxSet ( DbU::Unit height, DbU::Unit width, size_t index )
: BoxSet( height, width )
, _nfing(nfing)
, _index(index)
{
++_count;
++_countAll;
@ -276,7 +285,7 @@ namespace Bora {
DBoxSet::DBoxSet ( DBoxSet* boxSet )
: BoxSet( boxSet )
, _nfing( boxSet->getNFing() )
, _index( boxSet->getIndex() )
{ }
@ -286,15 +295,40 @@ namespace Bora {
}
DBoxSet* DBoxSet::create ( DbU::Unit height, DbU::Unit width, int nfing )
DBoxSet* DBoxSet::create ( Cell* cell, int index, CRL::RoutingGauge* rg )
{
return new DBoxSet( height, width, nfing );
DbU::Unit abHeight = cell->getAbutmentBox().getHeight();
DbU::Unit abWidth = cell->getAbutmentBox().getWidth();
if (rg) {
DbU::Unit h2pitch = rg->getHorizontalPitch()*2;
DbU::Unit v2pitch = rg->getVerticalPitch ()*2;
if (abHeight % h2pitch) {
cerr << Warning( "DBoxSet::create(): The height of device \"%s\" (%s) is not pitched on 2*%s (adjusted)."
, getString(cell->getName()).c_str()
, DbU::getValueString(abHeight).c_str()
, DbU::getValueString(h2pitch ).c_str()
) << endl;
abHeight += h2pitch - (abHeight % h2pitch);
}
if (abWidth % v2pitch) {
cerr << Warning( "DBoxSet::create(): The width of device \"%s\" (%s) is not pitched on 2*%s (adjusted)."
, getString(cell->getName()).c_str()
, DbU::getValueString(abWidth).c_str()
, DbU::getValueString(v2pitch).c_str()
) << endl;
abWidth += v2pitch - (abWidth % v2pitch);
}
}
return new DBoxSet( abHeight, abWidth, index );
}
DBoxSet* DBoxSet::clone ()
{
return DBoxSet::create( getHeight(), getWidth(), getNFing() );
return new DBoxSet( getHeight(), getWidth(), getNFing() );
}

View File

@ -10,6 +10,7 @@
${PYTHON_INCLUDE_PATH}
)
set( includes bora/Constants.h
bora/ParameterRange.h
bora/BoxSet.h
bora/NodeSets.h
bora/HVSetState.h
@ -27,7 +28,10 @@
bora/BoraEngine.h
)
set( pyIncludes bora/PySlicingNode.h
set( pyIncludes bora/PyParameterRange.h
bora/PyStepParameterRange.h
bora/PyMatrixParameterRange.h
bora/PySlicingNode.h
bora/PyDSlicingNode.h
bora/PyHSlicingNode.h
bora/PyVSlicingNode.h
@ -44,6 +48,7 @@
)
set( cpps BoxSet.cpp
NodeSets.cpp
ParameterRange.cpp
HVSetState.cpp
SlicingNode.cpp
HVSlicingNode.cpp
@ -62,7 +67,10 @@
SlicingWidget.cpp
GraphicBoraEngine.cpp
)
set( pyCpps PySlicingNode.cpp
set( pyCpps PyParameterRange.cpp
PyStepParameterRange.cpp
PyMatrixParameterRange.cpp
PySlicingNode.cpp
PyDSlicingNode.cpp
PyHSlicingNode.cpp
PyRHSlicingNode.cpp

View File

@ -23,6 +23,7 @@
#include "hurricane/analog/CommonSourcePair.h"
#include "hurricane/analog/DifferentialPair.h"
#include "hurricane/analog/LayoutGenerator.h"
#include "hurricane/analog/MultiCapacitor.h"
#include "anabatic/Session.h"
#include "bora/DSlicingNode.h"
@ -35,10 +36,12 @@ namespace Bora {
using Hurricane::Transformation;
using Analog::Device;
using Analog::FormFactorParameter;
using Analog::MatrixParameter;
using Analog::TransistorFamily;
using Analog::Transistor;
using Analog::CommonSourcePair;
using Analog::DifferentialPair;
using Analog::MultiCapacitor;
using Analog::LayoutGenerator;
using Anabatic::Session;
@ -117,23 +120,11 @@ namespace Bora {
{ return (_boxSet) ? _boxSet->getNFing() : 1 ; }
double DSlicingNode::getStartParameter () const
{ return _nodeSets->getStartParameter(); }
double DSlicingNode::getStepParameter () const
{ return _nodeSets->getStepParameter(); }
double DSlicingNode::getCountParameter () const
{ return _nodeSets->getCountParameter(); }
void DSlicingNode::_place( DbU::Unit x, DbU::Unit y, bool replace )
{
cdebug_log(536,1) << "DSlicingNode::_place(DbU::Unit,DbU::Unit,bool replace)" << endl;
if (replace){
if (replace) {
SlicingNode::place( x, y );
if (_instance) {
Cell* model = _instance->getMasterCell();
@ -150,16 +141,43 @@ namespace Bora {
Device* device = dynamic_cast<Device*>( model );
if (device) {
unique_ptr<LayoutGenerator> layoutGenerator ( new LayoutGenerator() );
TransistorFamily* tf = dynamic_cast<TransistorFamily*>( device );
if (tf) {
tf->setNfing( getNFing() );
FormFactorParameter* pff = NULL;
if ((pff = dynamic_cast<FormFactorParameter*>(tf->getParameter("M"))) != NULL)
pff->setValue( tf->getNfing() );
shared_ptr<LayoutGenerator> layoutGenerator ( new LayoutGenerator() );
layoutGenerator->setDevice (device);
StepParameterRange* stepRange = dynamic_cast<StepParameterRange*>( getNodeSets()->getRange() );
if (not stepRange) {
throw Error( "DSlicingNode::_place(): Device \"%s\" must be associated with a StepParameterRange argument instead of %s."
, getString(device->getName()).c_str()
, getString(stepRange).c_str()
);
}
stepRange->setIndex( getBoxSet()->getIndex() );
int nfingers = stepRange->getValue();
tf->setNfing( nfingers );
layoutGenerator->setDevice ( device );
layoutGenerator->drawLayout();
} else {
MultiCapacitor* mcapacitor = dynamic_cast<MultiCapacitor *>( device );
MatrixParameterRange* matrixRange = dynamic_cast<MatrixParameterRange*>( getNodeSets()->getRange() );
if (mcapacitor) {
if (not matrixRange) {
throw Error( "DSlicingNode::create(): Device \"%s\" must be associated with a MatrixParameterRange argument instead of %s."
, getString(mcapacitor->getName()).c_str()
, getString(matrixRange).c_str()
);
}
matrixRange->setIndex( getBoxSet()->getIndex() );
MatrixParameter* mp = NULL;
if ( (mp = dynamic_cast<MatrixParameter*>(mcapacitor->getParameter("Matrix"))) != NULL )
mp->setMatrix( &matrixRange->getValue() );
layoutGenerator->setDevice( mcapacitor );
layoutGenerator->drawLayout();
}
}
}
_instance->setTransformation ( Transformation( _x - model->getAbutmentBox().getXMin()

View File

@ -18,6 +18,7 @@
#include "hurricane/Warning.h"
#include "hurricane/analog/Device.h"
#include "hurricane/analog/TransistorFamily.h"
#include "hurricane/analog/MultiCapacitor.h"
#include "hurricane/analog/LayoutGenerator.h"
#include "crlcore/RoutingGauge.h"
@ -28,115 +29,92 @@ namespace Bora {
using namespace Analog;
NodeSets::NodeSets ( double start, double step, double count )
NodeSets::NodeSets ( ParameterRange* range )
: _boxSets()
, _start ( start )
, _step ( step )
, _count ( count )
{ }
, _range (NULL)
{
if (range) {
_range = range->clone();
_range->setNested();
}
}
NodeSets::NodeSets ( const NodeSets* other )
: _boxSets( other->getBoxSets() )
, _start ( other->getStartParameter() )
, _step ( other->getStepParameter() )
, _count ( other->getCountParameter() )
{ }
NodeSets::NodeSets ( const NodeSets* from )
: _boxSets( from->getBoxSets() )
, _range (NULL)
{
if (from->_range) {
_range = from->_range->clone();
_range->setNested();
}
}
NodeSets::~NodeSets ()
{ }
{
if (_range) delete _range;
}
NodeSets* NodeSets::create ( Cell* cell
, double start
, double step
, double count
NodeSets* NodeSets::create ( Cell* cell
, ParameterRange* range
, CRL::RoutingGauge* rg )
{
NodeSets* nodeset = new NodeSets( start, step, count );
NodeSets* nodeset = new NodeSets( range );
if (not cell) return nodeset;
Device* dev = dynamic_cast<Device*>( cell );
if (dev) {
unique_ptr<LayoutGenerator> layoutGenerator ( new LayoutGenerator() );
TransistorFamily* device = dynamic_cast<TransistorFamily *>( cell );
StepParameterRange* stepRange = dynamic_cast<StepParameterRange*>( nodeset->getRange() );
if (device) {
//cdebug_log(536,0) << "createNodeSets for an Analog Device" << endl;
TransistorFamily* tf = dynamic_cast<TransistorFamily*>(dev);
for ( int i = 0; i < count; ++i ) {
tf->setNfing( start + i*step );
if (not stepRange) {
throw Error( "NodeSets::create(): Device \"%s\" must be associated with a StepParameterRange argument instead of %s."
, getString(device->getName()).c_str()
, getString(stepRange).c_str()
);
}
stepRange->reset();
do {
device->setNfing( stepRange->getValue() );
FormFactorParameter* pff = NULL;
if ( (pff = dynamic_cast<FormFactorParameter*>(tf->getParameter("M"))) != NULL )
pff->setValue( tf->getNfing() );
auto_ptr<LayoutGenerator> layoutGenerator ( new LayoutGenerator() );
layoutGenerator->setDevice( dev );
layoutGenerator->setDevice( device );
layoutGenerator->drawLayout();
if (rg) {
float h2pitch = rg->getHorizontalPitch()*2;
float v2pitch = rg->getVerticalPitch ()*2;
float h = dev->getAbutmentBox().getHeight();
float w = dev->getAbutmentBox().getWidth();
nodeset->push_back( DBoxSet::create( device, stepRange->getIndex(), rg ) );
if (fmod(h,h2pitch) > 1e-06) {
cerr << Warning( "NodeSets::create(): The height of device \"%s\" (%s) is not pitched on 2*%s (adjusted)."
, getString(dev->getName()).c_str()
, DbU::getValueString(dev->getAbutmentBox().getWidth()).c_str()
, DbU::getValueString(rg->getHorizontalPitch()*2).c_str()
) << endl;
}
if (fmod(w,v2pitch) > 1e-06) {
cerr << Warning( "NodeSets::create(): The width of device \"%s\" (%s) is not pitched on 2*%s (adjusted)."
, getString(dev->getName()).c_str()
, DbU::getValueString(dev->getAbutmentBox().getWidth()).c_str()
, DbU::getValueString(rg->getVerticalPitch()*2).c_str()
) << endl;
}
nodeset->push_back( DBoxSet::create( ceil(h/h2pitch)*h2pitch
, ceil(w/v2pitch)*v2pitch
, start + i*step
) );
} else {
nodeset->push_back( DBoxSet::create( dev->getAbutmentBox().getHeight()
, dev->getAbutmentBox().getWidth()
, start + i*step
) );
}
}
stepRange->progress();
} while ( stepRange->isValid() );
} else {
//cdebug_log(536,0) << "createNodeSets for a Digital Device: " << cell << endl;
if (rg) {
DbU::Unit h2pitch = rg->getHorizontalPitch()*2;
DbU::Unit v2pitch = rg->getVerticalPitch ()*2;
DbU::Unit h = cell->getAbutmentBox().getHeight();
DbU::Unit w = cell->getAbutmentBox().getWidth();
MultiCapacitor* mcapacitor = dynamic_cast<MultiCapacitor *>( cell );
MatrixParameterRange* matrixRange = dynamic_cast<MatrixParameterRange*>( nodeset->getRange() );
if (h % h2pitch) {
cerr << Warning( "NodeSets::create(): The height of device \"%s\" (%s) is not pitched on %s*2 (adjusted)."
, getString(cell->getName()).c_str()
, DbU::getValueString(cell->getAbutmentBox().getHeight()).c_str()
, DbU::getValueString(rg->getHorizontalPitch()).c_str()
) << endl;
}
if (w % v2pitch) {
cerr << Warning( "NodeSets::create(): The width of device \"%s\" (%s) is not pitched on %s*2 (adjusted)."
, getString(cell->getName()).c_str()
, DbU::getValueString(cell->getAbutmentBox().getWidth()).c_str()
, DbU::getValueString(rg->getVerticalPitch()).c_str()
) << endl;
}
if (mcapacitor) {
if (not matrixRange) {
throw Error( "NodeSets::create(): Device \"%s\" must be associated with a MatrixParameterRange argument instead of %s."
, getString(mcapacitor->getName()).c_str()
, getString(stepRange).c_str()
);
nodeset->push_back( DBoxSet::create( ceil(h/h2pitch)*h2pitch
, ceil(w/v2pitch)*v2pitch
) );
matrixRange->reset();
do {
MatrixParameter* mp = NULL;
if ( (mp = dynamic_cast<MatrixParameter*>(mcapacitor->getParameter("Matrix"))) != NULL )
mp->setMatrix( &matrixRange->getValue() );
layoutGenerator->setDevice( mcapacitor );
layoutGenerator->drawLayout();
nodeset->push_back( DBoxSet::create( mcapacitor, matrixRange->getIndex(), rg ) );
matrixRange->progress();
} while ( matrixRange->isValid() );
}
} else {
nodeset->push_back( DBoxSet::create( cell->getAbutmentBox().getHeight()
, cell->getAbutmentBox().getWidth()
) );
nodeset->push_back( DBoxSet::create( cell, 0, rg ) );
}
}
@ -355,7 +333,7 @@ namespace Bora {
NodeSets* NodeSets::clone()
{
NodeSets* nodesets = new NodeSets( _start, _step, _count );
NodeSets* nodesets = new NodeSets( _range );
for ( BoxSet* bs : _boxSets ) _boxSets.push_back( bs->clone() );
return nodesets;
}

158
bora/src/ParameterRange.cpp Normal file
View File

@ -0,0 +1,158 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2016-2019, 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 |
// | =============================================================== |
// | C++ Module : "./arameterRange.cpp" |
// +-----------------------------------------------------------------+
#include "bora/ParameterRange.h"
namespace Bora {
using namespace std;
// -------------------------------------------------------------------
// Class : "ParameterRange"
ParameterRange::ParameterRange ()
: _flags(0), _index(0)
{ }
ParameterRange::~ParameterRange ()
{ }
string ParameterRange::_getString () const
{ return "<" + _getTypeName() + ">"; }
Record* ParameterRange::_getRecord () const
{
Record* record = new Record( getString(this) );
record->add( getSlot("_index", _index) );
return record;
}
// -------------------------------------------------------------------
// Class : "StepParameterRange"
StepParameterRange::StepParameterRange ( double start, double step, double count )
: Super()
, _start(start)
, _step (step )
, _count(count)
{ }
StepParameterRange::~StepParameterRange ()
{ }
StepParameterRange* StepParameterRange::clone () const
{
return new StepParameterRange( _start, _step, _count );
}
size_t StepParameterRange::getSize () const
{ return size_t(_count); }
double StepParameterRange::getValue () const
{ return _start + getIndex() * _step; }
string StepParameterRange::_getTypeName () const
{ return "StepParameterRange"; }
string StepParameterRange::_getString () const
{
string s = Super::_getString();
s.insert( s.length() - 1, " [" + getString(_start));
s.insert( s.length() - 1, " +" + getString(_step ));
s.insert( s.length() - 1, " ," + getString(_count) + "]");
return s;
}
Record* StepParameterRange::_getRecord () const
{
Record* record = Super::_getRecord();
if (record) {
record->add( getSlot("_start", _start) );
record->add( getSlot("_step" , _step ) );
record->add( getSlot("_count", _count) );
}
return record;
}
// -------------------------------------------------------------------
// Class : "MatrixParameterRange"
MatrixParameterRange::MatrixParameterRange ()
: Super()
, _matrixes()
{ }
MatrixParameterRange::~MatrixParameterRange ()
{ }
MatrixParameterRange* MatrixParameterRange::clone () const
{
MatrixParameterRange* param = new MatrixParameterRange();
param->copy( this );
return param;
}
size_t MatrixParameterRange::getSize () const
{ return _matrixes.size(); }
const Matrix& MatrixParameterRange::getValue () const
{ return _matrixes[ getIndex() ]; }
string MatrixParameterRange::_getTypeName () const
{ return "MatrixParameterRange"; }
string MatrixParameterRange::_getString () const
{
string s = Super::_getString();
s.insert( s.length() - 1, " [" + getString(getSize()) + "]");
return s;
}
Record* MatrixParameterRange::_getRecord () const
{
Record* record = Super::_getRecord();
if (record) {
record->add( getSlot("_matrixes", &_matrixes) );
}
return record;
}
} // Bora namespace.

View File

@ -16,6 +16,9 @@
#include "hurricane/isobar/PyHurricane.h"
#include "hurricane/isobar/PyCell.h"
#include "bora/PyParameterRange.h"
#include "bora/PyStepParameterRange.h"
#include "bora/PyMatrixParameterRange.h"
#include "bora/PySlicingNode.h"
#include "bora/PyHSlicingNode.h"
#include "bora/PyVSlicingNode.h"
@ -66,6 +69,9 @@ extern "C" {
{
cdebug.log(61) << "initBora()" << endl;
PyParameterRange_LinkPyType();
PyStepParameterRange_LinkPyType();
PyMatrixParameterRange_LinkPyType();
PySlicingNode_LinkPyType();
PyHSlicingNode_LinkPyType();
PyVSlicingNode_LinkPyType();
@ -75,15 +81,18 @@ extern "C" {
PyBoraEngine_LinkPyType();
PyGraphicBoraEngine_LinkPyType();
PYTYPE_READY( ParameterRange )
PYTYPE_READY( SlicingNode )
PYTYPE_READY_SUB( HSlicingNode , SlicingNode )
PYTYPE_READY_SUB( VSlicingNode , SlicingNode )
PYTYPE_READY_SUB( DSlicingNode , SlicingNode )
PYTYPE_READY_SUB( RHSlicingNode , SlicingNode )
PYTYPE_READY_SUB( RVSlicingNode , SlicingNode )
PYTYPE_READY_SUB( BoraEngine , ToolEngine );
PYTYPE_READY_SUB( GraphicBoraEngine, GraphicTool );
PYTYPE_READY_SUB( StepParameterRange , ParameterRange );
PYTYPE_READY_SUB( MatrixParameterRange, ParameterRange );
PYTYPE_READY_SUB( HSlicingNode , SlicingNode );
PYTYPE_READY_SUB( VSlicingNode , SlicingNode );
PYTYPE_READY_SUB( DSlicingNode , SlicingNode );
PYTYPE_READY_SUB( RHSlicingNode , SlicingNode );
PYTYPE_READY_SUB( RVSlicingNode , SlicingNode );
PYTYPE_READY_SUB( BoraEngine , ToolEngine );
PYTYPE_READY_SUB( GraphicBoraEngine , GraphicTool );
PyObject* module = Py_InitModule( "Bora", PyBora_Methods );
@ -93,22 +102,28 @@ extern "C" {
return;
}
Py_INCREF( &PyTypeParameterRange );
PyModule_AddObject( module, "ParameterRange" , (PyObject*)&PyTypeParameterRange );
Py_INCREF( &PyTypeStepParameterRange );
PyModule_AddObject( module, "StepParameterRange" , (PyObject*)&PyTypeStepParameterRange );
Py_INCREF( &PyTypeMatrixParameterRange );
PyModule_AddObject( module, "MatrixParameterRange", (PyObject*)&PyTypeMatrixParameterRange );
Py_INCREF( &PyTypeSlicingNode );
PyModule_AddObject( module, "SlicingNode" , (PyObject*)&PyTypeSlicingNode );
Py_INCREF( &PyTypeHSlicingNode );
PyModule_AddObject( module, "HSlicingNode" , (PyObject*)&PyTypeHSlicingNode );
Py_INCREF( &PyTypeVSlicingNode );
PyModule_AddObject( module, "VSlicingNode" , (PyObject*)&PyTypeVSlicingNode );
Py_INCREF( &PyTypeDSlicingNode );
PyModule_AddObject( module, "DSlicingNode" , (PyObject*)&PyTypeDSlicingNode );
Py_INCREF( &PyTypeRHSlicingNode );
PyModule_AddObject( module, "RHSlicingNode" , (PyObject*)&PyTypeRHSlicingNode );
Py_INCREF( &PyTypeRVSlicingNode );
PyModule_AddObject( module, "RVSlicingNode" , (PyObject*)&PyTypeRVSlicingNode );
Py_INCREF( &PyTypeBoraEngine );
PyModule_AddObject( module, "BoraEngine" , (PyObject*)&PyTypeBoraEngine );
Py_INCREF( &PyTypeGraphicBoraEngine );
PyModule_AddObject( module, "GraphicBoraEngine", (PyObject*)&PyTypeGraphicBoraEngine );
PyModule_AddObject( module, "SlicingNode" , (PyObject*)&PyTypeSlicingNode );
Py_INCREF( &PyTypeHSlicingNode );
PyModule_AddObject( module, "HSlicingNode" , (PyObject*)&PyTypeHSlicingNode );
Py_INCREF( &PyTypeVSlicingNode );
PyModule_AddObject( module, "VSlicingNode" , (PyObject*)&PyTypeVSlicingNode );
Py_INCREF( &PyTypeDSlicingNode );
PyModule_AddObject( module, "DSlicingNode" , (PyObject*)&PyTypeDSlicingNode );
Py_INCREF( &PyTypeRHSlicingNode );
PyModule_AddObject( module, "RHSlicingNode" , (PyObject*)&PyTypeRHSlicingNode );
Py_INCREF( &PyTypeRVSlicingNode );
PyModule_AddObject( module, "RVSlicingNode" , (PyObject*)&PyTypeRVSlicingNode );
Py_INCREF( &PyTypeBoraEngine );
PyModule_AddObject( module, "BoraEngine" , (PyObject*)&PyTypeBoraEngine );
Py_INCREF( &PyTypeGraphicBoraEngine );
PyModule_AddObject( module, "GraphicBoraEngine" , (PyObject*)&PyTypeGraphicBoraEngine );
PySlicingNode_postModuleInit();
PyBoraEngine_postModuleInit();

View File

@ -17,6 +17,7 @@
#include "hurricane/analog/PyDevice.h"
#include "crlcore/PyRoutingGauge.h"
#include "bora/PyDSlicingNode.h"
#include "bora/PyStepParameterRange.h"
namespace Bora {
@ -53,40 +54,40 @@ extern "C" {
static PyObject* PyDSlicingNode_create ( PyObject* , PyObject* args )
{
PyObject* pyInstance = NULL;
PyObject* pyCell = NULL;
PyObject* pyRoutingGauge = NULL;
double start = 0.0;
double step = 0.0;
double count = 0.0;
DSlicingNode* node = NULL;
PyObject* pyInstance = NULL;
PyObject* pyCell = NULL;
PyObject* pyRoutingGauge = NULL;
PyObject* pyParameterRange = NULL;
DSlicingNode* node = NULL;
HTRY
if (not PyArg_ParseTuple( args,"SOddd|O:DSlicingNode.create"
if (not PyArg_ParseTuple( args,"SOO|O:DSlicingNode.create"
, &pyInstance
, &pyCell
, &start
, &step
, &count
, &pyParameterRange
, &pyRoutingGauge ) ) {
PyErr_SetString ( ConstructorError, "DSlicingNode.create(): Invalid/bad number of parameters ." );
return NULL;
}
if (not IsPyCell(pyCell)) {
PyErr_SetString( ConstructorError, "DSlicingNode.create(): First argument *must* be of type Cell." );
PyErr_SetString( ConstructorError, "DSlicingNode.create(): Second argument *must* be of type Cell." );
return NULL;
}
if (not IsPyStepParameterRange(pyParameterRange)) {
PyErr_SetString( ConstructorError, "DSlicingNode.create(): Third argument *must* be of type StepParameterRange." );
return NULL;
}
if (pyRoutingGauge and not IsPyRoutingGauge(pyRoutingGauge)) {
PyErr_SetString( ConstructorError, "DSlicingNode.create(): Fifth argument *must* be of type RoutingGauge." );
PyErr_SetString( ConstructorError, "DSlicingNode.create(): Fourth argument *must* be of type RoutingGauge." );
return NULL;
}
Cell* cell = PYCELL_O( pyCell );
Instance* instance = cell->getInstance( PyString_AsString(pyInstance) );
//Device* device = dynamic_cast<Device*>( instance->getMasterCell() );
RoutingGauge* rg = (pyRoutingGauge) ? PYROUTINGGAUGE_O(pyRoutingGauge) : NULL;
Cell* cell = PYCELL_O( pyCell );
Instance* instance = cell->getInstance( PyString_AsString(pyInstance) );
ParameterRange* range = ParameterRangeCast( pyParameterRange );
RoutingGauge* rg = (pyRoutingGauge) ? PYROUTINGGAUGE_O(pyRoutingGauge) : NULL;
node = DSlicingNode::create( NodeSets::create( instance->getMasterCell(), start, step, count, rg )
node = DSlicingNode::create( NodeSets::create( instance->getMasterCell(), range, rg )
, UnknownAlignment
, instance );
HCATCH

View File

@ -0,0 +1,147 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2019-2019, 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 |
// | =============================================================== |
// | C++ Module : "./bora/PyMatrixParameterRange.cpp" |
// +-----------------------------------------------------------------+
#include "hurricane/analog/PyMatrix.h"
#include "bora/PyMatrixParameterRange.h"
namespace Bora {
using namespace Hurricane;
using namespace Isobar;
extern "C" {
#undef ACCESS_OBJECT
#undef ACCESS_CLASS
#define ACCESS_OBJECT _baseObject._object
#define ACCESS_CLASS(_pyObject) &(_pyObject->_baseObject)
#define METHOD_HEAD(function) GENERIC_METHOD_HEAD(MatrixParameterRange,range,function)
// +=================================================================+
// | "PyMatrixParameterRange" Python Module Code Part |
// +=================================================================+
#if defined(__PYTHON_MODULE__)
static PyObject* PyMatrixParameterRange_NEW ( PyObject* , PyObject* args )
{
MatrixParameterRange* range = NULL;
HTRY
range = new MatrixParameterRange();
HCATCH
return PyMatrixParameterRange_Link(range);
}
static int PyMatrixParameterRange_Init ( PyMatrixParameterRange* self, PyObject* args, PyObject* kwargs )
{
cdebug_log(20,0) << "PyMatrixParameterRange_Init(): " << (void*)self << endl;
return 0;
}
static PyObject* PyMatrixParameterRange_addValue ( PyMatrixParameterRange* self, PyObject* args )
{
PyObject* pyMatrix = NULL;
METHOD_HEAD( "MatrixParameterRange.addValue()" );
HTRY
if (not PyArg_ParseTuple( args,"O:MatrixParameterRange.addValue", &pyMatrix ) ) {
PyErr_SetString ( ConstructorError, "MatrixParameterRange.addValue(): Invalid/bad number of parameters ." );
return NULL;
}
if (not IsPyMatrix(pyMatrix)) {
if (not PyList_Check(pyMatrix)) {
PyErr_SetString( ConstructorError, "MatrixParameterRange.addValue(): Argument is neither of type Matrix not list of list." );
return NULL;
}
Matrix m = Matrix_FromListOfList( pyMatrix );
if (m.empty()) return NULL;
range->addValue( &m );
} else {
range->addValue( PYMATRIX_O(pyMatrix) );
}
HCATCH
Py_RETURN_NONE;
}
static PyObject* PyMatrixParameterRange_getValue ( PyMatrixParameterRange* self, PyObject* args )
{
Matrix* matrix = NULL;
PyMatrix* pyMatrix = NULL;
METHOD_HEAD( "MatrixParameterRange.getValue()" );
HTRY
pyMatrix = PyObject_NEW( PyMatrix, &PyTypeMatrix );
if (pyMatrix == NULL) { return NULL; }
pyMatrix->_object = new Matrix( range->getValue() );
HCATCH
return (PyObject*)pyMatrix;
}
DirectDeleteMethod(PyMatrixParameterRange_DeAlloc,PyMatrixParameterRange)
// ---------------------------------------------------------------
// PyMatrixParameterRange Attribute Method table.
PyMethodDef PyMatrixParameterRange_Methods[] =
{ { "getValue" , (PyCFunction)PyMatrixParameterRange_getValue , METH_NOARGS , "To be documented." }
, { "addValue" , (PyCFunction)PyMatrixParameterRange_addValue , METH_VARARGS, "To be documented." }
, { NULL, NULL, 0, NULL } /* sentinel */
};
// +-------------------------------------------------------------+
// | "PyMatrixParameterRange" Object Methods |
// +-------------------------------------------------------------+
PyTypeObjectLinkPyTypeNewInit(MatrixParameterRange)
#else // End of Python Module Code Part.
// +=================================================================+
// | "PyMatrixParameterRange" Shared Library Code Part |
// +=================================================================+
extern LinkCreateMethod(MatrixParameterRange);
PyTypeInheritedObjectDefinitions(MatrixParameterRange, ParameterRange)
#endif // End of Shared Library Code Part.
} // extern "C".
} // Bora namespace.

View File

@ -0,0 +1,121 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2016-2018, 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 |
// | =============================================================== |
// | C++ Module : "./bora/PyParameterRange.cpp" |
// +-----------------------------------------------------------------+
#include "bora/PyParameterRange.h"
#include "bora/PyStepParameterRange.h"
namespace Bora {
using namespace Hurricane;
using namespace Isobar;
extern "C" {
#define METHOD_HEAD(function) GENERIC_METHOD_HEAD(ParameterRange,range,function)
// +=================================================================+
// | "PyParameterRange" Python Module Code Part |
// +=================================================================+
#if defined(__PYTHON_MODULE__)
// Standart destroy (Attribute).
//DBoDestroyAttribute(PyParameterRange_destroy ,PyParameterRange)
// Standart Accessors (Attributes).
DirectGetBoolAttribute(PyParameterRange_isValid ,isValid ,PyParameterRange,ParameterRange)
DirectGetBoolAttribute(PyParameterRange_progress,progress,PyParameterRange,ParameterRange)
DirectGetUIntAttribute(PyParameterRange_getIndex,getIndex,PyParameterRange,ParameterRange)
DirectGetUIntAttribute(PyParameterRange_getSize ,getSize ,PyParameterRange,ParameterRange)
DirectSetIntAttribute (PyParameterRange_setIndex,setIndex,PyParameterRange,ParameterRange)
DirectVoidMethod(ParameterRange,range,reset)
// ---------------------------------------------------------------
// PyParameterRange Attribute Method table.
PyMethodDef PyParameterRange_Methods[] =
{ { "isValid" , (PyCFunction)PyParameterRange_isValid , METH_NOARGS , "To be documented." }
, { "getIndex" , (PyCFunction)PyParameterRange_getIndex , METH_NOARGS , "To be documented." }
, { "getSize" , (PyCFunction)PyParameterRange_getSize , METH_NOARGS , "To be documented." }
, { "progress" , (PyCFunction)PyParameterRange_progress , METH_NOARGS , "To be documented." }
, { "setIndex" , (PyCFunction)PyParameterRange_setIndex , METH_VARARGS, "To be documented." }
//, { "destroy" , (PyCFunction)PyParameterRange_destroy , METH_NOARGS
// , "Destroy associated hurricane object, the python object remains." }
, {NULL, NULL, 0, NULL} /* sentinel */
};
PythonOnlyDeleteMethod(ParameterRange)
PyTypeObjectLinkPyType(ParameterRange)
#else // End of Python Module Code Part.
// +=================================================================+
// | "PyParameterRange" Shared Library Code Part |
// +=================================================================+
// ---------------------------------------------------------------
// Allocator Method : "PyParameterRange_NEW ()"
//
// No PyParameterRange should ever be created, it's not a terminal object
// of the class hierarchy. Instead create the real underlying PyObject.
PyObject* PyParameterRange_NEW ( ParameterRange* range ) {
if (not range) {
PyErr_SetString ( HurricaneError, "PyParameterRange_NEW(): NULL range argument." );
return NULL;
}
StepParameterRange* stepRange = dynamic_cast<StepParameterRange*>(range);
if (stepRange) return PyStepParameterRange_Link( stepRange );
Py_RETURN_NONE;
}
PyTypeRootObjectDefinitions(ParameterRange)
#endif // Shared Library Code Part.
} // extern "C".
// +=================================================================+
// | "PyParameterRange" Shared Library Code Part |
// +=================================================================+
# if !defined(__PYTHON_MODULE__)
ParameterRange* ParameterRangeCast ( PyObject* derivedObject ) {
if (IsPyStepParameterRange(derivedObject)) return PYSTEPPARAMETERRANGE_O(derivedObject);
return NULL;
}
#endif
} // Bora namespace.

View File

@ -0,0 +1,123 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2016-2018, 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 |
// | =============================================================== |
// | C++ Module : "./bora/PyStepParameterRange.cpp" |
// +-----------------------------------------------------------------+
#include "hurricane/analog/PyDevice.h"
#include "crlcore/PyRoutingGauge.h"
#include "bora/PyStepParameterRange.h"
namespace Bora {
using namespace Hurricane;
using namespace Isobar;
extern "C" {
#undef ACCESS_OBJECT
#undef ACCESS_CLASS
#define ACCESS_OBJECT _baseObject._object
#define ACCESS_CLASS(_pyObject) &(_pyObject->_baseObject)
#define METHOD_HEAD(function) GENERIC_METHOD_HEAD(StepParameterRange,node,function)
// +=================================================================+
// | "PyStepParameterRange" Python Module Code Part |
// +=================================================================+
#if defined(__PYTHON_MODULE__)
static PyObject* PyStepParameterRange_NEW ( PyObject* , PyObject* args )
{
double start = 0.0;
double step = 0.0;
double count = 0.0;
StepParameterRange* range = NULL;
HTRY
if (not PyArg_ParseTuple( args, "ddd:StepParameterRange_NEW", &start, &step, &count ) ) {
PyErr_SetString ( ConstructorError, "StepParameterRange.create(): Invalid/bad number of parameters ." );
return NULL;
}
range = new StepParameterRange( start, step, count );
HCATCH
return PyStepParameterRange_Link(range);
}
static int PyStepParameterRange_Init ( PyStepParameterRange* self, PyObject* args, PyObject* kwargs )
{
cdebug_log(20,0) << "PyStepParameterRange_Init(): " << (void*)self << endl;
return 0;
}
static void PyStepParameterRange_DeAlloc ( PyStepParameterRange* self )
{
cdebug_log(20,0) << "PyStepParameterRange_DeAlloc(" << (void*)self << ") "
<< (void*)(self->ACCESS_OBJECT) << ":" << self->ACCESS_OBJECT << endl;
if (self->ACCESS_OBJECT and not self->ACCESS_OBJECT->isNested()) {
cdebug_log(20,0) << "C++ object := " << &(self->ACCESS_OBJECT) << endl;
delete self->ACCESS_OBJECT;
}
PyObject_DEL( self );
}
DirectGetDoubleAttribute(PyStepParameterRange_getValue,getValue,PyStepParameterRange,StepParameterRange)
// Standart Destroy (Attribute).
// ---------------------------------------------------------------
// PyStepParameterRange Attribute Method table.
PyMethodDef PyStepParameterRange_Methods[] =
{ { "getValue" , (PyCFunction)PyStepParameterRange_getValue , METH_NOARGS , "To be documented." }
, { NULL, NULL, 0, NULL } /* sentinel */
};
// +-------------------------------------------------------------+
// | "PyStepParameterRange" Object Methods |
// +-------------------------------------------------------------+
PyTypeObjectLinkPyTypeNewInit(StepParameterRange)
#else // End of Python Module Code Part.
// +=================================================================+
// | "PyStepParameterRange" Shared Library Code Part |
// +=================================================================+
extern LinkCreateMethod(StepParameterRange);
PyTypeInheritedObjectDefinitions(StepParameterRange, ParameterRange)
#endif // End of Shared Library Code Part.
} // extern "C".
} // Bora namespace.

View File

@ -80,7 +80,7 @@ namespace Bora {
: Super()
, _parent (NULL)
, _flags (0)
, _nodeSets(NodeSets::create( NULL, 0.0, 0.0, 0.0 ))
, _nodeSets(NodeSets::create( NULL, NULL))
, _x (0)
, _y (0)
, _boxSet (NULL)
@ -823,27 +823,6 @@ namespace Bora {
}
double SlicingNode::getStartParameter () const
{
cerr << Error( "SlicingNode::getStartParameter(): Base class method must never be called." ) << endl;
return 0.0;
}
double SlicingNode::getStepParameter () const
{
cerr << Error( "SlicingNode::getStepParameter(): Base class method must never be called." ) << endl;
return 0.0;
}
double SlicingNode::getCountParameter () const
{
cerr << Error( "SlicingNode::getCountParameter(): Base class method must never be called." ) << endl;
return 0.0;
}
Instance* SlicingNode::getInstance () const
{
cerr << Error( "SlicingNode::getInstance(): Base class method must never be called." ) << endl;

View File

@ -33,10 +33,17 @@
#include <vector>
#include "hurricane/DbU.h"
#include "bora/Constants.h"
namespace Hurricane {
class Cell;
}
namespace CRL {
class RoutingGauge;
}
namespace Bora {
using Hurricane::DbU;
using Hurricane::Cell;
// -------------------------------------------------------------------
@ -62,6 +69,7 @@ namespace Bora {
virtual double getOccupationArea () const;
virtual const std::vector<BoxSet*>& getSet () const;
virtual int getNFing () const;
virtual size_t getIndex () const;
virtual void print () const;
virtual double getDevicesArea () const = 0;
virtual void setHeight ( DbU::Unit );
@ -179,29 +187,31 @@ namespace Bora {
class DBoxSet: public BoxSet
{
protected:
DBoxSet ( DbU::Unit height, DbU::Unit width, int nfing );
DBoxSet ( DbU::Unit height, DbU::Unit width, size_t index );
DBoxSet ( DBoxSet* boxSet );
~DBoxSet ();
public:
static DBoxSet* create ( DbU::Unit height, DbU::Unit width, int nfing=1 );
static DBoxSet* create ( Cell* , int index, CRL::RoutingGauge* rg=NULL );
DBoxSet* clone ();
inline unsigned int getType () const;
inline double getDevicesArea () const;
inline size_t getIndex () const;
inline int getNFing () const;
static inline int getCount ();
static inline void printCount ();
static inline void printCountAll ();
void destroy ();
private:
int _nfing;
static int _count;
static int _countAll;
size_t _index;
static int _count;
static int _countAll;
};
inline unsigned int DBoxSet::getType () const { return DeviceSNode; }
inline double DBoxSet::getDevicesArea () const { return _height*_width; }
inline int DBoxSet::getNFing () const { return _nfing; }
inline int DBoxSet::getNFing () const { return _index; }
inline size_t DBoxSet::getIndex () const { return _index; }
inline int DBoxSet::getCount () { return _count; }
inline void DBoxSet::printCount () { std::cerr << "DBoxSet::Count = " << _count << std::endl; }
inline void DBoxSet::printCountAll () { std::cerr << "DBoxSet::CountAll = " << _countAll << std::endl; }

View File

@ -63,9 +63,6 @@ namespace Bora {
void destroy ();
void preRecursiveDestroy ();
void recursiveDestroy ();
double getStartParameter () const;
double getStepParameter () const;
double getCountParameter () const;
bool checkInitialPlacement ( int& cpt ) const;// see notes in .cpp
void setGCell ( Anabatic::GCell* );
bool isSame ( SlicingNode* ) const;

View File

@ -20,6 +20,7 @@
#include <cstddef>
#include <limits>
#include "BoxSet.h"
#include "ParameterRange.h"
namespace Hurricane {
class Cell;
@ -48,13 +49,11 @@ namespace Bora {
//static const size_t NotFound = std::numeric_limits<size_t>()::max;
static const size_t NotFound = (size_t)-1L;
public:
NodeSets ( double start, double step, double count );
NodeSets ( ParameterRange *range );
NodeSets ( const NodeSets* other );
~NodeSets ();
static NodeSets* create ( Cell* cell =NULL
, double start=0.0
, double step =0.0
, double count=0.0
, ParameterRange* range=NULL
, CRL::RoutingGauge* rg =NULL );
BoxSet* operator[] ( size_t );
BoxSet* at ( size_t );
@ -79,14 +78,10 @@ namespace Bora {
void push_back ( std::vector<BoxSet*> vect, DbU::Unit height, DbU::Unit width, unsigned int type );
void push_back ( DbU::Unit height, DbU::Unit width );
NodeSets* clone ();
inline double getStartParameter () const;
inline double getStepParameter () const;
inline double getCountParameter () const;
inline ParameterRange* getRange () const;
private:
std::vector<BoxSet*> _boxSets;
int _start;
int _step;
int _count;
ParameterRange* _range;
};
@ -97,9 +92,7 @@ namespace Bora {
inline size_t NodeSets::size () const { return _boxSets.size() ; }
inline bool NodeSets::empty () const { return _boxSets.empty(); }
inline void NodeSets::sort () { std::sort( _boxSets.begin(),_boxSets.end(), compBoxSet() ); }
inline double NodeSets::getStartParameter () const { return _start; }
inline double NodeSets::getStepParameter () const { return _step ; }
inline double NodeSets::getCountParameter () const { return _count; }
inline ParameterRange* NodeSets::getRange () const { return _range; }
} // Bora namespace.

View File

@ -0,0 +1,145 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2016-2019, 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 |
// | =============================================================== |
// | C++ Header : "./bora/ParameterRange.h" |
// +-----------------------------------------------------------------+
#ifndef BORA_PARAMETER_RANGE_H
#define BORA_PARAMETER_RANGE_H
#include "hurricane/Commons.h"
#include "hurricane/analog/Matrix.h"
namespace Bora {
using Hurricane::Record;
using Analog::Matrix;
// -------------------------------------------------------------------
// Class : "ParameterRange"
class ParameterRange {
public:
enum { Nested=1 } Flags;
public:
ParameterRange ();
virtual ~ParameterRange ();
virtual size_t getSize () const = 0;
inline bool progress ();
inline bool isNested () const;
inline bool isValid () const;
inline size_t getIndex () const;
inline bool setIndex ( size_t );
inline void setNested ();
inline void reset ();
virtual ParameterRange* clone () const = 0;
virtual std::string _getTypeName () const = 0;
virtual std::string _getString () const;
virtual Record* _getRecord () const;
private:
unsigned long _flags;
size_t _index;
};
inline bool ParameterRange::progress ()
{ if (_index<getSize()) { ++_index; return true; } return false; }
inline bool ParameterRange::isValid () const
{ return (_index < getSize()); }
inline bool ParameterRange::isNested () const
{ return _flags & Nested; }
inline void ParameterRange::setNested ()
{ _flags |= Nested; }
inline bool ParameterRange::setIndex ( size_t i )
{ if (i<getSize()) { _index = i; return true; } return false; }
inline size_t ParameterRange::getIndex () const { return _index; }
inline void ParameterRange::reset () { _index=0; }
// -------------------------------------------------------------------
// Class : "StepParameterRange"
class StepParameterRange : public ParameterRange {
public:
typedef ParameterRange Super;
public:
StepParameterRange ( double start, double step, double count );
virtual ~StepParameterRange ();
double getValue () const;
virtual size_t getSize () const;
inline void copy ( const StepParameterRange* );
virtual StepParameterRange* clone () const;
virtual std::string _getTypeName () const;
virtual std::string _getString () const;
virtual Record* _getRecord () const;
private:
double _start;
double _step;
double _count;
};
inline void StepParameterRange::copy ( const StepParameterRange* from )
{
_start = from->_start;
_step = from->_step;
_count = from->_count;
}
// -------------------------------------------------------------------
// Class : "MatrixParameterRange"
class MatrixParameterRange : public ParameterRange {
public:
typedef ParameterRange Super;
public:
MatrixParameterRange ();
virtual ~MatrixParameterRange ();
const Matrix& getValue () const;
virtual size_t getSize () const;
inline void copy ( const MatrixParameterRange* );
virtual MatrixParameterRange* clone () const;
inline void addValue ( const Matrix* );
virtual std::string _getTypeName () const;
virtual std::string _getString () const;
virtual Record* _getRecord () const;
private:
std::vector<Matrix> _matrixes;
};
inline void MatrixParameterRange::copy ( const MatrixParameterRange* from )
{ for ( const Matrix& m : from->_matrixes ) addValue( &m ); }
inline void MatrixParameterRange::addValue ( const Matrix* m )
{ _matrixes.push_back( *m ); }
} // Bora namespace.
INSPECTOR_P_SUPPORT(Bora::ParameterRange);
INSPECTOR_P_SUPPORT(Bora::StepParameterRange);
INSPECTOR_P_SUPPORT(Bora::MatrixParameterRange);
#endif

View File

@ -0,0 +1,54 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2019-2019, 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 |
// | =============================================================== |
// | C++ Header : "./bora/PyMatrixParameterRange.h" |
// +-----------------------------------------------------------------+
#ifndef BORA_PY_MATRIX_PARAMETER_RANGE_H
#define BORA_PY_MATRIX_PARAMETER_RANGE_H
#include "bora/PyParameterRange.h"
namespace Bora {
extern "C" {
// -------------------------------------------------------------------
// Python Object : "PyMatrixParameterRange".
typedef struct {
PyParameterRange _baseObject;
} PyMatrixParameterRange;
// -------------------------------------------------------------------
// Functions & Types exported to "PyBora.cpp".
extern PyTypeObject PyTypeMatrixParameterRange;
extern PyMethodDef PyMatrixParameterRange_Methods[];
extern PyObject* PyMatrixParameterRange_Link ( MatrixParameterRange* node );
extern void PyMatrixParameterRange_LinkPyType ();
#define IsPyMatrixParameterRange(v) ( (v)->ob_type == &PyTypeMatrixParameterRange )
#define PYMATRIXPARAMETERRANGE(v) ( (PyMatrixParameterRange*)(v) )
#define PYMATRIXPARAMETERRANGE_O(v) ( dynamic_cast<MatrixParameterRange*>(PYMATRIXPARAMETERRANGE(v)->_baseObject._object) )
} // extern "C".
} // Bora namespace.
#endif // BORA_PY_MATRIX_PARAMETER_RANGE_H

View File

@ -0,0 +1,62 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2016-2018, 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 |
// | |
// | Authors : Jean-Paul Chaput |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./bora/PyParameterRange.h" |
// +-----------------------------------------------------------------+
#ifndef BORA_PY_PARAMETER_RANGE_H
#define BORA_PY_PARAMETER_RANGE_H
#include "hurricane/isobar/PyHurricane.h"
#include "bora/ParameterRange.h"
namespace Bora {
extern "C" {
// -------------------------------------------------------------------
// Python Object : "PyParameterRange".
typedef struct {
PyObject_HEAD
ParameterRange* _object;
} PyParameterRange;
// -------------------------------------------------------------------
// Functions & Types exported to "PyBora.ccp".
extern PyObject* PyParameterRange_NEW ( ParameterRange* range );
extern void PyParameterRange_LinkPyType ();
extern void PyParameterRange_postModuleInit ();
extern PyTypeObject PyTypeParameterRange;
extern PyMethodDef PyParameterRange_Methods[];
#define IsPyParameterRange(v) ( (v)->ob_type == &PyTypeParameterRange )
#define PYPARAMETERRANGE(v) ( (PyParameterRange*)(v) )
#define PYPARAMETERRANGE_O(v) ( PYPARAMETERRANGE(v)->_object )
} // extern "C".
ParameterRange* ParameterRangeCast ( PyObject* derivedObject );
} // Bora namespace.
#endif // BORA_PY_PARAMETER_RANGE_H

View File

@ -0,0 +1,54 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2016-2018, 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 |
// | =============================================================== |
// | C++ Header : "./bora/PyStepParameterRange.h" |
// +-----------------------------------------------------------------+
#ifndef BORA_PY_STEP_PARAMETER_RANGE_H
#define BORA_PY_STEP_PARAMETER_RANGE_H
#include "bora/PyParameterRange.h"
namespace Bora {
extern "C" {
// -------------------------------------------------------------------
// Python Object : "PyStepParameterRange".
typedef struct {
PyParameterRange _baseObject;
} PyStepParameterRange;
// -------------------------------------------------------------------
// Functions & Types exported to "PyBora.cpp".
extern PyTypeObject PyTypeStepParameterRange;
extern PyMethodDef PyStepParameterRange_Methods[];
extern PyObject* PyStepParameterRange_Link ( StepParameterRange* node );
extern void PyStepParameterRange_LinkPyType ();
#define IsPyStepParameterRange(v) ( (v)->ob_type == &PyTypeStepParameterRange )
#define PYSTEPPARAMETERRANGE(v) ( (PyStepParameterRange*)(v) )
#define PYSTEPPARAMETERRANGE_O(v) ( dynamic_cast<StepParameterRange*>(PYSTEPPARAMETERRANGE(v)->_baseObject._object) )
} // extern "C".
} // Bora namespace.
#endif // BORA_PY_STEP_PARAMETER_RANGE_H

View File

@ -253,9 +253,6 @@ namespace Bora {
virtual double getOccupationArea () const;
virtual void setNFing ( int );
virtual int getNFing () const;
virtual double getStartParameter () const;
virtual double getStepParameter () const;
virtual double getCountParameter () const;
virtual Instance* getInstance () const;
virtual void setInstance ( Instance* );
virtual bool checkCellInstances ( Cell* );

View File

@ -398,7 +398,7 @@ def createStyles ( scale=1.0 ):
style.addDrawingStyle( group='Viewer', name='mauka.container', color=toRGB('Magenta4' ), border=4, pattern='0000000000000000', goMatched=False )
# Group: Active Layers.
style.addDrawingStyle( group='Active Layers', name='nWell' , color=toRGB('Tan' ), pattern=toHexa('antipoids2.32'), border=1, threshold=0.02*scale )
style.addDrawingStyle( group='Active Layers', name='nWell' , color=toRGB('Tan' ), pattern=toHexa('urgo.32' ), border=1, threshold=0.02*scale )
style.addDrawingStyle( group='Active Layers', name='pWell' , color=toRGB('LightYellow'), pattern=toHexa('antipoids2.32'), border=1, threshold=0.02*scale )
style.addDrawingStyle( group='Active Layers', name='nImplant', color=toRGB('LawnGreen' ), pattern=toHexa('diffusion.32' ), border=0, threshold=0.02*scale )
style.addDrawingStyle( group='Active Layers', name='pImplant', color=toRGB('Yellow' ), pattern=toHexa('diffusion.32' ), border=0, threshold=0.02*scale )
@ -407,7 +407,7 @@ def createStyles ( scale=1.0 ):
style.addDrawingStyle( group='Active Layers', name='poly2' , color=toRGB('Orange' ), pattern=toHexa('antipoids2.32'), border=1, threshold=0.02*scale )
# Group: Routing Layers.
style.addDrawingStyle( group='Routing Layers', name='metal1' , color=toRGB('Blue' ), pattern=toHexa('slash.32' ), border=1, threshold=0.02*scale )
style.addDrawingStyle( group='Routing Layers', name='metal1' , color=toRGB('Blue' ), pattern=toHexa('slash.32' ), border=4, threshold=0.02*scale )
style.addDrawingStyle( group='Routing Layers', name='metal2' , color=toRGB('Aqua' ), pattern=toHexa('antislash2.32'), border=1, threshold=0.02*scale )
style.addDrawingStyle( group='Routing Layers', name='metcap' , color=toRGB('DarkTurquoise'), pattern=toHexa('poids2.32' ), border=2, threshold=0.02*scale )
style.addDrawingStyle( group='Routing Layers', name='metal3' , color=toRGB('LightPink' ), pattern=toHexa('antislash3.32'), border=1, threshold=0.02*scale )

View File

@ -308,11 +308,12 @@ add( name='light_antislash0.8'
, ' X X' ] )
add( name='urgo.32'
, bits=[ 'XXXXXXXXXXXXX XXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXX XXXXXXXXXXXXXXX'
, 'XXXXXXXXXXX XXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXX XXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXX XXXXXXXXXXXXXXXXX'
, bits=[ 'XXXXXXXXXXXX XXXXXXXXXXXXXXXX'
, 'XXXXXXXXX XXXXXXXXXXXXX'
, 'XXXXXXXXX XXXXXXXXXXXXX'
, 'XXXXXXXXXXXX XXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXX XXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXX XXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
@ -321,14 +322,14 @@ add( name='urgo.32'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX X'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX X'
, ' XXXXXXXXXXXXXXXXXXXXXXXXXX '
, ' XXXXXXXXXXXXXXXXXXXXXXXXXX '
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX X'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX X'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX '
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX '
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX '
, ' XXXXXXXXXXXXXXXXXXXXXX '
, ' XXXXXXXXXXXXXXXXXXXXXX '
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX '
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX '
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX '
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
@ -337,43 +338,42 @@ add( name='urgo.32'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXXX XXXXXXXXXXXXXXXXX' ] )
, 'XXXXXXXXXXXX XXXXXXXXXXXXXXXX'
, 'XXXXXXXXXXXX XXXXXXXXXXXXXXXX' ] )
add( name='slash.32'
, bits=[ ' X X'
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, 'X X '
, ' X X'
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, ' X X '
, 'X X ' ] )
, bits=[ ' XXXX XXX'
, ' XXXX XXXX'
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, 'XXXX XXXX '
, 'XXX XXXX X'
, 'XX XXXX XX'
, 'X XXXX XXX'
, ' XXXX XXXX'
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, ' XXXX XXXX '
, 'XXXX XXXX '
, 'XXX XXXX '
, 'XX XXXX ' ] )
add( name='antihash0.32'
, bits=[ ' XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX'

View File

@ -121,10 +121,10 @@ addDevice( name = 'SimpleCurrentMirrorBulkUnconnected'
, ('Interdigitated' , 'SCM_interdigitated.py' )
)
)
addDevice( name = 'MIMCapacitor'
, spice = spiceDir+'MIMCapacitor.spi'
, connectors = ( 'P1', 'P2' )
, layouts = ( ('SimpleMatrix' , 'MIM_simpleMatrix.py' ),
addDevice( name = 'MultiCapacitor'
#, spice = spiceDir+'MIM_OneCapacitor.spi'
#, connectors = ( 'T1', 'B1' )
, layouts = ( ('Matrix' , 'CapacitorMatrix.py' ),
)
)

View File

@ -55,6 +55,7 @@
PyLevelShifter.cpp
PyMCheckBoxParameter.cpp
PyMultiCapacitor.cpp
PyMatrix.cpp
PyParameter.cpp
PySimpleCurrentMirror.cpp
PySpinBoxParameter.cpp
@ -117,6 +118,7 @@
hurricane/analog/PyLevelShifter.h
hurricane/analog/PyMCheckBoxParameter.h
hurricane/analog/PyMultiCapacitor.h
hurricane/analog/PyMatrix.h
hurricane/analog/PyParameter.h
hurricane/analog/PySimpleCurrentMirror.h
hurricane/analog/PySpinBoxParameter.h

View File

@ -96,7 +96,7 @@ namespace Analog {
}
Parameter* Device::getParameter ( const string& parameterId )
Parameter* Device::getParameter ( const string& parameterId ) const
{
for ( Parameter* parameter : _parameterSet) {
if (parameter->getName() == parameterId)

View File

@ -35,36 +35,6 @@ namespace Analog {
using namespace Isobar;
// -------------------------------------------------------------------
// Class : "::LayoutGenerator::Logger".
LayoutGenerator::Logger::Logger ( LayoutGenerator* generator )
: _generator(generator)
{ }
LayoutGenerator::Logger::~Logger ()
{ }
void LayoutGenerator::Logger::popStatus ( const string& text )
{
if (_generator->getVerboseLevel() >= LayoutGenerator::Verbose)
cerr << text << endl;
}
void LayoutGenerator::Logger::popError ( const string& text )
{ cerr << text << endl; }
void LayoutGenerator::Logger::popScriptError ()
{
string scriptError = "! An error occured while creating layout. Please check the python console for more information.";
cerr << scriptError << endl;
}
// -------------------------------------------------------------------
// Class : "::LayoutGenerator".
@ -72,8 +42,7 @@ namespace Analog {
LayoutGenerator::LayoutGenerator ()
: _logger (NULL)
, _device (NULL)
: _device (NULL)
, _box (NULL)
, _activeBox(NULL)
, _matrix ()
@ -81,33 +50,34 @@ namespace Analog {
{
_activeBox = new Hurricane::Box();
_script = Script::create();
setLogger ( new Logger(this) );
}
LayoutGenerator::~LayoutGenerator ()
{
if (_script) _script->destroy();
if (_logger) delete _logger;
}
bool LayoutGenerator::checkScript()
{
if (not _device) {
popError( "Try to check for script but device does not exist." );
cerr << Error( "LayoutGenerator::checkScript(): No device loaded in the generator yet." ) << endl;
return false;
}
FILE* fs = fopen( _device->getLayoutScript().c_str(), "r" );
if (not fs) {
perror( NULL );
popError( "Cannot load script : file does not exist or bad access rights." );
cerr << Error( "LayoutGenerator::checkScript(): Unable to find/open layout script of device \"%s\".\n"
"(\"%s\")"
, getString(_device->getName()).c_str()
, _device->getLayoutScript().c_str()
);
return false;
}
fclose( fs );
popStatus( _device->getLayoutScript()+" found." );
return true;
}
@ -115,14 +85,14 @@ namespace Analog {
bool LayoutGenerator::checkFunctions()
{
if (not _script->getFunction("checkCoherency")) {
cerr << Error( "LayoutGenerator::drawLayout(): Module <%s> miss checkCoherency()."
cerr << Error( "LayoutGenerator::drawLayout(): Module \"%s\" miss checkCoherency() function."
, _script->getUserModuleName().c_str() ) << endl;
finalize( ShowTimeTag );
return false;
}
if (not _script->getFunction("layout")) {
cerr << Error( "LayoutGenerator::drawLayout(): Module <%s> miss layout()."
cerr << Error( "LayoutGenerator::drawLayout(): Module \"%s\" miss layout() function."
, _script->getUserModuleName().c_str() ) << endl;
finalize( ShowTimeTag );
return false;
@ -134,55 +104,37 @@ namespace Analog {
bool LayoutGenerator::drawLayout ()
{
if (_device == NULL) return false;
if (_device == NULL) return false;
//checkScript();
cdebug_log(500,0) << "LayoutGenerator::drawLayout() " << _device->getDeviceName() << endl;
cdebug_log(500,0) << "LayoutGenerator::drawLayout() " << _device->getDeviceName() << endl;
_device->destroyLayout();
_device->destroyLayout();
initialize();
initialize();
if (not _script->getUserModule()) {
finalize( ShowTimeTag );
cerr << Error( "LayoutGenerator::drawLayout(): Couldn't load module \"%s\"."
, _script->getUserModuleName().c_str() ) << endl;
return false;
}
if (not _script->getUserModule()) {
finalize( ShowTimeTag );
cerr << Error( "LayoutGenerator::drawLayout(): Couldn't load module <%s>"
, _script->getUserModuleName().c_str() ) << endl;
return false;
}
checkFunctions();
checkFunctions();
PyObject* pyArgs = NULL;
if (not toPyArguments(pyArgs,NoFlags)) {
finalize( ShowTimeTag );
return false;
}
PyObject* pyArgs = NULL;
if (not toPyArguments(pyArgs,NoFlags)) {
finalize( ShowTimeTag );
return false;
}
if (not callCheckCoherency(pyArgs,ShowError)) {
return false;
}
if (not callCheckCoherency(pyArgs,ShowError)) return false;
if (not callLayout (pyArgs) ) return false;
if (not callLayout(pyArgs)) {
cerr << "Layout failed" << endl; cerr.flush();
return false;
}
_device->setAbutmentBox( getDeviceBox() );
// Eric passed by here
//cerr << "Python driven Layout successfully drawn." << endl;
finalize( ShowTimeTag|StatusOk );
_device->setAbutmentBox( getDeviceBox() );
finalize( ShowTimeTag|StatusOk );
//string message = _device->checkLayoutOnPhysicalGrid();
//if (not message.empty())
// popError( message.c_str() );
// Eric passed by here
//popStatus( "Layout done." );
return true;
return true;
}
@ -199,10 +151,6 @@ namespace Analog {
dot = (dot!=string::npos) ? dot : moduleName.size();
moduleName = moduleName.substr( 0, dot );
// Eric passed by here
//cerr << "Path: " << modulePath << endl;
//cerr << "Name: " << moduleName << endl;
_script->setUserModuleName( moduleName );
return _script->initialize( Script::NoThrow );
}
@ -210,14 +158,6 @@ namespace Analog {
void LayoutGenerator::finalize ( unsigned int flags )
{
if (flags & ShowTimeTag) {
string code = "";
// Eric passed by here
//if (flags & StatusOk) code = "import time; print ' -- Script SUCCESS2 --', time.strftime('%H:%M:%S',time.localtime())\n";
if (flags & StatusOk) code = "";
else code = "import time; print ' -- Script FAILED --' , time.strftime('%H:%M:%S',time.localtime())\n";
PyRun_SimpleString( code.c_str() );
}
_script->finalize();
}
@ -237,20 +177,29 @@ namespace Analog {
PyObject* pTupleCheck = _script->callFunction( "checkCoherency", pArgsCheck );
if (not pTupleCheck) {
string code = "print ' -- Script FAILED --', time.strftime('%H:%M:%S',time.localtime())\n";
PyRun_SimpleString( code.c_str() );
cerr << Error( "LayoutGenerator::callCheckCoherency(): An exception may have occured in checkCoherency().\n"
" (\"%s\")"
, _script->getFileName()
) << endl;
finalize( NoFlags );
popScriptError();
return false;
}
if ( not PyTuple_Check(pTupleCheck) or (PyTuple_Size(pTupleCheck) != 2) ) {
popError( "checkCoherency function must return a tuple: (bool,errorMessage)" );
cerr << Error( "LayoutGenerator::callCheckCoherency(): checkCoherency() did not return a tuple (bool,str).\n"
" (\"%s\")"
, _script->getFileName()
) << endl;
return false;
}
PyObject* pCheckOk = PyTuple_GetItem( pTupleCheck, 0 );
if (pCheckOk == Py_False) {
if (flags & ShowError)
popError( string(PyString_AsString(PyTuple_GetItem(pTupleCheck,1))) );
cerr << Error( "%s\n (\"%s\")"
, PyString_AsString(PyTuple_GetItem(pTupleCheck,1))
, _script->getFileName()
) << endl;
return false;
}
return true;
@ -261,11 +210,11 @@ namespace Analog {
{
_matrix = _script->callFunction( "layout", pArgs );
if (not _matrix) {
string code = "print ' -- Script FAILED --', time.strftime('%H:%M:%S',time.localtime())";
PyRun_SimpleString( code.c_str() );
cerr << Error( "LayoutGenerator::callLayout(): An exception may have occured in layout().\n"
" (\"%s\")"
, _script->getFileName()
) << endl;
finalize( NoFlags );
popScriptError();
cerr << "There was a problem running layout function" << endl;
return false;
}
return true;
@ -291,54 +240,69 @@ namespace Analog {
Box LayoutGenerator::getDeviceBox ()
{
PyObject* pBox = getParamValue(getDic(getRow(0), 0), "box");
if (pBox == NULL) {
finalize( NoFlags );
popError("Layout function did not returned a valid device box 2!");
return Box();
PyObject* pyBox = getParamValue(getDic(getRow(0), 0), "box");
if (not pyBox) {
finalize( NoFlags );
cerr << Error( "LayoutGenerator::getDeviceBox(): No \"box\" key in returned dictionary.\n"
" (\"%s\")"
, _script->getFileName()
) << endl;
return Box();
}
if (pBox->ob_type != &PyTypeBox) {
if (not IsPyBox(pyBox)) {
cerr << Error( "LayoutGenerator::getDeviceBox(): Value associated with \"box\" key is *not* of Box type.\n"
" (\"%s\")"
, _script->getFileName()
) << endl;
finalize( NoFlags );
popError("Layout function did not returned a valid device box!");
return Box();
}
return *((PyBox*)pBox)->_object; //get the hurricane box
return *PYBOX_O(pyBox);
}
Box LayoutGenerator::getActiveBox ()
{
PyObject* pBox = getParamValue(getDic(getRow(0), 0), "globalActiveBox");
if (!pBox) {
finalize( NoFlags );
popError("Layout function did not returned a valid active box 2!");
return Box();
PyObject* pyBox = getParamValue( getDic(getRow(0),0), "globalActiveBox" );
if (not pyBox) {
cerr << Error( "LayoutGenerator::getDeviceBox(): No \"globalActiveBox\" key in returned dictionary.\n"
" (\"%s\")"
, _script->getFileName()
) << endl;
finalize( NoFlags );
return Box();
}
if (pBox->ob_type != &PyTypeBox) {
if (not IsPyBox(pyBox)) {
cerr << Error( "LayoutGenerator::getDeviceBox(): Value associated with \"globalActiveBox\" key is *not* of Box type.\n"
" (\"%s\")"
, _script->getFileName()
) << endl;
finalize( NoFlags );
popError("Layout function did not returned a valid active box!");
}
return *((PyBox*)pBox)->_object; //get the hurricane box
return *PYBOX_O(pyBox);
}
double LayoutGenerator::getParameterValue ( unsigned i, unsigned j, string paramName, bool& ok )
double LayoutGenerator::getParameterValue ( unsigned i, unsigned j, string paramName, bool& found )
{
PyObject* pValue = getParamValue(getDic(getRow(i),j), paramName);
if (pValue == NULL){
ok = false;
PyObject* pyValue = getParamValue( getDic(getRow(i),j), paramName );
if (not pyValue){
found = false;
return 0.0;
}
ok = true;
return (PyFloat_AsDouble(pValue));
found = true;
return PyFloat_AsDouble( pyValue );
}
PyObject* LayoutGenerator::getRow ( unsigned i )
{
if (_matrix and PyList_Check(_matrix) == 1 and ((int)i < PyList_Size(_matrix))){
return PyList_GetItem(_matrix, i);
if (_matrix and (PyList_Check(_matrix) == 1) and ((int)i < PyList_Size(_matrix))) {
return PyList_GetItem( _matrix, i );
}
return NULL;
}
@ -346,17 +310,19 @@ namespace Analog {
PyObject* LayoutGenerator::getDic ( PyObject* row, unsigned j )
{
if (row and PyList_Check(row) == 1 and ((int)j < PyList_Size(row))){
return PyList_GetItem(row, j);
if (row and (PyList_Check(row) == 1) and ((int)j < PyList_Size(row))) {
return PyList_GetItem( row, j );
}
return NULL;
}
PyObject* LayoutGenerator::getParamValue ( PyObject* dic, string paramName )
PyObject* LayoutGenerator::getParamValue ( PyObject* dict, string paramName )
{
if (dic and (PyDict_Check(dic) == 1) and (PyDict_Contains(dic,PyString_FromString(paramName.c_str()))))
return PyDict_GetItemString(dic,paramName.c_str());
if (dict
and (PyDict_Check(dict) == 1)
and (PyDict_Contains(dict,PyString_FromString(paramName.c_str()))) )
return PyDict_GetItemString( dict, paramName.c_str() );
return NULL;
}

View File

@ -21,19 +21,19 @@ namespace Analog {
MetaCapacitor::MetaCapacitor ( Library* library, const Name& name )
: Super(library,name)
, _plate1(NULL)
, _plate2(NULL)
, _ce (0.0)
: Super(library,name)
, _topPlate(NULL)
, _botPlate(NULL)
, _ce (0.0)
{ }
MetaCapacitor* MetaCapacitor::create ( Library* library, const Name& name )
{
MetaCapacitor* mCapacitor = new MetaCapacitor( library, name );
mCapacitor->_postCreate();
MetaCapacitor* mCapacitor = new MetaCapacitor( library, name );
mCapacitor->_postCreate();
return mCapacitor;
return mCapacitor;
}
@ -41,10 +41,10 @@ namespace Analog {
{
Super::_postCreate();
_plate1 = Net::create(this, "P1");
_plate1->setExternal(true);
_plate2 = Net::create(this, "P2");
_plate2->setExternal(true);
_topPlate = Net::create( this, "T" );
_topPlate->setExternal( true );
_botPlate = Net::create( this, "B" );
_botPlate->setExternal( true );
setTerminal( false );
}

View File

@ -10,7 +10,7 @@
// | Authors : Damien Dupuis |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./MultiCapacitor.cpp" |
// | C++ Module : "./MultiCapacitor.cpp" |
// +-----------------------------------------------------------------+
@ -32,12 +32,7 @@ namespace Analog {
, size_t count )
: Super(library, name, type)
, _metaCapacitor(NULL)
, _matrix (NULL)
, _count (count)
, _cDraw (0.0)
, _cBorder (0.0)
, _cParasite (0.0)
, _capacities (NULL)
{ }
@ -48,49 +43,48 @@ namespace Analog {
{
preCreate( _capacitorName );
UpdateSession::open();
MultiCapacitor* cp = new MultiCapacitor( library, name, type, count );
cp->_postCreate( _capacitorName );
cp->createConnections();
cp->setTerminal( true );
MultiCapacitor* mc = new MultiCapacitor( library, name, type, count );
mc->_postCreate( _capacitorName );
mc->createConnections ();
mc->addMatrixParameter ( "matrix" );
mc->addCapacitiesParameter( "capacities", count );
mc->setTerminal ( true );
UpdateSession::close();
return cp;
cerr << "capacities:" << mc->getParameter( "capacities" ) << endl;
return mc;
}
void MultiCapacitor::_postCreate ( const Name& deviceName )
{
Super::_postCreate( deviceName );
// get minimum and maximum value from technology
//AnalogEnv* aenv = AnalogEnv::get();
//AnalogTechnology* atechno = aenv->getAnalogTechnology();
//DbU::Unit capacitorMinL = atechno->getPhysicalRule("capacitorMinL").getValue();
//DbU::Unit capacitorMaxL = atechno->getPhysicalRule("capacitorMaxL").getValue();
//DbU::Unit capacitorMinW = atechno->getPhysicalRule("capacitorMinW").getValue();
//DbU::Unit capacitorMaxW = atechno->getPhysicalRule("capacitorMaxW").getValue();
// For now define arbitrary values:
//DbU::Unit capacitorMinC = DbU::physicalToDbu(0.25, DbU::Micro);
//DbU::Unit capacitorMaxC = DbU::physicalToDbu(25 , DbU::Micro);
//_c = addCapacitorParameter( "C", 0.0 );
}
void MultiCapacitor::createConnections ()
{
Net* p1 = Net::create( this, Name("P1") );
p1->setExternal( true );
Net* p2 = Net::create( this, Name("P2") );
p2->setExternal( true );
_metaCapacitor = MetaCapacitor::create( getSubDevicesLibrary(), Name("C1") );
Instance* metaCapacitorIns = Instance::create( this, Name("C1Instance"), _metaCapacitor );
setReferenceCapacitor( _metaCapacitor );
Plug* mcC1Plug = metaCapacitorIns->getPlug( _metaCapacitor->getPlate1() );
mcC1Plug->setNet( p1 );
Plug* mcC2Plug = metaCapacitorIns->getPlug( _metaCapacitor->getPlate2() );
mcC2Plug->setNet( p2 );
for ( size_t i=0 ; i<_count ; ++i ) {
string topPlateName = "t" + getString(i);
string botPlateName = "b" + getString(i);
string mcName = "c" + getString(i);
Net* topPlate = Net::create( this, topPlateName );
Net* botPlate = Net::create( this, botPlateName );
MetaCapacitor* mc = MetaCapacitor::create( getSubDevicesLibrary(), mcName );
Instance* mcInst = Instance::create( this, mcName, mc );
topPlate->setExternal( true );
botPlate->setExternal( true );
mcInst->getPlug( mc->getTopPlate() )->setNet( topPlate );
mcInst->getPlug( mc->getBotPlate() )->setNet( botPlate );
if (not _metaCapacitor) {
_metaCapacitor = mc;
setReferenceCapacitor( mc );
}
}
}
@ -98,4 +92,8 @@ namespace Analog {
{ return _capacitorName; }
string MultiCapacitor::_getTypeName () const
{ return "MultiCapacitor"; }
} // Analog namespace.

View File

@ -31,13 +31,15 @@
#include "hurricane/analog/PyCapacitorFamily.h"
#include "hurricane/analog/PyMultiCapacitor.h"
#include "hurricane/analog/PyMatrix.h"
#include "hurricane/analog/PyParameter.h"
#include "hurricane/analog/PyCapacitorParameter.h"
#include "hurricane/analog/PyChoiceParameter.h"
#include "hurricane/analog/PyFormFactorParameter.h"
#include "hurricane/analog/PyMCheckBoxParameter.h"
#include "hurricane/analog/PySpinBoxParameter.h"
#include "hurricane/analog/PyStepParameter.h"
#include "hurricane/analog/PyCapacitiesParameter.h"
#include "hurricane/analog/PyMatrixParameter.h"
#include "hurricane/analog/PyLayoutGenerator.h"
@ -79,18 +81,21 @@ extern "C" {
PyLevelShifter_LinkPyType();
PySimpleCurrentMirror_LinkPyType();
PyCascode_LinkPyType();
//PyMultiCapacitor_LinkPyType();
PyMatrix_LinkPyType();
PyParameter_LinkPyType();
PyCapacitorParameter_LinkPyType();
PyChoiceParameter_LinkPyType();
PyFormFactorParameter_LinkPyType();
PyMCheckBoxParameter_LinkPyType();
PySpinBoxParameter_LinkPyType();
PyStepParameter_LinkPyType();
PyCapacitiesParameter_LinkPyType();
PyMatrixParameter_LinkPyType();
PyCapacitorFamily_LinkPyType();
PyLayoutGenerator_LinkPyType();
PyMultiCapacitor_LinkPyType();
PYTYPE_READY( Matrix )
PYTYPE_READY( Parameter )
PYTYPE_READY( LayoutGenerator )
@ -108,14 +113,15 @@ extern "C" {
PYTYPE_READY_SUB( Cascode , TransistorPair )
PYTYPE_READY_SUB( CapacitorFamily , Device )
//PYTYPE_READY_SUB( MutliCapacitor , CapacitorFamily )
PYTYPE_READY_SUB( MultiCapacitor , CapacitorFamily )
PYTYPE_READY_SUB( CapacitorParameter , Parameter )
PYTYPE_READY_SUB( ChoiceParameter , Parameter )
PYTYPE_READY_SUB( FormFactorParameter , Parameter )
PYTYPE_READY_SUB( MCheckBoxParameter , Parameter )
PYTYPE_READY_SUB( SpinBoxParameter , Parameter )
PYTYPE_READY_SUB( StepParameter , Parameter )
PYTYPE_READY_SUB( CapacitiesParameter , Parameter )
PYTYPE_READY_SUB( MatrixParameter , Parameter )
// Identifier string can take up to 10 characters !
__cs.addType( "device" , &PyTypeDevice , "<Device>" , false, "cell" );
@ -132,15 +138,17 @@ extern "C" {
__cs.addType( "cascode" , &PyTypeCascode , "<Cascode>" , false, "transpair" );
__cs.addType( "cfamily" , &PyTypeCapacitorFamily , "<CapacitorFamily>" , false, "device" );
//__cs.addType( "mulcapa" , &PyTypeMultiCapacitor , "<MultiCapacitor>" , false, "cfamily" );
__cs.addType( "mulcapa" , &PyTypeMultiCapacitor , "<MultiCapacitor>" , false, "cfamily" );
__cs.addType( "matrix" , &PyTypeMatrix , "<Matrix>" , false );
__cs.addType( "parameter", &PyTypeParameter , "<Parameter>" , false );
__cs.addType( "capapar" , &PyTypeCapacitorParameter , "<CapacitorParameter>" , false, "parameter" );
__cs.addType( "choicepar", &PyTypeChoiceParameter , "<CapacitorParameter>" , false, "parameter" );
__cs.addType( "ffpar" , &PyTypeFormFactorParameter , "<FormFactorParameter>" , false, "parameter" );
__cs.addType( "mcboxpar" , &PyTypeMCheckBoxParameter , "<MCheckBoxParameter>" , false, "parameter" );
__cs.addType( "sboxpar" , &PyTypeSpinBoxParameter , "<SpinBoxParameter>" , false, "parameter" );
__cs.addType( "steppar" , &PyTypeStepParameter , "<StepParameter>" , false, "parameter" );
__cs.addType( "capspar" , &PyTypeCapacitiesParameter , "<CapacitiesParameter>" , false, "parameter" );
__cs.addType( "matrpar" , &PyTypeMatrixParameter , "<MatrixParameter>" , false, "parameter" );
__cs.addType( "laygen" , &PyTypeLayoutGenerator , "<LayoutGenerator>" , false );
@ -178,14 +186,14 @@ extern "C" {
Py_INCREF( &PyTypeCapacitorFamily );
PyModule_AddObject( module, "CapacitorFamily" , (PyObject*)&PyTypeCapacitorFamily );
//Py_INCREF( &PyTypeMutliCapacitor );
//PyModule_AddObject( module, "MultiCapacitor" , (PyObject*)&PyTypeMultiCapacitor );
Py_INCREF( &PyTypeMultiCapacitor );
PyModule_AddObject( module, "MultiCapacitor" , (PyObject*)&PyTypeMultiCapacitor );
Py_INCREF( &PyTypeMatrix );
PyModule_AddObject( module, "Matrix" , (PyObject*)&PyTypeMatrix );
Py_INCREF( &PyTypeParameter );
PyModule_AddObject( module, "Parameter" , (PyObject*)&PyTypeParameter );
Py_INCREF( &PyTypeCapacitorParameter );
PyModule_AddObject( module, "CapacitorParameter" , (PyObject*)&PyTypeCapacitorParameter );
Py_INCREF( &PyTypeChoiceParameter );
Py_INCREF( &PyTypeParameter );
PyModule_AddObject( module, "ChoiceParameter" , (PyObject*)&PyTypeChoiceParameter );
Py_INCREF( &PyTypeFormFactorParameter );
PyModule_AddObject( module, "FormFactorParameter", (PyObject*)&PyTypeFormFactorParameter );
@ -194,6 +202,10 @@ extern "C" {
Py_INCREF( &PyTypeSpinBoxParameter );
PyModule_AddObject( module, "SpinBoxParameter" , (PyObject*)&PyTypeSpinBoxParameter );
Py_INCREF( &PyTypeStepParameter );
PyModule_AddObject( module, "CapacitiesParameter", (PyObject*)&PyTypeCapacitiesParameter );
Py_INCREF( &PyTypeCapacitiesParameter );
PyModule_AddObject( module, "MatrixParameter" , (PyObject*)&PyTypeMatrixParameter );
Py_INCREF( &PyTypeMatrixParameter );
PyModule_AddObject( module, "StepParameter" , (PyObject*)&PyTypeStepParameter );
Py_INCREF( &PyTypeLayoutGenerator );
PyModule_AddObject( module, "LayoutGenerator" , (PyObject*)&PyTypeLayoutGenerator );

View File

@ -0,0 +1,226 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2019-2019, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | H u r r i c a n e A n a l o g |
// | |
// | Author : Jean-Paul Chaput |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./PyMatrix.cpp" |
// +-----------------------------------------------------------------+
#include "hurricane/analog/PyMatrix.h"
namespace Isobar {
using namespace Hurricane;
using namespace Analog;
extern "C" {
#define METHOD_HEAD(function) GENERIC_METHOD_HEAD(Matrix,matrix,function)
#if defined(__PYTHON_MODULE__)
// +=================================================================+
// | "PyMatrix" Python Module Code Part |
// +=================================================================+
DirectGetUIntAttribute(PyMatrix_rows , rows , PyMatrix, Matrix)
DirectGetUIntAttribute(PyMatrix_columns, columns, PyMatrix, Matrix)
static PyObject* PyMatrix_NEW ( PyObject* , PyObject* args )
{
unsigned int rows = 0;
unsigned int columns = 0;
Matrix* matrix = NULL;
PyMatrix* pyMatrix = NULL;
HTRY
if (not PyArg_ParseTuple( args, "II:Matrix_NEW", &rows, &columns ) ) {
PyErr_SetString ( ConstructorError, "Matrix.create(): Invalid/bad number of parameters ." );
return NULL;
}
pyMatrix = PyObject_NEW( PyMatrix, &PyTypeMatrix );
if (pyMatrix == NULL) { return NULL; }
pyMatrix->_object = new Matrix( rows, columns );
HCATCH
return (PyObject*)pyMatrix;
}
static int PyMatrix_Init ( PyMatrix* self, PyObject* args, PyObject* kwargs )
{
cdebug_log(20,0) << "PyMatrix_Init(): " << (void*)self << endl;
return 0;
}
static PyObject* PyMatrix_resize ( PyMatrix *self, PyObject* args )
{
cdebug_log(20,0) << "PyMatrix.resize()" << endl;
HTRY
METHOD_HEAD ( "Matrix.resize()" )
unsigned int rows = 0;
unsigned int columns = 0;
if (PyArg_ParseTuple(args,"II:Matrix.resize",&rows,&columns)) {
matrix->resize( (size_t)rows, (size_t)columns );
} else {
PyErr_SetString( ConstructorError, "Matrix.resize(): Invalid number/bad type of parameters." );
return NULL;
}
HCATCH
Py_RETURN_NONE;
}
static PyObject* PyMatrix_getValue ( PyMatrix *self, PyObject* args )
{
cdebug_log(20,0) << "PyMatrix.getValue()" << endl;
size_t value = 0;
HTRY
METHOD_HEAD ( "Matrix.getValue()" )
unsigned int row = 0;
unsigned int column = 0;
if (PyArg_ParseTuple(args,"II:Matrix.getValue",&row,&column)) {
value = matrix->at( (size_t)row, (size_t)column );
} else {
PyErr_SetString( ConstructorError, "Matrix.getValue(): Invalid number/bad type of parameters." );
return NULL;
}
HCATCH
return Py_BuildValue("I",(unsigned int)value);
}
static PyObject* PyMatrix_setValue ( PyMatrix *self, PyObject* args )
{
cdebug_log(20,0) << "PyMatrix.setValue()" << endl;
HTRY
METHOD_HEAD ( "Matrix.setValue()" )
unsigned int row = 0;
unsigned int column = 0;
unsigned int value = 0;
if (PyArg_ParseTuple(args,"III:Matrix.setValue",&row,&column,&value)) {
matrix->at( (size_t)row, (size_t)column ) = value;
} else {
PyErr_SetString( ConstructorError, "Matrix.setValue(): Invalid number/bad type of parameters." );
return NULL;
}
HCATCH
Py_RETURN_NONE;
}
// ---------------------------------------------------------------
// PyMatrix Attribute Method table.
PyMethodDef PyMatrix_Methods[] =
{ { "rows" , (PyCFunction)PyMatrix_rows , METH_NOARGS
, "Self explanatory." }
, { "columns" , (PyCFunction)PyMatrix_columns, METH_NOARGS
, "Self explanatory." }
, { "resize" , (PyCFunction)PyMatrix_resize , METH_VARARGS
, "Self explanatory." }
, { "getValue" , (PyCFunction)PyMatrix_getValue , METH_VARARGS
, "Self explanatory." }
, { "setValue" , (PyCFunction)PyMatrix_setValue , METH_VARARGS
, "Self explanatory." }
, { NULL, NULL, 0, NULL } /* sentinel */
};
// +-------------------------------------------------------------+
// | "PyMatrix" Object Methods |
// +-------------------------------------------------------------+
DirectDeleteMethod(PyMatrix_DeAlloc,PyMatrix)
PyTypeObjectLinkPyTypeNewInit(Matrix)
#else // End of Python Module Code Part.
// +=================================================================+
// | "PyMatrix" Shared Library Code Part |
// +=================================================================+
PyTypeObjectDefinitions(Matrix)
extern Matrix Matrix_FromListOfList ( PyObject* pyLoList )
{
Matrix matrix;
if (not PyList_Check(pyLoList)) {
PyErr_SetString( ConstructorError, "Matrix_FromListOfList(): First level type is *not* a list." );
return matrix;
}
Py_ssize_t rows = PyList_Size( pyLoList );
Py_ssize_t cols = 0;
for ( Py_ssize_t rowIndex = 0; rowIndex<rows ; ++rowIndex ) {
PyObject* row = PyList_GetItem( pyLoList, rowIndex );
if (not PyList_Check(row)) {
ostringstream message;
message << "Matrix_FromListOfList(): Row [" << rowIndex << "] type is *not* list.";
PyErr_SetString( ConstructorError, message.str().c_str() );
return matrix.makeEmpty();
}
if (not cols) {
cols = PyList_Size( row );
matrix.resize( rows, cols );
} else {
if (cols != PyList_Size(row)) {
ostringstream message;
message << "Matrix_FromListOfList(): Row [0] and [" << rowIndex << "] have different sizes ("
<< cols << " vs. " << PyList_Size(row) << ").";
PyErr_SetString( ConstructorError, message.str().c_str() );
return matrix.makeEmpty();
}
}
for ( Py_ssize_t colIndex = 0; colIndex<cols ; ++colIndex ) {
PyObject* element = PyList_GetItem( row, colIndex );
if (not PyInt_Check(element)) {
ostringstream message;
message << "Matrix_FromListOfList(): Element [" << colIndex << "," << rowIndex << "] is not an integer.";
PyErr_SetString( ConstructorError, message.str().c_str() );
return matrix.makeEmpty();
}
matrix.at( rowIndex, colIndex ) = (size_t)PyInt_AsLong( element );
}
}
return matrix;
}
#endif // End of Shared Library Code Part.
} // extern "C".
} // Isobar namespace.

View File

@ -14,6 +14,7 @@
// +-----------------------------------------------------------------+
#include "hurricane/analog/PyMatrix.h"
#include "hurricane/analog/PyMatrixParameter.h"
@ -42,6 +43,26 @@ extern "C" {
DirectGetUIntAttribute(PyMatrixParameter_getColumns, getColumns, PyMatrixParameter, MatrixParameter)
static PyObject* PyMatrixParameter_resize ( PyMatrixParameter *self, PyObject* args )
{
cdebug_log(20,0) << "PyMatrixParameter.resize()" << endl;
HTRY
METHOD_HEAD ( "MatrixParameter.resize()" )
unsigned int rows = 0;
unsigned int columns = 0;
if (PyArg_ParseTuple(args,"II:MatrixParameter.resize",&rows,&columns)) {
matrixParameter->resize( (size_t)rows, (size_t)columns );
} else {
PyErr_SetString( ConstructorError, "MatrixParameter.resize(): Invalid number/bad type of parameters." );
return NULL;
}
HCATCH
Py_RETURN_NONE;
}
static PyObject* PyMatrixParameter_getValue ( PyMatrixParameter *self, PyObject* args )
{
cdebug_log(20,0) << "PyMatrixParameter.getValue()" << endl;
@ -85,6 +106,36 @@ extern "C" {
}
static PyObject* PyMatrixParameter_setMatrix ( PyMatrixParameter *self, PyObject* args )
{
cdebug_log(20,0) << "PyMatrixParameter.setMatrix()" << endl;
HTRY
METHOD_HEAD ( "MatrixParameter.setMatrix()" )
PyObject* pyMatrix = NULL;
if (not PyArg_ParseTuple(args,"O:MatrixParameter.setMatrix",&pyMatrix)) {
PyErr_SetString( ConstructorError, "MatrixParameter.setValue(): Invalid number/bad type of parameters." );
return NULL;
}
if (not IsPyMatrix(pyMatrix)) {
if (not PyList_Check(pyMatrix)) {
PyErr_SetString( ConstructorError, "MatrixParameter.setMatrix(): Argument is neither of type Matrix not list of list." );
return NULL;
}
Matrix m = Matrix_FromListOfList( pyMatrix );
if (m.empty()) return NULL;
matrixParameter->setMatrix( &m );
} else {
matrixParameter->setMatrix( PYMATRIX_O(pyMatrix) );
}
HCATCH
Py_RETURN_NONE;
}
// ---------------------------------------------------------------
// PyMatrixParameter Attribute Method table.
@ -93,10 +144,14 @@ extern "C" {
, "Self explanatory." }
, { "getColumns" , (PyCFunction)PyMatrixParameter_getColumns, METH_NOARGS
, "Self explanatory." }
, { "resize" , (PyCFunction)PyMatrixParameter_resize , METH_VARARGS
, "Self explanatory." }
, { "getValue" , (PyCFunction)PyMatrixParameter_getValue , METH_VARARGS
, "Self explanatory." }
, { "setValue" , (PyCFunction)PyMatrixParameter_setValue , METH_VARARGS
, "Self explanatory." }
, { "setMatrix" , (PyCFunction)PyMatrixParameter_setMatrix , METH_VARARGS
, "Self explanatory." }
, { NULL, NULL, 0, NULL } /* sentinel */
};
@ -113,7 +168,7 @@ extern "C" {
#else // End of Python Module Code Part.
// +=================================================================+
// | "PyMatrixParameter" Shared Library Code Part |
// | "PyMatrixParameter" Shared Library Code Part |
// +=================================================================+

View File

@ -43,7 +43,7 @@ extern "C" {
{
cdebug.log(49) << "PyMultiCapacitor_create()" << endl;
MultiCapacitor* transistor = NULL;
MultiCapacitor* mcapacitor = NULL;
HTRY
PyObject* pyLibrary = NULL;
@ -71,7 +71,7 @@ extern "C" {
return NULL;
}
transistor = MultiCapacitor::create( PYLIBRARY_O(pyLibrary)
mcapacitor = MultiCapacitor::create( PYLIBRARY_O(pyLibrary)
, Name(name)
, (MultiCapacitor::Type)pyType
, (size_t)count
@ -82,7 +82,7 @@ extern "C" {
}
HCATCH
return PyMultiCapacitor_Link(transistor);
return PyMultiCapacitor_Link(mcapacitor);
}

View File

@ -15,7 +15,8 @@
#include "hurricane/analog/PyParameter.h"
#include "hurricane/analog/PyCapacitorParameter.h"
#include "hurricane/analog/PyMatrixParameter.h"
#include "hurricane/analog/PyCapacitiesParameter.h"
#include "hurricane/analog/PyChoiceParameter.h"
#include "hurricane/analog/PyFormFactorParameter.h"
#include "hurricane/analog/PyMCheckBoxParameter.h"
@ -98,8 +99,11 @@ extern "C" {
{
if (object == NULL) Py_RETURN_NONE;
CapacitorParameter* capacitorParameter = dynamic_cast<CapacitorParameter*>(object);
if (capacitorParameter) return PyCapacitorParameter_Link(capacitorParameter);
CapacitiesParameter* capacitiesParameter = dynamic_cast<CapacitiesParameter*>(object);
if (capacitiesParameter) return PyCapacitiesParameter_Link(capacitiesParameter);
MatrixParameter* matrixParameter = dynamic_cast<MatrixParameter*>(object);
if (matrixParameter) return PyMatrixParameter_Link(matrixParameter);
ChoiceParameter* choiceParameter = dynamic_cast<ChoiceParameter*>(object);
if (choiceParameter) return PyChoiceParameter_Link(choiceParameter);

View File

@ -52,7 +52,7 @@ namespace Analog {
typedef std::map<const Hurricane::Name,const std::string> Layouts;
public:
virtual Hurricane::Name getDeviceName () const = 0;
Parameter* getParameter ( const std::string& parameterId );
Parameter* getParameter ( const std::string& parameterId ) const;
inline Parameters& getParameters ();
const std::string getLayoutScript ();
inline float getTemperature () const;

View File

@ -44,19 +44,6 @@ namespace Analog {
class LayoutGenerator {
public:
class Logger {
public:
Logger ( LayoutGenerator* );
virtual ~Logger ();
inline LayoutGenerator* getGenerator ();
virtual void popStatus ( const std::string& );
virtual void popError ( const std::string& );
virtual void popScriptError ();
private:
LayoutGenerator* _generator;
};
public:
typedef std::map<std::string, std::map<std::string, double> > ParamMap;
enum Verbose { Quiet = 0
@ -77,7 +64,6 @@ namespace Analog {
public:
LayoutGenerator ();
~LayoutGenerator ();
inline Logger* getLogger ();
inline Device* getDevice ();
unsigned getNumberTransistor ();
unsigned getNumberStack ();
@ -87,16 +73,11 @@ namespace Analog {
PyObject* getRow ( unsigned i );
PyObject* getDic ( PyObject* row, unsigned j );
PyObject* getParamValue ( PyObject* dic, std::string paramName );
// double getParameterValue ( std::string trName , std::string paramName, bool& ok );
double getParameterValue ( unsigned i, unsigned j, std::string paramName, bool& ok );
inline double unitToMicro ( int );
inline double unitToMetter ( int );
public:
inline void setLogger ( Logger* );
inline void setDevice ( Device* );
inline void popStatus ( const std::string& );
inline void popError ( const std::string& );
inline void popScriptError ();
bool initialize ();
void finalize ( unsigned int flags );
bool checkScript ();
@ -108,7 +89,6 @@ namespace Analog {
private:
static int _verboseLevel;
private:
Logger* _logger;
Device* _device;
Hurricane::Box* _box;
Hurricane::Box* _activeBox;
@ -117,17 +97,10 @@ namespace Analog {
};
inline LayoutGenerator* LayoutGenerator::Logger::getGenerator () { return _generator; }
inline int LayoutGenerator::getVerboseLevel () { return _verboseLevel; }
inline LayoutGenerator::Logger* LayoutGenerator::getLogger () { return _logger; }
inline Device* LayoutGenerator::getDevice () { return _device; }
inline void LayoutGenerator::setDevice ( Device* device ) { _device = device; }
inline void LayoutGenerator::setVerboseLevel (int lvl ) { _verboseLevel = lvl; }
inline void LayoutGenerator::popStatus ( const std::string& text ) { if (_logger) _logger->popStatus(text); }
inline void LayoutGenerator::popError ( const std::string& text ) { if (_logger) _logger->popError(text); }
inline void LayoutGenerator::popScriptError () { if (_logger) _logger->popScriptError(); }
inline PyObject* LayoutGenerator::getMatrix () { return _matrix; }
inline double LayoutGenerator::unitToMicro ( int unit ) {
@ -138,12 +111,6 @@ namespace Analog {
return Hurricane::DbU::getPhysical(Hurricane::DbU::getOnPhysicalGrid(unit), Hurricane::DbU::Unity);
}
inline void LayoutGenerator::setLogger ( Logger* logger )
{
if ( _logger ) delete _logger;
_logger = logger;
}
} // Analog namespace.

View File

@ -22,15 +22,18 @@ namespace Analog {
class Matrix {
public:
inline Matrix ( size_t rows, size_t columns );
inline Matrix ( size_t rows=0, size_t columns=0 );
inline Matrix ( const Matrix& );
inline ~Matrix ();
inline bool empty () const;
inline Matrix& operator= ( const Matrix& );
inline size_t rows () const;
inline size_t columns () const;
inline size_t at ( size_t row, size_t column ) const;
inline size_t& at ( size_t row, size_t column );
inline size_t index ( size_t row, size_t column ) const;
inline size_t at ( size_t row , size_t column ) const;
inline size_t& at ( size_t row , size_t column );
inline size_t index ( size_t row , size_t column ) const;
inline void resize ( size_t rows, size_t columns );
inline Matrix& makeEmpty ();
private:
size_t _rows;
size_t _columns;
@ -41,7 +44,11 @@ namespace Analog {
inline Matrix::Matrix ( size_t rows, size_t columns )
: _rows(rows), _columns(columns), _table(NULL)
{
_table = new size_t [ _rows * _columns ];
if (empty()) {
_rows = 0;
_columns = 0;
} else
_table = new size_t [ _rows * _columns ];
}
@ -71,7 +78,31 @@ namespace Analog {
return *this;
}
inline void Matrix::resize ( size_t rows, size_t columns )
{
if (rows * columns > _rows * _columns) {
delete [] _table;
_table = new size_t [ rows * columns ];
}
_rows = rows;
_columns = columns;
}
inline Matrix& Matrix::makeEmpty ()
{
delete [] _table;
_rows = 0;
_columns = 0;
return *this;
}
inline bool Matrix::empty () const { return not _rows or not _columns; }
inline size_t Matrix::rows () const { return _rows; }
inline size_t Matrix::columns () const { return _columns; }
inline size_t Matrix::at ( size_t row, size_t column ) const { return _table[ index(row,column) ]; }

View File

@ -28,8 +28,10 @@ namespace Analog {
inline MatrixParameter ( std::string id, size_t rows=1, size_t columns=1 );
inline size_t getRows () const;
inline size_t getColumns () const;
inline size_t getValue ( size_t row, size_t column ) const;
inline void setValue ( size_t row, size_t column, size_t value );
inline size_t getValue ( size_t row , size_t column ) const;
inline void setValue ( size_t row , size_t column , size_t value );
inline void setMatrix ( const Matrix* );
inline void resize ( size_t rows, size_t columns );
private:
Matrix _matrix;
};
@ -42,8 +44,10 @@ namespace Analog {
inline size_t MatrixParameter::getRows () const { return _matrix.rows (); }
inline size_t MatrixParameter::getColumns () const { return _matrix.columns(); }
inline size_t MatrixParameter::getValue ( size_t row, size_t column ) const { return _matrix.at(row,column); }
inline void MatrixParameter::setValue ( size_t row, size_t column, size_t value ) { _matrix.at(row,column) = value; }
inline size_t MatrixParameter::getValue ( size_t row , size_t column ) const { return _matrix.at(row,column); }
inline void MatrixParameter::setValue ( size_t row , size_t column , size_t value ) { _matrix.at(row,column) = value; }
inline void MatrixParameter::resize ( size_t rows, size_t columns ) { _matrix.resize(rows,columns); }
inline void MatrixParameter::setMatrix ( const Matrix* from ) { _matrix = *from; }
} // Analog namespace.

View File

@ -30,25 +30,25 @@ namespace Analog {
typedef Cell Super;
public:
static MetaCapacitor* create ( Library* library, const Name& );
inline Net* getPlate1 ();
inline Net* getPlate2 ();
inline Net* getTopPlate ();
inline Net* getBotPlate ();
inline double getCE () const;
inline void setCE (double ce);
inline void setCE ( double );
protected:
void _postCreate ();
private:
MetaCapacitor ( Library* , const Name& );
private:
Net* _plate1;
Net* _plate2;
Net* _topPlate;
Net* _botPlate;
double _ce;
};
inline Net* MetaCapacitor::getPlate1 () { return _plate1; }
inline Net* MetaCapacitor::getPlate2 () { return _plate2; }
inline double MetaCapacitor::getCE () const { return _ce; }
inline void MetaCapacitor::setCE ( double ce ) { _ce = ce; }
inline Net* MetaCapacitor::getTopPlate () { return _topPlate; }
inline Net* MetaCapacitor::getBotPlate () { return _botPlate; }
inline double MetaCapacitor::getCE () const { return _ce; }
inline void MetaCapacitor::setCE ( double ce ) { _ce = ce; }
} // Analog namespace.

View File

@ -36,9 +36,6 @@ namespace Analog {
, const CapacitorFamily::Type&
, size_t count );
inline double getCapacity ( size_t ) const;
inline double getCDraw () const;
inline double getCBorder () const;
inline double getCParasite () const;
virtual Hurricane::Name getDeviceName () const;
protected:
MultiCapacitor ( Hurricane::Library*
@ -47,24 +44,21 @@ namespace Analog {
, size_t );
virtual void _postCreate ( const Hurricane::Name& deviceName );
virtual void createConnections ();
public:
virtual std::string _getTypeName () const;
private:
static const Hurricane::Name _capacitorName;
MetaCapacitor* _metaCapacitor;
MatrixParameter* _matrix;
size_t _count;
double _cDraw;
double _cBorder;
double _cParasite;
CapacitiesParameter* _capacities;
};
double MultiCapacitor::getCapacity ( size_t i ) const { return _capacities->getValue(i); }
double MultiCapacitor::getCDraw () const { return _cDraw; }
double MultiCapacitor::getCBorder () const { return _cBorder; }
double MultiCapacitor::getCParasite () const { return _cParasite; }
double MultiCapacitor::getCapacity ( size_t i ) const { return static_cast<const CapacitiesParameter*>(getParameter("capacities"))->getValue(i); }
} // Analog namespace.
INSPECTOR_P_SUPPORT(Analog::MultiCapacitor);
#endif // ANALOH_MULTI_CAPACITOR_H

View File

@ -0,0 +1,56 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2019-2019, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | H u r r i c a n e A n a l o g |
// | |
// | Author : Jean-Paul Chaput |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./hurricane/analog/PyMatrix.h" |
// +-----------------------------------------------------------------+
#ifndef ANALOG_PY_MATRIX_H
#define ANALOG_PY_MATRIX_H
#include "hurricane/isobar/PyHurricane.h"
#include "hurricane/analog/Matrix.h"
namespace Isobar {
extern "C" {
// -------------------------------------------------------------------
// Python Object : "PyMatrix".
typedef struct {
PyObject_HEAD
Analog::Matrix* _object;
} PyMatrix;
// -------------------------------------------------------------------
// Functions & Types exported to "PyHurricane.cpp".
extern PyTypeObject PyTypeMatrix;
extern PyMethodDef PyMatrix_Methods[];
extern void PyMatrix_LinkPyType ();
extern Analog::Matrix Matrix_FromListOfList ( PyObject* );
#define IsPyMatrix(v) ( (v)->ob_type == &PyTypeMatrix )
#define PYMATRIX(v) ( (PyMatrix*)(v) )
#define PYMATRIX_O(v) ( PYMATRIX(v)->_object )
} // extern "C".
} // Isobar namespace.
#endif // ANALOG_PY_MATRIX_H

View File

@ -124,7 +124,7 @@ namespace Analog {
inline void TransistorFamily::setSourceFirst ( const bool sourceFirst ) { _sourceFirst->setValue ( (sourceFirst)?1:0 ); }
inline void TransistorFamily::setWmin ( float wmin ) { _secureGetReferenceTransistor()->setWmin (wmin ); }
inline void TransistorFamily::setWmax ( float wmax ) { _secureGetReferenceTransistor()->setWmax (wmax ); }
inline void TransistorFamily::setNfing ( int nfing ) { _secureGetReferenceTransistor()->setNfing(nfing); }
inline void TransistorFamily::setNfing ( int nfing ) { _secureGetReferenceTransistor()->setNfing(nfing); _m->setValue(nfing); }
inline void TransistorFamily::setExternalDummy ( long ndumm ) { _externalDummy->setValue(ndumm); }
inline void TransistorFamily::setBulkType ( long btype ) { _bulkType->setValue(btype); }
inline void TransistorFamily::setWE ( float we ) { _secureGetReferenceTransistor()->setWE (we ); }

View File

@ -519,6 +519,10 @@ namespace Hurricane {
{
Name layerName ( layerStr );
const Layer* layer = getLayer( layerName );
if (not layer)
throw Error( "Technology::getPhysicalRule(): Layer \"%s\" is not defined (yet?)."
, layerStr.c_str() );
OneLayerRules::const_iterator ilayer = _oneLayerRules.find( layer );
if (ilayer == _oneLayerRules.end())

View File

@ -30,13 +30,13 @@ namespace Hurricane {
{ return lmd->getName() < rmd->getName(); }
};
public:
inline ModelDescriptor ( const Name& name
, const Name& simul
, const Name& model
, std::string netlist
, const Name& name_n
, const Name& name_p
, bool precise );
inline ModelDescriptor ( const Name& name
, const Name& simul
, const Name& model
, std::string netlist
, const Name& name_n
, const Name& name_p
, bool precise );
inline Name getName () const;
inline Name getSimulator () const;
inline Name getModel () const;
@ -45,23 +45,23 @@ namespace Hurricane {
inline Name getName_P () const;
inline bool isPrecise () const;
private:
Name _name;
Name _simulator;
Name _model;
std::string _netlist;
Name _name_N;
Name _name_P;
bool _precise;
Name _name;
Name _simulator;
Name _model;
std::string _netlist;
Name _name_N;
Name _name_P;
bool _precise;
};
inline ModelDescriptor::ModelDescriptor( const Name& name
, const Name& simul
, const Name& model
, std::string netlist
, const Name& name_n
, const Name& name_p
, bool precise )
inline ModelDescriptor::ModelDescriptor( const Name& name
, const Name& simul
, const Name& model
, std::string netlist
, const Name& name_n
, const Name& name_p
, bool precise )
: _name (name)
, _simulator(simul)
, _model (model)

View File

@ -1442,7 +1442,7 @@ extern "C" {
PyTypeObject PyType##SELF_TYPE = \
{ PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType##INHERITED_TYPE)) \
0 /* ob_size. */ \
, "Hurricane.Py" #SELF_TYPE /* tp_name. */ \
, "Hurricane." #SELF_TYPE /* tp_name. */ \
, sizeof(Py##SELF_TYPE) /* tp_basicsize. */ \
, 0 /* tp_itemsize. */ \
/* methods. */ \
@ -1562,32 +1562,33 @@ extern "C" {
# define HCATCH \
} \
catch ( const Warning& w ) { \
std::string message = "\n" + getString(w); \
std::string message = getString(w); \
PyErr_Warn ( HurricaneWarning, const_cast<char*>(message.c_str()) ); \
} \
catch ( const Error& e ) { \
std::string message = "\n" + getString(e) + "\n" + e.where(); \
std::string message = getString(e); \
if (not e.where().empty()) message += "\n" + e.where(); \
PyErr_SetString ( HurricaneError, message.c_str() ); \
return NULL; \
} \
catch ( const Bug& e ) { \
std::string message = "\n" + getString(e); \
std::string message = getString(e); \
PyErr_SetString ( HurricaneError, message.c_str() ); \
return NULL; \
} \
catch ( const Exception& e ) { \
std::string message = "\nUnknown Hurricane::Exception"; \
std::string message = "Unknown Hurricane::Exception"; \
PyErr_SetString ( HurricaneError, message.c_str() ); \
return NULL; \
} \
catch ( const std::exception& e ) { \
std::string message = "\n" + std::string(e.what()); \
std::string message = std::string(e.what()); \
PyErr_SetString ( HurricaneError, message.c_str() ); \
return NULL; \
} \
catch ( ... ) { \
std::string message = \
"\nUnmanaged exception, neither a Hurricane::Error nor" \
"Unmanaged exception, neither a Hurricane::Error nor" \
" a std::exception."; \
PyErr_SetString ( HurricaneError, message.c_str() ); \
return NULL; \

View File

@ -48,6 +48,7 @@ namespace Isobar {
static Script* create ( const std::string& name="" );
void destroy ();
inline std::string getUserModuleName () const;
inline const char* getFileName () const;
inline PyObject* getSysModule ();
inline PyObject* getHurricaneModule ();
inline PyObject* getUserModule ();
@ -92,6 +93,9 @@ namespace Isobar {
inline PyObject* Script::getHurricaneModule () { return _hurricaneModule; }
inline PyObject* Script::getUserModule () { return _userModule; }
inline const char* Script::getFileName () const
{ return (_userModule) ? PyModule_GetFilename(_userModule) : getUserModuleName().c_str(); }
inline PyObject* Script::_importHurricane ( unsigned int flags )
{ return _hurricaneModule = _importModule("Hurricane",flags); }

View File

@ -22,6 +22,7 @@ from helpers import isderived
from helpers import trace
from helpers.io import ErrorMessage as Error
from Analog import Device
from Analog import TransistorFamily
from Analog import Transistor
from Analog import CommonDrain
from Analog import CommonGatePair
@ -30,7 +31,13 @@ from Analog import CrossCoupledPair
from Analog import DifferentialPair
from Analog import LevelShifter
from Analog import SimpleCurrentMirror
from Analog import CapacitorFamily
from Analog import MultiCapacitor
from Analog import LayoutGenerator
from Analog import Matrix
from Bora import ParameterRange
from Bora import StepParameterRange
from Bora import MatrixParameterRange
from Bora import SlicingNode
from Bora import HSlicingNode
from Bora import VSlicingNode
@ -45,6 +52,9 @@ import Bora
NMOS = Transistor.NMOS
PMOS = Transistor.PMOS
PIP = CapacitorFamily.PIP
MIM = CapacitorFamily.MIM
MOM = CapacitorFamily.MOM
Center = SlicingNode.AlignCenter
Left = SlicingNode.AlignLeft
Right = SlicingNode.AlignRight
@ -60,6 +70,31 @@ 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 %d is not a list.' % row
sys.exit( 1 )
if row == 0:
columnCount = len(column)
matrix = Matrix( rowCount, columnCount )
else:
if columnCount != len(column):
print '[ERROR] readMatrix(): Column %d size discrepency (sould be %d).' % (len(column),columnCount)
sys.exit( 1 )
for column in range(len(column)):
matrix.setValue( row, column, rows[row][column] )
return matrix
class AnalogDesign ( object ):
@ -214,49 +249,74 @@ class AnalogDesign ( object ):
if not isinstance(dspec,list):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], is *not* a list.' % count
, '%s' % str(dspec) ])
if len(dspec) < 12:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], has %d items instead of 12 .' \
% (count,len(dspec))
, '%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 = 6
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 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
if specSize == 12:
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[11],bool):
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], field [11] (bulk connected) is *not* a boolean.' % count
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 specSize == 6:
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) ])
else:
raise Error( 3, [ 'AnalogDesign.doDevices(): \"self.devicesSpecs\" entry [%d], spec list do not match any known pattern.' % count
, '%s' % str(dspec) ])
return
@ -310,19 +370,35 @@ class AnalogDesign ( object ):
self.checkDSpec( count, dspec )
trace( 110, '\tBuilding \"%s\"\n' % dspec[1] )
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 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) > 12): device.getParameter( 'NERC' ).setValue(int (dspec[12]))
if (len(dspec) > 13): device.getParameter( 'NIRC' ).setValue(int (dspec[13]))
if not (dspec[7] is None): device.setMint ( dspec[7] )
if dspec[8]: device.setExternalDummy( dspec[8] )
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): capaCount = 1
elif isinstance(dspec[4],tuple): capaCount = len(dspec[4])
else:
print type(dspec[4]), dspec[4]
device = dspec[0].create( self.library, dspec[1], dspec[3], capaCount )
device.getParameter( 'Layout Styles' ).setValue ( dspec[2] )
device.getParameter( 'matrix' ).setMatrix( dspec[5] )
if isinstance(dspec[4],float):
device.getParameter( 'capacities' ).setValue( 0, dspec[4] )
else:
for index in range(len(dspec[4])):
device.getParameter( 'capacities' ).setValue( index, dspec[4][index] )
self.generator.setDevice ( device )
self.generator.drawLayout()
@ -504,7 +580,7 @@ class AnalogDesign ( object ):
return
def addDevice ( self, name, align, span=(0, 0, 0), NF=0 ):
node = DSlicingNode.create( name, self.cell, span[0], span[1], span[2], self.rg )
node = DSlicingNode.create( name, self.cell, StepParameterRange(span[0], span[1], span[2]), self.rg )
node.setAlignment( align )
if NF != 0: node.setNFing( NF )
self.topNode().push_back( node )

View File

@ -7,6 +7,11 @@
WIP_Transistor.py
WIP_DP.py
WIP_CSP.py
CapacitorUnit.py
CapacitorMatrix.py
CapacitorVRTracks.py
CapacitorRouted.py
MultiCapacitor.py
)
install( FILES ${pythonFiles} DESTINATION ${PYTHON_SITE_PACKAGES}/oroshi )

View File

@ -0,0 +1,602 @@
#!/usr/bin/python
import sys
from Hurricane import *
from CRL import *
from math import sqrt, ceil
from helpers.io import ErrorMessage as Error
from helpers import trace
from CapacitorUnit import CapacitorUnit
import helpers
import oroshi
import numpy
## Draws the layout of a compact capacitor or a matrix of adjacent identical capacitors. The matrix can be composed of one type of capacitors, either Poly-Poly or Metal-Metal in 350 nm AMS CMOS technology.
# When matching mode is off, every adjacent plates of any consecutive elementary capacitors are connected to each other using vertical routing layers.
# Otherwise, when matching mode is on, any of elementary capacitors can belong to, \f$ C_1 \f$ or \f$ C_2 \f$ according to the entered matching scheme. Thus, routing is not done in this class.
# In both modes, the complete routing process is done using the \c RoutCapacitor class.
class CapacitorStack( CapacitorUnit ):
rules = oroshi.getRules()
## This is the class constructor. Basically, the class there are three categories of attributes. There are the ones related to the capacitor caracteristics, its type, dimensions. Also, there are attributes to parametrize the class into matching mode or not and there are other attributes realted to the layout varibales. The class has defaut input values, thus, in this constructor, there are two "sub-constructors" according to the entered input parameters. The class attributes are :
#
# \param device The Hurricane AMS device into which the layout is drawn.
# \param capacitance The value of the capacitor, expressed in femto Farad (fF).
# \param capacitorType Can be MIM or PIP type capacitor.
# \param abutmentPosition Refers to the abscissa (XMin) of the bottom left corner of the abutment Box.
# \param abutmentBoxYMin Refers to the ordinate (YMin) of the bottom left corner of the abutment Box.
#
# Except the two last arguments, all the parameters are common with the CapacitorUnit class because the \c CapacitorStack constructor calls the mother class constructor to create either a compact capacitor of \c capacitance value or \c rowNumber* \c columnNumber unity capacitors.
#
# \param rowNumber Number of rows in the matrix of capacitors.
# \param columnNumber Number of columns in the matrix of capacitors.
def __init__( self, device, capacitance, capacitorType, abutmentBoxPosition, nets, unitCap = 0, matrixDim = [1,1], matchingMode = False, matchingScheme = [], dummyRing = False, dummyElement = False ):
self.device = device
self.capacitorType = capacitorType
self.matrixDim = { "columns" : matrixDim[1], "rows" : matrixDim[0] }
self.unitCapDim = self.__computeCapDim__( unitCap , capacitorType )
self.doMatrix = False
self.abutmentBox = Box()
self.abutmentBoxPosition = { "XMin" : abutmentBoxPosition[0], "YMin" : abutmentBoxPosition[1] }
self.nets = nets
self.matchingMode = matchingMode
self.dummyRing = dummyRing
self.dummyElement = dummyElement
self.capacitorsNumber = len(capacitance)
self.matchingScheme = matchingScheme
self.dummyRingPosition = {}
self.abutmentBox_spacing = 0
self.vRoutingTrack_width = 0
if self.__areInputDataOK__(capacitance) == True :
if self.matchingMode == False :
self.compactCapDim = self.__computeCapDim__( capacitance[0] , capacitorType )
if unitCap == 0 :
self.__initGivenZeroUnitCap__( capacitance[0] )
elif unitCap <> 0 and CapacitorUnit.__isCapacitorUnitOK__( self, self.unitCapDim ) :
self.__initGivenNonZeroUnitCap__( capacitance[0], unitCap )
else : raise Error( 1, '__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim )
else :
if unitCap == 0 :
self.__initGivenZeroUnitCapInMatchingMode__( capacitance )
elif unitCap <> 0 and CapacitorUnit.__isCapacitorUnitOK__( self, self.unitCapDim ) :
self.__initGivenNonZeroUnitCapInMatchingMode__( capacitance, unitCap )
else : raise Error( 1, '__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim )
return
def setRules( self ) :
CapacitorUnit.setRules ( self )
CapacitorUnit.__setattr__ ( self, "minWidth_vRoutingTrack" , CapacitorStack.rules.minWidth_metal3 )
CapacitorUnit.__setattr__ ( self, "minSpacing_vRoutingTrack" , CapacitorStack.rules.minSpacingWide1_metal3 )
CapacitorUnit.__setattr__ ( self, "minWidth_vRoutingTrackCut" , CapacitorStack.rules.minWidth_cut2 )
CapacitorUnit.__setattr__ ( self, "minSpacing_vRoutingTrackCut" , CapacitorStack.rules.minSpacing_cut2 )
CapacitorUnit.__setattr__ ( self, "minEnclosure_vRoutingTrackCut" , CapacitorStack.rules.minEnclosure_metal3_cut2 )
if self.capacitorType == 'MIMCap':
CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minWidth_cut2 )
CapacitorUnit.__setattr__ ( self, "minEnclosure_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minEnclosure_metal2_cut2 )
elif self.capacitorType == 'PIPCap' :
CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minWidth_cut1 )
CapacitorUnit.__setattr__ ( self, "minEnclosure_hRoutingLayer_topPlate_cut" , CapacitorStack.rules.minEnclosure_metal2_cut1 )
else: raise Error( 1, 'setRules() : Unsupported capacitor type : %s.' %self.capacitorType )
return
def __initMatchingMode__( self ) :
self.vRoutingTrack_width = max( self.minWidth_vRoutingTrack, 2*self.minEnclosure_vRoutingTrackCut + self.minWidth_vRoutingTrackCut,self.minWidth_hRoutingLayer_topPlate_cut + 2*self.minEnclosure_hRoutingLayer_topPlate_cut )
[factor1 , factor2 ] = [ self.capacitorsNumber , (self.capacitorsNumber +1) ] if ( self.capacitorsNumber % 2 == 0 ) else [ self.capacitorsNumber +1 , self.capacitorsNumber +2 ]
# if self.dummyElement == True : [factor1 , factor2 ] = [factor1 + 1 , factor2 + 1 ]
self.abutmentBox_spacing = factor1*self.vRoutingTrack_width + factor2*self.minSpacing_vRoutingTrack
return
def __initMatrixMode__( self, capacitance, unitCap ) :
[ self.capacitance, self.unitCapacitance , self.doMatrix ] = [ capacitance , unitCap , True ]
return
def __initGivenZeroUnitCap__( self, capacitance ):
if ( self.matrixDim.values() == [1,1] and CapacitorUnit.__isCapacitorUnitOK__(self, self.compactCapDim) ):
[ self.capacitance , self.unitCapDim ] = [ capacitance , self.compactCapDim ]
elif ( self.matrixDim.values() == [1,1] and not(CapacitorUnit.__isCapacitorUnitOK__( self, self.compactCapDim)) ): raise Error(1, '__init__(): Impossible to draw the capacitor, dimensions are either too large or too small, "%s".' % self.compactCapDim ) #com2 : use to physical
elif ( self.matrixDim["columns"]>1 or self.matrixDim["rows"]>1) :
unitCapacitance = capacitance / (self.matrixDim["columns"]*self.matrixDim["rows"])
unitCapDim = self.__computeCapDim__( unitCapacitance, self.capacitorType )
if CapacitorUnit.__isCapacitorUnitOK__(self, unitCapDim) == True :
self.unitCapDim = unitCapDim
[ self.unitCapacitance , self.capacitance, self.doMatrix ] = [ unitCapacitance , capacitance, True ]
else : raise Error( 1, '__init__(): Impossible to draw the unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim ) #com2 : use to physical
return
def __initGivenNonZeroUnitCap__( self, capacitance, unitCap ):
if ( self.matrixDim["columns"]>1 or self.matrixDim["rows"]>1 ) : # jai donne les dim de la matrice
if self.matrixDim.values()[0]*self.matrixDim.values()[1] == capacitance/unitCap :
self.__initMatrixMode__( capacitance, unitCap )
else : raise Error( 1, '__init__() : Matrix dimensions and unit capacitance are not compatible : "capacitance %d divides by unit capacitance %s <> columns %d * rows %d ".' %( capacitance, unitCap, self.matrixDim["columns"], self.matrixDim["rows"] ) )
else : # self.matrixDim.values() == [1,1] : # jai donne ou jai ps donne
if capacitance == unitCap : #compact
[ self.capacitance , self.unitCapDim ] = [ capacitance , self.compactCapDim ]
print("capa",capacitance)
elif capacitance <> unitCap : #matrice
self.__initMatrixMode__( capacitance, unitCap )
self.matrixDim = {"columns" : int(sqrt(capacitance/unitCap)), "rows" : int(sqrt(capacitance/unitCap)) } # ici mettre toutes les combi si matching mode = [] sinon utiliser la meme combi que matching scheme
else : raise Error( 1,'__initGivenNonZeroUnitCap__ : capacitance must be multiple of unit capacitance' )
return
def __initGivenZeroUnitCapInMatchingMode__( self, capacitance ):
if self.matrixDim.values() == [1,1] or (self.matrixDim["columns"] == len(self.matchingScheme[0]) and self.matrixDim["rows"] == len(self.matchingScheme)) :
unitCapList = self.computeUnitCap(capacitance)
if len( list(numpy.unique(unitCapList)) ) == 1 :
unitCapDim = self.__computeCapDim__( unitCapList[0], self.capacitorType )
if CapacitorUnit.__isCapacitorUnitOK__(self, unitCapDim) == True :
self.unitCapDim = unitCapDim
self.__initMatrixMode__( capacitance, unitCapList[0] )
if self.matrixDim.values() == [1,1] : self.matrixDim = {"columns" : len(self.matchingScheme[0]) , "rows" : len(self.matchingScheme) }
else : raise Error(1,'__initGivenZeroUnitCapInMatchingMode__() : Impossible to draw unit capacitor, dimensions are either too large or too small, "%s".' % unitCapDim)
else : raise Error(1,'__initGivenZeroUnitCapInMatchingMode__() : Not all capacitances are multiple of the unit capacitor.')
else : raise Error(1,'__initGivenZeroUnitCapInMatchingMode__() : Please check compatibility between matrix dimensions and matching scheme dimensions. Both must be equal.')
return
def __initGivenNonZeroUnitCapInMatchingMode__( self, capacitance, unitCap ):
if CapacitorUnit.__isCapacitorUnitOK__(self, self.unitCapDim) == True :
if self.matrixDim.values() == [1,1] or (self.matrixDim["columns"] == len(self.matchingScheme[0]) and self.matrixDim["rows"] == len(self.matchingScheme)) :
if self.evaluateUnitCap( capacitance, unitCap ) == True :
self.__initMatrixMode__( capacitance, unitCap )
if self.matrixDim.values() == [1,1] : self.matrixDim = {"columns" : len(self.matchingScheme[0]) , "rows" : len(self.matchingScheme) }
else: raise Error(1,'__initGivenNonZeroUnitCapInMatchingMode__() : Non valid unit capacitor value considering the entered matching scheme. Please make sure that capacitors values are all multiples of unit capacitor.')
else: raise Error(1,'__initGivenNonZeroUnitCapInMatchingMode__() : Please check compatibility between matrix dimensions and matching scheme dimensions. Both must be equal.')
else: raise Error(1,'__initGivenNonZeroUnitCapInMatchingMode__() : Impossible to draw unit capacitor, dimensions are either too large or too small, "%s".' % self.unitCapDim)
return
def __areMatrixDimOK__( self ): return True if self.matrixDim.values() > 0 else False
def computeUnitCap( self, capacitance ):
unitCapList = []
for k in range(0, self.capacitorsNumber):
unitCapList.append( capacitance[k]/self.capacitorIdOccurence(k) )
return unitCapList
def evaluateUnitCap( self, capacitance, unitCap ):
state = True
for k in range(0, self.capacitorsNumber):
print('self.capacitorIdOccurence( k )',self.capacitorIdOccurence( k ))
factor = capacitance[k]/unitCap
print('factor',factor)
if factor != self.capacitorIdOccurence( k ) : state = False
return state
## \return True if the drawn capacitor is a compact one. This function is useful when an instance is called in another class. \b Example : when the matrix or the compact capacitors are to be fully routed.
def __isUnitCap__( self ): return True if not self.doMatrix else False
## \return \c True if the matching scheme specifications are correct. Specifications are :
# - Similar number of elements as total number of elementary capacitor in the matrix.
# - Equal number of affected capacitors to C1 as to C2.
# - Capacitor identifiers equal to '1' or '2' only.
# - Otherwise, the function returns \c False.
def __isMatchingSchemeOK__ ( self ):
state = True
columsElementsNumber = [ len(self.matchingScheme[k]) for k in range(0,len(self.matchingScheme)) ]
if len( list(numpy.unique(columsElementsNumber)) ) > 1 :
state = False
else :
[ matrixDim , matchingSchemeDim ] = [ self.matrixDim["columns"]*self.matrixDim["rows"] , len(self.matchingScheme)*len(self.matchingScheme[0]) ]
comparaison = [ self.matrixDim[key]>1 for key in self.matrixDim.keys() ]
if ( True in comparaison ) and ( matchingSchemeDim != matrixDim ) : state = False
return state
## \return occurence of capacitor identifier in the entered matching scheme. This is useful to verify that \c self.matchingScheme is correct.
def capacitorIdOccurence ( self, capacitorIdentifier ):
occurence = sum( element.count(capacitorIdentifier) for element in self.matchingScheme )
return occurence
def __areInputDataOK__( self, capacitance ) :
state = False
if ( self.__areMatrixDimOK__() == True ) :
if self.matchingMode in [False, True] and self.dummyRing in [False,True] and self.dummyElement in [False,True]:
[ matchingSchemeCapIds , capacitanceIds ] = [ list( numpy.unique(self.matchingScheme) ) , range(0,self.capacitorsNumber) ]
if (self.matchingScheme != [] and set(matchingSchemeCapIds) == set(capacitanceIds) ) or (self.matchingScheme == [] and len(capacitance) == 1) :
if (len(self.nets) == self.capacitorsNumber + 1 and self.dummyElement == False and self.dummyRing == True ) or (len(self.nets) == self.capacitorsNumber and self.dummyElement == False and self.dummyRing == False) or (len(self.nets) == self.capacitorsNumber and self.dummyElement == True and self.dummyRing == True) or (len(self.nets) == self.capacitorsNumber and self.dummyElement == True and self.dummyRing == False ):
if ( self.matchingMode == True and self.__isMatchingSchemeOK__() ) or ( self.matchingMode == False and self.matchingScheme == [] ):
state = True
else: raise Error(1, '__areInputDataOK__(): Please check compatibility of the entered parameters (Matching mode, matching scheme, capacitance). It must be either equal to (False, [], one capacitance value) or ( True, matching scheme, capacitance values as much as there are capacitor ids in matching scheme ). The entered parameters are (%s, %s, %s).' %(self.matchingMode, self.matchingScheme, capacitance) ) #com2 : tester
else : raise Error(1,'__areInputDataOK__() : Nets number is incompatible with number of capacitors to be drawn.')
else : raise Error(1, '__areInputDataOK__() : Please check compatibility between matching scheme elements, %s, and capacitance indexes, %s. They must be identical. Otherwise, when matching scheme is "False", capacitance indexes must be [0].' %(matchingSchemeCapIds, capacitanceIds) )
else : raise Error(1,'__areInputDataOK__() : Matching mode, %s, dummy ring, %s, and dummy element, %s, must be all either "True" or "False".' %(self.matchingMode, self.dummyRing, self.dummyElement))
else : raise Error(1,'__areInputDataOK__(): Both matrix dimensions "%s" must be positive.' % self.matrixDim.keys())
return state
## Draw the compact or matrix of capacitors. First, . Second, . Finally, .
def create( self, bbMode = False ):
UpdateSession.open()
drawnCapacitor = {}
self.setRules()
if self.matchingMode == True :
self.__initMatchingMode__()
self.drawAbutmentBox( self.abutmentBox_spacing )
if bbMode == True:
output = self.computeBondingBoxDimensions()
print('output',output)
elif bbMode == False :
drawnCapacitor = self.drawCapacitorStack( )
output = drawnCapacitor
else :raise Error(1, 'create(): The bonding box mode parameter, "bbMode" must be either True or False : %s.' %bbMode )
UpdateSession.close ()
return output
def drawCapacitorStack( self ):
drawnCapacitor = []
bottomPlateRLayer = CapacitorUnit.getLayers( self )["bottomPlateRLayer"]
topPlateRLayer = CapacitorUnit.getLayers( self )["topPlateRLayer" ]
if self.doMatrix == True :
drawnCapacitor = self.capacitorMatrix ( self.abutmentBox_spacing )
if self.matchingMode == False :
if self.dummyRing == True:
drawnActiveCapacitor = [drawnCapacitor[1][1:len(drawnCapacitor[1])-1]]
for i in range(2,self.matrixDim["rows"]+1):
drawnActiveCapacitor.append(drawnCapacitor[i][1:len(drawnCapacitor[1])-1])
else : drawnActiveCapacitor = drawnCapacitor
self.drawBottomPlatesRLayers( bottomPlateRLayer, drawnActiveCapacitor )
self.drawTopPlatesRLayers ( topPlateRLayer , drawnActiveCapacitor )
else:
drawnCapacitor = CapacitorUnit( self.device, self.capacitance, self.capacitorType, [self.abutmentBoxPosition["XMin"], self.abutmentBoxPosition["YMin"]] )
drawnCapacitor.create( self.nets[0][0], self.nets[0][1] )
return drawnCapacitor
## Iteratively draws a horizontal or vertical line of capacitors according to the \c direction parameter. An exception is raised if the specified direction is different from \c {'horizontal','vertical'}. At every iteration, an instance of the CapacitorUnit class is created and its layout is drawn.
# \return a list containing the drawn capacitors.
# \param dy the vertical position of the first cut in cut line.
# \remarks An exception is raised if the specified direction is different from \c {'horizontal','vertical'}
def capacitorLine( self, dy, abutmentBox_spacing , matchingSchemeRowIndex = 0 ):
line = [ CapacitorUnit( self.device, self.unitCapacitance, self.capacitorType, [self.abutmentBoxPosition["XMin"], dy] ) ]
self.createElementInCapacitorLine( line, matchingSchemeRowIndex,0 )
limit = self.matrixDim["columns"] + 2 if self.dummyRing == True else self.matrixDim["columns"]
for j in range(1, limit ) :
line.append( CapacitorUnit( self.device, self.unitCapacitance, self.capacitorType, [line[j-1].abutmentBox.getXMax() + abutmentBox_spacing, dy] ) )
self.createElementInCapacitorLine( line, matchingSchemeRowIndex,j )
return line
def createElementInCapacitorLine( self, capacitorList, matchingSchemeRowIndex,capListIndex ):
if self.matchingMode == False :
capacitorList[capListIndex].create( self.nets[0][0], self.nets[0][1] )
else :
if self.dummyRing == True:
if (matchingSchemeRowIndex == 0 or matchingSchemeRowIndex == self.matrixDim["rows"] + 1 or capListIndex == 0 or capListIndex == self.matrixDim["columns"] + 1) :
[ t , b ] = [ self.nets[-1][0] , self.nets[-1][1] ]
else :
k = self.matchingScheme[matchingSchemeRowIndex-1][capListIndex-1]
[ t , b ] = [ self.nets[k][0] , self.nets[k][1] ]
else :
k = self.matchingScheme[matchingSchemeRowIndex][capListIndex]
[ t , b ] = [ self.nets[k][0] , self.nets[k][1] ]
capacitorList[capListIndex].create( t, b )
return
## Draws a matrix of identical capacitors. The matrix is iterativelly constructed. At every iteration, a new horizontal line of capacitors is drawn.
# \return a nested list of elementary capacitors.
def capacitorMatrix( self, abutmentBox_spacing = 0 ):
#print("capMatrix", nets)
matrix = [ self.capacitorLine( self.abutmentBoxPosition["YMin"], abutmentBox_spacing,0 ) ]
limit = self.matrixDim["rows"] + 2 if self.dummyRing == True else self.matrixDim["rows"]
for i in range( 1, limit ):
matrix.append( self.capacitorLine( matrix[i-1][-1].abutmentBox.getYMax() + abutmentBox_spacing, abutmentBox_spacing, i) )
return matrix
def dummyLine( self, direction, dx, dy ):
dummyList = [ CapacitorUnit( self.device, self.unitCapacitance, self.capacitorType, [dx, dy] ) ]
dummyList[0].create( self.nets[-1][0], self.nets[-1][1] )
if direction == 'vertical':
for i in range(1, self.matrixDim["rows"] + 2):
dummyList.append( CapacitorUnit( self.device, self.unitCapacitance, self.capacitorType, [dx, dummyList[i-1].abutmentBox.getYMax() + self.abutmentBox_spacing] ) )
dummyList[i].create(self.nets[-1][0], self.nets[-1][1])
elif direction == 'horizontal':
for j in range(1, self.matrixDim["columns"] + 2):
print('j',j)
dummyList.append( CapacitorUnit( self.device, self.unitCapacitance, self.capacitorType, [dummyList[j-1].abutmentBox.getXMax() + self.abutmentBox_spacing, dy]) )
dummyList[j].create(self.nets[-1][0], self.nets[-1][1])
else : raise Error(1,'dummyLine() : Direction must be either "horizontal" or "vertical".' %direction)
return dummyList
def computeAbutmentBoxDimensions( self, abutmentBox_spacing ):
abutmentBoxDimensions = {}
capDim = self.getCapDim()
[widthFactor1 , widthFactor2 ] = [self.matrixDim["columns"] , (self.matrixDim["columns"] - 1)] if self.dummyRing == False else [self.matrixDim["columns"] + 2, (self.matrixDim["columns"] + 1)]
[heightFactor1, heightFactor2] = [self.matrixDim["rows" ] , (self.matrixDim["rows" ] - 1)] if self.dummyRing == False else [self.matrixDim["rows" ] + 2, (self.matrixDim["rows" ] + 1)]
abutmentBoxDimElement = CapacitorUnit.computeAbutmentBoxDimensions(self, capDim)
abutmentBoxWidth = widthFactor1 *abutmentBoxDimElement["width" ] + widthFactor2 *abutmentBox_spacing
abutmentBoxHeight = heightFactor1*abutmentBoxDimElement["height"] + heightFactor2*abutmentBox_spacing
abutmentBoxDimensions = { "XMin" : self.abutmentBoxPosition["XMin"], "YMin" : self.abutmentBoxPosition["YMin"], "width" : abutmentBoxWidth , "height" : abutmentBoxHeight, "surface" : abutmentBoxWidth*abutmentBoxHeight}
return abutmentBoxDimensions
## Draws the abutment box of the matrix or campact capacitor.
def drawAbutmentBox( self, abutmentBox_spacing = 0 ):
abutmentBoxDimensions = self.computeAbutmentBoxDimensions(abutmentBox_spacing)
self.abutmentBox = Box(self.abutmentBoxPosition["XMin"],self.abutmentBoxPosition["YMin"],abutmentBoxDimensions["width"]+self.abutmentBoxPosition["XMin"],abutmentBoxDimensions["height"]+self.abutmentBoxPosition["YMin"])
self.device.setAbutmentBox( self.abutmentBox )
return
def computeBondingBoxDimensions( self ):
bondingBoxDimensions = {}
abutmentBoxDimensions = self.computeAbutmentBoxDimensions( self.abutmentBox_spacing )
for key in abutmentBoxDimensions:
if key != "XMin" and key != "YMin" : bondingBoxDimensions[key] = abutmentBoxDimensions[key]
return bondingBoxDimensions
## Draws the routing layers connecting the bottom plate in the matrix of capacitors. First, the relative positions of the routing layer is of the is extracted from the elementary capacitor instance. Then, its width is computed in a way to connect adjacent plates. Then, the routing layers are iterativelly drawn.
# The two borders are .
def drawBottomPlatesRLayers( self, bottomPlateRLayer, drawnCapacitor ):
[ dySourceBottom, dyTargetBottom ] = [ drawnCapacitor[0][0].getBotPlateRLayerYMin (), drawnCapacitor[-1][0].getBotPlateRLayerYMax() ]
if ( self.matrixDim["columns"] > 1 ) :
bottomPlateRLayer_width = ( drawnCapacitor[0][1].getBotPlateLeftRLayerXMax() - drawnCapacitor[0][0].getBotPlateRightRLayerXMin() )
bottomMetalXCenters = []
for j in range( 0,self.matrixDim["columns"]-1 ):
bottomMetalXCenters.append( drawnCapacitor[0][j].getBotPlateRightRLayerXMin() + bottomPlateRLayer_width/2 )
Vertical.create ( self.nets[0][1], bottomPlateRLayer, bottomMetalXCenters[j], bottomPlateRLayer_width, dySourceBottom, dyTargetBottom )
bordersXMin = [ drawnCapacitor[0][0].getBottomPlateLeftCutXMin(), drawnCapacitor[0][-1].getBottomPlateRightCutXMin() ]
for j in range( 0,2):
Vertical.create ( self.nets[0][1], bottomPlateRLayer , bordersXMin[j], drawnCapacitor[0][0].getBotPlateRLayerWidth(), dySourceBottom, dyTargetBottom )
return
## Draws the routing layers connecting the top plates in the matrix of capacitors. First, the relative positions of the routing layers is of the is extracted from the elementary capacitor instance. Then, its width is computed in a way to connect adjacent plates. Then, the routing layers are iterativelly drawn.
# The two borders are .
# \remarks An exception is raised if the number of rows in the matrix is lower than 2.
def drawTopPlatesRLayers( self, topPlateRLayer, drawnCapacitor):
if ( self.matrixDim["rows"] > 1 ) :
for j in range( 0,self.matrixDim["columns"] ):
Vertical.create ( self.nets[0][0], topPlateRLayer , drawnCapacitor[0][j].getTopPlateRLayerXCenter(), drawnCapacitor[0][j].getTopPlateRLayerWidth() , drawnCapacitor[0][0].getTopPlateRLayerYMin(), drawnCapacitor[-1][0].getTopPlateRLayerYMax() )
#else : print('The matrix does not contain enough rows') #com4 verify if this else is needed
return
## \return The width of the vertical routing tracks in matching mode.
# \remark This function is useful in matching mode, ie., in \C RoutCapacitor class, when routing the two capacitors.
def getVerticalRoutingTrack_width ( self ) : return self.vRoutingTrack_width
def getAbutmentBox_spacing ( self ) : return self.abutmentBox_spacing
## \return A dictionary contaning capacitor matrix's dimensions
def getMatrixDim ( self ) : return self.matrixDim
def getCapDim ( self ) : return self.unitCapDim if self.doMatrix == True else self.compactCapDim
# def getMatchingMode ( self ) : return self.matchingMode
def getVRoutingTrack_spacing ( self ) : return self.minSpacing_vRoutingTrack
def getvRoutingTrack_width ( self ) : return self.vRoutingTrack_width
## \return the matching scheme. The function is useful in \c RoutMatchedCapacitor class to load \c self.matchingScheme attribute.
def getMatchingScheme ( self ) : return self.matchingScheme
def ScriptMain( **kw ):
editor = None
if kw.has_key('editor') and kw['editor']:
editor = kw['editor']
UpdateSession.open()
device = AllianceFramework.get().createCell( 'capacitor' )
device.setTerminal( True )
bottomPlate_net0 = Net.create( device, 'b0' )
bottomPlate_net1 = Net.create( device, 'b1' )
bottomPlate_net2 = Net.create( device, 'b2' )
bottomPlate_net3 = Net.create( device, 'b3' )
bottomPlate_net0.setExternal( True )
bottomPlate_net1.setExternal( True )
bottomPlate_net2.setExternal( True )
bottomPlate_net3.setExternal( True )
b0 = device.getNet("b0")
b1 = device.getNet("b1")
b2 = device.getNet("b2")
b3 = device.getNet("b3")
topPlate_net0 = Net.create( device, 't0' )
topPlate_net1 = Net.create( device, 't1' )
topPlate_net2 = Net.create( device, 't2' )
topPlate_net3 = Net.create( device, 't3' )
topPlate_net0.setExternal( True )
topPlate_net1.setExternal( True )
topPlate_net2.setExternal( True )
topPlate_net3.setExternal( True )
t0 = device.getNet("t0")
t1 = device.getNet("t1")
t2 = device.getNet("t2")
t3 = device.getNet("t3")
if editor:
UpdateSession.close()
editor.setCell( device )
editor.fit()
UpdateSession.open()
nets = [[t0, b0]]# , [t1, b1], [t2, b2] ] # [t3, b3] ]
capacitorInstance = CapacitorStack( device, [750,750], 'MIMCap', [0,0], nets,unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ [1,0,1,0] , [0,1,0,1] , [1,0,1,0] , [0,1,0,1] ], dummyRing = True)
#capacitorInstance = CapacitorStack( device, [1488], 'MIMCap', [0,0], nets,unitCap = 93, matrixDim = [4,4], dummyRing = True)
#capacitorInstance = CapacitorStack( device, {"C1" : 558, "C2" : 558, "C3" : 372}, 'MIMCap', [0,0], nets, unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ ['C2','C1','C2','C1'] , ['C1','C2','C1','C2'] , ['C2','C1','C2','C1'] , ['C3','C3','C3','C3'] ])
#capacitorInstance = CapacitorStack( device, {"C1" : 558, "C2" : 558, "C3" : 186, "C4" : 186}, 'MIMCap', [0,0], nets, unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ ['C2','C1','C2','C1'] , ['C1','C2','C1','C2'] , ['C2','C1','C2','C1'] , ['C3','C3','C4','C4'] ])
capacitor = capacitorInstance.create()
print(capacitor)
AllianceFramework.get().saveCell( device, Catalog.State.Views )
return True

View File

@ -0,0 +1,767 @@
#!/usr/bin/python
import sys
from Hurricane import *
from CRL import *
import helpers
from helpers.io import ErrorMessage as Error
from helpers import trace
import oroshi
from CapacitorUnit import CapacitorUnit
from CapacitorMatrix import CapacitorStack
from CapacitorVRTracks import VerticalRoutingTracks
#from collections import OrderedDict
## Routs two matched capacitors, C1 and C2, drawn in a capacitor matrix. Connections are put in place with reference to a given matching scheme. Elementary capacitor units are connected to horizontal and vertical routeing tracks that represent top plates and bottom plates nets of C1 and C2 . Supported types of capacitors are Poly-Poly and Metal-Metal. Technologycal rules are provided by 350 nm AMS CMOS technology with three-four metal layers. Metal layers that are used for routeing are placed similarly to horziontal-vertical (HV) symbolic Alliance CAD tool routeer, where horizontal metal channels are drawn in metal 2 and the vertical ones are in metal 3. Given a matrix of dimensions \f$ R*C \f$, the total number of vertical tracks is \f$ 2C+2 \f$ equivalent to \f$ C+1 \f$ couples, ensuring that every elementary capacitor is positioned between four vertical tracks, two from each side. In fact, every adjacent couple of these tracks represent top plates and bottom plates of C1 or C2 as shown in Figure 1.
# \image html Layout.png "Layout" width=.1\linewidth
# An elementary capacitor unit can be a part of C1 or C2 according to the matching scheme. However, to respect common-centroid layout specifications, for C1 and C2 to be equal, the matrix number of colums and number of rows must be both even. Addionnally, the number of elementary capacitors dedicated to C1 must be equal to those dedicated to C2. These two conditions are tested in one of the class methods. An exception is raised if at least one of the two is not respected.
class RoutMatchedCapacitor( CapacitorUnit, CapacitorStack, VerticalRoutingTracks ):
rules = oroshi.getRules()
## A special method used to customize the class instance to an initial state in which :
# - the class attirbutes describing positions and dimensions of the layout are computed in dedicated class methods,
# - the attributes related to the capacitor matrix are copied from the \c CapacitorStack instance.
#
# Position and dimensions attributes, also refered by layout variables, in Figure 2, are defined below :
# \param device The Hurricane AMS device onto which the layout is drawn.
# \param capacitorInstance Instance of \c CapacitorStack class.
# \param capacitor A nested list containing the matrix elements, which are \c CapacitorUnit objects.
# \param matchingScheme A nested list, with equal dimensions as \c capacitor attribute, containing assignements of matrix elementary units to C1 and C2, identified by 1 and 2, respectively. Therefore, \c self.matchingScheme content is a succession of 1 and 2 values, defined as \ capacitor identifiers. For example, given a matrix of dimensions 2x2, the matching scheme can be \f$ [ [1,2], [1,2] ] or [ [2,1], [2,1] ] \f$. The first sub-list dictates that the first elementary capacitor, \f$ C_{00} \f$. The second element \f$ C_{01} \f$ is affected to C2 and so on. An immediate and obvious consequence to this, is that an error is raised if \c self.matchingSchem and \c self.capacitor dimensions are not identical or if \c self.matchingScheme content is different from supported capacitor identifiers, '1' and '2'.
#
# \param capacitorType Supported types of capacitors are MIM and PIP only. An exception is raised otherwise.
# \param abutmentBox The matrix's abutment box.
# \param matrxiDim The matrix dimensions, also equal to \c self.matchingScheme nested list dimensions.
# \param abutmentBox_spacing The spacing between elementary units in the matrix. It is computed in \c CapacitorStack and is reloaded in \c RoutMatchedCapacitor. \c self.abutmentBox_spacing includes, vertical routeing tracks width and minimum allowed spacing between two adjacent ones.
# \param hRoutingLayer_width The width of horizontal routeing layers in metal 2, which connect capacitors plates to vertical routeing tracks.
# \param vRoutingTrack_width The width of vertical routeing tracks in metal 3, which connects identical nets together ( ie : bottom plates of C1, top plates of C2, bottom plates of C2 and top plates of C2 ).
# \param hRoutingTrack_width The width of horizontal routeing tracks in metal 2, which connect identical vertical routeing tracks together.
# \param minSpacing_hRoutingTrack Minimum spacing between horizontal routeing tracks. Wide metal 2 specifications are considered since metal 2 dimensions may exceed 10 \f$ m\f$.
#
#\remark For more information about wide metal specifications, refer to ENG-183_rev8.pdf technology manual.
#
# \param minimumPosition The ordinate of the top plate's routeing layer's bottom extremity after stretching.
# \param maximumPosition The ordinate of the top plate's routeing layer's top extremity, also equivalent to the top plate's top extremity.
# \param vRoutingTrackXCenter A nested list of ordered dictionaries, with dimensions equal to \c self.matrixDim, containing abcissas of vertical routeing tracks. All sub-lists' lengths are identical and are equal to 2. The first and second elements describe position of top plate track and bottom plate track, respectively. For example, given a matrix of dimensions 2x2, \c self.vRoutingTrackXCenter can be [[0, 2], [4,6], [8,10]] \f$ \mu m\f$. Elements of this nested list have particular indexing as described in Figure 2.
#
# \param hRoutingtrackYCenter A nested dicitonary containing two keys, \c topTracks and \c bottomTracks. Each key contains as value a dictionary describing centers' ordinates of four parallel horizontal tracks. The reason why four tracks are needed on top and bottom positions of the matrix is that four nets are used, two for every capacitor \c Ci, were \c i is in [1,2].
# \param hRoutingLayerYCenter A nested dicitonary containing two keys, \c top and \c bottom. Each key contains as value a dictionary describing centers' ordinates of horizontal routeing layers.
# \param vRoutingTrackDict A dictionary of routeing tracks top and bottom extremities ordinates.
# \param topPlateStretching Since not only the same metal 2 layer is used to draw top/bottom plates connections to vertical tracks but also the two plates are superimposed, the top plate's routeing tracks is stretched. \c self.topPlateStretching is therefore the length added to top plate's routeing layer in order to avoid short circuits between top and bottom plates routeing to vertical tracks since the same metal is used for both.
def __init__( self, vRTInstance ) :
VerticalRoutingTracks.__init__( self, vRTInstance.capacitorInstance, vRTInstance.capacitor )
if self.dummyRing == True :
self.capacitor = [vRTInstance.capacitor[1][1:len(vRTInstance.capacitor[1])-1]]
for i in range(2,self.matrixDim["rows"]+1):
self.capacitor.append(vRTInstance.capacitor[i][1:len(vRTInstance.capacitor[1])-1])
self.dummyRingCapacitor = [ vRTInstance.capacitor[0], vRTInstance.capacitor[-1] ]
self.dummyRingVRLayersDict = {}
self.hRoutingLayer_width = 0
self.hRoutingTrack_width = vRTInstance.hRoutingTrack_width #gethRoutingTrack_width()
self.minSpacing_hRoutingTrack = 0
self.minimumPosition = 0
self.maximumPosition = 0
self.hRoutingtrackYCenter = { "topTracks" : {} , "bottomTracks" : {} }
self.hRoutingLayerYCenter = { "topPlate" : [] , "bottomPlate" : [] }
self.vRTInstance = vRTInstance
self.topPlateStretching = 0
return
## Draws the complete layout given the capacitor matrix. \c route method is succession of calls to user-defined methods inside a newly created \c Updatesession. The following tasks are excecuted :
# -# A nex \c UpdateSession is created,
# -# all required physical layers are loaded,
# -# technology rules are defined according to capacitor type,
# -# layout dimension parameters are computed,
# -# routeing tracks and layers are drawn,
# -# top plates are stretched,
# -# all required cuts are drawn,
# -# The \c UpdateSession is closed.
#
# Meanwhile, an exception is raised when the entered \c capacitor is not a capacitor matrix or if the capacitor type is unsupported.
def route( self, bbMode = False ):
UpdateSession.open ()
self.setRules ()
if not( self.capacitorInstance.__isUnitCap__() ):
if CapacitorStack.__isMatchingSchemeOK__(self):
layersDict = self.setLayers ()
bondingBox = self.computeDimensions( bbMode )
if not bbMode :
self.drawHRLayers ( layersDict["xPlateHRLayer" ] )
self.drawHRoutingTracks ( layersDict["hRoutingTracks" ] )
self.__stretchTopPlates__( self.capacitor , layersDict["xPlateRLayer" ] )
self.drawCuts ( layersDict["cut_hRoutingLayer_vRoutingTracks"] , layersDict["cut_hRoutingTracks_vRoutingTracks"], layersDict["cut_hRoutingLayer_topPlate"] )
if self.dummyRing == True:
self.routeDummyRing (layersDict ["xPlateVRLayer_dummyRing" ] , layersDict["cut_hRoutingTracks_vRoutingTracks"] )
else : raise Error( 1, 'drawHRLayers() : Invalid matching scheme : "%s".' % self.matchingScheme )
else : raise Error( 1,'An input matrix is required.' % self.matrixDim )
UpdateSession.close ()
return bondingBox
def routeDummyRing( self, routeingLayer, cutLayer ):
net = self.nets[-1][1]
bottomPlateRLayer_width = self.dummyRingCapacitor[0][0].getBotPlateRLayerWidth()
topPlateRLayer_width = self.dummyRingCapacitor[0][0].getTopPlateRLayerWidth()
self.computeDummyRingDimensions ()
self.routeLeftAndRightSides (net, routeingLayer, bottomPlateRLayer_width, topPlateRLayer_width )
self.routeTopOrBottomSide (net, "topSide" , routeingLayer , bottomPlateRLayer_width, topPlateRLayer_width)
self.routeTopOrBottomSide (net, "bottomSide" , routeingLayer , bottomPlateRLayer_width, topPlateRLayer_width)
self.drawDummyRing_hRTracks_Cuts (net, "topSide" , cutLayer )
self.drawDummyRing_hRTracks_Cuts (net, "bottomSide" , cutLayer )
return
def routeLeftAndRightSides( self, dummyNet, routeingLayer, bottomPlateRLayer_width, topPlateRLayer_width ) :
for i in range(0,2):
bottomPlateLeftRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateLeftRLayerXCenter()
bottomPlateRightRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateRightRLayerXCenter()
Vertical.create ( dummyNet, routeingLayer , bottomPlateLeftRLayerXCenter , bottomPlateRLayer_width , self.dummyRingVRLayersDict["YMin"] , self.dummyRingVRLayersDict["YMax"] )
Vertical.create ( dummyNet, routeingLayer , bottomPlateRightRLayerXCenter , bottomPlateRLayer_width , self.dummyRingVRLayersDict["YMin"] , self.dummyRingVRLayersDict["YMax"] )
for i in range(0,2):
topPlateRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].topPlateRLayerDict["XCenter"]
Vertical.create ( dummyNet, routeingLayer , topPlateRLayerXCenter , topPlateRLayer_width , self.dummyRingVRLayersDict["YMin"] , self.dummyRingVRLayersDict["YMax"] )
return
def routeTopOrBottomSide( self, dummyNet, side, routeingLayer, bottomPlateRLayer_width, topPlateRLayer_width):
if side == "topSide" :
dummyRingElement = self.dummyRingCapacitor[-1]
dyTarget = self.vRoutingTrackDict ["YMax"]
elif side == "bottomSide" :
dummyRingElement = self.dummyRingCapacitor[0]
dyTarget = self.vRoutingTrackDict ["YMin"]
else : raise Error(1,'routeTopOrBottomSide() : side parameter must be either "topSide" or "bottomSide" : %s' %side)
for j in range(1,len(self.dummyRingCapacitor[0])-1):
bottomPlateLeftRLayerXCenter = dummyRingElement[j].getBotPlateLeftRLayerXCenter()
bottomPlateRightRLayerXCenter = dummyRingElement[j].getBotPlateRightRLayerXCenter()
Vertical.create ( dummyNet, routeingLayer , bottomPlateLeftRLayerXCenter , bottomPlateRLayer_width , dummyRingElement[j].getBotPlateRLayerYMin() , dyTarget )
Vertical.create ( dummyNet, routeingLayer , bottomPlateRightRLayerXCenter , bottomPlateRLayer_width , dummyRingElement[j].getBotPlateRLayerYMin() , dyTarget )
topPlateRLayerXCenter = dummyRingElement[j].topPlateRLayerDict["XCenter"]
Vertical.create ( dummyNet, routeingLayer , topPlateRLayerXCenter , topPlateRLayer_width , dummyRingElement[j].getTopPlateRLayerYMin() , dyTarget )
return
## Defines technology rules used to draw the layout. Some of the rules, namely those describing routeing layers and tracks are applicable for both MIM and PIP capacitors. However, cuts rules are different. \remark All \c CapacitorStack class rules are also reloaded in this class. An exception is raised if the entered capacitor type is unsupported.
# \return a dictionary with rules labels as keys and rules content as values.
def setRules ( self ):
VerticalRoutingTracks.setRules ( self )
CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingLayer" , RoutMatchedCapacitor.rules.minSpacing_metbot )
CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingTrackCut" , RoutMatchedCapacitor.rules.minSpacing_cut2 )
CapacitorUnit.__setattr__ ( self, "minSpacing_vRoutingTrackCut" , RoutMatchedCapacitor.rules.minSpacing_cut2 )
CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingLayer_vRoutingTrack_cut" , RoutMatchedCapacitor.rules.minSpacing_cut2 )
if self.capacitorType == 'MIMCap':
CapacitorUnit.__setattr__( self, "minWidth_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minWidth_cut2 )
CapacitorUnit.__setattr__( self, "minSpacing_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minSpacing_cut2 )
CapacitorUnit.__setattr__( self, "minEnclosure_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minEnclosure_metal2_cut2 )
elif self.capacitorType == 'PIPCap' :
CapacitorUnit.__setattr__( self, "minWidth_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minWidth_cut1 )
CapacitorUnit.__setattr__( self, "minSpacing_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minSpacing_cut1 )
CapacitorUnit.__setattr__( self, "minEnclosure_hRoutingLayer_topPlate_cut" , RoutMatchedCapacitor.rules.minEnclosure_metal2_cut1 )
else: raise Error( 1, 'setRules() : Unsupported capacitor type : %s.' %self.capacitorType )
return
## Defines all physical layers used to draw the layout. Layers are loaded using \c DataBase API. The same routeing layers are used for both capacitor types except cuts layers that connect top plates to vertical routeing tracks. Basicaly, metal 2, meta 3, cut 1 and cut 2 are the ones defined.
# \return a dictionary composed of layers labels as keys and layers as values.
def setLayers( self ):
layersDict = {}
layersDict["hRoutingTracks" ] = DataBase.getDB().getTechnology().getLayer("metal2" )
layersDict["xPlateHRLayer" ] = DataBase.getDB().getTechnology().getLayer("metal2" )
layersDict["xPlateRLayer" ] = CapacitorUnit.getLayers( self )["bottomPlateRLayer"]
layersDict["cut_hRoutingTracks_vRoutingTracks"] = DataBase.getDB().getTechnology().getLayer("cut2" )
layersDict["cut_hRoutingLayer_vRoutingTracks" ] = DataBase.getDB().getTechnology().getLayer("cut2" )
layersDict["cut_hRoutingLayer_topPlate" ] = DataBase.getDB().getTechnology().getLayer("cut2" ) if self.capacitorType == 'MIMCap' else DataBase.getDB().getTechnology().getLayer("cut1")
if self.dummyRing == True:
layersDict["xPlateVRLayer_dummyRing" ] = DataBase.getDB().getTechnology().getLayer("metal3" ) if self.capacitorType == 'MIMCap' else DataBase.getDB().getTechnology().getLayer("metal1")
return layersDict
## Computes, through simple instructions and functions calls, layout variables detailed in Figure 2.
def computeDimensions ( self, bbMode ) :
print 'routMatchedCapacitor.computeDimensions()'
bondingBoxDimensions = {}
self.hRoutingLayer_width = max( self.minWidth_hRoutingLayer, self.minWidth_hRoutingLayer_vRoutingTrack_cut + 2*self.minEnclosure_hRoutingLayer_vRoutingTrack_cut, self.minWidth_hRoutingLayer_topPlate_cut + 2*self.minEnclosure_hRoutingLayer_topPlate_cut )
self.abutmentBox_spacing = self.capacitorInstance.abutmentBox_spacing
self.vRoutingTrack_spacing = self.capacitorInstance.getVRoutingTrack_spacing()
abutmentBoxXMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["XMin"] #getAbutmentBox_spacing()
abutmentBoxYMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["YMin"] #getAbutmentBox_spacing()
abutmentBoxYMax = abutmentBoxYMin + self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["height"] #getAbutmentBox_spacing()
self.minimumPosition = self.vRTInstance.minimumPosition #abutmentBoxYMin - self.__setStretching__()
self.maximumPosition = self.vRTInstance.maximumPosition #abutmentBoxYMax + self.__setStretching__()
self.vRoutingTrackDict = self.vRTInstance.vRoutingTrackDict #self.minimumPosition - 4*self.hRoutingTrack_width - 4*self.minSpacing_hRoutingTrack
translation1 = self.vRoutingTrack_width/2 + self.vRoutingTrack_spacing
translation2 = translation1 + self.vRoutingTrack_width/2
self.vRoutingTrackXCenter = self.vRTInstance.vRoutingTrackXCenter #getvRoutingTrackXCenter()
if bbMode == True :
bondingBoxDimensions = self.computeBondingBoxDimInbbMode()
elif bbMode == False :
self.computeHRoutingTrackYCenter()
self.computeHRLayerYCenter()
else :raise Error(1, 'computeDimensions(): The bonding box mode parameter, "bbMode" must be either True or False : %s.' %bbMode )
print 'BOUNDING BOX:', bondingBoxDimensions
return bondingBoxDimensions
def computeBondingBoxDimInbbMode( self ):
bondingBoxDimensions = {}
abutmentBoxXMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["XMin"]
abutmentBoxXMax = abutmentBoxXMin + self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["width" ]
bondingBoxDimensions["XMin" ] = self.vRoutingTrackXCenter[0 ]["t1"] - self.vRoutingTrack_width/2
if self.capacitorsNumber % 2 == 0 :
factor = self.capacitorsNumber
else :
factor = self.capacitorsNumber + 1 if self.matrixDim["columns"] % 2 == 0 else self.capacitorsNumber - 1
bondingBoxXMax = abutmentBoxXMax + factor*(self.vRoutingTrack_width + self.vRoutingTrack_spacing)
bondingBoxDimensions["YMin" ] = self.vRoutingTrackDict["YMin"]
bondingBoxYMax = self.vRoutingTrackDict["YMax"]
bondingBoxDimensions["width" ] = bondingBoxXMax - bondingBoxDimensions["XMin"]
bondingBoxDimensions["height" ] = bondingBoxYMax - bondingBoxDimensions["YMin"]
bondingBoxDimensions["surface"] = bondingBoxDimensions["width"]*bondingBoxDimensions["height"]
bondingBox = Box( bondingBoxDimensions["XMin"], bondingBoxDimensions["YMin"], bondingBoxXMax, bondingBoxYMax )
self.device.setAbutmentBox( bondingBox )
return bondingBoxDimensions
## Computes centers' ordinates of the eight horizontal routeing tracks. The tracks include four on top and four on bottom of the matrix. To do the computations, fist, center of the first bottom or top track, given in Figure 2, is computed. Then, all adjacent three centers are deduced by simples translation of the first one. Translation quantity is equal to the sum of distance between adjacent routeing tracks, self.hRoutingTracks_spacing, and half width of the routeing track itself, \c self.hRoutingTrack_width.
def computeHRoutingTrackYCenter( self ):
self.hRoutingtrackYCenter = { "topTracks" : {} , "bottomTracks" : {} }
self.hRoutingtrackYCenter["topTracks" ]["t0"] = self.maximumPosition + self.hRoutingTrack_width/2 + self.minSpacing_hRoutingTrack
self.hRoutingtrackYCenter["bottomTracks" ]["t0"] = self.minimumPosition - self.hRoutingTrack_width/2 - self.minSpacing_hRoutingTrack
keys = self.__setPlatesIds__()
print("key",keys)
print(" self.capacitorsNumber", self.capacitorsNumber)
# limit = 2*self.capacitorsNumber if self.dummyRing == False else 2*self.capacitorsNumber + 1
for k in range(1, len(keys)):
print('keysk',keys[k])
self.hRoutingtrackYCenter["topTracks" ][keys[k]] = self.hRoutingtrackYCenter["topTracks" ][keys[k-1]] + (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
self.hRoutingtrackYCenter["bottomTracks" ][keys[k]] = self.hRoutingtrackYCenter["bottomTracks"][keys[k-1]] - (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
print("keyskk",keys[k-1])
print("self.hRoutingtrackYCenter",self.hRoutingtrackYCenter)
# if self.dummyRing == True :
# self.hRoutingtrackYCenter["topTracks" ]["gnd"] = self.hRoutingtrackYCenter["topTracks" ][keys[k]] + (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
# self.hRoutingtrackYCenter["bottomTracks" ]["gnd"] = self.hRoutingtrackYCenter["bottomTracks"][keys[k]] - (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
print('self.hRoutingtrackYCenter',self.hRoutingtrackYCenter)
return
## Sets the stretching value of top plates. Then iteratively computes the centers of horizontal routeing layer regarding top and bottom plates.
def computeHRLayerYCenter ( self ):
shortCircuitLists = self.__findPossibleShortCircuits__()
self.topPlateStretching = self.__setStretching__( )
print(' shortCircuitLists', shortCircuitLists)
for i in range( 0,self.matrixDim["rows"] ):
print("i",i)
print("rows", self.matrixDim["rows"])
print("rowsCap", len(self.capacitor))
if shortCircuitLists[i][0] == 0 :
self.hRoutingLayerYCenter["bottomPlate"].append( [self.capacitor[i][0].getBottomPlateRightCutYMax ()] )
else :
bottomPlateYCenter0 = [(self.capacitor[i][0].getBottomPlateRightCutYMax () + self.capacitor[i][0].getBottomPlateRightCutYMin() ) /2 ]
self.hRoutingLayerYCenter["bottomPlate"].append(bottomPlateYCenter0)
topPlateYCenter = self.__setStretchingDySourceDyTarget__( self.capacitor[i][0], self.topPlateStretching )[1] + self.hRoutingLayer_width/2
self.hRoutingLayerYCenter["topPlate" ].append( [topPlateYCenter ] )
for j in range( 1,self.matrixDim["columns"] ):
topPlateYCenter = self.__setStretchingDySourceDyTarget__( self.capacitor[i][j], self.topPlateStretching )[1] + self.hRoutingLayer_width/2
if shortCircuitLists[i][j] == 0 :
self.hRoutingLayerYCenter["bottomPlate"][i].append( self.capacitor[i][j].getBottomPlateRightCutYMax () )
self.hRoutingLayerYCenter["topPlate" ][i].append( topPlateYCenter )
else :
bottomPlateYCenter = (self.capacitor[i][j].getBottomPlateRightCutYMax() + self.capacitor[i][j].getBottomPlateRightCutYMin()) /2
topPlateYCenter2 = topPlateYCenter + self.minSpacing_hRoutingLayer + self.hRoutingLayer_width
self.hRoutingLayerYCenter["bottomPlate"][i].append(bottomPlateYCenter)
self.hRoutingLayerYCenter["topPlate" ][i].append(topPlateYCenter2)
print('self.hRoutingLayerYCenter',self.hRoutingLayerYCenter)
return
def computeLayoutDimensionsInbbMode( self ):
bondingBoxDict = {}
bondingBoxDict["YMin" ] = self.hRoutingtrackYCenter["bottomTracks"]["botB"] - self.hRoutingTrack_width/2
bondingBoxDict["XMin" ] = self.vRoutingTrackXCenter[0 ][0] - self.vRoutingTrack_width/2
bondingBoxDict["height" ] = self.hRoutingtrackYCenter["topTracks" ]["botB"] + self.hRoutingTrack_width/2 - bondingBoxDict["YMin"]
bondingBoxDict["width" ] = self.vRoutingTrackXCenter[-1][1] + self.vRoutingTrack_width/2 - bondingBoxDict["XMin"]
self.bondingBox = Box( bondingBoxDict["XMin"], bondingBoxDict["YMin"], bondingBoxDict["XMin"] + bondingBoxDict["width"], bondingBoxDict["YMin"] + bondingBoxDict["height"] )
return bondingBoxDict
def computeDummyRingDimensions( self ):
for key in self.vRoutingTrackDict.keys():
self.dummyRingVRLayersDict[key] = self.vRoutingTrackDict[key]
return
## Iteratively draws horizontal routeing tracks on top and bottom positions of the matrix using physical layer \c routeingTracksLayer.
def drawHRoutingTracks( self , routeingTracksLayer ):
lastVRTId = self.vRoutingTrackXCenter[-1].keys()[-1]
firstVRTId = "t0"
# doDummyRing = 1 if self.dummyRing == True else 0
dxSource = self.vRoutingTrackXCenter[0][firstVRTId] - self.vRoutingTrack_width/2 if self.dummyRing == False else self.abutmentBox.getXMin()
dxTarget = self.vRoutingTrackXCenter[-1][lastVRTId] + self.vRoutingTrack_width/2 if self.dummyRing == False else self.abutmentBox.getXMax()
for i in self.hRoutingtrackYCenter.keys():
for j in self.hRoutingtrackYCenter[i].keys():
if j[0] == 't' :
net = self.nets[ int(j[1]) ][0]
elif j[0] == 'b' :
net = self.nets[ int(j[1]) ][1]
else :
print("hi")
net = self.nets[-1][1]
# net = self.nets[ int(j[1]) ][0] if j[0] == 't' else self.nets[ int(j[1]) ][1]
print('net',net)
Horizontal.create ( net , routeingTracksLayer, self.hRoutingtrackYCenter[i][j] , self.hRoutingTrack_width , dxSource , dxTarget )
return
## Iteratively draws the horizontal routeing layers starting with bottom left elementary capacitor \f$ C_{00} \f$.
def drawHRLayers( self, xPlateRLayer ) :
for i in range( 0,self.matrixDim["rows"] ):
for j in range( 0,self.matrixDim["columns"] ):
[ t , b ] = [ self.nets[self.matchingScheme[i][j]][0], self.nets[self.matchingScheme[i][j]][1] ]
dxDict = self.__computeConnections__( i,j, self.matchingScheme[i][j] )
Horizontal.create ( t, xPlateRLayer , self.hRoutingLayerYCenter["topPlate" ][i][j] , self.hRoutingLayer_width , dxDict["topPlate" ][ "source" ] , dxDict["topPlate" ][ "target" ] )
Horizontal.create ( b, xPlateRLayer , self.hRoutingLayerYCenter["bottomPlate"][i][j] , self.hRoutingLayer_width , dxDict["bottomPlate" ][ "source" ] , dxDict["bottomPlate" ][ "target" ] )
return
## Draws all required cuts using physical layers :
# - \c layer_hRTrack_hRLayer to connect bottom plates to vertical routeing tracks,
# - \c layer_tracksCut to connect vertical routeing tracks to horizontal ones,
# - \c layer_topPlateCut to connect top plates to vertical routeing tracks.
# ALso in \c drawCuts, nUmber of maximum cuts number on every layer is computed and cuts enclosure is adjusted according to layer's width.
def drawCuts( self, layer_hRTrack_hRLayer, layer_tracksCut, layer_topPlateCut ):
cutNumber = CapacitorUnit.cutMaxNumber( self, self.vRoutingTrack_width, self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut )
enclosure_hRoutingTrack_cut = (self.vRoutingTrack_width - cutNumber*self.minWidth_hRoutingTrackCut - (cutNumber - 1)*self.minSpacing_hRoutingTrackCut)/2
self.drawCuts_vRoutingTrack_HRLayer ( layer_hRTrack_hRLayer, cutNumber, enclosure_hRoutingTrack_cut )
self.drawCuts_vRoutingTrack_hRoutingTrack ( layer_tracksCut , cutNumber, enclosure_hRoutingTrack_cut )
self.drawCuts_stretchedTopPlate ( layer_topPlateCut )
return
def drawCuts_vRoutingTrack_HRLayer( self, cutLayer, cutNumber, enclosure_cut ):
[ vRoutingTrackXCenter, cutXMin ] = [{}, {}]
for i in range( 0, self.matrixDim["rows"] ):
for j in range( 0, self.matrixDim["columns"] ):
if ( j % 2 == 0 ):
leftVRTIds = self.capacitorIds[0:self.capacitorsNumber/2] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[0: int(self.capacitorsNumber/2+1)]
rightVRTIds = self.capacitorIds[self.capacitorsNumber/2 : self.capacitorsNumber] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[int(self.capacitorsNumber/2+1) : self.capacitorsNumber]
else:
leftVRTIds = self.capacitorIds[self.capacitorsNumber/2 : self.capacitorsNumber] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[int(self.capacitorsNumber/2+1) : self.capacitorsNumber]
rightVRTIds = self.capacitorIds[0:self.capacitorsNumber/2] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[0: int(self.capacitorsNumber/2+1)]
index1 = j if self.matchingScheme[i][j] in leftVRTIds else j+1
[topPlateLabel, bottomPlateLabel ] = [self.__setPlatesLabels__(i,j)["t"] , self.__setPlatesLabels__(i,j)["b"]]
vRoutingTrackXCenter["topPlate" ] = self.vRoutingTrackXCenter[index1][topPlateLabel + str( self.matchingScheme[i][j] )]
vRoutingTrackXCenter["bottomPlate"] = self.vRoutingTrackXCenter[index1][bottomPlateLabel + str( self.matchingScheme[i][j] )]
cutXMin["topPlate" ] = vRoutingTrackXCenter["topPlate" ] - self.vRoutingTrack_width/2 + enclosure_cut + self.minWidth_hRoutingTrackCut/2
cutXMin["bottomPlate"] = vRoutingTrackXCenter["bottomPlate"] - self.vRoutingTrack_width/2 + enclosure_cut + self.minWidth_hRoutingTrackCut/2
[ t , b ] = [ self.nets[self.matchingScheme[i][j]][0] , self.nets[self.matchingScheme[i][j]][1] ]
self.drawOneCut_vRoutingTrack_HRLayer( t, cutLayer, cutXMin["topPlate" ], self.hRoutingLayerYCenter["topPlate" ][i][j], cutNumber )
self.drawOneCut_vRoutingTrack_HRLayer( b, cutLayer, cutXMin["bottomPlate"], self.hRoutingLayerYCenter["bottomPlate"][i][j], cutNumber )
return
## Draws one cut, in layer \c cutLayer, in order to connect a vertical routeing track, at position \c cutXMin in metal 2, and a horizontal routeing track, at position \c cutYMin in metal 3.
def drawOneCut_vRoutingTrack_HRLayer( self, net, cutLayer, cutXMin, cutYMin, cutNumber ):
CapacitorUnit.cutLine(self,net,cutLayer,cutXMin,cutYMin,self.minWidth_hRoutingLayer_vRoutingTrack_cut,self.minWidth_hRoutingLayer_vRoutingTrack_cut,self.minSpacing_hRoutingLayer_vRoutingTrack_cut,cutNumber,'horizontal')
return
## Draws cuts to connect vertical routeing tracks in metal 2 and horizontal routeing tracks in metal 3.
def drawCuts_vRoutingTrack_hRoutingTrack( self,cutLayer, cutNumber, enclosure_cut ):
keysList = self.hRoutingtrackYCenter.keys()
for i in range(0, len(self.vRoutingTrackXCenter) ):
for k in self.vRoutingTrackXCenter[i]:
if self.vRoutingTrackXCenter[i][k] != None :
for l in range(0, 2) :
net = self.nets[ int(k[1]) ][0] if k[0] == 't' else self.nets[ int(k[1]) ][1]
cutXMin = self.vRoutingTrackXCenter[i][k] - self.vRoutingTrack_width/2 + enclosure_cut + self.minWidth_hRoutingTrackCut/2
CapacitorUnit.cutLine(self,net,cutLayer,cutXMin,self.hRoutingtrackYCenter[keysList[l]][k],self.minWidth_hRoutingTrackCut,self.minWidth_hRoutingTrackCut,self.minSpacing_hRoutingTrackCut,cutNumber,'horizontal')
return
# \param cutLayer
def drawCuts_stretchedTopPlate( self, cutLayer ):
layer_width = self.capacitor[0][0].getTopPlateRLayerWidth()
cutNumber = CapacitorUnit.cutMaxNumber( self, layer_width , self.minWidth_hRoutingLayer_topPlate_cut, self.minSpacing_hRoutingLayer_topPlate_cut , self.minEnclosure_hRoutingLayer_topPlate_cut )
enclosure_hRoutingTrack_cut = (layer_width - cutNumber*self.minWidth_hRoutingLayer_topPlate_cut - (cutNumber - 1)*self.minSpacing_hRoutingLayer_topPlate_cut)/2
for i in range(0, self.matrixDim["rows"] ):
for j in range(0, self.matrixDim["columns"] ):
tNet = self.nets[self.matchingScheme[i][j]][0]
cutXMin = self.capacitor[i][j].getTopPlateRLayerXMin() + enclosure_hRoutingTrack_cut + self.minWidth_hRoutingLayer_topPlate_cut/2
CapacitorUnit.cutLine( self, tNet, cutLayer, cutXMin , self.hRoutingLayerYCenter["topPlate"][i][j] , self.minWidth_hRoutingLayer_topPlate_cut, self.minWidth_hRoutingLayer_topPlate_cut, self.minSpacing_hRoutingLayer_topPlate_cut, cutNumber, 'horizontal' )
return
def drawDummyRing_hRTracks_Cuts( self, dummyNet, side, cutLayer ):
if side == "topSide" :
dummyRingElement = self.dummyRingCapacitor[-1]
key = "topTracks"
elif side == "bottomSide" :
dummyRingElement = self.dummyRingCapacitor[0]
key = "bottomTracks"
else : raise Error(1,'routeTopOrBottomSide() : side parameter must be either "topSide" or "bottomSide" : %s' %side)
topPlateLayer_width = dummyRingElement[0].getTopPlateRLayerWidth()
bottomPlateLayer_width = dummyRingElement[0].getBotPlateRLayerWidth()
topPlateCutNumber = CapacitorUnit.cutMaxNumber( self, topPlateLayer_width , self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut )
bottomPlateCutNumber = CapacitorUnit.cutMaxNumber( self, bottomPlateLayer_width, self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut )
topPlateCutEnclosure = (topPlateLayer_width - topPlateCutNumber *self.minWidth_vRoutingTrackCut - (topPlateCutNumber - 1)*self.minSpacing_vRoutingTrackCut)/2
# bottomPlateCutEnclosure = (bottomPlateLayer_width - bottomPlateCutNumber*self.minWidth_vRoutingTrackCut - (bottomPlateCutNumber - 1)*self.minSpacing_vRoutingTrackCut)/2
netsDistribution = self.__setPlatesIds__()
print("netsDistribution2",netsDistribution)
print("self.hRoutingtrackYCenter",self.hRoutingtrackYCenter)
for j in range(0,len(dummyRingElement)):
topPlateCutXCenter = dummyRingElement[j].getTopPlateRLayerXMin () + topPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2
bottomPlateLeftCutXCenter = dummyRingElement[j].getBottomPlateLeftCutXMin() #dummyRingElement[j].getBotPlateLeftRLayerXMin () + bottomPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2
bottomPlateRightCutXCenter = dummyRingElement[j].getBottomPlateRightCutXMin() #dummyRingElement[j].getBotPlateRightRLayerXMin() + bottomPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2f
CapacitorUnit.cutLine( self, dummyNet, cutLayer, topPlateCutXCenter , self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_vRoutingTrackCut,self.minWidth_vRoutingTrackCut,self.minSpacing_vRoutingTrackCut,topPlateCutNumber,'horizontal')
CapacitorUnit.cutLine( self, dummyNet, cutLayer, bottomPlateLeftCutXCenter , self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_vRoutingTrackCut,self.minWidth_vRoutingTrackCut,self.minSpacing_vRoutingTrackCut,bottomPlateCutNumber,'horizontal')
CapacitorUnit.cutLine( self, dummyNet, cutLayer, bottomPlateRightCutXCenter, self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_hRoutingTrackCut,self.minWidth_hRoutingTrackCut,self.minSpacing_hRoutingTrackCut,bottomPlateCutNumber,'horizontal')
return
## Iteratively performs top plates stretching for the capacitor matrix. Vertical segments are connected to top plate routeing layer.
# \param capacitor Capacitor matrix.
# \param rlayer Layer of the drawn vertical rectangle.
def __stretchTopPlates__( self, capacitor, rlayer ):
for i in range( 0, self.matrixDim["rows"] ):
for j in range( 0, self.matrixDim["columns"] ):
t = self.nets[self.matchingScheme[i][j]][0]
print('t',t)
self.__stretchTopPlateCompactCap__( t , capacitor[i][j], rlayer, j )
return
## Draws vertical stretched layers for a given elementary capacitor.
def __stretchTopPlateCompactCap__( self, net, capacitor, routeingLayer, j = 0 ):
topPlateRLayer_width = capacitor.getTopPlateRLayerWidth()
topPlateRLayerXCenter = capacitor.getTopPlateRLayerXCenter()
[ dySource , dyTarget ] = self.__setStretchingDySourceDyTarget__( capacitor, self.topPlateStretching )
Vertical.create ( net, routeingLayer , topPlateRLayerXCenter , topPlateRLayer_width , dySource , dyTarget )
return
## Sets the abcissas of the extremities of the vertical stretching to be applied to capacitor's top plates for a given elementary capacitor in the matrix.
# \param capacitor .values() Elementary unit capacitor.
# \param deltay Stretching value.
# \return A list that contains \c dySource and \dyTarget as top extremity and bottom extermity, respectively.
def __setStretchingDySourceDyTarget__( self, capacitor, deltay ):
dySource = capacitor.getTopPlateRLayerYMin()
dyTarget = dySource - deltay
return [ dySource , dyTarget ]
## Computes horizontal routeing layers source and target abcissas for top and bottom plates connections to its associated routeing track.
# \param (i,j) row and column indexes, respectively, in the matrix which describe the elementary capacitor position in the matrix.
# \param capacitorIdentifier equal to '1' if C1 and '2' if C2.
# \return A nested dicitionary. The overal dictionary is composed of keys equal to \c topPlate and \d bottomPlate and values equal to sub-dictionaries. The sub-dictionaries, are in their turn composed of two keys standing for the abcissa of the source and the abcissa of the target.
# \remark Naturally, an exception is raised if an unsupported capacitor identifier is given.
def __computeConnections__( self, i,j, capacitorIdentifier ):
if capacitorIdentifier in self.capacitorIds :
dxDict = { "bottomPlate": {}, "topPlate": {} }
if ( j % 2 == 0 ):
leftVRTIds = self.capacitorIds[0 :self.capacitorsNumber/2 ] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[0 : int(self.capacitorsNumber/2+1)]
rightVRTIds = self.capacitorIds[self.capacitorsNumber/2 : self.capacitorsNumber ] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[int(self.capacitorsNumber/2+1) : self.capacitorsNumber ]
else:
leftVRTIds = self.capacitorIds[self.capacitorsNumber/2 : self.capacitorsNumber ] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[int(self.capacitorsNumber/2+1) : self.capacitorsNumber ]
rightVRTIds = self.capacitorIds[0 : self.capacitorsNumber/2 ] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[0 : int(self.capacitorsNumber/2+1)]
[topPlateLabel, bottomPlateLabel ] = [self.__setPlatesLabels__(i,j)["t"] , self.__setPlatesLabels__(i,j)["b"]]
dxDict["topPlate" ][ "source" ] = self.capacitor[i][j].getTopPlateRLayerXMax () if self.matchingScheme[i][j] in leftVRTIds else self.capacitor[i][j].getTopPlateRLayerXMin()
dxDict["topPlate" ][ "target" ] = self.__findHRLDyTrarget__( i,j, topPlateLabel, leftVRTIds, rightVRTIds )
dxDict["bottomPlate" ][ "source" ] = self.capacitor[i][j].getBotPlateLeftRLayerXMax () if self.matchingScheme[i][j] in leftVRTIds else self.capacitor[i][j].getBotPlateRightRLayerXMin ()
# bottomPlateLabel = 'b' if self.dummyElement == False or not( self.__isCapacitorAdummy__(capacitorIdentifier) ) else 't'
print("bottomPlateLabel",bottomPlateLabel)
dxDict["bottomPlate" ][ "target" ] = self.__findHRLDyTrarget__( i, j, bottomPlateLabel, leftVRTIds, rightVRTIds )
else : raise Error(1, '__computeConnections__(): Unknown capacitor Id : %s.' %capacitorIdentifier )
print('dxDict',dxDict)
return dxDict
def __isCapacitorAdummy__( self, capacitorIdentifier ) :
state = False
if self.dummyElement == True :
if capacitorIdentifier == self.capacitorIds[-1] : state = True
else : raise Error(1,'The matrix contains no dummies because dummy element is "False".')
return state
def __setPlatesLabels__( self, i, j ):
platesLabels = {}
capacitorIdentifier = self.matchingScheme[i][j]
platesLabels["t"] = 't'
platesLabels["b"] = 'b' if self.dummyElement == False or not( self.__isCapacitorAdummy__(capacitorIdentifier) ) else 't'
return platesLabels
def __findHRLDyTrarget__( self, i,j, plateLabel, leftVRTIds, rightVRTIds ):
if plateLabel in ['t','b'] :
plateIndex = self.matchingScheme[i][j]
[ doLeft , doRight ] = [1,0] if self.matchingScheme[i][j] in leftVRTIds else [0,1]
xCenterList = leftVRTIds if [ doLeft , doRight ] == [1,0] else rightVRTIds
index1 = j if [ doLeft , doRight ] == [1,0] else j+1
for key in self.vRoutingTrackXCenter[index1].keys() :
if key == plateLabel + str(plateIndex) :
index2 = key
break
else : raise Error(1,'__findHRLDyTrarget__() : Plate label must be "t" for top plate and "b" for bottom plate. The given label is : %s.' %plateLabel)
return self.vRoutingTrackXCenter[index1][index2] - doLeft*self.vRoutingTrack_width/2 + doRight*self.vRoutingTrack_width/2
def __setPlatesIds__( self ):
keys = []
for k in range(0, len(self.nets)):
keys.append( 't' + str(k) )
keys.append( 'b' + str(k) )
if self.dummyRing == True or self.dummyElement == True : keys = keys[0:len(keys)-1]
return keys
def __findPossibleShortCircuits__( self ):
shortCircuitLists = []
self.vRTsDistribution = self.vRTInstance.vRTsDistribution
for i in range(0, self.matrixDim["rows"]):
shortCircuitLists.append([0])
for j in range(0, self.matrixDim["columns"]):
shortCircuitLists[i].append(0)
for i in range(0, self.matrixDim["rows"]):
for j in range(0, self.matrixDim["columns"]-1):
print('self.vRTsDistribution',self.vRTsDistribution)
if self.matchingScheme[i][j] in self.vRTsDistribution[j+1] and self.matchingScheme[i][j+1] in self.vRTsDistribution[j+1] and self.matchingScheme[i][j] > self.matchingScheme[i][j+1] : shortCircuitLists[i][j] = 1
return shortCircuitLists
def ScriptMain( **kw ):
editor = None
if kw.has_key('editor') and kw['editor']:
editor = kw['editor']
UpdateSession.open()
Device = AllianceFramework.get().createCell( 'capacitor' )
Device.setTerminal( True )
bottomPlate_net0 = Net.create( Device, 'b0' )
bottomPlate_net1 = Net.create( Device, 'b1' )
bottomPlate_net2 = Net.create( Device, 'b2' )
bottomPlate_net3 = Net.create( Device, 'b3' )
bottomPlate_net0.setExternal( True )
bottomPlate_net1.setExternal( True )
bottomPlate_net2.setExternal( True )
bottomPlate_net3.setExternal( True )
b0 = Device.getNet("b0")
b1 = Device.getNet("b1")
b2 = Device.getNet("b2")
b3 = Device.getNet("b3")
topPlate_net0 = Net.create( Device, 't0' )
topPlate_net1 = Net.create( Device, 't1' )
topPlate_net2 = Net.create( Device, 't2' )
topPlate_net3 = Net.create( Device, 't3' )
topPlate_net0.setExternal( True )
topPlate_net1.setExternal( True )
topPlate_net2.setExternal( True )
topPlate_net3.setExternal( True )
t0 = Device.getNet("t0")
t1 = Device.getNet("t1")
t2 = Device.getNet("t2")
t3 = Device.getNet("t3")
if editor:
UpdateSession.close()
editor.setCell( Device )
editor.fit()
UpdateSession.open()
nets = [[t0, b0] , [t1, b1], [t2, b2] ] # [t3, b3] ]
capacitorInstance = CapacitorStack( Device, [372,1116], 'MIMCap', [0,0], nets, unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ [1,1,1,0] , [0,1,1,1] , [1,1,1,0] , [0,1,1,1] ] , dummyRing = True )#dummyRing = True)
# capacitorInstance = CapacitorStack( Device, [279,1023, 186], 'MIMCap', [0,0], nets, unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ [1,1,1,0] , [0,1,2,1] , [1,1,1,0] , [2,1,1,1] ], dummyElement = True, dummyRing = True )#dummyRing = True)
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 50, matchingMode = True, matchingScheme = [ ['C2','C1','C2','C1','C1'] , ['C1','C2','C1','C2','C2'] , ['C1','C2','C2','C2', 'C1'] , ['C1','C2','C2','C1', 'C1'], ['C2','C2','C2','C2','C2'] ] )
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 93, matchingMode = True, matchingScheme = [ ['C2','C2','C2','C2'] , ['C1','C2','C2','C2'] , ['C1','C2','C2','C2'] , ['C1','C2','C2','C1'] ] )
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 93, matchingMode = True, matchingScheme = [ ['C2','C2','C1','C2'] , ['C1','C2','C2','C1'] , ['C1','C1','C2','C3'] , ['C1','C1','C2','C3'] ] )
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, matrixDim = [5,5] , matchingMode = True, matchingScheme = [ ['C2','C1','C2','C3','C1'] , ['C1','C2','C4','C3','C2'] , ['C4','C2','C2','C3', 'C1'] , ['C1','C2','C2','C1', 'C1'], ['C2','C2','C3','C2','C4'] ] )
capacitor = capacitorInstance.create()
print('capa',capacitor)
capWithVRT = VerticalRoutingTracks( capacitorInstance, capacitor, True )
capWithVRT.create()
routedCap = RoutMatchedCapacitor( capWithVRT )
surface = routedCap.route( )
print('routeMatchedCap bbMode', surface)
AllianceFramework.get().saveCell( Device, Catalog.State.Views )
return True

View File

@ -0,0 +1,697 @@
#!/usr/bin/python
import sys
import numpy
from Hurricane import *
from CRL import *
from math import sqrt, ceil
import helpers
from helpers.io import ErrorMessage as Error
from helpers import trace
import oroshi
def toDbU ( l ): return DbU.fromPhysical( l, DbU.UnitPowerMicro )
## Draws a capacitor of type Poly-Poly or Metal-Metal in 350 nm AMS CMOS technology.
# PIP and MIM capacitors are the result of surface superposition between poly1 and poly2 or metal2 and metalcap layers, respectively.
# Given the capacitor value, layout dimensions are computed, then, capacitor layers are drawn. Capacitor value, \f$C\f$, is given in the expression below, where \f$ C_{a}, C_{p}, A \f$ and \f$ P \f$ are, area capacitance, perimeter capacitance, area and permiter of the capacitor, respectively :
# \f[ C = C_{a}A + C_{p}P \f]
# The drawn layout shape is square. Thus, metcap or poly2 length and width are equal and are computed using the capacitor expression. Furthermore, given \f$ C_{a} \f$, \f$ C_{p} \f$ and enclosure technological rules, dimensions and positions of the abutment box as well as the bottom plate are computed. Layouts with dimensions that exceed technological limits cannot be drawn.
class CapacitorUnit():
rules = oroshi.getRules()
## This is the class constructor. Few of the class attributes final values are computed in this level. Most of attributes are only initialized to zero or empty values. Then, it is computed in dedicated class method. Input parameters are :
# \param device Hurricane AMS device into which layout is drawn.
# \param capacitance Capacitor value, expressed in \f$ femto Farad (fF) \f$.
# \param abutmentBoxPosition A list containing abscissa and ordinate of the bottom left corner of the abutment box.
#
# Class attributes are described in the list below. Most of class attributes refer to layout dimensions. Dictionaries are used to group attributes related to the same layout varibale. Layout dimensions and variables are described in Figure 1.
#
# \param device Hurricane AMS device into which layout is drawn.
# \param capacitance Capacitor value, expressed in \f$ femto Farad (fF) \f$.
# \param capacitorType Can be 'MIMCap' or 'PIPCap' as capacitor type.
# \param abutmentBoxDict A dictionary containing abscissa and ordinate of the bottom left corner of the abutment box, (XMin) and (YMin), respectively.
# \param abutmentBox Abutment box drawn square. It is an object of type \c Box.
# \param bottomPlateBox Bottom plate drawn square. It is an object of type \c Box.
# \param topPlateBox Top plate drawn square. It is an object of type \c Box.
# \param cut2MatrixDict A dictionary containing center position of the left bottom, which is cut the first to be drawn in the matrix of cuts. Initially, the dictionary is empty. It is only updated when \c self.capacitorType is equal to \c 'MIMCap'.
#
# \param cutLeftLineDict A dictionary containing abcissa and ordinate of the bottom cut in the left line of cuts to be drawn on bottom plate's layer.
# \param cutRightLineDict A dictionary containing abcissa and ordinate of the bottom cut in the right line of cuts to be drawn on bottom plate's layer.
# \param topCutLineDict A dictionary containing abcissa and ordinate of the bottom cut in the right line of cuts to be drawn on top plate's layer. Initially, the dictionary is empty. It is only updated when \c self.capacitorType is equal to \c 'PIPCap'.
#
# \param topPlateRLayerDict A dictionary containing position information of the top plate's routing layer. The dictionary includes ordinates of the layer's top and bottom extremities, \c 'XMin' and \c 'YMin', respectively, the abcissa of it's center, \c 'XCenter' and its width, \c 'width'.
#
# \param bottomPlateRLayerDict A dictionary containing
# \param enclosure_botPlate_topPlate Top plate's layer encolusre in bottom plate's layer.
# \param minheight_topPlatecut Minimum height of cuts for top plate connection to other metal layer.
# \param topCutLineNumber Maximum possible number cuts to be drawn for top plate's connection.
# \param bottomCutLineNumber Maximum possible number cuts to be drawn for top plate's connection.
def __init__( self, device, capacitance, capacitorType, abutmentBoxPosition ):
self.device = device
self.capacitorType = capacitorType
self.capDim = self.__computeCapDim__( capacitance, capacitorType )
self.abutmentBoxDict = { "XMin" : abutmentBoxPosition[0], "YMin" : abutmentBoxPosition[1] }
self.abutmentBox = Box ()
self.bottomPlateBox = Box ()
self.topPlateBox = Box ()
self.bottomPlateBoxDict = {}
self.topPlateBoxDict = {}
self.cut2MatrixDict = {}
self.cutLeftLineDict = {}
self.cutRightLineDict = {}
self.topCutLineDict = {}
self.topPlateRLayerDict = {}
self.bottomPlateRLayerDict = {}
self.enclosure_botPlate_topPlate = 0
self.minheight_topPlatecut = 0
self.topCutLineNumber = 0
self.bottomCutLineNumber = 0
# self.nets = { "bNet" : bNet, "tNet" : tNet }
return
## Sets the area and perimeter capacitances as specified in 350 nm AMS technology and according to \c capacitorType (MIM or PIP).
# \return a list containing the area and perimeter capacitances.
# \remarks An exception is raised if the entered capacitor type is unknown.
def __setCapacitorPerUnit__( self, capacitorType ) :
if capacitorType == 'MIMCap':
[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = [ CapacitorUnit.rules.MIMCap, CapacitorUnit.rules.MIMPerimeterCap ]
elif capacitorType == 'PIPCap':
[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = [ CapacitorUnit.rules.PIPCap, CapacitorUnit.rules.PIPPerimeterCap ]
else:
raise Error( 1, 'setCapacitorPerUnit() : Unsupported capacitor type : %s.' % capacitorType )
return [ areaCapacitorPerUnit, perimeterCapacitorPerUnit ]
## Computes width and length of the capacitor. Given \c capacitance value as well as the permiter and area capacitances, a quadratic equation is solved where the unknown parameter is the width ( also equivalent to the length ).
# \return a dictionary containing width and length.
# \remark The capacitor is square. Thus, length and width are equal.
def __computeCapDim__( self, capacitance, capacitorType ) :
[a, b, c ] = [ self.__setCapacitorPerUnit__( capacitorType )[0], 4*self.__setCapacitorPerUnit__( capacitorType )[1], -capacitance ]
delta = (b**2) - 4*a*c
c1 = ( -b + sqrt(delta) ) / (2*a)
return { "width" : toDbU(c1), "height" : toDbU(c1) }
## Checks if the computed capacitor dimensions exceed or are less than maximum and minimum limits, respectively, as specified in technology rules.
## \return \c True if all rules are respected.
# \remark Maximum poly2 layer dimensions for PIP capacitor are not specified in technology rules. Thus, only minimum limit condition is checked.
def __isCapacitorUnitOK__( self, capDim ):
if ( self.capacitorType == 'MIMCap' and CapacitorUnit.getMinimumCapWidth( self ) < capDim["width"] < self.getMaximumCapWidth()) or self.capacitorType == 'PIPCap' and self.getMinimumCapWidth() < capDim["width"]:
return True
## Redefines technological rules as object attributes of the class. For example, class attributes \c CapacitorUnit.rules.minWidth_metcap becomes \c self.minWidth_topPlate and \c CapacitorUnit.rules.minSpacing_cut2_metcap becomes \c self.minSpacing_botPlateCut_topPlat. This obviously helps using shorter names for the attributes. \c __setattr__() is declared in all \c Capacitor \c Generator classes, also in Hurricane and oroshi databases.
def __setattr__( self, attribute, value ):
self.__dict__[attribute] = value
return
## Selects technological rules according to the capacitor type.
# \return a dictionary with rules labels as keys and rules as values.
# Example of technology rules are :
# - minimum spacing between cuts or metals,
# - minimum width of a plate, a cut or a routing metal.
# - etc.
# Every rule takes two possible value according to the capacitor type (MIM or PIP). Therefore, dictionary keys are generic and its values are specific to the capacitor type.
# \remark An exception is raised if the entered capacitor type is unknown.
def setRules ( self ):
if self.capacitorType == 'MIMCap':
self.__setattr__( "minWidth_topPlate" , CapacitorUnit.rules.minWidth_metcap )
self.__setattr__( "minWidth_botRMetal" , CapacitorUnit.rules.minWidth_metal3 )
self.__setattr__( "minWidth_topRMetal" , CapacitorUnit.rules.minWidth_metal1 )
self.__setattr__( "minWidth_topPlatecut" , CapacitorUnit.rules.minWidth_cut2 )
self.__setattr__( "minWidth_botPlatecut" , CapacitorUnit.rules.minWidth_cut2 )
self.__setattr__( "minWidth_routingTrackcut" , CapacitorUnit.rules.minWidth_cut2 )
self.__setattr__( "minSpacing_botPlate" , CapacitorUnit.rules.minSpacing_metbot )
self.__setattr__( "minSpacing_botPlateCut_topPlate" , CapacitorUnit.rules.minSpacing_cut2_metcap )
self.__setattr__( "minSpacingOnBotPlate_cut" , CapacitorUnit.rules.minSpacingOnMetBot_cut2 )
self.__setattr__( "minSpacingOnTopPlate_cut" , CapacitorUnit.rules.minSpacingOnMetCap_cut2 )
self.__setattr__( "minEnclo_botPlate_botPlateCut" , CapacitorUnit.rules.minEnclosure_metbot_cut2 )
self.__setattr__( "minEnclo_topPlate_topPlateCut" , CapacitorUnit.rules.minEnclosure_metcap_cut2 )
self.__setattr__( "minEnclo_topPlateRMetal_topPlateCut" , CapacitorUnit.rules.minEnclosure_metal3_cut2 )
self.__setattr__( "minEnclo_botPlateRMetal_botPlateCut" , CapacitorUnit.rules.minEnclosure_metal3_cut2 )
self.__setattr__( "minEnclo_routingTrackMetal_cut" , CapacitorUnit.rules.minEnclosure_metal3_cut2 )
elif self.capacitorType == 'PIPCap':
self.__setattr__( "minWidth_topPlate" , CapacitorUnit.rules.minWidth_cpoly )
self.__setattr__( "minWidth_botRMetal" , CapacitorUnit.rules.minWidth_metal1 )
self.__setattr__( "minWidth_topRMetal" , CapacitorUnit.rules.minWidth_metal1 )
self.__setattr__( "minWidth_topPlatecut" , CapacitorUnit.rules.minWidth_cut0 )
self.__setattr__( "minWidth_botPlatecut" , CapacitorUnit.rules.minWidth_cut0 )
self.__setattr__( "minWidth_routingTrackcut" , CapacitorUnit.rules.minWidth_cut1 )
self.__setattr__( "minSpacing_botPlate" , CapacitorUnit.rules.minSpacing_poly )
self.__setattr__( "minSpacing_botPlateCut_topPlate" , CapacitorUnit.rules.minSpacing_cut0_cpoly )
self.__setattr__( "minSpacingOnBotPlate_cut" , CapacitorUnit.rules.minSpacing_cut0 )
self.__setattr__( "minSpacingOnTopPlate_cut" , CapacitorUnit.rules.minSpacing_cut0 )
self.__setattr__( "minEnclo_botPlate_botPlateCut" , CapacitorUnit.rules.minEnclosure_poly_cut0 )
self.__setattr__( "minEnclo_topPlate_topPlateCut" , CapacitorUnit.rules.minEnclosure_cpoly_cut0 )
self.__setattr__( "minEnclo_topPlateRMetal_topPlateCut" , CapacitorUnit.rules.minEnclosure_metal1_cut1 )
self.__setattr__( "minEnclo_botPlateRMetal_botPlateCut" , CapacitorUnit.rules.minEnclosure_metal1_cut0 )
self.__setattr__( "minEnclo_routingTrackMetal_cut" , CapacitorUnit.rules.minEnclosure_metal1_cut1 )
else :
raise Error( 1, 'setRules() : Unsupported capacitor type : %s.' % self.capacitorType )
self.minheight_topPlatecut = self.minWidth_topPlatecut
return
## \return capacitor type \c 'MIMCap' or \c 'PIPCap'.
# \remarks \c getCapacitorType() is especially useful when an instance of \c CapacitorUnit class is called in another classes instances to identify the capacitor's type.
def getCapacitorType ( self ) : return self.capacitorType
## \retun maximum size of capacitor's top plate. \c getMaximumCapWidth() is called to check if capacitor dimensions are within acceptable technological limits.
# An exception is raised if the entered capacitor type is unknown.
# \remarks 1. This function is especially usefull in drawing the layout of a unity capacitor, where it is important to garantee that the capacitor size does not exeed the maximum possible value. It is also useful when drawing a matrix of capacitors to make sure that also the unity capacitor respects the maximal values specified. \remarks 2. The maximum value of the poly2 size in PIP capacitor is not specified. Thus, it is not considered in \c getMaximumCapWidth()
def getMaximumCapWidth ( self ) :
if self.capacitorType == 'MIMCap':
maximumCapWidth = CapacitorUnit.rules.maxWidth_metcap
elif self.capacitorType == 'PIPCap':
maximumCapWidth = None #CapacitorUnit.rules.maxWidth_cpoly
else:
raise Error( 1, 'getMaximumCapWidth() : Unsupported capacitor type : %s.' % self.capacitorType )
return maximumCapWidth
## \return The minimum size of the capacitor's top plate. An exception is raised if the entered capacitor type is unknown.
# \remarks This function is especially usefull in drawing the layout of a matrix of capacitors where it is important to ensure that the unity capacitor respects the minimal values specified. \remarks An exception is raised if the entered capacitor type is unknown.
def getMinimumCapWidth ( self ) :
if self.capacitorType == 'MIMCap':
minimumCapWidth = CapacitorUnit.rules.minWidth_metcap
elif self.capacitorType == 'PIPCap':
minimumCapWidth = CapacitorUnit.rules.minWidth_cpoly
else:
raise Error( 1, 'getMinimumCapWidth() : Unsupported capacitor type : %s.' % self.capacitorType )
return minimumCapWidth
## Loads the technology file then extracts the adequate layers according to the capacitor type (MIM or PIP).
#
# \return a dictionary containing the layer labels as attributes and its values.
# \remarks An exception is raised if the entered capacitor type is unknown.
def getLayers( self ):
technology = DataBase.getDB().getTechnology()
layerDict = {}
if self.capacitorType == 'MIMCap':
layerDict["topPlateLayer" ] = technology.getLayer( "metcap" )
layerDict["bottomPlateLayer" ] = technology.getLayer( "metal2" )
layerDict["topPlateRLayer" ] = technology.getLayer( "metal3" )
layerDict["bottomPlateRLayer" ] = technology.getLayer( "metal3" )
layerDict["topBottomcutsLayer" ] = technology.getLayer( "cut2" )
elif self.capacitorType == 'PIPCap':
layerDict["topPlateLayer" ] = technology.getLayer( "poly2" )
layerDict["bottomPlateLayer" ] = technology.getLayer( "poly" )
layerDict["topPlateRLayer" ] = technology.getLayer( "metal1" )
layerDict["bottomPlateRLayer" ] = technology.getLayer( "metal1" )
layerDict["topBottomcutsLayer" ] = technology.getLayer( "cut0" )
else :
raise Error( 1, 'getLayers() : Unsupported capacitor type : %s.' % self.capacitorType )
return layerDict
## When bonding box mode is activated, the function draws all layout physical layers of the capacitor after checking its dimensions. All functions are excecuted in a new Update Session. In the contrary, only an exact estimation of layout dimensions is given. An error is raised when dimensions reach technological limits for MIM and PIP capacitors or when \c bbMode parameters is other than \c True or \c False.
#
# \param ( tNet , bNet ) nets of top and bottom plates, respectively
# \param bbMode activates bonding box dimensions computing when set to \c True
def create( self, tNet, bNet, bbMode = False ):
UpdateSession.open()
abutmentBoxDimensions = None
self.setRules ()
if self.__isCapacitorUnitOK__( self.capDim ) == True :
self.computeDimensions ( self.capDim )
self.drawAbutmentBox ()
self.device.setAbutmentBox( self.abutmentBox )
if bbMode == True :
abutmentBoxDimensions = self.abutmentBoxDict
elif bbMode == False :
layerDict = self.getLayers()
self.drawCapacitor( layerDict, tNet, bNet )
else :raise Error(1, 'drawCapacitor(): The bonding box mode parameter, "bbMode" must be either True or False : %s.' %bbMode )
else : raise Error(1, 'creat(): Impossible to draw the capacitor, dimensions are either too large or too small, "%s".' % self.capDim )
UpdateSession.close()
return abutmentBoxDimensions
## Draws all layout physicial layers of the capacitor.
#
# \param layerDict a dictionary containing a description of the required physical layers according to capacitor type
# \param ( tNet , bNet ) nets of top and bottom plates, respectively
def drawCapacitor( self, layerDict, tNet, bNet ):
self.bottomPlateBox = self.drawOnePlate( layerDict["bottomPlateLayer" ] , bNet , self.bottomPlateBoxDict )
self.topPlateBox = self.drawOnePlate( layerDict["topPlateLayer" ] , tNet , self.topPlateBoxDict )
self.drawBottomPlateCut ( layerDict["topBottomcutsLayer"] , bNet )
self.drawTopPlateCut ( layerDict["topBottomcutsLayer"] , tNet )
self.drawRoutingLayers ( layerDict["bottomPlateRLayer" ] , layerDict["topPlateRLayer"] , tNet , bNet )
return
## Computes needed parameters to draw bottom plate cuts in its exact position, including :
#
# - maximum number of cuts to draw on both sides of bottom plate,
# - adjusted enclosure of
# - abcissas of the two bottom cuts on left and right sides of bottom plate,
# - ordinate of the same two cuts.
#
# Given parameters described above, it is possible to draw the entire lines of cuts on both sides of bottom plate using \c cutLine function.
def computeBottomPlateCuts( self ):
self.bottomCutLineNumber = self.cutMaxNumber( self.bottomPlateBoxDict["height"], self.minheight_topPlatecut, self.minSpacingOnBotPlate_cut, self.minEnclo_botPlate_botPlateCut )
enclosure_botPlate_botPlateCut = ( self.bottomPlateBoxDict["height"] - (self.bottomCutLineNumber * self.minheight_topPlatecut + (self.bottomCutLineNumber -1) * self.minSpacingOnBotPlate_cut) )/2
self.cutLeftLineDict ["XMin"] = self.topPlateBoxDict["XMin"] - self.minSpacing_botPlateCut_topPlate - self.minWidth_topPlatecut/2
self.cutRightLineDict["XMin"] = self.topPlateBoxDict["XMin"] + self.topPlateBoxDict["width"] + self.minSpacing_botPlateCut_topPlate + self.minWidth_topPlatecut/2
self.cutLeftLineDict ["YMin"] = self.bottomPlateBoxDict["YMin"] + self.minheight_topPlatecut/2 + enclosure_botPlate_botPlateCut
self.cutRightLineDict["YMin"] = self.cutLeftLineDict["YMin"]
return
## Computes needed parameters to draw top plate cuts in its exact position, including :
#
# - maximum number of cuts to draw on both sides of top plate,
# - adjusted enclosure of
# - abcissas of the two top cuts on left and right sides of top plate,
# - ordinate of the same two cuts.
#
# Given parameters described above, it is possible to draw the entire lines of cuts on both sides of bottom plate using \c cutLine function.
def computeTopPlateCuts( self ):
self.topCutLineNumber = self.cutMaxNumber( self.topPlateBoxDict["height"], self.minheight_topPlatecut, self.minSpacingOnTopPlate_cut, self.minEnclo_topPlate_topPlateCut )
enclosure_topPlate_topPlateCut = ( self.topPlateBoxDict["height"] - (self.topCutLineNumber *self.minheight_topPlatecut + (self.topCutLineNumber -1)*self.minSpacingOnTopPlate_cut) )/2
if self.capacitorType == 'MIMCap':
self.cut2MatrixDict[ "Width" ] = (self.topCutLineNumber - 2)*self.minWidth_topPlatecut + (self.topCutLineNumber - 1) * self.minSpacingOnTopPlate_cut
cut2MatrixAttribute = ["XMin", "YMin" ]
topPlateBoxCordinates = [self.topPlateBoxDict["XMin"], self.topPlateBoxDict["YMin"]]
for i in range(2):
topPlateCutTab = [ self.minWidth_topPlatecut, self.minheight_topPlatecut ]
self.cut2MatrixDict[ cut2MatrixAttribute[i] ] = topPlateBoxCordinates[i] + topPlateCutTab[i] /2 + enclosure_topPlate_topPlateCut
elif self.capacitorType == 'PIPCap':
self.topCutLineDict["XMin"] = self.topPlateBoxDict["XMin"] + self.topPlateBoxDict["width"] - self.minEnclo_topPlate_topPlateCut - self.minWidth_topPlatecut/2
self.topCutLineDict["YMin"] = self.topPlateBoxDict["YMin"] + self.minheight_topPlatecut/2 + enclosure_topPlate_topPlateCut
else :
raise Error( 1, 'computeTopPlateCuts() : Unsupported capacitor type : %s. Cuts cannot be drawn. ' % self.capacitorType )
return
def computeRoutingLayersDimensions( self ):
if self.capacitorType == 'MIMCap' :
self.cut2MatrixDict ["XMax"] = self.cut2MatrixDict["XMin"] + self.cut2MatrixDict["Width"] + self.minWidth_topPlatecut
[ topmetalXMin,topmetalXMax ] = [ self.cut2MatrixDict["XMin"] - self.minEnclo_topPlateRMetal_topPlateCut - self.minWidth_topPlatecut/2, self.cut2MatrixDict["XMax"] + self.minEnclo_topPlateRMetal_topPlateCut + self.minWidth_topPlatecut/2]
[ width_topMetal, width_bottomMetal ] = [ topmetalXMax - topmetalXMin, max( self.minWidth_botRMetal, (self.minWidth_botPlatecut + 2*self.minEnclo_botPlateRMetal_botPlateCut) ) ]
topMetalXCenter = self.abutmentBoxDict["XMin"] + self.abutmentBoxDict["width"]/2
elif self.capacitorType == 'PIPCap' :
topMetalXCenter = self.topCutLineDict["XMin"]
width_topMetal = max( self.minWidth_botRMetal, (self.minWidth_topPlatecut+ 2*self.minEnclo_topPlateRMetal_topPlateCut), ( self.minWidth_routingTrackcut +2*self.minEnclo_routingTrackMetal_cut) )
width_bottomMetal = width_topMetal
else :
raise Error( 1, 'drawRoutingLayers() : Unsupported capacitor type : %s. Routing layers parameters cannot be computed. ' % self.capacitorType ) #com verirfy the two next lines are after else or before
[ dySourceTop , dyTargetTop ] = [ self.bottomPlateBoxDict["YMin"], self.topPlateBoxDict["YMin"] + self.topPlateBoxDict["height"] ]
[ dySourceBottom, dyTargetBottom ] = [ self.bottomPlateBoxDict["YMin"], self.bottomPlateBoxDict["YMin"]+self.bottomPlateBoxDict["height"] ]
self.topPlateRLayerDict = { "YMin" : dySourceTop, "YMax" : dyTargetTop, "XCenter" : topMetalXCenter , "width" : width_topMetal }
self.bottomPlateRLayerDict = { "left" : {"XMin": self.cutLeftLineDict["XMin"] - ( self.minEnclo_botPlate_botPlateCut + self.minWidth_botPlatecut/2 ), "XMax": self.cutLeftLineDict["XMin"] + ( self.minEnclo_botPlate_botPlateCut + self.minWidth_botPlatecut/2 )} , "right" : {"XMin": self.cutRightLineDict["XMin"] - ( self.minEnclo_botPlate_botPlateCut + self.minWidth_botPlatecut/2 )}, "YMin": dySourceBottom, "YMax": dyTargetBottom, "width": width_bottomMetal }
return
def computeAbutmentBoxDimensions( self, capDim ) :
self.enclosure_botPlate_topPlate = self.minEnclo_botPlate_botPlateCut + self.minWidth_topPlatecut + self.minSpacing_botPlateCut_topPlate
abutmentBoxDimensions = {}
for key in capDim.keys():
abutmentBoxDimensions[key] = 2*self.enclosure_botPlate_topPlate + capDim[key] + 2*self.minSpacing_botPlate
abutmentBoxDimensions["surface"] = numpy.prod(abutmentBoxDimensions.values())
return abutmentBoxDimensions
## Draws the abutment box of the capacitor in position \c <(abutmentBoxXMin, abutmentBoxYMin)>. First, the minimum enclosure of the top plate inside the bottom plate is computed. Second, using this parameters as well as the capacitor dimensions, the width and height of the abutment box are computed. The box is finally drawn.
def drawAbutmentBox( self ):
self.abutmentBox = Box(self.abutmentBoxDict["XMin"],self.abutmentBoxDict["YMin"],self.abutmentBoxDict["width"]+self.abutmentBoxDict["XMin"],self.abutmentBoxDict["height"]+self.abutmentBoxDict["YMin"])
return
def computeOnePlateBoxDimensions( self, inputBoxDimensions, enclosure ):
outputboxDimensions = {}
outputboxDimensions["XMin" ] = inputBoxDimensions["XMin" ] + enclosure
outputboxDimensions["YMin" ] = inputBoxDimensions["YMin" ] + enclosure
outputboxDimensions["width" ] = inputBoxDimensions["width" ] - 2*enclosure
outputboxDimensions["height"] = inputBoxDimensions["height"] - 2*enclosure
return outputboxDimensions
def computeDimensions( self, capDim ):
abutmentBoxDimensions = self.computeAbutmentBoxDimensions(capDim)
for key in abutmentBoxDimensions.keys():
self.abutmentBoxDict[key] = abutmentBoxDimensions[key]
self.bottomPlateBoxDict = self.computeOnePlateBoxDimensions( self.abutmentBoxDict , self.minSpacing_botPlate )
self.topPlateBoxDict = self.computeOnePlateBoxDimensions( self.bottomPlateBoxDict, self.enclosure_botPlate_topPlate )
self.computeBottomPlateCuts()
self.computeTopPlateCuts()
self.computeRoutingLayersDimensions()
return
## Draws the top or bottom plate through inflation of the Box under it. These boxes are the abutment box in the case of the bottom plate and the bottom plate's box in the case of the top plate. This function also creates a a net for the drawn plate and sets it as external.
# \return The drawn box.
#def drawOnePlate( self, layer, net, inputPlateBox, depth ):
# outputPlateBox = Box( inputPlateBox.getXMin(), inputPlateBox.getYMin(), inputPlateBox.getXMax(), inputPlateBox.getYMax() ).inflate( -depth )
# platePad = Pad.create( net, layer, outputPlateBox )
# NetExternalComponents.setExternal( platePad )
# return outputPlateBox
def drawOnePlate( self, layer, net, boxDimensions) :
outputPlateBox = Box( boxDimensions["XMin"], boxDimensions["YMin"], boxDimensions["XMin"] + boxDimensions["width"], boxDimensions["YMin"] + boxDimensions["height"] )
print("outputPlate",outputPlateBox)
print("net",net)
platePad = Pad.create( net, layer, outputPlateBox )
NetExternalComponents.setExternal( platePad )
return outputPlateBox
## Draws the required cuts to connect the bottom plate. First, the maximal possible number of cuts that can be drawn is computed. Second, using the computed number, the enclosure of this cuts in the bottom plate's layer is adjusted while the minimal enclosure is respected. Third, the relative positions of the cuts on both sides of the plate are computed. Finally, two vertical lines of cuts are drawns.
# \remark The relative positions describe the cordinates of the first bottom cut in every line of cuts. Then, knowing the spacing and width specifications of these cuts the rest of the line is easilly constructed.
def drawBottomPlateCut( self, layer, bNet ):
self.cutLine( bNet, layer, self.cutLeftLineDict ["XMin"], self.cutLeftLineDict ["YMin"], self.minWidth_botPlatecut, self.minheight_topPlatecut, self.minSpacingOnBotPlate_cut, self.bottomCutLineNumber , 'vertical' )
self.cutLine( bNet, layer, self.cutRightLineDict["XMin"], self.cutRightLineDict["YMin"], self.minWidth_botPlatecut, self.minheight_topPlatecut, self.minSpacingOnBotPlate_cut, self.bottomCutLineNumber , 'vertical' )
return
## Draws the top plate's cuts after computing the maximal number of cuts that can be placed and its exact enclosure in the top plate.
def drawTopPlateCut( self, layer, tNet ):
if self.capacitorType == 'MIMCap':
self.cutMatrix(tNet,layer,self.cut2MatrixDict["XMin"],self.cut2MatrixDict["YMin"],self.minWidth_topPlatecut,self.minheight_topPlatecut,self.minSpacingOnTopPlate_cut,self.topCutLineNumber,self.topCutLineNumber)
else : self.cutLine (tNet,layer,self.topCutLineDict["XMin"],self.topCutLineDict["YMin"],self.minWidth_topPlatecut,self.minheight_topPlatecut,self.minSpacingOnTopPlate_cut,self.topCutLineNumber,'vertical')
return
## Draws the routing layers of both bottom and top plates after computing widths and the exact position of these layers. Also computes positions if rlayers that are crucual for routing. this of putting it in a second function
def drawRoutingLayers( self, bottomPlateLayer, topPlateLayer, tNet, bNet ):
Vertical.create ( tNet, topPlateLayer, self.topPlateRLayerDict["XCenter"], self.topPlateRLayerDict["width"], self.topPlateRLayerDict["YMin"], self.topPlateRLayerDict["YMax"] )
cutLinesXMins = [ self.cutLeftLineDict["XMin"], self.cutRightLineDict["XMin"] ]
for i in range(2):
Vertical.create ( bNet, bottomPlateLayer, cutLinesXMins[i] , self.bottomPlateRLayerDict["width"], self.bottomPlateRLayerDict["YMin"], self.bottomPlateRLayerDict["YMax"] )
return
## Computes the maximal number of cuts to be placed on a layer of width \c width_layer considering specifications such as the spacing between the cuts, its width and its enclosure in the layer.
def cutMaxNumber( self, width_layer, width_cut, spacing_cut, enclosure_cut ):
cutNumber = int( (width_layer - 2*enclosure_cut + spacing_cut) / (width_cut + spacing_cut) )
if cutNumber > 0 :
return cutNumber
else : raise Error (1,"cutMaxNumber() : Zero number of cuts found. Layer width is too tight." )
## Creates a horizontal or vertical line of contacts according to the specified direction.
def cutLine( self, net, layer, firstCutXCenter, firstCutYCenter, width_cut, height_cut, spacing_cut, cutNumber, direction ):
for i in range( cutNumber) :
segment = Contact.create( net, layer, firstCutXCenter + i*(width_cut + spacing_cut), firstCutYCenter, width_cut, height_cut ) if direction == 'horizontal' else Contact.create( net, layer, firstCutXCenter, firstCutYCenter + i*(height_cut + spacing_cut), width_cut, height_cut )
return segment
## Creates a matrix of cuts by vertically stacking horizontal lines of identical cuts.
#
# \param net net to which the cuts belong
# \param layer cuts physical layer
# \param firstCutXCenter center's abcissa of the bottom left cut ( that is the first cut to be drawn in the matrix )
# \param firstCutYCenter center's abcissa of the bottom left cut
# \param (width_cut,height_cut,spacing_cut) cuts dimenions
# \param (cutColumnNumber,cutRowNumber) matrix dimensions
#
# \remarks The matrix can have any dimensions zero or negative one.
def cutMatrix( self, net, layer, firstCutXCenter, firstCutYCenter, width_cut, height_cut, spacing_cut, cutColumnNumber, cutRowNumber ):
for i in range( cutRowNumber):
matrix = self.cutLine( net, layer, firstCutXCenter, firstCutYCenter + i*(spacing_cut + width_cut), width_cut, height_cut, spacing_cut, cutColumnNumber, 'horizontal' )
return matrix
## \return the ordinate of the bottom plate's highest end-point ( that is equivalent to \c dySource of the bottom plate's box ) .
def getBottomPlateYMax ( self ) : return self.bottomPlateBoxDict["YMin"] + self.bottomPlateBoxDict["height"]
## \return the abcissa of the bottom plate's left line of cuts.
def getBottomPlateLeftCutXMin ( self ) : return self.cutLeftLineDict ["XMin" ]
## \return the ordinate of the first ( or bottom) cut in the left line of cuts on the bottom plate.
def getBottomPlateLeftCutYMin ( self ) : return self.cutLeftLineDict ["YMin" ]
## \return the ordinate of the highest cut of the bottom plate's left line of cuts.
def getBottomPlateLeftCutYMax ( self ) : return self.cutLeftLineDict ["YMin" ] + ( self.topCutLineNumber - 1 )*( self.minSpacingOnBotPlate_cut + self.minWidth_botPlatecut )
## \return the absissa of the bottom plate's right line of cuts.
def getBottomPlateRightCutXMin ( self ) : return self.cutRightLineDict ["XMin" ]
## \return the ordinate of the first ( or bottom) cut in the right line of cuts on the bottom plate.
def getBottomPlateRightCutYMin ( self ) : return self.cutRightLineDict ["YMin" ]
## \return the ordinate of the highest ( or top) cut in the right line of cuts on the bottom plate.
def getBottomPlateRightCutYMax ( self ) : return self.cutRightLineDict ["YMin" ] + ( self.bottomCutLineNumber - 1 )*( self.minSpacingOnBotPlate_cut + self.minWidth_botPlatecut )
## \return the center's ordinate of the bottom plate's left cut (the cut that is the first one in the line).
def getBotPlateLeftRLayerXMax ( self ) : return self.bottomPlateRLayerDict["left" ]["XMax" ]
## \return the position of the bottom plate's right cuts on the horitontal axis (also applicable to left cuts).
def getBottomPlateRightCutYCenter (self ) : return (self.getBottomPlateRightCutYMax() - self.getBottomPlateRightCutYMin())/2
## \return the position of the bottom plate's right cuts on the horitontal axis.
def getBotPlateRightRLayerXMin ( self ) : return self.bottomPlateRLayerDict ["right" ]["XMin" ]
## \return the position of the bottom plate's left cuts on the horitontal axis.
def getBotPlateLeftRLayerXMin ( self ) : return self.bottomPlateRLayerDict ["left" ]["XMin" ]
## \return the position of bottom plate's left cuts on the horitontal axis.
def getBotPlateRLayerYMin ( self ) : return self.bottomPlateRLayerDict ["YMin" ]
## \return the position of bottom plate's left cuts on the horitontal axis.
def getBotPlateRLayerYMax ( self ) : return self.bottomPlateRLayerDict ["YMax" ]
## \return the position of bottom plate's left cuts on the horitontal axis.
def getBotPlateRLayerWidth ( self ) : return self.bottomPlateRLayerDict ["width" ]
## \return the position of bottom plate's left cuts on the horitontal axis.
def getBotPlateRightRLayerXCenter ( self ) : return self.cutRightLineDict ["XMin" ]
## \return the position of bottom plate's left cuts on the horitontal axis.
def getBotPlateLeftRLayerXCenter ( self ) : return self.cutLeftLineDict ["XMin" ]
## \return the ordinate of the bottom end points of the top plate routing layer.
def getTopPlateRLayerYMin ( self ) : return self.topPlateRLayerDict ["YMin" ]
## \return the ordinate of the higher end points of the top plate routing layer.
def getTopPlateRLayerYMax ( self ) : return self.topPlateRLayerDict ["YMax" ]
## \return the width of top plate's routing layer.
def getTopPlateRLayerWidth ( self ) : return self.topPlateRLayerDict ["width" ]
## \return the center's abcissa of the bottom plate routing layer.
def getTopPlateRLayerXCenter ( self ) : return self.topPlateRLayerDict ["XCenter"]
## \return the origin (bottom-left end point) abcissa of the top plate routing layers.
def getTopPlateRLayerXMin ( self ) : return self.topPlateRLayerDict ["XCenter"] - self.topPlateRLayerDict ["width"]/2
## \return the abscissa of the bottom-right end-point of the top plate routing layer.
def getTopPlateRLayerXMax ( self ) : return self.topPlateRLayerDict ["XCenter"] + self.topPlateRLayerDict ["width"]/2
def ScriptMain( **kw ):
editor = None
if kw.has_key('editor') and kw['editor']:
editor = kw['editor']
UpdateSession.open()
device = AllianceFramework.get().createCell( 'capacitor' )
device.setTerminal( True )
bottomPlate_net = Net.create( device, 'bNet' )
bottomPlate_net.setExternal( True )
bNet = device.getNet("bNet")
topPlate_net = Net.create( device, 'tNet' )
topPlate_net.setExternal( True )
tNet = device.getNet("tNet")
if editor:
UpdateSession.close( )
editor.setCell ( device )
editor.fit ( )
UpdateSession.open ( )
capacitor = CapacitorUnit ( device,500, 'MIMCap', [0,0] ) # 129.56
surface = capacitor.create( bNet, tNet )
print(surface)
AllianceFramework.get().saveCell( device, Catalog.State.Views )
return True

View File

@ -0,0 +1,438 @@
#!/usr/bin/python
import sys
from Hurricane import *
from CRL import *
import helpers
from helpers.io import ErrorMessage as Error
from helpers import trace
import oroshi
from CapacitorUnit import CapacitorUnit
from CapacitorMatrix import CapacitorStack
from collections import OrderedDict
import numpy
## Routs two matched capacitors, C1 and C2, drawn in a capacitor matrix. Connections are put in place with reference to a given matching scheme. Elementary capacitor units are connected to horizontal and vertical routeing tracks that represent top plates and bottom plates nets of C1 and C2 . Supported types of capacitors are Poly-Poly and Metal-Metal. Technologycal rules are provided by 350 nm AMS CMOS technology with three-four metal layers. Metal layers that are used for routeing are placed similarly to horziontal-vertical (HV) symbolic Alliance CAD tool routeer, where horizontal metal channels are drawn in metal 2 and the vertical ones are in metal 3. Given a matrix of dimensions \f$ R*C \f$, the total number of vertical tracks is \f$ 2C+2 \f$ equivalent to \f$ C+1 \f$ couples, ensuring that every elementary capacitor is positioned between four vertical tracks, two from each side. In fact, every adjacent couple of these tracks represent top plates and bottom plates of C1 or C2 as shown in Figure 1.
# \image html Layout.png "Layout" width=.1\linewidth
# An elementary capacitor unit can be a part of C1 or C2 according to the matching scheme. However, to respect common-centroid layout specifications, for C1 and C2 to be equal, the matrix number of colums and number of rows must be both even. Addionnally, the number of elementary capacitors dedicated to C1 must be equal to those dedicated to C2. These two conditions are tested in one of the class methods. An exception is raised if at least one of the two is not respected.
class VerticalRoutingTracks( CapacitorUnit, CapacitorStack ):
rules = oroshi.getRules()
def __init__( self, capacitorInstance, capacitor, minimizeVRT = False ) :
self.device = capacitorInstance.device
self.capacitorInstance = capacitorInstance
self.capacitor = capacitor
self.matchingScheme = capacitorInstance.matchingScheme
self.capacitorType = capacitorInstance.capacitorType
self.abutmentBox = capacitorInstance.abutmentBox
self.matrixDim = self.capacitorInstance.matrixDim
self.nets = capacitorInstance.nets
self.capacitorsNumber = capacitorInstance.capacitorsNumber
self.dummyRing = capacitorInstance.dummyRing
self.dummyElement = capacitorInstance.dummyElement
print('capacitorInstance.capacitance',capacitorInstance.capacitance)
self.capacitorIds = range(0,self.capacitorsNumber)
self.abutmentBox_spacing = capacitorInstance.abutmentBox_spacing
self.vRoutingTrack_width = self.capacitorInstance.vRoutingTrack_width
self.vRoutingTrackXCenter = []
self.vRoutingTrackDict = {}
self.minimizeVRT = minimizeVRT
self.vRTsToEliminate = []
self.vRTsDistribution = []
self.platesDistribution = []
return
## Sets vertical stretching value considering spacing between elementary capacitors in the matrix.
# \return stratching value.
def __setStretching__( self ): return self.minSpacing_botPlate + self.abutmentBox_spacing/2
## Defines technology rules used to draw the layout. Some of the rules, namely those describing routeing layers and tracks are applicable for both MIM and PIP capacitors. However, cuts rules are different. \remark All \c CapacitorStack class rules are also reloaded in this class. An exception is raised if the entered capacitor type is unsupported.
# \return a dictionary with rules labels as keys and rules content as values.
def setRules ( self ):
CapacitorStack.setRules ( self )
CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingTrackCut" , VerticalRoutingTracks.rules.minWidth_cut2 )
CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingLayer_vRoutingTrack_cut" , VerticalRoutingTracks.rules.minWidth_cut2 )
CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingTrack" , VerticalRoutingTracks.rules.minWidth_metal2 )
CapacitorUnit.__setattr__ ( self, "minEnclosure_hRoutingLayer_vRoutingTrack_cut" , VerticalRoutingTracks.rules.minEnclosure_metal2_cut2 )
CapacitorUnit.__setattr__ ( self, "minEnclosure_hRoutingTrackCut" , VerticalRoutingTracks.rules.minEnclosure_metal2_cut2 )
CapacitorUnit.__setattr__ ( self, "minWidth_hRoutingLayer" , VerticalRoutingTracks.rules.minWidth_metal2 )
CapacitorUnit.__setattr__ ( self, "minSpacing_hRoutingTrack" , VerticalRoutingTracks.rules.minSpacing_metbot )
return
def create( self ):
UpdateSession.open ()
self.setRules ()
vRoutingTracksLayer = DataBase.getDB().getTechnology().getLayer("metal3" )
if self.capacitorInstance.doMatrix == True and self.capacitorsNumber > 1 :
self.minimizeVRTs()
self.computeVRTDimensions()
self.drawVRoutingTracks( vRoutingTracksLayer )
else : raise Error(1, 'create() : Impossible to route. This class only routes a matrix of two or more capacitors. Please use <routeCapacitorMatrix> class instead.')
UpdateSession.close ()
return
## Iteratively draws vertical routing tracks given the physical layer \c vRoutingTracksLayer. Every elementary capacitor is consequently positioned between four routing tracks, two from each side. Each couple of adjacent routeing tracks represent top plate and bottom plate nets of Ci, where i is in [1,2]. As given in Figure 2, capacitor \f$ C_{ij} \f$ with an even j value situated in even columns have and inversily for odd columns numbers.
def drawVRoutingTracks ( self, vRoutingTracksLayer ) :
netsDistribution = self.__setNetsDistribution__()
k = 0
print('netsDistribution',netsDistribution)
for j in range( 0, self.matrixDim["columns"] + 1 ):
for key in self.vRoutingTrackXCenter[j]:
if self.vRoutingTrackXCenter[j][key] != None:
Vertical.create( netsDistribution[j][k] , vRoutingTracksLayer , self.vRoutingTrackXCenter[j][key] , self.vRoutingTrack_width , self.vRoutingTrackDict["YMin"] , self.vRoutingTrackDict["YMax"] )
k = k + 1 if k < len(key)-1 else 0
return
def computeVRTDimensions( self ) :
self.hRoutingTrack_width = max( self.minWidth_hRoutingTrack, self.minWidth_hRoutingTrackCut + 2*self.minEnclosure_hRoutingTrackCut )
abutmentBoxXMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing) ["XMin"]
abutmentBoxYMin = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["YMin"]
abutmentBoxYMax = abutmentBoxYMin + self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["height"]
self.minimumPosition = abutmentBoxYMin - self.__setStretching__()
self.maximumPosition = abutmentBoxYMax + self.__setStretching__()
vRTsNumber = self.__computeVRTsNumber__()
print("vRTsNumber",vRTsNumber)
self.vRoutingTrackDict["YMin"] = self.minimumPosition - vRTsNumber*(self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
self.vRoutingTrackDict["YMax"] = self.maximumPosition + vRTsNumber*(self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
self.__setPlatesDistribution__()
self.computeXCenters()
return
def __computeVRTsNumber__ ( self ):
if self.dummyElement == True :
vRTsNumber = 2*self.capacitorsNumber - 1
else :
vRTsNumber = 2*self.capacitorsNumber + 1 if self.dummyRing == True else 2*self.capacitorsNumber
return vRTsNumber
def computeXCenters( self ):
unitCapDim = self.capacitorInstance.getCapDim()
abutmentBoxUnitCap_width = CapacitorUnit.computeAbutmentBoxDimensions( self, unitCapDim )["width"]
unitCapXMin = self.abutmentBox.getXMin() if self.dummyRing == False else self.abutmentBox.getXMin() + abutmentBoxUnitCap_width + self.capacitorInstance.abutmentBox_spacing
vRoutingTrack_spacing = self.capacitorInstance.minSpacing_vRoutingTrack
[ factor1 , factor2 ] = [ self.capacitorsNumber , self.capacitorsNumber-1 ] if ( self.capacitorsNumber % 2 == 0 ) else [ self.capacitorsNumber + 1 , self.capacitorsNumber ]
if self.vRTsToEliminate[0][0] == 1 :
self.vRoutingTrackXCenter.append( OrderedDict() )
self.vRoutingTrackXCenter[0][ self.platesDistribution[0][0] ] = unitCapXMin - factor1*vRoutingTrack_spacing - (factor2)*self.vRoutingTrack_width - self.vRoutingTrack_width/2
else :
self.vRoutingTrackXCenter.append( OrderedDict() )
self.vRoutingTrackXCenter[0][ self.platesDistribution[0][0] ] = None
leftVRTNumber = self.capacitorsNumber if ( self.capacitorsNumber % 2 == 0 ) else self.capacitorsNumber + 1
for k in range( 1, leftVRTNumber ):
self.vRoutingTrackXCenter[0][self.platesDistribution[0][k]] = unitCapXMin - (factor1-k)*vRoutingTrack_spacing -(factor2-k)*self.vRoutingTrack_width - self.vRoutingTrack_width/2 if self.vRTsToEliminate[0][k] == 1 else None
print('self.vRoutingTrackXCenter',self.vRoutingTrackXCenter)
for j in range( 1, self.matrixDim["columns"] + 1 ):
factor3 = j - 1 if self.dummyRing == False else j
unitCapXMin = self.abutmentBox.getXMin() + factor3*( abutmentBoxUnitCap_width + self.capacitorInstance.abutmentBox_spacing )
unitCapXMax = unitCapXMin + abutmentBoxUnitCap_width
if self.vRTsToEliminate[j][0] == 1:
self.vRoutingTrackXCenter.append( OrderedDict() )
self.vRoutingTrackXCenter[j][ self.platesDistribution[j][0] ] = unitCapXMax + vRoutingTrack_spacing + self.vRoutingTrack_width/2
else :
self.vRoutingTrackXCenter.append( OrderedDict() )
self.vRoutingTrackXCenter[j][ self.platesDistribution[j][0] ] = None
if self.capacitorsNumber % 2 == 0:
rightVRTNumber = self.capacitorsNumber
else :
if (j % 2 == 0) :
rightVRTNumber = self.capacitorsNumber + 1
else : rightVRTNumber = self.capacitorsNumber - 1 if self.dummyElement == False else self.capacitorsNumber - 2
for k in range( 1, rightVRTNumber ):
self.vRoutingTrackXCenter[j][ self.platesDistribution[j][k] ] = unitCapXMax + (k+1)*vRoutingTrack_spacing + (k)*self.vRoutingTrack_width + self.vRoutingTrack_width/2 if self.vRTsToEliminate[j][k] == 1 else None
print('self.vRoutingTrackXCenter',self.vRoutingTrackXCenter)
return
def __findUsedCapIdsPerColumn__( self ):
usedCapIdsPerColumn = []
for j in range(0, self.matrixDim["columns"] ):
usedCapIdsPerColumn.append( [self.matchingScheme[0][j]] )
for i in range(1, self.matrixDim["rows"] ):
usedCapIdsPerColumn[j].append( self.matchingScheme[i][j] )
usedCapIdsPerColumn[j] = numpy.unique(usedCapIdsPerColumn[j])
return usedCapIdsPerColumn
def __findCapIdsToEliminatePerColumn__( self, usedCapIdsPerColumn ):
capIdsToEliminatePerColumn = []
for j in range(0, len(usedCapIdsPerColumn) ):
if len(usedCapIdsPerColumn[j]) == self.capacitorsNumber:
capIdsToEliminatePerColumn.append( [None] )
else :
capIdsToEliminatePerColumn.append( list (set(usedCapIdsPerColumn[j])^set(self.capacitorIds) ) )
return capIdsToEliminatePerColumn
def __findCapIdsToEliminate__( self, capIdsToEliminatePerColumn ):
capIdsToEliminate = []
capIdsj = capIdsToEliminatePerColumn[0]
print('capIdsj',capIdsj)
sharedVRTIds = self.capacitorIds[0:self.capacitorsNumber/2] if self.capacitorsNumber % 2 == 0 else self.capacitorIds[0: int(self.capacitorsNumber/2+1)]
print('sharedVRTIds',sharedVRTIds)
intersection2 = list( set(capIdsj).intersection(set(sharedVRTIds)) )
capIdsToEliminate.append( [None] ) if intersection2 == [] else capIdsToEliminate.append( intersection2 )
for j in range(0, len(capIdsToEliminatePerColumn) ):
capIdsj = capIdsToEliminatePerColumn[j]
if (j % 2 == 0):
sharedVRTIds = self.capacitorIds[self.capacitorsNumber/2 : self.capacitorsNumber] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[int(self.capacitorsNumber/2+1) : self.capacitorsNumber]
else:
sharedVRTIds = self.capacitorIds[0:self.capacitorsNumber/2] if (self.capacitorsNumber % 2 == 0) else self.capacitorIds[0: int(self.capacitorsNumber/2+1)]
print('sharedVRTIds',sharedVRTIds)
if j == len(capIdsToEliminatePerColumn)-1:
intersection1 = list( set(capIdsj) )
else :
capIdsjp1 = capIdsToEliminatePerColumn[j+1]
intersection1 = list( set(capIdsj).intersection(set(capIdsjp1)) )
intersection2 = list( set(intersection1).intersection(set(sharedVRTIds)) )
capIdsToEliminate.append( [None] ) if intersection2 == [] else capIdsToEliminate.append( intersection2 )
return capIdsToEliminate
def __findVRTsToEliminate__( self, capIdsToEliminate ):
print('capIdsToEliminate',capIdsToEliminate)
for j in range( 0,len(self.vRTsDistribution) ) :
for k in range( 0,len(self.vRTsDistribution[j]) ) :
if k == 0 :
if self.vRTsDistribution[j][0] in capIdsToEliminate[j] :
self.vRTsToEliminate.append( [0] )
self.vRTsToEliminate[j].append( 0 )
else :
self.vRTsToEliminate.append( [1] )
self.vRTsToEliminate[j].append( 1 )
print('vRTsToEliminate',self.vRTsToEliminate)
else :
if self.vRTsDistribution[j][k] in capIdsToEliminate[j]:
[self.vRTsToEliminate[j].append( 0 ) for u in range(0,2)]
else :
[self.vRTsToEliminate[j].append( 1 ) for u in range(0,2)]
return
def minimizeVRTs( self ) :
self.__setVRTsDistribution__()
if self.minimizeVRT == False :
for j in range( 0, self.matrixDim["columns"]+1 ) :
self.vRTsToEliminate.append( [1] )
self.vRTsToEliminate[j].append( 1 )
for k in range( 0,len(self.vRTsDistribution[j]) ) :
[self.vRTsToEliminate[j].append( 1 ) for u in range(0,2)]
elif self.minimizeVRT == True :
usedCapIdsPerColumn = self.__findUsedCapIdsPerColumn__ ()
capIdsToEliminatePerColumn = self.__findCapIdsToEliminatePerColumn__(usedCapIdsPerColumn )
capIdsToEliminate = self.__findCapIdsToEliminate__ (capIdsToEliminatePerColumn)
self.__findVRTsToEliminate__ (capIdsToEliminate )
print("self.matchingScheme" ,self.matchingScheme)
print("usedCapIdsPerColumn" ,usedCapIdsPerColumn)
print("capIdsToEliminatePerColumn",capIdsToEliminatePerColumn)
print("capIdsToEliminate" ,capIdsToEliminate)
print('self.vRTsToEliminate' ,self.vRTsToEliminate)
else : raise Error(1,'minimizeVRTs() : ')
return
def __setVRTsDistribution__( self ):
element = [ self.capacitorIds[0:self.capacitorsNumber/2], self.capacitorIds[self.capacitorsNumber/2:self.capacitorsNumber] ] if self.capacitorsNumber % 2 == 0 else [ self.capacitorIds[0:int( self.capacitorsNumber/2 + 1 )], self.capacitorIds[int( self.capacitorsNumber/2 + 1 ):self.capacitorsNumber] ]
u = 0
for j in range(0,self.matrixDim["columns"]+1) :
self.vRTsDistribution.append( element[u] )
u = u+1 if u < 1 else 0
print('self.vRTsDistribution',self.vRTsDistribution)
return
def __setNetsDistribution__( self ):
netsList = self.nets[0:len(self.nets)-1] if self.dummyRing == True and self.dummyElement == False else self.nets
element = [ netsList[0:len(netsList)/2], netsList[len(netsList)/2:len(netsList)] ] if len(netsList) % 2 == 0 else [ netsList[0:int( len(netsList)/2 + 1 )], netsList[int( len(netsList)/2 + 1 ):len(netsList)] ]
u = 0
netsDistribution = []
for j in range(0,self.matrixDim["columns"]+1) :
netsDistribution.append( [element[u][0][0]] )
netsDistribution[j].append( element[u][0][1] )
for k in range(1,len(element[u])):
netsDistribution[j].append( element[u][k][0] )
netsDistribution[j].append( element[u][k][1] )
u = u+1 if u < 1 else 0
print('netsDistribution',netsDistribution)
return netsDistribution
def __setPlatesDistribution__( self ):
element = [ self.capacitorIds[0:self.capacitorsNumber/2], self.capacitorIds[self.capacitorsNumber/2:self.capacitorsNumber] ] if self.capacitorsNumber % 2 == 0 else [ self.capacitorIds[0:int( self.capacitorsNumber/2 + 1 )], self.capacitorIds[int( self.capacitorsNumber/2 + 1 ):self.capacitorsNumber] ]
u = 0
for j in range(0,self.matrixDim["columns"]+1) :
print("j",j)
self.platesDistribution.append( ['t' + str(element[u][0])] )
print('self.platesDistribution',self.platesDistribution)
if self.dummyElement == False or self.dummyElement == True and j % 2 == 0 and len(element[u]) > 1 :
print("jif",j)
self.platesDistribution[j].append( 'b' + str(element[u][0]) )
for k in element[u][1:len(element[u])]:
print('k',k)
self.platesDistribution[j].append( 't' + str(k) )
print("jj",j)
if self.dummyElement == False or self.dummyElement == True and j % 2 == 0 or self.dummyElement == True and j % 2 != 0 and k != element[u][len(element[u])-1] :
self.platesDistribution[j].append( 'b' + str(k) )
u = u+1 if u < 1 else 0
print('self.platesDistribution',self.platesDistribution)
return
def gethRoutingTrack_width ( self ) : return self.hRoutingTrack_width
def getvRoutingTrackXCenter ( self ) : return self.vRoutingTrackXCenter
def ScriptMain( **kw ):
editor = None
if kw.has_key('editor') and kw['editor']:
editor = kw['editor']
UpdateSession.open()
Device = AllianceFramework.get().createCell( 'capacitor' )
Device.setTerminal( True )
bottomPlate_net0 = Net.create( Device, 'b0' )
bottomPlate_net1 = Net.create( Device, 'b1' )
bottomPlate_net2 = Net.create( Device, 'b2' )
bottomPlate_net3 = Net.create( Device, 'b3' )
bottomPlate_net0.setExternal( True )
bottomPlate_net1.setExternal( True )
bottomPlate_net2.setExternal( True )
bottomPlate_net3.setExternal( True )
b0 = Device.getNet("b0")
b1 = Device.getNet("b1")
b2 = Device.getNet("b2")
b3 = Device.getNet("b3")
topPlate_net0 = Net.create( Device, 't0' )
topPlate_net1 = Net.create( Device, 't1' )
topPlate_net2 = Net.create( Device, 't2' )
topPlate_net3 = Net.create( Device, 't3' )
topPlate_net0.setExternal( True )
topPlate_net1.setExternal( True )
topPlate_net2.setExternal( True )
topPlate_net3.setExternal( True )
t0 = Device.getNet("t0")
t1 = Device.getNet("t1")
t2 = Device.getNet("t2")
t3 = Device.getNet("t3")
if editor:
UpdateSession.close()
editor.setCell( Device )
editor.fit()
UpdateSession.open()
nets = [[t0, b0] , [t1, b1] , [t2, b2] ] # [t3, b3] ]
#capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 93, matchingMode = True, matchingScheme = [ ['C2','C2','C2','C2'] , ['C1','C2','C2','C2'] , ['C1','C2','C2','C2'] , ['C1','C2','C2','C1'] ] )
capacitorInstance = CapacitorStack( Device, [372,1116], 'MIMCap', [0,0], nets,unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ [1,1,1,0] , [0,1,1,1] , [1,1,1,0] , [0,1,1,1]], dummyRing = True)
# capacitorInstance = CapacitorStack( Device, [372,1116], 'MIMCap', [0,0], nets,unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ [1,1,1,0] , [0,1,1,1] , [1,1,1,0] , [0,1,1,1] ], dummyRing = True)
# capacitorInstance = CapacitorStack( Device, [279], 'MIMCap', [0,0], nets, unitCap = 279 ) #, matrixDim = [4,4], matchingMode = True, matchingScheme = [ [1,1,1,0] , [0,1,2,1] , [1,1,1,0] , [2,1,1,1] ], dummyElement = True )#dummyRing = True)
# capacitorInstance = CapacitorStack( Device, [279,1023, 186], 'MIMCap', [0,0], nets, unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme = [ [1,1,1,0] , [0,1,2,1] , [1,1,1,0] , [2,1,1,1] ], dummyElement = True )#dummyRing = True)
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 93, matchingMode = True, matchingScheme = [ ['C2','C2','C1','C2'] , ['C1','C2','C2','C1'] , ['C1','C1','C2','C3'] , ['C1','C1','C2','C3'] ] )
# capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 93, matchingMode = True, matchingScheme = [ ['C1','C4','C1','C2'] , ['C1','C2','C4','C1'] , ['C3','C1','C4','C3'] , ['C3','C1','C2','C3'] ] )
capacitor = capacitorInstance.create( )
capWithVRT = VerticalRoutingTracks( capacitorInstance, capacitor, True ) # )
capWithVRT.create()
AllianceFramework.get().saveCell( Device, Catalog.State.Views )
return True

View File

@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-
from Hurricane import DataBase
from Hurricane import UpdateSession
from Hurricane import DbU
from Hurricane import Box
import helpers
import helpers.io
from helpers import trace
helpers.setTraceLevel( 1000 )
import Analog
import ParamsMatrix
import oroshi
from CapacitorUnit import CapacitorUnit
from CapacitorMatrix import CapacitorStack
from CapacitorVRTracks import VerticalRoutingTracks
from CapacitorRouted import RoutMatchedCapacitor
def toMatrixArgs ( matrix ):
valid = True
rows = matrix.getRows ()
columns = matrix.getColumns()
lol = []
for row in range(rows):
lol.append( [] )
for column in range(columns):
lol[-1].append( matrix.getValue(row,column) )
return [rows,columns], lol
def checkCoherency ( device, bbMode ):
message = 'CapacitorMatrix.checkCoherency():\n'
techno = DataBase.getDB().getTechnology()
rules = oroshi.getRules()
capacities = device.getParameter( 'capacities' )
if capacities is None:
message += ' Missing "capacities" parameter on %s' % str(device)
return (False, message)
pmatrix = device.getParameter( 'matrix' )
if pmatrix is None:
message += ' Missing "matrix" parameter on %s' % str(device)
return (False, message)
valid = True
if pmatrix:
rows = pmatrix.getRows ()
columns = pmatrix.getColumns()
for row in range(rows):
print ' [',
for column in range(columns):
capaIndex = pmatrix.getValue(row,column)
print '%2d' % capaIndex,
if capaIndex >= capacities.getCount():
valid = False
message += ' element [%d,%d] == %d is out of range, must be in [0..%d]\n' \
% (row,column,capaIndex,capacities.getCount()-1)
print ']'
if not valid: return (False, message)
return (True, "")
def layout ( device, bbMode ):
trace( 100, ',+', '\tCapacitorMatrix.layout() called.\n' )
paramsMatrix = ParamsMatrix.ParamsMatrix()
try:
capacities = device.getParameter( 'capacities' )
print str(device)
print 'Capacities = ', capacities
capValuesArg = []
vTrackNetsArg = []
for i in range(capacities.getCount()):
capValuesArg .append( capacities.getValue(i) )
vTrackNetsArg.append( [ device.getNet('t%d'%i), device.getNet("b%d"%i) ] )
matrixSizeArg, matchingSchemeArg = toMatrixArgs( device.getParameter('matrix') )
typeArg = 'UnknownType'
if device.isPIP(): typeArg = 'PIPCap'
if device.isMIM(): typeArg = 'MIMCap'
if device.isMOM(): typeArg = 'MOMCap'
capaGenerator = CapacitorStack( device
, capValuesArg
, typeArg
, matrixSizeArg
, vTrackNetsArg
, matrixDim =matrixSizeArg
, matchingMode =True
, matchingScheme=matchingSchemeArg
, dummyRing =False
)
capaMatrix = capaGenerator.create()
capaTracks = VerticalRoutingTracks( capaGenerator, capaMatrix, True )
capaTracks.create()
capaRouted = RoutMatchedCapacitor( capaTracks )
capaRouted.route()
paramsMatrix.setGlobalCapacitorParams( device.getAbutmentBox() )
trace( 100, '++' )
#paramsMatrix.trace()
except Exception, e:
helpers.io.catch( e )
trace( 100, '---' )
return paramsMatrix.getMatrix()

View File

@ -46,12 +46,19 @@ class ParamsMatrix ( object ):
def getMatrix ( self ): return self.matrix
def setGlobalParams ( self, w, L, M, boundingBox ):
def setGlobalTransistorParams ( self, w, L, M, boundingBox ):
self.matrix[0][0]['L' ] = L
self.matrix[0][0]['W' ] = w
self.matrix[0][0]['M' ] = M
self.matrix[0][0]['box' ] = boundingBox
self.matrix[0][0]['globalActiveBox' ] = Box()
self.matrix[0][0]['family' ] = 'Transistor'
return
def setGlobalCapacitorParams ( self, boundingBox ):
self.matrix[0][0]['box' ] = boundingBox
self.matrix[0][0]['family' ] = 'Capacitor'
return

View File

@ -5,7 +5,8 @@ from helpers import trace
class Rules ( object ):
ruleSet = [ 'minEnclosure_nImplant_active'
ruleSet = [ 'minSpacing_nWell'
, 'minEnclosure_nImplant_active'
, 'minEnclosure_pImplant_active'
, 'minSpacing_nImplant_pImplant'
, 'minSpacing_cut0'
@ -14,6 +15,7 @@ class Rules ( object ):
, 'minEnclosure_active_cut0'
, 'transistorMinL'
, 'transistorMinW'
, 'minSpacing_poly'
, 'minGateSpacing_poly'
, 'minSpacing_poly_active'
, 'minExtension_active_poly'
@ -38,8 +40,37 @@ class Rules ( object ):
, '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'
, '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'
]
def __init__ ( self, dtr ):
trace( 100, '\tRules.__init__()\n' )
@ -54,8 +85,12 @@ class Rules ( object ):
#print 'Rules.addAttr(): %s' % attribute
value = None
words = attribute.split( '_' )
if len(words) == 1 and words[0].endswith('Cap'): value = self.dtr.getUnitRule( words[0] ).getValue()
if len(words) < 4: value = self.dtr.getPhysicalRule( *tuple(words) ).getValue()
try:
if len(words) == 1 and words[0].endswith('Cap'): value = self.dtr.getUnitRule( words[0] ).getValue()
elif len(words) < 4: value = self.dtr.getPhysicalRule( *tuple(words) ).getValue()
except Exception, e:
print e
if not value is None:
self.__dict__[attribute] = value

View File

@ -20,7 +20,6 @@ from helpers import trace
from Analog import Device
import oroshi
helpers.staticInitialization( quiet=True )
#helpers.setTraceLevel( 100 )
def traceMT ( mt ):

View File

@ -84,11 +84,11 @@ def layout ( device, bbMode ):
stack.doLayout ( bbMode )
paramsMatrix = ParamsMatrix.ParamsMatrix()
paramsMatrix.setGlobalParams( oroshi.toUnity(stack.w)
, oroshi.toUnity(stack.L)
, device.getM()
, stack.boundingBox
)
paramsMatrix.setGlobalTransistorParams( oroshi.toUnity(stack.w)
, oroshi.toUnity(stack.L)
, device.getM()
, stack.boundingBox
)
paramsMatrix.setStacks( [ stack ] )
trace( 100, '++' )
paramsMatrix.trace()

View File

@ -87,11 +87,11 @@ def layout ( device, bbMode ):
stack.doLayout ( bbMode )
paramsMatrix = ParamsMatrix.ParamsMatrix()
paramsMatrix.setGlobalParams( oroshi.toUnity(stack.w)
, oroshi.toUnity(stack.L)
, device.getM()
, stack.boundingBox
)
paramsMatrix.setGlobalTransistorParams( oroshi.toUnity(stack.w)
, oroshi.toUnity(stack.L)
, device.getM()
, stack.boundingBox
)
paramsMatrix.setStacks( [ stack ] )
trace( 100, '++' )
paramsMatrix.trace()

View File

@ -69,11 +69,11 @@ def layout ( device, bbMode ):
stack.setWirings( wirings.format( **diffMap ) )
stack.doLayout ( bbMode )
paramsMatrix.setGlobalParams( oroshi.toUnity(stack.w)
, oroshi.toUnity(stack.L)
, device.getM()
, stack.boundingBox
)
paramsMatrix.setGlobalTransistorParams( oroshi.toUnity(stack.w)
, oroshi.toUnity(stack.L)
, device.getM()
, stack.boundingBox
)
paramsMatrix.setStacks( [ stack ] )
trace( 100, '++' )
paramsMatrix.trace()