diff options
Diffstat (limited to 'utils/regtools/lib/soc_desc.cpp')
-rw-r--r-- | utils/regtools/lib/soc_desc.cpp | 700 |
1 files changed, 693 insertions, 7 deletions
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp index 6a6d47648f..1c9eaf7972 100644 --- a/utils/regtools/lib/soc_desc.cpp +++ b/utils/regtools/lib/soc_desc.cpp @@ -21,8 +21,12 @@ #include "soc_desc.hpp" #include <libxml/parser.h> #include <libxml/tree.h> +#include <libxml/xmlsave.h> +#include <libxml/xmlwriter.h> #include <stdio.h> #include <string.h> +#include <algorithm> +#include <cctype> #define XML_CHAR_TO_CHAR(s) ((const char *)(s)) @@ -78,6 +82,9 @@ #define END_NODE_MATCH() \ } +namespace +{ + bool validate_string_hook(const std::string& str, std::string& s) { s = str; @@ -137,6 +144,7 @@ bool parse_value_elem(xmlNode *node, soc_reg_field_value_t& value) BEGIN_ATTR_MATCH(node->properties) MATCH_TEXT_ATTR("name", value.name) MATCH_UINT32_ATTR("value", value.value) + MATCH_TEXT_ATTR("desc", value.desc) END_ATTR_MATCH() return true; @@ -256,28 +264,706 @@ bool parse_soc_elem(xmlNode *node, soc_t& soc) return true; } -bool parse_root_elem(xmlNode *node, std::vector< soc_t >& soc) +bool parse_root_elem(xmlNode *node, soc_t& soc) { + std::vector< soc_t > socs; BEGIN_NODE_MATCH(node) - MATCH_ELEM_NODE("soc", soc, parse_soc_elem) + MATCH_ELEM_NODE("soc", socs, parse_soc_elem) END_NODE_MATCH() + if(socs.size() != 1) + { + fprintf(stderr, "A description file must contain exactly one soc element\n"); + return false; + } + soc = socs[0]; return true; } -bool soc_desc_parse_xml(const std::string& filename, std::vector< soc_t >& socs) +} + +bool soc_desc_parse_xml(const std::string& filename, soc_t& socs) { LIBXML_TEST_VERSION - xmlDoc *doc = xmlReadFile(filename.c_str(), NULL, 0); + xmlDocPtr doc = xmlReadFile(filename.c_str(), NULL, 0); if(doc == NULL) return false; - xmlNode *root_element = xmlDocGetRootElement(doc); - + xmlNodePtr root_element = xmlDocGetRootElement(doc); bool ret = parse_root_elem(root_element, socs); xmlFreeDoc(doc); xmlCleanupParser(); return ret; -}
\ No newline at end of file +} + +namespace +{ + +int produce_field(xmlTextWriterPtr writer, const soc_reg_field_t& field) +{ +#define SAFE(x) if((x) < 0) return -1; + /* <field> */ + SAFE(xmlTextWriterStartElement(writer, BAD_CAST "field")); + /* name */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.name.c_str())); + /* desc */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.desc.c_str())); + /* bitrange */ + SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "bitrange", "%d:%d", + field.last_bit, field.first_bit)); + /* values */ + for(size_t i = 0; i < field.value.size(); i++) + { + /* <value> */ + SAFE(xmlTextWriterStartElement(writer, BAD_CAST "value")); + /* name */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.value[i].name.c_str())); + /* value */ + SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "value", "0x%x", field.value[i].value)); + /* name */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.value[i].desc.c_str())); + /* </value> */ + SAFE(xmlTextWriterEndElement(writer)); + } + /* </field> */ + SAFE(xmlTextWriterEndElement(writer)); +#undef SAFE + return 0; +} + +int produce_reg(xmlTextWriterPtr writer, const soc_reg_t& reg) +{ +#define SAFE(x) if((x) < 0) return -1; + /* <reg> */ + SAFE(xmlTextWriterStartElement(writer, BAD_CAST "reg")); + /* name */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.name.c_str())); + /* name */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str())); + /* flags */ + if(reg.flags & REG_HAS_SCT) + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "sct", BAD_CAST "yes")); + /* formula */ + if(reg.formula.type != REG_FORMULA_NONE) + { + /* <formula> */ + SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula")); + switch(reg.formula.type) + { + case REG_FORMULA_STRING: + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "string", + BAD_CAST reg.formula.string.c_str())); + break; + default: + break; + } + /* </formula> */ + SAFE(xmlTextWriterEndElement(writer)); + } + /* addresses */ + for(size_t i = 0; i < reg.addr.size(); i++) + { + /* <addr> */ + SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr")); + /* name */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.addr[i].name.c_str())); + /* addr */ + SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", reg.addr[i].addr)); + /* </addr> */ + SAFE(xmlTextWriterEndElement(writer)); + } + /* fields */ + for(size_t i = 0; i < reg.field.size(); i++) + produce_field(writer, reg.field[i]); + /* </reg> */ + SAFE(xmlTextWriterEndElement(writer)); +#undef SAFE + return 0; +} + +int produce_dev(xmlTextWriterPtr writer, const soc_dev_t& dev) +{ +#define SAFE(x) if((x) < 0) return -1; + /* <dev> */ + SAFE(xmlTextWriterStartElement(writer, BAD_CAST "dev")); + /* name */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.name.c_str())); + /* long_name */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "long_name", BAD_CAST dev.long_name.c_str())); + /* desc */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST dev.desc.c_str())); + /* version */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST dev.version.c_str())); + /* addresses */ + for(size_t i = 0; i < dev.addr.size(); i++) + { + /* <addr> */ + SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr")); + /* name */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.addr[i].name.c_str())); + /* addr */ + SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", dev.addr[i].addr)); + /* </addr> */ + SAFE(xmlTextWriterEndElement(writer)); + } + /* registers */ + for(size_t i = 0; i < dev.reg.size(); i++) + produce_reg(writer, dev.reg[i]); + /* </dev> */ + SAFE(xmlTextWriterEndElement(writer)); +#undef SAFE + return 0; +} + +} + +bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc) +{ + LIBXML_TEST_VERSION + + xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.c_str(), 0); + if(writer == NULL) + return false; +#define SAFE(x) if((x) < 0) goto Lerr + SAFE(xmlTextWriterSetIndent(writer, 1)); + SAFE(xmlTextWriterSetIndentString(writer, BAD_CAST " ")); + /* <xml> */ + SAFE(xmlTextWriterStartDocument(writer, NULL, NULL, NULL)); + /* <soc> */ + SAFE(xmlTextWriterStartElement(writer, BAD_CAST "soc")); + /* name */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST soc.name.c_str())); + /* desc */ + SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST soc.desc.c_str())); + /* devices */ + for(size_t i = 0; i < soc.dev.size(); i++) + SAFE(produce_dev(writer, soc.dev[i])); + /* end <soc> */ + SAFE(xmlTextWriterEndElement(writer)); + /* </xml> */ + SAFE(xmlTextWriterEndDocument(writer)); + xmlFreeTextWriter(writer); + return true; +#undef SAFE +Lerr: + xmlFreeTextWriter(writer); + return false; +} + +namespace +{ + +struct soc_sorter +{ + bool operator()(const soc_dev_t& a, const soc_dev_t& b) const + { + return a.name < b.name; + } + + bool operator()(const soc_dev_addr_t& a, const soc_dev_addr_t& b) const + { + return a.name < b.name; + } + + bool operator()(const soc_reg_t& a, const soc_reg_t& b) const + { + soc_addr_t aa = a.addr.size() > 0 ? a.addr[0].addr : 0; + soc_addr_t ab = b.addr.size() > 0 ? b.addr[0].addr : 0; + return aa < ab; + } + + bool operator()(const soc_reg_addr_t& a, const soc_reg_addr_t& b) const + { + return a.addr < b.addr; + } + + bool operator()(const soc_reg_field_t& a, const soc_reg_field_t& b) const + { + return a.last_bit > b.last_bit; + } + + bool operator()(const soc_reg_field_value_t a, const soc_reg_field_value_t& b) const + { + return a.value < b.value; + } +}; + +void normalize(soc_reg_field_t& field) +{ + std::sort(field.value.begin(), field.value.end(), soc_sorter()); +} + +void normalize(soc_reg_t& reg) +{ + std::sort(reg.addr.begin(), reg.addr.end(), soc_sorter()); + std::sort(reg.field.begin(), reg.field.end(), soc_sorter()); + for(size_t i = 0; i < reg.field.size(); i++) + normalize(reg.field[i]); +} + +void normalize(soc_dev_t& dev) +{ + std::sort(dev.addr.begin(), dev.addr.end(), soc_sorter()); + std::sort(dev.reg.begin(), dev.reg.end(), soc_sorter()); + for(size_t i = 0; i < dev.reg.size(); i++) + normalize(dev.reg[i]); +} + +} + +void soc_desc_normalize(soc_t& soc) +{ + std::sort(soc.dev.begin(), soc.dev.end(), soc_sorter()); + for(size_t i = 0; i < soc.dev.size(); i++) + normalize(soc.dev[i]); +} + +namespace +{ + soc_error_t make_error(soc_error_level_t lvl, std::string at, std::string what) + { + soc_error_t err; + err.level = lvl; + err.location = at; + err.message = what; + return err; + } + + soc_error_t make_warning(std::string at, std::string what) + { + return make_error(SOC_ERROR_WARNING, at, what); + } + + soc_error_t make_fatal(std::string at, std::string what) + { + return make_error(SOC_ERROR_FATAL, at, what); + } + + soc_error_t prefix(soc_error_t err, const std::string& prefix_at) + { + err.location = prefix_at + "." + err.location; + return err; + } + + void add_errors(std::vector< soc_error_t >& errors, + const std::vector< soc_error_t >& new_errors, const std::string& prefix_at) + { + for(size_t i = 0; i < new_errors.size(); i++) + errors.push_back(prefix(new_errors[i], prefix_at)); + } + + std::vector< soc_error_t > no_error() + { + std::vector< soc_error_t > s; + return s; + } + + std::vector< soc_error_t > one_error(const soc_error_t& err) + { + std::vector< soc_error_t > s; + s.push_back(err); + return s; + } + + bool name_valid(char c) + { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || c == '_'; + } + + bool name_valid(const std::string& s) + { + for(size_t i = 0; i < s.size(); i++) + if(!name_valid(s[i])) + return false; + return true; + } +} + +std::vector< soc_error_t > soc_reg_field_value_t::errors(bool recursive) +{ + (void) recursive; + if(name.size() == 0) + return one_error(make_fatal(name, "empty name")); + else if(!name_valid(name)) + return one_error(make_fatal(name, "invalid name")); + else + return no_error(); +} + +std::vector< soc_error_t > soc_reg_field_t::errors(bool recursive) +{ + std::vector< soc_error_t > err; + std::string at(name); + if(name.size() == 0) + err.push_back(make_fatal(at, "empty name")); + else if(!name_valid(name)) + err.push_back(make_fatal(at, "invalid name")); + if(last_bit > 31) + err.push_back(make_fatal(at, "last bit is greater than 31")); + if(first_bit > last_bit) + err.push_back(make_fatal(at, "last bit is greater than first bit")); + for(size_t i = 0; i < value.size(); i++) + { + for(size_t j = 0; j < value.size(); j++) + { + if(i == j) + continue; + if(value[i].name == value[j].name) + err.push_back(prefix(make_fatal(value[i].name, + "there are several values with the same name"), at)); + if(value[i].value == value[j].value) + err.push_back(prefix(make_warning(value[i].name, + "there are several values with the same value"), at)); + } + if(value[i].value > (bitmask() >> first_bit)) + err.push_back(prefix(make_warning(at, "value doesn't fit into the field"), value[i].name)); + if(recursive) + add_errors(err, value[i].errors(true), at); + } + return err; +} + +std::vector< soc_error_t > soc_reg_addr_t::errors(bool recursive) +{ + (void) recursive; + if(name.size() == 0) + return one_error(make_fatal("", "empty name")); + else if(!name_valid(name)) + return one_error(make_fatal(name, "invalid name")); + else + return no_error(); +} + +std::vector< soc_error_t > soc_reg_formula_t::errors(bool recursive) +{ + (void) recursive; + if(type == REG_FORMULA_STRING && string.size() == 0) + return one_error(make_fatal("", "empty string formula")); + else + return no_error(); +} + +namespace +{ + +bool field_overlap(const soc_reg_field_t& a, const soc_reg_field_t& b) +{ + return !(a.first_bit > b.last_bit || b.first_bit > a.last_bit); +} + +} + +std::vector< soc_error_t > soc_reg_t::errors(bool recursive) +{ + std::vector< soc_error_t > err; + std::string at(name); + if(name.size() == 0) + err.push_back(make_fatal(at, "empty name")); + else if(!name_valid(name)) + err.push_back(make_fatal(at, "invalid name")); + for(size_t i = 0; i < addr.size(); i++) + { + for(size_t j = 0; j < addr.size(); j++) + { + if(i == j) + continue; + if(addr[i].name == addr[j].name) + err.push_back(prefix(make_fatal(addr[i].name, + "there are several instances with the same name"), at)); + if(addr[i].addr == addr[j].addr) + err.push_back(prefix(make_fatal(addr[i].name, + "there are several instances with the same address"), at)); + } + if(recursive) + add_errors(err, addr[i].errors(true), at); + } + if(recursive) + add_errors(err, formula.errors(true), at); + for(size_t i = 0; i < field.size(); i++) + { + for(size_t j = 0; j < field.size(); j++) + { + if(i == j) + continue; + if(field[i].name == field[j].name) + err.push_back(prefix(make_fatal(field[i].name, + "there are several fields with the same name"), at)); + if(field_overlap(field[i], field[j])) + err.push_back(prefix(make_fatal(field[i].name, + "there are overlapping fields"), at)); + } + if(recursive) + add_errors(err, field[i].errors(true), at); + } + return err; +} + +std::vector< soc_error_t > soc_dev_addr_t::errors(bool recursive) +{ + (void) recursive; + if(name.size() == 0) + return one_error(make_fatal("", "empty name")); + else if(!name_valid(name)) + return one_error(make_fatal(name, "invalid name")); + else + return no_error(); +} + +std::vector< soc_error_t > soc_dev_t::errors(bool recursive) +{ + std::vector< soc_error_t > err; + std::string at(name); + if(name.size() == 0) + err.push_back(make_fatal(at, "empty name")); + else if(!name_valid(name)) + err.push_back(make_fatal(at, "invalid name")); + for(size_t i = 0; i < addr.size(); i++) + { + for(size_t j = 0; j < addr.size(); j++) + { + if(i == j) + continue; + if(addr[i].name == addr[j].name) + err.push_back(prefix(make_fatal(addr[i].name, + "there are several instances with the same name"), at)); + if(addr[i].addr == addr[j].addr) + err.push_back(prefix(make_fatal(addr[i].name, + "there are several instances with the same address"), at)); + } + if(recursive) + add_errors(err, addr[i].errors(true), at); + } + for(size_t i = 0; i < reg.size(); i++) + { + for(size_t j = 0; j < reg.size(); j++) + { + if(i == j) + continue; + if(reg[i].name == reg[j].name) + err.push_back(prefix(make_fatal(reg[i].name, + "there are several registers with the same name"), at)); + } + if(recursive) + add_errors(err, reg[i].errors(true), at); + } + return err; +} + +std::vector< soc_error_t > soc_t::errors(bool recursive) +{ + std::vector< soc_error_t > err; + std::string at(name); + for(size_t i = 0; i < dev.size(); i++) + { + for(size_t j = 0; j < dev.size(); j++) + { + if(i == j) + continue; + if(dev[i].name == dev[j].name) + err.push_back(prefix(make_fatal(dev[i].name, + "there are several devices with the same name"), at)); + } + if(recursive) + add_errors(err, dev[i].errors(true), at); + } + return err; +} + +namespace +{ + +struct formula_evaluator +{ + std::string formula; + size_t pos; + std::string error; + + bool err(const char *fmt, ...) + { + char buffer[256]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer,sizeof(buffer), fmt, args); + va_end(args); + error = buffer; + return false; + } + + formula_evaluator(const std::string& s):pos(0) + { + for(size_t i = 0; i < s.size(); i++) + if(!isspace(s[i])) + formula.push_back(s[i]); + } + + void adv() + { + pos++; + } + + char cur() + { + return end() ? 0 : formula[pos]; + } + + bool end() + { + return pos >= formula.size(); + } + + bool parse_digit(char c, int basis, soc_word_t& res) + { + c = tolower(c); + if(isdigit(c)) + { + res = c - '0'; + return true; + } + if(basis == 16 && isxdigit(c)) + { + res = c + 10 - 'a'; + return true; + } + return err("invalid digit '%c'", c); + } + + bool parse_signed(soc_word_t& res) + { + char op = cur(); + if(op == '+' || op == '-') + { + adv(); + if(!parse_signed(res)) + return false; + if(op == '-') + res *= -1; + return true; + } + else if(op == '(') + { + adv(); + if(!parse_expression(res)) + return false; + if(cur() != ')') + return err("expected ')', got '%c'", cur()); + adv(); + return true; + } + else if(isdigit(op)) + { + res = op - '0'; + adv(); + int basis = 10; + if(op == '0' && cur() == 'x') + { + basis = 16; + adv(); + } + soc_word_t digit = 0; + while(parse_digit(cur(), basis, digit)) + { + res = res * basis + digit; + adv(); + } + return true; + } + else if(isalpha(op) || op == '_') + { + std::string name; + while(isalnum(cur()) || cur() == '_') + { + name.push_back(cur()); + adv(); + } + return get_variable(name, res); + } + else + return err("express signed expression, got '%c'", op); + } + + bool parse_term(soc_word_t& res) + { + if(!parse_signed(res)) + return false; + while(cur() == '*' || cur() == '/' || cur() == '%') + { + char op = cur(); + adv(); + soc_word_t tmp; + if(!parse_signed(tmp)) + return false; + if(op == '*') + res *= tmp; + else if(tmp != 0) + res = op == '/' ? res / tmp : res % tmp; + else + return err("division by 0"); + } + return true; + } + + bool parse_expression(soc_word_t& res) + { + if(!parse_term(res)) + return false; + while(!end() && (cur() == '+' || cur() == '-')) + { + char op = cur(); + adv(); + soc_word_t tmp; + if(!parse_term(tmp)) + return false; + if(op == '+') + res += tmp; + else + res -= tmp; + } + return true; + } + + bool parse(soc_word_t& res, std::string& _error) + { + bool ok = parse_expression(res); + if(ok && !end()) + err("unexpected character '%c'", cur()); + _error = error; + return ok && end(); + } + + virtual bool get_variable(std::string name, soc_word_t& res) + { + return err("unknown variable '%s'", name.c_str()); + } +}; + +struct my_evaluator : public formula_evaluator +{ + const std::map< std::string, soc_word_t>& var; + + my_evaluator(const std::string& formula, const std::map< std::string, soc_word_t>& _var) + :formula_evaluator(formula), var(_var) {} + + virtual bool get_variable(std::string name, soc_word_t& res) + { + std::map< std::string, soc_word_t>::const_iterator it = var.find(name); + if(it == var.end()) + return formula_evaluator::get_variable(name, res); + else + { + res = it->second; + return true; + } + } +}; + +} + +bool soc_desc_evaluate_formula(const std::string& formula, + const std::map< std::string, soc_word_t>& var, soc_word_t& result, std::string& error) +{ + my_evaluator e(formula, var); + return e.parse(result, error); +} |