coriolis/vlsisapd/dtr/src/Techno.cpp

231 lines
9.4 KiB
C++

/*
* Techno.cpp
* DTR
*
* Created by damien dupuis on 01/04/10.
* Copyright 2010 UPMC / LIP6. All rights reserved.
*
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
using namespace std;
#include <libxml/parser.h>
#include <libxml/tree.h>
#include "io/dtr/Techno.h"
#include "io/dtr/Rules.h"
#include "io/dtr/DTRException.h"
namespace {
template<class T> T getValue(xmlChar* str) {
std::istringstream iss;
iss.str((const char*) str);
T res;
iss >> res;
return res;
}
}
namespace DTR {
Techno::Techno(Name name, Name unit) : _name(name), _unit(unit) {}
Rule* Techno::addRule (Name name, double value, Name ref, Name layer1, Name layer2) {
Rule* rule = new Rule(name, value, ref, layer1, layer2);
_rules.push_back(rule);
return rule;
}
ARule* Techno::addARule (Name name, double value, Name ref, Name layer1, Name layer2) {
ARule* arule = new ARule(name, value, ref, layer1, layer2);
_rules.push_back(arule);
return arule;
}
double Techno::getValue(Name name) {
return getValue(name, Name(""), Name(""));
}
double Techno::getValue(Name name, Name layer) {
return getValue(name, layer, Name(""));
}
double Techno::getValue(Name name, Name layer1, Name layer2) {
bool testL1 = (layer1 == Name("")) ? false : true;
bool testL2 = (layer2 == Name("")) ? false : true;
for (size_t i = 0 ; i < _rules.size() ; i++) {
Rule* rule = _rules[i];
if (rule->getName() == name) {
if (testL1) {
if (rule->getLayer1() == layer1) {
if (testL2) {
if (rule->getLayer2() == layer2) {
return rule->getValue();
}
} else {
return rule->getValue();
}
}
} else {
return rule->getValue();
}
}
}
string error ("[ERROR] Could not found rule: ");
error += name.getString();
error += ".";
error += layer1.getString();
error += ".";
error += layer2.getString();
error += ".";
throw DTRException(error);
}
Techno* Techno::readFromFile(const string filePath) {
LIBXML_TEST_VERSION;
Techno* techno = NULL;
xmlDoc* doc = xmlReadFile(filePath.c_str(), NULL, 0);
if (doc == NULL) {
string error ("[ERROR] Failed to parse: ");
error += filePath;
throw DTRException(error);
//return NULL;
}
xmlNode* rootElement = xmlDocGetRootElement(doc);
if (rootElement->type == XML_ELEMENT_NODE && xmlStrEqual(rootElement->name, (xmlChar*)"technology")) {
xmlChar* technoNameC = xmlGetProp(rootElement, (xmlChar*)"name");
xmlChar* technoUnitC = xmlGetProp(rootElement, (xmlChar*)"unit");
if (technoNameC && technoUnitC) {
Name name ((const char*)technoNameC);
Name unit ((const char*)technoUnitC);
techno = new Techno(name, unit);
} else {
throw DTRException("[ERROR] 'technology' node must have 'name' and 'unit' 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*)"physical_rules")) {
throw DTRException("[ERROR] only 'physical_rules' node is allowed under 'technology' node.");
return NULL;
}
for (xmlNode* subnode = node->children ; subnode ; subnode = subnode->next) {
if (subnode->type == XML_ELEMENT_NODE) {
if (xmlStrEqual(subnode->name, (xmlChar*)"rule")) {
xmlChar* nameC = xmlGetProp(subnode, (xmlChar*)"name" );
xmlChar* layerC = xmlGetProp(subnode, (xmlChar*)"layer" );
xmlChar* layer1C = xmlGetProp(subnode, (xmlChar*)"layer1");
xmlChar* layer2C = xmlGetProp(subnode, (xmlChar*)"layer2");
xmlChar* valueC = xmlGetProp(subnode, (xmlChar*)"value" );
xmlChar* refC = xmlGetProp(subnode, (xmlChar*)"ref" );
xmlChar* typeC = xmlGetProp(subnode, (xmlChar*)"type" );
Rule* rule = NULL;
if (nameC && layer1C && layer2C && valueC && refC) { // rule with two layers
Name name ((const char*)nameC);
Name ref ((const char*)refC);
Name layer1 ((const char*)layer1C);
Name layer2 ((const char*)layer2C);
double value = ::getValue<double>(valueC);
rule = techno->addRule(name, value, ref, layer1, layer2);
} else if (nameC && layerC && valueC && refC) {// rule with only one layer
Name name ((const char*)nameC);
Name ref ((const char*)refC);
Name layer ((const char*)layerC);
double value = ::getValue<double>(valueC);
rule = techno->addRule(name, value, ref, layer);
} else if (nameC && valueC && refC) { // rule without layer
Name name ((const char*)nameC);
Name ref ((const char*)refC);
double value = ::getValue<double>(valueC);
rule = techno->addRule(name, value, ref);
} else { // invalid case
throw DTRException("[ERROR] properties of 'rule' node must be ('name', 'value', 'ref') or ('name', 'layer', 'value', 'ref') or ('name', 'layer1', 'layer2', 'value', 'ref').");
return NULL;
}
if (typeC) {
Name type ((const char*)typeC);
rule->setType(type);
}
} else if (xmlStrEqual(subnode->name, (xmlChar*)"arule")) {
xmlChar* nameC = xmlGetProp(subnode, (xmlChar*)"name" );
xmlChar* layer1C = xmlGetProp(subnode, (xmlChar*)"layer1");
xmlChar* layer2C = xmlGetProp(subnode, (xmlChar*)"layer2");
xmlChar* valueC = xmlGetProp(subnode, (xmlChar*)"value" );
xmlChar* refC = xmlGetProp(subnode, (xmlChar*)"ref" );
if (nameC && layer1C && layer2C && valueC && refC) {
Name name ((const char*)nameC);
Name layer1 ((const char*)layer1C);
Name layer2 ((const char*)layer2C);
Name ref ((const char*)refC);
double value = ::getValue<double>(valueC);
techno->addARule(name, value, ref, layer1, layer2);
} else {
throw DTRException("[ERROR] 'arule' node must have 'name', 'layer1', 'layer2', 'value' and 'ref' properties.");
return NULL;
}
} else {
throw DTRException("[ERROR] only 'rule' and 'arule' nodes are allowed under 'physical_rules' node.");
}
}
}
}
}
}
return techno;
}
bool Techno::writeToFile(string filePath) {
ofstream file;
file.open(filePath.c_str());
if (!file.is_open()) {
string error("[ERROR] Cannot open file ");
error += filePath;
error += " for writting.";
throw DTRException(error);
}
// checks before do anything
if (_rules.size() == 0) {
throw DTRException("[ERROR] Cannot writeToFile since no rule is defined!");
}
file << "<technology name=\"" << _name.getString() << "\" unit=\"" << _unit.getString() << "\">" << endl
<< " <physical_rules>" << endl;
for (size_t i = 0 ; i < _rules.size() ; i++) {
Rule* rule = _rules[i];
if (dynamic_cast<ARule*>(rule)) {
file << " <arule name=\"" << rule->getName().getString() << "\" ";
} else {
file << " <rule name=\"" << rule->getName().getString() << "\" ";
}
if (rule->getType() != Name("")) {
file << "type=\"" << rule->getType().getString() << "\" ";
}
if (rule->getLayer1() != Name("")) {
if (rule->getLayer2() != Name("")) {
file << "layer1=\"" << rule->getLayer1().getString() << "\" layer2=\"" << rule->getLayer2().getString() << "\" ";
} else {
file << "layer=\"" << rule->getLayer1().getString() << "\" ";
}
}
file << "value=\"" << rule->getValue() << "\" ref=\"" << rule->getRef().getString() << "\"/>" << endl;
}
file << " </physical_rules>" << endl
<< "</technology>" << endl;
file.close();
return true;
}
}