Manage .include in SPICE driver so they occurs only once.

SPICE simulators don't like to have the same model defined twice.
As we have a "one file per model policy", then we must include the
model file only once. This is particularly critical for standard
cells. So now, the driver include all the models in the top level,
both terminals ans intermediate. And the sub-models include nothing.
We stop at the "TerminalNetlist" level.
  Add an option flag througout all the Spice driver hierarchy to
convey that information.
This commit is contained in:
Jean-Paul Chaput 2021-06-24 11:17:21 +02:00
parent f49426f2bb
commit 2705226cd0
7 changed files with 58 additions and 26 deletions

View File

@ -32,7 +32,7 @@ namespace CRL {
class Spice { class Spice {
public: public:
static bool save ( Cell* ); static bool save ( Cell*, uint64_t flags );
static bool load ( Library*, std::string spicePath ); static bool load ( Library*, std::string spicePath );
static void clearProperties (); static void clearProperties ();
}; };

View File

@ -49,13 +49,16 @@ namespace Spice {
class Entity { class Entity {
public:
static const uint64_t TopCell = (1 << 0);
public: public:
static std::vector<Entity*>& static std::vector<Entity*>&
getAllEntities (); getAllEntities ();
static void orderPlugs ( Instance*, std::vector<Plug*>& ); static void orderPlugs ( Instance*, std::vector<Plug*>& );
public: public:
Entity ( EntityProperty*, Cell* ); Entity ( EntityProperty*, Cell*, uint64_t flags );
~Entity (); ~Entity ();
inline uint64_t getFlags () const;
const Cell* getCell () const; const Cell* getCell () const;
inline const BitVector& getBits () const; inline const BitVector& getBits () const;
void toNodeList ( ostream&, bool asInterf=true ) const; void toNodeList ( ostream&, bool asInterf=true ) const;
@ -68,10 +71,12 @@ namespace Spice {
BitVector _bits; BitVector _bits;
size_t _powerNode; size_t _powerNode;
size_t _groundNode; size_t _groundNode;
uint64_t _flags;
}; };
inline const BitVector& Entity::getBits () const { return _bits; } inline uint64_t Entity::getFlags () const { return _flags; }
inline const BitVector& Entity::getBits () const { return _bits; }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -82,7 +87,7 @@ namespace Spice {
public: public:
static Name _name; static Name _name;
public: public:
static EntityProperty* create ( Cell* owner ); static EntityProperty* create ( Cell* owner, uint64_t flags );
static Name getPropertyName (); static Name getPropertyName ();
virtual Name getName () const; virtual Name getName () const;
inline Entity* getEntity (); inline Entity* getEntity ();
@ -96,12 +101,12 @@ namespace Spice {
protected: protected:
// Constructor. // Constructor.
inline EntityProperty ( Cell* owner ); inline EntityProperty ( Cell* owner, uint64_t flags );
}; };
inline EntityProperty::EntityProperty ( Cell* owner ) inline EntityProperty::EntityProperty ( Cell* owner, uint64_t flags )
: PrivateProperty(), _entity(this,owner) : PrivateProperty(), _entity(this,owner,flags)
{ } { }
@ -115,7 +120,7 @@ namespace Spice {
public: public:
static void destroyAll (); static void destroyAll ();
static Entity* get ( const Cell* ); static Entity* get ( const Cell* );
static Entity* create ( Cell* ); static Entity* create ( Cell*, uint64_t flags );
static void destroy ( Cell* ); static void destroy ( Cell* );
private: private:
static const Cell* _owner; static const Cell* _owner;

View File

@ -62,9 +62,9 @@ namespace CRL {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Class : "CRL::Spice". // Class : "CRL::Spice".
bool Spice::save ( Cell* cell ) bool Spice::save ( Cell* cell, uint64_t flags )
{ {
::Spice::Entity* spiceEntity = ::Spice::EntityExtension::create( cell ); ::Spice::Entity* spiceEntity = ::Spice::EntityExtension::create( cell, flags );
string cellFile = getString(cell->getName()) + ".spi"; string cellFile = getString(cell->getName()) + ".spi";
ofstream cellStream ( cellFile ); ofstream cellStream ( cellFile );

View File

@ -25,6 +25,7 @@ namespace {
using Hurricane::Net; using Hurricane::Net;
using Hurricane::Instance; using Hurricane::Instance;
using Hurricane::Occurrence;
using Spice::Bit; using Spice::Bit;
using Spice::Entity; using Spice::Entity;
@ -57,10 +58,11 @@ namespace Spice {
ptrdiff_t Entity::_offset = 0; ptrdiff_t Entity::_offset = 0;
Entity::Entity ( EntityProperty* property, Cell* cell ) Entity::Entity ( EntityProperty* property, Cell* cell, uint64_t flags )
: _bits() : _bits()
, _powerNode (Bit::nindex) , _powerNode (Bit::nindex)
, _groundNode(Bit::nindex) , _groundNode(Bit::nindex)
, _flags(flags)
{ {
if (not _offset) { if (not _offset) {
//_offset = offsetof(EntityProperty,_entity); //_offset = offsetof(EntityProperty,_entity);
@ -143,14 +145,26 @@ namespace Spice {
out << "* \n"; out << "* \n";
toNodeList( out, true ); toNodeList( out, true );
for ( Instance* instance : getCell()->getInstances() ) { if (_flags & TopCell) {
Cell* model = instance->getMasterCell(); out << "* Terminal models (aka standard cells) used througout all the hierarchy.\n";
if (processedsModels.find(model) != processedsModels.end()) for ( Occurrence occurrence : getCell()->getTerminalNetlistInstanceOccurrences() ) {
continue; Cell* model = static_cast<Instance*>( occurrence.getEntity() )->getMasterCell();
out << ".include " << model->getName() << ".spi\n"; if (processedsModels.find(model) != processedsModels.end())
processedsModels.insert( model ); continue;
out << ".include " << model->getName() << ".spi\n";
processedsModels.insert( model );
}
out << "\n";
out << "* Non-terminal models (part of the user's design hierarchy).\n";
for ( Occurrence occurrence : getCell()->getNonTerminalNetlistInstanceOccurrences() ) {
Cell* model = static_cast<Instance*>( occurrence.getEntity() )->getMasterCell();
if (processedsModels.find(model) != processedsModels.end())
continue;
out << ".include " << model->getName() << ".spi\n";
processedsModels.insert( model );
}
out << "\n";
} }
out << "\n";
out << ".subckt " << getCell()->getName(); out << ".subckt " << getCell()->getName();
for ( Bit* bit : _bits ) { for ( Bit* bit : _bits ) {
@ -161,7 +175,7 @@ namespace Spice {
toNodeList( out, false ); toNodeList( out, false );
for ( Instance* instance : getCell()->getInstances() ) { for ( Instance* instance : getCell()->getInstances() ) {
Entity* masterEntity = EntityExtension::create( instance->getMasterCell() ); Entity* masterEntity = EntityExtension::create( instance->getMasterCell(), 0 );
out << "x" << instance->getName(); out << "x" << instance->getName();
vector<Plug*> sortedPlugs; vector<Plug*> sortedPlugs;
masterEntity->orderPlugs( instance, sortedPlugs ); masterEntity->orderPlugs( instance, sortedPlugs );
@ -222,6 +236,7 @@ namespace Spice {
record->add( getSlot("_bits" , _bits ) ); record->add( getSlot("_bits" , _bits ) );
record->add( getSlot("_powerNode" , _powerNode ) ); record->add( getSlot("_powerNode" , _powerNode ) );
record->add( getSlot("_groundNode", _groundNode ) ); record->add( getSlot("_groundNode", _groundNode ) );
record->add( getSlot("_flags" , _flags ) );
} }
return record; return record;
} }
@ -233,9 +248,9 @@ namespace Spice {
Name EntityProperty::_name = "Spice::Entity"; Name EntityProperty::_name = "Spice::Entity";
EntityProperty* EntityProperty::create ( Cell* owner ) EntityProperty* EntityProperty::create ( Cell* owner, uint64_t flags )
{ {
EntityProperty *property = new EntityProperty( owner ); EntityProperty *property = new EntityProperty( owner, flags );
property->_postCreate (); property->_postCreate ();
return property; return property;
@ -299,11 +314,11 @@ namespace Spice {
} }
Entity* EntityExtension::create ( Cell* cell ) Entity* EntityExtension::create ( Cell* cell, uint64_t flags )
{ {
get( cell ); get( cell );
if (not _cache) { if (not _cache) {
EntityProperty* property = new EntityProperty( cell ); EntityProperty* property = new EntityProperty( cell, flags );
cell->put( property ); cell->put( property );
_cache = property->getEntity(); _cache = property->getEntity();

View File

@ -220,6 +220,7 @@ extern "C" {
PyRoutingGauge_postModuleInit (); PyRoutingGauge_postModuleInit ();
PyRoutingLayerGauge_postModuleInit (); PyRoutingLayerGauge_postModuleInit ();
PyAllianceFramework_postModuleInit (); PyAllianceFramework_postModuleInit ();
PySpice_postModuleInit ();
//PyObject* dictionnary = PyModule_GetDict ( module ); //PyObject* dictionnary = PyModule_GetDict ( module );
//DbULoadConstants ( dictionnary ); //DbULoadConstants ( dictionnary );

View File

@ -17,6 +17,7 @@
#include "crlcore/PySpice.h" #include "crlcore/PySpice.h"
#include "hurricane/isobar/PyCell.h" #include "hurricane/isobar/PyCell.h"
#include "hurricane/isobar/PyLibrary.h" #include "hurricane/isobar/PyLibrary.h"
#include "crlcore/SpiceEntity.h"
#include <string> #include <string>
#include <sstream> #include <sstream>
@ -65,10 +66,11 @@ extern "C" {
cdebug_log(30,0) << "PySpice_save()" << endl; cdebug_log(30,0) << "PySpice_save()" << endl;
HTRY HTRY
long flags = 0;
PyObject* pyCell = NULL; PyObject* pyCell = NULL;
if (PyArg_ParseTuple( args, "O:Spice.save", &pyCell )) { if (PyArg_ParseTuple( args, "Ol:Spice.save", &pyCell, &flags )) {
if (IsPyCell(pyCell)) { if (IsPyCell(pyCell)) {
Spice::save( PYCELL_O(pyCell) ); Spice::save( PYCELL_O(pyCell), flags );
} else { } else {
PyErr_SetString( ConstructorError, "Spice.save(): Bad parameter type (not a Cell)." ); PyErr_SetString( ConstructorError, "Spice.save(): Bad parameter type (not a Cell)." );
return NULL; return NULL;
@ -147,6 +149,14 @@ extern "C" {
PyTypeObjectDefinitionsOfModule(CRL,Spice) PyTypeObjectDefinitionsOfModule(CRL,Spice)
extern void PySpice_postModuleInit ()
{
PyObject* constant;
LoadObjectConstant(PyTypeSpice.tp_dict,::Spice::Entity::TopCell,"TopCell");
}
#endif // End of Shared Library Code Part. #endif // End of Shared Library Code Part.
} // extern "C". } // extern "C".

View File

@ -39,7 +39,8 @@ extern "C" {
extern PyTypeObject PyTypeSpice; extern PyTypeObject PyTypeSpice;
extern PyMethodDef PySpice_Methods[]; extern PyMethodDef PySpice_Methods[];
extern void PySpice_LinkPyType(); extern void PySpice_LinkPyType ();
extern void PySpice_postModuleInit ();
#define IsPySpice(v) ( (v)->ob_type == &PyTypeSpice ) #define IsPySpice(v) ( (v)->ob_type == &PyTypeSpice )