coriolis/vlsisapd/openChams/Circuit.cpp

360 lines
14 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>
using namespace std;
#include "Circuit.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;
Circuit::Circuit(Name name, Name techno) : _name(name), _techno(techno) {}
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 {
cerr << "[ERROR] 'parameter' node must have 'name' and 'value' properties." << endl;
return Name("");
}
}
Name Circuit::readConnector(xmlNode* node) {
xmlChar* connectorNameC = xmlGetProp(node, (xmlChar*)"name");
if (connectorNameC) {
Name name((const char*)connectorNameC);
return name;
} else {
cerr << "[ERROR] 'connector' node must have 'name' property." << endl;
return Name("");
}
}
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 {
cerr << "[WARNING] Only 'parameter' nodes are authorized under 'parameters' node." << endl;
return;
}
}
}
}
readCircuitParametersDone = true;
}
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;
}
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);
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");
Instance* inst = NULL;
if (iNameC && iModelC && iMOSC) {
Name instanceName((const char*)iNameC);
Name modelName((const char*)iModelC);
Name mosName((const char*)iMOSC);
inst = new Instance(instanceName, modelName, mosName, netlist);
} else {
cerr << "[ERROR] 'instance' node must have 'name', 'model' and 'mos' properties." << endl;
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 {
cerr << "[WARNING] Only 'conectors' and 'parameters' nodes are allowed in 'instance', others will be ignored." << endl;
return NULL;
}
}
}
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);
}
}
}
}
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);
Name typeName((const char*)nTypeC);
string externStr((const char*)nExternC);
bool isExternal = (externStr == "True") ? true : false;
net = new Net(netName, typeName, isExternal, netlist);
netlist->addNet(net);
} else {
cerr << "[ERROR] 'net' node must have 'name', 'type' and 'isExternal' properties." << endl;
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) {
cerr << "[ERROR] no instance named \"" << iName.getString() << "\" in connector of net \"" << net->getName().getString() << "\"." << endl;
return;
}
inst->connect(cName, net->getName());
net->connectTo(iName, cName);
} else {
cerr << "[ERROR] 'connector' node must have 'instance' and 'name' properties (for net)." << endl;
}
}
Circuit* Circuit::readFromFile(string filePath) {
LIBXML_TEST_VERSION;
Circuit* cir = NULL;
xmlDoc* doc = xmlReadFile(filePath.c_str(), NULL, 0);
if (doc == NULL) {
cerr << "[ERROR] Failed to parse: " << filePath << endl;
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 {
cerr << "[ERROR] 'circuit' node must have 'name' and 'techno' properties." << endl;
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);
}
}
}
}
return cir;
}
bool Circuit::writeToFile(string filePath) {
ofstream file;
file.open(filePath.c_str());
// checks before do anything
if (!_netlist) {
cerr << "[ERROR] Cannot writeToFile since no netlist is defined !" << endl;
return false;
}
if (_netlist->hasNoInstances()) {
cerr << "[ERROR] Cannot writeToFile since no instance is defined in netlist !" << endl;
return false;
}
if (_netlist->hasNoNets()) {
cerr << "[ERROR] Cannot writeToFile since no net is defined in netlist !" << endl;
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>::iterator it = _params.getFirstIt() ; it != _params.getLastIt() ; ++it) {
file << " <parameter name=\"" << (*it).first.getString() << "\" value=\"" << (*it).second << "\"/>" << endl;
}
file << " </parameters>" << endl;
}
file << " <netlist>" << endl
<< " <instances>" << endl;
for (vector<Instance*>::iterator it = _netlist->getFirstInstanceIt() ; it != _netlist->getLastInstanceIt() ; ++it) {
Instance* inst = (*it);
if (inst->hasNoConnectors()) {
cerr << "[ERROR] Cannot writeToFile since instance (" << inst->getName().getString() << ") has no connectors !" << endl;
return false;
}
file << " <instance name=\"" << inst->getName().getString() << "\" model=\"" << inst->getModel().getString() << "\" mostype=\"" << inst->getMosType().getString() << "\">" << endl;
file << " <connectors>" << endl;
for (map<Name, Net*>::iterator it = inst->getFirstConnectorIt() ; it != inst->getLastConnectorIt() ; ++it) {
file << " <connector name=\"" << (*it).first.getString() << "\"/>" << endl;
}
file << " </connectors>" << endl;
if (!inst->getParameters().isEmpty()) {
Parameters params = inst->getParameters();
file << " <parameters>" << endl;
for (map<Name, double>::iterator it = params.getFirstIt() ; it != params.getLastIt() ; ++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*>::iterator it = _netlist->getFirstNetIt() ; it != _netlist->getLastNetIt() ; ++it) {
Net* net = (*it);
if (net->hasNoConnectors()) {
cerr << "[ERROR] Cannot writeToFile since net (" << net->getName().getString() << ") has no connectors !" << endl;
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> >::iterator it = net->getFirstConnectionIt() ; it != net->getLastConnectionIt() ; ++it) {
file << " <connector instance=\"" << (*it).first.getString() << "\" name=\"" << (*it).second.getString() << "\"/>" << endl;
}
file << " </net>" << endl;
}
file << " </nets>" << endl;
file << " </netlist>" << endl;
file << "</circuit>" << endl;
file.close();
return true;
}
}