739 lines
31 KiB
C++
739 lines
31 KiB
C++
/*
|
|
* Circuit.cpp
|
|
* openChams
|
|
*
|
|
* Created by damien dupuis on 18/12/09.
|
|
* Copyright 2009 UPMC / LIP6. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <algorithm>
|
|
using namespace std;
|
|
|
|
#include "Circuit.h"
|
|
#include "OpenChamsException.h"
|
|
|
|
namespace {
|
|
template<class T> T getValue(xmlChar* str) {
|
|
std::istringstream iss;
|
|
iss.str((const char*) str);
|
|
T res;
|
|
iss >> res;
|
|
return res;
|
|
}
|
|
}
|
|
|
|
namespace OpenChams {
|
|
|
|
static bool readCircuitParametersDone = false;
|
|
static bool readNetListDone = false;
|
|
static bool readInstancesDone = false;
|
|
static bool readNetsDone = false;
|
|
static bool readSchematicDone = false;
|
|
static bool readSizingDone = false;
|
|
|
|
Circuit::Circuit(Name name, Name techno) : _name(name), _techno(techno), _netlist(NULL), _schematic(NULL) {
|
|
readCircuitParametersDone = false;
|
|
readNetListDone = false;
|
|
readInstancesDone = false;
|
|
readNetsDone = false;
|
|
readSchematicDone = false;
|
|
readSizingDone = false;
|
|
}
|
|
|
|
// USEFUL //
|
|
void Circuit::check_uppercase(string& str, vector<string>& compares, string message) {
|
|
transform(str.begin(), str.end(), str.begin(), ::toupper);
|
|
bool equal = false;
|
|
for (size_t i = 0 ; i < compares.size() ; i++) {
|
|
if (str == compares[i]) {
|
|
equal = true;
|
|
}
|
|
}
|
|
if (!equal) {
|
|
throw OpenChamsException(message);
|
|
}
|
|
}
|
|
|
|
void Circuit::check_lowercase(string& str, vector<string>& compares, string message) {
|
|
transform(str.begin(), str.end(), str.begin(), ::tolower);
|
|
bool equal = false;
|
|
for (size_t i = 0 ; i < compares.size() ; i++) {
|
|
if (str == compares[i]) {
|
|
equal = true;
|
|
}
|
|
}
|
|
if (!equal) {
|
|
throw OpenChamsException(message);
|
|
}
|
|
}
|
|
|
|
Name Circuit::readParameter(xmlNode* node, double& value) {
|
|
xmlChar* paramNameC = xmlGetProp(node, (xmlChar*)"name");
|
|
xmlChar* valueC = xmlGetProp(node, (xmlChar*)"value");
|
|
if (paramNameC && valueC) {
|
|
Name name((const char*)paramNameC);
|
|
value = ::getValue<double>(valueC);
|
|
return name;
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'parameter' node must have 'name' and 'value' properties.");
|
|
}
|
|
}
|
|
|
|
Name Circuit::readParameterEq(xmlNode* node, string& eqStr) {
|
|
xmlChar* paramNameC = xmlGetProp(node, (xmlChar*)"name");
|
|
xmlChar* equationC = xmlGetProp(node, (xmlChar*)"equation");
|
|
if (paramNameC && equationC) {
|
|
Name name((const char*)paramNameC);
|
|
eqStr = string ((const char*)equationC);
|
|
return name;
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'parameterEq' node must have 'name' and 'equation' properties.");
|
|
}
|
|
}
|
|
|
|
Name Circuit::readConnector(xmlNode* node) {
|
|
xmlChar* connectorNameC = xmlGetProp(node, (xmlChar*)"name");
|
|
if (connectorNameC) {
|
|
Name name((const char*)connectorNameC);
|
|
return name;
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'connector' node must have 'name' property.");
|
|
//return Name("");
|
|
}
|
|
}
|
|
|
|
// CIRCUIT //
|
|
void Circuit::readCircuitParameters(xmlNode* node) {
|
|
if (readCircuitParametersDone) {
|
|
cerr << "[WARNING] Only one 'parameters' node is allowed in circuit, others will be ignored." << endl;
|
|
return;
|
|
}
|
|
if (node->type == XML_ELEMENT_NODE && node->children) {
|
|
for (xmlNode* paramNode = node->children ; paramNode ; paramNode = paramNode->next) {
|
|
if (paramNode->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(paramNode->name, (xmlChar*)"parameter")) {
|
|
double value = 0.0;
|
|
Name paramName = readParameter(paramNode, value);
|
|
if (paramName == Name("")) return; // error
|
|
addParameter(paramName, value);
|
|
} else if (xmlStrEqual(paramNode->name, (xmlChar*)"parameterEq")) {
|
|
string eqStr = "";
|
|
Name paramName = readParameterEq(paramNode, eqStr);
|
|
if (paramName == Name("")) return; // error
|
|
addParameter(paramName, eqStr);
|
|
} else {
|
|
cerr << "[WARNING] Only 'parameter' and 'parameterEq' nodes are allowed under 'parameters' node." << endl;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
readCircuitParametersDone = true;
|
|
}
|
|
|
|
// NETLIST //
|
|
void Circuit::readNetList(xmlNode* node) {
|
|
if (readNetListDone) {
|
|
cerr << "[WARNING] Only one 'netlist' node is allowed in circuit, others will be ignored." << endl;
|
|
return;
|
|
}
|
|
Netlist* netlist = new Netlist(this);
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"instances")) {
|
|
readInstances(node, netlist);
|
|
} else if (xmlStrEqual(node->name, (xmlChar*)"nets")) {
|
|
readNets(node, netlist);
|
|
} else {
|
|
cerr << "[WARNING] Only 'instances' and 'nets' nodes are allowed in 'netlist', others will be ignored." << endl;
|
|
}
|
|
}
|
|
}
|
|
readNetListDone = true;
|
|
_netlist = netlist;
|
|
}
|
|
|
|
// INSTANCES //
|
|
void Circuit::readInstances(xmlNode* node, Netlist* netlist) {
|
|
if (readInstancesDone) {
|
|
cerr << "[WARNING] Only one 'instances' node is allowed in 'netlist', others will be ignored." << endl;
|
|
return;
|
|
}
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"instance")) {
|
|
Instance* inst =readInstance(node, netlist);
|
|
if (inst)
|
|
netlist->addInstance(inst);
|
|
} else {
|
|
cerr << "[WARNING] Only 'instance' nodes are allowed in 'instances', others will be ignored." << endl;
|
|
}
|
|
}
|
|
}
|
|
readInstancesDone = true;
|
|
}
|
|
|
|
Instance* Circuit::readInstance(xmlNode* node, Netlist* netlist) {
|
|
xmlChar* iNameC = xmlGetProp(node, (xmlChar*)"name");
|
|
xmlChar* iModelC = xmlGetProp(node, (xmlChar*)"model");
|
|
xmlChar* iMOSC = xmlGetProp(node, (xmlChar*)"mostype");
|
|
xmlChar* iSBCC = xmlGetProp(node, (xmlChar*)"sourceBulkConnected");
|
|
Instance* inst = NULL;
|
|
if (iNameC && iModelC && iMOSC && iSBCC) {
|
|
Name instanceName((const char*)iNameC);
|
|
Name modelName((const char*)iModelC);
|
|
string mosStr((const char*)iMOSC);
|
|
string mosComp[2] = {"NMOS", "PMOS"};
|
|
vector<string> mosComps (mosComp, mosComp+2);
|
|
check_uppercase(mosStr, mosComps, "[ERROR] In 'instance', 'mostype' must be 'NMOS' or 'PMOS'.");
|
|
string sourceBulkStr((const char*)iSBCC);
|
|
string sbcComp[4] = {"true", "false", "on", "off"};
|
|
vector<string> sbcComps(sbcComp, sbcComp+4);
|
|
check_lowercase(sourceBulkStr, sbcComps, "[ERROR] In 'instance', 'sourceBulkConnected' must 'true', 'false', 'on' or 'off'.");
|
|
bool sourceBulkConnected = ((sourceBulkStr == "true") || (sourceBulkStr == "on")) ? true : false;
|
|
inst = new Instance(instanceName, modelName, Name(mosStr), sourceBulkConnected, netlist);
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'instance' node must have 'name', 'model', 'mostype' and 'sourceBulkConnected' properties.");
|
|
//return inst;
|
|
}
|
|
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"connectors")) {
|
|
readInstanceConnectors(node, inst);
|
|
} else if (xmlStrEqual(node->name, (xmlChar*)"parameters")) {
|
|
readInstanceParameters(node, inst);
|
|
} else if (xmlStrEqual(node->name, (xmlChar*)"transistors")) {
|
|
readInstanceTransistors(node, inst);
|
|
} else {
|
|
//cerr << "[WARNING] Only 'parameters' node is allowed in 'instance', others will be ignored." << endl;
|
|
cerr << "[WARNING] Only 'conectors', 'transistors' and 'parameters' nodes are allowed in 'instance', others will be ignored." << endl;
|
|
}
|
|
}
|
|
}
|
|
return inst;
|
|
}
|
|
|
|
void Circuit::readInstanceConnectors(xmlNode* node, Instance* inst) {
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"connector")) {
|
|
Name connectorName = readConnector(node);
|
|
if (connectorName == Name("")) return; // error
|
|
inst->addConnector(connectorName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Circuit::readInstanceParameters(xmlNode* node, Instance* inst) {
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"parameter")) {
|
|
double value = 0.0;
|
|
Name paramName = readParameter(node, value);
|
|
if (paramName == Name("")) return; // error
|
|
inst->addParameter(paramName, value);
|
|
} else if (xmlStrEqual(node->name, (xmlChar*)"parameterEq")) {
|
|
string eqStr = "";
|
|
Name paramName = readParameterEq(node, eqStr);
|
|
if (paramName == Name("")) return; // error
|
|
inst->addParameter(paramName, eqStr);
|
|
} else {
|
|
cerr << "[WARNING] Only 'parameter' and 'parameterEq' nodes are allowed under 'instance' node." << endl;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Circuit::readInstanceTransistors(xmlNode* node, Instance* inst) {
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"transistor")) {
|
|
readTransistor(node, inst);
|
|
} else {
|
|
cerr << "[WARNING] Only 'transistor' nodes are allowed in 'transistors', others will be ignored." << endl;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void Circuit::readTransistor(xmlNode* node, Instance* inst) {
|
|
xmlChar* tNameC = xmlGetProp(node, (xmlChar*)"name");
|
|
Transistor* trans = NULL;
|
|
if (tNameC) {
|
|
Name tName((const char*)tNameC);
|
|
trans = new Transistor(tName, inst);
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'transistor' node must have 'name' property.");
|
|
//return inst;
|
|
}
|
|
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"connection")) {
|
|
readTransistorConnection(node, trans);
|
|
} else if (xmlStrEqual(node->name, (xmlChar*)"parameters")) {
|
|
cerr << "Transistor parameters NOT SUPPORTED YET" << endl;
|
|
} else {
|
|
cerr << "[WARNING] Only 'conectors', 'transistors' and 'parameters' nodes are allowed in 'instance', others will be ignored." << endl;
|
|
}
|
|
}
|
|
}
|
|
inst->addTransistor(trans);
|
|
}
|
|
|
|
void Circuit::readTransistorConnection(xmlNode* node, Transistor* trans) {
|
|
xmlChar* gateC = xmlGetProp(node, (xmlChar*)"gate");
|
|
xmlChar* sourceC = xmlGetProp(node, (xmlChar*)"source");
|
|
xmlChar* drainC = xmlGetProp(node, (xmlChar*)"drain");
|
|
xmlChar* bulkC = xmlGetProp(node, (xmlChar*)"bulk");
|
|
if (gateC && sourceC && drainC && bulkC) {
|
|
Name gateN ((const char*)gateC);
|
|
Name sourceN((const char*)sourceC);
|
|
Name drainN ((const char*)drainC);
|
|
Name bulkN ((const char*)bulkC);
|
|
trans->setGate(gateN);
|
|
trans->setSource(sourceN);
|
|
trans->setDrain(drainN);
|
|
trans->setBulk(bulkN);
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'connection' node must have 'gate', 'source', 'drain' and 'bulk' properties.");
|
|
}
|
|
|
|
}
|
|
|
|
// NETS //
|
|
void Circuit::readNets(xmlNode* node, Netlist* netlist) {
|
|
if (readNetsDone) {
|
|
cerr << "[WARNING] Only one 'nets' node is allowed in 'netlist', others will be ignored." << endl;
|
|
return;
|
|
}
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"net")) {
|
|
readNet(node, netlist);
|
|
} else {
|
|
cerr << "[WARNING] Only 'net' nodes are allowed in 'nets', others will be ignored." << endl;
|
|
}
|
|
}
|
|
}
|
|
readNetsDone = true;
|
|
}
|
|
|
|
Net* Circuit::readNet(xmlNode* node, Netlist* netlist) {
|
|
xmlChar* nNameC = xmlGetProp(node, (xmlChar*)"name");
|
|
xmlChar* nTypeC = xmlGetProp(node, (xmlChar*)"type");
|
|
xmlChar* nExternC = xmlGetProp(node, (xmlChar*)"isExternal");
|
|
Net* net = NULL;
|
|
if (nNameC && nTypeC && nExternC) {
|
|
Name netName((const char*)nNameC);
|
|
string typeStr((const char*)nTypeC);
|
|
string typeComp[3] = {"power", "ground", "logical"};
|
|
vector<string> typeComps(typeComp, typeComp+3);
|
|
check_lowercase(typeStr, typeComps, "[ERROR] In 'net', 'type' must be 'power', 'ground' or 'logical'.");
|
|
string externStr((const char*)nExternC);
|
|
string extComp[4] = {"true", "false", "on", "off"};
|
|
vector<string> extComps(extComp, extComp+4);
|
|
check_lowercase(externStr, extComps, "[ERROR] In 'net', 'isExternal' must be 'true', 'false', 'on' or 'off'.");
|
|
bool isExternal = ((externStr == "true") || (externStr == "on")) ? true : false;
|
|
net = new Net(netName, Name(typeStr), isExternal, netlist);
|
|
netlist->addNet(net);
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'net' node must have 'name', 'type' and 'isExternal' properties.");
|
|
//return net;
|
|
}
|
|
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"connector")) {
|
|
readNetConnector(node, net);
|
|
} else {
|
|
cerr << "[WARNING] Only 'conector' nodes are allowed in 'net', others will be ignored." << endl;
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
return net;
|
|
}
|
|
|
|
void Circuit::readNetConnector(xmlNode* node, Net* net) {
|
|
xmlChar* instanceNameC = xmlGetProp(node, (xmlChar*)"instance");
|
|
xmlChar* connectorNameC = xmlGetProp(node, (xmlChar*)"name");
|
|
if (instanceNameC && connectorNameC) {
|
|
Name iName((const char*)instanceNameC);
|
|
Name cName((const char*)connectorNameC);
|
|
Instance* inst = net->getNetlist()->getInstance(iName);
|
|
if (!inst) {
|
|
string error("[ERROR] no instance named \"");
|
|
error += iName.getString();
|
|
error += "\" in connector of net \"";
|
|
error += net->getName().getString();
|
|
error += "\".";
|
|
throw OpenChamsException(error);
|
|
//return;
|
|
}
|
|
//inst->connect(cName, net->getName());
|
|
net->connectTo(iName, cName);
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'connector' node must have 'instance' and 'name' properties (for net).");
|
|
}
|
|
}
|
|
|
|
// SCHEMATIC //
|
|
void Circuit::readSchematic(xmlNode* node) {
|
|
if (readSchematicDone) {
|
|
cerr << "[WARNING] Only one 'schematic' node is allowed in circuit, others will be ignored." << endl;
|
|
return;
|
|
}
|
|
xmlChar* zoomC = xmlGetProp(node, (xmlChar*)"zoom");
|
|
double zoom = 1.0;
|
|
if (zoomC) {
|
|
zoom = ::getValue<double>(zoomC);
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'schematic' node must have 'zoom' property.");
|
|
}
|
|
|
|
Schematic* schematic = new Schematic(this, zoom);
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"instance")) {
|
|
readInstanceSchematic(node, schematic);
|
|
} else {
|
|
cerr << "[WARNING] Only 'instance' nodes are allowed in 'schematic', others will be ignored." << endl;
|
|
}
|
|
}
|
|
}
|
|
readSchematicDone = true;
|
|
_schematic = schematic;
|
|
}
|
|
|
|
void Circuit::readInstanceSchematic(xmlNode* node, Schematic* schematic) {
|
|
xmlChar* nameC = xmlGetProp(node, (xmlChar*)"name");
|
|
xmlChar* xC = xmlGetProp(node, (xmlChar*)"x");
|
|
xmlChar* yC = xmlGetProp(node, (xmlChar*)"y");
|
|
xmlChar* symC = xmlGetProp(node, (xmlChar*)"sym");
|
|
if (nameC && xC && yC && symC) {
|
|
Name iName((const char*)nameC);
|
|
double x = ::getValue<double>(xC);
|
|
double y = ::getValue<double>(yC);
|
|
string symStr((const char*)symC);
|
|
string symComp[8] = {"ID", "R1", "R2", "R3", "MX", "XR", "MY", "YR"};
|
|
vector<string> symComps (symComp, symComp+8);
|
|
check_uppercase(symStr, symComps, "[ERROR] In 'schematic/instance', 'sym' must be 'ID', 'R1', 'R2', 'R3', 'MX', 'XR', 'MY' or 'YR'.");
|
|
schematic->addInstance(iName, x, y, Name(symStr));
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'instance' node in 'schematic' must have 'name', 'x', 'y' and 'sym' properties.");
|
|
}
|
|
}
|
|
|
|
// SIZING //
|
|
void Circuit::readSizing(xmlNode* node) {
|
|
if (readSizingDone) {
|
|
cerr << "[WARNING] Only one 'sizing' node is allowed in circuit, others will be ignored." << endl;
|
|
return;
|
|
}
|
|
|
|
Sizing* sizing = new Sizing(this);
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"instance")) {
|
|
readInstanceSizing(node, sizing);
|
|
} else if (xmlStrEqual(node->name, (xmlChar*)"equations")) {
|
|
readEquations(node, sizing);
|
|
} else {
|
|
cerr << "[WARNING] Only 'instance' and 'equations' nodes are allowed in 'sizing', others will be ignored." << endl;
|
|
}
|
|
}
|
|
}
|
|
readSizingDone = true;
|
|
_sizing = sizing;
|
|
}
|
|
|
|
void Circuit::readInstanceSizing(xmlNode* node, Sizing* sizing) {
|
|
xmlChar* nameC = xmlGetProp(node, (xmlChar*)"name");
|
|
xmlChar* operatorC = xmlGetProp(node, (xmlChar*)"operator");
|
|
xmlChar* simulModC = xmlGetProp(node, (xmlChar*)"simulModel");
|
|
xmlChar* orderC = xmlGetProp(node, (xmlChar*)"callOrder");
|
|
if (nameC && operatorC && simulModC && orderC) {
|
|
Name iName ((const char*)nameC);
|
|
Name opName ((const char*)operatorC);
|
|
Name simulMod((const char*)simulModC);
|
|
unsigned callOrder = ::getValue<unsigned>(orderC);
|
|
Operator* op = sizing->addOperator(iName, opName, simulMod, callOrder);
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"constraint")) {
|
|
readConstraint(node, op);
|
|
} else {
|
|
cerr << "[WARNING] Only 'constraint' nodes are allowed in 'instance' of 'sizing', others will be ignored." << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'instance' node in 'sizing' must have 'name', 'operator', 'simulModel' and 'callOrder' properties.");
|
|
}
|
|
}
|
|
|
|
void Circuit::readConstraint(xmlNode* node, Operator* op) {
|
|
// attributes of constraint may be :
|
|
// param ref refParam [factor]
|
|
// param refEquation [factor]
|
|
xmlChar* paramC = xmlGetProp(node, (xmlChar*)"param");
|
|
xmlChar* refC = xmlGetProp(node, (xmlChar*)"ref");
|
|
xmlChar* refParamC = xmlGetProp(node, (xmlChar*)"refParam");
|
|
xmlChar* refEqC = xmlGetProp(node, (xmlChar*)"refEquation");
|
|
xmlChar* factorC = xmlGetProp(node, (xmlChar*)"factor");
|
|
if (paramC && refC && refParamC) {
|
|
Name param ((const char*)paramC);
|
|
Name ref ((const char*)refC);
|
|
Name refParam ((const char*)refParamC);
|
|
double factor = 1.0;
|
|
if (factorC) {
|
|
factor = ::getValue<double>(factorC);
|
|
}
|
|
op->addConstraint(param, ref, refParam, factor);
|
|
} else if (paramC && refEqC) {
|
|
Name param ((const char*)paramC);
|
|
Name refEq ((const char*)refEqC);
|
|
double factor = 1.0;
|
|
if (factorC) {
|
|
factor = ::getValue<double>(factorC);
|
|
}
|
|
op->addConstraint(param, refEq, factor);
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'constraint' node must have 'param, ref, refParam, [factor]' or 'param, refEq, [factor]' properties.");
|
|
}
|
|
}
|
|
|
|
void Circuit::readEquations(xmlNode* node, Sizing* sizing) {
|
|
xmlNode* child = node->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"eq")) {
|
|
readEquation(node, sizing);
|
|
} else {
|
|
throw OpenChamsException("[ERROR] Only 'eq' nodes are allowed in 'equations'.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Circuit::readEquation(xmlNode* node, Sizing* sizing) {
|
|
xmlChar* nameC = xmlGetProp(node, (xmlChar*)"name");
|
|
xmlChar* equationC = xmlGetProp(node, (xmlChar*)"equation");
|
|
if (nameC && equationC) {
|
|
Name eName ((const char*)nameC);
|
|
string eqStr ((const char*)equationC);
|
|
sizing->addEquation(eName, eqStr);
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'eq' node in 'equations' must have 'name' and 'equation' properties.");
|
|
}
|
|
}
|
|
|
|
Circuit* Circuit::readFromFile(const string filePath) {
|
|
LIBXML_TEST_VERSION;
|
|
Circuit* cir = NULL;
|
|
xmlDoc* doc = xmlReadFile(filePath.c_str(), NULL, 0);
|
|
if (doc == NULL) {
|
|
string error ("[ERROR] Failed to parse: ");
|
|
error += filePath;
|
|
throw OpenChamsException(error);
|
|
//return NULL;
|
|
}
|
|
xmlNode* rootElement = xmlDocGetRootElement(doc);
|
|
if (rootElement->type == XML_ELEMENT_NODE && xmlStrEqual(rootElement->name, (xmlChar*)"circuit")) {
|
|
xmlChar* circuitNameC = xmlGetProp(rootElement, (xmlChar*)"name");
|
|
xmlChar* technoNameC = xmlGetProp(rootElement, (xmlChar*)"techno");
|
|
|
|
if (circuitNameC && technoNameC) {
|
|
Name circuitName ((const char*)circuitNameC);
|
|
Name technoName ((const char*)technoNameC);
|
|
cir = new Circuit(circuitName, technoName);
|
|
} else {
|
|
throw OpenChamsException("[ERROR] 'circuit' node must have 'name' and 'techno' properties.");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
xmlNode* child = rootElement->children;
|
|
for (xmlNode* node = child; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (xmlStrEqual(node->name, (xmlChar*)"parameters")) {
|
|
cir->readCircuitParameters(node);
|
|
}
|
|
if (xmlStrEqual(node->name, (xmlChar*)"netlist")) {
|
|
cir->readNetList(node);
|
|
}
|
|
if (xmlStrEqual(node->name, (xmlChar*)"schematic")) {
|
|
cir->readSchematic(node);
|
|
}
|
|
if (xmlStrEqual(node->name, (xmlChar*)"sizing")) {
|
|
cir->readSizing(node);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!readNetListDone) {
|
|
throw OpenChamsException("[ERROR] no <netlist> section was found in parsed file !");
|
|
}
|
|
return cir;
|
|
}
|
|
|
|
bool Circuit::writeToFile(string filePath) {
|
|
ofstream file;
|
|
file.open(filePath.c_str());
|
|
// checks before do anything
|
|
if (!_netlist) {
|
|
cerr << "no netlist" << endl; cerr.flush();
|
|
throw OpenChamsException("[ERROR] Cannot writeToFile since no netlist is defined !");
|
|
//return false;
|
|
}
|
|
if (_netlist->hasNoInstances()) {
|
|
cerr << "no instances" << endl; cerr.flush();
|
|
throw OpenChamsException("[ERROR] Cannot writeToFile since no instance is defined in netlist !");
|
|
//return false;
|
|
}
|
|
if (_netlist->hasNoNets()) {
|
|
cerr << "no nets" << endl; cerr.flush();
|
|
throw OpenChamsException("[ERROR] Cannot writeToFile since no net is defined in netlist !");
|
|
//return false;
|
|
}
|
|
|
|
file << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl
|
|
<< "<circuit name=\"" << _name.getString() << "\" techno=\"" << _techno.getString() << "\">" << endl;
|
|
if (!_params.isEmpty()) {
|
|
file << " <parameters>" << endl;
|
|
for (map<Name, double>::const_iterator it = _params.getValues().begin() ; it != _params.getValues().end() ; ++it) {
|
|
file << " <parameter name=\"" << (*it).first.getString() << "\" value=\"" << (*it).second << "\"/>" << endl;
|
|
}
|
|
for (map<Name, string>::const_iterator it = _params.getEqValues().begin() ; it != _params.getEqValues().end() ; ++it) {
|
|
file << " <parameterEq name=\"" << (*it).first.getString() << "\" equation=\"" << (*it).second << "\"/>" << endl;
|
|
}
|
|
file << " </parameters>" << endl;
|
|
}
|
|
file << " <netlist>" << endl
|
|
<< " <instances>" << endl;
|
|
for (vector<Instance*>::const_iterator it = _netlist->getInstances().begin() ; it != _netlist->getInstances().end() ; ++it) {
|
|
Instance* inst = (*it);
|
|
if (inst->hasNoConnectors()) {
|
|
string error("[ERROR] Cannot writeToFile since instance (");
|
|
error += inst->getName().getString();
|
|
error += ") has no connectors !";
|
|
throw OpenChamsException(error);
|
|
//return false;
|
|
}
|
|
if (inst->hasNoTransistors()) {
|
|
string error("[ERROR] Cannot writeToFile since instance (");
|
|
error += inst->getName().getString();
|
|
error += ") has no transistors !";
|
|
throw OpenChamsException(error);
|
|
}
|
|
string sourceBulkStr = (inst->isSourceBulkConnected()) ? "True" : "False";
|
|
file << " <instance name=\"" << inst->getName().getString() << "\" model=\"" << inst->getModel().getString() << "\" mostype=\"" << inst->getMosType().getString() << "\" sourceBulkConnected=\"" << sourceBulkStr << "\">" << endl;
|
|
file << " <connectors>" << endl;
|
|
for (map<Name, Net*>::const_iterator it = inst->getConnectors().begin() ; it != inst->getConnectors().end() ; ++it) {
|
|
file << " <connector name=\"" << (*it).first.getString() << "\"/>" << endl;
|
|
}
|
|
file << " </connectors>" << endl
|
|
<< " <transistors>" << endl;
|
|
for (vector<Transistor*>::const_iterator it = inst->getTransistors().begin() ; it != inst->getTransistors().end() ; ++it ) {
|
|
Transistor* tr = (*it);
|
|
file << " <transistor name=\"" << tr->getName().getString() << "\">" << endl
|
|
<< " <connection gate=\"" << tr->getGate().getString() << "\" source=\"" << tr->getSource().getString() << "\" drain=\"" << tr->getDrain().getString() << "\" bulk=\"" << tr->getBulk().getString() << "\"/>" << endl
|
|
<< " </transistor>" << endl;
|
|
}
|
|
file << " </transistors>" << endl;
|
|
if (!inst->getParameters().isEmpty()) {
|
|
Parameters params = inst->getParameters();
|
|
file << " <parameters>" << endl;
|
|
for (map<Name, double>::const_iterator it = params.getValues().begin() ; it != params.getValues().end() ; ++it) {
|
|
file << " <parameter name=\"" << (*it).first.getString() << "\" value=\"" << (*it).second << "\"/>" << endl;
|
|
}
|
|
file << " </parameters>" << endl;
|
|
}
|
|
file << " </instance>" << endl;
|
|
}
|
|
file << " </instances>" << endl
|
|
<< " <nets>" << endl;
|
|
for (vector<Net*>::const_iterator it = _netlist->getNets().begin() ; it != _netlist->getNets().end() ; ++it) {
|
|
Net* net = (*it);
|
|
if (net->hasNoConnectors()) {
|
|
string error("[ERROR] Cannot writeToFile since net (");
|
|
error += net->getName().getString();
|
|
error += ") has no connectors !";
|
|
throw OpenChamsException(error);
|
|
//return false;
|
|
}
|
|
string externStr = (net->isExternal()) ? "True" : "False";
|
|
file << " <net name=\"" << net->getName().getString() << "\" type=\"" << net->getType().getString() << "\" isExternal=\"" << externStr << "\">" << endl;
|
|
for (vector<pair<Name, Name> >::const_iterator it = net->getConnections().begin() ; it != net->getConnections().end() ; ++it) {
|
|
file << " <connector instance=\"" << (*it).first.getString() << "\" name=\"" << (*it).second.getString() << "\"/>" << endl;
|
|
}
|
|
file << " </net>" << endl;
|
|
}
|
|
file << " </nets>" << endl;
|
|
file << " </netlist>" << endl;
|
|
if (_schematic && !_schematic->hasNoInstances()) {
|
|
file << " <schematic zoom=\"" << _schematic->getZoom() << "\">" << endl;
|
|
for (map<Name, Schematic::Infos*>::const_iterator it = _schematic->getInstances().begin() ; it != _schematic->getInstances().end(); ++it ) {
|
|
Schematic::Infos* infos = (*it).second;
|
|
file << " <instance name=\"" << ((*it).first).getString() << "\" x=\"" << infos->getX() << "\" y=\"" << infos->getY() << "\" sym=\"" << infos->getSymetry().getString() << "\"/>" << endl;
|
|
}
|
|
file << " </schematic>" << endl;
|
|
}
|
|
if (_sizing && !_sizing->hasNoOperators()) {
|
|
file << " <sizing>" << endl;
|
|
for (map<Name, Operator*>::const_iterator it = _sizing->getOperators().begin() ; it != _sizing->getOperators().end() ; ++it) {
|
|
Operator* op = (*it).second;
|
|
file << " <instance name=\"" << ((*it).first).getString() << "\" operator=\"" << op->getName().getString() << "\" simulModel=\"" << op->getSimulModel().getString() << "\" callOrder=\"" << op->getCallOrder() << "\">" << endl;
|
|
if (!op->hasNoConstraints()) {
|
|
for (map<Name, Operator::Constraint*>::const_iterator cit = op->getConstraints().begin() ; cit != op->getConstraints().end() ; ++cit) {
|
|
Operator::Constraint* cn = (*cit).second;
|
|
Name ref = cn->getRef();
|
|
if (ref == Name("")) {
|
|
file << " <constraint param=\"" << ((*cit).first).getString() << "\" refEquation=\"" << cn->getRefParam().getString() << "\" factor=\"" << cn->getFactor() << "\"/>" << endl;
|
|
} else {
|
|
file << " <constraint param=\"" << ((*cit).first).getString() << "\" ref=\"" << cn->getRef().getString() << "\" refParam=\"" << cn->getRefParam().getString() << "\" factor=\"" << cn->getFactor() << "\"/>" << endl;
|
|
}
|
|
}
|
|
}
|
|
file << " </instance>" << endl;
|
|
}
|
|
if (!_sizing->hasNoEquations()) {
|
|
file << " <equations>" << endl;
|
|
for (map<Name, string>::const_iterator it = _sizing->getEquations().begin() ; it != _sizing->getEquations().end() ; ++it) {
|
|
file << " <eq name=\"" << ((*it).first).getString() << "\" equation=\"" << (*it).second << "\"/>" << endl;
|
|
}
|
|
file << " </equations>" << endl;
|
|
}
|
|
file << " </sizing>" << endl;
|
|
}
|
|
file << "</circuit>" << endl;
|
|
file.close();
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|