mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 18:17:39 -04:00
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
This commit is contained in:
parent
3754624edc
commit
4356666101
22 changed files with 4390 additions and 614 deletions
|
@ -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
|
||||
|
|
28
utils/regtools/desc/regs-1.0.dtd
Normal file
28
utils/regtools/desc/regs-1.0.dtd
Normal file
|
@ -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>
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
|
@ -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:
|
||||
|
|
746
utils/regtools/qeditor/aux.cpp
Normal file
746
utils/regtools/qeditor/aux.cpp
Normal file
|
@ -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();
|
||||
}
|
227
utils/regtools/qeditor/aux.h
Normal file
227
utils/regtools/qeditor/aux.h
Normal file
|
@ -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 */
|
|
@ -4,6 +4,36 @@
|
|||
#include <QFileInfo>
|
||||
#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)
|
||||
{
|
||||
|
|
|
@ -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:
|
||||
SocRef():m_soc(0) {}
|
||||
SocRef(const soc_t *soc):m_soc(soc) {}
|
||||
const soc_t& GetSoc() const { return *m_soc; }
|
||||
SocFile();
|
||||
SocFile(const QString& filename);
|
||||
bool IsValid();
|
||||
|
||||
SocRef GetSocRef();
|
||||
QString GetFilename();
|
||||
soc_t& GetSoc() { return m_soc; }
|
||||
|
||||
protected:
|
||||
const soc_t *m_soc;
|
||||
bool m_valid;
|
||||
QString m_filename;
|
||||
soc_t m_soc;
|
||||
};
|
||||
|
||||
class SocFileRef
|
||||
{
|
||||
public:
|
||||
SocFileRef():m_socfile(0) {}
|
||||
SocFileRef(SocFile *file):m_socfile(file) {}
|
||||
SocFile *GetSocFile() const { return m_socfile; }
|
||||
|
||||
protected:
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
314
utils/regtools/qeditor/regdisplaypanel.cpp
Normal file
314
utils/regtools/qeditor/regdisplaypanel.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
|
77
utils/regtools/qeditor/regdisplaypanel.h
Normal file
77
utils/regtools/qeditor/regdisplaypanel.h
Normal file
|
@ -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 */
|
1324
utils/regtools/qeditor/regedit.cpp
Normal file
1324
utils/regtools/qeditor/regedit.cpp
Normal file
File diff suppressed because it is too large
Load diff
282
utils/regtools/qeditor/regedit.h
Normal file
282
utils/regtools/qeditor/regedit.h
Normal file
|
@ -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 */
|
|
@ -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)
|
||||
namespace
|
||||
{
|
||||
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)
|
||||
enum
|
||||
{
|
||||
}
|
||||
RegTreeDevType = QTreeWidgetItem::UserType,
|
||||
RegTreeRegType
|
||||
};
|
||||
|
||||
void SocFieldValidator::fixup(QString& input) const
|
||||
class DevTreeItem : public QTreeWidgetItem
|
||||
{
|
||||
input = input.trimmed();
|
||||
}
|
||||
public:
|
||||
DevTreeItem(const QString& string, const SocDevRef& ref)
|
||||
:QTreeWidgetItem(QStringList(string), RegTreeDevType), m_ref(ref) {}
|
||||
|
||||
QValidator::State SocFieldValidator::validate(QString& input, int& pos) const
|
||||
const SocDevRef& GetRef() { return m_ref; }
|
||||
private:
|
||||
SocDevRef m_ref;
|
||||
};
|
||||
|
||||
class RegTreeItem : public QTreeWidgetItem
|
||||
{
|
||||
(void) pos;
|
||||
soc_word_t val;
|
||||
State state = parse(input, val);
|
||||
return state;
|
||||
}
|
||||
public:
|
||||
RegTreeItem(const QString& string, const SocRegRef& ref)
|
||||
:QTreeWidgetItem(QStringList(string), RegTreeRegType), m_ref(ref) {}
|
||||
|
||||
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;
|
||||
}
|
||||
const SocRegRef& GetRef() { return m_ref; }
|
||||
private:
|
||||
SocRegRef m_ref;
|
||||
};
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* RegLineEdit
|
||||
* EmptyRegTabPanel
|
||||
*/
|
||||
RegLineEdit::RegLineEdit(QWidget *parent)
|
||||
EmptyRegTabPanel::EmptyRegTabPanel(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);
|
||||
QVBoxLayout *l = new QVBoxLayout;
|
||||
l->addStretch();
|
||||
setLayout(l);
|
||||
}
|
||||
|
||||
void RegLineEdit::SetReadOnly(bool ro)
|
||||
void EmptyRegTabPanel::AllowWrite(bool en)
|
||||
{
|
||||
m_edit->setReadOnly(ro);
|
||||
m_readonly = ro;
|
||||
ShowMode(!ro);
|
||||
Q_UNUSED(en);
|
||||
}
|
||||
|
||||
void RegLineEdit::EnableSCT(bool en)
|
||||
QWidget *EmptyRegTabPanel::GetWidget()
|
||||
{
|
||||
m_has_sct = en;
|
||||
if(!m_has_sct)
|
||||
{
|
||||
m_button->setMenu(0);
|
||||
SetMode(Write);
|
||||
}
|
||||
else
|
||||
m_button->setMenu(m_menu);
|
||||
return this;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* RegDisplayPanel
|
||||
*/
|
||||
|
||||
RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const SocRegRef& reg_ref)
|
||||
:QGroupBox(parent), m_io_backend(io_backend), m_reg(reg_ref)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
class RegTabPanel
|
||||
{
|
||||
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;
|
||||
RegTabPanel() {}
|
||||
virtual ~RegTabPanel() {}
|
||||
virtual void AllowWrite(bool en) = 0;
|
||||
virtual QWidget *GetWidget() = 0;
|
||||
};
|
||||
|
||||
class RegTreeItem : public QTreeWidgetItem
|
||||
class EmptyRegTabPanel : public QWidget, public 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;
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue