summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--utils/regtools/desc/XML.txt5
-rw-r--r--utils/regtools/desc/regs-1.0.dtd28
-rw-r--r--utils/regtools/headergen.cpp6
-rw-r--r--utils/regtools/lib/soc_desc.cpp700
-rw-r--r--utils/regtools/lib/soc_desc.hpp49
-rw-r--r--utils/regtools/qeditor/analyser.h5
-rw-r--r--utils/regtools/qeditor/aux.cpp746
-rw-r--r--utils/regtools/qeditor/aux.h227
-rw-r--r--utils/regtools/qeditor/backend.cpp67
-rw-r--r--utils/regtools/qeditor/backend.h79
-rw-r--r--utils/regtools/qeditor/mainwindow.cpp63
-rw-r--r--utils/regtools/qeditor/mainwindow.h16
-rw-r--r--utils/regtools/qeditor/qeditor.pro6
-rw-r--r--utils/regtools/qeditor/regdisplaypanel.cpp314
-rw-r--r--utils/regtools/qeditor/regdisplaypanel.h77
-rw-r--r--utils/regtools/qeditor/regedit.cpp1324
-rw-r--r--utils/regtools/qeditor/regedit.h282
-rw-r--r--utils/regtools/qeditor/regtab.cpp534
-rw-r--r--utils/regtools/qeditor/regtab.h119
-rw-r--r--utils/regtools/qeditor/std_analysers.cpp9
-rw-r--r--utils/regtools/qeditor/std_analysers.h4
-rw-r--r--utils/regtools/tester.cpp344
22 files changed, 4390 insertions, 614 deletions
diff --git a/utils/regtools/desc/XML.txt b/utils/regtools/desc/XML.txt
index a90f875f66..3c28154a1f 100644
--- a/utils/regtools/desc/XML.txt
+++ b/utils/regtools/desc/XML.txt
@@ -9,6 +9,11 @@ Example:
<!-- desc -->
</xml>
+Root Element: root
+------------------
+The root element can either be "soc" tag if the file contains a single description,
+or "root" with no properties and one or more "soc" tags as children.
+
Element: soc
------------
The XML can contain one or more SoC description. Each description is enclosed in
diff --git a/utils/regtools/desc/regs-1.0.dtd b/utils/regtools/desc/regs-1.0.dtd
new file mode 100644
index 0000000000..3204d29195
--- /dev/null
+++ b/utils/regtools/desc/regs-1.0.dtd
@@ -0,0 +1,28 @@
+<!-- Format specification of the 1.0 register description files. Files are
+ considered to be version 1.0 if no version field is specified -->
+<!ELEMENT soc (dev)*>
+<!ATTLIST soc name CDATA #REQUIRED>
+<!ATTLIST soc desc CDATA #IMPLIED>
+<!ELEMENT dev (addr|reg)*>
+<!ATTLIST dev name CDATA #REQUIRED>
+<!ATTLIST dev long_name CDATA #IMPLIED>
+<!ATTLIST dev desc CDATA #IMPLIED>
+<!ATTLIST dev version CDATA #IMPLIED>
+<!ELEMENT addr EMPTY>
+<!ATTLIST addr name CDATA #REQUIRED>
+<!ATTLIST addr addr CDATA #REQUIRED>
+<!ELEMENT reg (addr|field|formula)*>
+<!ATTLIST reg name CDATA #REQUIRED>
+<!ATTLIST reg addr CDATA #IMPLIED>
+<!ATTLIST reg desc CDATA #IMPLIED>
+<!ATTLIST reg sct (yes|no) "no">
+<!ELEMENT formula EMPTY>
+<!ATTLIST formula string CDATA #IMPLIED>
+<!ELEMENT field (value)*>
+<!ATTLIST field name CDATA #REQUIRED>
+<!ATTLIST field desc CDATA #IMPLIED>
+<!ATTLIST field bitrange CDATA #REQUIRED>
+<!ELEMENT value EMPTY>
+<!ATTLIST value name CDATA #REQUIRED>
+<!ATTLIST value value CDATA #REQUIRED>
+<!ATTLIST value desc CDATA #IMPLIED>
diff --git a/utils/regtools/headergen.cpp b/utils/regtools/headergen.cpp
index a95dc46215..b4ade5f186 100644
--- a/utils/regtools/headergen.cpp
+++ b/utils/regtools/headergen.cpp
@@ -574,11 +574,15 @@ int main(int argc, char **argv)
std::vector< soc_t > socs;
for(int i = optind; i < argc - 1; i++)
- if(!soc_desc_parse_xml(argv[i], socs))
+ {
+ soc_t s;
+ if(!soc_desc_parse_xml(argv[i], s))
{
printf("Cannot parse %s\n", argv[i]);
return 1;
}
+ socs.push_back(s);
+ }
g_gen_selector = force_selector || socs.size() > 1;
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);
+}
diff --git a/utils/regtools/lib/soc_desc.hpp b/utils/regtools/lib/soc_desc.hpp
index efaf813eb2..d9dbf0cc20 100644
--- a/utils/regtools/lib/soc_desc.hpp
+++ b/utils/regtools/lib/soc_desc.hpp
@@ -25,6 +25,7 @@
#include <vector>
#include <list>
#include <string>
+#include <map>
/**
* These data structures represent the SoC register in a convenient way.
@@ -50,6 +51,21 @@ typedef uint32_t soc_addr_t;
typedef uint32_t soc_word_t;
typedef uint32_t soc_reg_flags_t;
+/** SoC error gravity level */
+enum soc_error_level_t
+{
+ SOC_ERROR_WARNING,
+ SOC_ERROR_FATAL,
+};
+
+/** SoC description error */
+struct soc_error_t
+{
+ soc_error_level_t level; /// level (warning, fatal, ...)
+ std::string location; /// human description of the location
+ std::string message; /// message
+};
+
/** SoC register generic formula */
enum soc_reg_formula_type_t
{
@@ -66,6 +82,8 @@ struct soc_reg_field_value_t
std::string name; /// name of the value
soc_word_t value; /// numeric value
std::string desc; /// human description
+
+ std::vector< soc_error_t > errors(bool recursive);
};
/** SoC register field */
@@ -90,6 +108,8 @@ struct soc_reg_field_t
}
std::vector< soc_reg_field_value_t > value;
+
+ std::vector< soc_error_t > errors(bool recursive);
};
/** SoC register address */
@@ -97,6 +117,8 @@ struct soc_reg_addr_t
{
std::string name; /// actual register name
soc_addr_t addr; /// actual register address (relative to device)
+
+ std::vector< soc_error_t > errors(bool recursive);
};
/** SoC register formula */
@@ -104,6 +126,8 @@ struct soc_reg_formula_t
{
enum soc_reg_formula_type_t type;
std::string string; /// for STRING
+
+ std::vector< soc_error_t > errors(bool recursive);
};
/** SoC register */
@@ -116,6 +140,8 @@ struct soc_reg_t
soc_reg_flags_t flags; /// ORed value
std::vector< soc_reg_field_t > field;
+
+ std::vector< soc_error_t > errors(bool recursive);
};
/** Soc device address */
@@ -123,6 +149,8 @@ struct soc_dev_addr_t
{
std::string name; /// actual device name
soc_addr_t addr;
+
+ std::vector< soc_error_t > errors(bool recursive);
};
/** SoC device */
@@ -135,6 +163,8 @@ struct soc_dev_t
std::vector< soc_dev_addr_t > addr;
std::vector< soc_reg_t > reg;
+
+ std::vector< soc_error_t > errors(bool recursive);
};
/** SoC */
@@ -144,10 +174,23 @@ struct soc_t
std::string desc; /// SoC name
std::vector< soc_dev_t > dev;
+
+ std::vector< soc_error_t > errors(bool recursive);
};
-/** Parse a SoC description from a XML file, append it to <soc>. A file
- * can contain multiple SoC descriptions */
-bool soc_desc_parse_xml(const std::string& filename, std::vector< soc_t >& soc);
+/** Parse a SoC description from a XML file, append it to <soc>. */
+bool soc_desc_parse_xml(const std::string& filename, soc_t& soc);
+/** Write a SoC description to a XML file, overwriting it. A file can contain
+ * multiple Soc descriptions */
+bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc);
+/** Normalise a soc description by reordering elemnts so that:
+ * - devices are sorted by first name
+ * - registers are sorted by first address
+ * - fields are sorted by last bit
+ * - values are sorted by value */
+void soc_desc_normalize(soc_t& soc);
+/** Formula parser: try to parse and evaluate a formula to a specific value of 'n' */
+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);
#endif /* __SOC_DESC__ */ \ No newline at end of file
diff --git a/utils/regtools/qeditor/analyser.h b/utils/regtools/qeditor/analyser.h
index a06652bfb0..4f9830ac4c 100644
--- a/utils/regtools/qeditor/analyser.h
+++ b/utils/regtools/qeditor/analyser.h
@@ -5,13 +5,14 @@
#include <QVector>
#include <QString>
#include "backend.h"
+#include "regtab.h"
-class Analyser : public QObject
+class Analyser : public RegTabPanel
{
- Q_OBJECT
public:
Analyser(const SocRef& soc, IoBackend *backend);
virtual ~Analyser();
+ virtual void AllowWrite(bool en) { Q_UNUSED(en); }
virtual QWidget *GetWidget() = 0;
protected:
diff --git a/utils/regtools/qeditor/aux.cpp b/utils/regtools/qeditor/aux.cpp
new file mode 100644
index 0000000000..0614bb57f6
--- /dev/null
+++ b/utils/regtools/qeditor/aux.cpp
@@ -0,0 +1,746 @@
+#include "aux.h"
+#include <QFontMetrics>
+#include <QPainter>
+#include <QTextDocument>
+#include <QAbstractTextDocumentLayout>
+#include <QHeaderView>
+#include <QDebug>
+#include <QElapsedTimer>
+#include <QXmlStreamReader>
+#include <QXmlStreamWriter>
+#include <QTextBlock>
+
+/**
+ * SocBitRangeValidator
+ */
+SocBitRangeValidator::SocBitRangeValidator(QObject *parent)
+ :QValidator(parent)
+{
+}
+
+void SocBitRangeValidator::fixup(QString& input) const
+{
+ input = input.trimmed();
+}
+
+QValidator::State SocBitRangeValidator::validate(QString& input, int& pos) const
+{
+ Q_UNUSED(pos);
+ int first, last;
+ State state = parse(input, last, first);
+ return state;
+}
+
+QValidator::State SocBitRangeValidator::parse(const QString& input, int& last, int& first) const
+{
+ // the empty string is always intermediate
+ if(input.size() == 0)
+ return Intermediate;
+ // check if there is ':'
+ int pos = input.indexOf(':');
+ if(pos == -1)
+ pos = input.size();
+ // if field start with ':', the last bit is implicit and is 31
+ if(pos > 0)
+ {
+ // parse last bit and check it's between 0 and 31
+ bool ok = false;
+ last = input.left(pos).toInt(&ok);
+ if(!ok || last < 0 || last >= 32)
+ return Invalid;
+ }
+ else
+ last = 31;
+ // parse first bit
+ if(pos < input.size() - 1)
+ {
+ bool ok = false;
+ first = input.mid(pos + 1).toInt(&ok);
+ if(!ok || first < 0 || first > last)
+ return Invalid;
+ }
+ // if input ends with ':', first bit is implicit and is 0
+ else if(pos == input.size() - 1)
+ first = 0;
+ // if there no ':', first=last
+ else
+ first = last;
+ return Acceptable;
+}
+
+/**
+ * SocFieldValidator
+ */
+
+SocFieldValidator::SocFieldValidator(QObject *parent)
+ :QValidator(parent)
+{
+ m_field.first_bit = 0;
+ m_field.last_bit = 31;
+}
+
+SocFieldValidator::SocFieldValidator(const soc_reg_field_t& field, QObject *parent)
+ :QValidator(parent), m_field(field)
+{
+}
+
+void SocFieldValidator::fixup(QString& input) const
+{
+ input = input.trimmed();
+}
+
+QValidator::State SocFieldValidator::validate(QString& input, int& pos) const
+{
+ Q_UNUSED(pos);
+ soc_word_t val;
+ State state = parse(input, val);
+ return state;
+}
+
+QValidator::State SocFieldValidator::parse(const QString& input, soc_word_t& val) const
+{
+ // the empty string is always intermediate
+ if(input.size() == 0)
+ return Intermediate;
+ // first check named values
+ State state = Invalid;
+ foreach(const soc_reg_field_value_t& value, m_field.value)
+ {
+ QString name = QString::fromLocal8Bit(value.name.c_str());
+ // cannot be a substring if too long or empty
+ if(input.size() > name.size())
+ continue;
+ // check equal string
+ if(input == name)
+ {
+ state = Acceptable;
+ val = value.value;
+ break;
+ }
+ // check substring
+ if(name.startsWith(input))
+ state = Intermediate;
+ }
+ // early return for exact match
+ if(state == Acceptable)
+ return state;
+ // do a few special cases for convenience
+ if(input.compare("0x", Qt::CaseInsensitive) == 0 ||
+ input.compare("0b", Qt::CaseInsensitive) == 0)
+ return Intermediate;
+ // try by parsing
+ unsigned basis, pos;
+ if(input.size() >= 2 && input.startsWith("0x", Qt::CaseInsensitive))
+ {
+ basis = 16;
+ pos = 2;
+ }
+ else if(input.size() >= 2 && input.startsWith("0b", Qt::CaseInsensitive))
+ {
+ basis = 2;
+ pos = 2;
+ }
+ else if(input.size() >= 2 && input.startsWith("0"))
+ {
+ basis = 8;
+ pos = 1;
+ }
+ else
+ {
+ basis = 10;
+ pos = 0;
+ }
+ bool ok = false;
+ unsigned long v = input.mid(pos).toULong(&ok, basis);
+ // if not ok, return result of name parsing
+ if(!ok)
+ return state;
+ // if ok, check if it fits in the number of bits
+ unsigned nr_bits = m_field.last_bit - m_field.first_bit + 1;
+ unsigned long max = nr_bits == 32 ? 0xffffffff : (1 << nr_bits) - 1;
+ if(v <= max)
+ {
+ val = v;
+ return Acceptable;
+ }
+
+ return state;
+}
+
+/**
+ * RegLineEdit
+ */
+RegLineEdit::RegLineEdit(QWidget *parent)
+ :QWidget(parent)
+{
+ m_layout = new QHBoxLayout(this);
+ m_button = new QToolButton(this);
+ m_button->setCursor(Qt::ArrowCursor);
+ m_button->setStyleSheet("QToolButton { font-weight: bold; color: white; background: black; }");
+ m_button->setPopupMode(QToolButton::InstantPopup);
+ m_edit = new QLineEdit(this);
+ m_layout->addWidget(m_button);
+ m_layout->addWidget(m_edit);
+ m_menu = new QMenu(this);
+ connect(m_menu->addAction("Write"), SIGNAL(triggered()), this, SLOT(OnWriteAct()));
+ connect(m_menu->addAction("Set"), SIGNAL(triggered()), this, SLOT(OnSetAct()));
+ connect(m_menu->addAction("Clear"), SIGNAL(triggered()), this, SLOT(OnClearAct()));
+ connect(m_menu->addAction("Toggle"), SIGNAL(triggered()), this, SLOT(OnToggleAct()));
+ EnableSCT(false);
+ SetReadOnly(false);
+ ShowMode(true);
+ SetMode(Write);
+}
+
+void RegLineEdit::SetReadOnly(bool ro)
+{
+ m_edit->setReadOnly(ro);
+ m_readonly = ro;
+ ShowMode(!ro);
+}
+
+void RegLineEdit::EnableSCT(bool en)
+{
+ m_has_sct = en;
+ if(!m_has_sct)
+ {
+ m_button->setMenu(0);
+ SetMode(Write);
+ }
+ else
+ m_button->setMenu(m_menu);
+}
+
+RegLineEdit::~RegLineEdit()
+{
+}
+
+QLineEdit *RegLineEdit::GetLineEdit()
+{
+ return m_edit;
+}
+
+void RegLineEdit::ShowMode(bool show)
+{
+ if(show)
+ m_button->show();
+ else
+ m_button->hide();
+}
+
+void RegLineEdit::OnWriteAct()
+{
+ SetMode(Write);
+}
+
+void RegLineEdit::OnSetAct()
+{
+ SetMode(Set);
+}
+
+void RegLineEdit::OnClearAct()
+{
+ SetMode(Clear);
+}
+
+void RegLineEdit::OnToggleAct()
+{
+ SetMode(Toggle);
+}
+
+void RegLineEdit::SetMode(EditMode mode)
+{
+ m_mode = mode;
+ switch(m_mode)
+ {
+ case Write: m_button->setText("WR"); break;
+ case Set: m_button->setText("SET"); break;
+ case Clear: m_button->setText("CLR"); break;
+ case Toggle: m_button->setText("TOG"); break;
+ default: break;
+ }
+}
+
+RegLineEdit::EditMode RegLineEdit::GetMode()
+{
+ return m_mode;
+}
+
+void RegLineEdit::setText(const QString& text)
+{
+ m_edit->setText(text);
+}
+
+QString RegLineEdit::text() const
+{
+ return m_edit->text();
+}
+
+/**
+ * SocFieldItemDelegate
+ */
+
+QString SocFieldItemDelegate::displayText(const QVariant& value, const QLocale& locale) const
+{
+ if(value.type() == QVariant::UInt)
+ return QString("0x%1").arg(value.toUInt(), (m_bitcount + 3) / 4, 16, QChar('0'));
+ else
+ return QStyledItemDelegate::displayText(value, locale);
+}
+
+/**
+ * SocFieldEditor
+ */
+SocFieldEditor::SocFieldEditor(const soc_reg_field_t& field, QWidget *parent)
+ :QLineEdit(parent), m_reg_field(field)
+{
+ m_validator = new SocFieldValidator(field);
+ setValidator(m_validator);
+}
+
+SocFieldEditor::~SocFieldEditor()
+{
+ delete m_validator;
+}
+
+uint SocFieldEditor::field() const
+{
+ soc_word_t v;
+ /* in case validator fails to parse, return old value */
+ if(m_validator->parse(text(), v) == QValidator::Acceptable)
+ return v;
+ else
+ return m_field;
+}
+
+void SocFieldEditor::setField(uint field)
+{
+ m_field = field;
+ int digits = (m_reg_field.last_bit - m_reg_field.first_bit + 4) / 4;
+ setText(QString("0x%1").arg(field, digits, 16, QChar('0')));
+}
+
+/**
+ * SocFieldEditorCreator
+ */
+QWidget *SocFieldEditorCreator::createWidget(QWidget *parent) const
+{
+ return new SocFieldEditor(m_field, parent);
+}
+
+QByteArray SocFieldEditorCreator::valuePropertyName() const
+{
+ return QByteArray("field");
+}
+
+/**
+ * RegSexyDisplay
+ */
+RegSexyDisplay::RegSexyDisplay(const SocRegRef& reg, QWidget *parent)
+ :QWidget(parent), m_reg(reg)
+{
+ m_size = QSize();
+}
+
+int RegSexyDisplay::separatorSize() const
+{
+ return 1;
+}
+
+int RegSexyDisplay::marginSize() const
+{
+ return fontMetrics().height() / 3;
+}
+
+int RegSexyDisplay::textSep() const
+{
+ return marginSize() / 2;
+}
+
+int RegSexyDisplay::headerHeight() const
+{
+ return 2 * marginSize() + textSep() + 2 * fontMetrics().height();
+}
+
+int RegSexyDisplay::columnWidth() const
+{
+ return 2 * marginSize() + fontMetrics().height();
+}
+
+int RegSexyDisplay::maxContentHeight() const
+{
+ int max = 0;
+ QFontMetrics metrics = fontMetrics();
+ for(size_t i = 0; i < m_reg.GetReg().field.size(); i++)
+ {
+ QString s = QString::fromStdString(m_reg.GetReg().field[i].name);
+ // add extra spaces arounds
+ s = " " + s + " ";
+ max = qMax(max, metrics.boundingRect(s).width());
+ }
+ return 2 * marginSize() + max;
+}
+
+int RegSexyDisplay::gapHeight() const
+{
+ return marginSize() / 2;
+}
+
+QSize RegSexyDisplay::minimumSizeHint() const
+{
+ /* cache computation because it's expensive */
+ if(m_size.isValid())
+ return m_size;
+ /* width: display 32 columns + 33 vertical separators */
+ m_size.setWidth(32 * columnWidth() + 33 * separatorSize());
+ /* height: one separator + two digits + one separator + margin + separator
+ * + names + separator */
+ m_size.setHeight(4 * separatorSize() + headerHeight() + gapHeight() + maxContentHeight());
+ return m_size;
+}
+
+QSize RegSexyDisplay::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+void RegSexyDisplay::paintEvent(QPaintEvent *event)
+{
+ // FIXME could be optimised with QStaticText
+ Q_UNUSED(event);
+ int txt_h = fontMetrics().height();
+ int sep_sz = separatorSize();
+ int w = width();
+ int h = height() - 1;
+ int col_w = (w - 33 * sep_sz) / 32;
+ int hdr_h = headerHeight();
+ int gap_h = gapHeight();
+ int tot_w = 33 * sep_sz + 32 * col_w;
+ int margin = marginSize();
+ int txt_sep = textSep();
+ int tot_hdr_sz = 2 * sep_sz + hdr_h;
+ // computer xshift
+ int x_shift = (w - tot_w) / 2;
+#define ith_col_x(i) (x_shift + (i) * (sep_sz + col_w))
+
+ QPainter painter(this);
+ QBrush back_brush = palette().base();
+ QBrush line_brush = palette().dark();
+
+ // fill interesting zone with base
+ painter.fillRect(x_shift, 0, tot_w, h, back_brush);
+
+ // draw top and bottom lines
+ painter.setPen(QPen(palette().dark(), sep_sz));
+ painter.fillRect(x_shift, 0, tot_w, sep_sz, line_brush);
+ painter.fillRect(x_shift, h - sep_sz, tot_w, sep_sz, line_brush);
+ // draw intemediate lines
+ for(int i = 0; i <= 32; i++)
+ painter.fillRect(ith_col_x(i), 0, sep_sz, 2 * sep_sz + hdr_h, line_brush);
+ // draw bottom header lines
+ painter.fillRect(ith_col_x(0), sep_sz + hdr_h, tot_w, sep_sz, line_brush);
+ painter.fillRect(ith_col_x(0), tot_hdr_sz + gap_h, tot_w, sep_sz, line_brush);
+ // redraw some lines but wider
+ for(int i = 4; i < 32; i += 4)
+ painter.fillRect(ith_col_x(i) - sep_sz, 0, 3 * sep_sz, tot_hdr_sz, line_brush);
+ // draw numbers in the header
+ painter.setPen(palette().brush(QPalette::ButtonText).color());
+ for(int i = 0; i < 32; i++)
+ {
+ QRect r(ith_col_x(i), sep_sz + margin, col_w, txt_h);
+ painter.drawText(r, Qt::AlignCenter, QString("%1").arg((31 - i) / 10));
+ r.translate(0, txt_h + txt_sep);
+ painter.drawText(r, Qt::AlignCenter, QString("%1").arg((31 - i) % 10));
+ }
+ // display content
+ for(size_t i = 0; i < m_reg.GetReg().field.size(); i++)
+ {
+ const soc_reg_field_t& field = m_reg.GetReg().field[i];
+ QRect r(QPoint(ith_col_x(31 - field.last_bit) + sep_sz, tot_hdr_sz),
+ QPoint(ith_col_x(32 - field.first_bit), h - sep_sz));
+ painter.fillRect(r.x() - sep_sz, r.y(), sep_sz, r.height(), line_brush);
+ painter.fillRect(r.right(), r.y(), sep_sz, r.height(), line_brush);
+ r.setY(r.y() + gap_h + sep_sz);
+ // draw rotated text
+ painter.save();
+ painter.translate(r.bottomLeft());
+ painter.rotate(-90);
+ //painter.fillRect(QRect(0, 0, r.height(), r.width()), QBrush(Qt::red));
+ QRect r2(0, 0, r.height(), r.width());
+ painter.drawText(r2, Qt::AlignCenter, QString::fromStdString(field.name));
+ painter.restore();
+ }
+#undef ith_col_x
+}
+
+/**
+ * GrowingTextEdit
+ */
+GrowingTextEdit::GrowingTextEdit(QWidget *parent)
+ :QTextEdit(parent)
+{
+ connect(this, SIGNAL(textChanged()), this, SLOT(TextChanged()));
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+}
+
+void GrowingTextEdit::TextChanged()
+{
+ int content_size = document()->documentLayout()->documentSize().height();
+ content_size = qMax(content_size, fontMetrics().height());
+ setFixedHeight(content_size + contentsMargins().top() + contentsMargins().bottom());
+}
+
+/**
+ * GrowingTableWidget
+ */
+GrowingTableWidget::GrowingTableWidget(QWidget *parent)
+ :QTableWidget(parent)
+{
+ connect(model(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
+ this, SLOT(DataChanged(const QModelIndex&, const QModelIndex&)));
+}
+
+void GrowingTableWidget::DataChanged(const QModelIndex& tl, const QModelIndex& br)
+{
+ Q_UNUSED(tl);
+ Q_UNUSED(br);
+ resizeRowsToContents();
+ resizeColumnsToContents();
+ int h = contentsMargins().top() + contentsMargins().bottom();
+ h += horizontalHeader()->height();
+ for(int i = 0; i < rowCount(); i++)
+ h += rowHeight(i);
+ setMinimumHeight(h);
+}
+
+/**
+ * MyTextEditor
+ */
+MyTextEditor::MyTextEditor(QWidget *parent)
+ :QWidget(parent)
+{
+ QVBoxLayout *layout = new QVBoxLayout;
+ m_toolbar = new QToolBar(this);
+ m_edit = new QTextEdit(this);
+ layout->addWidget(m_toolbar, 0);
+ layout->addWidget(m_edit, 1);
+ setLayout(layout);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ m_edit->setAcceptRichText(false);
+ m_edit->setAutoFormatting(QTextEdit::AutoAll);
+
+ m_bold_button = new QToolButton(this);
+ m_bold_button->setIcon(QIcon::fromTheme("format-text-bold"));
+ m_bold_button->setText("bold");
+ m_bold_button->setCheckable(true);
+
+ m_italic_button = new QToolButton(this);
+ m_italic_button->setIcon(QIcon::fromTheme("format-text-italic"));
+ m_italic_button->setText("italic");
+ m_italic_button->setCheckable(true);
+
+ m_underline_button = new QToolButton(this);
+ m_underline_button->setIcon(QIcon::fromTheme("format-text-underline"));
+ m_underline_button->setText("underline");
+ m_underline_button->setCheckable(true);
+
+ m_toolbar->addWidget(m_bold_button);
+ m_toolbar->addWidget(m_italic_button);
+ m_toolbar->addWidget(m_underline_button);
+
+ connect(m_bold_button, SIGNAL(toggled(bool)), this, SLOT(OnTextBold(bool)));
+ connect(m_italic_button, SIGNAL(toggled(bool)), this, SLOT(OnTextItalic(bool)));
+ connect(m_underline_button, SIGNAL(toggled(bool)), this, SLOT(OnTextUnderline(bool)));
+ connect(m_edit, SIGNAL(textChanged()), this, SLOT(OnInternalTextChanged()));
+ connect(m_edit, SIGNAL(currentCharFormatChanged(const QTextCharFormat&)),
+ this, SLOT(OnCharFormatChanged(const QTextCharFormat&)));
+
+ SetGrowingMode(false);
+ SetReadOnly(false);
+}
+
+void MyTextEditor::SetReadOnly(bool en)
+{
+ m_read_only = en;
+ if(en)
+ m_toolbar->hide();
+ else
+ m_toolbar->hide();
+ m_edit->setReadOnly(en);
+}
+
+void MyTextEditor::SetGrowingMode(bool en)
+{
+ m_growing_mode = en;
+ if(en)
+ {
+ m_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+ m_edit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ OnTextChanged();
+ }
+ else
+ {
+ m_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_edit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ }
+}
+
+void MyTextEditor::OnInternalTextChanged()
+{
+ if(m_growing_mode)
+ {
+ int content_size = m_edit->document()->documentLayout()->documentSize().height();
+ content_size = qMax(content_size, m_edit->fontMetrics().height());
+ m_edit->setMinimumHeight(content_size + m_edit->contentsMargins().top() +
+ m_edit->contentsMargins().bottom());
+ }
+ emit OnTextChanged();
+}
+
+void MyTextEditor::OnTextBold(bool checked)
+{
+ QTextCursor cursor = m_edit->textCursor();
+ QTextCharFormat fmt = cursor.charFormat();
+ fmt.setFontWeight(checked ? QFont::Bold : QFont::Normal);
+ cursor.setCharFormat(fmt);
+ m_edit->setTextCursor(cursor);
+}
+
+void MyTextEditor::OnTextItalic(bool checked)
+{
+ QTextCursor cursor = m_edit->textCursor();
+ QTextCharFormat fmt = cursor.charFormat();
+ fmt.setFontItalic(checked);
+ cursor.setCharFormat(fmt);
+ m_edit->setTextCursor(cursor);
+}
+
+void MyTextEditor::OnTextUnderline(bool checked)
+{
+ QTextCursor cursor = m_edit->textCursor();
+ QTextCharFormat fmt = cursor.charFormat();
+ fmt.setFontUnderline(checked);
+ cursor.setCharFormat(fmt);
+ m_edit->setTextCursor(cursor);
+}
+
+void MyTextEditor::OnCharFormatChanged(const QTextCharFormat& fmt)
+{
+ /* NOTE: changing the button states programmaticaly doesn't trigger
+ * the toggled() signals, otherwise it would result in a loop
+ * between this function and OnText{Bold,Italic,Underline,...} */
+ m_bold_button->setChecked(fmt.fontWeight() > QFont::Normal);
+ m_italic_button->setChecked(fmt.fontItalic());
+ m_underline_button->setChecked(fmt.fontUnderline());
+}
+
+void MyTextEditor::SetTextHtml(const QString& text)
+{
+ m_edit->setHtml(text);
+}
+
+QString MyTextEditor::GetTextHtml()
+{
+ return m_edit->toPlainText();
+}
+
+bool MyTextEditor::IsModified()
+{
+ return m_edit->document()->isModified();
+}
+
+/**
+ * MySwitchableTextEditor
+ */
+MySwitchableTextEditor::MySwitchableTextEditor(QWidget *parent)
+ :QWidget(parent)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ m_edit = new MyTextEditor(this);
+ m_label = new QLabel(this);
+ m_label->setTextFormat(Qt::RichText);
+ m_label->setAlignment(Qt::AlignTop);
+ m_line = new QLineEdit(this);
+
+ layout->addWidget(m_label);
+ layout->addWidget(m_edit);
+ layout->addWidget(m_line);
+
+ setLayout(layout);
+
+ m_editor_mode = false;
+ m_line_mode = false;
+ UpdateVisibility();
+}
+
+void MySwitchableTextEditor::SetEditorMode(bool edit)
+{
+ if(edit == m_editor_mode)
+ return;
+ QString text = GetTextHtml();
+ m_editor_mode = edit;
+ UpdateVisibility();
+ SetTextHtml(text);
+}
+
+QString MySwitchableTextEditor::GetTextHtml()
+{
+ if(m_editor_mode)
+ return m_line_mode ? m_line->text() : m_edit->GetTextHtml();
+ else
+ return m_label->text();
+}
+
+void MySwitchableTextEditor::SetTextHtml(const QString& text)
+{
+ if(m_editor_mode)
+ {
+ if(m_line_mode)
+ m_line->setText(text);
+ else
+ m_edit->SetTextHtml(text);
+ }
+ else
+ m_label->setText(text);
+}
+
+MyTextEditor *MySwitchableTextEditor::GetEditor()
+{
+ return m_edit;
+}
+
+void MySwitchableTextEditor::SetLineMode(bool en)
+{
+ if(m_line_mode == en)
+ return;
+ QString text = GetTextHtml();
+ m_line_mode = en;
+ SetTextHtml(text);
+ UpdateVisibility();
+}
+
+QLineEdit *MySwitchableTextEditor::GetLineEdit()
+{
+ return m_line;
+}
+
+void MySwitchableTextEditor::UpdateVisibility()
+{
+ m_label->setVisible(!m_editor_mode);
+ m_edit->setVisible(m_editor_mode && !m_line_mode);
+ m_line->setVisible(m_editor_mode && m_line_mode);
+}
+
+QLabel *MySwitchableTextEditor::GetLabel()
+{
+ return m_label;
+}
+
+bool MySwitchableTextEditor::IsModified()
+{
+ if(!m_editor_mode)
+ return false;
+ return m_line_mode ? m_line->isModified() : m_edit->IsModified();
+}
diff --git a/utils/regtools/qeditor/aux.h b/utils/regtools/qeditor/aux.h
new file mode 100644
index 0000000000..d6a572826c
--- /dev/null
+++ b/utils/regtools/qeditor/aux.h
@@ -0,0 +1,227 @@
+#ifndef AUX_H
+#define AUX_H
+
+#include <QEvent>
+#include <QPaintEvent>
+#include <QLineEdit>
+#include <QValidator>
+#include <QToolButton>
+#include <QMenu>
+#include <QHBoxLayout>
+#include <QTextEdit>
+#include <QTableWidget>
+#include <QToolBar>
+#include <QLabel>
+#include <QHBoxLayout>
+#include <QItemEditorCreatorBase>
+#include <QStyledItemDelegate>
+#include "backend.h"
+
+class SocBitRangeValidator : public QValidator
+{
+ Q_OBJECT
+public:
+ SocBitRangeValidator(QObject *parent = 0);
+
+ virtual void fixup(QString& input) const;
+ virtual State validate(QString& input, int& pos) const;
+ /* validate and return the interpreted value */
+ State parse(const QString& input, int& last_bit, int& first_bit) const;
+};
+
+class SocFieldValidator : public QValidator
+{
+ Q_OBJECT
+public:
+ SocFieldValidator(QObject *parent = 0);
+ SocFieldValidator(const soc_reg_field_t& field, QObject *parent = 0);
+
+ virtual void fixup(QString& input) const;
+ virtual State validate(QString& input, int& pos) const;
+ /* validate and return the interpreted value */
+ State parse(const QString& input, soc_word_t& val) const;
+
+protected:
+ soc_reg_field_t m_field;
+};
+
+class RegLineEdit : public QWidget
+{
+ Q_OBJECT
+public:
+ enum EditMode
+ {
+ Write, Set, Clear, Toggle
+ };
+
+ RegLineEdit(QWidget *parent = 0);
+ ~RegLineEdit();
+ void SetReadOnly(bool ro);
+ void EnableSCT(bool en);
+ void SetMode(EditMode mode);
+ EditMode GetMode();
+ QLineEdit *GetLineEdit();
+ void setText(const QString& text);
+ QString text() const;
+
+ Q_PROPERTY(QString text READ text WRITE setText USER true)
+
+protected slots:
+ void OnWriteAct();
+ void OnSetAct();
+ void OnClearAct();
+ void OnToggleAct();
+protected:
+ void ShowMode(bool show);
+ void DoAutoHide();
+
+ QHBoxLayout *m_layout;
+ QToolButton *m_button;
+ QLineEdit *m_edit;
+ EditMode m_mode;
+ bool m_has_sct;
+ bool m_readonly;
+ QMenu *m_menu;
+};
+
+class SocFieldItemDelegate : public QStyledItemDelegate
+{
+public:
+ SocFieldItemDelegate(QObject *parent = 0):QStyledItemDelegate(parent), m_bitcount(32) {}
+ SocFieldItemDelegate(const soc_reg_field_t& field, QObject *parent = 0)
+ :QStyledItemDelegate(parent), m_bitcount(field.last_bit - field.first_bit + 1) {}
+
+ virtual QString displayText(const QVariant& value, const QLocale& locale) const;
+protected:
+ int m_bitcount;
+};
+
+class SocFieldEditor : public QLineEdit
+{
+ Q_OBJECT
+ Q_PROPERTY(uint field READ field WRITE setField USER true)
+public:
+ SocFieldEditor(const soc_reg_field_t& field, QWidget *parent = 0);
+ virtual ~SocFieldEditor();
+
+ uint field() const;
+ void setField(uint field);
+
+protected:
+ SocFieldValidator *m_validator;
+ uint m_field;
+ soc_reg_field_t m_reg_field;
+};
+
+class SocFieldEditorCreator : public QItemEditorCreatorBase
+{
+public:
+ SocFieldEditorCreator() { m_field.first_bit = 0; m_field.last_bit = 31; }
+ SocFieldEditorCreator(const soc_reg_field_t& field):m_field(field) {}
+
+ virtual QWidget *createWidget(QWidget *parent) const;
+ virtual QByteArray valuePropertyName() const;
+
+protected:
+ soc_reg_field_t m_field;
+};
+
+class RegSexyDisplay : public QWidget
+{
+ Q_OBJECT
+public:
+ RegSexyDisplay(const SocRegRef& reg, QWidget *parent = 0);
+
+ QSize minimumSizeHint() const;
+ QSize sizeHint() const;
+
+protected:
+ int marginSize() const;
+ int separatorSize() const;
+ int columnWidth() const;
+ int headerHeight() const;
+ int gapHeight() const;
+ int maxContentHeight() const;
+ int textSep() const;
+ void paintEvent(QPaintEvent *event);
+
+private:
+ SocRegRef m_reg;
+ mutable QSize m_size;
+};
+
+class GrowingTextEdit : public QTextEdit
+{
+ Q_OBJECT
+public:
+ GrowingTextEdit(QWidget *parent = 0);
+
+protected slots:
+ void TextChanged();
+};
+
+class GrowingTableWidget : public QTableWidget
+{
+ Q_OBJECT
+public:
+ GrowingTableWidget(QWidget *parent = 0);
+
+protected slots:
+ void DataChanged(const QModelIndex& tl, const QModelIndex& br);
+};
+
+class MyTextEditor : public QWidget
+{
+ Q_OBJECT
+public:
+ MyTextEditor(QWidget *parent = 0);
+ void SetGrowingMode(bool en);
+ void SetReadOnly(bool ro);
+ void SetTextHtml(const QString& text);
+ QString GetTextHtml();
+ bool IsModified();
+signals:
+ void OnTextChanged();
+
+protected slots:
+ void OnInternalTextChanged();
+ void OnTextBold(bool checked);
+ void OnTextItalic(bool checked);
+ void OnTextUnderline(bool checked);
+ void OnCharFormatChanged(const QTextCharFormat& fmt);
+
+protected:
+ bool m_growing_mode;
+ bool m_read_only;
+ QToolBar *m_toolbar;
+ QTextEdit *m_edit;
+ QToolButton *m_bold_button;
+ QToolButton *m_italic_button;
+ QToolButton *m_underline_button;
+};
+
+class MySwitchableTextEditor : public QWidget
+{
+ Q_OBJECT
+public:
+ MySwitchableTextEditor(QWidget *parent = 0);
+ QString GetTextHtml();
+ void SetTextHtml(const QString& text);
+ void SetEditorMode(bool en);
+ MyTextEditor *GetEditor();
+ QLineEdit *GetLineEdit();
+ QLabel *GetLabel();
+ void SetLineMode(bool en);
+ bool IsModified();
+
+protected:
+ void UpdateVisibility();
+
+ bool m_editor_mode;
+ bool m_line_mode;
+ QLabel *m_label;
+ MyTextEditor *m_edit;
+ QLineEdit *m_line;
+};
+
+#endif /* AUX_H */
diff --git a/utils/regtools/qeditor/backend.cpp b/utils/regtools/qeditor/backend.cpp
index eebda31989..204c160054 100644
--- a/utils/regtools/qeditor/backend.cpp
+++ b/utils/regtools/qeditor/backend.cpp
@@ -5,6 +5,36 @@
#include "backend.h"
/**
+ * SocFile
+ */
+SocFile::SocFile()
+ :m_valid(false)
+{
+}
+
+SocFile::SocFile(const QString& filename)
+ :m_filename(filename)
+{
+ m_valid = soc_desc_parse_xml(filename.toStdString(), m_soc);
+ soc_desc_normalize(m_soc);
+}
+
+bool SocFile::IsValid()
+{
+ return m_valid;
+}
+
+SocRef SocFile::GetSocRef()
+{
+ return SocRef(this);
+}
+
+QString SocFile::GetFilename()
+{
+ return m_filename;
+}
+
+/**
* Backend
*/
@@ -12,33 +42,31 @@ Backend::Backend()
{
}
-QStringList Backend::GetSocNameList()
+
+QList< SocFileRef > Backend::GetSocFileList()
{
- QStringList sl;
- foreach(const soc_t& soc, m_socs)
- sl.append(QString(soc.name.c_str()));
- return sl;
+ QList< SocFileRef > list;
+ for(std::list< SocFile >::iterator it = m_socs.begin(); it != m_socs.end(); ++it)
+ list.append(SocFileRef(&(*it)));
+ return list;
}
-bool Backend::GetSocByName(const QString& name, SocRef& s)
+QList< SocRef > Backend::GetSocList()
{
- for(std::list< soc_t >::iterator it = m_socs.begin(); it != m_socs.end(); ++it)
- if(it->name == name.toStdString())
- {
- s = SocRef(&(*it));
- return true;
- }
- return false;
+ QList< SocRef > list;
+ for(std::list< SocFile >::iterator it = m_socs.begin(); it != m_socs.end(); ++it)
+ list.append(it->GetSocRef());
+ return list;
}
bool Backend::LoadSocDesc(const QString& filename)
{
- std::vector< soc_t > new_socs;
- bool ret = soc_desc_parse_xml(filename.toStdString(), new_socs);
- for(size_t i = 0; i < new_socs.size(); i++)
- m_socs.push_back(new_socs[i]);
+ SocFile f(filename);
+ if(!f.IsValid())
+ return false;
+ m_socs.push_back(f);
emit OnSocListChanged();
- return ret;
+ return true;
}
IoBackend *Backend::CreateFileIoBackend(const QString& filename)
@@ -321,7 +349,7 @@ HWStubBackendHelper::HWStubBackendHelper()
if(m_hotplug)
{
m_hotplug = LIBUSB_SUCCESS == libusb_hotplug_register_callback(
- NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
+ NULL, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
LIBUSB_HOTPLUG_ENUMERATE, HWSTUB_USB_VID, HWSTUB_USB_PID, HWSTUB_CLASS,
&HWStubBackendHelper::HotPlugCallback, reinterpret_cast< void* >(this), &m_hotplug_handle);
}
@@ -364,6 +392,7 @@ void HWStubBackendHelper::OnHotPlug(bool arrived, struct libusb_device *dev)
int HWStubBackendHelper::HotPlugCallback(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event, void *user_data)
{
+ Q_UNUSED(ctx);
HWStubBackendHelper *helper = reinterpret_cast< HWStubBackendHelper* >(user_data);
switch(event)
{
diff --git a/utils/regtools/qeditor/backend.h b/utils/regtools/qeditor/backend.h
index 939ed9529f..a813f5929f 100644
--- a/utils/regtools/qeditor/backend.h
+++ b/utils/regtools/qeditor/backend.h
@@ -5,10 +5,11 @@
#include <QStringList>
#include <QMap>
#include <QVector>
-#include "soc_desc.hpp"
+#include <QMetaType>
#ifdef HAVE_HWSTUB
#include "hwstub.h"
#endif
+#include "soc.h"
class IoBackend : public QObject
{
@@ -62,18 +63,18 @@ class DummyIoBackend : public IoBackend
public:
DummyIoBackend() {}
- virtual bool SupportAccess(AccessType type) { (void) type; return false; }
+ virtual bool SupportAccess(AccessType type) { Q_UNUSED(type); return false; }
virtual QString GetSocName() { return ""; }
virtual bool ReadRegister(const QString& name, soc_word_t& value)
- { (void) name; (void) value; return false; }
+ { Q_UNUSED(name); Q_UNUSED(value); return false; }
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value)
- { (void) addr; (void) value; return false; }
+ { Q_UNUSED(addr); Q_UNUSED(value); return false; }
virtual bool Reload() { return false; }
virtual bool IsReadOnly() { return true; }
virtual bool WriteRegister(const QString& name, soc_word_t value, WriteMode mode)
- { (void) name; (void) value; (void) mode; return false; }
+ { Q_UNUSED(name); Q_UNUSED(value); Q_UNUSED(mode); return false; }
virtual bool WriteRegister(soc_addr_t addr, soc_word_t value, WriteMode mode)
- { (void) addr; (void) value; (void) mode; return false; }
+ { Q_UNUSED(addr); Q_UNUSED(value); Q_UNUSED(mode); return false; }
virtual bool IsDirty() { return false; }
virtual bool Commit() { return false; }
};
@@ -90,12 +91,12 @@ public:
virtual QString GetSocName();
virtual bool ReadRegister(const QString& name, soc_word_t& value);
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value)
- { (void) addr; (void) value; return false; }
+ { Q_UNUSED(addr); Q_UNUSED(value); return false; }
virtual bool Reload();
virtual bool IsReadOnly() { return m_readonly; }
virtual bool WriteRegister(const QString& name, soc_word_t value, WriteMode mode);
virtual bool WriteRegister(soc_addr_t addr, soc_word_t value, WriteMode mode)
- { (void) addr; (void) value; (void) mode; return false; }
+ { Q_UNUSED(addr); Q_UNUSED(value); Q_UNUSED(mode); return false; }
virtual bool IsDirty() { return m_dirty; }
virtual bool Commit();
@@ -149,12 +150,12 @@ public:
virtual bool SupportAccess(AccessType type) { return type == ByAddress; }
virtual QString GetSocName();
virtual bool ReadRegister(const QString& name, soc_word_t& value)
- { (void) name; (void) value; return false; }
+ { Q_UNUSED(name); Q_UNUSED(value); return false; }
virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value);
virtual bool Reload();
virtual bool IsReadOnly() { return false; }
virtual bool WriteRegister(const QString& name, soc_word_t value, WriteMode mode)
- { (void) name; (void) value; (void) mode; return false; }
+ { Q_UNUSED(name); Q_UNUSED(value); Q_UNUSED(mode); return false; }
virtual bool WriteRegister(soc_addr_t addr, soc_word_t value, WriteMode mode);
virtual bool IsDirty() { return false; }
virtual bool Commit() { return true; }
@@ -191,16 +192,48 @@ protected:
};
#endif
-class SocRef
+class SocRef;
+
+class SocFile
+{
+public:
+ SocFile();
+ SocFile(const QString& filename);
+ bool IsValid();
+
+ SocRef GetSocRef();
+ QString GetFilename();
+ soc_t& GetSoc() { return m_soc; }
+
+protected:
+ bool m_valid;
+ QString m_filename;
+ soc_t m_soc;
+};
+
+class SocFileRef
{
public:
- SocRef():m_soc(0) {}
- SocRef(const soc_t *soc):m_soc(soc) {}
- const soc_t& GetSoc() const { return *m_soc; }
+ SocFileRef():m_socfile(0) {}
+ SocFileRef(SocFile *file):m_socfile(file) {}
+ SocFile *GetSocFile() const { return m_socfile; }
+
protected:
- const soc_t *m_soc;
+ SocFile *m_socfile;
};
+Q_DECLARE_METATYPE(SocFileRef)
+
+class SocRef : public SocFileRef
+{
+public:
+ SocRef() {}
+ SocRef(SocFile *file):SocFileRef(file) {}
+ soc_t& GetSoc() const { return GetSocFile()->GetSoc(); }
+};
+
+Q_DECLARE_METATYPE(SocRef)
+
class SocDevRef : public SocRef
{
public:
@@ -208,9 +241,9 @@ public:
SocDevRef(const SocRef& soc, int dev_idx, int dev_addr_idx)
:SocRef(soc), m_dev_idx(dev_idx), m_dev_addr_idx(dev_addr_idx) {}
int GetDevIndex() const { return m_dev_idx; }
- const soc_dev_t& GetDev() const { return GetSoc().dev[GetDevIndex()]; }
+ soc_dev_t& GetDev() const { return GetSoc().dev[GetDevIndex()]; }
int GetDevAddrIndex() const { return m_dev_addr_idx; }
- const soc_dev_addr_t& GetDevAddr() const { return GetDev().addr[GetDevAddrIndex()]; }
+ soc_dev_addr_t& GetDevAddr() const { return GetDev().addr[GetDevAddrIndex()]; }
protected:
int m_dev_idx, m_dev_addr_idx;
};
@@ -222,9 +255,9 @@ public:
SocRegRef(const SocDevRef& dev, int reg_idx, int reg_addr_idx)
:SocDevRef(dev), m_reg_idx(reg_idx), m_reg_addr_idx(reg_addr_idx) {}
int GetRegIndex() const { return m_reg_idx; }
- const soc_reg_t& GetReg() const { return GetDev().reg[GetRegIndex()]; }
+ soc_reg_t& GetReg() const { return GetDev().reg[GetRegIndex()]; }
int GetRegAddrIndex() const { return m_reg_addr_idx; }
- const soc_reg_addr_t& GetRegAddr() const { return GetReg().addr[GetRegAddrIndex()]; }
+ soc_reg_addr_t& GetRegAddr() const { return GetReg().addr[GetRegAddrIndex()]; }
protected:
int m_reg_idx, m_reg_addr_idx;
};
@@ -236,7 +269,7 @@ public:
SocFieldRef(const SocRegRef& reg, int field_idx)
:SocRegRef(reg), m_field_idx(field_idx) {}
int GetFieldIndex() const { return m_field_idx; }
- const soc_reg_field_t& GetField() const { return GetReg().field[GetFieldIndex()]; }
+ soc_reg_field_t& GetField() const { return GetReg().field[GetFieldIndex()]; }
protected:
int m_field_idx;
};
@@ -247,9 +280,9 @@ class Backend : public QObject
public:
Backend();
- QStringList GetSocNameList();
+ QList< SocFileRef > GetSocFileList();
+ QList< SocRef > GetSocList();
bool LoadSocDesc(const QString& filename);
- bool GetSocByName(const QString& name, SocRef& s);
IoBackend *CreateDummyIoBackend();
IoBackend *CreateFileIoBackend(const QString& filename);
#ifdef HAVE_HWSTUB
@@ -259,7 +292,7 @@ public:
signals:
void OnSocListChanged();
private:
- std::list< soc_t > m_socs;
+ std::list< SocFile > m_socs;
};
class BackendHelper
diff --git a/utils/regtools/qeditor/mainwindow.cpp b/utils/regtools/qeditor/mainwindow.cpp
index 2ba781b042..cd0926851c 100644
--- a/utils/regtools/qeditor/mainwindow.cpp
+++ b/utils/regtools/qeditor/mainwindow.cpp
@@ -12,6 +12,7 @@
#include "mainwindow.h"
#include "regtab.h"
+#include "regedit.h"
MyTabWidget::MyTabWidget()
{
@@ -20,23 +21,37 @@ MyTabWidget::MyTabWidget()
connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(OnCloseTab(int)));
}
-void MyTabWidget::OnCloseTab(int index)
+bool MyTabWidget::CloseTab(int index)
{
QWidget *w = this->widget(index);
- removeTab(index);
- delete w;
+ DocumentTab *doc = dynamic_cast< DocumentTab* >(w);
+ if(doc->Quit())
+ {
+ removeTab(index);
+ delete w;
+ return true;
+ }
+ else
+ return false;
+}
+
+void MyTabWidget::OnCloseTab(int index)
+{
+ CloseTab(index);
}
MainWindow::MainWindow(Backend *backend)
:m_backend(backend)
{
- QAction *new_regtab_act = new QAction(QIcon::fromTheme("document-new"), tr("&Register Tab"), this);
+ QAction *new_regtab_act = new QAction(QIcon::fromTheme("document-new"), tr("Register &Tab"), this);
+ QAction *new_regedit_act = new QAction(QIcon::fromTheme("document-edit"), tr("Register &Editor"), this);
QAction *load_desc_act = new QAction(QIcon::fromTheme("document-open"), tr("&Soc Description"), this);
QAction *quit_act = new QAction(QIcon::fromTheme("application-exit"), tr("&Quit"), this);
QAction *about_act = new QAction(QIcon::fromTheme("help-about"), tr("&About"), this);
QAction *about_qt_act = new QAction(QIcon::fromTheme("help-about"), tr("About &Qt"), this);
connect(new_regtab_act, SIGNAL(triggered()), this, SLOT(OnNewRegTab()));
+ connect(new_regedit_act, SIGNAL(triggered()), this, SLOT(OnNewRegEdit()));
connect(load_desc_act, SIGNAL(triggered()), this, SLOT(OnLoadDesc()));
connect(quit_act, SIGNAL(triggered()), this, SLOT(OnQuit()));
connect(about_act, SIGNAL(triggered()), this, SLOT(OnAbout()));
@@ -48,6 +63,7 @@ MainWindow::MainWindow(Backend *backend)
file_menu->addAction(quit_act);
new_submenu->addAction(new_regtab_act);
+ new_submenu->addAction(new_regedit_act);
load_submenu->addAction(load_desc_act);
@@ -91,6 +107,8 @@ void MainWindow::OnAboutQt()
void MainWindow::closeEvent(QCloseEvent *event)
{
+ if(!Quit())
+ return event->ignore();
WriteSettings();
event->accept();
}
@@ -100,7 +118,7 @@ void MainWindow::OnLoadDesc()
QFileDialog *fd = new QFileDialog(this);
fd->setFilter("XML files (*.xml);;All files (*)");
fd->setFileMode(QFileDialog::ExistingFiles);
- fd->setDirectory(Settings::Get()->value("mainwindow/loaddescdir", QDir::currentPath()).toString());
+ fd->setDirectory(Settings::Get()->value("loaddescdir", QDir::currentPath()).toString());
if(fd->exec())
{
QStringList filenames = fd->selectedFiles();
@@ -111,11 +129,42 @@ void MainWindow::OnLoadDesc()
msg.setText(QString("Cannot load ") + filenames[i]);
msg.exec();
}
- Settings::Get()->setValue("mainwindow/loaddescdir", fd->directory().absolutePath());
+ Settings::Get()->setValue("loaddescdir", fd->directory().absolutePath());
}
}
+void MainWindow::OnTabModified(bool modified)
+{
+ QWidget *sender = qobject_cast< QWidget* >(QObject::sender());
+ int index = m_tab->indexOf(sender);
+ if(modified)
+ m_tab->setTabIcon(index, QIcon::fromTheme("document-save"));
+ else
+ m_tab->setTabIcon(index, QIcon());
+}
+
+void MainWindow::AddTab(QWidget *tab, const QString& title)
+{
+ connect(tab, SIGNAL(OnModified(bool)), this, SLOT(OnTabModified(bool)));
+ m_tab->setCurrentIndex(m_tab->addTab(tab, title));
+}
+
void MainWindow::OnNewRegTab()
{
- m_tab->addTab(new RegTab(m_backend), "Register Tab");
+ AddTab(new RegTab(m_backend, this), "Register Tab");
+}
+
+void MainWindow::OnNewRegEdit()
+{
+ AddTab(new RegEdit(m_backend, this), "Register Editor");
+}
+
+bool MainWindow::Quit()
+{
+ while(m_tab->count() > 0)
+ {
+ if(!m_tab->CloseTab(0))
+ return false;
+ }
+ return true;
}
diff --git a/utils/regtools/qeditor/mainwindow.h b/utils/regtools/qeditor/mainwindow.h
index d7dab3717f..b32b0647f5 100644
--- a/utils/regtools/qeditor/mainwindow.h
+++ b/utils/regtools/qeditor/mainwindow.h
@@ -7,11 +7,19 @@
#include "backend.h"
#include "settings.h"
+class DocumentTab
+{
+public:
+ virtual bool Quit() = 0;
+ virtual void OnModified(bool modified) = 0;
+};
+
class MyTabWidget : public QTabWidget
{
Q_OBJECT
public:
MyTabWidget();
+ bool CloseTab(int index);
private slots:
void OnCloseTab(int index);
@@ -30,15 +38,21 @@ public:
private:
void closeEvent(QCloseEvent *event);
+protected:
+ void AddTab(QWidget *tab, const QString& title);
+ bool Quit();
+
private slots:
void OnQuit();
void OnAbout();
void OnAboutQt();
void OnLoadDesc();
void OnNewRegTab();
+ void OnNewRegEdit();
+ void OnTabModified(bool modified);
private:
- QTabWidget *m_tab;
+ MyTabWidget *m_tab;
Backend *m_backend;
};
diff --git a/utils/regtools/qeditor/qeditor.pro b/utils/regtools/qeditor/qeditor.pro
index 5604fe9d41..38d7c987bf 100644
--- a/utils/regtools/qeditor/qeditor.pro
+++ b/utils/regtools/qeditor/qeditor.pro
@@ -1,7 +1,9 @@
QT += widgets
-HEADERS += mainwindow.h backend.h regtab.h analyser.h settings.h std_analysers.h
-SOURCES += main.cpp mainwindow.cpp regtab.cpp backend.cpp analyser.cpp std_analysers.cpp settings.cpp
+HEADERS += mainwindow.h backend.h regtab.h analyser.h settings.h \
+ std_analysers.h aux.h regdisplaypanel.h regedit.h
+SOURCES += main.cpp mainwindow.cpp regtab.cpp backend.cpp analyser.cpp \
+ std_analysers.cpp settings.cpp aux.cpp regdisplaypanel.cpp regedit.cpp
LIBS += -L../lib/ -lsocdesc -lxml2
INCLUDEPATH += ../lib/ ../../hwstub/lib
diff --git a/utils/regtools/qeditor/regdisplaypanel.cpp b/utils/regtools/qeditor/regdisplaypanel.cpp
new file mode 100644
index 0000000000..cef5f9807b
--- /dev/null
+++ b/utils/regtools/qeditor/regdisplaypanel.cpp
@@ -0,0 +1,314 @@
+#include "regdisplaypanel.h"
+#include <QHeaderView>
+#include <QDebug>
+
+/**
+ * RegItemEditorCreator
+ */
+
+QWidget *RegItemEditorCreator::createWidget(QWidget * parent) const
+{
+ return new RegLineEdit(parent);
+}
+
+QByteArray RegItemEditorCreator::valuePropertyName () const
+{
+ return QByteArray("text");
+}
+
+/**
+ * DevDisplayPanel
+ */
+DevDisplayPanel::DevDisplayPanel(QWidget *parent, const SocDevRef& dev_ref)
+ :QGroupBox(parent), m_dev(dev_ref), m_reg_font(font())
+{
+ QVBoxLayout *right_layout = new QVBoxLayout;
+ const soc_dev_addr_t& dev_addr = m_dev.GetDevAddr();
+
+ m_reg_font.setWeight(100);
+ m_reg_font.setKerning(false);
+
+ QString dev_name;
+ dev_name.sprintf("HW_%s_BASE", dev_addr.name.c_str());
+
+ QLabel *label_names = new QLabel("<b>" + dev_name + "</b>");
+ label_names->setTextFormat(Qt::RichText);
+
+ QLabel *label_addr = new QLabel("<b>" + QString().sprintf("0x%03x", dev_addr.addr) + "</b>");
+ label_addr->setTextFormat(Qt::RichText);
+
+ QHBoxLayout *top_layout = new QHBoxLayout;
+ top_layout->addStretch();
+ top_layout->addWidget(label_names);
+ top_layout->addWidget(label_addr);
+ top_layout->addStretch();
+
+ m_name = new QLabel(this);
+ m_name->setTextFormat(Qt::RichText);
+ m_name->setText("<h1>" + QString::fromStdString(m_dev.GetDev().long_name) + "</h1>");
+
+ m_desc = new QLabel(this);
+ m_name->setTextFormat(Qt::RichText);
+ m_desc->setText(QString::fromStdString(m_dev.GetDev().desc));
+
+ right_layout->addLayout(top_layout, 0);
+ right_layout->addWidget(m_name, 0);
+ right_layout->addWidget(m_desc, 0);
+ right_layout->addStretch(1);
+
+ setTitle("Device Description");
+ setLayout(right_layout);
+}
+
+void DevDisplayPanel::AllowWrite(bool en)
+{
+ Q_UNUSED(en);
+}
+
+QWidget *DevDisplayPanel::GetWidget()
+{
+ return this;
+}
+
+/**
+ * RegDisplayPanel
+ */
+
+RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const SocRegRef& reg_ref)
+ :QGroupBox(parent), m_io_backend(io_backend), m_reg(reg_ref), m_reg_font(font())
+{
+ bool read_only = m_io_backend->IsReadOnly();
+
+ QVBoxLayout *right_layout = new QVBoxLayout;
+
+ const soc_dev_addr_t& dev_addr = m_reg.GetDevAddr();
+ const soc_reg_t& reg = m_reg.GetReg();
+ const soc_reg_addr_t& reg_addr = m_reg.GetRegAddr();
+
+ m_reg_font.setWeight(100);
+ m_reg_font.setKerning(false);
+
+ QString reg_name;
+ reg_name.sprintf("HW_%s_%s", dev_addr.name.c_str(), reg_addr.name.c_str());
+ QStringList names;
+ QVector< soc_addr_t > addresses;
+ names.append(reg_name);
+ addresses.append(reg_addr.addr);
+ if(reg.flags & REG_HAS_SCT)
+ {
+ names.append(reg_name + "_SET");
+ names.append(reg_name + "_CLR");
+ names.append(reg_name + "_TOG");
+ addresses.append(reg_addr.addr + 4);
+ addresses.append(reg_addr.addr + 8);
+ addresses.append(reg_addr.addr + 12);
+ }
+
+ QString str;
+ str += "<table align=left>";
+ for(int i = 0; i < names.size(); i++)
+ str += "<tr><td><b>" + names[i] + "</b></td></tr>";
+ str += "</table>";
+ QLabel *label_names = new QLabel;
+ label_names->setTextFormat(Qt::RichText);
+ label_names->setText(str);
+
+ QString str_addr;
+ str_addr += "<table align=left>";
+ for(int i = 0; i < names.size(); i++)
+ str_addr += "<tr><td><b>" + QString().sprintf("0x%03x", addresses[i]) + "</b></td></tr>";
+ str_addr += "</table>";
+ QLabel *label_addr = new QLabel;
+ label_addr->setTextFormat(Qt::RichText);
+ label_addr->setText(str_addr);
+
+ QHBoxLayout *top_layout = new QHBoxLayout;
+ top_layout->addStretch();
+ top_layout->addWidget(label_names);
+ top_layout->addWidget(label_addr);
+ top_layout->addStretch();
+
+ m_raw_val_name = new QLabel;
+ m_raw_val_name->setText("Raw value:");
+ m_raw_val_edit = new RegLineEdit;
+ m_raw_val_edit->SetReadOnly(read_only);
+ m_raw_val_edit->GetLineEdit()->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+ m_raw_val_edit->GetLineEdit()->setValidator(new SocFieldValidator(m_raw_val_edit));
+ m_raw_val_edit->EnableSCT(!!(reg.flags & REG_HAS_SCT));
+ m_raw_val_edit->GetLineEdit()->setFont(m_reg_font);
+ connect(m_raw_val_edit->GetLineEdit(), SIGNAL(returnPressed()), this, SLOT(OnRawRegValueReturnPressed()));
+ QHBoxLayout *raw_val_layout = new QHBoxLayout;
+ raw_val_layout->addStretch();
+ raw_val_layout->addWidget(m_raw_val_name);
+ raw_val_layout->addWidget(m_raw_val_edit);
+ raw_val_layout->addStretch();
+
+ m_value_table = new GrowingTableWidget;
+ m_value_table->setRowCount(reg.field.size());
+ m_value_table->setColumnCount(5);
+ for(size_t row = 0; row < reg.field.size(); row++)
+ {
+ const soc_reg_field_t& field = reg.field[row];
+ QString bits_str;
+ if(field.first_bit == field.last_bit)
+ bits_str.sprintf("%d", field.first_bit);
+ else
+ bits_str.sprintf("%d:%d", field.last_bit, field.first_bit);
+ QTableWidgetItem *item = new QTableWidgetItem(bits_str);
+ item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_value_table->setItem(row, 0, item);
+ item = new QTableWidgetItem(QString(field.name.c_str()));
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_value_table->setItem(row, 1, item);
+ item = new QTableWidgetItem(QString(field.desc.c_str()));
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_value_table->setItem(row, 4, item);
+ }
+ m_value_table->setHorizontalHeaderItem(0, new QTableWidgetItem("Bits"));
+ m_value_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Name"));
+ m_value_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Value"));
+ m_value_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Meaning"));
+ m_value_table->setHorizontalHeaderItem(4, new QTableWidgetItem("Description"));
+ m_value_table->verticalHeader()->setVisible(false);
+ m_value_table->resizeColumnsToContents();
+ m_value_table->horizontalHeader()->setStretchLastSection(true);
+ m_value_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ m_table_delegate = new QStyledItemDelegate(this);
+ m_table_edit_factory = new QItemEditorFactory();
+ m_regedit_creator = new RegItemEditorCreator();
+ m_table_edit_factory->registerEditor(QVariant::String, m_regedit_creator);
+ m_table_delegate->setItemEditorFactory(m_table_edit_factory);
+ m_value_table->setItemDelegate(m_table_delegate);
+
+ m_sexy_display = new RegSexyDisplay(reg_ref, this);
+ m_sexy_display->setFont(m_reg_font);
+
+ m_desc = new QLabel(this);
+ m_desc->setTextFormat(Qt::RichText);
+ m_desc->setText(QString::fromStdString(m_reg.GetReg().desc));
+
+ right_layout->addWidget(m_desc);
+ right_layout->addLayout(top_layout);
+ if(raw_val_layout)
+ right_layout->addLayout(raw_val_layout);
+ right_layout->addWidget(m_sexy_display);
+ right_layout->addWidget(m_value_table);
+
+ setTitle("Register Description");
+ m_viewport = new QWidget;
+ m_viewport->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_viewport->setLayout(right_layout);
+ m_scroll = new QScrollArea;
+ m_scroll->setWidget(m_viewport);
+ m_scroll->setWidgetResizable(true);
+ m_scroll->setFrameShape(QFrame::NoFrame);
+ QHBoxLayout *layout = new QHBoxLayout;
+ layout->addWidget(m_scroll, 1);
+ setLayout(layout);
+ AllowWrite(false);
+
+ // load data
+ Reload();
+}
+
+RegDisplayPanel::~RegDisplayPanel()
+{
+ delete m_table_edit_factory;
+}
+
+void RegDisplayPanel::Reload()
+{
+ const soc_dev_addr_t& dev_addr = m_reg.GetDevAddr();
+ const soc_reg_t& reg = m_reg.GetReg();
+ const soc_reg_addr_t& reg_addr = m_reg.GetRegAddr();
+ soc_word_t value;
+ BackendHelper helper(m_io_backend, m_reg);
+ bool has_value = helper.ReadRegister(dev_addr.name.c_str(), reg_addr.name.c_str(), value);
+
+ if(has_value)
+ {
+ m_raw_val_name->show();
+ m_raw_val_edit->show();
+ m_raw_val_edit->GetLineEdit()->setText(QString().sprintf("0x%08x", value));
+ }
+ else
+ {
+ m_raw_val_name->hide();
+ m_raw_val_edit->hide();
+ }
+
+ int row = 0;
+ foreach(const soc_reg_field_t& field, reg.field)
+ {
+ QTableWidgetItem *item = new QTableWidgetItem();
+ QTableWidgetItem *desc_item = new QTableWidgetItem();
+ if(has_value)
+ {
+ soc_word_t v = (value & field.bitmask()) >> field.first_bit;
+ QString value_name;
+ foreach(const soc_reg_field_value_t& rval, field.value)
+ if(v == rval.value)
+ value_name = rval.name.c_str();
+ const char *fmt = "%lu";
+ // heuristic
+ if((field.last_bit - field.first_bit + 1) > 16)
+ fmt = "0x%lx";
+ item->setText(QString().sprintf(fmt, (unsigned long)v));
+ item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+
+ if(value_name.size() != 0)
+ {
+ desc_item->setText(value_name);
+ desc_item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+ }
+ }
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ desc_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_value_table->setItem(row, 2, item);
+ m_value_table->setItem(row, 3, desc_item);
+ row++;
+ }
+}
+
+void RegDisplayPanel::AllowWrite(bool en)
+{
+ m_allow_write = en;
+ if(m_raw_val_edit)
+ m_raw_val_edit->SetReadOnly(m_io_backend->IsReadOnly() || !m_allow_write);
+}
+
+IoBackend::WriteMode RegDisplayPanel::EditModeToWriteMode(RegLineEdit::EditMode mode)
+{
+ switch(mode)
+ {
+ case RegLineEdit::Write: return IoBackend::Write;
+ case RegLineEdit::Set: return IoBackend::Set;
+ case RegLineEdit::Clear: return IoBackend::Clear;
+ case RegLineEdit::Toggle: return IoBackend::Toggle;
+ default: return IoBackend::Write;
+ }
+}
+
+void RegDisplayPanel::OnRawRegValueReturnPressed()
+{
+ soc_word_t val;
+ QLineEdit *edit = m_raw_val_edit->GetLineEdit();
+ const SocFieldValidator *validator = dynamic_cast< const SocFieldValidator *>(edit->validator());
+ QValidator::State state = validator->parse(edit->text(), val);
+ if(state != QValidator::Acceptable)
+ return;
+ IoBackend::WriteMode mode = EditModeToWriteMode(m_raw_val_edit->GetMode());
+ BackendHelper helper(m_io_backend, m_reg);
+ helper.WriteRegister(m_reg.GetDevAddr().name.c_str(), m_reg.GetRegAddr().name.c_str(),
+ val, mode);
+ // FIXME: we should notify the UI to read value back because it has changed
+ Reload();
+}
+
+QWidget *RegDisplayPanel::GetWidget()
+{
+ return this;
+}
+
diff --git a/utils/regtools/qeditor/regdisplaypanel.h b/utils/regtools/qeditor/regdisplaypanel.h
new file mode 100644
index 0000000000..444f3615f2
--- /dev/null
+++ b/utils/regtools/qeditor/regdisplaypanel.h
@@ -0,0 +1,77 @@
+#ifndef REGDISPLAYPANEL_H
+#define REGDISPLAYPANEL_H
+
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QGroupBox>
+#include <QTableWidget>
+#include <QStyledItemDelegate>
+#include <QItemEditorCreatorBase>
+#include <QTextEdit>
+#include <QScrollArea>
+#include <soc_desc.hpp>
+#include "backend.h"
+#include "settings.h"
+#include "aux.h"
+#include "regtab.h"
+
+class RegItemEditorCreator : public QItemEditorCreatorBase
+{
+public:
+ RegItemEditorCreator() {}
+ virtual QWidget *createWidget(QWidget * parent) const;
+ virtual QByteArray valuePropertyName () const;
+};
+
+class DevDisplayPanel : public QGroupBox, public RegTabPanel
+{
+ Q_OBJECT
+public:
+ DevDisplayPanel(QWidget *parent, const SocDevRef& reg);
+ void Reload();
+ void AllowWrite(bool en);
+ QWidget *GetWidget();
+ bool Quit();
+
+protected:
+
+ const SocDevRef& m_dev;
+ QFont m_reg_font;
+ QLabel *m_name;
+ QLabel *m_desc;
+};
+
+class RegDisplayPanel : public QGroupBox, public RegTabPanel
+{
+ Q_OBJECT
+public:
+ RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const SocRegRef& reg);
+ ~RegDisplayPanel();
+ void AllowWrite(bool en);
+ void Reload();
+ QWidget *GetWidget();
+ bool Quit();
+
+protected:
+ IoBackend::WriteMode EditModeToWriteMode(RegLineEdit::EditMode mode);
+
+ IoBackend *m_io_backend;
+ const SocRegRef& m_reg;
+ bool m_allow_write;
+ RegLineEdit *m_raw_val_edit;
+ RegSexyDisplay *m_sexy_display;
+ GrowingTableWidget *m_value_table;
+ QStyledItemDelegate *m_table_delegate;
+ QItemEditorFactory *m_table_edit_factory;
+ RegItemEditorCreator *m_regedit_creator;
+ QLabel *m_raw_val_name;
+ QFont m_reg_font;
+ QLabel *m_desc;
+ QWidget *m_viewport;
+ QScrollArea *m_scroll;
+
+private slots:
+ void OnRawRegValueReturnPressed();
+};
+
+#endif /* REGDISPLAYPANEL_H */
diff --git a/utils/regtools/qeditor/regedit.cpp b/utils/regtools/qeditor/regedit.cpp
new file mode 100644
index 0000000000..5e498ce496
--- /dev/null
+++ b/utils/regtools/qeditor/regedit.cpp
@@ -0,0 +1,1324 @@
+#include "regedit.h"
+#include <QFileDialog>
+#include <QDebug>
+#include <QHeaderView>
+#include <QMessageBox>
+#include <QInputDialog>
+
+/**
+ * EmptyEditPanel
+ */
+EmptyEditPanel::EmptyEditPanel(QWidget *parent)
+ :QWidget(parent)
+{
+}
+
+/**
+ * SocEditPanel
+ */
+SocEditPanel::SocEditPanel(SocRef ref, QWidget *parent)
+ :QWidget(parent), m_ref(ref)
+{
+ m_name_group = new QGroupBox("Name", this);
+ m_name_edit = new QLineEdit(this);
+ m_name_edit->setText(QString::fromStdString(ref.GetSoc().name));
+ QVBoxLayout *name_group_layout = new QVBoxLayout;
+ name_group_layout->addWidget(m_name_edit);
+ m_name_group->setLayout(name_group_layout);
+
+ m_desc_group = new QGroupBox("Description", this);
+ QHBoxLayout *group_layout = new QHBoxLayout;
+ m_desc_edit = new MyTextEditor(this);
+ m_desc_edit->SetTextHtml(QString::fromStdString(ref.GetSoc().desc));
+ group_layout->addWidget(m_desc_edit);
+ m_desc_group->setLayout(group_layout);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget(m_name_group);
+ layout->addWidget(m_desc_group);
+ layout->addStretch(1);
+
+ connect(m_name_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnNameEdited(const QString&)));
+ connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnTextEdited()));
+
+ setLayout(layout);
+}
+
+void SocEditPanel::OnNameEdited(const QString& text)
+{
+ m_ref.GetSoc().name = text.toStdString();
+ emit OnModified(m_name_edit->isModified());
+}
+
+void SocEditPanel::OnTextEdited()
+{
+ m_ref.GetSoc().desc = m_desc_edit->GetTextHtml().toStdString();
+ emit OnModified(m_desc_edit->IsModified());
+}
+
+/**
+ * DevEditPanel
+ */
+DevEditPanel::DevEditPanel(SocDevRef ref, QWidget *parent)
+ :QWidget(parent), m_ref(ref)
+{
+ m_name_group = new QGroupBox("Name", this);
+ m_name_edit = new QLineEdit(this);
+ m_name_edit->setText(QString::fromStdString(ref.GetDev().name));
+ QVBoxLayout *name_group_layout = new QVBoxLayout;
+ name_group_layout->addWidget(m_name_edit);
+ m_name_group->setLayout(name_group_layout);
+
+ m_long_name_group = new QGroupBox("Long Name", this);
+ m_long_name_edit = new QLineEdit(this);
+ m_long_name_edit->setText(QString::fromStdString(ref.GetDev().long_name));
+ QVBoxLayout *long_name_group_layout = new QVBoxLayout;
+ long_name_group_layout->addWidget(m_long_name_edit);
+ m_long_name_group->setLayout(long_name_group_layout);
+
+ m_version_group = new QGroupBox("Version", this);
+ m_version_edit = new QLineEdit(this);
+ m_version_edit->setText(QString::fromStdString(ref.GetDev().version));
+ QVBoxLayout *version_group_layout = new QVBoxLayout;
+ version_group_layout->addWidget(m_version_edit);
+ m_version_group->setLayout(version_group_layout);
+
+ QVBoxLayout *name_ver_layout = new QVBoxLayout;
+ name_ver_layout->addWidget(m_name_group);
+ name_ver_layout->addWidget(m_long_name_group);
+ name_ver_layout->addWidget(m_version_group);
+ name_ver_layout->addStretch();
+
+ m_instances_table = new QTableWidget(this);
+ m_instances_table->setRowCount(ref.GetDev().addr.size() + 1);
+ m_instances_table->setColumnCount(3);
+ for(size_t row = 0; row < ref.GetDev().addr.size(); row++)
+ FillRow(row, ref.GetDev().addr[row]);
+ CreateNewRow(ref.GetDev().addr.size());
+ m_instances_table->setHorizontalHeaderItem(0, new QTableWidgetItem(""));
+ m_instances_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Name"));
+ m_instances_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Address"));
+ m_instances_table->verticalHeader()->setVisible(false);
+ m_instances_table->resizeColumnsToContents();
+ m_instances_table->horizontalHeader()->setStretchLastSection(true);
+ m_instances_table->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ m_instances_group = new QGroupBox("Instances", this);
+ QHBoxLayout *instances_group_layout = new QHBoxLayout;
+ instances_group_layout->addWidget(m_instances_table);
+ m_instances_group->setLayout(instances_group_layout);
+
+ QHBoxLayout *top_layout = new QHBoxLayout;
+ top_layout->addWidget(m_instances_group);
+ top_layout->addLayout(name_ver_layout);
+ top_layout->addStretch();
+
+ m_desc_group = new QGroupBox("Description", this);
+ QHBoxLayout *group_layout = new QHBoxLayout;
+ m_desc_edit = new MyTextEditor(this);
+ m_desc_edit->SetTextHtml(QString::fromStdString(ref.GetDev().desc));
+ group_layout->addWidget(m_desc_edit);
+ m_desc_group->setLayout(group_layout);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addLayout(top_layout, 0);
+ layout->addWidget(m_desc_group, 1);
+
+ setLayout(layout);
+
+ SocFieldItemDelegate *m_table_delegate = new SocFieldItemDelegate(this);
+ QItemEditorFactory *m_table_edit_factory = new QItemEditorFactory();
+ SocFieldEditorCreator *m_table_edit_creator = new SocFieldEditorCreator();
+ m_table_edit_factory->registerEditor(QVariant::UInt, m_table_edit_creator);
+ m_table_delegate->setItemEditorFactory(m_table_edit_factory);
+ m_instances_table->setItemDelegate(m_table_delegate);
+
+ connect(m_instances_table, SIGNAL(cellActivated(int,int)), this, SLOT(OnInstActivated(int,int)));
+ connect(m_instances_table, SIGNAL(cellChanged(int,int)), this, SLOT(OnInstChanged(int,int)));
+ connect(m_name_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnNameEdited(const QString&)));
+ connect(m_long_name_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnLongNameEdited(const QString&)));
+ connect(m_version_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnVersionEdited(const QString&)));
+ connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnDescEdited()));
+}
+
+void DevEditPanel::OnNameEdited(const QString& text)
+{
+ m_ref.GetDev().name = text.toStdString();
+ emit OnModified(m_name_edit->isModified());
+}
+
+void DevEditPanel::OnLongNameEdited(const QString& text)
+{
+ m_ref.GetDev().long_name = text.toStdString();
+ emit OnModified(m_long_name_edit->isModified());
+}
+
+void DevEditPanel::OnVersionEdited(const QString& text)
+{
+ m_ref.GetDev().version = text.toStdString();
+ emit OnModified(m_version_edit->isModified());
+}
+
+void DevEditPanel::OnDescEdited()
+{
+ m_ref.GetDev().desc = m_desc_edit->GetTextHtml().toStdString();
+ emit OnModified(m_desc_edit->IsModified());
+}
+
+void DevEditPanel::CreateNewRow(int row)
+{
+ QTableWidgetItem *item = new QTableWidgetItem(QIcon::fromTheme("list-add"), "", DevInstNewType);
+ item->setToolTip("New?");
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_instances_table->setItem(row, DevInstIconColumn, item);
+ item = new QTableWidgetItem("New instance...");
+ QFont font = item->font();
+ font.setItalic(true);
+ item->setFont(font);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_instances_table->setItem(row, DevInstNameColumn, item);
+ item = new QTableWidgetItem("");
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_instances_table->setItem(row, DevInstAddrColumn, item);
+}
+
+void DevEditPanel::FillRow(int row, const soc_dev_addr_t& addr)
+{
+ QTableWidgetItem *item = new QTableWidgetItem(QString::fromStdString(addr.name));
+ item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+ m_instances_table->setItem(row, DevInstNameColumn, item);
+ item = new QTableWidgetItem();
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+ item->setData(Qt::DisplayRole, QVariant(addr.addr));
+ m_instances_table->setItem(row, DevInstAddrColumn, item);
+ item = new QTableWidgetItem(QIcon::fromTheme("list-remove"), "", DevInstDeleteType);
+ item->setToolTip("Remove?");
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_instances_table->setItem(row, DevInstIconColumn, item);
+}
+
+void DevEditPanel::OnInstActivated(int row, int column)
+{
+ if(column != 0)
+ return;
+ int type = m_instances_table->item(row, column)->type();
+ if(type == DevInstDeleteType)
+ {
+ m_ref.GetDev().addr.erase(m_ref.GetDev().addr.begin() + row);
+ m_instances_table->removeRow(row);
+ }
+ else if(type == DevInstNewType)
+ {
+ m_instances_table->insertRow(row);
+ soc_dev_addr_t addr;
+ addr.name = QString("UNNAMED_%1").arg(row).toStdString();
+ addr.addr = 0;
+ m_ref.GetDev().addr.push_back(addr);
+ FillRow(row, addr);
+ }
+}
+
+void DevEditPanel::OnInstChanged(int row, int column)
+{
+ /* ignore extra row for addition */
+ if(row >= (int)m_ref.GetDev().addr.size())
+ return;
+ QTableWidgetItem *item = m_instances_table->item(row, column);
+ if(column == DevInstNameColumn)
+ {
+ m_ref.GetDev().addr[row].name = item->text().toStdString();
+ emit OnModified(true);
+ }
+ else if(column == DevInstAddrColumn)
+ {
+ m_ref.GetDev().addr[row].addr = item->data(Qt::DisplayRole).toUInt();
+ emit OnModified(true);
+ }
+}
+
+/**
+ * RegEditPanel
+ */
+
+RegEditPanel::RegEditPanel(SocRegRef ref, QWidget *parent)
+ :QWidget(parent), m_ref(ref), m_reg_font(font())
+{
+ m_reg_font.setWeight(100);
+ m_reg_font.setKerning(false);
+
+ m_name_group = new QGroupBox("Name", this);
+ m_name_edit = new QLineEdit(this);
+ m_name_edit->setText(QString::fromStdString(ref.GetReg().name));
+ QVBoxLayout *name_group_layout = new QVBoxLayout;
+ name_group_layout->addWidget(m_name_edit);
+ m_name_group->setLayout(name_group_layout);
+
+ m_instances_table = new QTableWidget(this);
+ m_instances_table->setRowCount(ref.GetReg().addr.size() + 1);
+ m_instances_table->setColumnCount(RegInstNrColumns);
+ for(size_t row = 0; row < ref.GetReg().addr.size(); row++)
+ FillRow(row, ref.GetReg().addr[row]);
+ CreateNewAddrRow(ref.GetReg().addr.size());
+ m_instances_table->setHorizontalHeaderItem(RegInstIconColumn, new QTableWidgetItem(""));
+ m_instances_table->setHorizontalHeaderItem(RegInstNameColumn, new QTableWidgetItem("Name"));
+ m_instances_table->setHorizontalHeaderItem(RegInstAddrColumn, new QTableWidgetItem("Address"));
+ m_instances_table->verticalHeader()->setVisible(false);
+ m_instances_table->resizeColumnsToContents();
+ m_instances_table->horizontalHeader()->setStretchLastSection(true);
+ m_instances_table->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ m_instances_group = new QGroupBox("Instances", this);
+ QHBoxLayout *instances_group_layout = new QHBoxLayout;
+ instances_group_layout->addWidget(m_instances_table);
+ m_instances_group->setLayout(instances_group_layout);
+
+ m_desc_group = new QGroupBox("Description", this);
+ QHBoxLayout *group_layout = new QHBoxLayout;
+ m_desc_edit = new MyTextEditor(this);
+ m_desc_edit->SetTextHtml(QString::fromStdString(ref.GetReg().desc));
+ group_layout->addWidget(m_desc_edit);
+ m_desc_group->setLayout(group_layout);
+
+ bool has_sct = m_ref.GetReg().flags & REG_HAS_SCT;
+ m_sct_check = new QCheckBox("Set/Clear/Toggle", this);
+ m_sct_check->setCheckState(has_sct ? Qt::Checked : Qt::Unchecked);
+ QHBoxLayout *flags_layout = new QHBoxLayout;
+ flags_layout->addWidget(m_sct_check);
+ flags_layout->addStretch();
+ m_flags_group = new QGroupBox("Flags", this);
+ m_flags_group->setLayout(flags_layout);
+
+ m_formula_combo = new QComboBox(this);
+ m_formula_combo->addItem("None", QVariant(REG_FORMULA_NONE));
+ m_formula_combo->addItem("String", QVariant(REG_FORMULA_STRING));
+ m_formula_combo->setCurrentIndex(m_formula_combo->findData(QVariant(m_ref.GetReg().formula.type)));
+ m_formula_type_label = new QLabel("Type:", this);
+ QHBoxLayout *formula_top_layout = new QHBoxLayout;
+ formula_top_layout->addWidget(m_formula_type_label);
+ formula_top_layout->addWidget(m_formula_combo);
+ m_formula_string_edit = new QLineEdit(QString::fromStdString(ref.GetReg().formula.string), this);
+ QVBoxLayout *formula_layout = new QVBoxLayout;
+ formula_layout->addLayout(formula_top_layout);
+ formula_layout->addWidget(m_formula_string_edit);
+ m_formula_string_gen = new QPushButton("Generate", this);
+ formula_layout->addWidget(m_formula_string_gen);
+ m_formula_group = new QGroupBox("Formula", this);
+ m_formula_group->setLayout(formula_layout);
+
+ QVBoxLayout *name_layout = new QVBoxLayout;
+ name_layout->addWidget(m_name_group);
+ name_layout->addWidget(m_flags_group);
+ name_layout->addWidget(m_formula_group);
+ name_layout->addStretch();
+
+ QHBoxLayout *top_layout = new QHBoxLayout;
+ top_layout->addWidget(m_instances_group);
+ top_layout->addLayout(name_layout);
+ top_layout->addWidget(m_desc_group, 1);
+
+ m_sexy_display = new RegSexyDisplay(m_ref, this);
+ m_sexy_display->setFont(m_reg_font);
+
+ m_field_table = new QTableWidget;
+ m_field_table->setRowCount(m_ref.GetReg().field.size());
+ m_field_table->setColumnCount(4);
+ for(size_t row = 0; row < m_ref.GetReg().field.size(); row++)
+ {
+ const soc_reg_field_t& field = m_ref.GetReg().field[row];
+ QString bits_str;
+ if(field.first_bit == field.last_bit)
+ bits_str.sprintf("%d", field.first_bit);
+ else
+ bits_str.sprintf("%d:%d", field.last_bit, field.first_bit);
+ QTableWidgetItem *item = new QTableWidgetItem(bits_str);
+ item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_field_table->setItem(row, 1, item);
+ item = new QTableWidgetItem(QString(field.name.c_str()));
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_field_table->setItem(row, 2, item);
+ item = new QTableWidgetItem(QString(field.desc.c_str()));
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_field_table->setItem(row, 3, item);
+ UpdateWarning(row);
+ }
+ m_field_table->setHorizontalHeaderItem(0, new QTableWidgetItem(""));
+ m_field_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Bits"));
+ m_field_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Name"));
+ m_field_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Description"));
+ m_field_table->verticalHeader()->setVisible(false);
+ m_field_table->resizeColumnsToContents();
+ m_field_table->horizontalHeader()->setStretchLastSection(true);
+ QHBoxLayout *field_layout = new QHBoxLayout;
+ field_layout->addWidget(m_field_table);
+ m_field_group = new QGroupBox("Flags", this);
+ m_field_group->setLayout(field_layout);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addLayout(top_layout, 0);
+ layout->addWidget(m_sexy_display, 0);
+ layout->addWidget(m_field_group);
+
+ UpdateFormula();
+
+ setLayout(layout);
+
+ SocFieldItemDelegate *m_table_delegate = new SocFieldItemDelegate(this);
+ QItemEditorFactory *m_table_edit_factory = new QItemEditorFactory();
+ SocFieldEditorCreator *m_table_edit_creator = new SocFieldEditorCreator();
+ m_table_edit_factory->registerEditor(QVariant::UInt, m_table_edit_creator);
+ m_table_delegate->setItemEditorFactory(m_table_edit_factory);
+ m_instances_table->setItemDelegate(m_table_delegate);
+
+ connect(m_instances_table, SIGNAL(cellActivated(int,int)), this, SLOT(OnInstActivated(int,int)));
+ connect(m_instances_table, SIGNAL(cellChanged(int,int)), this, SLOT(OnInstChanged(int,int)));
+ connect(m_name_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnNameEdited(const QString&)));
+ connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnDescEdited()));
+ connect(m_sct_check, SIGNAL(stateChanged(int)), this, SLOT(OnSctEdited(int)));
+ connect(m_formula_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFormulaChanged(int)));
+ connect(m_formula_string_edit, SIGNAL(textChanged(const QString&)), this,
+ SLOT(OnFormulaStringChanged(const QString&)));
+ connect(m_formula_string_gen, SIGNAL(clicked(bool)), this, SLOT(OnFormulaGenerate(bool)));
+}
+
+void RegEditPanel::UpdateWarning(int row)
+{
+ Q_UNUSED(row);
+}
+
+void RegEditPanel::OnFormulaStringChanged(const QString& text)
+{
+ m_ref.GetReg().formula.string = text.toStdString();
+ emit OnModified(true);
+}
+
+void RegEditPanel::OnFormulaGenerate(bool checked)
+{
+ Q_UNUSED(checked);
+ bool ok;
+ int count = QInputDialog::getInt(this, "Instance generator", "Number of instances",
+ 0, 0, 100, 1, &ok);
+ if(!ok)
+ return;
+ std::string name(m_ref.GetReg().name);
+ size_t pos = name.find('n');
+ if(pos == std::string::npos)
+ {
+ name.push_back('n');
+ pos = name.size() - 1;
+ }
+ std::map< std::string, soc_word_t > map;
+ std::vector< std::pair< std::string, soc_word_t > > list;
+ std::string formula = m_ref.GetReg().formula.string;
+ for(int n = 0; n < count; n++)
+ {
+ map["n"] = n;
+ std::string err;
+ soc_word_t res;
+ if(!soc_desc_evaluate_formula(formula, map, res, err))
+ {
+ qDebug() << "Cannot evaluator " << QString::fromStdString(formula)
+ << "for n=" << n << ": " << QString::fromStdString(err);
+ return;
+ }
+ std::string regname = name;
+ std::string strn = QString("%1").arg(n).toStdString();
+ regname.replace(pos, 1, strn);
+ list.push_back(std::make_pair(regname, res));
+ }
+ // everything went good, commit result
+ while(m_instances_table->rowCount() > 1)
+ m_instances_table->removeRow(0);
+ m_ref.GetReg().addr.resize(list.size());
+ for(size_t i = 0; i < list.size(); i++)
+ {
+ m_instances_table->insertRow(i);
+ m_ref.GetReg().addr[i].name = list[i].first;
+ m_ref.GetReg().addr[i].addr = list[i].second;
+ FillRow(i, m_ref.GetReg().addr[i]);
+ }
+}
+
+void RegEditPanel::OnFormulaChanged(int index)
+{
+ if(index == -1)
+ return;
+ m_ref.GetReg().formula.type = static_cast< soc_reg_formula_type_t >(m_formula_combo->itemData(index).toInt());
+ UpdateFormula();
+ emit OnModified(true);
+}
+
+void RegEditPanel::UpdateFormula()
+{
+ m_formula_string_edit->hide();
+ m_formula_string_gen->hide();
+ switch(m_ref.GetReg().formula.type)
+ {
+ case REG_FORMULA_STRING:
+ m_formula_string_edit->show();
+ m_formula_string_gen->show();
+ break;
+ case REG_FORMULA_NONE:
+ default:
+ break;
+ }
+}
+
+void RegEditPanel::OnSctEdited(int state)
+{
+ if(state == Qt::Checked)
+ m_ref.GetReg().flags |= REG_HAS_SCT;
+ else
+ m_ref.GetReg().flags &= ~REG_HAS_SCT;
+ emit OnModified(true);
+}
+
+void RegEditPanel::FillRow(int row, const soc_reg_addr_t& addr)
+{
+ QTableWidgetItem *item = new QTableWidgetItem(QString::fromStdString(addr.name));
+ item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+ m_instances_table->setItem(row, RegInstNameColumn, item);
+ item = new QTableWidgetItem();
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+ item->setData(Qt::DisplayRole, QVariant(addr.addr));
+ m_instances_table->setItem(row, RegInstAddrColumn, item);
+ item = new QTableWidgetItem(QIcon::fromTheme("list-remove"), "", RegInstDeleteType);
+ item->setToolTip("Remove?");
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_instances_table->setItem(row, RegInstIconColumn, item);
+}
+
+void RegEditPanel::CreateNewAddrRow(int row)
+{
+ QTableWidgetItem *item = new QTableWidgetItem(QIcon::fromTheme("list-add"), "", RegInstNewType);
+ item->setToolTip("New?");
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_instances_table->setItem(row, RegInstIconColumn, item);
+ item = new QTableWidgetItem("New instance...");
+ QFont font = item->font();
+ font.setItalic(true);
+ item->setFont(font);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_instances_table->setItem(row, RegInstNameColumn, item);
+ item = new QTableWidgetItem("");
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_instances_table->setItem(row, RegInstAddrColumn, item);
+}
+
+void RegEditPanel::OnNameEdited(const QString& text)
+{
+ m_ref.GetReg().name = text.toStdString();
+ emit OnModified(m_name_edit->isModified());
+}
+
+void RegEditPanel::OnDescEdited()
+{
+ m_ref.GetReg().desc = m_desc_edit->GetTextHtml().toStdString();
+ emit OnModified(m_desc_edit->IsModified());
+}
+
+void RegEditPanel::OnInstActivated(int row, int column)
+{
+ if(column != 0)
+ return;
+ int type = m_instances_table->item(row, column)->type();
+ if(type == RegInstDeleteType)
+ {
+ m_ref.GetReg().addr.erase(m_ref.GetReg().addr.begin() + row);
+ m_instances_table->removeRow(row);
+ }
+ else if(type == RegInstNewType)
+ {
+ m_instances_table->insertRow(row);
+ soc_reg_addr_t addr;
+ addr.name = QString("UNNAMED_%1").arg(row).toStdString();
+ addr.addr = 0;
+ m_ref.GetReg().addr.push_back(addr);
+ FillRow(row, addr);
+ }
+}
+
+void RegEditPanel::OnInstChanged(int row, int column)
+{
+ /* ignore extra row for addition */
+ if(row >= (int)m_ref.GetReg().addr.size())
+ return;
+ QTableWidgetItem *item = m_instances_table->item(row, column);
+ if(column == RegInstNameColumn)
+ {
+ m_ref.GetReg().addr[row].name = item->text().toStdString();
+ emit OnModified(true);
+ }
+ else if(column == RegInstAddrColumn)
+ {
+ m_ref.GetReg().addr[row].addr = item->data(Qt::DisplayRole).toUInt();
+ emit OnModified(true);
+ }
+}
+
+/**
+ * FieldEditPanel
+ */
+FieldEditPanel::FieldEditPanel(SocFieldRef ref, QWidget *parent)
+ :QWidget(parent), m_ref(ref)
+{
+ m_name_group = new QGroupBox("Name", this);
+ m_name_edit = new QLineEdit(this);
+ m_name_edit->setText(QString::fromStdString(ref.GetField().name));
+ QVBoxLayout *name_group_layout = new QVBoxLayout;
+ name_group_layout->addWidget(m_name_edit);
+ m_name_group->setLayout(name_group_layout);
+
+ m_bitrange_group = new QGroupBox("Bit Range", this);
+ m_bitrange_edit = new QLineEdit(this);
+ const soc_reg_field_t& field = ref.GetField();
+ QString bits_str;
+ if(field.first_bit == field.last_bit)
+ bits_str.sprintf("%d", field.first_bit);
+ else
+ bits_str.sprintf("%d:%d", field.last_bit, field.first_bit);
+ m_bitrange_edit->setText(bits_str);
+ m_bitrange_edit->setValidator(new SocBitRangeValidator(m_bitrange_edit));
+ QVBoxLayout *bitrange_group_layout = new QVBoxLayout;
+ bitrange_group_layout->addWidget(m_bitrange_edit);
+ m_bitrange_group->setLayout(bitrange_group_layout);
+
+ m_desc_group = new QGroupBox("Description", this);
+ QHBoxLayout *group_layout = new QHBoxLayout;
+ m_desc_edit = new MyTextEditor(this);
+ m_desc_edit->SetTextHtml(QString::fromStdString(ref.GetField().desc));
+ group_layout->addWidget(m_desc_edit);
+ m_desc_group->setLayout(group_layout);
+
+ m_value_group = new QGroupBox("Values", this);
+ QHBoxLayout *value_layout = new QHBoxLayout;
+ m_value_table = new QTableWidget(this);
+ m_value_table->setRowCount(ref.GetField().value.size() + 1);
+ m_value_table->setColumnCount(FieldValueNrColumns);
+ for(size_t row = 0; row < ref.GetField().value.size(); row++)
+ FillRow(row, ref.GetField().value[row]);
+ CreateNewRow(ref.GetField().value.size());
+ m_value_table->setHorizontalHeaderItem(FieldValueIconColumn, new QTableWidgetItem(""));
+ m_value_table->setHorizontalHeaderItem(FieldValueNameColumn, new QTableWidgetItem("Name"));
+ m_value_table->setHorizontalHeaderItem(FieldValueValueColumn, new QTableWidgetItem("Value"));
+ m_value_table->setHorizontalHeaderItem(FieldValueDescColumn, new QTableWidgetItem("Description"));
+ m_value_table->verticalHeader()->setVisible(false);
+ m_value_table->horizontalHeader()->setStretchLastSection(true);
+ value_layout->addWidget(m_value_table);
+ m_value_group->setLayout(value_layout);
+
+ QHBoxLayout *line_layout = new QHBoxLayout;
+ line_layout->addWidget(m_name_group);
+ line_layout->addWidget(m_bitrange_group);
+ line_layout->addStretch();
+
+ QVBoxLayout *left_layout = new QVBoxLayout;
+ left_layout->addLayout(line_layout);
+ left_layout->addWidget(m_desc_group);
+ left_layout->addWidget(m_value_group, 1);
+
+ UpdateDelegates();
+
+ connect(m_name_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnNameEdited(const QString&)));
+ connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnDescEdited()));
+ connect(m_value_table, SIGNAL(cellActivated(int,int)), this, SLOT(OnValueActivated(int,int)));
+ connect(m_value_table, SIGNAL(cellChanged(int,int)), this, SLOT(OnValueChanged(int,int)));
+ connect(m_bitrange_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnBitRangeEdited(const QString&)));
+
+ setLayout(left_layout);
+}
+
+void FieldEditPanel::UpdateDelegates()
+{
+ SocFieldItemDelegate *m_table_delegate = new SocFieldItemDelegate(m_ref.GetField(), this);
+ QItemEditorFactory *m_table_edit_factory = new QItemEditorFactory();
+ SocFieldEditorCreator *m_table_edit_creator = new SocFieldEditorCreator(m_ref.GetField());
+ m_table_edit_factory->registerEditor(QVariant::UInt, m_table_edit_creator);
+ m_table_delegate->setItemEditorFactory(m_table_edit_factory);
+ m_value_table->setItemDelegate(m_table_delegate);
+ m_value_table->resizeColumnsToContents();
+}
+
+void FieldEditPanel::UpdateWarning(int row)
+{
+ soc_word_t val = m_ref.GetField().value[row].value;
+ soc_word_t max = m_ref.GetField().bitmask() >> m_ref.GetField().first_bit;
+ QTableWidgetItem *item = m_value_table->item(row, FieldValueValueColumn);
+ if(val > max)
+ {
+ item->setIcon(QIcon::fromTheme("dialog-warning"));
+ item->setToolTip("Value is too big for the field");
+ }
+ else
+ {
+ item->setIcon(QIcon());
+ item->setToolTip("");
+ }
+}
+
+void FieldEditPanel::FillRow(int row, const soc_reg_field_value_t& val)
+{
+ QTableWidgetItem *item = new QTableWidgetItem(QString::fromStdString(val.name));
+ item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+ m_value_table->setItem(row, FieldValueNameColumn, item);
+ item = new QTableWidgetItem();
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+ item->setData(Qt::DisplayRole, QVariant(val.value));
+ m_value_table->setItem(row, FieldValueValueColumn, item);
+ item = new QTableWidgetItem(QString::fromStdString(val.desc));
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+ m_value_table->setItem(row, FieldValueDescColumn, item);
+ item = new QTableWidgetItem(QIcon::fromTheme("list-remove"), "", FieldValueDeleteType);
+ item->setToolTip("Remove?");
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_value_table->setItem(row, FieldValueIconColumn, item);
+ UpdateWarning(row);
+}
+
+void FieldEditPanel::CreateNewRow(int row)
+{
+ QTableWidgetItem *item = new QTableWidgetItem(QIcon::fromTheme("list-add"), "", FieldValueNewType);
+ item->setToolTip("New?");
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_value_table->setItem(row, FieldValueIconColumn, item);
+ item = new QTableWidgetItem("New value...");
+ QFont font = item->font();
+ font.setItalic(true);
+ item->setFont(font);
+ item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ m_value_table->setItem(row, FieldValueNameColumn, item);
+}
+
+void FieldEditPanel::OnBitRangeEdited(const QString& input)
+{
+ const SocBitRangeValidator *validator =
+ dynamic_cast< const SocBitRangeValidator *>(m_bitrange_edit->validator());
+ int first, last;
+ QValidator::State state = validator->parse(input, last, first);
+ if(state != QValidator::Acceptable)
+ return;
+ m_ref.GetField().first_bit = first;
+ m_ref.GetField().last_bit = last;
+ // update all warning signs
+ for(size_t row = 0; row < m_ref.GetField().value.size(); row++)
+ UpdateWarning(row);
+ // also updates delegates because they now have the wrong view of the field
+ UpdateDelegates();
+ emit OnModified(true);
+}
+
+void FieldEditPanel::OnNameEdited(const QString& text)
+{
+ m_ref.GetField().name = text.toStdString();
+ emit OnModified(m_name_edit->isModified());
+}
+
+void FieldEditPanel::OnDescEdited()
+{
+ m_ref.GetField().desc = m_desc_edit->GetTextHtml().toStdString();
+ emit OnModified(m_desc_edit->IsModified());
+}
+
+void FieldEditPanel::OnValueActivated(int row, int column)
+{
+ if(column != 0)
+ return;
+ int type = m_value_table->item(row, column)->type();
+ if(type == FieldValueDeleteType)
+ {
+ m_ref.GetField().value.erase(m_ref.GetField().value.begin() + row);
+ m_value_table->removeRow(row);
+ }
+ else if(type == FieldValueNewType)
+ {
+ m_value_table->insertRow(row);
+ soc_reg_field_value_t val;
+ val.name = QString("UNNAMED_%1").arg(row).toStdString();
+ val.value = 0;
+ m_ref.GetField().value.push_back(val);
+ FillRow(row, val);
+ }
+}
+
+void FieldEditPanel::OnValueChanged(int row, int column)
+{
+ /* ignore extra row for addition */
+ if(row >= (int)m_ref.GetField().value.size())
+ return;
+ QTableWidgetItem *item = m_value_table->item(row, column);
+ if(column == FieldValueNameColumn)
+ m_ref.GetField().value[row].name = item->text().toStdString();
+ else if(column == FieldValueValueColumn)
+ {
+ soc_word_t& fval = m_ref.GetField().value[row].value;
+ soc_word_t new_val = item->data(Qt::DisplayRole).toUInt();
+ /* avoid infinite recursion by calling UpdateWarning() when
+ * only the icon changes which would trigger this callback again */
+ if(fval != new_val)
+ {
+ fval = new_val;
+ UpdateWarning(row);
+ }
+ }
+ else if(column == FieldValueDescColumn)
+ m_ref.GetField().value[row].desc = item->text().toStdString();
+ emit OnModified(true);
+}
+
+namespace
+{
+
+enum
+{
+ SocTreeSocType = QTreeWidgetItem::UserType,
+ SocTreeDevType,
+ SocTreeRegType,
+ SocTreeFieldType,
+ SocTreeNewDevType,
+ SocTreeNewRegType,
+ SocTreeNewFieldType,
+};
+
+/**
+ * SocTreeItem
+ */
+
+class SocTreeItem : public QTreeWidgetItem
+{
+public:
+ SocTreeItem(const QString& string, const SocRef& ref)
+ :QTreeWidgetItem(QStringList(string), SocTreeSocType), m_ref(ref) {}
+
+ const SocRef& GetRef() { return m_ref; }
+private:
+ SocRef m_ref;
+};
+
+/**
+ * NewDevTreeItem
+ */
+
+class NewDevTreeItem : public QTreeWidgetItem
+{
+public:
+ NewDevTreeItem(const QString& string, const SocRef& ref)
+ :QTreeWidgetItem(QStringList(string), SocTreeNewDevType), m_ref(ref) {}
+
+ const SocRef& GetRef() { return m_ref; }
+private:
+ SocRef m_ref;
+};
+
+/**
+ * DevTreeItem
+ */
+
+class DevTreeItem : public QTreeWidgetItem
+{
+public:
+ DevTreeItem(const QString& string, const SocDevRef& ref)
+ :QTreeWidgetItem(QStringList(string), SocTreeDevType), m_ref(ref) {}
+
+ const SocDevRef& GetRef() { return m_ref; }
+private:
+ SocDevRef m_ref;
+};
+
+/**
+ * NewRegTreeItem
+ */
+
+class NewRegTreeItem : public QTreeWidgetItem
+{
+public:
+ NewRegTreeItem(const QString& string, const SocDevRef& ref)
+ :QTreeWidgetItem(QStringList(string), SocTreeNewRegType), m_ref(ref) {}
+
+ const SocDevRef& GetRef() { return m_ref; }
+private:
+ SocDevRef m_ref;
+};
+
+/**
+ * RegTreeItem
+ */
+
+class RegTreeItem : public QTreeWidgetItem
+{
+public:
+ RegTreeItem(const QString& string, const SocRegRef& ref)
+ :QTreeWidgetItem(QStringList(string), SocTreeRegType), m_ref(ref) {}
+
+ const SocRegRef& GetRef() { return m_ref; }
+private:
+ SocRegRef m_ref;
+};
+
+/**
+ * NewFieldTreeItem
+ */
+
+class NewFieldTreeItem : public QTreeWidgetItem
+{
+public:
+ NewFieldTreeItem(const QString& string, const SocRegRef& ref)
+ :QTreeWidgetItem(QStringList(string), SocTreeNewFieldType), m_ref(ref) {}
+
+ const SocRegRef& GetRef() { return m_ref; }
+private:
+ SocRegRef m_ref;
+};
+
+/**
+ * FieldTreeItem
+ */
+
+class FieldTreeItem : public QTreeWidgetItem
+{
+public:
+ FieldTreeItem(const QString& string, const SocFieldRef& ref)
+ :QTreeWidgetItem(QStringList(string), SocTreeFieldType), m_ref(ref) {}
+
+ const SocFieldRef& GetRef() { return m_ref; }
+private:
+ SocFieldRef m_ref;
+};
+
+}
+
+/**
+ * RegEdit
+ */
+RegEdit::RegEdit(Backend *backend, QWidget *parent)
+ :QWidget(parent), m_backend(backend)
+{
+ QVBoxLayout *m_vert_layout = new QVBoxLayout();
+ m_file_group = new QGroupBox("File selection", this);
+ QHBoxLayout *m_file_group_layout = new QHBoxLayout();
+ m_file_edit = new QLineEdit(this);
+ m_file_edit->setReadOnly(true);
+ m_file_open = new QToolButton(this);
+ m_file_open->setText("Open");
+ m_file_open->setIcon(QIcon::fromTheme("document-open"));
+ m_file_open->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ QMenu *file_open_menu = new QMenu(this);
+ QAction *new_act = file_open_menu->addAction(QIcon::fromTheme("document-new"), "New...");
+ m_file_open->setMenu(file_open_menu);
+
+ m_file_save = new QToolButton(this);
+ m_file_save->setText("Save");
+ m_file_save->setIcon(QIcon::fromTheme("document-save"));
+ m_file_save->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ QMenu *file_save_menu = new QMenu(this);
+ QAction *saveas_act = file_save_menu->addAction(QIcon::fromTheme("document-save-as"), "Save as...");
+ m_file_save->setMenu(file_save_menu);
+ m_file_group_layout->addWidget(m_file_open);
+ m_file_group_layout->addWidget(m_file_save);
+ m_file_group_layout->addWidget(m_file_edit);
+
+ m_splitter = new QSplitter(this);
+ m_soc_tree = new QTreeWidget(this);
+ m_soc_tree->setColumnCount(1);
+ m_soc_tree->setHeaderLabel(QString("Name"));
+ m_splitter->addWidget(m_soc_tree);
+ m_splitter->setStretchFactor(0, 0);
+
+ m_file_group->setLayout(m_file_group_layout);
+ m_vert_layout->addWidget(m_file_group);
+ m_vert_layout->addWidget(m_splitter, 1);
+
+ setLayout(m_vert_layout);
+
+ SetModified(false, false);
+ m_right_panel = 0;
+ SetPanel(new EmptyEditPanel(this));
+
+ connect(m_file_open, SIGNAL(clicked()), this, SLOT(OnOpen()));
+ connect(m_file_save, SIGNAL(clicked()), this, SLOT(OnSave()));
+ connect(new_act, SIGNAL(triggered()), this, SLOT(OnNew()));
+ connect(saveas_act, SIGNAL(triggered()), this, SLOT(OnSaveAs()));
+ connect(m_soc_tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
+ this, SLOT(OnSocItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
+ connect(m_soc_tree, SIGNAL(itemActivated(QTreeWidgetItem*, int)),
+ this, SLOT(OnSocItemActivated(QTreeWidgetItem*, int)));
+}
+
+RegEdit::~RegEdit()
+{
+}
+
+void RegEdit::OnSave()
+{
+ SaveSoc();
+}
+
+void RegEdit::OnSaveAs()
+{
+ SaveSocAs();
+}
+
+bool RegEdit::CloseSoc()
+{
+ if(!m_modified)
+ return true;
+ QMessageBox msgBox;
+ msgBox.setText("The description has been modified.");
+ msgBox.setInformativeText("Do you want to save your changes?");
+ msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
+ msgBox.setDefaultButton(QMessageBox::Save);
+ int ret = msgBox.exec();
+ if(ret == QMessageBox::Discard)
+ return true;
+ if(ret == QMessageBox::Cancel)
+ return false;
+ return SaveSoc();
+}
+
+bool RegEdit::SaveSoc()
+{
+ if(m_file_edit->text().size() == 0)
+ return SaveSocAs();
+ else
+ return SaveSocFile(m_file_edit->text());
+}
+
+bool RegEdit::GetFilename(QString& filename, bool save)
+{
+ QFileDialog *fd = new QFileDialog(this);
+ if(save)
+ fd->setAcceptMode(QFileDialog::AcceptSave);
+ fd->setFilter("Description files (*.xml);;All files (*)");
+ fd->setDirectory(Settings::Get()->value("loaddescdir", QDir::currentPath()).toString());
+ if(fd->exec())
+ {
+ QStringList filenames = fd->selectedFiles();
+ filename = filenames[0];
+ Settings::Get()->setValue("loaddescdir", fd->directory().absolutePath());
+ return true;
+ }
+ else
+ return false;
+}
+
+bool RegEdit::SaveSocAs()
+{
+ QString filename;
+ if(!GetFilename(filename, true))
+ return false;
+ m_file_edit->setText(filename);
+ return SaveSocFile(filename);
+}
+
+void RegEdit::OnOpen()
+{
+ if(!CloseSoc())
+ return;
+ QString filename;
+ if(!GetFilename(filename, false))
+ return;
+ LoadSocFile(filename);
+}
+
+void RegEdit::OnNew()
+{
+ if(!CloseSoc())
+ return;
+ m_cur_socfile = SocFile();
+ m_file_edit->setText("");
+ SetModified(false, false);
+ UpdateSocFile();
+}
+
+bool RegEdit::SaveSocFile(const QString& filename)
+{
+ soc_desc_normalize(m_cur_socfile.GetSoc());
+ if(!soc_desc_produce_xml(filename.toStdString(), m_cur_socfile.GetSoc()))
+ {
+ QMessageBox::warning(this, "The description was not saved",
+ "There was an error when saving the file");
+ return false;
+ }
+ m_soc_tree->clear();
+ FillSocTree();
+ SetModified(false, false);
+ return true;
+}
+
+void RegEdit::LoadSocFile(const QString& filename)
+{
+ m_cur_socfile = SocFile(filename);
+ if(!m_cur_socfile.IsValid())
+ {
+ QMessageBox::warning(this, "The description was not loaded",
+ "There was an error when loading the file");
+ return;
+ }
+ m_file_edit->setText(filename);
+ SetModified(false, false);
+ UpdateSocFile();
+}
+
+void RegEdit::CreateNewFieldItem(QTreeWidgetItem *_parent)
+{
+ RegTreeItem *parent = dynamic_cast< RegTreeItem* >(_parent);
+ NewFieldTreeItem *newdev_item = new NewFieldTreeItem("New field...", parent->GetRef());
+ MakeItalic(newdev_item, true);
+ newdev_item->setIcon(0, QIcon::fromTheme("list-add"));
+ parent->addChild(newdev_item);
+}
+
+void RegEdit::FillRegTreeItem(QTreeWidgetItem *_item)
+{
+ RegTreeItem *item = dynamic_cast< RegTreeItem* >(_item);
+ const soc_reg_t& reg = item->GetRef().GetReg();
+ for(size_t i = 0; i < reg.field.size(); i++)
+ {
+ const soc_reg_field_t& field = reg.field[i];
+ FieldTreeItem *field_item = new FieldTreeItem(QString::fromStdString(field.name),
+ SocFieldRef(item->GetRef(), i));
+ FixupEmptyItem(field_item);
+ item->addChild(field_item);
+ }
+ CreateNewFieldItem(item);
+}
+
+void RegEdit::CreateNewRegisterItem(QTreeWidgetItem *_parent)
+{
+ DevTreeItem *parent = dynamic_cast< DevTreeItem* >(_parent);
+ NewRegTreeItem *newdev_item = new NewRegTreeItem("New register...", parent->GetRef());
+ MakeItalic(newdev_item, true);
+ newdev_item->setIcon(0, QIcon::fromTheme("list-add"));
+ parent->addChild(newdev_item);
+}
+
+void RegEdit::FillDevTreeItem(QTreeWidgetItem *_item)
+{
+ DevTreeItem *item = dynamic_cast< DevTreeItem* >(_item);
+ const soc_dev_t& dev = item->GetRef().GetDev();
+ for(size_t i = 0; i < dev.reg.size(); i++)
+ {
+ const soc_reg_t& reg = dev.reg[i];
+ RegTreeItem *reg_item = new RegTreeItem(QString::fromStdString(reg.name),
+ SocRegRef(item->GetRef(), i, -1));
+ FixupEmptyItem(reg_item);
+ FillRegTreeItem(reg_item);
+ item->addChild(reg_item);
+ }
+ CreateNewRegisterItem(item);
+}
+
+void RegEdit::CreateNewDeviceItem(QTreeWidgetItem *_parent)
+{
+ SocTreeItem *parent = dynamic_cast< SocTreeItem* >(_parent);
+ NewDevTreeItem *newdev_item = new NewDevTreeItem("New device...", parent->GetRef());
+ MakeItalic(newdev_item, true);
+ newdev_item->setIcon(0, QIcon::fromTheme("list-add"));
+ parent->addChild(newdev_item);
+}
+
+void RegEdit::FillSocTreeItem(QTreeWidgetItem *_item)
+{
+ SocTreeItem *item = dynamic_cast< SocTreeItem* >(_item);
+ const soc_t& soc = item->GetRef().GetSoc();
+ for(size_t i = 0; i < soc.dev.size(); i++)
+ {
+ const soc_dev_t& reg = soc.dev[i];
+ DevTreeItem *dev_item = new DevTreeItem(QString::fromStdString(reg.name),
+ SocDevRef(item->GetRef(), i, -1));
+ FixupEmptyItem(dev_item);
+ FillDevTreeItem(dev_item);
+ item->addChild(dev_item);
+ }
+ CreateNewDeviceItem(item);
+}
+
+void RegEdit::FillSocTree()
+{
+ SocRef ref = m_cur_socfile.GetSocRef();
+ SocTreeItem *soc_item = new SocTreeItem(
+ QString::fromStdString(ref.GetSoc().name), ref);
+ FixupEmptyItem(soc_item);
+ FillSocTreeItem(soc_item);
+ m_soc_tree->addTopLevelItem(soc_item);
+ soc_item->setExpanded(true);
+}
+
+void RegEdit::MakeItalic(QTreeWidgetItem *item, bool it)
+{
+ QFont font = item->font(0);
+ font.setItalic(it);
+ item->setFont(0, font);
+}
+
+void RegEdit::FixupEmptyItem(QTreeWidgetItem *item)
+{
+ if(item->text(0).size() == 0)
+ {
+ item->setIcon(0, QIcon::fromTheme("dialog-error"));
+ MakeItalic(item, true);
+ item->setText(0, "Unnamed");
+ }
+ else
+ {
+ item->setIcon(0, QIcon::fromTheme("cpu"));
+ MakeItalic(item, false);
+ }
+}
+
+void RegEdit::UpdateSocFile()
+{
+ m_soc_tree->clear();
+ FillSocTree();
+ SetPanel(new EmptyEditPanel(this));
+}
+
+void RegEdit::SetPanel(QWidget *panel)
+{
+ delete m_right_panel;
+ m_right_panel = panel;
+ connect(m_right_panel, SIGNAL(OnModified(bool)), this, SLOT(OnSocModified(bool)));
+ m_splitter->addWidget(m_right_panel);
+ m_splitter->setStretchFactor(1, 2);
+}
+
+void RegEdit::SetModified(bool add, bool mod)
+{
+ m_modified = add ? (m_modified || mod) : mod;
+ emit OnModified(mod);
+}
+
+void RegEdit::OnSocModified(bool modified)
+{
+ // we might need to update the name in the tree
+ UpdateName(m_soc_tree->currentItem());
+ if(modified)
+ SetModified(true, true);
+}
+
+void RegEdit::DisplaySoc(SocRef ref)
+{
+ SetPanel(new SocEditPanel(ref, this));
+}
+
+void RegEdit::DisplayDev(SocDevRef ref)
+{
+ SetPanel(new DevEditPanel(ref, this));
+}
+
+void RegEdit::DisplayReg(SocRegRef ref)
+{
+ SetPanel(new RegEditPanel(ref, this));
+}
+
+void RegEdit::DisplayField(SocFieldRef ref)
+{
+ SetPanel(new FieldEditPanel(ref, this));
+}
+
+void RegEdit::UpdateName(QTreeWidgetItem *current)
+{
+ if(current == 0)
+ return;
+ if(current->type() == SocTreeSocType)
+ {
+ SocTreeItem *item = dynamic_cast< SocTreeItem * >(current);
+ item->setText(0, QString::fromStdString(item->GetRef().GetSoc().name));
+ }
+ else if(current->type() == SocTreeDevType)
+ {
+ DevTreeItem *item = dynamic_cast< DevTreeItem * >(current);
+ item->setText(0, QString::fromStdString(item->GetRef().GetDev().name));
+ }
+ else if(current->type() == SocTreeRegType)
+ {
+ RegTreeItem *item = dynamic_cast< RegTreeItem * >(current);
+ item->setText(0, QString::fromStdString(item->GetRef().GetReg().name));
+ }
+ else if(current->type() == SocTreeFieldType)
+ {
+ FieldTreeItem *item = dynamic_cast< FieldTreeItem * >(current);
+ item->setText(0, QString::fromStdString(item->GetRef().GetField().name));
+ }
+ FixupEmptyItem(current);
+}
+
+void RegEdit::OnSocItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
+{
+ Q_UNUSED(previous);
+ if(current == 0)
+ return;
+ if(current->type() == SocTreeSocType)
+ {
+ SocTreeItem *item = dynamic_cast< SocTreeItem * >(current);
+ DisplaySoc(item->GetRef());
+ }
+ else if(current->type() == SocTreeDevType)
+ {
+ DevTreeItem *item = dynamic_cast< DevTreeItem * >(current);
+ DisplayDev(item->GetRef());
+ }
+ else if(current->type() == SocTreeRegType)
+ {
+ RegTreeItem *item = dynamic_cast< RegTreeItem * >(current);
+ DisplayReg(item->GetRef());
+ }
+ else if(current->type() == SocTreeFieldType)
+ {
+ FieldTreeItem *item = dynamic_cast< FieldTreeItem * >(current);
+ DisplayField(item->GetRef());
+ }
+}
+
+void RegEdit::OnSocItemActivated(QTreeWidgetItem *current, int column)
+{
+ Q_UNUSED(column);
+ if(current == 0)
+ return;
+ if(current->type() == SocTreeNewDevType)
+ AddDevice(current);
+ else if(current->type() == SocTreeNewRegType)
+ AddRegister(current);
+ else if(current->type() == SocTreeNewFieldType)
+ AddField(current);
+}
+
+void RegEdit::AddDevice(QTreeWidgetItem *_item)
+{
+ NewDevTreeItem *item = dynamic_cast< NewDevTreeItem * >(_item);
+ item->GetRef().GetSoc().dev.push_back(soc_dev_t());
+ DevTreeItem *dev_item = new DevTreeItem("",
+ SocDevRef(item->GetRef(), item->GetRef().GetSoc().dev.size() - 1, -1));
+ FixupEmptyItem(dev_item);
+ item->parent()->insertChild(item->parent()->indexOfChild(item), dev_item);
+ CreateNewRegisterItem(dev_item);
+ m_soc_tree->setCurrentItem(dev_item);
+}
+
+void RegEdit::AddRegister(QTreeWidgetItem *_item)
+{
+ NewRegTreeItem *item = dynamic_cast< NewRegTreeItem * >(_item);
+ item->GetRef().GetDev().reg.push_back(soc_reg_t());
+ RegTreeItem *reg_item = new RegTreeItem("",
+ SocRegRef(item->GetRef(), item->GetRef().GetDev().reg.size() - 1, -1));
+ FixupEmptyItem(reg_item);
+ item->parent()->insertChild(item->parent()->indexOfChild(item), reg_item);
+ CreateNewFieldItem(reg_item);
+ m_soc_tree->setCurrentItem(reg_item);
+}
+
+void RegEdit::AddField(QTreeWidgetItem *_item)
+{
+ NewFieldTreeItem *item = dynamic_cast< NewFieldTreeItem * >(_item);
+ item->GetRef().GetReg().field.push_back(soc_reg_field_t());
+ FieldTreeItem *field_item = new FieldTreeItem("",
+ SocFieldRef(item->GetRef(), item->GetRef().GetReg().field.size() - 1));
+ FixupEmptyItem(field_item);
+ item->parent()->insertChild(item->parent()->indexOfChild(item), field_item);
+ m_soc_tree->setCurrentItem(field_item);
+}
+
+bool RegEdit::Quit()
+{
+ return CloseSoc();
+} \ No newline at end of file
diff --git a/utils/regtools/qeditor/regedit.h b/utils/regtools/qeditor/regedit.h
new file mode 100644
index 0000000000..8615816783
--- /dev/null
+++ b/utils/regtools/qeditor/regedit.h
@@ -0,0 +1,282 @@
+#ifndef REGEDIT_H
+#define REGEDIT_H
+
+#include <QComboBox>
+#include <QTreeWidget>
+#include <QVBoxLayout>
+#include <QTabWidget>
+#include <QSplitter>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QLabel>
+#include <QListWidget>
+#include <QGroupBox>
+#include <QToolButton>
+#include <QMenu>
+#include <QCheckBox>
+#include <QRadioButton>
+#include <QButtonGroup>
+#include <QDebug>
+#include <QScrollArea>
+#include "backend.h"
+#include "settings.h"
+#include "mainwindow.h"
+#include "aux.h"
+
+class AbstractRegEditPanel
+{
+public:
+ AbstractRegEditPanel() {}
+ virtual ~AbstractRegEditPanel() {}
+ virtual void OnModified(bool mod) = 0;
+};
+
+class EmptyEditPanel : public QWidget, public AbstractRegEditPanel
+{
+ Q_OBJECT
+public:
+ EmptyEditPanel(QWidget *parent);
+
+signals:
+ void OnModified(bool mod);
+
+protected:
+};
+
+class SocEditPanel : public QWidget, public AbstractRegEditPanel
+{
+ Q_OBJECT
+public:
+ SocEditPanel(SocRef ref, QWidget *parent = 0);
+
+signals:
+ void OnModified(bool mod);
+
+protected slots:
+ void OnTextEdited();
+ void OnNameEdited(const QString& text);
+
+protected:
+ SocRef m_ref;
+ QGroupBox *m_name_group;
+ QLineEdit *m_name_edit;
+ QGroupBox *m_desc_group;
+ MyTextEditor *m_desc_edit;
+};
+
+class DevEditPanel : public QWidget, public AbstractRegEditPanel
+{
+ Q_OBJECT
+public:
+ DevEditPanel(SocDevRef ref, QWidget *parent = 0);
+
+signals:
+ void OnModified(bool mod);
+
+protected slots:
+ void OnInstActivated(int row, int column);
+ void OnInstChanged(int row, int column);
+ void OnNameEdited(const QString& text);
+ void OnLongNameEdited(const QString& text);
+ void OnVersionEdited(const QString& text);
+ void OnDescEdited();
+
+protected:
+ void FillRow(int row, const soc_dev_addr_t& addr);
+ void CreateNewRow(int row);
+
+ enum
+ {
+ DevInstDeleteType = QTableWidgetItem::UserType,
+ DevInstNewType
+ };
+
+ enum
+ {
+ DevInstIconColumn = 0,
+ DevInstNameColumn = 1,
+ DevInstAddrColumn = 2,
+ };
+
+ SocDevRef m_ref;
+ QGroupBox *m_name_group;
+ QLineEdit *m_name_edit;
+ QGroupBox *m_long_name_group;
+ QLineEdit *m_long_name_edit;
+ QGroupBox *m_version_group;
+ QLineEdit *m_version_edit;
+ QGroupBox *m_instances_group;
+ QTableWidget *m_instances_table;
+ QGroupBox *m_desc_group;
+ MyTextEditor *m_desc_edit;
+};
+
+class RegEditPanel : public QWidget, public AbstractRegEditPanel
+{
+ Q_OBJECT
+public:
+ RegEditPanel(SocRegRef ref, QWidget *parent = 0);
+
+signals:
+ void OnModified(bool mod);
+
+protected slots:
+ void OnInstActivated(int row, int column);
+ void OnInstChanged(int row, int column);
+ void OnNameEdited(const QString& text);
+ void OnDescEdited();
+ void OnSctEdited(int state);
+ void OnFormulaChanged(int index);
+ void OnFormulaStringChanged(const QString& text);
+ void OnFormulaGenerate(bool checked);
+
+protected:
+ void CreateNewAddrRow(int row);
+ void FillRow(int row, const soc_reg_addr_t& addr);
+ void UpdateFormula();
+ void UpdateWarning(int row);
+
+ enum
+ {
+ RegInstDeleteType = QTableWidgetItem::UserType,
+ RegInstNewType
+ };
+
+ enum
+ {
+ RegInstIconColumn = 0,
+ RegInstNameColumn,
+ RegInstAddrColumn,
+ RegInstNrColumns,
+ };
+
+ SocRegRef m_ref;
+ QGroupBox *m_name_group;
+ QLineEdit *m_name_edit;
+ QGroupBox *m_instances_group;
+ QTableWidget *m_instances_table;
+ QGroupBox *m_desc_group;
+ QGroupBox *m_flags_group;
+ QCheckBox *m_sct_check;
+ QFont m_reg_font;
+ QGroupBox *m_formula_group;
+ QButtonGroup *m_formula_radio_group;
+ QLabel *m_formula_type_label;
+ QComboBox *m_formula_combo;
+ QLineEdit *m_formula_string_edit;
+ QPushButton *m_formula_string_gen;
+ RegSexyDisplay *m_sexy_display;
+ MyTextEditor *m_desc_edit;
+ QGroupBox *m_field_group;
+ QTableWidget *m_field_table;
+};
+
+class FieldEditPanel : public QWidget, public AbstractRegEditPanel
+{
+ Q_OBJECT
+public:
+ FieldEditPanel(SocFieldRef ref, QWidget *parent = 0);
+
+signals:
+ void OnModified(bool mod);
+
+protected slots:
+ void OnDescEdited();
+ void OnNameEdited(const QString& text);
+ void OnBitRangeEdited(const QString& string);
+ void OnValueActivated(int row, int column);
+ void OnValueChanged(int row, int column);
+
+protected:
+ void CreateNewRow(int row);
+ void FillRow(int row, const soc_reg_field_value_t& val);
+ void UpdateWarning(int row);
+ void UpdateDelegates();
+
+ enum
+ {
+ FieldValueDeleteType = QTableWidgetItem::UserType,
+ FieldValueNewType,
+ };
+
+ enum
+ {
+ FieldValueIconColumn = 0,
+ FieldValueNameColumn,
+ FieldValueValueColumn,
+ FieldValueDescColumn,
+ FieldValueNrColumns,
+ };
+
+ SocFieldRef m_ref;
+ QGroupBox *m_name_group;
+ QLineEdit *m_name_edit;
+ QGroupBox *m_bitrange_group;
+ QLineEdit *m_bitrange_edit;
+ QGroupBox *m_desc_group;
+ MyTextEditor *m_desc_edit;
+ QGroupBox *m_value_group;
+ QTableWidget *m_value_table;
+};
+
+class RegEdit : public QWidget, public DocumentTab
+{
+ Q_OBJECT
+public:
+ RegEdit(Backend *backend, QWidget *parent = 0);
+ ~RegEdit();
+ virtual bool Quit();
+
+signals:
+ void OnModified(bool mod);
+
+protected slots:
+ void OnSocItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
+ void OnSocItemActivated(QTreeWidgetItem *current, int column);
+ void OnOpen();
+ void OnSave();
+ void OnSaveAs();
+ void OnSocModified(bool modified);
+ void OnNew();
+
+protected:
+ void LoadSocFile(const QString& filename);
+ void UpdateSocFile();
+ void FillSocTree();
+ void FillSocTreeItem(QTreeWidgetItem *_item);
+ void FillDevTreeItem(QTreeWidgetItem *_item);
+ void FillRegTreeItem(QTreeWidgetItem *_item);
+ void SetPanel(QWidget *panel);
+ void DisplaySoc(SocRef ref);
+ void DisplayDev(SocDevRef ref);
+ void DisplayReg(SocRegRef ref);
+ void DisplayField(SocFieldRef ref);
+ bool CloseSoc();
+ bool SaveSoc();
+ bool SaveSocAs();
+ bool SaveSocFile(const QString& filename);
+ bool GetFilename(QString& filename, bool save);
+ void SetModified(bool add, bool mod);
+ void FixupEmptyItem(QTreeWidgetItem *item);
+ void MakeItalic(QTreeWidgetItem *item, bool it);
+ void AddDevice(QTreeWidgetItem *item);
+ void AddRegister(QTreeWidgetItem *_item);
+ void UpdateName(QTreeWidgetItem *current);
+ void AddField(QTreeWidgetItem *_item);
+ void CreateNewDeviceItem(QTreeWidgetItem *parent);
+ void CreateNewRegisterItem(QTreeWidgetItem *parent);
+ void CreateNewFieldItem(QTreeWidgetItem *parent);
+
+ QGroupBox *m_file_group;
+ QToolButton *m_file_open;
+ QToolButton *m_file_save;
+ QLineEdit *m_file_edit;
+ QSplitter *m_splitter;
+ QTreeWidget *m_soc_tree;
+ Backend *m_backend;
+ bool m_modified;
+ SocFile m_cur_socfile;
+ QWidget *m_right_panel;
+};
+
+#endif /* REGEDIT_H */
diff --git a/utils/regtools/qeditor/regtab.cpp b/utils/regtools/qeditor/regtab.cpp
index 4cd4e7b283..568d859c0e 100644
--- a/utils/regtools/qeditor/regtab.cpp
+++ b/utils/regtools/qeditor/regtab.cpp
@@ -1,406 +1,75 @@
#include "regtab.h"
-#include <QSplitter>
-#include <QVBoxLayout>
-#include <QAbstractListModel>
-#include <QMessageBox>
#include <QSizePolicy>
-#include <QHBoxLayout>
#include <QStringBuilder>
-#include <QLabel>
-#include <QGridLayout>
-#include <QTableWidget>
-#include <QHeaderView>
#include <QFileDialog>
#include <QDebug>
#include <QStyle>
#include "backend.h"
#include "analyser.h"
+#include "regdisplaypanel.h"
-/**
- * SocFieldValidator
- */
-
-SocFieldValidator::SocFieldValidator(QObject *parent)
- :QValidator(parent)
-{
- m_field.first_bit = 0;
- m_field.last_bit = 31;
-}
-
-SocFieldValidator::SocFieldValidator(const soc_reg_field_t& field, QObject *parent)
- :QValidator(parent), m_field(field)
-{
-}
-
-void SocFieldValidator::fixup(QString& input) const
-{
- input = input.trimmed();
-}
-
-QValidator::State SocFieldValidator::validate(QString& input, int& pos) const
-{
- (void) pos;
- soc_word_t val;
- State state = parse(input, val);
- return state;
-}
-
-QValidator::State SocFieldValidator::parse(const QString& input, soc_word_t& val) const
-{
- // the empty string is all alwats intermediate
- if(input.size() == 0)
- return Intermediate;
- // first check named values
- State state = Invalid;
- foreach(const soc_reg_field_value_t& value, m_field.value)
- {
- QString name = QString::fromLocal8Bit(value.name.c_str());
- // cannot be a substring if too long or empty
- if(input.size() > name.size())
- continue;
- // check equal string
- if(input == name)
- {
- state = Acceptable;
- val = value.value;
- break;
- }
- // check substring
- if(name.startsWith(input))
- state = Intermediate;
- }
- // early return for exact match
- if(state == Acceptable)
- return state;
- // do a few special cases for convenience
- if(input.compare("0x", Qt::CaseInsensitive) == 0 ||
- input.compare("0b", Qt::CaseInsensitive) == 0)
- return Intermediate;
- // try by parsing
- unsigned basis, pos;
- if(input.size() >= 2 && input.startsWith("0x", Qt::CaseInsensitive))
- {
- basis = 16;
- pos = 2;
- }
- else if(input.size() >= 2 && input.startsWith("0b", Qt::CaseInsensitive))
- {
- basis = 2;
- pos = 2;
- }
- else if(input.size() >= 2 && input.startsWith("0"))
- {
- basis = 8;
- pos = 1;
- }
- else
- {
- basis = 10;
- pos = 0;
- }
- bool ok = false;
- unsigned long v = input.mid(pos).toULong(&ok, basis);
- // if not ok, return result of name parsing
- if(!ok)
- return state;
- // if ok, check if it fits in the number of bits
- unsigned nr_bits = m_field.last_bit - m_field.first_bit + 1;
- unsigned long max = nr_bits == 32 ? 0xffffffff : (1 << nr_bits) - 1;
- if(v <= max)
- {
- val = v;
- return Acceptable;
- }
-
- return state;
-}
-
-/**
- * RegLineEdit
- */
-RegLineEdit::RegLineEdit(QWidget *parent)
- :QWidget(parent)
+namespace
{
- m_layout = new QHBoxLayout(this);
- m_button = new QToolButton(this);
- m_button->setCursor(Qt::ArrowCursor);
- m_button->setStyleSheet("QToolButton { font-weight: bold; color: white; background: black; }");
- m_button->setPopupMode(QToolButton::InstantPopup);
- m_edit = new QLineEdit(this);
- m_layout->addWidget(m_button);
- m_layout->addWidget(m_edit);
- m_menu = new QMenu(this);
- connect(m_menu->addAction("Write"), SIGNAL(triggered()), this, SLOT(OnWriteAct()));
- connect(m_menu->addAction("Set"), SIGNAL(triggered()), this, SLOT(OnSetAct()));
- connect(m_menu->addAction("Clear"), SIGNAL(triggered()), this, SLOT(OnClearAct()));
- connect(m_menu->addAction("Toggle"), SIGNAL(triggered()), this, SLOT(OnToggleAct()));
- EnableSCT(false);
- SetReadOnly(false);
- ShowMode(true);
- SetMode(Write);
-}
-void RegLineEdit::SetReadOnly(bool ro)
+enum
{
- m_edit->setReadOnly(ro);
- m_readonly = ro;
- ShowMode(!ro);
-}
+ RegTreeDevType = QTreeWidgetItem::UserType,
+ RegTreeRegType
+};
-void RegLineEdit::EnableSCT(bool en)
+class DevTreeItem : public QTreeWidgetItem
{
- m_has_sct = en;
- if(!m_has_sct)
- {
- m_button->setMenu(0);
- SetMode(Write);
- }
- else
- m_button->setMenu(m_menu);
-}
-
-RegLineEdit::~RegLineEdit()
-{
-}
+public:
+ DevTreeItem(const QString& string, const SocDevRef& ref)
+ :QTreeWidgetItem(QStringList(string), RegTreeDevType), m_ref(ref) {}
-QLineEdit *RegLineEdit::GetLineEdit()
-{
- return m_edit;
-}
+ const SocDevRef& GetRef() { return m_ref; }
+private:
+ SocDevRef m_ref;
+};
-void RegLineEdit::ShowMode(bool show)
+class RegTreeItem : public QTreeWidgetItem
{
- if(show)
- m_button->show();
- else
- m_button->hide();
-}
+public:
+ RegTreeItem(const QString& string, const SocRegRef& ref)
+ :QTreeWidgetItem(QStringList(string), RegTreeRegType), m_ref(ref) {}
-void RegLineEdit::OnWriteAct()
-{
- SetMode(Write);
-}
-
-void RegLineEdit::OnSetAct()
-{
- SetMode(Set);
-}
-
-void RegLineEdit::OnClearAct()
-{
- SetMode(Clear);
-}
-
-void RegLineEdit::OnToggleAct()
-{
- SetMode(Toggle);
-}
-
-void RegLineEdit::SetMode(EditMode mode)
-{
- m_mode = mode;
- switch(m_mode)
- {
- case Write: m_button->setText("WR"); break;
- case Set: m_button->setText("SET"); break;
- case Clear: m_button->setText("CLR"); break;
- case Toggle: m_button->setText("TOG"); break;
- default: break;
- }
-}
+ const SocRegRef& GetRef() { return m_ref; }
+private:
+ SocRegRef m_ref;
+};
-RegLineEdit::EditMode RegLineEdit::GetMode()
-{
- return m_mode;
}
/**
- * RegDisplayPanel
+ * EmptyRegTabPanel
*/
-
-RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const SocRegRef& reg_ref)
- :QGroupBox(parent), m_io_backend(io_backend), m_reg(reg_ref)
+EmptyRegTabPanel::EmptyRegTabPanel(QWidget *parent)
+ :QWidget(parent)
{
- bool read_only = m_io_backend->IsReadOnly();
-
- QVBoxLayout *right_layout = new QVBoxLayout;
-
- const soc_dev_addr_t& dev_addr = m_reg.GetDevAddr();
- const soc_reg_t& reg = m_reg.GetReg();
- const soc_reg_addr_t& reg_addr = m_reg.GetRegAddr();
-
- QString reg_name;
- reg_name.sprintf("HW_%s_%s", dev_addr.name.c_str(), reg_addr.name.c_str());
- QStringList names;
- QVector< soc_addr_t > addresses;
- names.append(reg_name);
- addresses.append(reg_addr.addr);
- if(reg.flags & REG_HAS_SCT)
- {
- names.append(reg_name + "_SET");
- names.append(reg_name + "_CLR");
- names.append(reg_name + "_TOG");
- addresses.append(reg_addr.addr + 4);
- addresses.append(reg_addr.addr + 8);
- addresses.append(reg_addr.addr + 12);
- }
-
- QString str;
- str += "<table align=left>";
- for(int i = 0; i < names.size(); i++)
- str += "<tr><td><b>" + names[i] + "</b></td></tr>";
- str += "</table>";
- QLabel *label_names = new QLabel;
- label_names->setTextFormat(Qt::RichText);
- label_names->setText(str);
-
- QString str_addr;
- str_addr += "<table align=left>";
- for(int i = 0; i < names.size(); i++)
- str_addr += "<tr><td><b>" + QString().sprintf("0x%03x", addresses[i]) + "</b></td></tr>";
- str_addr += "</table>";
- QLabel *label_addr = new QLabel;
- label_addr->setTextFormat(Qt::RichText);
- label_addr->setText(str_addr);
-
- QHBoxLayout *top_layout = new QHBoxLayout;
- top_layout->addStretch();
- top_layout->addWidget(label_names);
- top_layout->addWidget(label_addr);
- top_layout->addStretch();
-
- soc_word_t value;
- BackendHelper helper(m_io_backend, m_reg);
- bool has_value = helper.ReadRegister(dev_addr.name.c_str(), reg_addr.name.c_str(), value);
-
- QHBoxLayout *raw_val_layout = 0;
- if(has_value)
- {
- QLabel *raw_val_name = new QLabel;
- raw_val_name->setText("Raw value:");
- m_raw_val_edit = new RegLineEdit;
- m_raw_val_edit->SetReadOnly(read_only);
- m_raw_val_edit->GetLineEdit()->setText(QString().sprintf("0x%08x", value));
- m_raw_val_edit->GetLineEdit()->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
- m_raw_val_edit->GetLineEdit()->setValidator(new SocFieldValidator(m_raw_val_edit));
- m_raw_val_edit->EnableSCT(!!(reg.flags & REG_HAS_SCT));
- connect(m_raw_val_edit->GetLineEdit(), SIGNAL(returnPressed()), this, SLOT(OnRawRegValueReturnPressed()));
- raw_val_layout = new QHBoxLayout;
- raw_val_layout->addStretch();
- raw_val_layout->addWidget(raw_val_name);
- raw_val_layout->addWidget(m_raw_val_edit);
- raw_val_layout->addStretch();
- }
- else
- m_raw_val_edit = 0;
-
- QTableWidget *value_table = new QTableWidget;
- value_table->setRowCount(reg.field.size());
- value_table->setColumnCount(4);
- int row = 0;
- foreach(const soc_reg_field_t& field, reg.field)
- {
- QString bits_str;
- if(field.first_bit == field.last_bit)
- bits_str.sprintf("%d", field.first_bit);
- else
- bits_str.sprintf("%d:%d", field.last_bit, field.first_bit);
- QTableWidgetItem *item = new QTableWidgetItem(bits_str);
- item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
- item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
- value_table->setItem(row, 0, item);
- item = new QTableWidgetItem(QString(field.name.c_str()));
- item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
- value_table->setItem(row, 1, item);
- item = new QTableWidgetItem();
- if(has_value)
- {
- soc_word_t v = (value & field.bitmask()) >> field.first_bit;
- QString value_name;
- foreach(const soc_reg_field_value_t& rval, field.value)
- if(v == rval.value)
- value_name = rval.name.c_str();
- const char *fmt = "%lu";
- // heuristic
- if((field.last_bit - field.first_bit + 1) > 16)
- fmt = "0x%lx";
- item->setText(QString().sprintf(fmt, (unsigned long)v));
- item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
-
- if(value_name.size() != 0)
- {
- QTableWidgetItem *t = new QTableWidgetItem(value_name);
- t->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
- t->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
- value_table->setItem(row, 3, t);
- }
- }
- item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
- value_table->setItem(row, 2, item);
- row++;
- }
- value_table->setHorizontalHeaderItem(0, new QTableWidgetItem("Bits"));
- value_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Name"));
- value_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Value"));
- value_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Meaning"));
- value_table->verticalHeader()->setVisible(false);
- value_table->resizeColumnsToContents();
- value_table->horizontalHeader()->setStretchLastSection(true);
- value_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-
- right_layout->addLayout(top_layout);
- if(raw_val_layout)
- right_layout->addLayout(raw_val_layout);
- //right_layout->addWidget(bits_label);
- right_layout->addWidget(value_table);
- //right_layout->addStretch();
-
- setTitle("Register Description");
- setLayout(right_layout);
- AllowWrite(false);
+ QVBoxLayout *l = new QVBoxLayout;
+ l->addStretch();
+ setLayout(l);
}
-void RegDisplayPanel::AllowWrite(bool en)
+void EmptyRegTabPanel::AllowWrite(bool en)
{
- m_allow_write = en;
- if(m_raw_val_edit)
- m_raw_val_edit->SetReadOnly(m_io_backend->IsReadOnly() || !m_allow_write);
+ Q_UNUSED(en);
}
-IoBackend::WriteMode RegDisplayPanel::EditModeToWriteMode(RegLineEdit::EditMode mode)
+QWidget *EmptyRegTabPanel::GetWidget()
{
- switch(mode)
- {
- case RegLineEdit::Write: return IoBackend::Write;
- case RegLineEdit::Set: return IoBackend::Set;
- case RegLineEdit::Clear: return IoBackend::Clear;
- case RegLineEdit::Toggle: return IoBackend::Toggle;
- default: return IoBackend::Write;
- }
+ return this;
}
-void RegDisplayPanel::OnRawRegValueReturnPressed()
-{
- soc_word_t val;
- QLineEdit *edit = m_raw_val_edit->GetLineEdit();
- const SocFieldValidator *validator = dynamic_cast< const SocFieldValidator *>(edit->validator());
- QValidator::State state = validator->parse(edit->text(), val);
- if(state != QValidator::Acceptable)
- return;
- IoBackend::WriteMode mode = EditModeToWriteMode(m_raw_val_edit->GetMode());
- BackendHelper helper(m_io_backend, m_reg);
- helper.WriteRegister(m_reg.GetDevAddr().name.c_str(), m_reg.GetRegAddr().name.c_str(),
- val, mode);
- // FIXME: we should notify the UI to read value back because it has changed
-}
/**
* RegTab
*/
-RegTab::RegTab(Backend *backend)
- :m_backend(backend)
+RegTab::RegTab(Backend *backend, QWidget *parent)
+ :QSplitter(parent), m_backend(backend)
{
QWidget *left = new QWidget;
this->addWidget(left);
@@ -432,7 +101,7 @@ RegTab::RegTab(Backend *backend)
QGroupBox *data_sel_group = new QGroupBox("Data selection");
QHBoxLayout *data_sel_layout = new QHBoxLayout;
m_data_selector = new QComboBox;
- m_data_selector->addItem(QIcon::fromTheme("face-sad"), "None", QVariant(DataSelNothing));
+ m_data_selector->addItem(QIcon::fromTheme("text-x-generic"), "Explore", QVariant(DataSelNothing));
m_data_selector->addItem(QIcon::fromTheme("document-open"), "File...", QVariant(DataSelFile));
#ifdef HAVE_HWSTUB
m_data_selector->addItem(QIcon::fromTheme("multimedia-player"), "Device...", QVariant(DataSelDevice));
@@ -446,7 +115,8 @@ RegTab::RegTab(Backend *backend)
data_sel_reload->setIcon(QIcon::fromTheme("view-refresh"));
data_sel_reload->setToolTip("Reload data");
data_sel_layout->addWidget(m_data_selector);
- data_sel_layout->addWidget(m_data_sel_edit);
+ data_sel_layout->addWidget(m_data_sel_edit, 1);
+ data_sel_layout->addStretch(0);
#ifdef HAVE_HWSTUB
m_dev_selector = new QComboBox;
data_sel_layout->addWidget(m_dev_selector, 1);
@@ -457,12 +127,9 @@ RegTab::RegTab(Backend *backend)
data_sel_group->setLayout(data_sel_layout);
m_data_soc_label->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
- m_right_panel->addWidget(data_sel_group);
- m_right_content = new QWidget;
- QVBoxLayout *l = new QVBoxLayout;
- l->addStretch();
- m_right_content->setLayout(l);
- m_right_panel->addWidget(m_right_content);
+ m_right_panel->addWidget(data_sel_group, 0);
+ m_right_content = 0;
+ SetPanel(new EmptyRegTabPanel);
QWidget *w = new QWidget;
w->setLayout(m_right_panel);
this->addWidget(w);
@@ -470,21 +137,17 @@ RegTab::RegTab(Backend *backend)
m_io_backend = m_backend->CreateDummyIoBackend();
- connect(m_soc_selector, SIGNAL(currentIndexChanged(const QString&)),
- this, SLOT(OnSocChanged(const QString&)));
+ connect(m_soc_selector, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(OnSocChanged(int)));
connect(m_backend, SIGNAL(OnSocListChanged()), this, SLOT(OnSocListChanged()));
connect(m_reg_tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
this, SLOT(OnRegItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
- connect(m_reg_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
- SLOT(OnRegItemClicked(QTreeWidgetItem *, int)));
connect(m_data_selector, SIGNAL(activated(int)),
this, SLOT(OnDataSelChanged(int)));
connect(m_data_soc_label, SIGNAL(linkActivated(const QString&)), this,
SLOT(OnDataSocActivated(const QString&)));
connect(m_analysers_list, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
this, SLOT(OnAnalyserChanged(QListWidgetItem *, QListWidgetItem *)));
- connect(m_analysers_list, SIGNAL(itemClicked(QListWidgetItem *)), this,
- SLOT(OnAnalyserClicked(QListWidgetItem *)));
#ifdef HAVE_HWSTUB
connect(m_dev_selector, SIGNAL(currentIndexChanged(int)),
this, SLOT(OnDevChanged(int)));
@@ -492,14 +155,22 @@ RegTab::RegTab(Backend *backend)
connect(m_readonly_check, SIGNAL(clicked(bool)), this, SLOT(OnReadOnlyClicked(bool)));
OnSocListChanged();
- OnDataSelChanged(DataSelNothing);
+ OnDataSelChanged(0);
}
RegTab::~RegTab()
{
+#ifdef HAVE_HWSTUB
+ ClearDevList();
+#endif
delete m_io_backend;
}
+bool RegTab::Quit()
+{
+ return true;
+}
+
void RegTab::SetDataSocName(const QString& socname)
{
if(socname.size() != 0)
@@ -533,9 +204,10 @@ void RegTab::OnDataSelChanged(int index)
#ifdef HAVE_HWSTUB
m_dev_selector->hide();
#endif
+ m_readonly_check->show();
QFileDialog *fd = new QFileDialog(m_data_selector);
fd->setFilter("Textual files (*.txt);;All files (*)");
- fd->setDirectory(Settings::Get()->value("regtab/loaddatadir", QDir::currentPath()).toString());
+ fd->setDirectory(Settings::Get()->value("loaddatadir", QDir::currentPath()).toString());
if(fd->exec())
{
QStringList filenames = fd->selectedFiles();
@@ -545,13 +217,14 @@ void RegTab::OnDataSelChanged(int index)
SetDataSocName(m_io_backend->GetSocName());
OnDataSocActivated(m_io_backend->GetSocName());
}
- Settings::Get()->setValue("regtab/loaddatadir", fd->directory().absolutePath());
+ Settings::Get()->setValue("loaddatadir", fd->directory().absolutePath());
SetReadOnlyIndicator();
}
#ifdef HAVE_HWSTUB
else if(var == DataSelDevice)
{
m_data_sel_edit->hide();
+ m_readonly_check->show();
m_dev_selector->show();
OnDevListChanged();
}
@@ -562,13 +235,31 @@ void RegTab::OnDataSelChanged(int index)
#ifdef HAVE_HWSTUB
m_dev_selector->hide();
#endif
+ m_readonly_check->hide();
+
delete m_io_backend;
m_io_backend = m_backend->CreateDummyIoBackend();
+ m_readonly_check->setCheckState(Qt::Checked);
SetDataSocName("");
+ UpdateSocFilename();
}
OnDataChanged();
}
+void RegTab::UpdateSocFilename()
+{
+ int index = m_data_selector->currentIndex();
+ if(index == -1)
+ return;
+ if(m_data_selector->itemData(index) != DataSelNothing)
+ return;
+ index = m_soc_selector->currentIndex();
+ if(index == -1)
+ return;
+ SocRef ref = m_soc_selector->itemData(index).value< SocRef >();
+ m_data_sel_edit->setText(ref.GetSocFile()->GetFilename());
+}
+
void RegTab::SetReadOnlyIndicator()
{
if(m_io_backend->IsReadOnly())
@@ -582,23 +273,30 @@ void RegTab::OnDataChanged()
void RegTab::OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
- (void) previous;
+ Q_UNUSED(previous);
OnRegItemClicked(current, 0);
}
void RegTab::OnRegItemClicked(QTreeWidgetItem *current, int col)
{
- (void) col;
- if(current == 0 || current->type() != RegTreeRegType)
+ Q_UNUSED(col);
+ if(current == 0)
return;
- RegTreeItem *item = dynamic_cast< RegTreeItem * >(current);
-
- DisplayRegister(item->GetRef());
+ if(current->type() == RegTreeRegType)
+ {
+ RegTreeItem *item = dynamic_cast< RegTreeItem * >(current);
+ DisplayRegister(item->GetRef());
+ }
+ else if(current->type() == RegTreeDevType)
+ {
+ DevTreeItem *item = dynamic_cast< DevTreeItem * >(current);
+ DisplayDevice(item->GetRef());
+ }
}
void RegTab::OnAnalyserChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
- (void) previous;
+ Q_UNUSED(previous);
OnAnalyserClicked(current);
}
@@ -606,33 +304,44 @@ void RegTab::OnAnalyserClicked(QListWidgetItem *current)
{
if(current == 0)
return;
- delete m_right_content;
AnalyserFactory *ana = AnalyserFactory::GetAnalyserByName(current->text());
- m_right_content = ana->Create(m_cur_soc, m_io_backend)->GetWidget();
- m_right_panel->addWidget(m_right_content, 1);
+ SetPanel(ana->Create(m_cur_soc, m_io_backend));
}
void RegTab::DisplayRegister(const SocRegRef& ref)
{
+ SetPanel(new RegDisplayPanel(this, m_io_backend, ref));
+}
+
+void RegTab::DisplayDevice(const SocDevRef& ref)
+{
+ SetPanel(new DevDisplayPanel(this, ref));
+}
+
+void RegTab::SetPanel(RegTabPanel *panel)
+{
delete m_right_content;
- RegDisplayPanel *panel = new RegDisplayPanel(this, m_io_backend, ref);
- panel->AllowWrite(m_readonly_check->checkState() == Qt::Unchecked);
m_right_content = panel;
- m_right_panel->addWidget(m_right_content);
+ m_right_content->AllowWrite(m_readonly_check->checkState() == Qt::Unchecked);
+ m_right_panel->addWidget(m_right_content->GetWidget(), 1);
}
void RegTab::OnSocListChanged()
{
m_soc_selector->clear();
- QStringList socs = m_backend->GetSocNameList();
+ QList< SocRef > socs = m_backend->GetSocList();
for(int i = 0; i < socs.size(); i++)
- m_soc_selector->addItem(socs[i]);
+ {
+ QVariant v;
+ v.setValue(socs[i]);
+ m_soc_selector->addItem(QString::fromStdString(socs[i].GetSoc().name), v);
+ }
}
#ifdef HAVE_HWSTUB
void RegTab::OnDevListChanged()
{
- m_dev_selector->clear();
+ ClearDevList();
QList< HWStubDevice* > list = m_hwstub_helper.GetDevList();
foreach(HWStubDevice *dev, list)
{
@@ -659,10 +368,21 @@ void RegTab::OnDevChanged(int index)
OnDataSocActivated(m_io_backend->GetSocName());
OnDataChanged();
}
+
+void RegTab::ClearDevList()
+{
+ while(m_dev_selector->count() > 0)
+ {
+ HWStubDevice *dev = reinterpret_cast< HWStubDevice* >(m_dev_selector->itemData(0).value< void* >());
+ delete dev;
+ m_dev_selector->removeItem(0);
+ }
+}
#endif
-void RegTab::FillDevSubTree(DevTreeItem *item)
+void RegTab::FillDevSubTree(QTreeWidgetItem *_item)
{
+ DevTreeItem *item = dynamic_cast< DevTreeItem* >(_item);
const soc_dev_t& dev = item->GetRef().GetDev();
for(size_t i = 0; i < dev.reg.size(); i++)
{
@@ -697,23 +417,21 @@ void RegTab::FillAnalyserList()
m_analysers_list->addItems(AnalyserFactory::GetAnalysersForSoc(m_cur_soc.GetSoc().name.c_str()));
}
-void RegTab::OnSocChanged(const QString& soc)
+void RegTab::OnSocChanged(int index)
{
- m_reg_tree->clear();
- if(!m_backend->GetSocByName(soc, m_cur_soc))
+ if(index == -1)
return;
+ m_reg_tree->clear();
+ m_cur_soc = m_soc_selector->itemData(index).value< SocRef >();
FillRegTree();
FillAnalyserList();
+ UpdateSocFilename();
}
void RegTab::OnReadOnlyClicked(bool checked)
{
if(m_io_backend->IsReadOnly())
return SetReadOnlyIndicator();
- if(m_right_content == 0)
- return;
- RegDisplayPanel *panel = dynamic_cast< RegDisplayPanel* >(m_right_content);
- if(panel == 0)
- return;
- panel->AllowWrite(!checked);
+ m_right_content->AllowWrite(!checked);
+ UpdateSocFilename();
}
diff --git a/utils/regtools/qeditor/regtab.h b/utils/regtools/qeditor/regtab.h
index 9fa1437119..78a10ba379 100644
--- a/utils/regtools/qeditor/regtab.h
+++ b/utils/regtools/qeditor/regtab.h
@@ -2,7 +2,6 @@
#define REGTAB_H
#include <QComboBox>
-#include <QEvent>
#include <QTreeWidget>
#include <QVBoxLayout>
#include <QTabWidget>
@@ -11,118 +10,41 @@
#include <QPushButton>
#include <QLabel>
#include <QListWidget>
-#include <QValidator>
#include <QGroupBox>
#include <QToolButton>
#include <QMenu>
#include <QCheckBox>
-#include <soc_desc.hpp>
#include "backend.h"
#include "settings.h"
+#include "mainwindow.h"
-enum
-{
- RegTreeDevType = QTreeWidgetItem::UserType,
- RegTreeRegType
-};
-
-class DevTreeItem : public QTreeWidgetItem
-{
-public:
- DevTreeItem(const QString& string, const SocDevRef& ref)
- :QTreeWidgetItem(QStringList(string), RegTreeDevType), m_ref(ref) {}
-
- const SocDevRef& GetRef() { return m_ref; }
-private:
- SocDevRef m_ref;
-};
-
-class RegTreeItem : public QTreeWidgetItem
+class RegTabPanel
{
public:
- RegTreeItem(const QString& string, const SocRegRef& ref)
- :QTreeWidgetItem(QStringList(string), RegTreeRegType), m_ref(ref) {}
-
- const SocRegRef& GetRef() { return m_ref; }
-private:
- SocRegRef m_ref;
+ RegTabPanel() {}
+ virtual ~RegTabPanel() {}
+ virtual void AllowWrite(bool en) = 0;
+ virtual QWidget *GetWidget() = 0;
};
-class SocFieldValidator : public QValidator
+class EmptyRegTabPanel : public QWidget, public RegTabPanel
{
- Q_OBJECT
public:
- SocFieldValidator(QObject *parent = 0);
- SocFieldValidator(const soc_reg_field_t& field, QObject *parent = 0);
-
- virtual void fixup(QString& input) const;
- virtual State validate(QString& input, int& pos) const;
- /* validate and return the interpreted value */
- State parse(const QString& input, soc_word_t& val) const;
-
-protected:
- soc_reg_field_t m_field;
-};
-
-class RegLineEdit : public QWidget
-{
- Q_OBJECT
-public:
- enum EditMode
- {
- Write, Set, Clear, Toggle
- };
-
- RegLineEdit(QWidget *parent = 0);
- ~RegLineEdit();
- void SetReadOnly(bool ro);
- void EnableSCT(bool en);
- void SetMode(EditMode mode);
- EditMode GetMode();
- QLineEdit *GetLineEdit();
-
-protected slots:
- void OnWriteAct();
- void OnSetAct();
- void OnClearAct();
- void OnToggleAct();
-protected:
- void ShowMode(bool show);
-
- QHBoxLayout *m_layout;
- QToolButton *m_button;
- QLineEdit *m_edit;
- EditMode m_mode;
- bool m_has_sct;
- bool m_readonly;
- QMenu *m_menu;
-};
-
-class RegDisplayPanel : public QGroupBox
-{
- Q_OBJECT
-public:
- RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const SocRegRef& reg);
+ EmptyRegTabPanel(QWidget *parent = 0);
void AllowWrite(bool en);
-
-protected:
- IoBackend::WriteMode EditModeToWriteMode(RegLineEdit::EditMode mode);
-
- IoBackend *m_io_backend;
- const SocRegRef& m_reg;
- bool m_allow_write;
- RegLineEdit *m_raw_val_edit;
-
-private slots:
- void OnRawRegValueReturnPressed();
+ QWidget *GetWidget();
};
-class RegTab : public QSplitter
+class RegTab : public QSplitter, public DocumentTab
{
Q_OBJECT
public:
- RegTab(Backend *backend);
+ RegTab(Backend *backend, QWidget *parent = 0);
~RegTab();
+ virtual bool Quit();
+
+signals:
+ void OnModified(bool modified);
protected:
enum
@@ -134,12 +56,16 @@ protected:
#endif
};
- void FillDevSubTree(DevTreeItem *item);
+ void FillDevSubTree(QTreeWidgetItem *item);
void FillRegTree();
void FillAnalyserList();
void UpdateSocList();
void DisplayRegister(const SocRegRef& ref);
+ void DisplayDevice(const SocDevRef& ref);
void SetDataSocName(const QString& socname);
+ void SetPanel(RegTabPanel *panel);
+ void UpdateSocFilename();
+
QComboBox *m_soc_selector;
#ifdef HAVE_HWSTUB
QComboBox *m_dev_selector;
@@ -149,7 +75,7 @@ protected:
QTreeWidget *m_reg_tree;
SocRef m_cur_soc;
QVBoxLayout *m_right_panel;
- QWidget *m_right_content;
+ RegTabPanel *m_right_content;
QLineEdit *m_data_sel_edit;
QCheckBox *m_readonly_check;
QLabel *m_data_soc_label;
@@ -163,9 +89,10 @@ private slots:
#ifdef HAVE_HWSTUB
void OnDevListChanged();
void OnDevChanged(int index);
+ void ClearDevList();
#endif
void SetReadOnlyIndicator();
- void OnSocChanged(const QString& text);
+ void OnSocChanged(int index);
void OnSocListChanged();
void OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void OnRegItemClicked(QTreeWidgetItem *clicked, int col);
diff --git a/utils/regtools/qeditor/std_analysers.cpp b/utils/regtools/qeditor/std_analysers.cpp
index 2cc84cb488..5847e39f7d 100644
--- a/utils/regtools/qeditor/std_analysers.cpp
+++ b/utils/regtools/qeditor/std_analysers.cpp
@@ -23,6 +23,7 @@ ClockAnalyser::ClockAnalyser(const SocRef& soc, IoBackend *backend)
ClockAnalyser::~ClockAnalyser()
{
+ delete m_group;
}
QWidget *ClockAnalyser::GetWidget()
@@ -287,9 +288,9 @@ void ClockAnalyser::FillTree()
else
AddClock(ref_xtal, "clk_rtc32k", INVALID);
- (void) clk_x;
- (void) clk_gpmi;
- (void) clk_h;
+ Q_UNUSED(clk_x);
+ Q_UNUSED(clk_gpmi);
+ Q_UNUSED(clk_h);
m_tree_widget->expandAll();
m_tree_widget->resizeColumnToContents(0);
@@ -334,6 +335,7 @@ EmiAnalyser::EmiAnalyser(const SocRef& soc, IoBackend *backend)
EmiAnalyser::~EmiAnalyser()
{
+ delete m_group;
}
QWidget *EmiAnalyser::GetWidget()
@@ -671,6 +673,7 @@ PinAnalyser::PinAnalyser(const SocRef& soc, IoBackend *backend)
PinAnalyser::~PinAnalyser()
{
+ delete m_group;
}
QWidget *PinAnalyser::GetWidget()
diff --git a/utils/regtools/qeditor/std_analysers.h b/utils/regtools/qeditor/std_analysers.h
index aae8e40207..cca8b12b99 100644
--- a/utils/regtools/qeditor/std_analysers.h
+++ b/utils/regtools/qeditor/std_analysers.h
@@ -21,7 +21,6 @@
class ClockAnalyser : public Analyser
{
- Q_OBJECT
public:
ClockAnalyser(const SocRef& soc, IoBackend *backend);
virtual ~ClockAnalyser();
@@ -50,7 +49,7 @@ private:
/**
* EMI analyser
*/
-class EmiAnalyser : public Analyser
+class EmiAnalyser : public QObject, public Analyser
{
Q_OBJECT
public:
@@ -96,7 +95,6 @@ private:
*/
class PinAnalyser : public Analyser
{
- Q_OBJECT
public:
PinAnalyser(const SocRef& soc, IoBackend *backend);
virtual ~PinAnalyser();
diff --git a/utils/regtools/tester.cpp b/utils/regtools/tester.cpp
index 1fa21c6894..1beba5fe9b 100644
--- a/utils/regtools/tester.cpp
+++ b/utils/regtools/tester.cpp
@@ -21,77 +21,343 @@
#include "soc_desc.hpp"
#include <stdio.h>
#include <stdlib.h>
+#include <map>
+#include <cstring>
-void print_value_desc(const soc_reg_field_value_t& value)
+template< typename T >
+bool build_map(const char *type, const std::vector< T >& vec,
+ std::map< std::string, size_t >& map)
{
- printf(" VALUE %s (%#x)\n", value.name.c_str(), value.value);
+ for(size_t i = 0; i < vec.size(); i++)
+ {
+ if(map.find(vec[i].name) != map.end())
+ {
+ printf("soc has duplicate %s '%s'\n", type, vec[i].name.c_str());
+ return false;
+ }
+ map[vec[i].name] = i;
+ }
+ return true;
}
-void print_field_desc(const soc_reg_field_t& field)
+template< typename T >
+bool build_map(const char *type, const std::vector< T >& a, const std::vector< T >& b,
+ std::vector< std::pair< size_t, size_t > >& m)
{
- printf(" FIELD %s (%d:%d)\n", field.name.c_str(), field.last_bit,
- field.first_bit);
- for(size_t i = 0; i < field.value.size(); i++)
- print_value_desc(field.value[i]);
+ std::map< std::string, size_t > ma, mb;
+ if(!build_map(type, a, ma) || !build_map(type, b, mb))
+ return false;
+ std::map< std::string, size_t >::iterator it;
+ for(it = ma.begin(); it != ma.end(); ++it)
+ {
+ if(mb.find(it->first) == mb.end())
+ {
+ printf("%s '%s' exists in only one file\n", type, it->first.c_str());
+ return false;
+ }
+ m.push_back(std::make_pair(it->second, mb[it->first]));
+ }
+ for(it = mb.begin(); it != mb.end(); ++it)
+ {
+ if(ma.find(it->first) == ma.end())
+ {
+ printf("%s '%s' exists in only one file\n", type, it->first.c_str());
+ return false;
+ }
+ }
+ return true;
}
-std::string compute_sct(soc_reg_flags_t f)
+bool compare_value(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& reg,
+ const soc_reg_field_t& field, const soc_reg_field_value_t& a, const soc_reg_field_value_t& b)
{
- if(f & REG_HAS_SCT) return "SCT";
- else return "";
+ if(a.value != b.value)
+ {
+ printf("register field value '%s.%s.%s.%s.%s' have different values\n", soc.name.c_str(),
+ dev.name.c_str(), reg.name.c_str(), field.name.c_str(), a.name.c_str());
+ return false;
+ }
+ if(a.desc != b.desc)
+ {
+ printf("register field value '%s.%s.%s.%s.%s' have different descriptions\n", soc.name.c_str(),
+ dev.name.c_str(), reg.name.c_str(), field.name.c_str(), a.name.c_str());
+ return false;
+ }
+ return true;
}
-void print_reg_addr_desc(const soc_reg_addr_t& reg)
+bool compare_field(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& reg,
+ const soc_reg_field_t& a, const soc_reg_field_t& b)
{
- printf(" ADDR %s %#x\n", reg.name.c_str(), reg.addr);
+ if(a.first_bit != b.first_bit || a.last_bit != b.last_bit)
+ {
+ printf("register address '%s.%s.%s.%s' have different bit ranges\n", soc.name.c_str(),
+ dev.name.c_str(), reg.name.c_str(), a.name.c_str());
+ return false;
+ }
+ if(a.desc != b.desc)
+ {
+ printf("register address '%s.%s.%s.%s' have different descriptions\n", soc.name.c_str(),
+ dev.name.c_str(), reg.name.c_str(), a.name.c_str());
+ return false;
+ }
+ /* values */
+ std::vector< std::pair< size_t, size_t > > map;
+ if(!build_map("field value", a.value, b.value, map))
+ return false;
+ for(size_t i = 0; i < map.size(); i++)
+ if(!compare_value(soc, dev, reg, a, a.value[map[i].first], b.value[map[i].second]))
+ return false;
+ return true;
}
-void print_reg_desc(const soc_reg_t& reg)
+bool compare_reg_addr(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& reg,
+ const soc_reg_addr_t& a, const soc_reg_addr_t& b)
{
- std::string sct = compute_sct(reg.flags);
- printf(" REG %s %s\n", reg.name.c_str(), sct.c_str());
- for(size_t i = 0; i < reg.addr.size(); i++)
- print_reg_addr_desc(reg.addr[i]);
- for(size_t i = 0; i < reg.field.size(); i++)
- print_field_desc(reg.field[i]);
+ if(a.addr != b.addr)
+ {
+ printf("register address '%s.%s.%s.%s' have different values\n", soc.name.c_str(),
+ dev.name.c_str(), reg.name.c_str(), a.name.c_str());
+ return false;
+ }
+ else
+ return true;
}
-void print_dev_addr_desc(const soc_dev_addr_t& dev)
+bool compare_reg(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& a,
+ const soc_reg_t& b)
{
- printf(" ADDR %s %#x\n", dev.name.c_str(), dev.addr);
+ if(a.desc != b.desc)
+ {
+ printf("register '%s.%s.%s' have different descriptions\n", soc.name.c_str(),
+ dev.name.c_str(), a.name.c_str());
+ return false;
+ }
+ if(a.flags != b.flags)
+ {
+ printf("device '%s.%s.%s' have different flags\n", soc.name.c_str(),
+ dev.name.c_str(), a.name.c_str());
+ return false;
+ }
+ if(a.formula.type != b.formula.type)
+ {
+ printf("device '%s.%s.%s' have different formula types\n", soc.name.c_str(),
+ dev.name.c_str(), a.name.c_str());
+ return false;
+ }
+ if(a.formula.string != b.formula.string)
+ {
+ printf("device '%s.%s.%s' have different formula string\n", soc.name.c_str(),
+ dev.name.c_str(), a.name.c_str());
+ return false;
+ }
+ /* addresses */
+ std::vector< std::pair< size_t, size_t > > map;
+ if(!build_map("register address", a.addr, b.addr, map))
+ return false;
+ for(size_t i = 0; i < map.size(); i++)
+ if(!compare_reg_addr(soc, dev, a, a.addr[map[i].first], b.addr[map[i].second]))
+ return false;
+ /* field */
+ map.clear();
+ if(!build_map("field", a.field, b.field, map))
+ return false;
+ for(size_t i = 0; i < map.size(); i++)
+ if(!compare_field(soc, dev, a, a.field[map[i].first], b.field[map[i].second]))
+ return false;
+ return true;
}
-void print_dev_desc(const soc_dev_t& dev)
+bool compare_dev_addr(const soc_t& soc, const soc_dev_t& dev, const soc_dev_addr_t& a,
+ const soc_dev_addr_t& b)
{
- printf(" DEV %s\n", dev.name.c_str());
- for(size_t i = 0; i < dev.addr.size(); i++)
- print_dev_addr_desc(dev.addr[i]);
- for(size_t i = 0; i < dev.reg.size(); i++)
- print_reg_desc(dev.reg[i]);
+ if(a.addr != b.addr)
+ {
+ printf("device address '%s.%s.%s' have different values\n", soc.name.c_str(),
+ dev.name.c_str(), a.name.c_str());
+ return false;
+ }
+ else
+ return true;
}
-void print_soc_desc(const soc_t& soc)
+bool compare_dev(const soc_t& soc, const soc_dev_t& a, const soc_dev_t& b)
{
- printf("SOC %s (%s)\n", soc.name.c_str(), soc.desc.c_str());
- for(size_t i = 0; i < soc.dev.size(); i++)
- print_dev_desc(soc.dev[i]);
+ if(a.long_name != b.long_name)
+ {
+ printf("device '%s.%s' have different long names\n", soc.name.c_str(),
+ a.name.c_str());
+ return false;
+ }
+ if(a.desc != b.desc)
+ {
+ printf("device '%s.%s' have different descriptions\n", soc.name.c_str(),
+ a.name.c_str());
+ return false;
+ }
+ if(a.version != b.version)
+ {
+ printf("device '%s.%s' have different versions\n", soc.name.c_str(),
+ a.name.c_str());
+ return false;
+ }
+ /* addresses */
+ std::vector< std::pair< size_t, size_t > > map;
+ if(!build_map("device address", a.addr, b.addr, map))
+ return false;
+ for(size_t i = 0; i < map.size(); i++)
+ if(!compare_dev_addr(soc, a, a.addr[map[i].first], b.addr[map[i].second]))
+ return false;
+ /* reg */
+ map.clear();
+ if(!build_map("register", a.reg, b.reg, map))
+ return false;
+ for(size_t i = 0; i < map.size(); i++)
+ if(!compare_reg(soc, a, a.reg[map[i].first], b.reg[map[i].second]))
+ return false;
+ return true;
+}
+
+bool compare_soc(const soc_t& a, const soc_t& b)
+{
+ if(a.name != b.name)
+ {
+ return printf("soc have different names\n");
+ return false;
+ }
+ if(a.desc != b.desc)
+ {
+ printf("soc '%s' have different descriptions\n", a.name.c_str());
+ return false;
+ }
+ std::vector< std::pair< size_t, size_t > > map;
+ if(!build_map("device", a.dev, b.dev, map))
+ return false;
+ for(size_t i = 0; i< map.size(); i++)
+ if(!compare_dev(a, a.dev[map[i].first], b.dev[map[i].second]))
+ return false;
+ return true;
+}
+
+int do_compare(int argc, char **argv)
+{
+ if(argc != 2)
+ return printf("compare mode expects two arguments\n");
+ soc_t soc[2];
+ if(!soc_desc_parse_xml(argv[0], soc[0]))
+ return printf("cannot read file '%s'\n", argv[0]);
+ if(!soc_desc_parse_xml(argv[1], soc[1]))
+ return printf("cannot read file '%s'\n", argv[1]);
+ if(compare_soc(soc[0], soc[1]))
+ printf("Files are identical.\n");
+ return 0;
+}
+
+int do_write(int argc, char **argv)
+{
+ if(argc != 2)
+ return printf("write mode expects two arguments\n");
+ soc_t soc;
+ if(!soc_desc_parse_xml(argv[0], soc))
+ return printf("cannot read file '%s'\n", argv[0]);
+ if(!soc_desc_produce_xml(argv[1], soc))
+ return printf("cannot write file '%s'\n", argv[1]);
+ return 0;
+}
+
+int do_check(int argc, char **argv)
+{
+ for(int i = 0; i < argc; i++)
+ {
+ soc_t soc;
+ if(!soc_desc_parse_xml(argv[i], soc))
+ {
+ printf("cannot read file '%s'\n", argv[i]);
+ continue;
+ }
+ printf("[%s]\n", argv[i]);
+ std::vector< soc_error_t > errs = soc.errors(true);
+ for(size_t i = 0; i < errs.size(); i++)
+ {
+ const soc_error_t& e = errs[i];
+ switch(e.level)
+ {
+ case SOC_ERROR_WARNING: printf("[WARN ] "); break;
+ case SOC_ERROR_FATAL: printf("[FATAL] "); break;
+ default: printf("[ UNK ] "); break;
+ }
+ printf("%s: %s\n", e.location.c_str(), e.message.c_str());
+ }
+ }
+ return 0;
+}
+
+int do_eval(int argc, char **argv)
+{
+ std::map< std::string, soc_word_t > map;
+ for(int i = 0; i < argc; i++)
+ {
+ std::string error;
+ std::string formula(argv[i]);
+ soc_word_t result;
+ if(strcmp(argv[i], "--var") == 0)
+ {
+ if(i + 1 >= argc)
+ break;
+ i++;
+ std::string str(argv[i]);
+ size_t pos = str.find('=');
+ if(pos == std::string::npos)
+ {
+ printf("invalid variable string '%s'\n", str.c_str());
+ continue;
+ }
+ std::string name = str.substr(0, pos);
+ std::string val = str.substr(pos + 1);
+ char *end;
+ soc_word_t v = strtoul(val.c_str(), &end, 0);
+ if(*end)
+ {
+ printf("invalid variable string '%s'\n", str.c_str());
+ continue;
+ }
+ printf("%s = %#lx\n", name.c_str(), (unsigned long)v);
+ map[name] = v;
+ continue;
+ }
+ if(!soc_desc_evaluate_formula(formula, map, result, error))
+ printf("error: %s\n", error.c_str());
+ else
+ printf("result: %lu (%#lx)\n", (unsigned long)result, (unsigned long)result);
+ }
+ return 0;
}
void usage()
{
- printf("usage: tester <desc file>\n");
+ printf("usage: tester <mode> [options]\n");
+ printf("modes:\n");
+ printf(" compare <desc file> <desc file>\n");
+ printf(" write <read file> <write file>\n");
+ printf(" check <files...>\n");
+ printf(" eval [<formula>|--var <name>=<val>]...\n");
exit(1);
}
int main(int argc, char **argv)
{
- if(argc != 2)
+ if(argc < 2)
+ usage();
+ std::string mode = argv[1];
+ if(mode == "compare")
+ return do_compare(argc - 2, argv + 2);
+ else if(mode == "write")
+ return do_write(argc - 2, argv + 2);
+ else if(mode == "check")
+ return do_check(argc - 2, argv + 2);
+ else if(mode == "eval")
+ return do_eval(argc - 2, argv + 2);
+ else
usage();
- std::vector< soc_t > socs;
- bool ret = soc_desc_parse_xml(argv[1], socs);
- printf("parse result: %d\n", ret);
- if(ret)
- for(size_t i = 0; i < socs.size(); i++)
- print_soc_desc(socs[i]);
return 0;
} \ No newline at end of file