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
This commit is contained in:
parent
e2f77eb7ee
commit
2f17ce7b37
|
@ -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)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ADD_SUBDIRECTORY(src)
|
|
@ -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)
|
|
@ -0,0 +1,435 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
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<string, string>::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<string, string>::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<string> 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<string, string>::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<string, string>::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<string>& tokens) {
|
||||
cleanMultipleSpaces(line);
|
||||
istringstream iss(line);
|
||||
copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter<vector<string> >(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<Mosfet*>(inst)) {
|
||||
} else if (dynamic_cast<Capacitor*>(inst)) {
|
||||
Capacitor* capa = static_cast<Capacitor*>(inst);
|
||||
file << capa->getName() << " " << capa->getPositive() << " " << capa->getNegative() << " " << capa->getValue();
|
||||
} else if (dynamic_cast<Resistor*>(inst)) {
|
||||
Resistor* res = static_cast<Resistor*>(inst);
|
||||
file << res->getName() << " " << res->getFirst() << " " << res->getSecond() << " " << res->getValue();
|
||||
} else {
|
||||
file << inst->getName();
|
||||
for (vector<string>::const_iterator it = inst->getConnectors().begin() ; it != inst->getConnectors().end() ; ++it) {
|
||||
file << " " << (*it);
|
||||
}
|
||||
file << " " << inst->getModel();
|
||||
int j=0;
|
||||
for (map<string, string>::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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#include <iostream>
|
||||
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<string, string>::iterator pit = _parameters.find(name);
|
||||
if (pit != _parameters.end()) {
|
||||
return (*pit).second;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::addParameter(string name, string value) {
|
||||
map<string, string>::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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#include <iostream>
|
||||
#include <sstream>
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
#ifndef __SPICE_CIRCUIT_H
|
||||
#define __SPICE_CIRCUIT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
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<std::string, std::string> string_pair;
|
||||
typedef std::vector<string_pair> strpair_vector;
|
||||
typedef std::vector<std::string> string_vector;
|
||||
typedef std::map<std::string, std::string> strings_map;
|
||||
private:
|
||||
unsigned _line;
|
||||
std::string _title;
|
||||
string_vector _includes;
|
||||
strpair_vector _libraries;
|
||||
strings_map _options;
|
||||
strings_map _parameters;
|
||||
std::vector<Subckt*> _subckts;
|
||||
std::vector<Instance*> _instances;
|
||||
std::vector<Source*> _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<Subckt*>& getSubckts();
|
||||
inline const std::vector<Instance*>& getInstances();
|
||||
inline const std::vector<Source*>& 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<std::string>& 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<Subckt*>& Circuit::getSubckts() { return _subckts; }
|
||||
inline const std::vector<Instance*>& Circuit::getInstances() { return _instances; }
|
||||
inline const std::vector<Source*>& 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
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef __SPICE_INSTANCE_H
|
||||
#define __SPICE_INSTANCE_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace SPICE {
|
||||
class Value;
|
||||
|
||||
class Instance {
|
||||
protected:
|
||||
std::string _name;
|
||||
std::string _model;
|
||||
std::vector<std::string> _connectors;
|
||||
std::map<std::string, std::string> _parameters;
|
||||
|
||||
public:
|
||||
Instance(std::string name, std::string model);
|
||||
virtual ~Instance() {};
|
||||
|
||||
inline std::string getName();
|
||||
inline std::string getModel();
|
||||
inline const std::vector<std::string>& getConnectors();
|
||||
inline const std::map<std::string, std::string>& 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<std::string>& Instance::getConnectors() { return _connectors; }
|
||||
inline const std::map<std::string, std::string>& 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
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef __SPICE_INSTANCES_H
|
||||
#define __SPICE_INSTANCES_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#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
|
|
@ -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
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef __SPICE_EXCEPTION_H
|
||||
#define __SPICE_EXCEPTION_H
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef __SPICE_SUBCKT_H
|
||||
#define __SPICE_SUBCKT_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace SPICE {
|
||||
class Instance;
|
||||
|
||||
class Subckt {
|
||||
private:
|
||||
std::string _name;
|
||||
std::vector<std::string> _interfaces;
|
||||
std::vector<Instance*> _instances;
|
||||
|
||||
public:
|
||||
Subckt(std::string name): _name(name), _interfaces(), _instances() {}
|
||||
~Subckt() {}
|
||||
|
||||
inline std::string getName();
|
||||
inline std::vector<std::string>& getInterfaces();
|
||||
inline std::vector<Instance*>& getInstances();
|
||||
|
||||
inline void addInterface(std::string);
|
||||
inline void addInstance (Instance*);
|
||||
};
|
||||
inline std::string Subckt::getName() { return _name; }
|
||||
inline std::vector<std::string>& Subckt::getInterfaces() { return _interfaces; }
|
||||
inline std::vector<Instance*>& 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
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef __SPICE_VALUE_H
|
||||
#define __SPICE_VALUE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
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
|
Loading…
Reference in New Issue