Added basic SPICE driver support.
The structure of the driver is copied from the Vhdl one. It is not integrated as a an AllianceFramework one but as a standalone like GDS. For now use numerical indexes for electrical nodes but also support strings. The nets are ordereds in reverse alphabetical order, but a custom order can be defined, if we read the model from an external SPICE subckt (to be done). SPICE saving has also been added to the cumulus/rsave plugin and the block/chip P&R one.
This commit is contained in:
parent
eeda81f746
commit
51ca8ab4af
|
@ -20,7 +20,7 @@
|
|||
${CRLCORE_SOURCE_DIR}/src/ccore/ispd04
|
||||
${CRLCORE_SOURCE_DIR}/src/ccore/ispd05
|
||||
${CRLCORE_SOURCE_DIR}/src/ccore/iccad04
|
||||
#${CRLCORE_SOURCE_DIR}/src/ccore/cspice
|
||||
${CRLCORE_SOURCE_DIR}/src/ccore/spice
|
||||
${CRLCORE_SOURCE_DIR}/src/ccore/lefdef
|
||||
${CRLCORE_SOURCE_DIR}/src/ccore/blif
|
||||
${CRLCORE_SOURCE_DIR}/src/ccore/alliance/ap
|
||||
|
@ -105,10 +105,11 @@
|
|||
ToolEngine.cpp
|
||||
GraphicToolEngine.cpp
|
||||
)
|
||||
#set ( spice_cpps spice/SpiceParser.cpp
|
||||
# spice/SpiceDriver.cpp
|
||||
# spice/Spice.cpp
|
||||
# )
|
||||
set ( spice_cpps spice/SpiceBit.cpp
|
||||
spice/SpiceEntity.cpp
|
||||
spice/SpiceParser.cpp
|
||||
spice/SpiceDriver.cpp
|
||||
)
|
||||
set ( bookshelf_cpps bookshelf/BookshelfParser.cpp
|
||||
bookshelf/BookshelfDriver.cpp
|
||||
)
|
||||
|
@ -296,7 +297,7 @@
|
|||
${ispd04_cpps}
|
||||
${ispd05_cpps}
|
||||
${blif_cpps}
|
||||
#${spice_cpps}
|
||||
${spice_cpps}
|
||||
${lefdef_cpps}
|
||||
${openaccess_cpps}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) SU/LIP6 2021-2021, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | S P I C E / Hurricane Interface |
|
||||
// | |
|
||||
// | Author : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Header : "./crlcore/Spice.h" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace Hurricane {
|
||||
class Cell;
|
||||
class Library;
|
||||
}
|
||||
|
||||
|
||||
namespace CRL {
|
||||
|
||||
using Hurricane::Cell;
|
||||
using Hurricane::Library;
|
||||
|
||||
|
||||
class Spice {
|
||||
public:
|
||||
static bool save ( Cell* );
|
||||
static bool load ( Library*, std::string spicePath );
|
||||
static void clearProperties ();
|
||||
};
|
||||
|
||||
|
||||
} // CRL namespace.
|
|
@ -0,0 +1,144 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) SU 2021-2021, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | S P I C E / Hurricane Interface |
|
||||
// | |
|
||||
// | Author : Jean-Paul Chaput |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Header : "./crlcore/SpiceBit.h" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include "hurricane/Name.h"
|
||||
#include "hurricane/Property.h"
|
||||
#include "hurricane/Slot.h"
|
||||
#include "hurricane/Net.h"
|
||||
|
||||
|
||||
namespace Spice {
|
||||
|
||||
using Hurricane::Record;
|
||||
using Hurricane::Name;
|
||||
using Hurricane::DBo;
|
||||
using Hurricane::Net;
|
||||
using Hurricane::PrivateProperty;
|
||||
class BitProperty;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "::Bit" (declaration).
|
||||
|
||||
class Bit {
|
||||
public:
|
||||
static const size_t nindex;
|
||||
public:
|
||||
Bit ( BitProperty*, const Net*, size_t index, std::string name="" );
|
||||
Bit ( size_t index, std::string name="" );
|
||||
~Bit ();
|
||||
bool isExternal () const;
|
||||
inline BitProperty* getProperty () const;
|
||||
inline const Net* getNet () const;
|
||||
inline std::string getName () const;
|
||||
size_t getIndex () const;
|
||||
inline void destroy ();
|
||||
std::string _getString () const;
|
||||
Record* _getRecord () const;
|
||||
private:
|
||||
static ptrdiff_t _offset;
|
||||
size_t _index;
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
|
||||
inline std::string Bit::getName () const { return _name; }
|
||||
|
||||
|
||||
typedef std::vector<Bit*> BitVector;
|
||||
|
||||
|
||||
struct GreaterBitByIndex {
|
||||
inline bool operator() ( const Bit* lhs, const Bit* rhs ) const
|
||||
{ return lhs->getIndex() > rhs->getIndex(); }
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Spice::BitProperty".
|
||||
|
||||
class BitProperty : public Hurricane::PrivateProperty {
|
||||
friend class BitExtension;
|
||||
public:
|
||||
static Name _name;
|
||||
public:
|
||||
static BitProperty* create ( Net* owner, size_t index );
|
||||
static Name getPropertyName ();
|
||||
virtual Name getName () const;
|
||||
inline Bit* getBit ();
|
||||
inline std::string getBitName () const;
|
||||
virtual void onReleasedBy ( DBo* owner );
|
||||
virtual std::string _getTypeName () const;
|
||||
virtual std::string _getString () const;
|
||||
virtual Record* _getRecord () const;
|
||||
protected:
|
||||
// Attributes.
|
||||
Bit _bit;
|
||||
protected:
|
||||
// Constructor.
|
||||
inline BitProperty ( Net* owner, size_t );
|
||||
};
|
||||
|
||||
|
||||
inline BitProperty::BitProperty ( Net* owner, size_t index )
|
||||
: PrivateProperty(), _bit(this,owner,index)
|
||||
{ }
|
||||
|
||||
inline Bit* BitProperty::getBit () { return &_bit; }
|
||||
inline std::string BitProperty::getBitName () const { return _bit.getName(); }
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Spice::BitExtension".
|
||||
|
||||
class BitExtension {
|
||||
public:
|
||||
static inline size_t getIndex ( const Net* );
|
||||
static inline std::string getName ( const Net* );
|
||||
static Bit* get ( const Net* );
|
||||
static Bit* create ( Net*, size_t index=Bit::nindex );
|
||||
private:
|
||||
static const Net* _owner;
|
||||
static Bit* _cache;
|
||||
};
|
||||
|
||||
|
||||
inline size_t BitExtension::getIndex ( const Net* net )
|
||||
{
|
||||
Bit* bit = get( net );
|
||||
return (bit == NULL) ? false : bit->getIndex();
|
||||
}
|
||||
|
||||
|
||||
inline std::string BitExtension::getName ( const Net* net )
|
||||
{
|
||||
Bit* bit = get( net );
|
||||
return (bit == NULL) ? "?" : bit->getName();
|
||||
}
|
||||
|
||||
|
||||
inline BitProperty* Bit::getProperty () const { return (BitProperty*)((ptrdiff_t)(this) - _offset); }
|
||||
inline const Net* Bit::getNet () const { return (const Net*)getProperty()->getOwner(); }
|
||||
inline void Bit::destroy () { ((Net*)getProperty()->getOwner())->remove( getProperty() ); }
|
||||
|
||||
|
||||
} // Spice Namespace.
|
||||
|
||||
|
||||
INSPECTOR_P_SUPPORT(Spice::Bit);
|
|
@ -0,0 +1,129 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) SU 2021-2021, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | S P I C E / Hurricane Interface |
|
||||
// | |
|
||||
// | Author : Jean-Paul Chaput |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Header : "./crlcore/SpiceEntity.h" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "hurricane/Name.h"
|
||||
#include "hurricane/Property.h"
|
||||
#include "hurricane/Slot.h"
|
||||
namespace Hurricane {
|
||||
class Net;
|
||||
class Instance;
|
||||
}
|
||||
#include "crlcore/ToolBox.h"
|
||||
#include "crlcore/SpiceBit.h"
|
||||
|
||||
|
||||
namespace Spice {
|
||||
|
||||
using std::ostream;
|
||||
using Hurricane::Record;
|
||||
using Hurricane::Name;
|
||||
using Hurricane::DBo;
|
||||
using Hurricane::Net;
|
||||
using Hurricane::Cell;
|
||||
using Hurricane::Instance;
|
||||
using Hurricane::Plug;
|
||||
using Hurricane::PrivateProperty;
|
||||
using CRL::NamingScheme;
|
||||
|
||||
class Bit;
|
||||
class EntityProperty;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Spice::Entity".
|
||||
|
||||
|
||||
class Entity {
|
||||
public:
|
||||
static std::vector<Entity*>&
|
||||
getAllEntities ();
|
||||
static void orderPlugs ( Instance*, std::vector<Plug*>& );
|
||||
public:
|
||||
Entity ( EntityProperty*, Cell* );
|
||||
~Entity ();
|
||||
const Cell* getCell () const;
|
||||
inline const BitVector& getBits () const;
|
||||
void toNodeList ( ostream&, bool asInterf=true ) const;
|
||||
void toEntity ( ostream& ) const;
|
||||
std::string _getString () const;
|
||||
Record* _getRecord () const;
|
||||
private:
|
||||
static std::vector<Entity*> _entities;
|
||||
static std::ptrdiff_t _offset;
|
||||
BitVector _bits;
|
||||
size_t _powerNode;
|
||||
size_t _groundNode;
|
||||
};
|
||||
|
||||
|
||||
inline const BitVector& Entity::getBits () const { return _bits; }
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Spice::EntityProperty".
|
||||
|
||||
class EntityProperty : public Hurricane::PrivateProperty {
|
||||
friend class EntityExtension;
|
||||
public:
|
||||
static Name _name;
|
||||
public:
|
||||
static EntityProperty* create ( Cell* owner );
|
||||
static Name getPropertyName ();
|
||||
virtual Name getName () const;
|
||||
inline Entity* getEntity ();
|
||||
virtual void onReleasedBy ( DBo* owner );
|
||||
virtual std::string _getTypeName () const;
|
||||
virtual std::string _getString () const;
|
||||
virtual Record* _getRecord () const;
|
||||
protected:
|
||||
// Attributes.
|
||||
Entity _entity;
|
||||
|
||||
protected:
|
||||
// Constructor.
|
||||
inline EntityProperty ( Cell* owner );
|
||||
};
|
||||
|
||||
|
||||
inline EntityProperty::EntityProperty ( Cell* owner )
|
||||
: PrivateProperty(), _entity(this,owner)
|
||||
{ }
|
||||
|
||||
|
||||
inline Entity* EntityProperty::getEntity () { return &_entity; }
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Spice::EntityExtension".
|
||||
|
||||
class EntityExtension {
|
||||
public:
|
||||
static void destroyAll ();
|
||||
static Entity* get ( const Cell* );
|
||||
static Entity* create ( Cell* );
|
||||
static void destroy ( Cell* );
|
||||
private:
|
||||
static const Cell* _owner;
|
||||
static Entity* _cache;
|
||||
};
|
||||
|
||||
|
||||
} // Spice Namespace.
|
||||
|
||||
|
||||
INSPECTOR_P_SUPPORT(Spice::Entity);
|
|
@ -0,0 +1,173 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) SU 2021-2021, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | S P I C E / Hurricane Interface |
|
||||
// | |
|
||||
// | Author : Jean-Paul Chaput |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Module : "./alliance/spice/SpiceBit.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include "crlcore/SpiceBit.h"
|
||||
|
||||
|
||||
namespace Spice {
|
||||
|
||||
using namespace std;
|
||||
using Hurricane::_TName;
|
||||
using Hurricane::Property;
|
||||
|
||||
|
||||
const size_t Bit::nindex = std::numeric_limits<size_t>::max();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "::Bit" (implementation).
|
||||
|
||||
ptrdiff_t Bit::_offset = 0;
|
||||
|
||||
|
||||
Bit::Bit ( BitProperty* property, const Net* net, size_t index, string name )
|
||||
: _index(index)
|
||||
, _name (name)
|
||||
{
|
||||
if (not _offset) {
|
||||
//_offset = offsetof(ScalarSignal,_toNet);
|
||||
_offset = (ptrdiff_t)this - (ptrdiff_t)property;
|
||||
}
|
||||
if (_name.empty())
|
||||
_name = to_string(_index);
|
||||
|
||||
// if (net->isPower ()) _name = getString(net->getName());
|
||||
// if (net->isGround()) _name = getString(net->getName());
|
||||
}
|
||||
|
||||
|
||||
Bit::Bit ( size_t index, string name )
|
||||
: _index(index)
|
||||
, _name (name)
|
||||
{ }
|
||||
|
||||
|
||||
Bit::~Bit ()
|
||||
{ }
|
||||
|
||||
|
||||
bool Bit::isExternal () const { return getNet()->isExternal(); }
|
||||
size_t Bit::getIndex () const { return _index; }
|
||||
|
||||
|
||||
string Bit::_getString () const
|
||||
{
|
||||
string s = "<" + getString(getNet()->getName());
|
||||
s += " order:";
|
||||
if (_index != nindex) s += getString(_index);
|
||||
else s += "nindex";
|
||||
s += " node:\"" + _name + "\"";
|
||||
s += ">";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Record* Bit::_getRecord () const
|
||||
{
|
||||
Record* record = new Record ( "<Bit " + _getString() + " >" );
|
||||
if (record != NULL) {
|
||||
record->add( getSlot("_index" , _index ) );
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "BitProperty"
|
||||
|
||||
Name BitProperty::_name = "Spice::Bit";
|
||||
|
||||
|
||||
BitProperty* BitProperty::create ( Net* owner, size_t index )
|
||||
{
|
||||
BitProperty *property = new BitProperty( owner, index );
|
||||
|
||||
property->_postCreate ();
|
||||
return property;
|
||||
}
|
||||
|
||||
|
||||
void BitProperty::onReleasedBy ( DBo* owner )
|
||||
{ PrivateProperty::onReleasedBy( owner ); }
|
||||
|
||||
|
||||
Name BitProperty::getPropertyName ()
|
||||
{ return _name; }
|
||||
|
||||
|
||||
Name BitProperty::getName () const
|
||||
{ return getPropertyName(); }
|
||||
|
||||
|
||||
string BitProperty::_getTypeName () const
|
||||
{ return "Spice::BitProperty"; }
|
||||
|
||||
|
||||
string BitProperty::_getString () const
|
||||
{
|
||||
string s = PrivateProperty::_getString ();
|
||||
s.insert ( s.length() - 1 , " " + getString(&_bit) );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Record* BitProperty::_getRecord () const
|
||||
{
|
||||
Record* record = PrivateProperty::_getRecord();
|
||||
if ( record ) {
|
||||
record->add( getSlot( "_name", _name ) );
|
||||
record->add( getSlot( "_bit" , &_bit ) );
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "BitExtension"
|
||||
|
||||
|
||||
const Net* BitExtension::_owner = NULL;
|
||||
Bit* BitExtension::_cache = NULL;
|
||||
|
||||
|
||||
Bit* BitExtension::get ( const Net* net )
|
||||
{
|
||||
if (net == _owner) return _cache;
|
||||
_owner = net;
|
||||
|
||||
Property* property = _owner->getProperty( BitProperty::getPropertyName() );
|
||||
if (property) _cache = static_cast<BitProperty*>(property)->getBit();
|
||||
else _cache = NULL;
|
||||
|
||||
return _cache;
|
||||
}
|
||||
|
||||
|
||||
Bit* BitExtension::create ( Net* net, size_t index )
|
||||
{
|
||||
get( net );
|
||||
if (_cache) return _cache;
|
||||
|
||||
BitProperty* property = new BitProperty( net, index );
|
||||
net->put( property );
|
||||
|
||||
_cache = property->getBit();
|
||||
return _cache;
|
||||
}
|
||||
|
||||
|
||||
} // Spice namespace.
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) SU 2021-2021, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | S P I C E / Hurricane Interface |
|
||||
// | |
|
||||
// | Author : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Module : "./spice/SpiceDriver.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include <ctime>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cfenv>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
#include "vlsisapd/configuration/Configuration.h"
|
||||
#include "hurricane/Warning.h"
|
||||
#include "hurricane/DataBase.h"
|
||||
#include "hurricane/BasicLayer.h"
|
||||
#include "hurricane/Technology.h"
|
||||
#include "hurricane/Horizontal.h"
|
||||
#include "hurricane/Vertical.h"
|
||||
#include "hurricane/Diagonal.h"
|
||||
#include "hurricane/Rectilinear.h"
|
||||
#include "hurricane/Polygon.h"
|
||||
#include "hurricane/Pad.h"
|
||||
#include "hurricane/Net.h"
|
||||
#include "hurricane/NetExternalComponents.h"
|
||||
#include "hurricane/Cell.h"
|
||||
#include "hurricane/Plug.h"
|
||||
#include "hurricane/Instance.h"
|
||||
using namespace Hurricane;
|
||||
|
||||
#include "crlcore/Utilities.h"
|
||||
#include "crlcore/NetExtension.h"
|
||||
#include "crlcore/ToolBox.h"
|
||||
#include "crlcore/Spice.h"
|
||||
#include "crlcore/SpiceBit.h"
|
||||
#include "crlcore/SpiceEntity.h"
|
||||
using namespace CRL;
|
||||
|
||||
|
||||
|
||||
namespace CRL {
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "CRL::Spice".
|
||||
|
||||
bool Spice::save ( Cell* cell )
|
||||
{
|
||||
::Spice::Entity* spiceEntity = ::Spice::EntityExtension::create( cell );
|
||||
|
||||
string cellFile = getString(cell->getName()) + ".spi";
|
||||
ofstream cellStream ( cellFile );
|
||||
spiceEntity->toEntity( cellStream );
|
||||
cellStream.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Spice::clearProperties ()
|
||||
{
|
||||
::Spice::EntityExtension::destroyAll();
|
||||
}
|
||||
|
||||
|
||||
} // CRL namespace.
|
|
@ -0,0 +1,311 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) SU 2021-2021, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | S P I C E / Hurricane Interface |
|
||||
// | |
|
||||
// | Author : Jean-Paul Chaput |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Module : "./SpiceEntity.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
#include "hurricane/Warning.h"
|
||||
#include "hurricane/Cell.h"
|
||||
#include "crlcore/SpiceEntity.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
using Hurricane::Net;
|
||||
using Hurricane::Instance;
|
||||
using Spice::Bit;
|
||||
using Spice::Entity;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace Spice {
|
||||
|
||||
using namespace std;
|
||||
using Hurricane::Warning;
|
||||
using Hurricane::Property;
|
||||
using Hurricane::_TName;
|
||||
using Hurricane::Plug;
|
||||
|
||||
|
||||
class ComparePlugBySpiceIndex {
|
||||
public:
|
||||
inline bool operator() ( const Plug* lhs, const Plug* rhs ) const
|
||||
{ return BitExtension::getIndex( lhs->getMasterNet() )
|
||||
< BitExtension::getIndex( rhs->getMasterNet() ); }
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "::Entity".
|
||||
|
||||
vector<Entity*> Entity::_entities;
|
||||
ptrdiff_t Entity::_offset = 0;
|
||||
|
||||
|
||||
Entity::Entity ( EntityProperty* property, Cell* cell )
|
||||
: _bits()
|
||||
, _powerNode (Bit::nindex)
|
||||
, _groundNode(Bit::nindex)
|
||||
{
|
||||
if (not _offset) {
|
||||
//_offset = offsetof(EntityProperty,_entity);
|
||||
_offset = (ptrdiff_t)this - (ptrdiff_t)property;
|
||||
}
|
||||
|
||||
map< string, Net*, greater<string> > orderedNets;
|
||||
for ( Net* net : cell->getNets() ) {
|
||||
orderedNets.insert( make_pair( getString(net->getName()), net ) );
|
||||
}
|
||||
for ( auto item : orderedNets ) {
|
||||
Bit* bit = BitExtension::create( item.second, _bits.size() );
|
||||
_bits.push_back( bit );
|
||||
if (item.second->isPower ()) _powerNode = bit->getIndex();
|
||||
if (item.second->isGround()) _groundNode = bit->getIndex();
|
||||
}
|
||||
|
||||
_entities.push_back( this );
|
||||
}
|
||||
|
||||
|
||||
Entity::~Entity ()
|
||||
{
|
||||
for ( auto bit : _bits ) bit->destroy();
|
||||
for ( auto ientity=_entities.begin() ; ientity!=_entities.end() ; ++ientity ) {
|
||||
if (*ientity == this) {
|
||||
_entities.erase( ientity );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vector<Entity*>& Entity::getAllEntities ()
|
||||
{ return _entities; }
|
||||
|
||||
|
||||
void Entity::orderPlugs ( Instance* instance, vector<Plug*>& ordereds )
|
||||
{
|
||||
ordereds.clear();
|
||||
//Entity* entity = EntityExtension::create( instance->getMasterCell() );
|
||||
for ( Plug* plug : instance->getPlugs() )
|
||||
ordereds.push_back( plug );
|
||||
sort( ordereds.begin(), ordereds.end(), ComparePlugBySpiceIndex() );
|
||||
}
|
||||
|
||||
|
||||
const Cell* Entity::getCell () const
|
||||
{
|
||||
EntityProperty* property = (EntityProperty*)((ptrdiff_t)(this) - _offset);
|
||||
return (const Cell*)property->getOwner();
|
||||
}
|
||||
|
||||
|
||||
void Entity::toNodeList ( ostream& out, bool asInterf ) const
|
||||
{
|
||||
for ( Bit* bit : _bits ) {
|
||||
const Net* net = bit->getNet();
|
||||
if (not net->isExternal() and asInterf) continue;
|
||||
out << "* " << ((asInterf) ? "INTERF" : "NET")
|
||||
<< setw(6) << BitExtension::getName(net)
|
||||
<< " " << net->getName() << ".\n";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
|
||||
void Entity::toEntity ( ostream& out ) const
|
||||
{
|
||||
set<Cell*,DBo::CompareById> processedsModels;
|
||||
string cellName = getString( getCell()->getName() );
|
||||
time_t clock = time( nullptr );
|
||||
tm tm = *localtime( &clock );
|
||||
char stamp[1024];
|
||||
strftime( stamp, 1024, "%b %d, %Y, %H:%M", &tm );
|
||||
|
||||
out << "* Coriolis Structural SPICE Driver\n";
|
||||
out << "* Generated on " << stamp << "\n";
|
||||
out << "* Cell/Subckt \"" << cellName << "\".\n";
|
||||
out << "* \n";
|
||||
toNodeList( out, true );
|
||||
|
||||
for ( Instance* instance : getCell()->getInstances() ) {
|
||||
Cell* model = instance->getMasterCell();
|
||||
if (processedsModels.find(model) != processedsModels.end())
|
||||
continue;
|
||||
out << ".include " << model->getName() << ".spi\n";
|
||||
processedsModels.insert( model );
|
||||
}
|
||||
out << "\n";
|
||||
|
||||
out << ".subckt " << getCell()->getName();
|
||||
for ( Bit* bit : _bits ) {
|
||||
if (not bit->getNet()->isExternal()) continue;
|
||||
out << " " << bit->getName();
|
||||
}
|
||||
out << "\n";
|
||||
toNodeList( out, false );
|
||||
|
||||
for ( Instance* instance : getCell()->getInstances() ) {
|
||||
Entity* masterEntity = EntityExtension::create( instance->getMasterCell() );
|
||||
out << "x" << instance->getName();
|
||||
vector<Plug*> sortedPlugs;
|
||||
masterEntity->orderPlugs( instance, sortedPlugs );
|
||||
for ( Plug* plug : sortedPlugs ) {
|
||||
Net* plugNet = plug->getNet();
|
||||
if (plugNet) {
|
||||
out << " " << BitExtension::getName(plugNet);
|
||||
} else {
|
||||
if (plug->getMasterNet()->isPower()) {
|
||||
out << " " << _powerNode;
|
||||
} else {
|
||||
if (plug->getMasterNet()->isGround()) {
|
||||
out << " " << _groundNode;
|
||||
} else
|
||||
out << " ?";
|
||||
}
|
||||
}
|
||||
}
|
||||
out << " " << instance->getMasterCell()->getName() << "\n";
|
||||
}
|
||||
out << ".ends " << getCell()->getName() << "\n";
|
||||
}
|
||||
|
||||
|
||||
string Entity::_getString () const
|
||||
{
|
||||
string s = getString(getCell()->getName());
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Record* Entity::_getRecord () const
|
||||
{
|
||||
Record* record = new Record ( "<Entity " + _getString() + " >" );
|
||||
if (record != NULL) {
|
||||
record->add( getSlot("_bits" , _bits ) );
|
||||
record->add( getSlot("_powerNode" , _powerNode ) );
|
||||
record->add( getSlot("_groundNode", _groundNode ) );
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "EntityProperty"
|
||||
|
||||
Name EntityProperty::_name = "Spice::Entity";
|
||||
|
||||
|
||||
EntityProperty* EntityProperty::create ( Cell* owner )
|
||||
{
|
||||
EntityProperty *property = new EntityProperty( owner );
|
||||
|
||||
property->_postCreate ();
|
||||
return property;
|
||||
}
|
||||
|
||||
|
||||
void EntityProperty::onReleasedBy ( DBo* owner )
|
||||
{ PrivateProperty::onReleasedBy( owner ); }
|
||||
|
||||
|
||||
Name EntityProperty::getPropertyName ()
|
||||
{ return _name; }
|
||||
|
||||
|
||||
Name EntityProperty::getName () const
|
||||
{ return getPropertyName(); }
|
||||
|
||||
|
||||
string EntityProperty::_getTypeName () const
|
||||
{ return _TName( "EntityProperty" ); }
|
||||
|
||||
|
||||
string EntityProperty::_getString () const
|
||||
{
|
||||
string s = PrivateProperty::_getString ();
|
||||
s.insert ( s.length() - 1 , " " + getString(&_entity) );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Record* EntityProperty::_getRecord () const
|
||||
{
|
||||
Record* record = PrivateProperty::_getRecord();
|
||||
if ( record ) {
|
||||
record->add( getSlot( "_name" , _name ) );
|
||||
record->add( getSlot( "_entity", &_entity ) );
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "EntityExtension"
|
||||
|
||||
|
||||
const Cell* EntityExtension::_owner = NULL;
|
||||
Entity* EntityExtension::_cache = NULL;
|
||||
|
||||
|
||||
Entity* EntityExtension::get ( const Cell* cell )
|
||||
{
|
||||
if (cell != _owner) {
|
||||
_owner = cell;
|
||||
|
||||
Property* property = _owner->getProperty( EntityProperty::getPropertyName() );
|
||||
if (property) _cache = static_cast<EntityProperty*>(property)->getEntity();
|
||||
else _cache = NULL;
|
||||
}
|
||||
return _cache;
|
||||
}
|
||||
|
||||
|
||||
Entity* EntityExtension::create ( Cell* cell )
|
||||
{
|
||||
get( cell );
|
||||
if (not _cache) {
|
||||
EntityProperty* property = new EntityProperty( cell );
|
||||
cell->put( property );
|
||||
|
||||
_cache = property->getEntity();
|
||||
}
|
||||
return _cache;
|
||||
}
|
||||
|
||||
|
||||
void EntityExtension::destroy ( Cell* cell )
|
||||
{
|
||||
Property* property = cell->getProperty( EntityProperty::getPropertyName() );
|
||||
if (property) cell->remove( property );
|
||||
|
||||
_owner = NULL;
|
||||
_cache = NULL;
|
||||
}
|
||||
|
||||
|
||||
void EntityExtension::destroyAll ()
|
||||
{
|
||||
vector<Entity*>& entities = Entity::getAllEntities();
|
||||
|
||||
while ( not entities.empty() ) destroy( const_cast<Cell*>(entities.back()->getCell()) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // Spice namespace.
|
|
@ -0,0 +1,80 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) SU 2021-2021, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | S P I C E / Hurricane Interface |
|
||||
// | |
|
||||
// | Author : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Module : "./spice/SpiceParser.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <bitset>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
#include "vlsisapd/configuration/Configuration.h"
|
||||
#include "hurricane/DebugSession.h"
|
||||
#include "hurricane/UpdateSession.h"
|
||||
#include "hurricane/Warning.h"
|
||||
#include "hurricane/DataBase.h"
|
||||
#include "hurricane/Technology.h"
|
||||
#include "hurricane/BasicLayer.h"
|
||||
#include "hurricane/Horizontal.h"
|
||||
#include "hurricane/Vertical.h"
|
||||
#include "hurricane/Diagonal.h"
|
||||
#include "hurricane/Rectilinear.h"
|
||||
#include "hurricane/Pad.h"
|
||||
#include "hurricane/Net.h"
|
||||
#include "hurricane/Cell.h"
|
||||
#include "hurricane/Library.h"
|
||||
#include "hurricane/Plug.h"
|
||||
#include "hurricane/Instance.h"
|
||||
#include "hurricane/NetExternalComponents.h"
|
||||
#include "hurricane/UpdateSession.h"
|
||||
using namespace Hurricane;
|
||||
|
||||
#include "crlcore/Utilities.h"
|
||||
#include "crlcore/NetExtension.h"
|
||||
#include "crlcore/ToolBox.h"
|
||||
#include "crlcore/Spice.h"
|
||||
using namespace CRL;
|
||||
|
||||
|
||||
namespace CRL {
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "CRL::Spice".
|
||||
|
||||
bool Spice::load ( Library* library, string spicePath )
|
||||
{
|
||||
//DebugSession::open( 101, 110 );
|
||||
UpdateSession::open();
|
||||
|
||||
cerr << Error( "Spice::load(): SPICE parser is not implemented yet.\n"
|
||||
" \"%s\"."
|
||||
, spicePath.c_str()
|
||||
) << endl;
|
||||
|
||||
UpdateSession::close();
|
||||
//DebugSession::close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // CRL namespace.
|
|
@ -44,6 +44,7 @@
|
|||
PyGraphicToolEngine.cpp
|
||||
PyAcmSigda.cpp
|
||||
PyIspd05.cpp
|
||||
PySpice.cpp
|
||||
PyBlif.cpp
|
||||
PyGds.cpp
|
||||
PyLefImport.cpp
|
||||
|
@ -65,6 +66,7 @@
|
|||
crlcore/PyGraphicToolEngine.h
|
||||
crlcore/PyAcmSigda.h
|
||||
crlcore/PyIspd05.h
|
||||
crlcore/PySpice.h
|
||||
crlcore/PyBlif.h
|
||||
crlcore/PyGds.h
|
||||
crlcore/PyLefImport.h
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) UPMC 2010-2018, All Rights Reserved
|
||||
// Copyright (c) SU 2010-2021, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
|
@ -32,6 +32,7 @@
|
|||
#include "crlcore/PyToolEngineCollection.h"
|
||||
#include "crlcore/PyAcmSigda.h"
|
||||
#include "crlcore/PyIspd05.h"
|
||||
#include "crlcore/PySpice.h"
|
||||
#include "crlcore/PyBlif.h"
|
||||
#include "crlcore/PyGds.h"
|
||||
#include "crlcore/PyLefImport.h"
|
||||
|
@ -125,6 +126,7 @@ extern "C" {
|
|||
PyToolEngineCollection_LinkPyType ();
|
||||
PyAcmSigda_LinkPyType ();
|
||||
PyIspd05_LinkPyType ();
|
||||
PySpice_LinkPyType ();
|
||||
PyBlif_LinkPyType ();
|
||||
PyGds_LinkPyType ();
|
||||
PyLefImport_LinkPyType ();
|
||||
|
@ -147,6 +149,7 @@ extern "C" {
|
|||
PYTYPE_READY ( ToolEngineCollectionLocator );
|
||||
PYTYPE_READY ( AcmSigda );
|
||||
PYTYPE_READY ( Ispd05 );
|
||||
PYTYPE_READY ( Spice );
|
||||
PYTYPE_READY ( Blif );
|
||||
PYTYPE_READY ( Gds );
|
||||
PYTYPE_READY ( LefImport );
|
||||
|
@ -201,6 +204,8 @@ extern "C" {
|
|||
PyModule_AddObject ( module, "AcmSigda", (PyObject*)&PyTypeAcmSigda );
|
||||
Py_INCREF ( &PyTypeIspd05 );
|
||||
PyModule_AddObject ( module, "Ispd05", (PyObject*)&PyTypeIspd05 );
|
||||
Py_INCREF ( &PyTypeSpice );
|
||||
PyModule_AddObject ( module, "Spice", (PyObject*)&PyTypeSpice );
|
||||
Py_INCREF ( &PyTypeBlif );
|
||||
PyModule_AddObject ( module, "Blif", (PyObject*)&PyTypeBlif );
|
||||
Py_INCREF ( &PyTypeGds );
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) SU 2021-2021, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | Alliance / Hurricane Interface |
|
||||
// | |
|
||||
// | Author : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Module : "./PySpice.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include "crlcore/PySpice.h"
|
||||
#include "hurricane/isobar/PyCell.h"
|
||||
#include "hurricane/isobar/PyLibrary.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace CRL {
|
||||
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::hex;
|
||||
using std::string;
|
||||
using std::ostringstream;
|
||||
using Hurricane::tab;
|
||||
using Hurricane::Exception;
|
||||
using Hurricane::Bug;
|
||||
using Hurricane::Error;
|
||||
using Hurricane::Warning;
|
||||
using Isobar::ProxyProperty;
|
||||
using Isobar::ProxyError;
|
||||
using Isobar::ConstructorError;
|
||||
using Isobar::HurricaneError;
|
||||
using Isobar::HurricaneWarning;
|
||||
using Isobar::getPyHash;
|
||||
using Isobar::ParseOneArg;
|
||||
using Isobar::ParseTwoArg;
|
||||
using Isobar::__cs;
|
||||
using Isobar::PyCell;
|
||||
using Isobar::PyTypeCell;
|
||||
using Isobar::PyCell_Link;
|
||||
using Isobar::PyLibrary;
|
||||
using Isobar::PyTypeLibrary;
|
||||
using Isobar::PyLibrary_Link;
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
||||
#if defined(__PYTHON_MODULE__)
|
||||
|
||||
// +=================================================================+
|
||||
// | "PySpice" Python Module Code Part |
|
||||
// +=================================================================+
|
||||
|
||||
|
||||
static PyObject* PySpice_save ( PyObject*, PyObject* args )
|
||||
{
|
||||
cdebug_log(30,0) << "PySpice_save()" << endl;
|
||||
|
||||
HTRY
|
||||
PyObject* pyCell = NULL;
|
||||
if (PyArg_ParseTuple( args, "O:Spice.save", &pyCell )) {
|
||||
if (IsPyCell(pyCell)) {
|
||||
Spice::save( PYCELL_O(pyCell) );
|
||||
} else {
|
||||
PyErr_SetString( ConstructorError, "Spice.save(): Bad parameter type (not a Cell)." );
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
PyErr_SetString( ConstructorError, "Spice.save(): Bad number of parameters." );
|
||||
return NULL;
|
||||
}
|
||||
HCATCH
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject* PySpice_load ( PyObject*, PyObject* args )
|
||||
{
|
||||
cdebug_log(30,0) << "PySpice_load()" << endl;
|
||||
|
||||
char* path = NULL;
|
||||
|
||||
HTRY
|
||||
PyObject* pyLibrary = NULL;
|
||||
if (PyArg_ParseTuple( args, "Os:Spice.load", &pyLibrary, &path )) {
|
||||
if (IsPyLibrary(pyLibrary)) {
|
||||
Spice::load( PYLIBRARY_O(pyLibrary), string(path) );
|
||||
} else {
|
||||
PyErr_SetString( ConstructorError, "Spice.load(): Bad parameter type (not a Library)." );
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
PyErr_SetString( ConstructorError, "Spice.load(): Bad number of parameters." );
|
||||
return NULL;
|
||||
}
|
||||
HCATCH
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject* PySpice_clearProperties ( PyObject* )
|
||||
{
|
||||
cdebug_log(30,0) << "PySpice_clearProperties()" << endl;
|
||||
HTRY
|
||||
Spice::clearProperties();
|
||||
HCATCH
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
// Standart Destroy (Attribute).
|
||||
|
||||
|
||||
PyMethodDef PySpice_Methods[] =
|
||||
{ { "save" , (PyCFunction)PySpice_save , METH_VARARGS|METH_STATIC
|
||||
, "Save a complete Spice design." }
|
||||
, { "load" , (PyCFunction)PySpice_load , METH_VARARGS|METH_STATIC
|
||||
, "Load a Spice layout inside a Cell (cumulative)." }
|
||||
, { "clearProperties" , (PyCFunction)PySpice_clearProperties, METH_NOARGS|METH_STATIC
|
||||
, "Remove all SPICE related properties from the Cells." }
|
||||
, {NULL, NULL, 0, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
||||
NoObjectDeleteMethod(Spice)
|
||||
PyTypeObjectLinkPyTypeWithoutObject(Spice,Spice)
|
||||
|
||||
|
||||
#else // End of Python Module Code Part.
|
||||
|
||||
|
||||
// +=================================================================+
|
||||
// | "PySpice" Shared Library Code Part |
|
||||
// +=================================================================+
|
||||
|
||||
// Type Definition.
|
||||
PyTypeObjectDefinitionsOfModule(CRL,Spice)
|
||||
|
||||
|
||||
#endif // End of Shared Library Code Part.
|
||||
|
||||
} // extern "C".
|
||||
|
||||
} // CRL namespace.
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) SU 2021-2021, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | Alliance / Hurricane Interface |
|
||||
// | |
|
||||
// | Author : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@asim.lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Header : "./crlcore/PySpice.h" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#pragma once
|
||||
#include "hurricane/isobar/PyHurricane.h"
|
||||
#include "crlcore/Spice.h"
|
||||
|
||||
|
||||
namespace CRL {
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Python Object : "PySpice".
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
} PySpice;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Functions & Types exported to "PyCRL.ccp".
|
||||
|
||||
extern PyTypeObject PyTypeSpice;
|
||||
extern PyMethodDef PySpice_Methods[];
|
||||
|
||||
extern void PySpice_LinkPyType();
|
||||
|
||||
|
||||
#define IsPySpice(v) ( (v)->ob_type == &PyTypeSpice )
|
||||
#define PY_SPICE(v) ( (PySpice*)(v) )
|
||||
|
||||
|
||||
} // extern "C".
|
||||
|
||||
} // Hurricane namespace.
|
|
@ -1236,11 +1236,12 @@ class BlockConf ( GaugeConf ):
|
|||
topCell = self.chip
|
||||
self.corona.setName( self.corona.getName()+'_r' )
|
||||
self.chip .setName( self.chip .getName()+'_r' )
|
||||
rsave( self.corona, views|flags )
|
||||
rsave( self.chip , views|flags )
|
||||
rsave( self.corona, views|flags, enableSpice=True )
|
||||
rsave( self.chip , views|flags, enableSpice=True )
|
||||
if not self.routingGauge.isSymbolic():
|
||||
print( ' + {} (GDSII).'.format( topCell.getName() ))
|
||||
CRL.Gds.save( topCell )
|
||||
CRL.Spice.clearProperties()
|
||||
return
|
||||
|
||||
def toXPitch ( self, x, superior=False ):
|
||||
|
|
|
@ -31,7 +31,7 @@ except Exception, e:
|
|||
sys.exit(2)
|
||||
|
||||
|
||||
def rsave ( cell, views=CRL.Catalog.State.Physical, depth=0 ):
|
||||
def rsave ( cell, views=CRL.Catalog.State.Physical, depth=0, enableSpice=False ):
|
||||
"""
|
||||
Write back layout to disk if everything has gone fine.
|
||||
Must write all the sub-blocks of the core but *not* the
|
||||
|
@ -47,15 +47,20 @@ def rsave ( cell, views=CRL.Catalog.State.Physical, depth=0 ):
|
|||
if views & CRL.Catalog.State.Logical:
|
||||
sviews += 'netlist'
|
||||
if views & CRL.Catalog.State.VstUseConcat:
|
||||
if sviews: sviews += ','
|
||||
sviews += ' uses &'
|
||||
if sviews: sviews += ', '
|
||||
sviews += 'uses &'
|
||||
if views & CRL.Catalog.State.VstNoLowerCase:
|
||||
if sviews: sviews += ', no lowercase'
|
||||
if sviews: sviews += ', '
|
||||
sviews += 'no lowercase'
|
||||
if views & CRL.Catalog.State.VstUniquifyUpperCase:
|
||||
if sviews: sviews += ', uniquify uppercase'
|
||||
if sviews: sviews += ', '
|
||||
sviews += 'uniquify uppercase'
|
||||
if views & CRL.Catalog.State.VstNoLinkage:
|
||||
if sviews: sviews += ', no linkage'
|
||||
sviews += ''
|
||||
if sviews: sviews += ', '
|
||||
sviews += 'no linkage'
|
||||
if enableSpice:
|
||||
if sviews: sviews += ', '
|
||||
sviews += 'SPICE'
|
||||
if views & CRL.Catalog.State.Physical:
|
||||
if sviews: sviews += ','
|
||||
sviews += 'layout'
|
||||
|
@ -64,11 +69,12 @@ def rsave ( cell, views=CRL.Catalog.State.Physical, depth=0 ):
|
|||
if cell.getName().endswith('_cts'): views |= CRL.Catalog.State.Logical
|
||||
if cell.getName().endswith('_r' ): views |= CRL.Catalog.State.Logical
|
||||
framework.saveCell( cell, views )
|
||||
CRL.Spice.save( cell )
|
||||
for instance in cell.getInstances():
|
||||
#print( ' {}| {}.'.format(' '*(depth*2), instance) )
|
||||
masterCell = instance.getMasterCell()
|
||||
if not masterCell.isTerminalNetlist():
|
||||
rsave( masterCell, views, depth+1 )
|
||||
rsave( masterCell, views, depth+1, enableSpice )
|
||||
#else:
|
||||
# print( ' {}| Master cell is terminal netlist {}.'.format(' '*(depth*2), instance.getMasterCell()) )
|
||||
return
|
||||
|
|
Loading…
Reference in New Issue