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/ispd04
|
||||||
${CRLCORE_SOURCE_DIR}/src/ccore/ispd05
|
${CRLCORE_SOURCE_DIR}/src/ccore/ispd05
|
||||||
${CRLCORE_SOURCE_DIR}/src/ccore/iccad04
|
${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/lefdef
|
||||||
${CRLCORE_SOURCE_DIR}/src/ccore/blif
|
${CRLCORE_SOURCE_DIR}/src/ccore/blif
|
||||||
${CRLCORE_SOURCE_DIR}/src/ccore/alliance/ap
|
${CRLCORE_SOURCE_DIR}/src/ccore/alliance/ap
|
||||||
|
@ -105,10 +105,11 @@
|
||||||
ToolEngine.cpp
|
ToolEngine.cpp
|
||||||
GraphicToolEngine.cpp
|
GraphicToolEngine.cpp
|
||||||
)
|
)
|
||||||
#set ( spice_cpps spice/SpiceParser.cpp
|
set ( spice_cpps spice/SpiceBit.cpp
|
||||||
# spice/SpiceDriver.cpp
|
spice/SpiceEntity.cpp
|
||||||
# spice/Spice.cpp
|
spice/SpiceParser.cpp
|
||||||
# )
|
spice/SpiceDriver.cpp
|
||||||
|
)
|
||||||
set ( bookshelf_cpps bookshelf/BookshelfParser.cpp
|
set ( bookshelf_cpps bookshelf/BookshelfParser.cpp
|
||||||
bookshelf/BookshelfDriver.cpp
|
bookshelf/BookshelfDriver.cpp
|
||||||
)
|
)
|
||||||
|
@ -296,7 +297,7 @@
|
||||||
${ispd04_cpps}
|
${ispd04_cpps}
|
||||||
${ispd05_cpps}
|
${ispd05_cpps}
|
||||||
${blif_cpps}
|
${blif_cpps}
|
||||||
#${spice_cpps}
|
${spice_cpps}
|
||||||
${lefdef_cpps}
|
${lefdef_cpps}
|
||||||
${openaccess_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
|
PyGraphicToolEngine.cpp
|
||||||
PyAcmSigda.cpp
|
PyAcmSigda.cpp
|
||||||
PyIspd05.cpp
|
PyIspd05.cpp
|
||||||
|
PySpice.cpp
|
||||||
PyBlif.cpp
|
PyBlif.cpp
|
||||||
PyGds.cpp
|
PyGds.cpp
|
||||||
PyLefImport.cpp
|
PyLefImport.cpp
|
||||||
|
@ -65,6 +66,7 @@
|
||||||
crlcore/PyGraphicToolEngine.h
|
crlcore/PyGraphicToolEngine.h
|
||||||
crlcore/PyAcmSigda.h
|
crlcore/PyAcmSigda.h
|
||||||
crlcore/PyIspd05.h
|
crlcore/PyIspd05.h
|
||||||
|
crlcore/PySpice.h
|
||||||
crlcore/PyBlif.h
|
crlcore/PyBlif.h
|
||||||
crlcore/PyGds.h
|
crlcore/PyGds.h
|
||||||
crlcore/PyLefImport.h
|
crlcore/PyLefImport.h
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// -*- C++ -*-
|
// -*- C++ -*-
|
||||||
//
|
//
|
||||||
// This file is part of the Coriolis Software.
|
// 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 |
|
// | C O R I O L I S |
|
||||||
|
@ -32,6 +32,7 @@
|
||||||
#include "crlcore/PyToolEngineCollection.h"
|
#include "crlcore/PyToolEngineCollection.h"
|
||||||
#include "crlcore/PyAcmSigda.h"
|
#include "crlcore/PyAcmSigda.h"
|
||||||
#include "crlcore/PyIspd05.h"
|
#include "crlcore/PyIspd05.h"
|
||||||
|
#include "crlcore/PySpice.h"
|
||||||
#include "crlcore/PyBlif.h"
|
#include "crlcore/PyBlif.h"
|
||||||
#include "crlcore/PyGds.h"
|
#include "crlcore/PyGds.h"
|
||||||
#include "crlcore/PyLefImport.h"
|
#include "crlcore/PyLefImport.h"
|
||||||
|
@ -125,6 +126,7 @@ extern "C" {
|
||||||
PyToolEngineCollection_LinkPyType ();
|
PyToolEngineCollection_LinkPyType ();
|
||||||
PyAcmSigda_LinkPyType ();
|
PyAcmSigda_LinkPyType ();
|
||||||
PyIspd05_LinkPyType ();
|
PyIspd05_LinkPyType ();
|
||||||
|
PySpice_LinkPyType ();
|
||||||
PyBlif_LinkPyType ();
|
PyBlif_LinkPyType ();
|
||||||
PyGds_LinkPyType ();
|
PyGds_LinkPyType ();
|
||||||
PyLefImport_LinkPyType ();
|
PyLefImport_LinkPyType ();
|
||||||
|
@ -147,6 +149,7 @@ extern "C" {
|
||||||
PYTYPE_READY ( ToolEngineCollectionLocator );
|
PYTYPE_READY ( ToolEngineCollectionLocator );
|
||||||
PYTYPE_READY ( AcmSigda );
|
PYTYPE_READY ( AcmSigda );
|
||||||
PYTYPE_READY ( Ispd05 );
|
PYTYPE_READY ( Ispd05 );
|
||||||
|
PYTYPE_READY ( Spice );
|
||||||
PYTYPE_READY ( Blif );
|
PYTYPE_READY ( Blif );
|
||||||
PYTYPE_READY ( Gds );
|
PYTYPE_READY ( Gds );
|
||||||
PYTYPE_READY ( LefImport );
|
PYTYPE_READY ( LefImport );
|
||||||
|
@ -201,6 +204,8 @@ extern "C" {
|
||||||
PyModule_AddObject ( module, "AcmSigda", (PyObject*)&PyTypeAcmSigda );
|
PyModule_AddObject ( module, "AcmSigda", (PyObject*)&PyTypeAcmSigda );
|
||||||
Py_INCREF ( &PyTypeIspd05 );
|
Py_INCREF ( &PyTypeIspd05 );
|
||||||
PyModule_AddObject ( module, "Ispd05", (PyObject*)&PyTypeIspd05 );
|
PyModule_AddObject ( module, "Ispd05", (PyObject*)&PyTypeIspd05 );
|
||||||
|
Py_INCREF ( &PyTypeSpice );
|
||||||
|
PyModule_AddObject ( module, "Spice", (PyObject*)&PyTypeSpice );
|
||||||
Py_INCREF ( &PyTypeBlif );
|
Py_INCREF ( &PyTypeBlif );
|
||||||
PyModule_AddObject ( module, "Blif", (PyObject*)&PyTypeBlif );
|
PyModule_AddObject ( module, "Blif", (PyObject*)&PyTypeBlif );
|
||||||
Py_INCREF ( &PyTypeGds );
|
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
|
topCell = self.chip
|
||||||
self.corona.setName( self.corona.getName()+'_r' )
|
self.corona.setName( self.corona.getName()+'_r' )
|
||||||
self.chip .setName( self.chip .getName()+'_r' )
|
self.chip .setName( self.chip .getName()+'_r' )
|
||||||
rsave( self.corona, views|flags )
|
rsave( self.corona, views|flags, enableSpice=True )
|
||||||
rsave( self.chip , views|flags )
|
rsave( self.chip , views|flags, enableSpice=True )
|
||||||
if not self.routingGauge.isSymbolic():
|
if not self.routingGauge.isSymbolic():
|
||||||
print( ' + {} (GDSII).'.format( topCell.getName() ))
|
print( ' + {} (GDSII).'.format( topCell.getName() ))
|
||||||
CRL.Gds.save( topCell )
|
CRL.Gds.save( topCell )
|
||||||
|
CRL.Spice.clearProperties()
|
||||||
return
|
return
|
||||||
|
|
||||||
def toXPitch ( self, x, superior=False ):
|
def toXPitch ( self, x, superior=False ):
|
||||||
|
|
|
@ -31,7 +31,7 @@ except Exception, e:
|
||||||
sys.exit(2)
|
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.
|
Write back layout to disk if everything has gone fine.
|
||||||
Must write all the sub-blocks of the core but *not* the
|
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:
|
if views & CRL.Catalog.State.Logical:
|
||||||
sviews += 'netlist'
|
sviews += 'netlist'
|
||||||
if views & CRL.Catalog.State.VstUseConcat:
|
if views & CRL.Catalog.State.VstUseConcat:
|
||||||
if sviews: sviews += ','
|
if sviews: sviews += ', '
|
||||||
sviews += ' uses &'
|
sviews += 'uses &'
|
||||||
if views & CRL.Catalog.State.VstNoLowerCase:
|
if views & CRL.Catalog.State.VstNoLowerCase:
|
||||||
if sviews: sviews += ', no lowercase'
|
if sviews: sviews += ', '
|
||||||
|
sviews += 'no lowercase'
|
||||||
if views & CRL.Catalog.State.VstUniquifyUpperCase:
|
if views & CRL.Catalog.State.VstUniquifyUpperCase:
|
||||||
if sviews: sviews += ', uniquify uppercase'
|
if sviews: sviews += ', '
|
||||||
|
sviews += 'uniquify uppercase'
|
||||||
if views & CRL.Catalog.State.VstNoLinkage:
|
if views & CRL.Catalog.State.VstNoLinkage:
|
||||||
if sviews: sviews += ', no linkage'
|
if sviews: sviews += ', '
|
||||||
sviews += ''
|
sviews += 'no linkage'
|
||||||
|
if enableSpice:
|
||||||
|
if sviews: sviews += ', '
|
||||||
|
sviews += 'SPICE'
|
||||||
if views & CRL.Catalog.State.Physical:
|
if views & CRL.Catalog.State.Physical:
|
||||||
if sviews: sviews += ','
|
if sviews: sviews += ','
|
||||||
sviews += 'layout'
|
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('_cts'): views |= CRL.Catalog.State.Logical
|
||||||
if cell.getName().endswith('_r' ): views |= CRL.Catalog.State.Logical
|
if cell.getName().endswith('_r' ): views |= CRL.Catalog.State.Logical
|
||||||
framework.saveCell( cell, views )
|
framework.saveCell( cell, views )
|
||||||
|
CRL.Spice.save( cell )
|
||||||
for instance in cell.getInstances():
|
for instance in cell.getInstances():
|
||||||
#print( ' {}| {}.'.format(' '*(depth*2), instance) )
|
#print( ' {}| {}.'.format(' '*(depth*2), instance) )
|
||||||
masterCell = instance.getMasterCell()
|
masterCell = instance.getMasterCell()
|
||||||
if not masterCell.isTerminalNetlist():
|
if not masterCell.isTerminalNetlist():
|
||||||
rsave( masterCell, views, depth+1 )
|
rsave( masterCell, views, depth+1, enableSpice )
|
||||||
#else:
|
#else:
|
||||||
# print( ' {}| Master cell is terminal netlist {}.'.format(' '*(depth*2), instance.getMasterCell()) )
|
# print( ' {}| Master cell is terminal netlist {}.'.format(' '*(depth*2), instance.getMasterCell()) )
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue