/* * Circuit.cpp * openChams * * Created by damien dupuis on 18/12/09. * Copyright 2009 UPMC / LIP6. All rights reserved. * */ #include #include #include #include using namespace std; #include "Circuit.h" namespace { template 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(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 << "" << endl << "" << endl; if (!_params.isEmpty()) { file << " " << endl; for (map::iterator it = _params.getFirstIt() ; it != _params.getLastIt() ; ++it) { file << " " << endl; } file << " " << endl; } file << " " << endl << " " << endl; for (vector::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 << " getName().getString() << "\" model=\"" << inst->getModel().getString() << "\" mostype=\"" << inst->getMosType().getString() << "\">" << endl; file << " " << endl; for (map::iterator it = inst->getFirstConnectorIt() ; it != inst->getLastConnectorIt() ; ++it) { file << " " << endl; } file << " " << endl; if (!inst->getParameters().isEmpty()) { Parameters params = inst->getParameters(); file << " " << endl; for (map::iterator it = params.getFirstIt() ; it != params.getLastIt() ; ++it) { file << " " << endl; } file << " " << endl; } file << " " << endl; } file << " " << endl << " " << endl; for (vector::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 << " getName().getString() << "\" type=\"" << net->getType().getString() << "\" isExternal=\"" << externStr << "\">" << endl; for (vector >::iterator it = net->getFirstConnectionIt() ; it != net->getLastConnectionIt() ; ++it) { file << " " << endl; } file << " " << endl; } file << " " << endl; file << " " << endl; file << "" << endl; file.close(); return true; } }