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:
parent
ef0f6f771a
commit
8035b31f27
|
@ -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() );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,18 +120,6 @@ 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;
|
||||
|
@ -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() );
|
||||
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();
|
||||
|
||||
shared_ptr<LayoutGenerator> layoutGenerator ( new LayoutGenerator() );
|
||||
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()
|
||||
|
|
|
@ -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
|
||||
, 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);
|
||||
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()
|
||||
);
|
||||
}
|
||||
|
||||
for ( int i = 0; i < count; ++i ) {
|
||||
tf->setNfing( start + i*step );
|
||||
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;
|
||||
nodeset->push_back( DBoxSet::create( device, stepRange->getIndex(), rg ) );
|
||||
|
||||
float h = dev->getAbutmentBox().getHeight();
|
||||
float w = dev->getAbutmentBox().getWidth();
|
||||
|
||||
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
|
||||
) );
|
||||
stepRange->progress();
|
||||
} while ( stepRange->isValid() );
|
||||
} else {
|
||||
nodeset->push_back( DBoxSet::create( dev->getAbutmentBox().getHeight()
|
||||
, dev->getAbutmentBox().getWidth()
|
||||
, start + i*step
|
||||
) );
|
||||
}
|
||||
MultiCapacitor* mcapacitor = dynamic_cast<MultiCapacitor *>( cell );
|
||||
MatrixParameterRange* matrixRange = dynamic_cast<MatrixParameterRange*>( nodeset->getRange() );
|
||||
|
||||
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()
|
||||
);
|
||||
|
||||
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 {
|
||||
//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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
nodeset->push_back( DBoxSet::create( ceil(h/h2pitch)*h2pitch
|
||||
, ceil(w/v2pitch)*v2pitch
|
||||
) );
|
||||
} 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;
|
||||
}
|
||||
|
|
|
@ -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.
|
|
@ -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,13 +81,16 @@ 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( 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 );
|
||||
|
||||
|
@ -93,6 +102,12 @@ 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 );
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "hurricane/analog/PyDevice.h"
|
||||
#include "crlcore/PyRoutingGauge.h"
|
||||
#include "bora/PyDSlicingNode.h"
|
||||
#include "bora/PyStepParameterRange.h"
|
||||
|
||||
|
||||
namespace Bora {
|
||||
|
@ -56,37 +57,37 @@ extern "C" {
|
|||
PyObject* pyInstance = NULL;
|
||||
PyObject* pyCell = NULL;
|
||||
PyObject* pyRoutingGauge = NULL;
|
||||
double start = 0.0;
|
||||
double step = 0.0;
|
||||
double count = 0.0;
|
||||
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() );
|
||||
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
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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;
|
||||
|
|
|
@ -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,21 +187,22 @@ 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;
|
||||
size_t _index;
|
||||
static int _count;
|
||||
static int _countAll;
|
||||
};
|
||||
|
@ -201,7 +210,8 @@ namespace Bora {
|
|||
|
||||
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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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* );
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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' ),
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
@ -136,8 +106,6 @@ namespace Analog {
|
|||
{
|
||||
if (_device == NULL) return false;
|
||||
|
||||
//checkScript();
|
||||
|
||||
cdebug_log(500,0) << "LayoutGenerator::drawLayout() " << _device->getDeviceName() << endl;
|
||||
|
||||
_device->destroyLayout();
|
||||
|
@ -146,7 +114,7 @@ namespace Analog {
|
|||
|
||||
if (not _script->getUserModule()) {
|
||||
finalize( ShowTimeTag );
|
||||
cerr << Error( "LayoutGenerator::drawLayout(): Couldn't load module <%s>"
|
||||
cerr << Error( "LayoutGenerator::drawLayout(): Couldn't load module \"%s\"."
|
||||
, _script->getUserModuleName().c_str() ) << endl;
|
||||
return false;
|
||||
}
|
||||
|
@ -159,29 +127,13 @@ namespace Analog {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (not callCheckCoherency(pyArgs,ShowError)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (not callLayout(pyArgs)) {
|
||||
cerr << "Layout failed" << endl; cerr.flush();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Eric passed by here
|
||||
//cerr << "Python driven Layout successfully drawn." << endl;
|
||||
if (not callCheckCoherency(pyArgs,ShowError)) return false;
|
||||
if (not callLayout (pyArgs) ) return false;
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
|
@ -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,53 +240,68 @@ namespace Analog {
|
|||
|
||||
Box LayoutGenerator::getDeviceBox ()
|
||||
{
|
||||
PyObject* pBox = getParamValue(getDic(getRow(0), 0), "box");
|
||||
if (pBox == NULL) {
|
||||
PyObject* pyBox = getParamValue(getDic(getRow(0), 0), "box");
|
||||
if (not pyBox) {
|
||||
finalize( NoFlags );
|
||||
popError("Layout function did not returned a valid device box 2!");
|
||||
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) {
|
||||
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 );
|
||||
popError("Layout function did not returned a valid active box 2!");
|
||||
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))){
|
||||
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))){
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ namespace Analog {
|
|||
|
||||
MetaCapacitor::MetaCapacitor ( Library* library, const Name& name )
|
||||
: Super(library,name)
|
||||
, _plate1(NULL)
|
||||
, _plate2(NULL)
|
||||
, _topPlate(NULL)
|
||||
, _botPlate(NULL)
|
||||
, _ce (0.0)
|
||||
{ }
|
||||
|
||||
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
for ( size_t i=0 ; i<_count ; ++i ) {
|
||||
string topPlateName = "t" + getString(i);
|
||||
string botPlateName = "b" + getString(i);
|
||||
string mcName = "c" + getString(i);
|
||||
|
||||
Net* p2 = Net::create( this, Name("P2") );
|
||||
p2->setExternal( true );
|
||||
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 );
|
||||
|
||||
_metaCapacitor = MetaCapacitor::create( getSubDevicesLibrary(), Name("C1") );
|
||||
Instance* metaCapacitorIns = Instance::create( this, Name("C1Instance"), _metaCapacitor );
|
||||
setReferenceCapacitor( _metaCapacitor );
|
||||
topPlate->setExternal( true );
|
||||
botPlate->setExternal( true );
|
||||
|
||||
Plug* mcC1Plug = metaCapacitorIns->getPlug( _metaCapacitor->getPlate1() );
|
||||
mcC1Plug->setNet( p1 );
|
||||
Plug* mcC2Plug = metaCapacitorIns->getPlug( _metaCapacitor->getPlate2() );
|
||||
mcC2Plug->setNet( p2 );
|
||||
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.
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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.
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 void resize ( size_t rows, size_t columns );
|
||||
inline Matrix& makeEmpty ();
|
||||
private:
|
||||
size_t _rows;
|
||||
size_t _columns;
|
||||
|
@ -41,6 +44,10 @@ namespace Analog {
|
|||
inline Matrix::Matrix ( size_t rows, size_t columns )
|
||||
: _rows(rows), _columns(columns), _table(NULL)
|
||||
{
|
||||
if (empty()) {
|
||||
_rows = 0;
|
||||
_columns = 0;
|
||||
} else
|
||||
_table = new size_t [ _rows * _columns ];
|
||||
}
|
||||
|
||||
|
@ -72,6 +79,30 @@ namespace Analog {
|
|||
}
|
||||
|
||||
|
||||
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) ]; }
|
||||
|
|
|
@ -30,6 +30,8 @@ namespace Analog {
|
|||
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 void setMatrix ( const Matrix* );
|
||||
inline void resize ( size_t rows, size_t columns );
|
||||
private:
|
||||
Matrix _matrix;
|
||||
};
|
||||
|
@ -44,6 +46,8 @@ namespace Analog {
|
|||
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 void MatrixParameter::resize ( size_t rows, size_t columns ) { _matrix.resize(rows,columns); }
|
||||
inline void MatrixParameter::setMatrix ( const Matrix* from ) { _matrix = *from; }
|
||||
|
||||
|
||||
} // Analog namespace.
|
||||
|
|
|
@ -30,23 +30,23 @@ 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 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; }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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 ); }
|
||||
|
|
|
@ -520,6 +520,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())
|
||||
throw Error( "Technology::getPhysicalRule(): No rules for %s."
|
||||
|
|
|
@ -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; \
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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,19 +249,30 @@ 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 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) ])
|
||||
|
@ -258,6 +304,20 @@ class AnalogDesign ( object ):
|
|||
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
|
||||
|
||||
def checkDSpecDigital ( self, count, dspec ):
|
||||
|
@ -310,6 +370,7 @@ class AnalogDesign ( object ):
|
|||
self.checkDSpec( count, dspec )
|
||||
|
||||
trace( 110, '\tBuilding \"%s\"\n' % dspec[1] )
|
||||
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]) )
|
||||
|
@ -324,6 +385,21 @@ class AnalogDesign ( object ):
|
|||
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()
|
||||
instance = Instance.create( self.cell
|
||||
|
@ -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 )
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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,7 +40,36 @@ 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 ):
|
||||
|
@ -54,8 +85,12 @@ class Rules ( object ):
|
|||
#print 'Rules.addAttr(): %s' % attribute
|
||||
value = None
|
||||
words = attribute.split( '_' )
|
||||
try:
|
||||
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()
|
||||
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
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ from helpers import trace
|
|||
from Analog import Device
|
||||
import oroshi
|
||||
|
||||
helpers.staticInitialization( quiet=True )
|
||||
#helpers.setTraceLevel( 100 )
|
||||
|
||||
def traceMT ( mt ):
|
||||
|
|
|
@ -84,7 +84,7 @@ def layout ( device, bbMode ):
|
|||
stack.doLayout ( bbMode )
|
||||
|
||||
paramsMatrix = ParamsMatrix.ParamsMatrix()
|
||||
paramsMatrix.setGlobalParams( oroshi.toUnity(stack.w)
|
||||
paramsMatrix.setGlobalTransistorParams( oroshi.toUnity(stack.w)
|
||||
, oroshi.toUnity(stack.L)
|
||||
, device.getM()
|
||||
, stack.boundingBox
|
||||
|
|
|
@ -87,7 +87,7 @@ def layout ( device, bbMode ):
|
|||
stack.doLayout ( bbMode )
|
||||
|
||||
paramsMatrix = ParamsMatrix.ParamsMatrix()
|
||||
paramsMatrix.setGlobalParams( oroshi.toUnity(stack.w)
|
||||
paramsMatrix.setGlobalTransistorParams( oroshi.toUnity(stack.w)
|
||||
, oroshi.toUnity(stack.L)
|
||||
, device.getM()
|
||||
, stack.boundingBox
|
||||
|
|
|
@ -69,7 +69,7 @@ def layout ( device, bbMode ):
|
|||
stack.setWirings( wirings.format( **diffMap ) )
|
||||
stack.doLayout ( bbMode )
|
||||
|
||||
paramsMatrix.setGlobalParams( oroshi.toUnity(stack.w)
|
||||
paramsMatrix.setGlobalTransistorParams( oroshi.toUnity(stack.w)
|
||||
, oroshi.toUnity(stack.L)
|
||||
, device.getM()
|
||||
, stack.boundingBox
|
||||
|
|
Loading…
Reference in New Issue