From 2f17ce7b37d55ecbb9744f886fc3afa086bb41c4 Mon Sep 17 00:00:00 2001 From: Damien Dupuis Date: Fri, 6 May 2011 09:21:01 +0000 Subject: [PATCH] Adding spice parser/driver (only database right now, examples code will follow) Supported grammar is : .INCLUDE .LIB .PARAM .OPTION .SUBCKT Xxxx Rxxx Cxxx Ixxx Vxxx Mxxx and Dxxx are on the todo list --- vlsisapd/src/CMakeLists.txt | 3 + vlsisapd/src/spice/CMakeLists.txt | 1 + vlsisapd/src/spice/src/CMakeLists.txt | 33 ++ vlsisapd/src/spice/src/Circuit.cpp | 435 ++++++++++++++++++ vlsisapd/src/spice/src/Instance.cpp | 29 ++ vlsisapd/src/spice/src/Value.cpp | 69 +++ .../src/spice/src/vlsisapd/spice/Circuit.h | 108 +++++ .../src/spice/src/vlsisapd/spice/Instance.h | 43 ++ .../src/spice/src/vlsisapd/spice/Instances.h | 69 +++ .../src/spice/src/vlsisapd/spice/Sources.h | 39 ++ .../spice/src/vlsisapd/spice/SpiceException.h | 20 + .../src/spice/src/vlsisapd/spice/Subckt.h | 35 ++ vlsisapd/src/spice/src/vlsisapd/spice/Value.h | 41 ++ 13 files changed, 925 insertions(+) create mode 100644 vlsisapd/src/spice/CMakeLists.txt create mode 100644 vlsisapd/src/spice/src/CMakeLists.txt create mode 100644 vlsisapd/src/spice/src/Circuit.cpp create mode 100644 vlsisapd/src/spice/src/Instance.cpp create mode 100644 vlsisapd/src/spice/src/Value.cpp create mode 100644 vlsisapd/src/spice/src/vlsisapd/spice/Circuit.h create mode 100644 vlsisapd/src/spice/src/vlsisapd/spice/Instance.h create mode 100644 vlsisapd/src/spice/src/vlsisapd/spice/Instances.h create mode 100644 vlsisapd/src/spice/src/vlsisapd/spice/Sources.h create mode 100644 vlsisapd/src/spice/src/vlsisapd/spice/SpiceException.h create mode 100644 vlsisapd/src/spice/src/vlsisapd/spice/Subckt.h create mode 100644 vlsisapd/src/spice/src/vlsisapd/spice/Value.h diff --git a/vlsisapd/src/CMakeLists.txt b/vlsisapd/src/CMakeLists.txt index 1edf89f1..e2aee49b 100644 --- a/vlsisapd/src/CMakeLists.txt +++ b/vlsisapd/src/CMakeLists.txt @@ -6,6 +6,9 @@ ENDIF(IS_DIRECTORY ${VLSISAPD_SOURCE_DIR}/src/openChams) IF(IS_DIRECTORY ${VLSISAPD_SOURCE_DIR}/src/dtr) ADD_SUBDIRECTORY(dtr) ENDIF(IS_DIRECTORY ${VLSISAPD_SOURCE_DIR}/src/dtr) +IF(IS_DIRECTORY ${VLSISAPD_SOURCE_DIR}/src/spice) + ADD_SUBDIRECTORY(spice) +ENDIF(IS_DIRECTORY ${VLSISAPD_SOURCE_DIR}/src/spice) ADD_SUBDIRECTORY(bookshelf) ADD_SUBDIRECTORY(configuration) ADD_SUBDIRECTORY(liberty) diff --git a/vlsisapd/src/spice/CMakeLists.txt b/vlsisapd/src/spice/CMakeLists.txt new file mode 100644 index 00000000..4b7537b5 --- /dev/null +++ b/vlsisapd/src/spice/CMakeLists.txt @@ -0,0 +1 @@ +ADD_SUBDIRECTORY(src) diff --git a/vlsisapd/src/spice/src/CMakeLists.txt b/vlsisapd/src/spice/src/CMakeLists.txt new file mode 100644 index 00000000..8d4b3bac --- /dev/null +++ b/vlsisapd/src/spice/src/CMakeLists.txt @@ -0,0 +1,33 @@ +INCLUDE_DIRECTORIES(${VLSISAPD_SOURCE_DIR}/src/spice/src ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_PATH}) + +SET ( hpps vlsisapd/spice/Circuit.h + vlsisapd/spice/Subckt.h + vlsisapd/spice/Instance.h + vlsisapd/spice/Instances.h + vlsisapd/spice/Value.h + vlsisapd/spice/Sources.h + vlsisapd/spice/SpiceException.h + ) +SET ( cpps Circuit.cpp + Instance.cpp + Value.cpp + ) +#SET ( pycpps PySpice.cpp +# ) + +ADD_LIBRARY(spice ${cpps}) +TARGET_LINK_LIBRARIES(spice) +SET_TARGET_PROPERTIES(spice PROPERTIES VERSION 1.0 SOVERSION 1) +INSTALL(TARGETS spice DESTINATION lib${LIB_SUFFIX} ) + +#IF(Boost_FOUND) +# ADD_LIBRARY(pySPICE MODULE ${pycpps}) +# SET_TARGET_PROPERTIES(pySPICE PROPERTIES +# OUTPUT_NAME "SPICE" +# PREFIX "" +# ) +# TARGET_LINK_LIBRARIES(pySPICE spice ${Boost_LIBRARIES} ${PYTHON_LIBRARIES}) +# INSTALL(TARGETS pySPICE DESTINATION ${PYTHON_SITE_PACKAGES}) +#ENDIF(Boost_FOUND) + +INSTALL(FILES ${hpps} DESTINATION include/vlsisapd/spice) diff --git a/vlsisapd/src/spice/src/Circuit.cpp b/vlsisapd/src/spice/src/Circuit.cpp new file mode 100644 index 00000000..27ad35c8 --- /dev/null +++ b/vlsisapd/src/spice/src/Circuit.cpp @@ -0,0 +1,435 @@ +#include +#include +#include +#include +#include +using namespace std; + +#include "vlsisapd/spice/Circuit.h" +#include "vlsisapd/spice/Value.h" +#include "vlsisapd/spice/Subckt.h" +#include "vlsisapd/spice/Instances.h" +#include "vlsisapd/spice/Sources.h" +#include "vlsisapd/spice/SpiceException.h" + +namespace SPICE { +#define DEBUG +void Circuit::addOption(string name, string value) { + map::iterator it = _options.find(name); + if (it != _options.end()) { + cerr << "[WARNING] SPICE:: Cannot add option " << name + << " to Circuit since it already exists." << endl; + return; + } + _options[name] = value; +} + +void Circuit::addParameter(string name, string value) { + map::iterator pit = _parameters.find(name); + if (pit != _parameters.end()) { + cerr << "[WARNING] SPICE:: Cannot add parameter " << name + << " to Circuit since it already exists." << endl; + return; + } + _parameters[name] = value; +} + +Subckt* Circuit::addSubckt(string name) { + Subckt* sub = new Subckt(name); + if (!sub) + throw SpiceException("SPICE::Circuit::addSubckt: Could not create new Subckt !"); + + _subckts.push_back(sub); + return sub; +} + +Circuit* Circuit::readFromFile(const string& filename) { + cerr << "reading file: " << filename << endl; + std::ifstream spfile(filename.c_str()); + if (!spfile) + throw SpiceException("SPICE::Circuit::readFromFile: Cannot open file: "+filename+" !"); + Circuit* circuit = new Circuit(); + if (!circuit) + throw SpiceException("SPICE::Circuit::readFromFile: Cannot create new Circuit !"); + string line; + // catch first line + if (getNextLineType(spfile, line) != Circuit::ENDFILE) { + #ifdef DEBUG + cerr << "TITLE | " << line << endl; + #endif + circuit->setTitle(line); + } else { + throw SpiceException("SPICE::Circuit::readFromFile: File seems empty !"); + } + + bool inSubckt = false; // to know whether parsed line is in subckt or not + Subckt* sub = NULL; + Circuit::LineType type = getNextFullLineType(spfile, line); + while (type != Circuit::ENDFILE) { + // decompose line into tokens + vector tokens; + tokenize(line, tokens); + // based on line type: do something + switch(type) { + case Circuit::INCLUDE: + { + #ifdef DEBUG + cerr << "INCLUDE | " << line << endl; + #endif + circuit->addInclude(tokens[1]); + break; + } + case Circuit::LIBRARY: + { + #ifdef DEBUG + cerr << "LIBRARY | " << line << endl; + #endif + if (tokens.size() == 3) + circuit->addLibrary(tokens[1], tokens[2]); // with LIBTYPE + else + circuit->addLibrary(tokens[1]); // without LIBTYPE + break; + } + case Circuit::PARAM: + { + #ifdef DEBUG + cerr << "PARAM | " << line << endl; + #endif + string name, value; + parametrize(tokens[1], name, value); // value must be a numeric value + circuit->addParameter(name, value); + break; + } + case Circuit::OPTION: + { + #ifdef DEBUG + cerr << "OPTION | " << line << endl; + #endif + for (size_t i = 1 ; i < tokens.size() ; i++) { + string name, value; + parametrize(tokens[i], name, value); + circuit->addOption(name, value); + } + break; + } + case Circuit::SUBCKT: + { + #ifdef DEBUG + cerr << "SUBCKT | " << line << endl; + #endif + if (inSubckt) throw SpiceException("SPICE::Circuit::readFromFile: Found hierarchic .subckt !"); + inSubckt = true; + sub = circuit->addSubckt(tokens[1]); + for (size_t i = 2 ; i < tokens.size() ; i++) + sub->addInterface(tokens[i]); + break; + } + case Circuit::ENDSUB: + #ifdef DEBUG + cerr << "ENDSUB | " << line << endl; + #endif + if (!inSubckt) throw SpiceException("SPICE::Circuit::readFromFile: Cannot close Subckt since it was not opened !"); + inSubckt = false; + break; + case Circuit::END: + #ifdef DEBUG + cerr << "END | " << line << endl; + #endif + break; + case Circuit::INSTANCE: + { + #ifdef DEBUG + cerr << "INSTANCE | " << line << endl; + #endif + size_t modelIdx = 0; + for (size_t i = tokens.size()-1 ; i >= 1 ; i--) { + if(tokens[i].find("=") == string::npos) { + modelIdx = i; + break; + } + } + Instance* inst = new Instance(tokens[0], tokens[modelIdx]); + for (size_t i = 1 ; i < modelIdx ; i++) + inst->addConnector(tokens[i]); + for (size_t i = modelIdx+1 ; i < tokens.size() ; i++) { + string name, value; + parametrize(tokens[i], name, value); + inst->addParameter(name, value); + } + if (inSubckt) { // must add instance to current subckt + sub->addInstance(inst); + } else { // instance is added to top-level circuit + circuit->addInstance(inst); + } + break; + } + case Circuit::VOLTAGE: + { + #ifdef DEBUG + cerr << "VOLTAGE | " << line << endl; + #endif + circuit->addSource(new Voltage(tokens[0], tokens[1], tokens[2], tokens[3])); + break; + } + case Circuit::CURRENT: + #ifdef DEBUG + cerr << "CURRENT | " << line << endl; + #endif + break; + case Circuit::MOSFET: + { + #ifdef DEBUG + cerr << "MOSFET | " << line << endl; + #endif + break; + } + case Circuit::CAPACITOR: + { + #ifdef DEBUG + cerr << "CAPACITOR| " << line << endl; + #endif + Instance* inst = new Capacitor(tokens[0], tokens[1], tokens[2], tokens[3]); + if (inSubckt) { // must add instance to current subckt + sub->addInstance(inst); + } else { // instance is added to top-level circuit + circuit->addInstance(inst); + } + break; + } + case Circuit::RESISTOR: + { + #ifdef DEBUG + cerr << "RESISTOR | " << line << endl; + #endif + Instance* inst = new Resistor(tokens[0], tokens[1], tokens[2], tokens[3]); + if (inSubckt) { // must add instance to current subckt + sub->addInstance(inst); + } else { // instance is added to top-level circuit + circuit->addInstance(inst); + } + break; + } + case Circuit::DIODE: + #ifdef DEBUG + cerr << "DIODE | " << line << endl; + #endif + break; + case Circuit::UNDEF: + #ifdef DEBUG + cerr << "UNDEF | " << line << endl; + #endif + break; + default: + { + ostringstream oss; + oss << type; + throw SpiceException("SPICE::Circuit::readFromFile: Unkown LineType "+oss.str()+" !"); + } + } + // prepare to process next line + type = getNextFullLineType(spfile, line); + } + spfile.close(); + return circuit; +} + +void Circuit::writeToFile(const string& filename) { + cerr << "writing file: " << filename << endl; + std::ofstream spfile(filename.c_str()); + if (!spfile) + throw SpiceException("SPICE::Circuit::writeToFile: Cannot open file: "+filename+" !"); + spfile << _title << endl; + spfile << "* generated with VLSISAPD - SPICE parser/driver" << endl << endl; + + if (_includes.size()) { + spfile << "* includes" << endl; + for (size_t i = 0 ; i < _includes.size() ; i++) + spfile << ".INCLUDE " << _includes[i] << endl; + spfile << endl; + } + + if ( _libraries.size()) { + spfile << "* libraries" << endl; + for (size_t i = 0 ; i < _libraries.size() ; i++) + spfile << ".LIB " << _libraries[i].first << " " << _libraries[i].second << endl; + spfile << endl; + } + + if (_parameters.size()) { + spfile << "* parameters" << endl; + for (map::const_iterator it = _parameters.begin() ; it != _parameters.end() ; ++it) + spfile << ".PARAM " << (*it).first << "=" << (*it).second << endl; + spfile << endl; + } + + if (_options.size()) { + spfile << "* options" << endl; + for (map::const_iterator it = _options.begin() ; it != _options.end() ; ++it) { + spfile << ".OPTION " << (*it).first; + if ((*it).second != "") + spfile << "=" << (*it).second; + spfile << endl; + } + spfile << endl; + } + + if (_sources.size()) { + spfile << "* sources" << endl; + for (size_t i = 0 ; i < _sources.size() ; i++) { + Source* s = _sources[i]; + spfile << s->getName() << " " << s->getPositive() << " " << s->getNegative() << " " << s->getValue() << endl; + } + spfile << endl; + } + + if (_subckts.size()) { + spfile << "* subckts" << endl; + for (size_t i = 0 ; i < _subckts.size() ; i++) { + Subckt* sub = _subckts[i]; + spfile << ".SUBCKT " << sub->getName(); + for (size_t j = 0 ; j < sub->getInterfaces().size() ; j++) + spfile << " " << sub->getInterfaces()[j]; + spfile << endl; + for (size_t j = 0 ; j < sub->getInstances().size() ; j++) { + Instance* inst = sub->getInstances()[j]; + writeInstance(spfile, inst); + } + spfile << ".ENDS " << sub->getName()<< endl << endl; // to separate consecutive subckts + } + } + + if (_instances.size()) { + spfile << "* instances" << endl; + for (size_t i = 0 ; i < _instances.size() ; i++) { + Instance* inst = _instances[i]; + writeInstance(spfile, inst); + } + } + + spfile << ".END" << endl; + spfile.close(); +} + +// this method ignores comment/empty lines and concatenates "+ lines" +Circuit::LineType Circuit::getNextFullLineType(std::ifstream& file, string& fullLine) { + string line; + Circuit::LineType type = getNextLineType(file, line); + while ((type == Circuit::COMMENT) || (type == Circuit::EMPTY)) { + type = getNextLineType(file, line); + } + Circuit::LineType baseType = type; // non empty/comment line + fullLine = string(line); + int lineStart = file.tellg(); + type = getNextLineType(file, line); + while ((type == Circuit::CONTINUE) || (type == Circuit::EMPTY) || (type == Circuit::COMMENT)) { + if (type == Circuit::CONTINUE) { + fullLine += line.erase(0,1); // remove the '+' sign + } else { +// // it is a comment/empty line + } + lineStart = file.tellg(); + type = getNextLineType(file, line); + } +// + file.seekg(lineStart); // unget last line which is needed (at worst we wil reread a comment) + return baseType; +} + +Circuit::LineType Circuit::getNextLineType(std::ifstream& file, string& line) { + if (getline(file, line)) { + if (lineBeginsWith(line, "*")) return Circuit::COMMENT; + else if (lineBeginsWith(line, ".include")) return Circuit::INCLUDE; + else if (lineBeginsWith(line, ".lib")) return Circuit::LIBRARY; + else if (lineBeginsWith(line, ".param")) return Circuit::PARAM; + else if (lineBeginsWith(line, ".option")) return Circuit::OPTION; + else if (lineBeginsWith(line, ".subckt")) return Circuit::SUBCKT; + else if (lineBeginsWith(line, ".ends")) return Circuit::ENDSUB; + else if (lineBeginsWith(line, ".end")) return Circuit::END; + else if (lineBeginsWith(line, "+")) return Circuit::CONTINUE; + else if (lineBeginsWith(line, "x")) return Circuit::INSTANCE; + else if (lineBeginsWith(line, "m")) return Circuit::MOSFET; + else if (lineBeginsWith(line, "v")) return Circuit::VOLTAGE; + else if (lineBeginsWith(line, "i")) return Circuit::CURRENT; + else if (lineBeginsWith(line, "c")) return Circuit::CAPACITOR; + else if (lineBeginsWith(line, "r")) return Circuit::RESISTOR; + else if (lineBeginsWith(line, "d")) return Circuit::DIODE; + else if (line == "") return Circuit::EMPTY; + else return Circuit::UNDEF; + } else { + return Circuit::ENDFILE; + } +} + +bool Circuit::lineBeginsWith(string line, string substr) { + int size = substr.size(); + string substrU (substr); + transform(substrU.begin(), substrU.end(), substrU.begin(), ::toupper); + if((!line.compare(0, size, substr)) or (!line.compare(0, size, substrU))) + return true; + return false; +} + +void Circuit::cleanMultipleSpaces(string& line) { + size_t it; + + // first replace all tabs with spaces + string search = "\t"; + while ((it = line.find(search)) != string::npos) + line.replace(it, 1, " "); + + // then remove multiple spaces + search = " "; + while ((it = line.find(search)) != string::npos) + line.erase(it, 1); + + // finally replace ' = ' with '=' in two steps + search = " ="; + while ((it = line.find(search)) != string::npos) + line.erase(it, 1); + search = "= "; + while ((it = line.find(search)) != string::npos) + line.erase(it+1, 1); +} + +void Circuit::tokenize(string line, vector& tokens) { + cleanMultipleSpaces(line); + istringstream iss(line); + copy(istream_iterator(iss), istream_iterator(), back_inserter >(tokens)); +} + +void Circuit::parametrize(string param, string& name, string& value) { + size_t it = param.find("="); + if (it == string::npos) { + name = param; + value = ""; + } else { + name = param.substr(0, it); + value = param.substr(it+1, param.size()-it); + } + cerr << "parametrize: " << name << "=" << value << endl; +} + +void Circuit::writeInstance(std::ofstream& file, Instance* inst) { + if (dynamic_cast(inst)) { + } else if (dynamic_cast(inst)) { + Capacitor* capa = static_cast(inst); + file << capa->getName() << " " << capa->getPositive() << " " << capa->getNegative() << " " << capa->getValue(); + } else if (dynamic_cast(inst)) { + Resistor* res = static_cast(inst); + file << res->getName() << " " << res->getFirst() << " " << res->getSecond() << " " << res->getValue(); + } else { + file << inst->getName(); + for (vector::const_iterator it = inst->getConnectors().begin() ; it != inst->getConnectors().end() ; ++it) { + file << " " << (*it); + } + file << " " << inst->getModel(); + int j=0; + for (map::const_iterator it = inst->getParameters().begin() ; it != inst->getParameters().end() ; ++it, j++) { + if (j%6 == 0) + file << endl << "+"; + file << " " << (*it).first << "=" << (*it).second; + } + } + file << endl << endl; // to separate to consecutive instances +} +} diff --git a/vlsisapd/src/spice/src/Instance.cpp b/vlsisapd/src/spice/src/Instance.cpp new file mode 100644 index 00000000..05162742 --- /dev/null +++ b/vlsisapd/src/spice/src/Instance.cpp @@ -0,0 +1,29 @@ +#include +using namespace std; + +#include "vlsisapd/spice/Instance.h" +#include "vlsisapd/spice/Value.h" + +namespace SPICE { +Instance::Instance(string name, string model) : _name(name), _model(model) +{} + +string Instance::getParameterValue(string name) { + map::iterator pit = _parameters.find(name); + if (pit != _parameters.end()) { + return (*pit).second; + } else { + return ""; + } +} + +void Instance::addParameter(string name, string value) { + map::iterator pit = _parameters.find(name); + if (pit != _parameters.end()) { + cerr << "[WARNING] SPICE:: Cannot add parameter " << name + << " to instance " << _name << " since it already exists." << endl; + return; + } + _parameters[name] = value; +} +} diff --git a/vlsisapd/src/spice/src/Value.cpp b/vlsisapd/src/spice/src/Value.cpp new file mode 100644 index 00000000..04c5885f --- /dev/null +++ b/vlsisapd/src/spice/src/Value.cpp @@ -0,0 +1,69 @@ +#include +#include +using namespace std; + +#include "vlsisapd/spice/Value.h" +#include "vlsisapd/spice/SpiceException.h" + +namespace SPICE { +Value::Value(double value, Value::Unit unit): _value(value), _unit(unit) +{} + +double Value::getUnitAsDouble(Value::Unit unit) { + switch(unit) { + case Value::T: return 1e12; // T + case Value::G: return 1e9; // G + case Value::Meg: return 1e6; // Meg + case Value::K: return 1e3; // K + case Value::Unity: return 1; // Unity + case Value::m: return 1e-3; // m + case Value::u: return 1e-6; // u + case Value::n: return 1e-9; // n + case Value::p: return 1e-12; // p + case Value::f: return 1e-15; // f + default: throw SpiceException("SPICE:: Unknown unit for Value !"); + } +} + +double Value::getConvertedDouble(Value::Unit unit) { + return _value * (getUnitAsDouble(_unit)/getUnitAsDouble(unit)); +} + +void Value::print() { + switch(_unit) { + case Value::T: cerr << _value << " T" << endl; break; + case Value::G: cerr << _value << " G" << endl; break; + case Value::Meg: cerr << _value << " Meg" << endl; break; + case Value::K: cerr << _value << " K" << endl; break; + case Value::m: cerr << _value << " m" << endl; break; + case Value::u: cerr << _value << " u" << endl; break; + case Value::n: cerr << _value << " n" << endl; break; + case Value::p: cerr << _value << " p" << endl; break; + case Value::f: cerr << _value << " f" << endl; break; + default: cerr << _value << endl; break; + } +} + +Value* Value::string2Value(string str) { + size_t it = str.find_last_of("0123456789"); + if (it == string::npos) + throw SpiceException("SPICE::Value::string2Value: Could not correctly identify value."); + istringstream iss; + iss.str(str.substr(0, it+1)); + double val; + iss >> val; + string unit = str.substr(it+1); + Value* value= NULL; + if (!unit.compare(0, 1, "T") ) value = new Value(val, Value::T); + else if (!unit.compare(0, 1, "G") ) value = new Value(val, Value::G); + else if (!unit.compare(0, 3, "Meg")) value = new Value(val, Value::Meg); + else if (!unit.compare(0, 1, "K") ) value = new Value(val, Value::K); + else if (!unit.compare(0, 1, "m") ) value = new Value(val, Value::m); + else if (!unit.compare(0, 1, "u") ) value = new Value(val, Value::u); + else if (!unit.compare(0, 1, "n") ) value = new Value(val, Value::n); + else if (!unit.compare(0, 1, "p") ) value = new Value(val, Value::p); + else if (!unit.compare(0, 1, "f") ) value = new Value(val, Value::f); + else value = new Value(val, Value::Unity); + return value; +} +} diff --git a/vlsisapd/src/spice/src/vlsisapd/spice/Circuit.h b/vlsisapd/src/spice/src/vlsisapd/spice/Circuit.h new file mode 100644 index 00000000..5c956631 --- /dev/null +++ b/vlsisapd/src/spice/src/vlsisapd/spice/Circuit.h @@ -0,0 +1,108 @@ +#ifndef __SPICE_CIRCUIT_H +#define __SPICE_CIRCUIT_H + +#include +#include +#include +class ifstream; + +namespace SPICE { +class Value; +class Subckt; +class Instance; +class Source; + +class Circuit { + public: + enum LineType { ENDFILE = -2 // means the getline failed : should only happens at end of file + , UNDEF = -1 // not recognized + , EMPTY = 0 // empty line + , COMMENT = 1 // begins with '*...' + , INCLUDE = 2 // begins with '.include ' + , LIBRARY = 3 // begins with '.lib ' + , OPTION = 4 // begins with '.option ' + , PARAM = 5 // begins with '.param ' + , SUBCKT = 6 // begins with '.subckt ' + , CONTINUE = 7 // begins with '+ ' + , ENDSUB = 8 // begins with '.ends ' + , END = 9 // begins with '.end ' + + , INSTANCE = 20 // begins with 'x...' + , MOSFET = 21 // begins with 'm...' + , CAPACITOR = 22 // begins with 'c...' + , RESISTOR = 23 // begins with 'r...' + , INDUCTOR = 24 // begins with 'l...' + , DIODE = 25 // begins with 'd...' + + , VOLTAGE = 30 // begins with 'v...' voltage source + , CURRENT = 31 // begins with 'i...' current source + }; + + typedef std::pair string_pair; + typedef std::vector strpair_vector; + typedef std::vector string_vector; + typedef std::map strings_map; + private: + unsigned _line; + std::string _title; + string_vector _includes; + strpair_vector _libraries; + strings_map _options; + strings_map _parameters; + std::vector _subckts; + std::vector _instances; + std::vector _sources; + + public: + Circuit(): _line(0), _title(""), _includes(), _libraries(), _options(), _parameters(), _subckts(), _instances() {}; + ~Circuit() {}; + + inline std::string getTitle(); + inline const string_vector& getIncludes(); + inline const strpair_vector& getLibraries(); + inline const strings_map& getOptions(); + inline const strings_map& getParameters(); + inline const std::vector& getSubckts(); + inline const std::vector& getInstances(); + inline const std::vector& getSources(); + + + inline void setTitle (std::string); + inline void addInclude (std::string); + inline void addLibrary (std::string file, std::string type = ""); + inline void addInstance(Instance*); + inline void addSource (Source*); + + void addOption (std::string, std::string); + void addParameter(std::string, std::string); + Subckt* addSubckt (std::string); + + static Circuit* readFromFile(const std::string&); + void writeToFile (const std::string&); + + private: + static Circuit::LineType getNextLineType (std::ifstream& file, std::string& line); + static Circuit::LineType getNextFullLineType(std::ifstream& file, std::string& fullLine); + static bool lineBeginsWith (std::string line, std::string substr); + static void cleanMultipleSpaces(std::string&); + static void tokenize (std::string line, std::vector& tokens); + static void parametrize (std::string param, std::string& name, std::string& value); + static void writeInstance (std::ofstream& file, Instance* inst); + +}; +inline std::string Circuit::getTitle() { return _title; } +inline const Circuit::string_vector& Circuit::getIncludes() { return _includes; } +inline const Circuit::strpair_vector& Circuit::getLibraries() { return _libraries; } +inline const Circuit::strings_map& Circuit::getOptions() { return _options; } +inline const Circuit::strings_map& Circuit::getParameters() { return _parameters; } +inline const std::vector& Circuit::getSubckts() { return _subckts; } +inline const std::vector& Circuit::getInstances() { return _instances; } +inline const std::vector& Circuit::getSources() { return _sources; } + +inline void Circuit::setTitle (std::string title) { _title = title; } +inline void Circuit::addInclude (std::string include) { _includes.push_back(include); } +inline void Circuit::addLibrary (std::string file, std::string type) { _libraries.push_back(Circuit::string_pair(file, type)); } +inline void Circuit::addInstance(Instance* inst) { _instances.push_back(inst); } +inline void Circuit::addSource (Source* source) {_sources.push_back(source); } +} +#endif diff --git a/vlsisapd/src/spice/src/vlsisapd/spice/Instance.h b/vlsisapd/src/spice/src/vlsisapd/spice/Instance.h new file mode 100644 index 00000000..4fb42c00 --- /dev/null +++ b/vlsisapd/src/spice/src/vlsisapd/spice/Instance.h @@ -0,0 +1,43 @@ +#ifndef __SPICE_INSTANCE_H +#define __SPICE_INSTANCE_H + + +#include +#include +#include + +namespace SPICE { +class Value; + +class Instance { + protected: + std::string _name; + std::string _model; + std::vector _connectors; + std::map _parameters; + + public: + Instance(std::string name, std::string model); + virtual ~Instance() {}; + + inline std::string getName(); + inline std::string getModel(); + inline const std::vector& getConnectors(); + inline const std::map& getParameters(); + + std::string getParameterValue(std::string name); + + inline void addConnector(std::string connector); + + void addParameter(std::string name, std::string value); + +}; + +inline std::string Instance::getName() { return _name; } +inline std::string Instance::getModel() { return _model; } +inline const std::vector& Instance::getConnectors() { return _connectors; } +inline const std::map& Instance::getParameters() { return _parameters; } + +inline void Instance::addConnector(std::string connector) { _connectors.push_back(connector); } // no verification : same net can be used on several interfaces +} +#endif diff --git a/vlsisapd/src/spice/src/vlsisapd/spice/Instances.h b/vlsisapd/src/spice/src/vlsisapd/spice/Instances.h new file mode 100644 index 00000000..f4d77058 --- /dev/null +++ b/vlsisapd/src/spice/src/vlsisapd/spice/Instances.h @@ -0,0 +1,69 @@ +#ifndef __SPICE_INSTANCES_H +#define __SPICE_INSTANCES_H + +#include + +#include "vlsisapd/spice/Instance.h" + +namespace SPICE { +class Mosfet : public Instance { + public: + Mosfet(std::string name, std::string nd, std::string ng, std::string ns, std::string nb, std::string model) + : Instance(name, model), _nd(nd), _ng(ng), _ns(ns), _nb(nb) {} + virtual ~Mosfet() {}; + + inline std::string getDrain(); + inline std::string getGrid(); + inline std::string getSource(); + inline std::string getBulk(); + + private: + std::string _nd; + std::string _ng; + std::string _ns; + std::string _nb; +}; +inline std::string Mosfet::getDrain() { return _nd; } +inline std::string Mosfet::getGrid() { return _ng; } +inline std::string Mosfet::getSource() { return _ns; } +inline std::string Mosfet::getBulk() { return _nb; } + +class Resistor : public Instance { + public: + Resistor(std::string name, std::string first, std::string second, std::string value) + : Instance(name, ""), _first(first), _second(second), _value(value) {} + virtual ~Resistor() {}; + + inline std::string getFirst(); + inline std::string getSecond(); + inline std::string getValue(); + + private: + std::string _first; + std::string _second; + std::string _value; +}; +inline std::string Resistor::getFirst() { return _first; } +inline std::string Resistor::getSecond() { return _second; } +inline std::string Resistor::getValue() { return _value; } + +class Capacitor : public Instance { + public: + Capacitor(std::string name, std::string pos, std::string neg, std::string value) + : Instance(name, ""), _pos(pos), _neg(neg), _value(value) {} + virtual ~Capacitor() {}; + + inline std::string getPositive(); + inline std::string getNegative(); + inline std::string getValue(); + + private: + std::string _pos; + std::string _neg; + std::string _value; +}; +inline std::string Capacitor::getPositive() { return _pos; }; +inline std::string Capacitor::getNegative() { return _neg; }; +inline std::string Capacitor::getValue() { return _value; }; +} +#endif diff --git a/vlsisapd/src/spice/src/vlsisapd/spice/Sources.h b/vlsisapd/src/spice/src/vlsisapd/spice/Sources.h new file mode 100644 index 00000000..42b53c3d --- /dev/null +++ b/vlsisapd/src/spice/src/vlsisapd/spice/Sources.h @@ -0,0 +1,39 @@ +#ifndef __SPICE_SOURCES_H +#define __SPICE_SOURCES_H + +namespace SPICE { +class Source { + private: + std::string _name; + std::string _pos; + std::string _neg; + std::string _value; + + protected: + Source(std::string name, std::string pos, std::string neg, std::string value): _name(name), _pos(pos), _neg(neg), _value(value) {} + virtual ~Source() {} + + public: + inline std::string getName(); + inline std::string getPositive(); + inline std::string getNegative(); + inline std::string getValue(); +}; +inline std::string Source::getName() { return _name; } +inline std::string Source::getPositive() { return _pos; } +inline std::string Source::getNegative() { return _neg; } +inline std::string Source::getValue() { return _value; } + +class Voltage: public Source { + public: + Voltage(std::string name, std::string pos, std::string neg, std::string value): Source(name, pos, neg, value) {} + ~Voltage() {} +}; + +class Current: public Source { + public: + Current(std::string name, std::string pos, std::string neg, std::string value): Source(name, pos, neg, value) {} + ~Current() {} +}; +} +#endif diff --git a/vlsisapd/src/spice/src/vlsisapd/spice/SpiceException.h b/vlsisapd/src/spice/src/vlsisapd/spice/SpiceException.h new file mode 100644 index 00000000..9c5a0687 --- /dev/null +++ b/vlsisapd/src/spice/src/vlsisapd/spice/SpiceException.h @@ -0,0 +1,20 @@ +#ifndef __SPICE_EXCEPTION_H +#define __SPICE_EXCEPTION_H + +#include +#include + +namespace SPICE { +class SpiceException { + public: + SpiceException(const std::string& what) throw() : _what(what) {} + virtual const char* what() const throw() { return _what.c_str(); } + virtual ~SpiceException() throw() {} + + private: + std::string _what; +}; +} // namespace +#endif + + diff --git a/vlsisapd/src/spice/src/vlsisapd/spice/Subckt.h b/vlsisapd/src/spice/src/vlsisapd/spice/Subckt.h new file mode 100644 index 00000000..d23d0c41 --- /dev/null +++ b/vlsisapd/src/spice/src/vlsisapd/spice/Subckt.h @@ -0,0 +1,35 @@ +#ifndef __SPICE_SUBCKT_H +#define __SPICE_SUBCKT_H + + +#include +#include + +namespace SPICE { +class Instance; + +class Subckt { + private: + std::string _name; + std::vector _interfaces; + std::vector _instances; + + public: + Subckt(std::string name): _name(name), _interfaces(), _instances() {} + ~Subckt() {} + + inline std::string getName(); + inline std::vector& getInterfaces(); + inline std::vector& getInstances(); + + inline void addInterface(std::string); + inline void addInstance (Instance*); +}; +inline std::string Subckt::getName() { return _name; } +inline std::vector& Subckt::getInterfaces() { return _interfaces; } +inline std::vector& Subckt::getInstances() { return _instances; } + +inline void Subckt::addInterface(std::string name) { _interfaces.push_back(name); } +inline void Subckt::addInstance(Instance* inst) { _instances.push_back(inst); } +} +#endif diff --git a/vlsisapd/src/spice/src/vlsisapd/spice/Value.h b/vlsisapd/src/spice/src/vlsisapd/spice/Value.h new file mode 100644 index 00000000..040c5df3 --- /dev/null +++ b/vlsisapd/src/spice/src/vlsisapd/spice/Value.h @@ -0,0 +1,41 @@ +#ifndef __SPICE_VALUE_H +#define __SPICE_VALUE_H + +#include + +namespace SPICE { +class Value { + public: + enum Unit { T = 0 + , G = 1 + , Meg = 2 + , K = 3 + , Unity = 4 + , m = 5 + , u = 6 + , n = 7 + , p = 8 + , f = 9 + }; + + private: + double _value; + Unit _unit; + + public: + Value(double value, Unit unit); + virtual ~Value() {}; + + inline double getDouble(); + inline Unit getUnit(); + static double getUnitAsDouble(Unit unit); + + double getConvertedDouble(Unit unit); + void print(); + + static Value* string2Value(std::string); +}; +inline double Value::getDouble() { return _value; } +inline Value::Unit Value::getUnit() { return _unit; } +} +#endif