summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2014-04-07 11:28:04 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2014-05-01 19:34:18 +0200
commit4356666101e0e7985e65a19f86bc4a74519e93f9 (patch)
treebf8de8057d93d0fab0a30cae92a90f5a4edc79dc
parent3754624edc48539c5cc5acbf426ce909477e87d8 (diff)
downloadrockbox-4356666101e0e7985e65a19f86bc4a74519e93f9.tar.gz
rockbox-4356666101e0e7985e65a19f86bc4a74519e93f9.zip
regtools: completely rework qeditor, improve soc desc library and tools
The graphical editor can now display and editor description files. The library has been improved to provide more useful function. The XML format has been slightly changed: only one soc is allowed per file (this is was already de facto the case since <soc> was the root tag). Also introduce a DTD to validate the files. Change-Id: If70ba35b6dc0242bdb87411cf4baee9597798aac
-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