diff --git a/crlcore/src/ccore/crlcore/Spice.h b/crlcore/src/ccore/crlcore/Spice.h index 13a4c4d5..e1585c24 100644 --- a/crlcore/src/ccore/crlcore/Spice.h +++ b/crlcore/src/ccore/crlcore/Spice.h @@ -31,9 +31,11 @@ namespace CRL { class Spice { + public: + static const uint64_t PIN_ORDERING = (1<<0); public: static bool save ( Cell*, uint64_t flags ); - static bool load ( Library*, std::string spicePath ); + static bool load ( Library*, std::string spicePath, uint64_t mode ); static void clearProperties (); }; diff --git a/crlcore/src/ccore/crlcore/SpiceBit.h b/crlcore/src/ccore/crlcore/SpiceBit.h index 16f9bb06..38cb4be3 100644 --- a/crlcore/src/ccore/crlcore/SpiceBit.h +++ b/crlcore/src/ccore/crlcore/SpiceBit.h @@ -61,9 +61,6 @@ namespace Spice { inline std::string Bit::getName () const { return _name; } - typedef std::vector BitVector; - - struct GreaterBitByIndex { inline bool operator() ( const Bit* lhs, const Bit* rhs ) const { return lhs->getIndex() > rhs->getIndex(); } @@ -82,6 +79,7 @@ namespace Spice { static Name getPropertyName (); virtual Name getName () const; inline Bit* getBit (); + inline Net* getNet (); inline std::string getBitName () const; virtual void onReleasedBy ( DBo* owner ); virtual std::string _getTypeName () const; @@ -100,6 +98,7 @@ namespace Spice { : PrivateProperty(), _bit(this,owner,index) { } + inline Net* BitProperty::getNet () { return const_cast( _bit.getNet() ); } inline Bit* BitProperty::getBit () { return &_bit; } inline std::string BitProperty::getBitName () const { return _bit.getName(); } @@ -109,10 +108,12 @@ namespace Spice { 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 ); + static inline size_t getIndex ( const Net* ); + static inline std::string getName ( const Net* ); + static Bit* get ( const Net* ); + static void remove ( const Net* ); + static Bit* create ( Net*, size_t index=Bit::nindex ); + static inline void clearCache ( Net* ); private: static const Net* _owner; static Bit* _cache; @@ -125,13 +126,15 @@ namespace Spice { return (bit == NULL) ? false : bit->getIndex(); } - inline std::string BitExtension::getName ( const Net* net ) { Bit* bit = get( net ); return (bit == NULL) ? "?" : bit->getName(); } + inline void BitExtension::clearCache ( Net* net ) + { if (_owner == net) { _owner = NULL; _cache = NULL; } } + inline BitProperty* Bit::getProperty () const { return (BitProperty*)((ptrdiff_t)(this) - _offset); } inline const Net* Bit::getNet () const { return (const Net*)getProperty()->getOwner(); } diff --git a/crlcore/src/ccore/crlcore/SpiceEntity.h b/crlcore/src/ccore/crlcore/SpiceEntity.h index bf74b830..754d92e7 100644 --- a/crlcore/src/ccore/crlcore/SpiceEntity.h +++ b/crlcore/src/ccore/crlcore/SpiceEntity.h @@ -50,33 +50,42 @@ namespace Spice { class Entity { public: - static const uint64_t TopCell = (1 << 0); + static const uint64_t TopCell = (1 << 0); + static const uint64_t ReferenceCell = (1 << 1); public: static std::vector& - getAllEntities (); - static void orderPlugs ( Instance*, std::vector& ); + getAllEntities (); + static void orderPlugs ( Instance*, std::vector& ); public: - Entity ( EntityProperty*, Cell*, uint64_t flags ); - ~Entity (); - inline uint64_t getFlags () const; - 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; + Entity ( EntityProperty*, Cell*, uint64_t flags ); + ~Entity (); + inline bool isTopCell () const; + inline bool isReferenceCell () const; + inline uint64_t getFlags () const; + const Cell* getCell () const; + inline const std::vector& + getBits () const; + inline void setFlags ( uint64_t ); + void setOrder ( const std::vector& ); + void toNodeList ( ostream&, bool asInterf=true ) const; + void toEntity ( ostream& ) const; + std::string _getString () const; + Record* _getRecord () const; private: static std::vector _entities; static std::ptrdiff_t _offset; - BitVector _bits; + std::vector _bits; size_t _powerNode; size_t _groundNode; uint64_t _flags; }; - inline uint64_t Entity::getFlags () const { return _flags; } - inline const BitVector& Entity::getBits () const { return _bits; } + inline bool Entity::isTopCell () const { return _flags & TopCell; } + inline bool Entity::isReferenceCell () const { return _flags & ReferenceCell; } + inline uint64_t Entity::getFlags () const { return _flags; } + inline const std::vector& Entity::getBits () const { return _bits; } + inline void Entity::setFlags ( uint64_t flags ) { _flags |= flags; } // ------------------------------------------------------------------- diff --git a/crlcore/src/ccore/crlcore/ToolBox.h b/crlcore/src/ccore/crlcore/ToolBox.h index 70bcbaf1..1865720d 100644 --- a/crlcore/src/ccore/crlcore/ToolBox.h +++ b/crlcore/src/ccore/crlcore/ToolBox.h @@ -74,6 +74,7 @@ namespace CRL { public: typedef std::function< Name(const Name&,uint32_t) > converter_t; public: + static Name vhdlToVlog ( const Name& vhdlName ); static Name vlogToVhdl ( const Name& vlogName, uint32_t flags ); static void toVhdl ( Cell* topCell, uint32_t flags ); NamingScheme ( uint32_t flags ); diff --git a/crlcore/src/ccore/spice/SpiceBit.cpp b/crlcore/src/ccore/spice/SpiceBit.cpp index 1529251a..3fdfcae5 100644 --- a/crlcore/src/ccore/spice/SpiceBit.cpp +++ b/crlcore/src/ccore/spice/SpiceBit.cpp @@ -102,7 +102,10 @@ namespace Spice { void BitProperty::onReleasedBy ( DBo* owner ) - { PrivateProperty::onReleasedBy( owner ); } + { + BitExtension::clearCache( static_cast(owner) ); + PrivateProperty::onReleasedBy( owner ); + } Name BitProperty::getPropertyName () @@ -145,6 +148,16 @@ namespace Spice { Bit* BitExtension::_cache = NULL; + void BitExtension::remove ( const Net* net ) + { + Property* property = net->getProperty( BitProperty::getPropertyName() ); + if (property) { + const_cast( net )->remove( property ); + } + if (net == _owner) _owner = NULL; + } + + Bit* BitExtension::get ( const Net* net ) { if (net == _owner) return _cache; diff --git a/crlcore/src/ccore/spice/SpiceEntity.cpp b/crlcore/src/ccore/spice/SpiceEntity.cpp index baf4af9f..ab082794 100644 --- a/crlcore/src/ccore/spice/SpiceEntity.cpp +++ b/crlcore/src/ccore/spice/SpiceEntity.cpp @@ -21,18 +21,6 @@ #include "crlcore/SpiceEntity.h" -namespace { - - using Hurricane::Net; - using Hurricane::Instance; - using Hurricane::Occurrence; - using Spice::Bit; - using Spice::Entity; - - -} - - namespace Spice { using namespace std; @@ -41,6 +29,8 @@ namespace Spice { using Hurricane::Property; using Hurricane::_TName; using Hurricane::Plug; + using Hurricane::Occurrence; + using CRL::NamingScheme; class ComparePlugBySpiceIndex { @@ -64,6 +54,7 @@ namespace Spice { , _groundNode(Bit::nindex) , _flags(flags) { + //cerr << "Entity::Entity() on " << cell << endl; if (not _offset) { //_offset = offsetof(EntityProperty,_entity); _offset = (ptrdiff_t)this - (ptrdiff_t)property; @@ -84,15 +75,31 @@ namespace Spice { } + void Entity::setOrder ( const vector& orderedNets ) + { + for ( auto bit : _bits ) + BitExtension::remove( bit->getNet() ); + _bits.clear(); + + for ( auto net : orderedNets ) { + Bit* bit = BitExtension::create( net, _bits.size() ); + _bits.push_back( bit ); + if (net->isPower ()) _powerNode = bit->getIndex(); + if (net->isGround()) _groundNode = bit->getIndex(); + } + } + + Entity::~Entity () { - for ( auto bit : _bits ) bit->destroy(); for ( auto ientity=_entities.begin() ; ientity!=_entities.end() ; ++ientity ) { if (*ientity == this) { _entities.erase( ientity ); break; } } + for ( auto bit : _bits ) + BitExtension::remove( bit->getNet() ); } @@ -122,9 +129,13 @@ namespace Spice { 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"; + if (asInterf) { + out << "* " << "INTERF" //<< setw(6) << BitExtension::getName(net) + << " " << NamingScheme::vhdlToVlog(net->getName()) << "\n"; + } else { + out << "* " << "NET" << setw(6) << BitExtension::getName(net) + << " = " << NamingScheme::vhdlToVlog(net->getName()) << "\n"; + } } out << "\n"; } @@ -233,10 +244,10 @@ namespace Spice { { Record* record = new Record ( "" ); if (record != NULL) { - record->add( getSlot("_bits" , _bits ) ); - record->add( getSlot("_powerNode" , _powerNode ) ); - record->add( getSlot("_groundNode", _groundNode ) ); - record->add( getSlot("_flags" , _flags ) ); + record->add( getSlot("_bits" , &_bits ) ); + record->add( getSlot("_powerNode" , _powerNode ) ); + record->add( getSlot("_groundNode", _groundNode ) ); + record->add( getSlot("_flags" , _flags ) ); } return record; } @@ -340,8 +351,17 @@ namespace Spice { void EntityExtension::destroyAll () { vector& entities = Entity::getAllEntities(); + size_t current = 0; + while ( current < entities.size() ) { + if (entities[current]->isReferenceCell()) { + ++current; + } else { + //cerr << "Destroy SPICE entity on " << entities[current]->getCell() << endl; + destroy( const_cast(entities[current]->getCell()) ); + } + } - while ( not entities.empty() ) destroy( const_cast(entities.back()->getCell()) ); + //while ( not entities.empty() ) destroy( const_cast(entities.back()->getCell()) ); } diff --git a/crlcore/src/ccore/spice/SpiceParser.cpp b/crlcore/src/ccore/spice/SpiceParser.cpp index ccc0bd2f..ec5efc62 100644 --- a/crlcore/src/ccore/spice/SpiceParser.cpp +++ b/crlcore/src/ccore/spice/SpiceParser.cpp @@ -14,6 +14,7 @@ // +-----------------------------------------------------------------+ +#include #include #include #include @@ -23,7 +24,7 @@ #include #include #include -#include +#include using namespace std; #include "hurricane/configuration/Configuration.h" @@ -51,29 +52,293 @@ using namespace Hurricane; #include "crlcore/NetExtension.h" #include "crlcore/ToolBox.h" #include "crlcore/Spice.h" +#include "crlcore/SpiceBit.h" +#include "crlcore/SpiceEntity.h" using namespace CRL; +namespace { + + using namespace std; + using CRL::NamingScheme; + + + string& uppercase ( string& s ) + { + for ( size_t i=0 ; i& tokens (); + bool readEntry (); + private: + bool _readline (); + private: + size_t _lineno; + uint32_t _flags; + ifstream _stream; + list _tokens; + }; + + + Tokenize::Tokenize ( string spiceFile ) + : _lineno (0) + , _flags (0) + , _stream () + , _tokens () + { + _stream.open( spiceFile ); + if (_stream.fail()) + throw Error( "Unable to open SPICE file %s\n", spiceFile.c_str() ); + } + + + inline size_t Tokenize::lineno () const { return (_lineno) ? _lineno-1 : 0; } + inline uint32_t Tokenize::flags () const { return _flags; } + inline list& Tokenize::tokens () { return _tokens; } + + + bool Tokenize::readEntry () + { + _flags = 0; + + if (_stream.eof()) return false; + + if (not _readline()) return false; + string first = _tokens.front(); + uppercase( first ); + if (first[0] == '*' ) { _flags |= COMMENT; } + else if (first[0] == '.' ) { + if (first == ".MODEL" ) { _flags |= MODEL; } + else if (first == ".END" ) { _flags |= END; } + else if (first == ".SUBCKT" ) { _flags |= SUBCKT; } + else if (first == ".ENDS" ) { _flags |= ENDS; } + } + else if (first[0] == 'R') { _flags |= RESISTOR; } + else if (first[0] == 'C') { _flags |= CAPACITOR; } + else if (first[0] == 'L') { _flags |= INDUCTOR; } + else if (first[0] == 'K') { _flags |= COUPLED_INDUCTOR; } + else if (first[0] == 'D') { _flags |= DIODE; } + else if (first[0] == 'Q') { _flags |= BJT; } + else if (first[0] == 'J') { _flags |= JFET; } + else if (first[0] == 'M') { _flags |= MOSFET; } + else if (first[0] == 'X') { _flags |= SUBCIRCUIT; } + + return true; + } + + + bool Tokenize::_readline () + { + _tokens.clear(); + + bool nextLine = true; + + while ( nextLine ) { + if (_stream.eof()) return false; + + nextLine = false; + ++_lineno; + + string line; + getline( _stream, line ); + + size_t tokstart = 0; + for ( size_t i=0 ; i tokstart) + _tokens.push_back( line.substr(tokstart,i-tokstart) ); + tokstart = nextTokstart; + } + + if (tokstart < line.size()) { + if (line.substr(tokstart) == ";") + nextLine = true; + else + _tokens.push_back( line.substr(tokstart) ); + } + + if (_tokens.empty()) + nextLine = true; + } + + return not _tokens.empty(); + } + + +} // Anonymous namespace. + + namespace CRL { // ------------------------------------------------------------------- // Class : "CRL::Spice". - bool Spice::load ( Library* library, string spicePath ) + bool Spice::load ( Library* library, string spiceFile, uint64_t mode ) { + if (mode != PIN_ORDERING) { + cerr << Error( "Spice::load(): SPICE parser only support PIN_ORDERING mode.\n" + " \"%s\"." + , spiceFile.c_str() + ) << endl; + return false; + } + //DebugSession::open( 101, 110 ); UpdateSession::open(); - cerr << Error( "Spice::load(): SPICE parser is not implemented yet.\n" - " \"%s\"." - , spicePath.c_str() - ) << endl; + Tokenize tokenize ( spiceFile ); + + while ( tokenize.readEntry() ) { + if (tokenize.flags() & Tokenize::SUBCKT) { + list& tokens = tokenize.tokens(); + // cerr << "Found SUBCKT:"; + // for ( const string& item : tokens ) + // cerr << " " << item; + // cerr << endl; + + if (tokens.size() < 2) { + cerr << Error( "Spice::load(): Invalid SUBCKT, no parameters at all.\n" + " File %s at line %u." + , spiceFile.c_str() + , tokenize.lineno() + ) << endl; + continue; + } + + string cellName = *(next( tokens.begin(), 1)); + Cell* cell = library->getCell( cellName ); + if (not cell) { + cerr << Error( "Spice::load(): Library \"%s\" has no Cell named \"%s\".\n" + " File %s at line %u." + , getString( library->getName() ).c_str() + , getString( cellName ).c_str() + , spiceFile.c_str() + , tokenize.lineno() + ) << endl; + continue; + } + + tokens.pop_front(); + tokens.pop_front(); + // cerr << "Net order of " << cell; + // for ( auto& name : tokens ) + // cerr << " " << name; + // cerr << endl; + bool hasErrors = false; + vector orderedNets; + for ( const string& netName : tokens ) { + Net* net = cell->getNet( netName ); + if (not net) { + cerr << Error( "Spice::load(): Cell \"%s\" has no Net \"%s\".\n" + " File %s at line %u." + , getString( cell->getName() ).c_str() + , netName.c_str() + , spiceFile.c_str() + , tokenize.lineno() + ) << endl; + hasErrors = true; + continue; + } + if (not net->isExternal()) { + cerr << Error( "Spice::load(): In cell \"%s\", net \"%s\" is *not* external.\n" + " File %s at line %u." + , getString( cell->getName() ).c_str() + , getString( net ->getName() ).c_str() + , spiceFile.c_str() + , tokenize.lineno() + ) << endl; + hasErrors = true; + continue; + } + orderedNets.push_back( net ); + } + map< string, Net*, greater > internalNets; + for ( Net* net : cell->getNets() ) { + if (net->isExternal()) continue; + internalNets.insert( make_pair( getString(net->getName()), net ) ); + } + for ( auto item : internalNets ) { + orderedNets.push_back( item.second ); + } + // for ( Net* net : orderedNets ) + // cerr << " " << net->getName(); + // cerr << endl; + + for ( Net* net : cell->getExternalNets() ) { + if (find( orderedNets.begin(), orderedNets.end(), net) == orderedNets.end()) { + cerr << Error( "Spice::load(): In cell \"%s\", external net \"%s\" *not* ordered.\n" + " File %s at line %u." + , getString( cell->getName() ).c_str() + , getString( net ->getName() ).c_str() + , spiceFile.c_str() + , tokenize.lineno() + ) << endl; + hasErrors = true; + break; + } + } + if (hasErrors) continue; + + ::Spice::Entity* spiceEntity = ::Spice::EntityExtension::get( cell ); + if (spiceEntity) { + if (spiceEntity->getFlags() & ::Spice::Entity::ReferenceCell) { + cerr << Warning( "Spice::load(): Redefinition of external net order of \"%s\".\n" + " (from file: \"%s\")" + , getString( cell->getName() ).c_str() + , spiceFile.c_str() + ) << endl; + } else { + spiceEntity->setFlags( ::Spice::Entity::ReferenceCell ); + } + } else { + spiceEntity = ::Spice::EntityExtension::create( cell, ::Spice::Entity::ReferenceCell ); + } + spiceEntity->setOrder( orderedNets ); + } + } UpdateSession::close(); //DebugSession::close(); - return false; + return true; } diff --git a/crlcore/src/ccore/toolbox/NamingScheme.cpp b/crlcore/src/ccore/toolbox/NamingScheme.cpp index 1f8af188..7b8e9998 100644 --- a/crlcore/src/ccore/toolbox/NamingScheme.cpp +++ b/crlcore/src/ccore/toolbox/NamingScheme.cpp @@ -29,6 +29,20 @@ namespace CRL { using Hurricane::Instance; + Name NamingScheme::vhdlToVlog ( const Name& vhdlName ) + { + string vlogName; + + for ( size_t i=0 ; i