summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2014-04-07 11:28:04 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2014-05-01 19:34:18 +0200
commit4356666101e0e7985e65a19f86bc4a74519e93f9 (patch)
treebf8de8057d93d0fab0a30cae92a90f5a4edc79dc /utils
parent3754624edc48539c5cc5acbf426ce909477e87d8 (diff)
downloadrockbox-4356666101e0e7985e65a19f86bc4a74519e93f9.tar.gz
rockbox-4356666101e0e7985e65a19f86bc4a74519e93f9.zip
regtools: completely rework qeditor, improve soc desc library and tools
The graphical editor can now display and editor description files. The library has been improved to provide more useful function. The XML format has been slightly changed: only one soc is allowed per file (this is was already de facto the case since <soc> was the root tag). Also introduce a DTD to validate the files. Change-Id: If70ba35b6dc0242bdb87411cf4baee9597798aac
Diffstat (limited to 'utils')
-rw-r--r--utils/regtools/desc/XML.txt5
-rw-r--r--utils/regtools/desc/regs-1.0.dtd28
-rw-r--r--utils/regtools/headergen.cpp6
-rw-r--r--utils/regtools/lib/soc_desc.cpp700
-rw-r--r--utils/regtools/lib/soc_desc.hpp49
-rw-r--r--utils/regtools/qeditor/analyser.h5
-rw-r--r--utils/regtools/qeditor/aux.cpp746
-rw-r--r--utils/regtools/qeditor/aux.h227
-rw-r--r--utils/regtools/qeditor/backend.cpp67
-rw-r--r--utils/regtools/qeditor/backend.h79
-rw-r--r--utils/regtools/qeditor/mainwindow.cpp63
-rw-r--r--utils/regtools/qeditor/mainwindow.h16
-rw-r--r--utils/regtools/qeditor/qeditor.pro6
-rw-r--r--utils/regtools/qeditor/regdisplaypanel.cpp314
-rw-r--r--utils/regtools/qeditor/regdisplaypanel.h77
-rw-r--r--utils/regtools/qeditor/regedit.cpp1324
-rw-r--r--utils/regtools/qeditor/regedit.h282
-rw-r--r--utils/regtools/qeditor/regtab.cpp534
-rw-r--r--utils/regtools/qeditor/regtab.h119
-rw-r--r--utils/regtools/qeditor/std_analysers.cpp9
-rw-r--r--utils/regtools/qeditor/std_analysers.h4
-rw-r--r--utils/regtools/tester.cpp344
22 files changed, 4390 insertions, 614 deletions
diff --git a/utils/regtools/desc/XML.txt b/utils/regtools/desc/XML.txt
index a90f875f66..3c28154a1f 100644
--- a/utils/regtools/desc/XML.txt
+++ b/utils/regtools/desc/XML.txt
@@ -9,6 +9,11 @@ Example:
9<!-- desc --> 9<!-- desc -->
10</xml> 10</xml>
11 11
12Root Element: root
13------------------
14The root element can either be "soc" tag if the file contains a single description,
15or "root" with no properties and one or more "soc" tags as children.
16
12Element: soc 17Element: soc
13------------ 18------------
14The XML can contain one or more SoC description. Each description is enclosed in 19The XML can contain one or more SoC description. Each description is enclosed in
diff --git a/utils/regtools/desc/regs-1.0.dtd b/utils/regtools/desc/regs-1.0.dtd
new file mode 100644
index 0000000000..3204d29195
--- /dev/null
+++ b/utils/regtools/desc/regs-1.0.dtd
@@ -0,0 +1,28 @@
1<!-- Format specification of the 1.0 register description files. Files are
2 considered to be version 1.0 if no version field is specified -->
3<!ELEMENT soc (dev)*>
4<!ATTLIST soc name CDATA #REQUIRED>
5<!ATTLIST soc desc CDATA #IMPLIED>
6<!ELEMENT dev (addr|reg)*>
7<!ATTLIST dev name CDATA #REQUIRED>
8<!ATTLIST dev long_name CDATA #IMPLIED>
9<!ATTLIST dev desc CDATA #IMPLIED>
10<!ATTLIST dev version CDATA #IMPLIED>
11<!ELEMENT addr EMPTY>
12<!ATTLIST addr name CDATA #REQUIRED>
13<!ATTLIST addr addr CDATA #REQUIRED>
14<!ELEMENT reg (addr|field|formula)*>
15<!ATTLIST reg name CDATA #REQUIRED>
16<!ATTLIST reg addr CDATA #IMPLIED>
17<!ATTLIST reg desc CDATA #IMPLIED>
18<!ATTLIST reg sct (yes|no) "no">
19<!ELEMENT formula EMPTY>
20<!ATTLIST formula string CDATA #IMPLIED>
21<!ELEMENT field (value)*>
22<!ATTLIST field name CDATA #REQUIRED>
23<!ATTLIST field desc CDATA #IMPLIED>
24<!ATTLIST field bitrange CDATA #REQUIRED>
25<!ELEMENT value EMPTY>
26<!ATTLIST value name CDATA #REQUIRED>
27<!ATTLIST value value CDATA #REQUIRED>
28<!ATTLIST value desc CDATA #IMPLIED>
diff --git a/utils/regtools/headergen.cpp b/utils/regtools/headergen.cpp
index a95dc46215..b4ade5f186 100644
--- a/utils/regtools/headergen.cpp
+++ b/utils/regtools/headergen.cpp
@@ -574,11 +574,15 @@ int main(int argc, char **argv)
574 574
575 std::vector< soc_t > socs; 575 std::vector< soc_t > socs;
576 for(int i = optind; i < argc - 1; i++) 576 for(int i = optind; i < argc - 1; i++)
577 if(!soc_desc_parse_xml(argv[i], socs)) 577 {
578 soc_t s;
579 if(!soc_desc_parse_xml(argv[i], s))
578 { 580 {
579 printf("Cannot parse %s\n", argv[i]); 581 printf("Cannot parse %s\n", argv[i]);
580 return 1; 582 return 1;
581 } 583 }
584 socs.push_back(s);
585 }
582 586
583 g_gen_selector = force_selector || socs.size() > 1; 587 g_gen_selector = force_selector || socs.size() > 1;
584 588
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp
index 6a6d47648f..1c9eaf7972 100644
--- a/utils/regtools/lib/soc_desc.cpp
+++ b/utils/regtools/lib/soc_desc.cpp
@@ -21,8 +21,12 @@
21#include "soc_desc.hpp" 21#include "soc_desc.hpp"
22#include <libxml/parser.h> 22#include <libxml/parser.h>
23#include <libxml/tree.h> 23#include <libxml/tree.h>
24#include <libxml/xmlsave.h>
25#include <libxml/xmlwriter.h>
24#include <stdio.h> 26#include <stdio.h>
25#include <string.h> 27#include <string.h>
28#include <algorithm>
29#include <cctype>
26 30
27#define XML_CHAR_TO_CHAR(s) ((const char *)(s)) 31#define XML_CHAR_TO_CHAR(s) ((const char *)(s))
28 32
@@ -78,6 +82,9 @@
78#define END_NODE_MATCH() \ 82#define END_NODE_MATCH() \
79 } 83 }
80 84
85namespace
86{
87
81bool validate_string_hook(const std::string& str, std::string& s) 88bool validate_string_hook(const std::string& str, std::string& s)
82{ 89{
83 s = str; 90 s = str;
@@ -137,6 +144,7 @@ bool parse_value_elem(xmlNode *node, soc_reg_field_value_t& value)
137 BEGIN_ATTR_MATCH(node->properties) 144 BEGIN_ATTR_MATCH(node->properties)
138 MATCH_TEXT_ATTR("name", value.name) 145 MATCH_TEXT_ATTR("name", value.name)
139 MATCH_UINT32_ATTR("value", value.value) 146 MATCH_UINT32_ATTR("value", value.value)
147 MATCH_TEXT_ATTR("desc", value.desc)
140 END_ATTR_MATCH() 148 END_ATTR_MATCH()
141 149
142 return true; 150 return true;
@@ -256,28 +264,706 @@ bool parse_soc_elem(xmlNode *node, soc_t& soc)
256 return true; 264 return true;
257} 265}
258 266
259bool parse_root_elem(xmlNode *node, std::vector< soc_t >& soc) 267bool parse_root_elem(xmlNode *node, soc_t& soc)
260{ 268{
269 std::vector< soc_t > socs;
261 BEGIN_NODE_MATCH(node) 270 BEGIN_NODE_MATCH(node)
262 MATCH_ELEM_NODE("soc", soc, parse_soc_elem) 271 MATCH_ELEM_NODE("soc", socs, parse_soc_elem)
263 END_NODE_MATCH() 272 END_NODE_MATCH()
273 if(socs.size() != 1)
274 {
275 fprintf(stderr, "A description file must contain exactly one soc element\n");
276 return false;
277 }
278 soc = socs[0];
264 return true; 279 return true;
265} 280}
266 281
267bool soc_desc_parse_xml(const std::string& filename, std::vector< soc_t >& socs) 282}
283
284bool soc_desc_parse_xml(const std::string& filename, soc_t& socs)
268{ 285{
269 LIBXML_TEST_VERSION 286 LIBXML_TEST_VERSION
270 287
271 xmlDoc *doc = xmlReadFile(filename.c_str(), NULL, 0); 288 xmlDocPtr doc = xmlReadFile(filename.c_str(), NULL, 0);
272 if(doc == NULL) 289 if(doc == NULL)
273 return false; 290 return false;
274 291
275 xmlNode *root_element = xmlDocGetRootElement(doc); 292 xmlNodePtr root_element = xmlDocGetRootElement(doc);
276
277 bool ret = parse_root_elem(root_element, socs); 293 bool ret = parse_root_elem(root_element, socs);
278 294
279 xmlFreeDoc(doc); 295 xmlFreeDoc(doc);
280 xmlCleanupParser(); 296 xmlCleanupParser();
281 297
282 return ret; 298 return ret;
283} \ No newline at end of file 299}
300
301namespace
302{
303
304int produce_field(xmlTextWriterPtr writer, const soc_reg_field_t& field)
305{
306#define SAFE(x) if((x) < 0) return -1;
307 /* <field> */
308 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "field"));
309 /* name */
310 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.name.c_str()));
311 /* desc */
312 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.desc.c_str()));
313 /* bitrange */
314 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "bitrange", "%d:%d",
315 field.last_bit, field.first_bit));
316 /* values */
317 for(size_t i = 0; i < field.value.size(); i++)
318 {
319 /* <value> */
320 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "value"));
321 /* name */
322 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.value[i].name.c_str()));
323 /* value */
324 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "value", "0x%x", field.value[i].value));
325 /* name */
326 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.value[i].desc.c_str()));
327 /* </value> */
328 SAFE(xmlTextWriterEndElement(writer));
329 }
330 /* </field> */
331 SAFE(xmlTextWriterEndElement(writer));
332#undef SAFE
333 return 0;
334}
335
336int produce_reg(xmlTextWriterPtr writer, const soc_reg_t& reg)
337{
338#define SAFE(x) if((x) < 0) return -1;
339 /* <reg> */
340 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "reg"));
341 /* name */
342 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.name.c_str()));
343 /* name */
344 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str()));
345 /* flags */
346 if(reg.flags & REG_HAS_SCT)
347 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "sct", BAD_CAST "yes"));
348 /* formula */
349 if(reg.formula.type != REG_FORMULA_NONE)
350 {
351 /* <formula> */
352 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula"));
353 switch(reg.formula.type)
354 {
355 case REG_FORMULA_STRING:
356 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "string",
357 BAD_CAST reg.formula.string.c_str()));
358 break;
359 default:
360 break;
361 }
362 /* </formula> */
363 SAFE(xmlTextWriterEndElement(writer));
364 }
365 /* addresses */
366 for(size_t i = 0; i < reg.addr.size(); i++)
367 {
368 /* <addr> */
369 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr"));
370 /* name */
371 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.addr[i].name.c_str()));
372 /* addr */
373 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", reg.addr[i].addr));
374 /* </addr> */
375 SAFE(xmlTextWriterEndElement(writer));
376 }
377 /* fields */
378 for(size_t i = 0; i < reg.field.size(); i++)
379 produce_field(writer, reg.field[i]);
380 /* </reg> */
381 SAFE(xmlTextWriterEndElement(writer));
382#undef SAFE
383 return 0;
384}
385
386int produce_dev(xmlTextWriterPtr writer, const soc_dev_t& dev)
387{
388#define SAFE(x) if((x) < 0) return -1;
389 /* <dev> */
390 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "dev"));
391 /* name */
392 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.name.c_str()));
393 /* long_name */
394 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "long_name", BAD_CAST dev.long_name.c_str()));
395 /* desc */
396 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST dev.desc.c_str()));
397 /* version */
398 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST dev.version.c_str()));
399 /* addresses */
400 for(size_t i = 0; i < dev.addr.size(); i++)
401 {
402 /* <addr> */
403 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr"));
404 /* name */
405 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.addr[i].name.c_str()));
406 /* addr */
407 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", dev.addr[i].addr));
408 /* </addr> */
409 SAFE(xmlTextWriterEndElement(writer));
410 }
411 /* registers */
412 for(size_t i = 0; i < dev.reg.size(); i++)
413 produce_reg(writer, dev.reg[i]);
414 /* </dev> */
415 SAFE(xmlTextWriterEndElement(writer));
416#undef SAFE
417 return 0;
418}
419
420}
421
422bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc)
423{
424 LIBXML_TEST_VERSION
425
426 xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.c_str(), 0);
427 if(writer == NULL)
428 return false;
429#define SAFE(x) if((x) < 0) goto Lerr
430 SAFE(xmlTextWriterSetIndent(writer, 1));
431 SAFE(xmlTextWriterSetIndentString(writer, BAD_CAST " "));
432 /* <xml> */
433 SAFE(xmlTextWriterStartDocument(writer, NULL, NULL, NULL));
434 /* <soc> */
435 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "soc"));
436 /* name */
437 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST soc.name.c_str()));
438 /* desc */
439 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST soc.desc.c_str()));
440 /* devices */
441 for(size_t i = 0; i < soc.dev.size(); i++)
442 SAFE(produce_dev(writer, soc.dev[i]));
443 /* end <soc> */
444 SAFE(xmlTextWriterEndElement(writer));
445 /* </xml> */
446 SAFE(xmlTextWriterEndDocument(writer));
447 xmlFreeTextWriter(writer);
448 return true;
449#undef SAFE
450Lerr:
451 xmlFreeTextWriter(writer);
452 return false;
453}
454
455namespace
456{
457
458struct soc_sorter
459{
460 bool operator()(const soc_dev_t& a, const soc_dev_t& b) const
461 {
462 return a.name < b.name;
463 }
464
465 bool operator()(const soc_dev_addr_t& a, const soc_dev_addr_t& b) const
466 {
467 return a.name < b.name;
468 }
469
470 bool operator()(const soc_reg_t& a, const soc_reg_t& b) const
471 {
472 soc_addr_t aa = a.addr.size() > 0 ? a.addr[0].addr : 0;
473 soc_addr_t ab = b.addr.size() > 0 ? b.addr[0].addr : 0;
474 return aa < ab;
475 }
476
477 bool operator()(const soc_reg_addr_t& a, const soc_reg_addr_t& b) const
478 {
479 return a.addr < b.addr;
480 }
481
482 bool operator()(const soc_reg_field_t& a, const soc_reg_field_t& b) const
483 {
484 return a.last_bit > b.last_bit;
485 }
486
487 bool operator()(const soc_reg_field_value_t a, const soc_reg_field_value_t& b) const
488 {
489 return a.value < b.value;
490 }
491};
492
493void normalize(soc_reg_field_t& field)
494{
495 std::sort(field.value.begin(), field.value.end(), soc_sorter());
496}
497
498void normalize(soc_reg_t& reg)
499{
500 std::sort(reg.addr.begin(), reg.addr.end(), soc_sorter());
501 std::sort(reg.field.begin(), reg.field.end(), soc_sorter());
502 for(size_t i = 0; i < reg.field.size(); i++)
503 normalize(reg.field[i]);
504}
505
506void normalize(soc_dev_t& dev)
507{
508 std::sort(dev.addr.begin(), dev.addr.end(), soc_sorter());
509 std::sort(dev.reg.begin(), dev.reg.end(), soc_sorter());
510 for(size_t i = 0; i < dev.reg.size(); i++)
511 normalize(dev.reg[i]);
512}
513
514}
515
516void soc_desc_normalize(soc_t& soc)
517{
518 std::sort(soc.dev.begin(), soc.dev.end(), soc_sorter());
519 for(size_t i = 0; i < soc.dev.size(); i++)
520 normalize(soc.dev[i]);
521}
522
523namespace
524{
525 soc_error_t make_error(soc_error_level_t lvl, std::string at, std::string what)
526 {
527 soc_error_t err;
528 err.level = lvl;
529 err.location = at;
530 err.message = what;
531 return err;
532 }
533
534 soc_error_t make_warning(std::string at, std::string what)
535 {
536 return make_error(SOC_ERROR_WARNING, at, what);
537 }
538
539 soc_error_t make_fatal(std::string at, std::string what)
540 {
541 return make_error(SOC_ERROR_FATAL, at, what);
542 }
543
544 soc_error_t prefix(soc_error_t err, const std::string& prefix_at)
545 {
546 err.location = prefix_at + "." + err.location;
547 return err;
548 }
549
550 void add_errors(std::vector< soc_error_t >& errors,
551 const std::vector< soc_error_t >& new_errors, const std::string& prefix_at)
552 {
553 for(size_t i = 0; i < new_errors.size(); i++)
554 errors.push_back(prefix(new_errors[i], prefix_at));
555 }
556
557 std::vector< soc_error_t > no_error()
558 {
559 std::vector< soc_error_t > s;
560 return s;
561 }
562
563 std::vector< soc_error_t > one_error(const soc_error_t& err)
564 {
565 std::vector< soc_error_t > s;
566 s.push_back(err);
567 return s;
568 }
569
570 bool name_valid(char c)
571 {
572 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
573 (c >= 'A' && c <= 'Z') || c == '_';
574 }
575
576 bool name_valid(const std::string& s)
577 {
578 for(size_t i = 0; i < s.size(); i++)
579 if(!name_valid(s[i]))
580 return false;
581 return true;
582 }
583}
584
585std::vector< soc_error_t > soc_reg_field_value_t::errors(bool recursive)
586{
587 (void) recursive;
588 if(name.size() == 0)
589 return one_error(make_fatal(name, "empty name"));
590 else if(!name_valid(name))
591 return one_error(make_fatal(name, "invalid name"));
592 else
593 return no_error();
594}
595
596std::vector< soc_error_t > soc_reg_field_t::errors(bool recursive)
597{
598 std::vector< soc_error_t > err;
599 std::string at(name);
600 if(name.size() == 0)
601 err.push_back(make_fatal(at, "empty name"));
602 else if(!name_valid(name))
603 err.push_back(make_fatal(at, "invalid name"));
604 if(last_bit > 31)
605 err.push_back(make_fatal(at, "last bit is greater than 31"));
606 if(first_bit > last_bit)
607 err.push_back(make_fatal(at, "last bit is greater than first bit"));
608 for(size_t i = 0; i < value.size(); i++)
609 {
610 for(size_t j = 0; j < value.size(); j++)
611 {
612 if(i == j)
613 continue;
614 if(value[i].name == value[j].name)
615 err.push_back(prefix(make_fatal(value[i].name,
616 "there are several values with the same name"), at));
617 if(value[i].value == value[j].value)
618 err.push_back(prefix(make_warning(value[i].name,
619 "there are several values with the same value"), at));
620 }
621 if(value[i].value > (bitmask() >> first_bit))
622 err.push_back(prefix(make_warning(at, "value doesn't fit into the field"), value[i].name));
623 if(recursive)
624 add_errors(err, value[i].errors(true), at);
625 }
626 return err;
627}
628
629std::vector< soc_error_t > soc_reg_addr_t::errors(bool recursive)
630{
631 (void) recursive;
632 if(name.size() == 0)
633 return one_error(make_fatal("", "empty name"));
634 else if(!name_valid(name))
635 return one_error(make_fatal(name, "invalid name"));
636 else
637 return no_error();
638}
639
640std::vector< soc_error_t > soc_reg_formula_t::errors(bool recursive)
641{
642 (void) recursive;
643 if(type == REG_FORMULA_STRING && string.size() == 0)
644 return one_error(make_fatal("", "empty string formula"));
645 else
646 return no_error();
647}
648
649namespace
650{
651
652bool field_overlap(const soc_reg_field_t& a, const soc_reg_field_t& b)
653{
654 return !(a.first_bit > b.last_bit || b.first_bit > a.last_bit);
655}
656
657}
658
659std::vector< soc_error_t > soc_reg_t::errors(bool recursive)
660{
661 std::vector< soc_error_t > err;
662 std::string at(name);
663 if(name.size() == 0)
664 err.push_back(make_fatal(at, "empty name"));
665 else if(!name_valid(name))
666 err.push_back(make_fatal(at, "invalid name"));
667 for(size_t i = 0; i < addr.size(); i++)
668 {
669 for(size_t j = 0; j < addr.size(); j++)
670 {
671 if(i == j)
672 continue;
673 if(addr[i].name == addr[j].name)
674 err.push_back(prefix(make_fatal(addr[i].name,
675 "there are several instances with the same name"), at));
676 if(addr[i].addr == addr[j].addr)
677 err.push_back(prefix(make_fatal(addr[i].name,
678 "there are several instances with the same address"), at));
679 }
680 if(recursive)
681 add_errors(err, addr[i].errors(true), at);
682 }
683 if(recursive)
684 add_errors(err, formula.errors(true), at);
685 for(size_t i = 0; i < field.size(); i++)
686 {
687 for(size_t j = 0; j < field.size(); j++)
688 {
689 if(i == j)
690 continue;
691 if(field[i].name == field[j].name)
692 err.push_back(prefix(make_fatal(field[i].name,
693 "there are several fields with the same name"), at));
694 if(field_overlap(field[i], field[j]))
695 err.push_back(prefix(make_fatal(field[i].name,
696 "there are overlapping fields"), at));
697 }
698 if(recursive)
699 add_errors(err, field[i].errors(true), at);
700 }
701 return err;
702}
703
704std::vector< soc_error_t > soc_dev_addr_t::errors(bool recursive)
705{
706 (void) recursive;
707 if(name.size() == 0)
708 return one_error(make_fatal("", "empty name"));
709 else if(!name_valid(name))
710 return one_error(make_fatal(name, "invalid name"));
711 else
712 return no_error();
713}
714
715std::vector< soc_error_t > soc_dev_t::errors(bool recursive)
716{
717 std::vector< soc_error_t > err;
718 std::string at(name);
719 if(name.size() == 0)
720 err.push_back(make_fatal(at, "empty name"));
721 else if(!name_valid(name))
722 err.push_back(make_fatal(at, "invalid name"));
723 for(size_t i = 0; i < addr.size(); i++)
724 {
725 for(size_t j = 0; j < addr.size(); j++)
726 {
727 if(i == j)
728 continue;
729 if(addr[i].name == addr[j].name)
730 err.push_back(prefix(make_fatal(addr[i].name,
731 "there are several instances with the same name"), at));
732 if(addr[i].addr == addr[j].addr)
733 err.push_back(prefix(make_fatal(addr[i].name,
734 "there are several instances with the same address"), at));
735 }
736 if(recursive)
737 add_errors(err, addr[i].errors(true), at);
738 }
739 for(size_t i = 0; i < reg.size(); i++)
740 {
741 for(size_t j = 0; j < reg.size(); j++)
742 {
743 if(i == j)
744 continue;
745 if(reg[i].name == reg[j].name)
746 err.push_back(prefix(make_fatal(reg[i].name,
747 "there are several registers with the same name"), at));
748 }
749 if(recursive)
750 add_errors(err, reg[i].errors(true), at);
751 }
752 return err;
753}
754
755std::vector< soc_error_t > soc_t::errors(bool recursive)
756{
757 std::vector< soc_error_t > err;
758 std::string at(name);
759 for(size_t i = 0; i < dev.size(); i++)
760 {
761 for(size_t j = 0; j < dev.size(); j++)
762 {
763 if(i == j)
764 continue;
765 if(dev[i].name == dev[j].name)
766 err.push_back(prefix(make_fatal(dev[i].name,
767 "there are several devices with the same name"), at));
768 }
769 if(recursive)
770 add_errors(err, dev[i].errors(true), at);
771 }
772 return err;
773}
774
775namespace
776{
777
778struct formula_evaluator
779{
780 std::string formula;
781 size_t pos;
782 std::string error;
783
784 bool err(const char *fmt, ...)
785 {
786 char buffer[256];
787 va_list args;
788 va_start(args, fmt);
789 vsnprintf(buffer,sizeof(buffer), fmt, args);
790 va_end(args);
791 error = buffer;
792 return false;
793 }
794
795 formula_evaluator(const std::string& s):pos(0)
796 {
797 for(size_t i = 0; i < s.size(); i++)
798 if(!isspace(s[i]))
799 formula.push_back(s[i]);
800 }
801
802 void adv()
803 {
804 pos++;
805 }
806
807 char cur()
808 {
809 return end() ? 0 : formula[pos];
810 }
811
812 bool end()
813 {
814 return pos >= formula.size();
815 }
816
817 bool parse_digit(char c, int basis, soc_word_t& res)
818 {
819 c = tolower(c);
820 if(isdigit(c))
821 {
822 res = c - '0';
823 return true;
824 }
825 if(basis == 16 && isxdigit(c))
826 {
827 res = c + 10 - 'a';
828 return true;
829 }
830 return err("invalid digit '%c'", c);
831 }
832
833 bool parse_signed(soc_word_t& res)
834 {
835 char op = cur();
836 if(op == '+' || op == '-')
837 {
838 adv();
839 if(!parse_signed(res))
840 return false;
841 if(op == '-')
842 res *= -1;
843 return true;
844 }
845 else if(op == '(')
846 {
847 adv();
848 if(!parse_expression(res))
849 return false;
850 if(cur() != ')')
851 return err("expected ')', got '%c'", cur());
852 adv();
853 return true;
854 }
855 else if(isdigit(op))
856 {
857 res = op - '0';
858 adv();
859 int basis = 10;
860 if(op == '0' && cur() == 'x')
861 {
862 basis = 16;
863 adv();
864 }
865 soc_word_t digit = 0;
866 while(parse_digit(cur(), basis, digit))
867 {
868 res = res * basis + digit;
869 adv();
870 }
871 return true;
872 }
873 else if(isalpha(op) || op == '_')
874 {
875 std::string name;
876 while(isalnum(cur()) || cur() == '_')
877 {
878 name.push_back(cur());
879 adv();
880 }
881 return get_variable(name, res);
882 }
883 else
884 return err("express signed expression, got '%c'", op);
885 }
886
887 bool parse_term(soc_word_t& res)
888 {
889 if(!parse_signed(res))
890 return false;
891 while(cur() == '*' || cur() == '/' || cur() == '%')
892 {
893 char op = cur();
894 adv();
895 soc_word_t tmp;
896 if(!parse_signed(tmp))
897 return false;
898 if(op == '*')
899 res *= tmp;
900 else if(tmp != 0)
901 res = op == '/' ? res / tmp : res % tmp;
902 else
903 return err("division by 0");
904 }
905 return true;
906 }
907
908 bool parse_expression(soc_word_t& res)
909 {
910 if(!parse_term(res))
911 return false;
912 while(!end() && (cur() == '+' || cur() == '-'))
913 {
914 char op = cur();
915 adv();
916 soc_word_t tmp;
917 if(!parse_term(tmp))
918 return false;
919 if(op == '+')
920 res += tmp;
921 else
922 res -= tmp;
923 }
924 return true;
925 }
926
927 bool parse(soc_word_t& res, std::string& _error)
928 {
929 bool ok = parse_expression(res);
930 if(ok && !end())
931 err("unexpected character '%c'", cur());
932 _error = error;
933 return ok && end();
934 }
935
936 virtual bool get_variable(std::string name, soc_word_t& res)
937 {
938 return err("unknown variable '%s'", name.c_str());
939 }
940};
941
942struct my_evaluator : public formula_evaluator
943{
944 const std::map< std::string, soc_word_t>& var;
945
946 my_evaluator(const std::string& formula, const std::map< std::string, soc_word_t>& _var)
947 :formula_evaluator(formula), var(_var) {}
948
949 virtual bool get_variable(std::string name, soc_word_t& res)
950 {
951 std::map< std::string, soc_word_t>::const_iterator it = var.find(name);
952 if(it == var.end())
953 return formula_evaluator::get_variable(name, res);
954 else
955 {
956 res = it->second;
957 return true;
958 }
959 }
960};
961
962}
963
964bool soc_desc_evaluate_formula(const std::string& formula,
965 const std::map< std::string, soc_word_t>& var, soc_word_t& result, std::string& error)
966{
967 my_evaluator e(formula, var);
968 return e.parse(result, error);
969}
diff --git a/utils/regtools/lib/soc_desc.hpp b/utils/regtools/lib/soc_desc.hpp
index efaf813eb2..d9dbf0cc20 100644
--- a/utils/regtools/lib/soc_desc.hpp
+++ b/utils/regtools/lib/soc_desc.hpp
@@ -25,6 +25,7 @@
25#include <vector> 25#include <vector>
26#include <list> 26#include <list>
27#include <string> 27#include <string>
28#include <map>
28 29
29/** 30/**
30 * These data structures represent the SoC register in a convenient way. 31 * These data structures represent the SoC register in a convenient way.
@@ -50,6 +51,21 @@ typedef uint32_t soc_addr_t;
50typedef uint32_t soc_word_t; 51typedef uint32_t soc_word_t;
51typedef uint32_t soc_reg_flags_t; 52typedef uint32_t soc_reg_flags_t;
52 53
54/** SoC error gravity level */
55enum soc_error_level_t
56{
57 SOC_ERROR_WARNING,
58 SOC_ERROR_FATAL,
59};
60
61/** SoC description error */
62struct soc_error_t
63{
64 soc_error_level_t level; /// level (warning, fatal, ...)
65 std::string location; /// human description of the location
66 std::string message; /// message
67};
68
53/** SoC register generic formula */ 69/** SoC register generic formula */
54enum soc_reg_formula_type_t 70enum soc_reg_formula_type_t
55{ 71{
@@ -66,6 +82,8 @@ struct soc_reg_field_value_t
66 std::string name; /// name of the value 82 std::string name; /// name of the value
67 soc_word_t value; /// numeric value 83 soc_word_t value; /// numeric value
68 std::string desc; /// human description 84 std::string desc; /// human description
85
86 std::vector< soc_error_t > errors(bool recursive);
69}; 87};
70 88
71/** SoC register field */ 89/** SoC register field */
@@ -90,6 +108,8 @@ struct soc_reg_field_t
90 } 108 }
91 109
92 std::vector< soc_reg_field_value_t > value; 110 std::vector< soc_reg_field_value_t > value;
111
112 std::vector< soc_error_t > errors(bool recursive);
93}; 113};
94 114
95/** SoC register address */ 115/** SoC register address */
@@ -97,6 +117,8 @@ struct soc_reg_addr_t
97{ 117{
98 std::string name; /// actual register name 118 std::string name; /// actual register name
99 soc_addr_t addr; /// actual register address (relative to device) 119 soc_addr_t addr; /// actual register address (relative to device)
120
121 std::vector< soc_error_t > errors(bool recursive);
100}; 122};
101 123
102/** SoC register formula */ 124/** SoC register formula */
@@ -104,6 +126,8 @@ struct soc_reg_formula_t
104{ 126{
105 enum soc_reg_formula_type_t type; 127 enum soc_reg_formula_type_t type;
106 std::string string; /// for STRING 128 std::string string; /// for STRING
129
130 std::vector< soc_error_t > errors(bool recursive);
107}; 131};
108 132
109/** SoC register */ 133/** SoC register */
@@ -116,6 +140,8 @@ struct soc_reg_t
116 soc_reg_flags_t flags; /// ORed value 140 soc_reg_flags_t flags; /// ORed value
117 141
118 std::vector< soc_reg_field_t > field; 142 std::vector< soc_reg_field_t > field;
143
144 std::vector< soc_error_t > errors(bool recursive);
119}; 145};
120 146
121/** Soc device address */ 147/** Soc device address */
@@ -123,6 +149,8 @@ struct soc_dev_addr_t
123{ 149{
124 std::string name; /// actual device name 150 std::string name; /// actual device name
125 soc_addr_t addr; 151 soc_addr_t addr;
152
153 std::vector< soc_error_t > errors(bool recursive);
126}; 154};
127 155
128/** SoC device */ 156/** SoC device */
@@ -135,6 +163,8 @@ struct soc_dev_t
135 std::vector< soc_dev_addr_t > addr; 163 std::vector< soc_dev_addr_t > addr;
136 164
137 std::vector< soc_reg_t > reg; 165 std::vector< soc_reg_t > reg;
166
167 std::vector< soc_error_t > errors(bool recursive);
138}; 168};
139 169
140/** SoC */ 170/** SoC */
@@ -144,10 +174,23 @@ struct soc_t
144 std::string desc; /// SoC name 174 std::string desc; /// SoC name
145 175
146 std::vector< soc_dev_t > dev; 176 std::vector< soc_dev_t > dev;
177
178 std::vector< soc_error_t > errors(bool recursive);
147}; 179};
148 180
149/** Parse a SoC description from a XML file, append it to <soc>. A file 181/** Parse a SoC description from a XML file, append it to <soc>. */
150 * can contain multiple SoC descriptions */ 182bool soc_desc_parse_xml(const std::string& filename, soc_t& soc);
151bool soc_desc_parse_xml(const std::string& filename, std::vector< soc_t >& soc); 183/** Write a SoC description to a XML file, overwriting it. A file can contain
184 * multiple Soc descriptions */
185bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc);
186/** Normalise a soc description by reordering elemnts so that:
187 * - devices are sorted by first name
188 * - registers are sorted by first address
189 * - fields are sorted by last bit
190 * - values are sorted by value */
191void soc_desc_normalize(soc_t& soc);
192/** Formula parser: try to parse and evaluate a formula to a specific value of 'n' */
193bool soc_desc_evaluate_formula(const std::string& formula,
194 const std::map< std::string, soc_word_t>& var, soc_word_t& result, std::string& error);
152 195
153#endif /* __SOC_DESC__ */ \ No newline at end of file 196#endif /* __SOC_DESC__ */ \ No newline at end of file
diff --git a/utils/regtools/qeditor/analyser.h b/utils/regtools/qeditor/analyser.h
index a06652bfb0..4f9830ac4c 100644
--- a/utils/regtools/qeditor/analyser.h
+++ b/utils/regtools/qeditor/analyser.h
@@ -5,13 +5,14 @@
5#include <QVector> 5#include <QVector>
6#include <QString> 6#include <QString>
7#include "backend.h" 7#include "backend.h"
8#include "regtab.h"
8 9
9class Analyser : public QObject 10class Analyser : public RegTabPanel
10{ 11{
11 Q_OBJECT
12public: 12public:
13 Analyser(const SocRef& soc, IoBackend *backend); 13 Analyser(const SocRef& soc, IoBackend *backend);
14 virtual ~Analyser(); 14 virtual ~Analyser();
15 virtual void AllowWrite(bool en) { Q_UNUSED(en); }
15 virtual QWidget *GetWidget() = 0; 16 virtual QWidget *GetWidget() = 0;
16 17
17protected: 18protected:
diff --git a/utils/regtools/qeditor/aux.cpp b/utils/regtools/qeditor/aux.cpp
new file mode 100644
index 0000000000..0614bb57f6
--- /dev/null
+++ b/utils/regtools/qeditor/aux.cpp
@@ -0,0 +1,746 @@
1#include "aux.h"
2#include <QFontMetrics>
3#include <QPainter>
4#include <QTextDocument>
5#include <QAbstractTextDocumentLayout>
6#include <QHeaderView>
7#include <QDebug>
8#include <QElapsedTimer>
9#include <QXmlStreamReader>
10#include <QXmlStreamWriter>
11#include <QTextBlock>
12
13/**
14 * SocBitRangeValidator
15 */
16SocBitRangeValidator::SocBitRangeValidator(QObject *parent)
17 :QValidator(parent)
18{
19}
20
21void SocBitRangeValidator::fixup(QString& input) const
22{
23 input = input.trimmed();
24}
25
26QValidator::State SocBitRangeValidator::validate(QString& input, int& pos) const
27{
28 Q_UNUSED(pos);
29 int first, last;
30 State state = parse(input, last, first);
31 return state;
32}
33
34QValidator::State SocBitRangeValidator::parse(const QString& input, int& last, int& first) const
35{
36 // the empty string is always intermediate
37 if(input.size() == 0)
38 return Intermediate;
39 // check if there is ':'
40 int pos = input.indexOf(':');
41 if(pos == -1)
42 pos = input.size();
43 // if field start with ':', the last bit is implicit and is 31
44 if(pos > 0)
45 {
46 // parse last bit and check it's between 0 and 31
47 bool ok = false;
48 last = input.left(pos).toInt(&ok);
49 if(!ok || last < 0 || last >= 32)
50 return Invalid;
51 }
52 else
53 last = 31;
54 // parse first bit
55 if(pos < input.size() - 1)
56 {
57 bool ok = false;
58 first = input.mid(pos + 1).toInt(&ok);
59 if(!ok || first < 0 || first > last)
60 return Invalid;
61 }
62 // if input ends with ':', first bit is implicit and is 0
63 else if(pos == input.size() - 1)
64 first = 0;
65 // if there no ':', first=last
66 else
67 first = last;
68 return Acceptable;
69}
70
71/**
72 * SocFieldValidator
73 */
74
75SocFieldValidator::SocFieldValidator(QObject *parent)
76 :QValidator(parent)
77{
78 m_field.first_bit = 0;
79 m_field.last_bit = 31;
80}
81
82SocFieldValidator::SocFieldValidator(const soc_reg_field_t& field, QObject *parent)
83 :QValidator(parent), m_field(field)
84{
85}
86
87void SocFieldValidator::fixup(QString& input) const
88{
89 input = input.trimmed();
90}
91
92QValidator::State SocFieldValidator::validate(QString& input, int& pos) const
93{
94 Q_UNUSED(pos);
95 soc_word_t val;
96 State state = parse(input, val);
97 return state;
98}
99
100QValidator::State SocFieldValidator::parse(const QString& input, soc_word_t& val) const
101{
102 // the empty string is always intermediate
103 if(input.size() == 0)
104 return Intermediate;
105 // first check named values
106 State state = Invalid;
107 foreach(const soc_reg_field_value_t& value, m_field.value)
108 {
109 QString name = QString::fromLocal8Bit(value.name.c_str());
110 // cannot be a substring if too long or empty
111 if(input.size() > name.size())
112 continue;
113 // check equal string
114 if(input == name)
115 {
116 state = Acceptable;
117 val = value.value;
118 break;
119 }
120 // check substring
121 if(name.startsWith(input))
122 state = Intermediate;
123 }
124 // early return for exact match
125 if(state == Acceptable)
126 return state;
127 // do a few special cases for convenience
128 if(input.compare("0x", Qt::CaseInsensitive) == 0 ||
129 input.compare("0b", Qt::CaseInsensitive) == 0)
130 return Intermediate;
131 // try by parsing
132 unsigned basis, pos;
133 if(input.size() >= 2 && input.startsWith("0x", Qt::CaseInsensitive))
134 {
135 basis = 16;
136 pos = 2;
137 }
138 else if(input.size() >= 2 && input.startsWith("0b", Qt::CaseInsensitive))
139 {
140 basis = 2;
141 pos = 2;
142 }
143 else if(input.size() >= 2 && input.startsWith("0"))
144 {
145 basis = 8;
146 pos = 1;
147 }
148 else
149 {
150 basis = 10;
151 pos = 0;
152 }
153 bool ok = false;
154 unsigned long v = input.mid(pos).toULong(&ok, basis);
155 // if not ok, return result of name parsing
156 if(!ok)
157 return state;
158 // if ok, check if it fits in the number of bits
159 unsigned nr_bits = m_field.last_bit - m_field.first_bit + 1;
160 unsigned long max = nr_bits == 32 ? 0xffffffff : (1 << nr_bits) - 1;
161 if(v <= max)
162 {
163 val = v;
164 return Acceptable;
165 }
166
167 return state;
168}
169
170/**
171 * RegLineEdit
172 */
173RegLineEdit::RegLineEdit(QWidget *parent)
174 :QWidget(parent)
175{
176 m_layout = new QHBoxLayout(this);
177 m_button = new QToolButton(this);
178 m_button->setCursor(Qt::ArrowCursor);
179 m_button->setStyleSheet("QToolButton { font-weight: bold; color: white; background: black; }");
180 m_button->setPopupMode(QToolButton::InstantPopup);
181 m_edit = new QLineEdit(this);
182 m_layout->addWidget(m_button);
183 m_layout->addWidget(m_edit);
184 m_menu = new QMenu(this);
185 connect(m_menu->addAction("Write"), SIGNAL(triggered()), this, SLOT(OnWriteAct()));
186 connect(m_menu->addAction("Set"), SIGNAL(triggered()), this, SLOT(OnSetAct()));
187 connect(m_menu->addAction("Clear"), SIGNAL(triggered()), this, SLOT(OnClearAct()));
188 connect(m_menu->addAction("Toggle"), SIGNAL(triggered()), this, SLOT(OnToggleAct()));
189 EnableSCT(false);
190 SetReadOnly(false);
191 ShowMode(true);
192 SetMode(Write);
193}
194
195void RegLineEdit::SetReadOnly(bool ro)
196{
197 m_edit->setReadOnly(ro);
198 m_readonly = ro;
199 ShowMode(!ro);
200}
201
202void RegLineEdit::EnableSCT(bool en)
203{
204 m_has_sct = en;
205 if(!m_has_sct)
206 {
207 m_button->setMenu(0);
208 SetMode(Write);
209 }
210 else
211 m_button->setMenu(m_menu);
212}
213
214RegLineEdit::~RegLineEdit()
215{
216}
217
218QLineEdit *RegLineEdit::GetLineEdit()
219{
220 return m_edit;
221}
222
223void RegLineEdit::ShowMode(bool show)
224{
225 if(show)
226 m_button->show();
227 else
228 m_button->hide();
229}
230
231void RegLineEdit::OnWriteAct()
232{
233 SetMode(Write);
234}
235
236void RegLineEdit::OnSetAct()
237{
238 SetMode(Set);
239}
240
241void RegLineEdit::OnClearAct()
242{
243 SetMode(Clear);
244}
245
246void RegLineEdit::OnToggleAct()
247{
248 SetMode(Toggle);
249}
250
251void RegLineEdit::SetMode(EditMode mode)
252{
253 m_mode = mode;
254 switch(m_mode)
255 {
256 case Write: m_button->setText("WR"); break;
257 case Set: m_button->setText("SET"); break;
258 case Clear: m_button->setText("CLR"); break;
259 case Toggle: m_button->setText("TOG"); break;
260 default: break;
261 }
262}
263
264RegLineEdit::EditMode RegLineEdit::GetMode()
265{
266 return m_mode;
267}
268
269void RegLineEdit::setText(const QString& text)
270{
271 m_edit->setText(text);
272}
273
274QString RegLineEdit::text() const
275{
276 return m_edit->text();
277}
278
279/**
280 * SocFieldItemDelegate
281 */
282
283QString SocFieldItemDelegate::displayText(const QVariant& value, const QLocale& locale) const
284{
285 if(value.type() == QVariant::UInt)
286 return QString("0x%1").arg(value.toUInt(), (m_bitcount + 3) / 4, 16, QChar('0'));
287 else
288 return QStyledItemDelegate::displayText(value, locale);
289}
290
291/**
292 * SocFieldEditor
293 */
294SocFieldEditor::SocFieldEditor(const soc_reg_field_t& field, QWidget *parent)
295 :QLineEdit(parent), m_reg_field(field)
296{
297 m_validator = new SocFieldValidator(field);
298 setValidator(m_validator);
299}
300
301SocFieldEditor::~SocFieldEditor()
302{
303 delete m_validator;
304}
305
306uint SocFieldEditor::field() const
307{
308 soc_word_t v;
309 /* in case validator fails to parse, return old value */
310 if(m_validator->parse(text(), v) == QValidator::Acceptable)
311 return v;
312 else
313 return m_field;
314}
315
316void SocFieldEditor::setField(uint field)
317{
318 m_field = field;
319 int digits = (m_reg_field.last_bit - m_reg_field.first_bit + 4) / 4;
320 setText(QString("0x%1").arg(field, digits, 16, QChar('0')));
321}
322
323/**
324 * SocFieldEditorCreator
325 */
326QWidget *SocFieldEditorCreator::createWidget(QWidget *parent) const
327{
328 return new SocFieldEditor(m_field, parent);
329}
330
331QByteArray SocFieldEditorCreator::valuePropertyName() const
332{
333 return QByteArray("field");
334}
335
336/**
337 * RegSexyDisplay
338 */
339RegSexyDisplay::RegSexyDisplay(const SocRegRef& reg, QWidget *parent)
340 :QWidget(parent), m_reg(reg)
341{
342 m_size = QSize();
343}
344
345int RegSexyDisplay::separatorSize() const
346{
347 return 1;
348}
349
350int RegSexyDisplay::marginSize() const
351{
352 return fontMetrics().height() / 3;
353}
354
355int RegSexyDisplay::textSep() const
356{
357 return marginSize() / 2;
358}
359
360int RegSexyDisplay::headerHeight() const
361{
362 return 2 * marginSize() + textSep() + 2 * fontMetrics().height();
363}
364
365int RegSexyDisplay::columnWidth() const
366{
367 return 2 * marginSize() + fontMetrics().height();
368}
369
370int RegSexyDisplay::maxContentHeight() const
371{
372 int max = 0;
373 QFontMetrics metrics = fontMetrics();
374 for(size_t i = 0; i < m_reg.GetReg().field.size(); i++)
375 {
376 QString s = QString::fromStdString(m_reg.GetReg().field[i].name);
377 // add extra spaces arounds
378 s = " " + s + " ";
379 max = qMax(max, metrics.boundingRect(s).width());
380 }
381 return 2 * marginSize() + max;
382}
383
384int RegSexyDisplay::gapHeight() const
385{
386 return marginSize() / 2;
387}
388
389QSize RegSexyDisplay::minimumSizeHint() const
390{
391 /* cache computation because it's expensive */
392 if(m_size.isValid())
393 return m_size;
394 /* width: display 32 columns + 33 vertical separators */
395 m_size.setWidth(32 * columnWidth() + 33 * separatorSize());
396 /* height: one separator + two digits + one separator + margin + separator
397 * + names + separator */
398 m_size.setHeight(4 * separatorSize() + headerHeight() + gapHeight() + maxContentHeight());
399 return m_size;
400}
401
402QSize RegSexyDisplay::sizeHint() const
403{
404 return minimumSizeHint();
405}
406
407void RegSexyDisplay::paintEvent(QPaintEvent *event)
408{
409 // FIXME could be optimised with QStaticText
410 Q_UNUSED(event);
411 int txt_h = fontMetrics().height();
412 int sep_sz = separatorSize();
413 int w = width();
414 int h = height() - 1;
415 int col_w = (w - 33 * sep_sz) / 32;
416 int hdr_h = headerHeight();
417 int gap_h = gapHeight();
418 int tot_w = 33 * sep_sz + 32 * col_w;
419 int margin = marginSize();
420 int txt_sep = textSep();
421 int tot_hdr_sz = 2 * sep_sz + hdr_h;
422 // computer xshift
423 int x_shift = (w - tot_w) / 2;
424#define ith_col_x(i) (x_shift + (i) * (sep_sz + col_w))
425
426 QPainter painter(this);
427 QBrush back_brush = palette().base();
428 QBrush line_brush = palette().dark();
429
430 // fill interesting zone with base
431 painter.fillRect(x_shift, 0, tot_w, h, back_brush);
432
433 // draw top and bottom lines
434 painter.setPen(QPen(palette().dark(), sep_sz));
435 painter.fillRect(x_shift, 0, tot_w, sep_sz, line_brush);
436 painter.fillRect(x_shift, h - sep_sz, tot_w, sep_sz, line_brush);
437 // draw intemediate lines
438 for(int i = 0; i <= 32; i++)
439 painter.fillRect(ith_col_x(i), 0, sep_sz, 2 * sep_sz + hdr_h, line_brush);
440 // draw bottom header lines
441 painter.fillRect(ith_col_x(0), sep_sz + hdr_h, tot_w, sep_sz, line_brush);
442 painter.fillRect(ith_col_x(0), tot_hdr_sz + gap_h, tot_w, sep_sz, line_brush);
443 // redraw some lines but wider
444 for(int i = 4; i < 32; i += 4)
445 painter.fillRect(ith_col_x(i) - sep_sz, 0, 3 * sep_sz, tot_hdr_sz, line_brush);
446 // draw numbers in the header
447 painter.setPen(palette().brush(QPalette::ButtonText).color());
448 for(int i = 0; i < 32; i++)
449 {
450 QRect r(ith_col_x(i), sep_sz + margin, col_w, txt_h);
451 painter.drawText(r, Qt::AlignCenter, QString("%1").arg((31 - i) / 10));
452 r.translate(0, txt_h + txt_sep);
453 painter.drawText(r, Qt::AlignCenter, QString("%1").arg((31 - i) % 10));
454 }
455 // display content
456 for(size_t i = 0; i < m_reg.GetReg().field.size(); i++)
457 {
458 const soc_reg_field_t& field = m_reg.GetReg().field[i];
459 QRect r(QPoint(ith_col_x(31 - field.last_bit) + sep_sz, tot_hdr_sz),
460 QPoint(ith_col_x(32 - field.first_bit), h - sep_sz));
461 painter.fillRect(r.x() - sep_sz, r.y(), sep_sz, r.height(), line_brush);
462 painter.fillRect(r.right(), r.y(), sep_sz, r.height(), line_brush);
463 r.setY(r.y() + gap_h + sep_sz);
464 // draw rotated text
465 painter.save();
466 painter.translate(r.bottomLeft());
467 painter.rotate(-90);
468 //painter.fillRect(QRect(0, 0, r.height(), r.width()), QBrush(Qt::red));
469 QRect r2(0, 0, r.height(), r.width());
470 painter.drawText(r2, Qt::AlignCenter, QString::fromStdString(field.name));
471 painter.restore();
472 }
473#undef ith_col_x
474}
475
476/**
477 * GrowingTextEdit
478 */
479GrowingTextEdit::GrowingTextEdit(QWidget *parent)
480 :QTextEdit(parent)
481{
482 connect(this, SIGNAL(textChanged()), this, SLOT(TextChanged()));
483 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
484 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
485}
486
487void GrowingTextEdit::TextChanged()
488{
489 int content_size = document()->documentLayout()->documentSize().height();
490 content_size = qMax(content_size, fontMetrics().height());
491 setFixedHeight(content_size + contentsMargins().top() + contentsMargins().bottom());
492}
493
494/**
495 * GrowingTableWidget
496 */
497GrowingTableWidget::GrowingTableWidget(QWidget *parent)
498 :QTableWidget(parent)
499{
500 connect(model(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
501 this, SLOT(DataChanged(const QModelIndex&, const QModelIndex&)));
502}
503
504void GrowingTableWidget::DataChanged(const QModelIndex& tl, const QModelIndex& br)
505{
506 Q_UNUSED(tl);
507 Q_UNUSED(br);
508 resizeRowsToContents();
509 resizeColumnsToContents();
510 int h = contentsMargins().top() + contentsMargins().bottom();
511 h += horizontalHeader()->height();
512 for(int i = 0; i < rowCount(); i++)
513 h += rowHeight(i);
514 setMinimumHeight(h);
515}
516
517/**
518 * MyTextEditor
519 */
520MyTextEditor::MyTextEditor(QWidget *parent)
521 :QWidget(parent)
522{
523 QVBoxLayout *layout = new QVBoxLayout;
524 m_toolbar = new QToolBar(this);
525 m_edit = new QTextEdit(this);
526 layout->addWidget(m_toolbar, 0);
527 layout->addWidget(m_edit, 1);
528 setLayout(layout);
529 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
530
531 m_edit->setAcceptRichText(false);
532 m_edit->setAutoFormatting(QTextEdit::AutoAll);
533
534 m_bold_button = new QToolButton(this);
535 m_bold_button->setIcon(QIcon::fromTheme("format-text-bold"));
536 m_bold_button->setText("bold");
537 m_bold_button->setCheckable(true);
538
539 m_italic_button = new QToolButton(this);
540 m_italic_button->setIcon(QIcon::fromTheme("format-text-italic"));
541 m_italic_button->setText("italic");
542 m_italic_button->setCheckable(true);
543
544 m_underline_button = new QToolButton(this);
545 m_underline_button->setIcon(QIcon::fromTheme("format-text-underline"));
546 m_underline_button->setText("underline");
547 m_underline_button->setCheckable(true);
548
549 m_toolbar->addWidget(m_bold_button);
550 m_toolbar->addWidget(m_italic_button);
551 m_toolbar->addWidget(m_underline_button);
552
553 connect(m_bold_button, SIGNAL(toggled(bool)), this, SLOT(OnTextBold(bool)));
554 connect(m_italic_button, SIGNAL(toggled(bool)), this, SLOT(OnTextItalic(bool)));
555 connect(m_underline_button, SIGNAL(toggled(bool)), this, SLOT(OnTextUnderline(bool)));
556 connect(m_edit, SIGNAL(textChanged()), this, SLOT(OnInternalTextChanged()));
557 connect(m_edit, SIGNAL(currentCharFormatChanged(const QTextCharFormat&)),
558 this, SLOT(OnCharFormatChanged(const QTextCharFormat&)));
559
560 SetGrowingMode(false);
561 SetReadOnly(false);
562}
563
564void MyTextEditor::SetReadOnly(bool en)
565{
566 m_read_only = en;
567 if(en)
568 m_toolbar->hide();
569 else
570 m_toolbar->hide();
571 m_edit->setReadOnly(en);
572}
573
574void MyTextEditor::SetGrowingMode(bool en)
575{
576 m_growing_mode = en;
577 if(en)
578 {
579 m_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
580 m_edit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
581 OnTextChanged();
582 }
583 else
584 {
585 m_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
586 m_edit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
587 }
588}
589
590void MyTextEditor::OnInternalTextChanged()
591{
592 if(m_growing_mode)
593 {
594 int content_size = m_edit->document()->documentLayout()->documentSize().height();
595 content_size = qMax(content_size, m_edit->fontMetrics().height());
596 m_edit->setMinimumHeight(content_size + m_edit->contentsMargins().top() +
597 m_edit->contentsMargins().bottom());
598 }
599 emit OnTextChanged();
600}
601
602void MyTextEditor::OnTextBold(bool checked)
603{
604 QTextCursor cursor = m_edit->textCursor();
605 QTextCharFormat fmt = cursor.charFormat();
606 fmt.setFontWeight(checked ? QFont::Bold : QFont::Normal);
607 cursor.setCharFormat(fmt);
608 m_edit->setTextCursor(cursor);
609}
610
611void MyTextEditor::OnTextItalic(bool checked)
612{
613 QTextCursor cursor = m_edit->textCursor();
614 QTextCharFormat fmt = cursor.charFormat();
615 fmt.setFontItalic(checked);
616 cursor.setCharFormat(fmt);
617 m_edit->setTextCursor(cursor);
618}
619
620void MyTextEditor::OnTextUnderline(bool checked)
621{
622 QTextCursor cursor = m_edit->textCursor();
623 QTextCharFormat fmt = cursor.charFormat();
624 fmt.setFontUnderline(checked);
625 cursor.setCharFormat(fmt);
626 m_edit->setTextCursor(cursor);
627}
628
629void MyTextEditor::OnCharFormatChanged(const QTextCharFormat& fmt)
630{
631 /* NOTE: changing the button states programmaticaly doesn't trigger
632 * the toggled() signals, otherwise it would result in a loop
633 * between this function and OnText{Bold,Italic,Underline,...} */
634 m_bold_button->setChecked(fmt.fontWeight() > QFont::Normal);
635 m_italic_button->setChecked(fmt.fontItalic());
636 m_underline_button->setChecked(fmt.fontUnderline());
637}
638
639void MyTextEditor::SetTextHtml(const QString& text)
640{
641 m_edit->setHtml(text);
642}
643
644QString MyTextEditor::GetTextHtml()
645{
646 return m_edit->toPlainText();
647}
648
649bool MyTextEditor::IsModified()
650{
651 return m_edit->document()->isModified();
652}
653
654/**
655 * MySwitchableTextEditor
656 */
657MySwitchableTextEditor::MySwitchableTextEditor(QWidget *parent)
658 :QWidget(parent)
659{
660 QVBoxLayout *layout = new QVBoxLayout(this);
661 m_edit = new MyTextEditor(this);
662 m_label = new QLabel(this);
663 m_label->setTextFormat(Qt::RichText);
664 m_label->setAlignment(Qt::AlignTop);
665 m_line = new QLineEdit(this);
666
667 layout->addWidget(m_label);
668 layout->addWidget(m_edit);
669 layout->addWidget(m_line);
670
671 setLayout(layout);
672
673 m_editor_mode = false;
674 m_line_mode = false;
675 UpdateVisibility();
676}
677
678void MySwitchableTextEditor::SetEditorMode(bool edit)
679{
680 if(edit == m_editor_mode)
681 return;
682 QString text = GetTextHtml();
683 m_editor_mode = edit;
684 UpdateVisibility();
685 SetTextHtml(text);
686}
687
688QString MySwitchableTextEditor::GetTextHtml()
689{
690 if(m_editor_mode)
691 return m_line_mode ? m_line->text() : m_edit->GetTextHtml();
692 else
693 return m_label->text();
694}
695
696void MySwitchableTextEditor::SetTextHtml(const QString& text)
697{
698 if(m_editor_mode)
699 {
700 if(m_line_mode)
701 m_line->setText(text);
702 else
703 m_edit->SetTextHtml(text);
704 }
705 else
706 m_label->setText(text);
707}
708
709MyTextEditor *MySwitchableTextEditor::GetEditor()
710{
711 return m_edit;
712}
713
714void MySwitchableTextEditor::SetLineMode(bool en)
715{
716 if(m_line_mode == en)
717 return;
718 QString text = GetTextHtml();
719 m_line_mode = en;
720 SetTextHtml(text);
721 UpdateVisibility();
722}
723
724QLineEdit *MySwitchableTextEditor::GetLineEdit()
725{
726 return m_line;
727}
728
729void MySwitchableTextEditor::UpdateVisibility()
730{
731 m_label->setVisible(!m_editor_mode);
732 m_edit->setVisible(m_editor_mode && !m_line_mode);
733 m_line->setVisible(m_editor_mode && m_line_mode);
734}
735
736QLabel *MySwitchableTextEditor::GetLabel()
737{
738 return m_label;
739}
740
741bool MySwitchableTextEditor::IsModified()
742{
743 if(!m_editor_mode)
744 return false;
745 return m_line_mode ? m_line->isModified() : m_edit->IsModified();
746}
diff --git a/utils/regtools/qeditor/aux.h b/utils/regtools/qeditor/aux.h
new file mode 100644
index 0000000000..d6a572826c
--- /dev/null
+++ b/utils/regtools/qeditor/aux.h
@@ -0,0 +1,227 @@
1#ifndef AUX_H
2#define AUX_H
3
4#include <QEvent>
5#include <QPaintEvent>
6#include <QLineEdit>
7#include <QValidator>
8#include <QToolButton>
9#include <QMenu>
10#include <QHBoxLayout>
11#include <QTextEdit>
12#include <QTableWidget>
13#include <QToolBar>
14#include <QLabel>
15#include <QHBoxLayout>
16#include <QItemEditorCreatorBase>
17#include <QStyledItemDelegate>
18#include "backend.h"
19
20class SocBitRangeValidator : public QValidator
21{
22 Q_OBJECT
23public:
24 SocBitRangeValidator(QObject *parent = 0);
25
26 virtual void fixup(QString& input) const;
27 virtual State validate(QString& input, int& pos) const;
28 /* validate and return the interpreted value */
29 State parse(const QString& input, int& last_bit, int& first_bit) const;
30};
31
32class SocFieldValidator : public QValidator
33{
34 Q_OBJECT
35public:
36 SocFieldValidator(QObject *parent = 0);
37 SocFieldValidator(const soc_reg_field_t& field, QObject *parent = 0);
38
39 virtual void fixup(QString& input) const;
40 virtual State validate(QString& input, int& pos) const;
41 /* validate and return the interpreted value */
42 State parse(const QString& input, soc_word_t& val) const;
43
44protected:
45 soc_reg_field_t m_field;
46};
47
48class RegLineEdit : public QWidget
49{
50 Q_OBJECT
51public:
52 enum EditMode
53 {
54 Write, Set, Clear, Toggle
55 };
56
57 RegLineEdit(QWidget *parent = 0);
58 ~RegLineEdit();
59 void SetReadOnly(bool ro);
60 void EnableSCT(bool en);
61 void SetMode(EditMode mode);
62 EditMode GetMode();
63 QLineEdit *GetLineEdit();
64 void setText(const QString& text);
65 QString text() const;
66
67 Q_PROPERTY(QString text READ text WRITE setText USER true)
68
69protected slots:
70 void OnWriteAct();
71 void OnSetAct();
72 void OnClearAct();
73 void OnToggleAct();
74protected:
75 void ShowMode(bool show);
76 void DoAutoHide();
77
78 QHBoxLayout *m_layout;
79 QToolButton *m_button;
80 QLineEdit *m_edit;
81 EditMode m_mode;
82 bool m_has_sct;
83 bool m_readonly;
84 QMenu *m_menu;
85};
86
87class SocFieldItemDelegate : public QStyledItemDelegate
88{
89public:
90 SocFieldItemDelegate(QObject *parent = 0):QStyledItemDelegate(parent), m_bitcount(32) {}
91 SocFieldItemDelegate(const soc_reg_field_t& field, QObject *parent = 0)
92 :QStyledItemDelegate(parent), m_bitcount(field.last_bit - field.first_bit + 1) {}
93
94 virtual QString displayText(const QVariant& value, const QLocale& locale) const;
95protected:
96 int m_bitcount;
97};
98
99class SocFieldEditor : public QLineEdit
100{
101 Q_OBJECT
102 Q_PROPERTY(uint field READ field WRITE setField USER true)
103public:
104 SocFieldEditor(const soc_reg_field_t& field, QWidget *parent = 0);
105 virtual ~SocFieldEditor();
106
107 uint field() const;
108 void setField(uint field);
109
110protected:
111 SocFieldValidator *m_validator;
112 uint m_field;
113 soc_reg_field_t m_reg_field;
114};
115
116class SocFieldEditorCreator : public QItemEditorCreatorBase
117{
118public:
119 SocFieldEditorCreator() { m_field.first_bit = 0; m_field.last_bit = 31; }
120 SocFieldEditorCreator(const soc_reg_field_t& field):m_field(field) {}
121
122 virtual QWidget *createWidget(QWidget *parent) const;
123 virtual QByteArray valuePropertyName() const;
124
125protected:
126 soc_reg_field_t m_field;
127};
128
129class RegSexyDisplay : public QWidget
130{
131 Q_OBJECT
132public:
133 RegSexyDisplay(const SocRegRef& reg, QWidget *parent = 0);
134
135 QSize minimumSizeHint() const;
136 QSize sizeHint() const;
137
138protected:
139 int marginSize() const;
140 int separatorSize() const;
141 int columnWidth() const;
142 int headerHeight() const;
143 int gapHeight() const;
144 int maxContentHeight() const;
145 int textSep() const;
146 void paintEvent(QPaintEvent *event);
147
148private:
149 SocRegRef m_reg;
150 mutable QSize m_size;
151};
152
153class GrowingTextEdit : public QTextEdit
154{
155 Q_OBJECT
156public:
157 GrowingTextEdit(QWidget *parent = 0);
158
159protected slots:
160 void TextChanged();
161};
162
163class GrowingTableWidget : public QTableWidget
164{
165 Q_OBJECT
166public:
167 GrowingTableWidget(QWidget *parent = 0);
168
169protected slots:
170 void DataChanged(const QModelIndex& tl, const QModelIndex& br);
171};
172
173class MyTextEditor : public QWidget
174{
175 Q_OBJECT
176public:
177 MyTextEditor(QWidget *parent = 0);
178 void SetGrowingMode(bool en);
179 void SetReadOnly(bool ro);
180 void SetTextHtml(const QString& text);
181 QString GetTextHtml();
182 bool IsModified();
183signals:
184 void OnTextChanged();
185
186protected slots:
187 void OnInternalTextChanged();
188 void OnTextBold(bool checked);
189 void OnTextItalic(bool checked);
190 void OnTextUnderline(bool checked);
191 void OnCharFormatChanged(const QTextCharFormat& fmt);
192
193protected:
194 bool m_growing_mode;
195 bool m_read_only;
196 QToolBar *m_toolbar;
197 QTextEdit *m_edit;
198 QToolButton *m_bold_button;
199 QToolButton *m_italic_button;
200 QToolButton *m_underline_button;
201};
202
203class MySwitchableTextEditor : public QWidget
204{
205 Q_OBJECT
206public:
207 MySwitchableTextEditor(QWidget *parent = 0);
208 QString GetTextHtml();
209 void SetTextHtml(const QString& text);
210 void SetEditorMode(bool en);
211 MyTextEditor *GetEditor();
212 QLineEdit *GetLineEdit();
213 QLabel *GetLabel();
214 void SetLineMode(bool en);
215 bool IsModified();
216
217protected:
218 void UpdateVisibility();
219
220 bool m_editor_mode;
221 bool m_line_mode;
222 QLabel *m_label;
223 MyTextEditor *m_edit;
224 QLineEdit *m_line;
225};
226
227#endif /* AUX_H */
diff --git a/utils/regtools/qeditor/backend.cpp b/utils/regtools/qeditor/backend.cpp
index eebda31989..204c160054 100644
--- a/utils/regtools/qeditor/backend.cpp
+++ b/utils/regtools/qeditor/backend.cpp
@@ -5,6 +5,36 @@
5#include "backend.h" 5#include "backend.h"
6 6
7/** 7/**
8 * SocFile
9 */
10SocFile::SocFile()
11 :m_valid(false)
12{
13}
14
15SocFile::SocFile(const QString& filename)
16 :m_filename(filename)
17{
18 m_valid = soc_desc_parse_xml(filename.toStdString(), m_soc);
19 soc_desc_normalize(m_soc);
20}
21
22bool SocFile::IsValid()
23{
24 return m_valid;
25}
26
27SocRef SocFile::GetSocRef()
28{
29 return SocRef(this);
30}
31
32QString SocFile::GetFilename()
33{
34 return m_filename;
35}
36
37/**
8 * Backend 38 * Backend
9 */ 39 */
10 40
@@ -12,33 +42,31 @@ Backend::Backend()
12{ 42{
13} 43}
14 44
15QStringList Backend::GetSocNameList() 45
46QList< SocFileRef > Backend::GetSocFileList()
16{ 47{
17 QStringList sl; 48 QList< SocFileRef > list;
18 foreach(const soc_t& soc, m_socs) 49 for(std::list< SocFile >::iterator it = m_socs.begin(); it != m_socs.end(); ++it)
19 sl.append(QString(soc.name.c_str())); 50 list.append(SocFileRef(&(*it)));
20 return sl; 51 return list;
21} 52}
22 53
23bool Backend::GetSocByName(const QString& name, SocRef& s) 54QList< SocRef > Backend::GetSocList()
24{ 55{
25 for(std::list< soc_t >::iterator it = m_socs.begin(); it != m_socs.end(); ++it) 56 QList< SocRef > list;
26 if(it->name == name.toStdString()) 57 for(std::list< SocFile >::iterator it = m_socs.begin(); it != m_socs.end(); ++it)
27 { 58 list.append(it->GetSocRef());
28 s = SocRef(&(*it)); 59 return list;
29 return true;
30 }
31 return false;
32} 60}
33 61
34bool Backend::LoadSocDesc(const QString& filename) 62bool Backend::LoadSocDesc(const QString& filename)
35{ 63{
36 std::vector< soc_t > new_socs; 64 SocFile f(filename);
37 bool ret = soc_desc_parse_xml(filename.toStdString(), new_socs); 65 if(!f.IsValid())
38 for(size_t i = 0; i < new_socs.size(); i++) 66 return false;
39 m_socs.push_back(new_socs[i]); 67 m_socs.push_back(f);
40 emit OnSocListChanged(); 68 emit OnSocListChanged();
41 return ret; 69 return true;
42} 70}
43 71
44IoBackend *Backend::CreateFileIoBackend(const QString& filename) 72IoBackend *Backend::CreateFileIoBackend(const QString& filename)
@@ -321,7 +349,7 @@ HWStubBackendHelper::HWStubBackendHelper()
321 if(m_hotplug) 349 if(m_hotplug)
322 { 350 {
323 m_hotplug = LIBUSB_SUCCESS == libusb_hotplug_register_callback( 351 m_hotplug = LIBUSB_SUCCESS == libusb_hotplug_register_callback(
324 NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 352 NULL, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
325 LIBUSB_HOTPLUG_ENUMERATE, HWSTUB_USB_VID, HWSTUB_USB_PID, HWSTUB_CLASS, 353 LIBUSB_HOTPLUG_ENUMERATE, HWSTUB_USB_VID, HWSTUB_USB_PID, HWSTUB_CLASS,
326 &HWStubBackendHelper::HotPlugCallback, reinterpret_cast< void* >(this), &m_hotplug_handle); 354 &HWStubBackendHelper::HotPlugCallback, reinterpret_cast< void* >(this), &m_hotplug_handle);
327 } 355 }
@@ -364,6 +392,7 @@ void HWStubBackendHelper::OnHotPlug(bool arrived, struct libusb_device *dev)
364int HWStubBackendHelper::HotPlugCallback(struct libusb_context *ctx, struct libusb_device *dev, 392int HWStubBackendHelper::HotPlugCallback(struct libusb_context *ctx, struct libusb_device *dev,
365 libusb_hotplug_event event, void *user_data) 393 libusb_hotplug_event event, void *user_data)
366{ 394{
395 Q_UNUSED(ctx);
367 HWStubBackendHelper *helper = reinterpret_cast< HWStubBackendHelper* >(user_data); 396 HWStubBackendHelper *helper = reinterpret_cast< HWStubBackendHelper* >(user_data);
368 switch(event) 397 switch(event)
369 { 398 {
diff --git a/utils/regtools/qeditor/backend.h b/utils/regtools/qeditor/backend.h
index 939ed9529f..a813f5929f 100644
--- a/utils/regtools/qeditor/backend.h
+++ b/utils/regtools/qeditor/backend.h
@@ -5,10 +5,11 @@
5#include <QStringList> 5#include <QStringList>
6#include <QMap> 6#include <QMap>
7#include <QVector> 7#include <QVector>
8#include "soc_desc.hpp" 8#include <QMetaType>
9#ifdef HAVE_HWSTUB 9#ifdef HAVE_HWSTUB
10#include "hwstub.h" 10#include "hwstub.h"
11#endif 11#endif
12#include "soc.h"
12 13
13class IoBackend : public QObject 14class IoBackend : public QObject
14{ 15{
@@ -62,18 +63,18 @@ class DummyIoBackend : public IoBackend
62public: 63public:
63 DummyIoBackend() {} 64 DummyIoBackend() {}
64 65
65 virtual bool SupportAccess(AccessType type) { (void) type; return false; } 66 virtual bool SupportAccess(AccessType type) { Q_UNUSED(type); return false; }
66 virtual QString GetSocName() { return ""; } 67 virtual QString GetSocName() { return ""; }
67 virtual bool ReadRegister(const QString& name, soc_word_t& value) 68 virtual bool ReadRegister(const QString& name, soc_word_t& value)
68 { (void) name; (void) value; return false; } 69 { Q_UNUSED(name); Q_UNUSED(value); return false; }
69 virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value) 70 virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value)
70 { (void) addr; (void) value; return false; } 71 { Q_UNUSED(addr); Q_UNUSED(value); return false; }
71 virtual bool Reload() { return false; } 72 virtual bool Reload() { return false; }
72 virtual bool IsReadOnly() { return true; } 73 virtual bool IsReadOnly() { return true; }
73 virtual bool WriteRegister(const QString& name, soc_word_t value, WriteMode mode) 74 virtual bool WriteRegister(const QString& name, soc_word_t value, WriteMode mode)
74 { (void) name; (void) value; (void) mode; return false; } 75 { Q_UNUSED(name); Q_UNUSED(value); Q_UNUSED(mode); return false; }
75 virtual bool WriteRegister(soc_addr_t addr, soc_word_t value, WriteMode mode) 76 virtual bool WriteRegister(soc_addr_t addr, soc_word_t value, WriteMode mode)
76 { (void) addr; (void) value; (void) mode; return false; } 77 { Q_UNUSED(addr); Q_UNUSED(value); Q_UNUSED(mode); return false; }
77 virtual bool IsDirty() { return false; } 78 virtual bool IsDirty() { return false; }
78 virtual bool Commit() { return false; } 79 virtual bool Commit() { return false; }
79}; 80};
@@ -90,12 +91,12 @@ public:
90 virtual QString GetSocName(); 91 virtual QString GetSocName();
91 virtual bool ReadRegister(const QString& name, soc_word_t& value); 92 virtual bool ReadRegister(const QString& name, soc_word_t& value);
92 virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value) 93 virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value)
93 { (void) addr; (void) value; return false; } 94 { Q_UNUSED(addr); Q_UNUSED(value); return false; }
94 virtual bool Reload(); 95 virtual bool Reload();
95 virtual bool IsReadOnly() { return m_readonly; } 96 virtual bool IsReadOnly() { return m_readonly; }
96 virtual bool WriteRegister(const QString& name, soc_word_t value, WriteMode mode); 97 virtual bool WriteRegister(const QString& name, soc_word_t value, WriteMode mode);
97 virtual bool WriteRegister(soc_addr_t addr, soc_word_t value, WriteMode mode) 98 virtual bool WriteRegister(soc_addr_t addr, soc_word_t value, WriteMode mode)
98 { (void) addr; (void) value; (void) mode; return false; } 99 { Q_UNUSED(addr); Q_UNUSED(value); Q_UNUSED(mode); return false; }
99 virtual bool IsDirty() { return m_dirty; } 100 virtual bool IsDirty() { return m_dirty; }
100 virtual bool Commit(); 101 virtual bool Commit();
101 102
@@ -149,12 +150,12 @@ public:
149 virtual bool SupportAccess(AccessType type) { return type == ByAddress; } 150 virtual bool SupportAccess(AccessType type) { return type == ByAddress; }
150 virtual QString GetSocName(); 151 virtual QString GetSocName();
151 virtual bool ReadRegister(const QString& name, soc_word_t& value) 152 virtual bool ReadRegister(const QString& name, soc_word_t& value)
152 { (void) name; (void) value; return false; } 153 { Q_UNUSED(name); Q_UNUSED(value); return false; }
153 virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value); 154 virtual bool ReadRegister(soc_addr_t addr, soc_word_t& value);
154 virtual bool Reload(); 155 virtual bool Reload();
155 virtual bool IsReadOnly() { return false; } 156 virtual bool IsReadOnly() { return false; }
156 virtual bool WriteRegister(const QString& name, soc_word_t value, WriteMode mode) 157 virtual bool WriteRegister(const QString& name, soc_word_t value, WriteMode mode)
157 { (void) name; (void) value; (void) mode; return false; } 158 { Q_UNUSED(name); Q_UNUSED(value); Q_UNUSED(mode); return false; }
158 virtual bool WriteRegister(soc_addr_t addr, soc_word_t value, WriteMode mode); 159 virtual bool WriteRegister(soc_addr_t addr, soc_word_t value, WriteMode mode);
159 virtual bool IsDirty() { return false; } 160 virtual bool IsDirty() { return false; }
160 virtual bool Commit() { return true; } 161 virtual bool Commit() { return true; }
@@ -191,16 +192,48 @@ protected:
191}; 192};
192#endif 193#endif
193 194
194class SocRef 195class SocRef;
196
197class SocFile
198{
199public:
200 SocFile();
201 SocFile(const QString& filename);
202 bool IsValid();
203
204 SocRef GetSocRef();
205 QString GetFilename();
206 soc_t& GetSoc() { return m_soc; }
207
208protected:
209 bool m_valid;
210 QString m_filename;
211 soc_t m_soc;
212};
213
214class SocFileRef
195{ 215{
196public: 216public:
197 SocRef():m_soc(0) {} 217 SocFileRef():m_socfile(0) {}
198 SocRef(const soc_t *soc):m_soc(soc) {} 218 SocFileRef(SocFile *file):m_socfile(file) {}
199 const soc_t& GetSoc() const { return *m_soc; } 219 SocFile *GetSocFile() const { return m_socfile; }
220
200protected: 221protected:
201 const soc_t *m_soc; 222 SocFile *m_socfile;
202}; 223};
203 224
225Q_DECLARE_METATYPE(SocFileRef)
226
227class SocRef : public SocFileRef
228{
229public:
230 SocRef() {}
231 SocRef(SocFile *file):SocFileRef(file) {}
232 soc_t& GetSoc() const { return GetSocFile()->GetSoc(); }
233};
234
235Q_DECLARE_METATYPE(SocRef)
236
204class SocDevRef : public SocRef 237class SocDevRef : public SocRef
205{ 238{
206public: 239public:
@@ -208,9 +241,9 @@ public:
208 SocDevRef(const SocRef& soc, int dev_idx, int dev_addr_idx) 241 SocDevRef(const SocRef& soc, int dev_idx, int dev_addr_idx)
209 :SocRef(soc), m_dev_idx(dev_idx), m_dev_addr_idx(dev_addr_idx) {} 242 :SocRef(soc), m_dev_idx(dev_idx), m_dev_addr_idx(dev_addr_idx) {}
210 int GetDevIndex() const { return m_dev_idx; } 243 int GetDevIndex() const { return m_dev_idx; }
211 const soc_dev_t& GetDev() const { return GetSoc().dev[GetDevIndex()]; } 244 soc_dev_t& GetDev() const { return GetSoc().dev[GetDevIndex()]; }
212 int GetDevAddrIndex() const { return m_dev_addr_idx; } 245 int GetDevAddrIndex() const { return m_dev_addr_idx; }
213 const soc_dev_addr_t& GetDevAddr() const { return GetDev().addr[GetDevAddrIndex()]; } 246 soc_dev_addr_t& GetDevAddr() const { return GetDev().addr[GetDevAddrIndex()]; }
214protected: 247protected:
215 int m_dev_idx, m_dev_addr_idx; 248 int m_dev_idx, m_dev_addr_idx;
216}; 249};
@@ -222,9 +255,9 @@ public:
222 SocRegRef(const SocDevRef& dev, int reg_idx, int reg_addr_idx) 255 SocRegRef(const SocDevRef& dev, int reg_idx, int reg_addr_idx)
223 :SocDevRef(dev), m_reg_idx(reg_idx), m_reg_addr_idx(reg_addr_idx) {} 256 :SocDevRef(dev), m_reg_idx(reg_idx), m_reg_addr_idx(reg_addr_idx) {}
224 int GetRegIndex() const { return m_reg_idx; } 257 int GetRegIndex() const { return m_reg_idx; }
225 const soc_reg_t& GetReg() const { return GetDev().reg[GetRegIndex()]; } 258 soc_reg_t& GetReg() const { return GetDev().reg[GetRegIndex()]; }
226 int GetRegAddrIndex() const { return m_reg_addr_idx; } 259 int GetRegAddrIndex() const { return m_reg_addr_idx; }
227 const soc_reg_addr_t& GetRegAddr() const { return GetReg().addr[GetRegAddrIndex()]; } 260 soc_reg_addr_t& GetRegAddr() const { return GetReg().addr[GetRegAddrIndex()]; }
228protected: 261protected:
229 int m_reg_idx, m_reg_addr_idx; 262 int m_reg_idx, m_reg_addr_idx;
230}; 263};
@@ -236,7 +269,7 @@ public:
236 SocFieldRef(const SocRegRef& reg, int field_idx) 269 SocFieldRef(const SocRegRef& reg, int field_idx)
237 :SocRegRef(reg), m_field_idx(field_idx) {} 270 :SocRegRef(reg), m_field_idx(field_idx) {}
238 int GetFieldIndex() const { return m_field_idx; } 271 int GetFieldIndex() const { return m_field_idx; }
239 const soc_reg_field_t& GetField() const { return GetReg().field[GetFieldIndex()]; } 272 soc_reg_field_t& GetField() const { return GetReg().field[GetFieldIndex()]; }
240protected: 273protected:
241 int m_field_idx; 274 int m_field_idx;
242}; 275};
@@ -247,9 +280,9 @@ class Backend : public QObject
247public: 280public:
248 Backend(); 281 Backend();
249 282
250 QStringList GetSocNameList(); 283 QList< SocFileRef > GetSocFileList();
284 QList< SocRef > GetSocList();
251 bool LoadSocDesc(const QString& filename); 285 bool LoadSocDesc(const QString& filename);
252 bool GetSocByName(const QString& name, SocRef& s);
253 IoBackend *CreateDummyIoBackend(); 286 IoBackend *CreateDummyIoBackend();
254 IoBackend *CreateFileIoBackend(const QString& filename); 287 IoBackend *CreateFileIoBackend(const QString& filename);
255#ifdef HAVE_HWSTUB 288#ifdef HAVE_HWSTUB
@@ -259,7 +292,7 @@ public:
259signals: 292signals:
260 void OnSocListChanged(); 293 void OnSocListChanged();
261private: 294private:
262 std::list< soc_t > m_socs; 295 std::list< SocFile > m_socs;
263}; 296};
264 297
265class BackendHelper 298class BackendHelper
diff --git a/utils/regtools/qeditor/mainwindow.cpp b/utils/regtools/qeditor/mainwindow.cpp
index 2ba781b042..cd0926851c 100644
--- a/utils/regtools/qeditor/mainwindow.cpp
+++ b/utils/regtools/qeditor/mainwindow.cpp
@@ -12,6 +12,7 @@
12 12
13#include "mainwindow.h" 13#include "mainwindow.h"
14#include "regtab.h" 14#include "regtab.h"
15#include "regedit.h"
15 16
16MyTabWidget::MyTabWidget() 17MyTabWidget::MyTabWidget()
17{ 18{
@@ -20,23 +21,37 @@ MyTabWidget::MyTabWidget()
20 connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(OnCloseTab(int))); 21 connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(OnCloseTab(int)));
21} 22}
22 23
23void MyTabWidget::OnCloseTab(int index) 24bool MyTabWidget::CloseTab(int index)
24{ 25{
25 QWidget *w = this->widget(index); 26 QWidget *w = this->widget(index);
26 removeTab(index); 27 DocumentTab *doc = dynamic_cast< DocumentTab* >(w);
27 delete w; 28 if(doc->Quit())
29 {
30 removeTab(index);
31 delete w;
32 return true;
33 }
34 else
35 return false;
36}
37
38void MyTabWidget::OnCloseTab(int index)
39{
40 CloseTab(index);
28} 41}
29 42
30MainWindow::MainWindow(Backend *backend) 43MainWindow::MainWindow(Backend *backend)
31 :m_backend(backend) 44 :m_backend(backend)
32{ 45{
33 QAction *new_regtab_act = new QAction(QIcon::fromTheme("document-new"), tr("&Register Tab"), this); 46 QAction *new_regtab_act = new QAction(QIcon::fromTheme("document-new"), tr("Register &Tab"), this);
47 QAction *new_regedit_act = new QAction(QIcon::fromTheme("document-edit"), tr("Register &Editor"), this);
34 QAction *load_desc_act = new QAction(QIcon::fromTheme("document-open"), tr("&Soc Description"), this); 48 QAction *load_desc_act = new QAction(QIcon::fromTheme("document-open"), tr("&Soc Description"), this);
35 QAction *quit_act = new QAction(QIcon::fromTheme("application-exit"), tr("&Quit"), this); 49 QAction *quit_act = new QAction(QIcon::fromTheme("application-exit"), tr("&Quit"), this);
36 QAction *about_act = new QAction(QIcon::fromTheme("help-about"), tr("&About"), this); 50 QAction *about_act = new QAction(QIcon::fromTheme("help-about"), tr("&About"), this);
37 QAction *about_qt_act = new QAction(QIcon::fromTheme("help-about"), tr("About &Qt"), this); 51 QAction *about_qt_act = new QAction(QIcon::fromTheme("help-about"), tr("About &Qt"), this);
38 52
39 connect(new_regtab_act, SIGNAL(triggered()), this, SLOT(OnNewRegTab())); 53 connect(new_regtab_act, SIGNAL(triggered()), this, SLOT(OnNewRegTab()));
54 connect(new_regedit_act, SIGNAL(triggered()), this, SLOT(OnNewRegEdit()));
40 connect(load_desc_act, SIGNAL(triggered()), this, SLOT(OnLoadDesc())); 55 connect(load_desc_act, SIGNAL(triggered()), this, SLOT(OnLoadDesc()));
41 connect(quit_act, SIGNAL(triggered()), this, SLOT(OnQuit())); 56 connect(quit_act, SIGNAL(triggered()), this, SLOT(OnQuit()));
42 connect(about_act, SIGNAL(triggered()), this, SLOT(OnAbout())); 57 connect(about_act, SIGNAL(triggered()), this, SLOT(OnAbout()));
@@ -48,6 +63,7 @@ MainWindow::MainWindow(Backend *backend)
48 file_menu->addAction(quit_act); 63 file_menu->addAction(quit_act);
49 64
50 new_submenu->addAction(new_regtab_act); 65 new_submenu->addAction(new_regtab_act);
66 new_submenu->addAction(new_regedit_act);
51 67
52 load_submenu->addAction(load_desc_act); 68 load_submenu->addAction(load_desc_act);
53 69
@@ -91,6 +107,8 @@ void MainWindow::OnAboutQt()
91 107
92void MainWindow::closeEvent(QCloseEvent *event) 108void MainWindow::closeEvent(QCloseEvent *event)
93{ 109{
110 if(!Quit())
111 return event->ignore();
94 WriteSettings(); 112 WriteSettings();
95 event->accept(); 113 event->accept();
96} 114}
@@ -100,7 +118,7 @@ void MainWindow::OnLoadDesc()
100 QFileDialog *fd = new QFileDialog(this); 118 QFileDialog *fd = new QFileDialog(this);
101 fd->setFilter("XML files (*.xml);;All files (*)"); 119 fd->setFilter("XML files (*.xml);;All files (*)");
102 fd->setFileMode(QFileDialog::ExistingFiles); 120 fd->setFileMode(QFileDialog::ExistingFiles);
103 fd->setDirectory(Settings::Get()->value("mainwindow/loaddescdir", QDir::currentPath()).toString()); 121 fd->setDirectory(Settings::Get()->value("loaddescdir", QDir::currentPath()).toString());
104 if(fd->exec()) 122 if(fd->exec())
105 { 123 {
106 QStringList filenames = fd->selectedFiles(); 124 QStringList filenames = fd->selectedFiles();
@@ -111,11 +129,42 @@ void MainWindow::OnLoadDesc()
111 msg.setText(QString("Cannot load ") + filenames[i]); 129 msg.setText(QString("Cannot load ") + filenames[i]);
112 msg.exec(); 130 msg.exec();
113 } 131 }
114 Settings::Get()->setValue("mainwindow/loaddescdir", fd->directory().absolutePath()); 132 Settings::Get()->setValue("loaddescdir", fd->directory().absolutePath());
115 } 133 }
116} 134}
117 135
136void MainWindow::OnTabModified(bool modified)
137{
138 QWidget *sender = qobject_cast< QWidget* >(QObject::sender());
139 int index = m_tab->indexOf(sender);
140 if(modified)
141 m_tab->setTabIcon(index, QIcon::fromTheme("document-save"));
142 else
143 m_tab->setTabIcon(index, QIcon());
144}
145
146void MainWindow::AddTab(QWidget *tab, const QString& title)
147{
148 connect(tab, SIGNAL(OnModified(bool)), this, SLOT(OnTabModified(bool)));
149 m_tab->setCurrentIndex(m_tab->addTab(tab, title));
150}
151
118void MainWindow::OnNewRegTab() 152void MainWindow::OnNewRegTab()
119{ 153{
120 m_tab->addTab(new RegTab(m_backend), "Register Tab"); 154 AddTab(new RegTab(m_backend, this), "Register Tab");
155}
156
157void MainWindow::OnNewRegEdit()
158{
159 AddTab(new RegEdit(m_backend, this), "Register Editor");
160}
161
162bool MainWindow::Quit()
163{
164 while(m_tab->count() > 0)
165 {
166 if(!m_tab->CloseTab(0))
167 return false;
168 }
169 return true;
121} 170}
diff --git a/utils/regtools/qeditor/mainwindow.h b/utils/regtools/qeditor/mainwindow.h
index d7dab3717f..b32b0647f5 100644
--- a/utils/regtools/qeditor/mainwindow.h
+++ b/utils/regtools/qeditor/mainwindow.h
@@ -7,11 +7,19 @@
7#include "backend.h" 7#include "backend.h"
8#include "settings.h" 8#include "settings.h"
9 9
10class DocumentTab
11{
12public:
13 virtual bool Quit() = 0;
14 virtual void OnModified(bool modified) = 0;
15};
16
10class MyTabWidget : public QTabWidget 17class MyTabWidget : public QTabWidget
11{ 18{
12 Q_OBJECT 19 Q_OBJECT
13public: 20public:
14 MyTabWidget(); 21 MyTabWidget();
22 bool CloseTab(int index);
15 23
16private slots: 24private slots:
17 void OnCloseTab(int index); 25 void OnCloseTab(int index);
@@ -30,15 +38,21 @@ public:
30private: 38private:
31 void closeEvent(QCloseEvent *event); 39 void closeEvent(QCloseEvent *event);
32 40
41protected:
42 void AddTab(QWidget *tab, const QString& title);
43 bool Quit();
44
33private slots: 45private slots:
34 void OnQuit(); 46 void OnQuit();
35 void OnAbout(); 47 void OnAbout();
36 void OnAboutQt(); 48 void OnAboutQt();
37 void OnLoadDesc(); 49 void OnLoadDesc();
38 void OnNewRegTab(); 50 void OnNewRegTab();
51 void OnNewRegEdit();
52 void OnTabModified(bool modified);
39 53
40private: 54private:
41 QTabWidget *m_tab; 55 MyTabWidget *m_tab;
42 Backend *m_backend; 56 Backend *m_backend;
43}; 57};
44 58
diff --git a/utils/regtools/qeditor/qeditor.pro b/utils/regtools/qeditor/qeditor.pro
index 5604fe9d41..38d7c987bf 100644
--- a/utils/regtools/qeditor/qeditor.pro
+++ b/utils/regtools/qeditor/qeditor.pro
@@ -1,7 +1,9 @@
1QT += widgets 1QT += widgets
2 2
3HEADERS += mainwindow.h backend.h regtab.h analyser.h settings.h std_analysers.h 3HEADERS += mainwindow.h backend.h regtab.h analyser.h settings.h \
4SOURCES += main.cpp mainwindow.cpp regtab.cpp backend.cpp analyser.cpp std_analysers.cpp settings.cpp 4 std_analysers.h aux.h regdisplaypanel.h regedit.h
5SOURCES += main.cpp mainwindow.cpp regtab.cpp backend.cpp analyser.cpp \
6 std_analysers.cpp settings.cpp aux.cpp regdisplaypanel.cpp regedit.cpp
5LIBS += -L../lib/ -lsocdesc -lxml2 7LIBS += -L../lib/ -lsocdesc -lxml2
6INCLUDEPATH += ../lib/ ../../hwstub/lib 8INCLUDEPATH += ../lib/ ../../hwstub/lib
7 9
diff --git a/utils/regtools/qeditor/regdisplaypanel.cpp b/utils/regtools/qeditor/regdisplaypanel.cpp
new file mode 100644
index 0000000000..cef5f9807b
--- /dev/null
+++ b/utils/regtools/qeditor/regdisplaypanel.cpp
@@ -0,0 +1,314 @@
1#include "regdisplaypanel.h"
2#include <QHeaderView>
3#include <QDebug>
4
5/**
6 * RegItemEditorCreator
7 */
8
9QWidget *RegItemEditorCreator::createWidget(QWidget * parent) const
10{
11 return new RegLineEdit(parent);
12}
13
14QByteArray RegItemEditorCreator::valuePropertyName () const
15{
16 return QByteArray("text");
17}
18
19/**
20 * DevDisplayPanel
21 */
22DevDisplayPanel::DevDisplayPanel(QWidget *parent, const SocDevRef& dev_ref)
23 :QGroupBox(parent), m_dev(dev_ref), m_reg_font(font())
24{
25 QVBoxLayout *right_layout = new QVBoxLayout;
26 const soc_dev_addr_t& dev_addr = m_dev.GetDevAddr();
27
28 m_reg_font.setWeight(100);
29 m_reg_font.setKerning(false);
30
31 QString dev_name;
32 dev_name.sprintf("HW_%s_BASE", dev_addr.name.c_str());
33
34 QLabel *label_names = new QLabel("<b>" + dev_name + "</b>");
35 label_names->setTextFormat(Qt::RichText);
36
37 QLabel *label_addr = new QLabel("<b>" + QString().sprintf("0x%03x", dev_addr.addr) + "</b>");
38 label_addr->setTextFormat(Qt::RichText);
39
40 QHBoxLayout *top_layout = new QHBoxLayout;
41 top_layout->addStretch();
42 top_layout->addWidget(label_names);
43 top_layout->addWidget(label_addr);
44 top_layout->addStretch();
45
46 m_name = new QLabel(this);
47 m_name->setTextFormat(Qt::RichText);
48 m_name->setText("<h1>" + QString::fromStdString(m_dev.GetDev().long_name) + "</h1>");
49
50 m_desc = new QLabel(this);
51 m_name->setTextFormat(Qt::RichText);
52 m_desc->setText(QString::fromStdString(m_dev.GetDev().desc));
53
54 right_layout->addLayout(top_layout, 0);
55 right_layout->addWidget(m_name, 0);
56 right_layout->addWidget(m_desc, 0);
57 right_layout->addStretch(1);
58
59 setTitle("Device Description");
60 setLayout(right_layout);
61}
62
63void DevDisplayPanel::AllowWrite(bool en)
64{
65 Q_UNUSED(en);
66}
67
68QWidget *DevDisplayPanel::GetWidget()
69{
70 return this;
71}
72
73/**
74 * RegDisplayPanel
75 */
76
77RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const SocRegRef& reg_ref)
78 :QGroupBox(parent), m_io_backend(io_backend), m_reg(reg_ref), m_reg_font(font())
79{
80 bool read_only = m_io_backend->IsReadOnly();
81
82 QVBoxLayout *right_layout = new QVBoxLayout;
83
84 const soc_dev_addr_t& dev_addr = m_reg.GetDevAddr();
85 const soc_reg_t& reg = m_reg.GetReg();
86 const soc_reg_addr_t& reg_addr = m_reg.GetRegAddr();
87
88 m_reg_font.setWeight(100);
89 m_reg_font.setKerning(false);
90
91 QString reg_name;
92 reg_name.sprintf("HW_%s_%s", dev_addr.name.c_str(), reg_addr.name.c_str());
93 QStringList names;
94 QVector< soc_addr_t > addresses;
95 names.append(reg_name);
96 addresses.append(reg_addr.addr);
97 if(reg.flags & REG_HAS_SCT)
98 {
99 names.append(reg_name + "_SET");
100 names.append(reg_name + "_CLR");
101 names.append(reg_name + "_TOG");
102 addresses.append(reg_addr.addr + 4);
103 addresses.append(reg_addr.addr + 8);
104 addresses.append(reg_addr.addr + 12);
105 }
106
107 QString str;
108 str += "<table align=left>";
109 for(int i = 0; i < names.size(); i++)
110 str += "<tr><td><b>" + names[i] + "</b></td></tr>";
111 str += "</table>";
112 QLabel *label_names = new QLabel;
113 label_names->setTextFormat(Qt::RichText);
114 label_names->setText(str);
115
116 QString str_addr;
117 str_addr += "<table align=left>";
118 for(int i = 0; i < names.size(); i++)
119 str_addr += "<tr><td><b>" + QString().sprintf("0x%03x", addresses[i]) + "</b></td></tr>";
120 str_addr += "</table>";
121 QLabel *label_addr = new QLabel;
122 label_addr->setTextFormat(Qt::RichText);
123 label_addr->setText(str_addr);
124
125 QHBoxLayout *top_layout = new QHBoxLayout;
126 top_layout->addStretch();
127 top_layout->addWidget(label_names);
128 top_layout->addWidget(label_addr);
129 top_layout->addStretch();
130
131 m_raw_val_name = new QLabel;
132 m_raw_val_name->setText("Raw value:");
133 m_raw_val_edit = new RegLineEdit;
134 m_raw_val_edit->SetReadOnly(read_only);
135 m_raw_val_edit->GetLineEdit()->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
136 m_raw_val_edit->GetLineEdit()->setValidator(new SocFieldValidator(m_raw_val_edit));
137 m_raw_val_edit->EnableSCT(!!(reg.flags & REG_HAS_SCT));
138 m_raw_val_edit->GetLineEdit()->setFont(m_reg_font);
139 connect(m_raw_val_edit->GetLineEdit(), SIGNAL(returnPressed()), this, SLOT(OnRawRegValueReturnPressed()));
140 QHBoxLayout *raw_val_layout = new QHBoxLayout;
141 raw_val_layout->addStretch();
142 raw_val_layout->addWidget(m_raw_val_name);
143 raw_val_layout->addWidget(m_raw_val_edit);
144 raw_val_layout->addStretch();
145
146 m_value_table = new GrowingTableWidget;
147 m_value_table->setRowCount(reg.field.size());
148 m_value_table->setColumnCount(5);
149 for(size_t row = 0; row < reg.field.size(); row++)
150 {
151 const soc_reg_field_t& field = reg.field[row];
152 QString bits_str;
153 if(field.first_bit == field.last_bit)
154 bits_str.sprintf("%d", field.first_bit);
155 else
156 bits_str.sprintf("%d:%d", field.last_bit, field.first_bit);
157 QTableWidgetItem *item = new QTableWidgetItem(bits_str);
158 item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
159 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
160 m_value_table->setItem(row, 0, item);
161 item = new QTableWidgetItem(QString(field.name.c_str()));
162 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
163 m_value_table->setItem(row, 1, item);
164 item = new QTableWidgetItem(QString(field.desc.c_str()));
165 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
166 m_value_table->setItem(row, 4, item);
167 }
168 m_value_table->setHorizontalHeaderItem(0, new QTableWidgetItem("Bits"));
169 m_value_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Name"));
170 m_value_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Value"));
171 m_value_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Meaning"));
172 m_value_table->setHorizontalHeaderItem(4, new QTableWidgetItem("Description"));
173 m_value_table->verticalHeader()->setVisible(false);
174 m_value_table->resizeColumnsToContents();
175 m_value_table->horizontalHeader()->setStretchLastSection(true);
176 m_value_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
177
178 m_table_delegate = new QStyledItemDelegate(this);
179 m_table_edit_factory = new QItemEditorFactory();
180 m_regedit_creator = new RegItemEditorCreator();
181 m_table_edit_factory->registerEditor(QVariant::String, m_regedit_creator);
182 m_table_delegate->setItemEditorFactory(m_table_edit_factory);
183 m_value_table->setItemDelegate(m_table_delegate);
184
185 m_sexy_display = new RegSexyDisplay(reg_ref, this);
186 m_sexy_display->setFont(m_reg_font);
187
188 m_desc = new QLabel(this);
189 m_desc->setTextFormat(Qt::RichText);
190 m_desc->setText(QString::fromStdString(m_reg.GetReg().desc));
191
192 right_layout->addWidget(m_desc);
193 right_layout->addLayout(top_layout);
194 if(raw_val_layout)
195 right_layout->addLayout(raw_val_layout);
196 right_layout->addWidget(m_sexy_display);
197 right_layout->addWidget(m_value_table);
198
199 setTitle("Register Description");
200 m_viewport = new QWidget;
201 m_viewport->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
202 m_viewport->setLayout(right_layout);
203 m_scroll = new QScrollArea;
204 m_scroll->setWidget(m_viewport);
205 m_scroll->setWidgetResizable(true);
206 m_scroll->setFrameShape(QFrame::NoFrame);
207 QHBoxLayout *layout = new QHBoxLayout;
208 layout->addWidget(m_scroll, 1);
209 setLayout(layout);
210 AllowWrite(false);
211
212 // load data
213 Reload();
214}
215
216RegDisplayPanel::~RegDisplayPanel()
217{
218 delete m_table_edit_factory;
219}
220
221void RegDisplayPanel::Reload()
222{
223 const soc_dev_addr_t& dev_addr = m_reg.GetDevAddr();
224 const soc_reg_t& reg = m_reg.GetReg();
225 const soc_reg_addr_t& reg_addr = m_reg.GetRegAddr();
226 soc_word_t value;
227 BackendHelper helper(m_io_backend, m_reg);
228 bool has_value = helper.ReadRegister(dev_addr.name.c_str(), reg_addr.name.c_str(), value);
229
230 if(has_value)
231 {
232 m_raw_val_name->show();
233 m_raw_val_edit->show();
234 m_raw_val_edit->GetLineEdit()->setText(QString().sprintf("0x%08x", value));
235 }
236 else
237 {
238 m_raw_val_name->hide();
239 m_raw_val_edit->hide();
240 }
241
242 int row = 0;
243 foreach(const soc_reg_field_t& field, reg.field)
244 {
245 QTableWidgetItem *item = new QTableWidgetItem();
246 QTableWidgetItem *desc_item = new QTableWidgetItem();
247 if(has_value)
248 {
249 soc_word_t v = (value & field.bitmask()) >> field.first_bit;
250 QString value_name;
251 foreach(const soc_reg_field_value_t& rval, field.value)
252 if(v == rval.value)
253 value_name = rval.name.c_str();
254 const char *fmt = "%lu";
255 // heuristic
256 if((field.last_bit - field.first_bit + 1) > 16)
257 fmt = "0x%lx";
258 item->setText(QString().sprintf(fmt, (unsigned long)v));
259 item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
260
261 if(value_name.size() != 0)
262 {
263 desc_item->setText(value_name);
264 desc_item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
265 }
266 }
267 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
268 desc_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
269 m_value_table->setItem(row, 2, item);
270 m_value_table->setItem(row, 3, desc_item);
271 row++;
272 }
273}
274
275void RegDisplayPanel::AllowWrite(bool en)
276{
277 m_allow_write = en;
278 if(m_raw_val_edit)
279 m_raw_val_edit->SetReadOnly(m_io_backend->IsReadOnly() || !m_allow_write);
280}
281
282IoBackend::WriteMode RegDisplayPanel::EditModeToWriteMode(RegLineEdit::EditMode mode)
283{
284 switch(mode)
285 {
286 case RegLineEdit::Write: return IoBackend::Write;
287 case RegLineEdit::Set: return IoBackend::Set;
288 case RegLineEdit::Clear: return IoBackend::Clear;
289 case RegLineEdit::Toggle: return IoBackend::Toggle;
290 default: return IoBackend::Write;
291 }
292}
293
294void RegDisplayPanel::OnRawRegValueReturnPressed()
295{
296 soc_word_t val;
297 QLineEdit *edit = m_raw_val_edit->GetLineEdit();
298 const SocFieldValidator *validator = dynamic_cast< const SocFieldValidator *>(edit->validator());
299 QValidator::State state = validator->parse(edit->text(), val);
300 if(state != QValidator::Acceptable)
301 return;
302 IoBackend::WriteMode mode = EditModeToWriteMode(m_raw_val_edit->GetMode());
303 BackendHelper helper(m_io_backend, m_reg);
304 helper.WriteRegister(m_reg.GetDevAddr().name.c_str(), m_reg.GetRegAddr().name.c_str(),
305 val, mode);
306 // FIXME: we should notify the UI to read value back because it has changed
307 Reload();
308}
309
310QWidget *RegDisplayPanel::GetWidget()
311{
312 return this;
313}
314
diff --git a/utils/regtools/qeditor/regdisplaypanel.h b/utils/regtools/qeditor/regdisplaypanel.h
new file mode 100644
index 0000000000..444f3615f2
--- /dev/null
+++ b/utils/regtools/qeditor/regdisplaypanel.h
@@ -0,0 +1,77 @@
1#ifndef REGDISPLAYPANEL_H
2#define REGDISPLAYPANEL_H
3
4#include <QVBoxLayout>
5#include <QLabel>
6#include <QGroupBox>
7#include <QTableWidget>
8#include <QStyledItemDelegate>
9#include <QItemEditorCreatorBase>
10#include <QTextEdit>
11#include <QScrollArea>
12#include <soc_desc.hpp>
13#include "backend.h"
14#include "settings.h"
15#include "aux.h"
16#include "regtab.h"
17
18class RegItemEditorCreator : public QItemEditorCreatorBase
19{
20public:
21 RegItemEditorCreator() {}
22 virtual QWidget *createWidget(QWidget * parent) const;
23 virtual QByteArray valuePropertyName () const;
24};
25
26class DevDisplayPanel : public QGroupBox, public RegTabPanel
27{
28 Q_OBJECT
29public:
30 DevDisplayPanel(QWidget *parent, const SocDevRef& reg);
31 void Reload();
32 void AllowWrite(bool en);
33 QWidget *GetWidget();
34 bool Quit();
35
36protected:
37
38 const SocDevRef& m_dev;
39 QFont m_reg_font;
40 QLabel *m_name;
41 QLabel *m_desc;
42};
43
44class RegDisplayPanel : public QGroupBox, public RegTabPanel
45{
46 Q_OBJECT
47public:
48 RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const SocRegRef& reg);
49 ~RegDisplayPanel();
50 void AllowWrite(bool en);
51 void Reload();
52 QWidget *GetWidget();
53 bool Quit();
54
55protected:
56 IoBackend::WriteMode EditModeToWriteMode(RegLineEdit::EditMode mode);
57
58 IoBackend *m_io_backend;
59 const SocRegRef& m_reg;
60 bool m_allow_write;
61 RegLineEdit *m_raw_val_edit;
62 RegSexyDisplay *m_sexy_display;
63 GrowingTableWidget *m_value_table;
64 QStyledItemDelegate *m_table_delegate;
65 QItemEditorFactory *m_table_edit_factory;
66 RegItemEditorCreator *m_regedit_creator;
67 QLabel *m_raw_val_name;
68 QFont m_reg_font;
69 QLabel *m_desc;
70 QWidget *m_viewport;
71 QScrollArea *m_scroll;
72
73private slots:
74 void OnRawRegValueReturnPressed();
75};
76
77#endif /* REGDISPLAYPANEL_H */
diff --git a/utils/regtools/qeditor/regedit.cpp b/utils/regtools/qeditor/regedit.cpp
new file mode 100644
index 0000000000..5e498ce496
--- /dev/null
+++ b/utils/regtools/qeditor/regedit.cpp
@@ -0,0 +1,1324 @@
1#include "regedit.h"
2#include <QFileDialog>
3#include <QDebug>
4#include <QHeaderView>
5#include <QMessageBox>
6#include <QInputDialog>
7
8/**
9 * EmptyEditPanel
10 */
11EmptyEditPanel::EmptyEditPanel(QWidget *parent)
12 :QWidget(parent)
13{
14}
15
16/**
17 * SocEditPanel
18 */
19SocEditPanel::SocEditPanel(SocRef ref, QWidget *parent)
20 :QWidget(parent), m_ref(ref)
21{
22 m_name_group = new QGroupBox("Name", this);
23 m_name_edit = new QLineEdit(this);
24 m_name_edit->setText(QString::fromStdString(ref.GetSoc().name));
25 QVBoxLayout *name_group_layout = new QVBoxLayout;
26 name_group_layout->addWidget(m_name_edit);
27 m_name_group->setLayout(name_group_layout);
28
29 m_desc_group = new QGroupBox("Description", this);
30 QHBoxLayout *group_layout = new QHBoxLayout;
31 m_desc_edit = new MyTextEditor(this);
32 m_desc_edit->SetTextHtml(QString::fromStdString(ref.GetSoc().desc));
33 group_layout->addWidget(m_desc_edit);
34 m_desc_group->setLayout(group_layout);
35
36 QVBoxLayout *layout = new QVBoxLayout;
37 layout->addWidget(m_name_group);
38 layout->addWidget(m_desc_group);
39 layout->addStretch(1);
40
41 connect(m_name_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnNameEdited(const QString&)));
42 connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnTextEdited()));
43
44 setLayout(layout);
45}
46
47void SocEditPanel::OnNameEdited(const QString& text)
48{
49 m_ref.GetSoc().name = text.toStdString();
50 emit OnModified(m_name_edit->isModified());
51}
52
53void SocEditPanel::OnTextEdited()
54{
55 m_ref.GetSoc().desc = m_desc_edit->GetTextHtml().toStdString();
56 emit OnModified(m_desc_edit->IsModified());
57}
58
59/**
60 * DevEditPanel
61 */
62DevEditPanel::DevEditPanel(SocDevRef ref, QWidget *parent)
63 :QWidget(parent), m_ref(ref)
64{
65 m_name_group = new QGroupBox("Name", this);
66 m_name_edit = new QLineEdit(this);
67 m_name_edit->setText(QString::fromStdString(ref.GetDev().name));
68 QVBoxLayout *name_group_layout = new QVBoxLayout;
69 name_group_layout->addWidget(m_name_edit);
70 m_name_group->setLayout(name_group_layout);
71
72 m_long_name_group = new QGroupBox("Long Name", this);
73 m_long_name_edit = new QLineEdit(this);
74 m_long_name_edit->setText(QString::fromStdString(ref.GetDev().long_name));
75 QVBoxLayout *long_name_group_layout = new QVBoxLayout;
76 long_name_group_layout->addWidget(m_long_name_edit);
77 m_long_name_group->setLayout(long_name_group_layout);
78
79 m_version_group = new QGroupBox("Version", this);
80 m_version_edit = new QLineEdit(this);
81 m_version_edit->setText(QString::fromStdString(ref.GetDev().version));
82 QVBoxLayout *version_group_layout = new QVBoxLayout;
83 version_group_layout->addWidget(m_version_edit);
84 m_version_group->setLayout(version_group_layout);
85
86 QVBoxLayout *name_ver_layout = new QVBoxLayout;
87 name_ver_layout->addWidget(m_name_group);
88 name_ver_layout->addWidget(m_long_name_group);
89 name_ver_layout->addWidget(m_version_group);
90 name_ver_layout->addStretch();
91
92 m_instances_table = new QTableWidget(this);
93 m_instances_table->setRowCount(ref.GetDev().addr.size() + 1);
94 m_instances_table->setColumnCount(3);
95 for(size_t row = 0; row < ref.GetDev().addr.size(); row++)
96 FillRow(row, ref.GetDev().addr[row]);
97 CreateNewRow(ref.GetDev().addr.size());
98 m_instances_table->setHorizontalHeaderItem(0, new QTableWidgetItem(""));
99 m_instances_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Name"));
100 m_instances_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Address"));
101 m_instances_table->verticalHeader()->setVisible(false);
102 m_instances_table->resizeColumnsToContents();
103 m_instances_table->horizontalHeader()->setStretchLastSection(true);
104 m_instances_table->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
105 m_instances_group = new QGroupBox("Instances", this);
106 QHBoxLayout *instances_group_layout = new QHBoxLayout;
107 instances_group_layout->addWidget(m_instances_table);
108 m_instances_group->setLayout(instances_group_layout);
109
110 QHBoxLayout *top_layout = new QHBoxLayout;
111 top_layout->addWidget(m_instances_group);
112 top_layout->addLayout(name_ver_layout);
113 top_layout->addStretch();
114
115 m_desc_group = new QGroupBox("Description", this);
116 QHBoxLayout *group_layout = new QHBoxLayout;
117 m_desc_edit = new MyTextEditor(this);
118 m_desc_edit->SetTextHtml(QString::fromStdString(ref.GetDev().desc));
119 group_layout->addWidget(m_desc_edit);
120 m_desc_group->setLayout(group_layout);
121
122 QVBoxLayout *layout = new QVBoxLayout;
123 layout->addLayout(top_layout, 0);
124 layout->addWidget(m_desc_group, 1);
125
126 setLayout(layout);
127
128 SocFieldItemDelegate *m_table_delegate = new SocFieldItemDelegate(this);
129 QItemEditorFactory *m_table_edit_factory = new QItemEditorFactory();
130 SocFieldEditorCreator *m_table_edit_creator = new SocFieldEditorCreator();
131 m_table_edit_factory->registerEditor(QVariant::UInt, m_table_edit_creator);
132 m_table_delegate->setItemEditorFactory(m_table_edit_factory);
133 m_instances_table->setItemDelegate(m_table_delegate);
134
135 connect(m_instances_table, SIGNAL(cellActivated(int,int)), this, SLOT(OnInstActivated(int,int)));
136 connect(m_instances_table, SIGNAL(cellChanged(int,int)), this, SLOT(OnInstChanged(int,int)));
137 connect(m_name_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnNameEdited(const QString&)));
138 connect(m_long_name_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnLongNameEdited(const QString&)));
139 connect(m_version_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnVersionEdited(const QString&)));
140 connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnDescEdited()));
141}
142
143void DevEditPanel::OnNameEdited(const QString& text)
144{
145 m_ref.GetDev().name = text.toStdString();
146 emit OnModified(m_name_edit->isModified());
147}
148
149void DevEditPanel::OnLongNameEdited(const QString& text)
150{
151 m_ref.GetDev().long_name = text.toStdString();
152 emit OnModified(m_long_name_edit->isModified());
153}
154
155void DevEditPanel::OnVersionEdited(const QString& text)
156{
157 m_ref.GetDev().version = text.toStdString();
158 emit OnModified(m_version_edit->isModified());
159}
160
161void DevEditPanel::OnDescEdited()
162{
163 m_ref.GetDev().desc = m_desc_edit->GetTextHtml().toStdString();
164 emit OnModified(m_desc_edit->IsModified());
165}
166
167void DevEditPanel::CreateNewRow(int row)
168{
169 QTableWidgetItem *item = new QTableWidgetItem(QIcon::fromTheme("list-add"), "", DevInstNewType);
170 item->setToolTip("New?");
171 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
172 m_instances_table->setItem(row, DevInstIconColumn, item);
173 item = new QTableWidgetItem("New instance...");
174 QFont font = item->font();
175 font.setItalic(true);
176 item->setFont(font);
177 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
178 m_instances_table->setItem(row, DevInstNameColumn, item);
179 item = new QTableWidgetItem("");
180 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
181 m_instances_table->setItem(row, DevInstAddrColumn, item);
182}
183
184void DevEditPanel::FillRow(int row, const soc_dev_addr_t& addr)
185{
186 QTableWidgetItem *item = new QTableWidgetItem(QString::fromStdString(addr.name));
187 item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
188 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
189 m_instances_table->setItem(row, DevInstNameColumn, item);
190 item = new QTableWidgetItem();
191 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
192 item->setData(Qt::DisplayRole, QVariant(addr.addr));
193 m_instances_table->setItem(row, DevInstAddrColumn, item);
194 item = new QTableWidgetItem(QIcon::fromTheme("list-remove"), "", DevInstDeleteType);
195 item->setToolTip("Remove?");
196 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
197 m_instances_table->setItem(row, DevInstIconColumn, item);
198}
199
200void DevEditPanel::OnInstActivated(int row, int column)
201{
202 if(column != 0)
203 return;
204 int type = m_instances_table->item(row, column)->type();
205 if(type == DevInstDeleteType)
206 {
207 m_ref.GetDev().addr.erase(m_ref.GetDev().addr.begin() + row);
208 m_instances_table->removeRow(row);
209 }
210 else if(type == DevInstNewType)
211 {
212 m_instances_table->insertRow(row);
213 soc_dev_addr_t addr;
214 addr.name = QString("UNNAMED_%1").arg(row).toStdString();
215 addr.addr = 0;
216 m_ref.GetDev().addr.push_back(addr);
217 FillRow(row, addr);
218 }
219}
220
221void DevEditPanel::OnInstChanged(int row, int column)
222{
223 /* ignore extra row for addition */
224 if(row >= (int)m_ref.GetDev().addr.size())
225 return;
226 QTableWidgetItem *item = m_instances_table->item(row, column);
227 if(column == DevInstNameColumn)
228 {
229 m_ref.GetDev().addr[row].name = item->text().toStdString();
230 emit OnModified(true);
231 }
232 else if(column == DevInstAddrColumn)
233 {
234 m_ref.GetDev().addr[row].addr = item->data(Qt::DisplayRole).toUInt();
235 emit OnModified(true);
236 }
237}
238
239/**
240 * RegEditPanel
241 */
242
243RegEditPanel::RegEditPanel(SocRegRef ref, QWidget *parent)
244 :QWidget(parent), m_ref(ref), m_reg_font(font())
245{
246 m_reg_font.setWeight(100);
247 m_reg_font.setKerning(false);
248
249 m_name_group = new QGroupBox("Name", this);
250 m_name_edit = new QLineEdit(this);
251 m_name_edit->setText(QString::fromStdString(ref.GetReg().name));
252 QVBoxLayout *name_group_layout = new QVBoxLayout;
253 name_group_layout->addWidget(m_name_edit);
254 m_name_group->setLayout(name_group_layout);
255
256 m_instances_table = new QTableWidget(this);
257 m_instances_table->setRowCount(ref.GetReg().addr.size() + 1);
258 m_instances_table->setColumnCount(RegInstNrColumns);
259 for(size_t row = 0; row < ref.GetReg().addr.size(); row++)
260 FillRow(row, ref.GetReg().addr[row]);
261 CreateNewAddrRow(ref.GetReg().addr.size());
262 m_instances_table->setHorizontalHeaderItem(RegInstIconColumn, new QTableWidgetItem(""));
263 m_instances_table->setHorizontalHeaderItem(RegInstNameColumn, new QTableWidgetItem("Name"));
264 m_instances_table->setHorizontalHeaderItem(RegInstAddrColumn, new QTableWidgetItem("Address"));
265 m_instances_table->verticalHeader()->setVisible(false);
266 m_instances_table->resizeColumnsToContents();
267 m_instances_table->horizontalHeader()->setStretchLastSection(true);
268 m_instances_table->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
269 m_instances_group = new QGroupBox("Instances", this);
270 QHBoxLayout *instances_group_layout = new QHBoxLayout;
271 instances_group_layout->addWidget(m_instances_table);
272 m_instances_group->setLayout(instances_group_layout);
273
274 m_desc_group = new QGroupBox("Description", this);
275 QHBoxLayout *group_layout = new QHBoxLayout;
276 m_desc_edit = new MyTextEditor(this);
277 m_desc_edit->SetTextHtml(QString::fromStdString(ref.GetReg().desc));
278 group_layout->addWidget(m_desc_edit);
279 m_desc_group->setLayout(group_layout);
280
281 bool has_sct = m_ref.GetReg().flags & REG_HAS_SCT;
282 m_sct_check = new QCheckBox("Set/Clear/Toggle", this);
283 m_sct_check->setCheckState(has_sct ? Qt::Checked : Qt::Unchecked);
284 QHBoxLayout *flags_layout = new QHBoxLayout;
285 flags_layout->addWidget(m_sct_check);
286 flags_layout->addStretch();
287 m_flags_group = new QGroupBox("Flags", this);
288 m_flags_group->setLayout(flags_layout);
289
290 m_formula_combo = new QComboBox(this);
291 m_formula_combo->addItem("None", QVariant(REG_FORMULA_NONE));
292 m_formula_combo->addItem("String", QVariant(REG_FORMULA_STRING));
293 m_formula_combo->setCurrentIndex(m_formula_combo->findData(QVariant(m_ref.GetReg().formula.type)));
294 m_formula_type_label = new QLabel("Type:", this);
295 QHBoxLayout *formula_top_layout = new QHBoxLayout;
296 formula_top_layout->addWidget(m_formula_type_label);
297 formula_top_layout->addWidget(m_formula_combo);
298 m_formula_string_edit = new QLineEdit(QString::fromStdString(ref.GetReg().formula.string), this);
299 QVBoxLayout *formula_layout = new QVBoxLayout;
300 formula_layout->addLayout(formula_top_layout);
301 formula_layout->addWidget(m_formula_string_edit);
302 m_formula_string_gen = new QPushButton("Generate", this);
303 formula_layout->addWidget(m_formula_string_gen);
304 m_formula_group = new QGroupBox("Formula", this);
305 m_formula_group->setLayout(formula_layout);
306
307 QVBoxLayout *name_layout = new QVBoxLayout;
308 name_layout->addWidget(m_name_group);
309 name_layout->addWidget(m_flags_group);
310 name_layout->addWidget(m_formula_group);
311 name_layout->addStretch();
312
313 QHBoxLayout *top_layout = new QHBoxLayout;
314 top_layout->addWidget(m_instances_group);
315 top_layout->addLayout(name_layout);
316 top_layout->addWidget(m_desc_group, 1);
317
318 m_sexy_display = new RegSexyDisplay(m_ref, this);
319 m_sexy_display->setFont(m_reg_font);
320
321 m_field_table = new QTableWidget;
322 m_field_table->setRowCount(m_ref.GetReg().field.size());
323 m_field_table->setColumnCount(4);
324 for(size_t row = 0; row < m_ref.GetReg().field.size(); row++)
325 {
326 const soc_reg_field_t& field = m_ref.GetReg().field[row];
327 QString bits_str;
328 if(field.first_bit == field.last_bit)
329 bits_str.sprintf("%d", field.first_bit);
330 else
331 bits_str.sprintf("%d:%d", field.last_bit, field.first_bit);
332 QTableWidgetItem *item = new QTableWidgetItem(bits_str);
333 item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
334 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
335 m_field_table->setItem(row, 1, item);
336 item = new QTableWidgetItem(QString(field.name.c_str()));
337 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
338 m_field_table->setItem(row, 2, item);
339 item = new QTableWidgetItem(QString(field.desc.c_str()));
340 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
341 m_field_table->setItem(row, 3, item);
342 UpdateWarning(row);
343 }
344 m_field_table->setHorizontalHeaderItem(0, new QTableWidgetItem(""));
345 m_field_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Bits"));
346 m_field_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Name"));
347 m_field_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Description"));
348 m_field_table->verticalHeader()->setVisible(false);
349 m_field_table->resizeColumnsToContents();
350 m_field_table->horizontalHeader()->setStretchLastSection(true);
351 QHBoxLayout *field_layout = new QHBoxLayout;
352 field_layout->addWidget(m_field_table);
353 m_field_group = new QGroupBox("Flags", this);
354 m_field_group->setLayout(field_layout);
355
356 QVBoxLayout *layout = new QVBoxLayout;
357 layout->addLayout(top_layout, 0);
358 layout->addWidget(m_sexy_display, 0);
359 layout->addWidget(m_field_group);
360
361 UpdateFormula();
362
363 setLayout(layout);
364
365 SocFieldItemDelegate *m_table_delegate = new SocFieldItemDelegate(this);
366 QItemEditorFactory *m_table_edit_factory = new QItemEditorFactory();
367 SocFieldEditorCreator *m_table_edit_creator = new SocFieldEditorCreator();
368 m_table_edit_factory->registerEditor(QVariant::UInt, m_table_edit_creator);
369 m_table_delegate->setItemEditorFactory(m_table_edit_factory);
370 m_instances_table->setItemDelegate(m_table_delegate);
371
372 connect(m_instances_table, SIGNAL(cellActivated(int,int)), this, SLOT(OnInstActivated(int,int)));
373 connect(m_instances_table, SIGNAL(cellChanged(int,int)), this, SLOT(OnInstChanged(int,int)));
374 connect(m_name_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnNameEdited(const QString&)));
375 connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnDescEdited()));
376 connect(m_sct_check, SIGNAL(stateChanged(int)), this, SLOT(OnSctEdited(int)));
377 connect(m_formula_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFormulaChanged(int)));
378 connect(m_formula_string_edit, SIGNAL(textChanged(const QString&)), this,
379 SLOT(OnFormulaStringChanged(const QString&)));
380 connect(m_formula_string_gen, SIGNAL(clicked(bool)), this, SLOT(OnFormulaGenerate(bool)));
381}
382
383void RegEditPanel::UpdateWarning(int row)
384{
385 Q_UNUSED(row);
386}
387
388void RegEditPanel::OnFormulaStringChanged(const QString& text)
389{
390 m_ref.GetReg().formula.string = text.toStdString();
391 emit OnModified(true);
392}
393
394void RegEditPanel::OnFormulaGenerate(bool checked)
395{
396 Q_UNUSED(checked);
397 bool ok;
398 int count = QInputDialog::getInt(this, "Instance generator", "Number of instances",
399 0, 0, 100, 1, &ok);
400 if(!ok)
401 return;
402 std::string name(m_ref.GetReg().name);
403 size_t pos = name.find('n');
404 if(pos == std::string::npos)
405 {
406 name.push_back('n');
407 pos = name.size() - 1;
408 }
409 std::map< std::string, soc_word_t > map;
410 std::vector< std::pair< std::string, soc_word_t > > list;
411 std::string formula = m_ref.GetReg().formula.string;
412 for(int n = 0; n < count; n++)
413 {
414 map["n"] = n;
415 std::string err;
416 soc_word_t res;
417 if(!soc_desc_evaluate_formula(formula, map, res, err))
418 {
419 qDebug() << "Cannot evaluator " << QString::fromStdString(formula)
420 << "for n=" << n << ": " << QString::fromStdString(err);
421 return;
422 }
423 std::string regname = name;
424 std::string strn = QString("%1").arg(n).toStdString();
425 regname.replace(pos, 1, strn);
426 list.push_back(std::make_pair(regname, res));
427 }
428 // everything went good, commit result
429 while(m_instances_table->rowCount() > 1)
430 m_instances_table->removeRow(0);
431 m_ref.GetReg().addr.resize(list.size());
432 for(size_t i = 0; i < list.size(); i++)
433 {
434 m_instances_table->insertRow(i);
435 m_ref.GetReg().addr[i].name = list[i].first;
436 m_ref.GetReg().addr[i].addr = list[i].second;
437 FillRow(i, m_ref.GetReg().addr[i]);
438 }
439}
440
441void RegEditPanel::OnFormulaChanged(int index)
442{
443 if(index == -1)
444 return;
445 m_ref.GetReg().formula.type = static_cast< soc_reg_formula_type_t >(m_formula_combo->itemData(index).toInt());
446 UpdateFormula();
447 emit OnModified(true);
448}
449
450void RegEditPanel::UpdateFormula()
451{
452 m_formula_string_edit->hide();
453 m_formula_string_gen->hide();
454 switch(m_ref.GetReg().formula.type)
455 {
456 case REG_FORMULA_STRING:
457 m_formula_string_edit->show();
458 m_formula_string_gen->show();
459 break;
460 case REG_FORMULA_NONE:
461 default:
462 break;
463 }
464}
465
466void RegEditPanel::OnSctEdited(int state)
467{
468 if(state == Qt::Checked)
469 m_ref.GetReg().flags |= REG_HAS_SCT;
470 else
471 m_ref.GetReg().flags &= ~REG_HAS_SCT;
472 emit OnModified(true);
473}
474
475void RegEditPanel::FillRow(int row, const soc_reg_addr_t& addr)
476{
477 QTableWidgetItem *item = new QTableWidgetItem(QString::fromStdString(addr.name));
478 item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
479 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
480 m_instances_table->setItem(row, RegInstNameColumn, item);
481 item = new QTableWidgetItem();
482 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
483 item->setData(Qt::DisplayRole, QVariant(addr.addr));
484 m_instances_table->setItem(row, RegInstAddrColumn, item);
485 item = new QTableWidgetItem(QIcon::fromTheme("list-remove"), "", RegInstDeleteType);
486 item->setToolTip("Remove?");
487 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
488 m_instances_table->setItem(row, RegInstIconColumn, item);
489}
490
491void RegEditPanel::CreateNewAddrRow(int row)
492{
493 QTableWidgetItem *item = new QTableWidgetItem(QIcon::fromTheme("list-add"), "", RegInstNewType);
494 item->setToolTip("New?");
495 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
496 m_instances_table->setItem(row, RegInstIconColumn, item);
497 item = new QTableWidgetItem("New instance...");
498 QFont font = item->font();
499 font.setItalic(true);
500 item->setFont(font);
501 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
502 m_instances_table->setItem(row, RegInstNameColumn, item);
503 item = new QTableWidgetItem("");
504 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
505 m_instances_table->setItem(row, RegInstAddrColumn, item);
506}
507
508void RegEditPanel::OnNameEdited(const QString& text)
509{
510 m_ref.GetReg().name = text.toStdString();
511 emit OnModified(m_name_edit->isModified());
512}
513
514void RegEditPanel::OnDescEdited()
515{
516 m_ref.GetReg().desc = m_desc_edit->GetTextHtml().toStdString();
517 emit OnModified(m_desc_edit->IsModified());
518}
519
520void RegEditPanel::OnInstActivated(int row, int column)
521{
522 if(column != 0)
523 return;
524 int type = m_instances_table->item(row, column)->type();
525 if(type == RegInstDeleteType)
526 {
527 m_ref.GetReg().addr.erase(m_ref.GetReg().addr.begin() + row);
528 m_instances_table->removeRow(row);
529 }
530 else if(type == RegInstNewType)
531 {
532 m_instances_table->insertRow(row);
533 soc_reg_addr_t addr;
534 addr.name = QString("UNNAMED_%1").arg(row).toStdString();
535 addr.addr = 0;
536 m_ref.GetReg().addr.push_back(addr);
537 FillRow(row, addr);
538 }
539}
540
541void RegEditPanel::OnInstChanged(int row, int column)
542{
543 /* ignore extra row for addition */
544 if(row >= (int)m_ref.GetReg().addr.size())
545 return;
546 QTableWidgetItem *item = m_instances_table->item(row, column);
547 if(column == RegInstNameColumn)
548 {
549 m_ref.GetReg().addr[row].name = item->text().toStdString();
550 emit OnModified(true);
551 }
552 else if(column == RegInstAddrColumn)
553 {
554 m_ref.GetReg().addr[row].addr = item->data(Qt::DisplayRole).toUInt();
555 emit OnModified(true);
556 }
557}
558
559/**
560 * FieldEditPanel
561 */
562FieldEditPanel::FieldEditPanel(SocFieldRef ref, QWidget *parent)
563 :QWidget(parent), m_ref(ref)
564{
565 m_name_group = new QGroupBox("Name", this);
566 m_name_edit = new QLineEdit(this);
567 m_name_edit->setText(QString::fromStdString(ref.GetField().name));
568 QVBoxLayout *name_group_layout = new QVBoxLayout;
569 name_group_layout->addWidget(m_name_edit);
570 m_name_group->setLayout(name_group_layout);
571
572 m_bitrange_group = new QGroupBox("Bit Range", this);
573 m_bitrange_edit = new QLineEdit(this);
574 const soc_reg_field_t& field = ref.GetField();
575 QString bits_str;
576 if(field.first_bit == field.last_bit)
577 bits_str.sprintf("%d", field.first_bit);
578 else
579 bits_str.sprintf("%d:%d", field.last_bit, field.first_bit);
580 m_bitrange_edit->setText(bits_str);
581 m_bitrange_edit->setValidator(new SocBitRangeValidator(m_bitrange_edit));
582 QVBoxLayout *bitrange_group_layout = new QVBoxLayout;
583 bitrange_group_layout->addWidget(m_bitrange_edit);
584 m_bitrange_group->setLayout(bitrange_group_layout);
585
586 m_desc_group = new QGroupBox("Description", this);
587 QHBoxLayout *group_layout = new QHBoxLayout;
588 m_desc_edit = new MyTextEditor(this);
589 m_desc_edit->SetTextHtml(QString::fromStdString(ref.GetField().desc));
590 group_layout->addWidget(m_desc_edit);
591 m_desc_group->setLayout(group_layout);
592
593 m_value_group = new QGroupBox("Values", this);
594 QHBoxLayout *value_layout = new QHBoxLayout;
595 m_value_table = new QTableWidget(this);
596 m_value_table->setRowCount(ref.GetField().value.size() + 1);
597 m_value_table->setColumnCount(FieldValueNrColumns);
598 for(size_t row = 0; row < ref.GetField().value.size(); row++)
599 FillRow(row, ref.GetField().value[row]);
600 CreateNewRow(ref.GetField().value.size());
601 m_value_table->setHorizontalHeaderItem(FieldValueIconColumn, new QTableWidgetItem(""));
602 m_value_table->setHorizontalHeaderItem(FieldValueNameColumn, new QTableWidgetItem("Name"));
603 m_value_table->setHorizontalHeaderItem(FieldValueValueColumn, new QTableWidgetItem("Value"));
604 m_value_table->setHorizontalHeaderItem(FieldValueDescColumn, new QTableWidgetItem("Description"));
605 m_value_table->verticalHeader()->setVisible(false);
606 m_value_table->horizontalHeader()->setStretchLastSection(true);
607 value_layout->addWidget(m_value_table);
608 m_value_group->setLayout(value_layout);
609
610 QHBoxLayout *line_layout = new QHBoxLayout;
611 line_layout->addWidget(m_name_group);
612 line_layout->addWidget(m_bitrange_group);
613 line_layout->addStretch();
614
615 QVBoxLayout *left_layout = new QVBoxLayout;
616 left_layout->addLayout(line_layout);
617 left_layout->addWidget(m_desc_group);
618 left_layout->addWidget(m_value_group, 1);
619
620 UpdateDelegates();
621
622 connect(m_name_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnNameEdited(const QString&)));
623 connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnDescEdited()));
624 connect(m_value_table, SIGNAL(cellActivated(int,int)), this, SLOT(OnValueActivated(int,int)));
625 connect(m_value_table, SIGNAL(cellChanged(int,int)), this, SLOT(OnValueChanged(int,int)));
626 connect(m_bitrange_edit, SIGNAL(textChanged(const QString&)), this, SLOT(OnBitRangeEdited(const QString&)));
627
628 setLayout(left_layout);
629}
630
631void FieldEditPanel::UpdateDelegates()
632{
633 SocFieldItemDelegate *m_table_delegate = new SocFieldItemDelegate(m_ref.GetField(), this);
634 QItemEditorFactory *m_table_edit_factory = new QItemEditorFactory();
635 SocFieldEditorCreator *m_table_edit_creator = new SocFieldEditorCreator(m_ref.GetField());
636 m_table_edit_factory->registerEditor(QVariant::UInt, m_table_edit_creator);
637 m_table_delegate->setItemEditorFactory(m_table_edit_factory);
638 m_value_table->setItemDelegate(m_table_delegate);
639 m_value_table->resizeColumnsToContents();
640}
641
642void FieldEditPanel::UpdateWarning(int row)
643{
644 soc_word_t val = m_ref.GetField().value[row].value;
645 soc_word_t max = m_ref.GetField().bitmask() >> m_ref.GetField().first_bit;
646 QTableWidgetItem *item = m_value_table->item(row, FieldValueValueColumn);
647 if(val > max)
648 {
649 item->setIcon(QIcon::fromTheme("dialog-warning"));
650 item->setToolTip("Value is too big for the field");
651 }
652 else
653 {
654 item->setIcon(QIcon());
655 item->setToolTip("");
656 }
657}
658
659void FieldEditPanel::FillRow(int row, const soc_reg_field_value_t& val)
660{
661 QTableWidgetItem *item = new QTableWidgetItem(QString::fromStdString(val.name));
662 item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
663 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
664 m_value_table->setItem(row, FieldValueNameColumn, item);
665 item = new QTableWidgetItem();
666 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
667 item->setData(Qt::DisplayRole, QVariant(val.value));
668 m_value_table->setItem(row, FieldValueValueColumn, item);
669 item = new QTableWidgetItem(QString::fromStdString(val.desc));
670 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
671 m_value_table->setItem(row, FieldValueDescColumn, item);
672 item = new QTableWidgetItem(QIcon::fromTheme("list-remove"), "", FieldValueDeleteType);
673 item->setToolTip("Remove?");
674 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
675 m_value_table->setItem(row, FieldValueIconColumn, item);
676 UpdateWarning(row);
677}
678
679void FieldEditPanel::CreateNewRow(int row)
680{
681 QTableWidgetItem *item = new QTableWidgetItem(QIcon::fromTheme("list-add"), "", FieldValueNewType);
682 item->setToolTip("New?");
683 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
684 m_value_table->setItem(row, FieldValueIconColumn, item);
685 item = new QTableWidgetItem("New value...");
686 QFont font = item->font();
687 font.setItalic(true);
688 item->setFont(font);
689 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
690 m_value_table->setItem(row, FieldValueNameColumn, item);
691}
692
693void FieldEditPanel::OnBitRangeEdited(const QString& input)
694{
695 const SocBitRangeValidator *validator =
696 dynamic_cast< const SocBitRangeValidator *>(m_bitrange_edit->validator());
697 int first, last;
698 QValidator::State state = validator->parse(input, last, first);
699 if(state != QValidator::Acceptable)
700 return;
701 m_ref.GetField().first_bit = first;
702 m_ref.GetField().last_bit = last;
703 // update all warning signs
704 for(size_t row = 0; row < m_ref.GetField().value.size(); row++)
705 UpdateWarning(row);
706 // also updates delegates because they now have the wrong view of the field
707 UpdateDelegates();
708 emit OnModified(true);
709}
710
711void FieldEditPanel::OnNameEdited(const QString& text)
712{
713 m_ref.GetField().name = text.toStdString();
714 emit OnModified(m_name_edit->isModified());
715}
716
717void FieldEditPanel::OnDescEdited()
718{
719 m_ref.GetField().desc = m_desc_edit->GetTextHtml().toStdString();
720 emit OnModified(m_desc_edit->IsModified());
721}
722
723void FieldEditPanel::OnValueActivated(int row, int column)
724{
725 if(column != 0)
726 return;
727 int type = m_value_table->item(row, column)->type();
728 if(type == FieldValueDeleteType)
729 {
730 m_ref.GetField().value.erase(m_ref.GetField().value.begin() + row);
731 m_value_table->removeRow(row);
732 }
733 else if(type == FieldValueNewType)
734 {
735 m_value_table->insertRow(row);
736 soc_reg_field_value_t val;
737 val.name = QString("UNNAMED_%1").arg(row).toStdString();
738 val.value = 0;
739 m_ref.GetField().value.push_back(val);
740 FillRow(row, val);
741 }
742}
743
744void FieldEditPanel::OnValueChanged(int row, int column)
745{
746 /* ignore extra row for addition */
747 if(row >= (int)m_ref.GetField().value.size())
748 return;
749 QTableWidgetItem *item = m_value_table->item(row, column);
750 if(column == FieldValueNameColumn)
751 m_ref.GetField().value[row].name = item->text().toStdString();
752 else if(column == FieldValueValueColumn)
753 {
754 soc_word_t& fval = m_ref.GetField().value[row].value;
755 soc_word_t new_val = item->data(Qt::DisplayRole).toUInt();
756 /* avoid infinite recursion by calling UpdateWarning() when
757 * only the icon changes which would trigger this callback again */
758 if(fval != new_val)
759 {
760 fval = new_val;
761 UpdateWarning(row);
762 }
763 }
764 else if(column == FieldValueDescColumn)
765 m_ref.GetField().value[row].desc = item->text().toStdString();
766 emit OnModified(true);
767}
768
769namespace
770{
771
772enum
773{
774 SocTreeSocType = QTreeWidgetItem::UserType,
775 SocTreeDevType,
776 SocTreeRegType,
777 SocTreeFieldType,
778 SocTreeNewDevType,
779 SocTreeNewRegType,
780 SocTreeNewFieldType,
781};
782
783/**
784 * SocTreeItem
785 */
786
787class SocTreeItem : public QTreeWidgetItem
788{
789public:
790 SocTreeItem(const QString& string, const SocRef& ref)
791 :QTreeWidgetItem(QStringList(string), SocTreeSocType), m_ref(ref) {}
792
793 const SocRef& GetRef() { return m_ref; }
794private:
795 SocRef m_ref;
796};
797
798/**
799 * NewDevTreeItem
800 */
801
802class NewDevTreeItem : public QTreeWidgetItem
803{
804public:
805 NewDevTreeItem(const QString& string, const SocRef& ref)
806 :QTreeWidgetItem(QStringList(string), SocTreeNewDevType), m_ref(ref) {}
807
808 const SocRef& GetRef() { return m_ref; }
809private:
810 SocRef m_ref;
811};
812
813/**
814 * DevTreeItem
815 */
816
817class DevTreeItem : public QTreeWidgetItem
818{
819public:
820 DevTreeItem(const QString& string, const SocDevRef& ref)
821 :QTreeWidgetItem(QStringList(string), SocTreeDevType), m_ref(ref) {}
822
823 const SocDevRef& GetRef() { return m_ref; }
824private:
825 SocDevRef m_ref;
826};
827
828/**
829 * NewRegTreeItem
830 */
831
832class NewRegTreeItem : public QTreeWidgetItem
833{
834public:
835 NewRegTreeItem(const QString& string, const SocDevRef& ref)
836 :QTreeWidgetItem(QStringList(string), SocTreeNewRegType), m_ref(ref) {}
837
838 const SocDevRef& GetRef() { return m_ref; }
839private:
840 SocDevRef m_ref;
841};
842
843/**
844 * RegTreeItem
845 */
846
847class RegTreeItem : public QTreeWidgetItem
848{
849public:
850 RegTreeItem(const QString& string, const SocRegRef& ref)
851 :QTreeWidgetItem(QStringList(string), SocTreeRegType), m_ref(ref) {}
852
853 const SocRegRef& GetRef() { return m_ref; }
854private:
855 SocRegRef m_ref;
856};
857
858/**
859 * NewFieldTreeItem
860 */
861
862class NewFieldTreeItem : public QTreeWidgetItem
863{
864public:
865 NewFieldTreeItem(const QString& string, const SocRegRef& ref)
866 :QTreeWidgetItem(QStringList(string), SocTreeNewFieldType), m_ref(ref) {}
867
868 const SocRegRef& GetRef() { return m_ref; }
869private:
870 SocRegRef m_ref;
871};
872
873/**
874 * FieldTreeItem
875 */
876
877class FieldTreeItem : public QTreeWidgetItem
878{
879public:
880 FieldTreeItem(const QString& string, const SocFieldRef& ref)
881 :QTreeWidgetItem(QStringList(string), SocTreeFieldType), m_ref(ref) {}
882
883 const SocFieldRef& GetRef() { return m_ref; }
884private:
885 SocFieldRef m_ref;
886};
887
888}
889
890/**
891 * RegEdit
892 */
893RegEdit::RegEdit(Backend *backend, QWidget *parent)
894 :QWidget(parent), m_backend(backend)
895{
896 QVBoxLayout *m_vert_layout = new QVBoxLayout();
897 m_file_group = new QGroupBox("File selection", this);
898 QHBoxLayout *m_file_group_layout = new QHBoxLayout();
899 m_file_edit = new QLineEdit(this);
900 m_file_edit->setReadOnly(true);
901 m_file_open = new QToolButton(this);
902 m_file_open->setText("Open");
903 m_file_open->setIcon(QIcon::fromTheme("document-open"));
904 m_file_open->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
905 QMenu *file_open_menu = new QMenu(this);
906 QAction *new_act = file_open_menu->addAction(QIcon::fromTheme("document-new"), "New...");
907 m_file_open->setMenu(file_open_menu);
908
909 m_file_save = new QToolButton(this);
910 m_file_save->setText("Save");
911 m_file_save->setIcon(QIcon::fromTheme("document-save"));
912 m_file_save->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
913 QMenu *file_save_menu = new QMenu(this);
914 QAction *saveas_act = file_save_menu->addAction(QIcon::fromTheme("document-save-as"), "Save as...");
915 m_file_save->setMenu(file_save_menu);
916 m_file_group_layout->addWidget(m_file_open);
917 m_file_group_layout->addWidget(m_file_save);
918 m_file_group_layout->addWidget(m_file_edit);
919
920 m_splitter = new QSplitter(this);
921 m_soc_tree = new QTreeWidget(this);
922 m_soc_tree->setColumnCount(1);
923 m_soc_tree->setHeaderLabel(QString("Name"));
924 m_splitter->addWidget(m_soc_tree);
925 m_splitter->setStretchFactor(0, 0);
926
927 m_file_group->setLayout(m_file_group_layout);
928 m_vert_layout->addWidget(m_file_group);
929 m_vert_layout->addWidget(m_splitter, 1);
930
931 setLayout(m_vert_layout);
932
933 SetModified(false, false);
934 m_right_panel = 0;
935 SetPanel(new EmptyEditPanel(this));
936
937 connect(m_file_open, SIGNAL(clicked()), this, SLOT(OnOpen()));
938 connect(m_file_save, SIGNAL(clicked()), this, SLOT(OnSave()));
939 connect(new_act, SIGNAL(triggered()), this, SLOT(OnNew()));
940 connect(saveas_act, SIGNAL(triggered()), this, SLOT(OnSaveAs()));
941 connect(m_soc_tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
942 this, SLOT(OnSocItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
943 connect(m_soc_tree, SIGNAL(itemActivated(QTreeWidgetItem*, int)),
944 this, SLOT(OnSocItemActivated(QTreeWidgetItem*, int)));
945}
946
947RegEdit::~RegEdit()
948{
949}
950
951void RegEdit::OnSave()
952{
953 SaveSoc();
954}
955
956void RegEdit::OnSaveAs()
957{
958 SaveSocAs();
959}
960
961bool RegEdit::CloseSoc()
962{
963 if(!m_modified)
964 return true;
965 QMessageBox msgBox;
966 msgBox.setText("The description has been modified.");
967 msgBox.setInformativeText("Do you want to save your changes?");
968 msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
969 msgBox.setDefaultButton(QMessageBox::Save);
970 int ret = msgBox.exec();
971 if(ret == QMessageBox::Discard)
972 return true;
973 if(ret == QMessageBox::Cancel)
974 return false;
975 return SaveSoc();
976}
977
978bool RegEdit::SaveSoc()
979{
980 if(m_file_edit->text().size() == 0)
981 return SaveSocAs();
982 else
983 return SaveSocFile(m_file_edit->text());
984}
985
986bool RegEdit::GetFilename(QString& filename, bool save)
987{
988 QFileDialog *fd = new QFileDialog(this);
989 if(save)
990 fd->setAcceptMode(QFileDialog::AcceptSave);
991 fd->setFilter("Description files (*.xml);;All files (*)");
992 fd->setDirectory(Settings::Get()->value("loaddescdir", QDir::currentPath()).toString());
993 if(fd->exec())
994 {
995 QStringList filenames = fd->selectedFiles();
996 filename = filenames[0];
997 Settings::Get()->setValue("loaddescdir", fd->directory().absolutePath());
998 return true;
999 }
1000 else
1001 return false;
1002}
1003
1004bool RegEdit::SaveSocAs()
1005{
1006 QString filename;
1007 if(!GetFilename(filename, true))
1008 return false;
1009 m_file_edit->setText(filename);
1010 return SaveSocFile(filename);
1011}
1012
1013void RegEdit::OnOpen()
1014{
1015 if(!CloseSoc())
1016 return;
1017 QString filename;
1018 if(!GetFilename(filename, false))
1019 return;
1020 LoadSocFile(filename);
1021}
1022
1023void RegEdit::OnNew()
1024{
1025 if(!CloseSoc())
1026 return;
1027 m_cur_socfile = SocFile();
1028 m_file_edit->setText("");
1029 SetModified(false, false);
1030 UpdateSocFile();
1031}
1032
1033bool RegEdit::SaveSocFile(const QString& filename)
1034{
1035 soc_desc_normalize(m_cur_socfile.GetSoc());
1036 if(!soc_desc_produce_xml(filename.toStdString(), m_cur_socfile.GetSoc()))
1037 {
1038 QMessageBox::warning(this, "The description was not saved",
1039 "There was an error when saving the file");
1040 return false;
1041 }
1042 m_soc_tree->clear();
1043 FillSocTree();
1044 SetModified(false, false);
1045 return true;
1046}
1047
1048void RegEdit::LoadSocFile(const QString& filename)
1049{
1050 m_cur_socfile = SocFile(filename);
1051 if(!m_cur_socfile.IsValid())
1052 {
1053 QMessageBox::warning(this, "The description was not loaded",
1054 "There was an error when loading the file");
1055 return;
1056 }
1057 m_file_edit->setText(filename);
1058 SetModified(false, false);
1059 UpdateSocFile();
1060}
1061
1062void RegEdit::CreateNewFieldItem(QTreeWidgetItem *_parent)
1063{
1064 RegTreeItem *parent = dynamic_cast< RegTreeItem* >(_parent);
1065 NewFieldTreeItem *newdev_item = new NewFieldTreeItem("New field...", parent->GetRef());
1066 MakeItalic(newdev_item, true);
1067 newdev_item->setIcon(0, QIcon::fromTheme("list-add"));
1068 parent->addChild(newdev_item);
1069}
1070
1071void RegEdit::FillRegTreeItem(QTreeWidgetItem *_item)
1072{
1073 RegTreeItem *item = dynamic_cast< RegTreeItem* >(_item);
1074 const soc_reg_t& reg = item->GetRef().GetReg();
1075 for(size_t i = 0; i < reg.field.size(); i++)
1076 {
1077 const soc_reg_field_t& field = reg.field[i];
1078 FieldTreeItem *field_item = new FieldTreeItem(QString::fromStdString(field.name),
1079 SocFieldRef(item->GetRef(), i));
1080 FixupEmptyItem(field_item);
1081 item->addChild(field_item);
1082 }
1083 CreateNewFieldItem(item);
1084}
1085
1086void RegEdit::CreateNewRegisterItem(QTreeWidgetItem *_parent)
1087{
1088 DevTreeItem *parent = dynamic_cast< DevTreeItem* >(_parent);
1089 NewRegTreeItem *newdev_item = new NewRegTreeItem("New register...", parent->GetRef());
1090 MakeItalic(newdev_item, true);
1091 newdev_item->setIcon(0, QIcon::fromTheme("list-add"));
1092 parent->addChild(newdev_item);
1093}
1094
1095void RegEdit::FillDevTreeItem(QTreeWidgetItem *_item)
1096{
1097 DevTreeItem *item = dynamic_cast< DevTreeItem* >(_item);
1098 const soc_dev_t& dev = item->GetRef().GetDev();
1099 for(size_t i = 0; i < dev.reg.size(); i++)
1100 {
1101 const soc_reg_t& reg = dev.reg[i];
1102 RegTreeItem *reg_item = new RegTreeItem(QString::fromStdString(reg.name),
1103 SocRegRef(item->GetRef(), i, -1));
1104 FixupEmptyItem(reg_item);
1105 FillRegTreeItem(reg_item);
1106 item->addChild(reg_item);
1107 }
1108 CreateNewRegisterItem(item);
1109}
1110
1111void RegEdit::CreateNewDeviceItem(QTreeWidgetItem *_parent)
1112{
1113 SocTreeItem *parent = dynamic_cast< SocTreeItem* >(_parent);
1114 NewDevTreeItem *newdev_item = new NewDevTreeItem("New device...", parent->GetRef());
1115 MakeItalic(newdev_item, true);
1116 newdev_item->setIcon(0, QIcon::fromTheme("list-add"));
1117 parent->addChild(newdev_item);
1118}
1119
1120void RegEdit::FillSocTreeItem(QTreeWidgetItem *_item)
1121{
1122 SocTreeItem *item = dynamic_cast< SocTreeItem* >(_item);
1123 const soc_t& soc = item->GetRef().GetSoc();
1124 for(size_t i = 0; i < soc.dev.size(); i++)
1125 {
1126 const soc_dev_t& reg = soc.dev[i];
1127 DevTreeItem *dev_item = new DevTreeItem(QString::fromStdString(reg.name),
1128 SocDevRef(item->GetRef(), i, -1));
1129 FixupEmptyItem(dev_item);
1130 FillDevTreeItem(dev_item);
1131 item->addChild(dev_item);
1132 }
1133 CreateNewDeviceItem(item);
1134}
1135
1136void RegEdit::FillSocTree()
1137{
1138 SocRef ref = m_cur_socfile.GetSocRef();
1139 SocTreeItem *soc_item = new SocTreeItem(
1140 QString::fromStdString(ref.GetSoc().name), ref);
1141 FixupEmptyItem(soc_item);
1142 FillSocTreeItem(soc_item);
1143 m_soc_tree->addTopLevelItem(soc_item);
1144 soc_item->setExpanded(true);
1145}
1146
1147void RegEdit::MakeItalic(QTreeWidgetItem *item, bool it)
1148{
1149 QFont font = item->font(0);
1150 font.setItalic(it);
1151 item->setFont(0, font);
1152}
1153
1154void RegEdit::FixupEmptyItem(QTreeWidgetItem *item)
1155{
1156 if(item->text(0).size() == 0)
1157 {
1158 item->setIcon(0, QIcon::fromTheme("dialog-error"));
1159 MakeItalic(item, true);
1160 item->setText(0, "Unnamed");
1161 }
1162 else
1163 {
1164 item->setIcon(0, QIcon::fromTheme("cpu"));
1165 MakeItalic(item, false);
1166 }
1167}
1168
1169void RegEdit::UpdateSocFile()
1170{
1171 m_soc_tree->clear();
1172 FillSocTree();
1173 SetPanel(new EmptyEditPanel(this));
1174}
1175
1176void RegEdit::SetPanel(QWidget *panel)
1177{
1178 delete m_right_panel;
1179 m_right_panel = panel;
1180 connect(m_right_panel, SIGNAL(OnModified(bool)), this, SLOT(OnSocModified(bool)));
1181 m_splitter->addWidget(m_right_panel);
1182 m_splitter->setStretchFactor(1, 2);
1183}
1184
1185void RegEdit::SetModified(bool add, bool mod)
1186{
1187 m_modified = add ? (m_modified || mod) : mod;
1188 emit OnModified(mod);
1189}
1190
1191void RegEdit::OnSocModified(bool modified)
1192{
1193 // we might need to update the name in the tree
1194 UpdateName(m_soc_tree->currentItem());
1195 if(modified)
1196 SetModified(true, true);
1197}
1198
1199void RegEdit::DisplaySoc(SocRef ref)
1200{
1201 SetPanel(new SocEditPanel(ref, this));
1202}
1203
1204void RegEdit::DisplayDev(SocDevRef ref)
1205{
1206 SetPanel(new DevEditPanel(ref, this));
1207}
1208
1209void RegEdit::DisplayReg(SocRegRef ref)
1210{
1211 SetPanel(new RegEditPanel(ref, this));
1212}
1213
1214void RegEdit::DisplayField(SocFieldRef ref)
1215{
1216 SetPanel(new FieldEditPanel(ref, this));
1217}
1218
1219void RegEdit::UpdateName(QTreeWidgetItem *current)
1220{
1221 if(current == 0)
1222 return;
1223 if(current->type() == SocTreeSocType)
1224 {
1225 SocTreeItem *item = dynamic_cast< SocTreeItem * >(current);
1226 item->setText(0, QString::fromStdString(item->GetRef().GetSoc().name));
1227 }
1228 else if(current->type() == SocTreeDevType)
1229 {
1230 DevTreeItem *item = dynamic_cast< DevTreeItem * >(current);
1231 item->setText(0, QString::fromStdString(item->GetRef().GetDev().name));
1232 }
1233 else if(current->type() == SocTreeRegType)
1234 {
1235 RegTreeItem *item = dynamic_cast< RegTreeItem * >(current);
1236 item->setText(0, QString::fromStdString(item->GetRef().GetReg().name));
1237 }
1238 else if(current->type() == SocTreeFieldType)
1239 {
1240 FieldTreeItem *item = dynamic_cast< FieldTreeItem * >(current);
1241 item->setText(0, QString::fromStdString(item->GetRef().GetField().name));
1242 }
1243 FixupEmptyItem(current);
1244}
1245
1246void RegEdit::OnSocItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
1247{
1248 Q_UNUSED(previous);
1249 if(current == 0)
1250 return;
1251 if(current->type() == SocTreeSocType)
1252 {
1253 SocTreeItem *item = dynamic_cast< SocTreeItem * >(current);
1254 DisplaySoc(item->GetRef());
1255 }
1256 else if(current->type() == SocTreeDevType)
1257 {
1258 DevTreeItem *item = dynamic_cast< DevTreeItem * >(current);
1259 DisplayDev(item->GetRef());
1260 }
1261 else if(current->type() == SocTreeRegType)
1262 {
1263 RegTreeItem *item = dynamic_cast< RegTreeItem * >(current);
1264 DisplayReg(item->GetRef());
1265 }
1266 else if(current->type() == SocTreeFieldType)
1267 {
1268 FieldTreeItem *item = dynamic_cast< FieldTreeItem * >(current);
1269 DisplayField(item->GetRef());
1270 }
1271}
1272
1273void RegEdit::OnSocItemActivated(QTreeWidgetItem *current, int column)
1274{
1275 Q_UNUSED(column);
1276 if(current == 0)
1277 return;
1278 if(current->type() == SocTreeNewDevType)
1279 AddDevice(current);
1280 else if(current->type() == SocTreeNewRegType)
1281 AddRegister(current);
1282 else if(current->type() == SocTreeNewFieldType)
1283 AddField(current);
1284}
1285
1286void RegEdit::AddDevice(QTreeWidgetItem *_item)
1287{
1288 NewDevTreeItem *item = dynamic_cast< NewDevTreeItem * >(_item);
1289 item->GetRef().GetSoc().dev.push_back(soc_dev_t());
1290 DevTreeItem *dev_item = new DevTreeItem("",
1291 SocDevRef(item->GetRef(), item->GetRef().GetSoc().dev.size() - 1, -1));
1292 FixupEmptyItem(dev_item);
1293 item->parent()->insertChild(item->parent()->indexOfChild(item), dev_item);
1294 CreateNewRegisterItem(dev_item);
1295 m_soc_tree->setCurrentItem(dev_item);
1296}
1297
1298void RegEdit::AddRegister(QTreeWidgetItem *_item)
1299{
1300 NewRegTreeItem *item = dynamic_cast< NewRegTreeItem * >(_item);
1301 item->GetRef().GetDev().reg.push_back(soc_reg_t());
1302 RegTreeItem *reg_item = new RegTreeItem("",
1303 SocRegRef(item->GetRef(), item->GetRef().GetDev().reg.size() - 1, -1));
1304 FixupEmptyItem(reg_item);
1305 item->parent()->insertChild(item->parent()->indexOfChild(item), reg_item);
1306 CreateNewFieldItem(reg_item);
1307 m_soc_tree->setCurrentItem(reg_item);
1308}
1309
1310void RegEdit::AddField(QTreeWidgetItem *_item)
1311{
1312 NewFieldTreeItem *item = dynamic_cast< NewFieldTreeItem * >(_item);
1313 item->GetRef().GetReg().field.push_back(soc_reg_field_t());
1314 FieldTreeItem *field_item = new FieldTreeItem("",
1315 SocFieldRef(item->GetRef(), item->GetRef().GetReg().field.size() - 1));
1316 FixupEmptyItem(field_item);
1317 item->parent()->insertChild(item->parent()->indexOfChild(item), field_item);
1318 m_soc_tree->setCurrentItem(field_item);
1319}
1320
1321bool RegEdit::Quit()
1322{
1323 return CloseSoc();
1324} \ No newline at end of file
diff --git a/utils/regtools/qeditor/regedit.h b/utils/regtools/qeditor/regedit.h
new file mode 100644
index 0000000000..8615816783
--- /dev/null
+++ b/utils/regtools/qeditor/regedit.h
@@ -0,0 +1,282 @@
1#ifndef REGEDIT_H
2#define REGEDIT_H
3
4#include <QComboBox>
5#include <QTreeWidget>
6#include <QVBoxLayout>
7#include <QTabWidget>
8#include <QSplitter>
9#include <QLineEdit>
10#include <QPushButton>
11#include <QLabel>
12#include <QListWidget>
13#include <QGroupBox>
14#include <QToolButton>
15#include <QMenu>
16#include <QCheckBox>
17#include <QRadioButton>
18#include <QButtonGroup>
19#include <QDebug>
20#include <QScrollArea>
21#include "backend.h"
22#include "settings.h"
23#include "mainwindow.h"
24#include "aux.h"
25
26class AbstractRegEditPanel
27{
28public:
29 AbstractRegEditPanel() {}
30 virtual ~AbstractRegEditPanel() {}
31 virtual void OnModified(bool mod) = 0;
32};
33
34class EmptyEditPanel : public QWidget, public AbstractRegEditPanel
35{
36 Q_OBJECT
37public:
38 EmptyEditPanel(QWidget *parent);
39
40signals:
41 void OnModified(bool mod);
42
43protected:
44};
45
46class SocEditPanel : public QWidget, public AbstractRegEditPanel
47{
48 Q_OBJECT
49public:
50 SocEditPanel(SocRef ref, QWidget *parent = 0);
51
52signals:
53 void OnModified(bool mod);
54
55protected slots:
56 void OnTextEdited();
57 void OnNameEdited(const QString& text);
58
59protected:
60 SocRef m_ref;
61 QGroupBox *m_name_group;
62 QLineEdit *m_name_edit;
63 QGroupBox *m_desc_group;
64 MyTextEditor *m_desc_edit;
65};
66
67class DevEditPanel : public QWidget, public AbstractRegEditPanel
68{
69 Q_OBJECT
70public:
71 DevEditPanel(SocDevRef ref, QWidget *parent = 0);
72
73signals:
74 void OnModified(bool mod);
75
76protected slots:
77 void OnInstActivated(int row, int column);
78 void OnInstChanged(int row, int column);
79 void OnNameEdited(const QString& text);
80 void OnLongNameEdited(const QString& text);
81 void OnVersionEdited(const QString& text);
82 void OnDescEdited();
83
84protected:
85 void FillRow(int row, const soc_dev_addr_t& addr);
86 void CreateNewRow(int row);
87
88 enum
89 {
90 DevInstDeleteType = QTableWidgetItem::UserType,
91 DevInstNewType
92 };
93
94 enum
95 {
96 DevInstIconColumn = 0,
97 DevInstNameColumn = 1,
98 DevInstAddrColumn = 2,
99 };
100
101 SocDevRef m_ref;
102 QGroupBox *m_name_group;
103 QLineEdit *m_name_edit;
104 QGroupBox *m_long_name_group;
105 QLineEdit *m_long_name_edit;
106 QGroupBox *m_version_group;
107 QLineEdit *m_version_edit;
108 QGroupBox *m_instances_group;
109 QTableWidget *m_instances_table;
110 QGroupBox *m_desc_group;
111 MyTextEditor *m_desc_edit;
112};
113
114class RegEditPanel : public QWidget, public AbstractRegEditPanel
115{
116 Q_OBJECT
117public:
118 RegEditPanel(SocRegRef ref, QWidget *parent = 0);
119
120signals:
121 void OnModified(bool mod);
122
123protected slots:
124 void OnInstActivated(int row, int column);
125 void OnInstChanged(int row, int column);
126 void OnNameEdited(const QString& text);
127 void OnDescEdited();
128 void OnSctEdited(int state);
129 void OnFormulaChanged(int index);
130 void OnFormulaStringChanged(const QString& text);
131 void OnFormulaGenerate(bool checked);
132
133protected:
134 void CreateNewAddrRow(int row);
135 void FillRow(int row, const soc_reg_addr_t& addr);
136 void UpdateFormula();
137 void UpdateWarning(int row);
138
139 enum
140 {
141 RegInstDeleteType = QTableWidgetItem::UserType,
142 RegInstNewType
143 };
144
145 enum
146 {
147 RegInstIconColumn = 0,
148 RegInstNameColumn,
149 RegInstAddrColumn,
150 RegInstNrColumns,
151 };
152
153 SocRegRef m_ref;
154 QGroupBox *m_name_group;
155 QLineEdit *m_name_edit;
156 QGroupBox *m_instances_group;
157 QTableWidget *m_instances_table;
158 QGroupBox *m_desc_group;
159 QGroupBox *m_flags_group;
160 QCheckBox *m_sct_check;
161 QFont m_reg_font;
162 QGroupBox *m_formula_group;
163 QButtonGroup *m_formula_radio_group;
164 QLabel *m_formula_type_label;
165 QComboBox *m_formula_combo;
166 QLineEdit *m_formula_string_edit;
167 QPushButton *m_formula_string_gen;
168 RegSexyDisplay *m_sexy_display;
169 MyTextEditor *m_desc_edit;
170 QGroupBox *m_field_group;
171 QTableWidget *m_field_table;
172};
173
174class FieldEditPanel : public QWidget, public AbstractRegEditPanel
175{
176 Q_OBJECT
177public:
178 FieldEditPanel(SocFieldRef ref, QWidget *parent = 0);
179
180signals:
181 void OnModified(bool mod);
182
183protected slots:
184 void OnDescEdited();
185 void OnNameEdited(const QString& text);
186 void OnBitRangeEdited(const QString& string);
187 void OnValueActivated(int row, int column);
188 void OnValueChanged(int row, int column);
189
190protected:
191 void CreateNewRow(int row);
192 void FillRow(int row, const soc_reg_field_value_t& val);
193 void UpdateWarning(int row);
194 void UpdateDelegates();
195
196 enum
197 {
198 FieldValueDeleteType = QTableWidgetItem::UserType,
199 FieldValueNewType,
200 };
201
202 enum
203 {
204 FieldValueIconColumn = 0,
205 FieldValueNameColumn,
206 FieldValueValueColumn,
207 FieldValueDescColumn,
208 FieldValueNrColumns,
209 };
210
211 SocFieldRef m_ref;
212 QGroupBox *m_name_group;
213 QLineEdit *m_name_edit;
214 QGroupBox *m_bitrange_group;
215 QLineEdit *m_bitrange_edit;
216 QGroupBox *m_desc_group;
217 MyTextEditor *m_desc_edit;
218 QGroupBox *m_value_group;
219 QTableWidget *m_value_table;
220};
221
222class RegEdit : public QWidget, public DocumentTab
223{
224 Q_OBJECT
225public:
226 RegEdit(Backend *backend, QWidget *parent = 0);
227 ~RegEdit();
228 virtual bool Quit();
229
230signals:
231 void OnModified(bool mod);
232
233protected slots:
234 void OnSocItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
235 void OnSocItemActivated(QTreeWidgetItem *current, int column);
236 void OnOpen();
237 void OnSave();
238 void OnSaveAs();
239 void OnSocModified(bool modified);
240 void OnNew();
241
242protected:
243 void LoadSocFile(const QString& filename);
244 void UpdateSocFile();
245 void FillSocTree();
246 void FillSocTreeItem(QTreeWidgetItem *_item);
247 void FillDevTreeItem(QTreeWidgetItem *_item);
248 void FillRegTreeItem(QTreeWidgetItem *_item);
249 void SetPanel(QWidget *panel);
250 void DisplaySoc(SocRef ref);
251 void DisplayDev(SocDevRef ref);
252 void DisplayReg(SocRegRef ref);
253 void DisplayField(SocFieldRef ref);
254 bool CloseSoc();
255 bool SaveSoc();
256 bool SaveSocAs();
257 bool SaveSocFile(const QString& filename);
258 bool GetFilename(QString& filename, bool save);
259 void SetModified(bool add, bool mod);
260 void FixupEmptyItem(QTreeWidgetItem *item);
261 void MakeItalic(QTreeWidgetItem *item, bool it);
262 void AddDevice(QTreeWidgetItem *item);
263 void AddRegister(QTreeWidgetItem *_item);
264 void UpdateName(QTreeWidgetItem *current);
265 void AddField(QTreeWidgetItem *_item);
266 void CreateNewDeviceItem(QTreeWidgetItem *parent);
267 void CreateNewRegisterItem(QTreeWidgetItem *parent);
268 void CreateNewFieldItem(QTreeWidgetItem *parent);
269
270 QGroupBox *m_file_group;
271 QToolButton *m_file_open;
272 QToolButton *m_file_save;
273 QLineEdit *m_file_edit;
274 QSplitter *m_splitter;
275 QTreeWidget *m_soc_tree;
276 Backend *m_backend;
277 bool m_modified;
278 SocFile m_cur_socfile;
279 QWidget *m_right_panel;
280};
281
282#endif /* REGEDIT_H */
diff --git a/utils/regtools/qeditor/regtab.cpp b/utils/regtools/qeditor/regtab.cpp
index 4cd4e7b283..568d859c0e 100644
--- a/utils/regtools/qeditor/regtab.cpp
+++ b/utils/regtools/qeditor/regtab.cpp
@@ -1,406 +1,75 @@
1#include "regtab.h" 1#include "regtab.h"
2 2
3#include <QSplitter>
4#include <QVBoxLayout>
5#include <QAbstractListModel>
6#include <QMessageBox>
7#include <QSizePolicy> 3#include <QSizePolicy>
8#include <QHBoxLayout>
9#include <QStringBuilder> 4#include <QStringBuilder>
10#include <QLabel>
11#include <QGridLayout>
12#include <QTableWidget>
13#include <QHeaderView>
14#include <QFileDialog> 5#include <QFileDialog>
15#include <QDebug> 6#include <QDebug>
16#include <QStyle> 7#include <QStyle>
17#include "backend.h" 8#include "backend.h"
18#include "analyser.h" 9#include "analyser.h"
10#include "regdisplaypanel.h"
19 11
20/** 12namespace
21 * SocFieldValidator
22 */
23
24SocFieldValidator::SocFieldValidator(QObject *parent)
25 :QValidator(parent)
26{
27 m_field.first_bit = 0;
28 m_field.last_bit = 31;
29}
30
31SocFieldValidator::SocFieldValidator(const soc_reg_field_t& field, QObject *parent)
32 :QValidator(parent), m_field(field)
33{
34}
35
36void SocFieldValidator::fixup(QString& input) const
37{
38 input = input.trimmed();
39}
40
41QValidator::State SocFieldValidator::validate(QString& input, int& pos) const
42{
43 (void) pos;
44 soc_word_t val;
45 State state = parse(input, val);
46 return state;
47}
48
49QValidator::State SocFieldValidator::parse(const QString& input, soc_word_t& val) const
50{
51 // the empty string is all alwats intermediate
52 if(input.size() == 0)
53 return Intermediate;
54 // first check named values
55 State state = Invalid;
56 foreach(const soc_reg_field_value_t& value, m_field.value)
57 {
58 QString name = QString::fromLocal8Bit(value.name.c_str());
59 // cannot be a substring if too long or empty
60 if(input.size() > name.size())
61 continue;
62 // check equal string
63 if(input == name)
64 {
65 state = Acceptable;
66 val = value.value;
67 break;
68 }
69 // check substring
70 if(name.startsWith(input))
71 state = Intermediate;
72 }
73 // early return for exact match
74 if(state == Acceptable)
75 return state;
76 // do a few special cases for convenience
77 if(input.compare("0x", Qt::CaseInsensitive) == 0 ||
78 input.compare("0b", Qt::CaseInsensitive) == 0)
79 return Intermediate;
80 // try by parsing
81 unsigned basis, pos;
82 if(input.size() >= 2 && input.startsWith("0x", Qt::CaseInsensitive))
83 {
84 basis = 16;
85 pos = 2;
86 }
87 else if(input.size() >= 2 && input.startsWith("0b", Qt::CaseInsensitive))
88 {
89 basis = 2;
90 pos = 2;
91 }
92 else if(input.size() >= 2 && input.startsWith("0"))
93 {
94 basis = 8;
95 pos = 1;
96 }
97 else
98 {
99 basis = 10;
100 pos = 0;
101 }
102 bool ok = false;
103 unsigned long v = input.mid(pos).toULong(&ok, basis);
104 // if not ok, return result of name parsing
105 if(!ok)
106 return state;
107 // if ok, check if it fits in the number of bits
108 unsigned nr_bits = m_field.last_bit - m_field.first_bit + 1;
109 unsigned long max = nr_bits == 32 ? 0xffffffff : (1 << nr_bits) - 1;
110 if(v <= max)
111 {
112 val = v;
113 return Acceptable;
114 }
115
116 return state;
117}
118
119/**
120 * RegLineEdit
121 */
122RegLineEdit::RegLineEdit(QWidget *parent)
123 :QWidget(parent)
124{ 13{
125 m_layout = new QHBoxLayout(this);
126 m_button = new QToolButton(this);
127 m_button->setCursor(Qt::ArrowCursor);
128 m_button->setStyleSheet("QToolButton { font-weight: bold; color: white; background: black; }");
129 m_button->setPopupMode(QToolButton::InstantPopup);
130 m_edit = new QLineEdit(this);
131 m_layout->addWidget(m_button);
132 m_layout->addWidget(m_edit);
133 m_menu = new QMenu(this);
134 connect(m_menu->addAction("Write"), SIGNAL(triggered()), this, SLOT(OnWriteAct()));
135 connect(m_menu->addAction("Set"), SIGNAL(triggered()), this, SLOT(OnSetAct()));
136 connect(m_menu->addAction("Clear"), SIGNAL(triggered()), this, SLOT(OnClearAct()));
137 connect(m_menu->addAction("Toggle"), SIGNAL(triggered()), this, SLOT(OnToggleAct()));
138 EnableSCT(false);
139 SetReadOnly(false);
140 ShowMode(true);
141 SetMode(Write);
142}
143 14
144void RegLineEdit::SetReadOnly(bool ro) 15enum
145{ 16{
146 m_edit->setReadOnly(ro); 17 RegTreeDevType = QTreeWidgetItem::UserType,
147 m_readonly = ro; 18 RegTreeRegType
148 ShowMode(!ro); 19};
149}
150 20
151void RegLineEdit::EnableSCT(bool en) 21class DevTreeItem : public QTreeWidgetItem
152{ 22{
153 m_has_sct = en; 23public:
154 if(!m_has_sct) 24 DevTreeItem(const QString& string, const SocDevRef& ref)
155 { 25 :QTreeWidgetItem(QStringList(string), RegTreeDevType), m_ref(ref) {}
156 m_button->setMenu(0);
157 SetMode(Write);
158 }
159 else
160 m_button->setMenu(m_menu);
161}
162
163RegLineEdit::~RegLineEdit()
164{
165}
166 26
167QLineEdit *RegLineEdit::GetLineEdit() 27 const SocDevRef& GetRef() { return m_ref; }
168{ 28private:
169 return m_edit; 29 SocDevRef m_ref;
170} 30};
171 31
172void RegLineEdit::ShowMode(bool show) 32class RegTreeItem : public QTreeWidgetItem
173{ 33{
174 if(show) 34public:
175 m_button->show(); 35 RegTreeItem(const QString& string, const SocRegRef& ref)
176 else 36 :QTreeWidgetItem(QStringList(string), RegTreeRegType), m_ref(ref) {}
177 m_button->hide();
178}
179 37
180void RegLineEdit::OnWriteAct() 38 const SocRegRef& GetRef() { return m_ref; }
181{ 39private:
182 SetMode(Write); 40 SocRegRef m_ref;
183} 41};
184
185void RegLineEdit::OnSetAct()
186{
187 SetMode(Set);
188}
189
190void RegLineEdit::OnClearAct()
191{
192 SetMode(Clear);
193}
194
195void RegLineEdit::OnToggleAct()
196{
197 SetMode(Toggle);
198}
199
200void RegLineEdit::SetMode(EditMode mode)
201{
202 m_mode = mode;
203 switch(m_mode)
204 {
205 case Write: m_button->setText("WR"); break;
206 case Set: m_button->setText("SET"); break;
207 case Clear: m_button->setText("CLR"); break;
208 case Toggle: m_button->setText("TOG"); break;
209 default: break;
210 }
211}
212 42
213RegLineEdit::EditMode RegLineEdit::GetMode()
214{
215 return m_mode;
216} 43}
217 44
218/** 45/**
219 * RegDisplayPanel 46 * EmptyRegTabPanel
220 */ 47 */
221 48EmptyRegTabPanel::EmptyRegTabPanel(QWidget *parent)
222RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const SocRegRef& reg_ref) 49 :QWidget(parent)
223 :QGroupBox(parent), m_io_backend(io_backend), m_reg(reg_ref)
224{ 50{
225 bool read_only = m_io_backend->IsReadOnly(); 51 QVBoxLayout *l = new QVBoxLayout;
226 52 l->addStretch();
227 QVBoxLayout *right_layout = new QVBoxLayout; 53 setLayout(l);
228
229 const soc_dev_addr_t& dev_addr = m_reg.GetDevAddr();
230 const soc_reg_t& reg = m_reg.GetReg();
231 const soc_reg_addr_t& reg_addr = m_reg.GetRegAddr();
232
233 QString reg_name;
234 reg_name.sprintf("HW_%s_%s", dev_addr.name.c_str(), reg_addr.name.c_str());
235 QStringList names;
236 QVector< soc_addr_t > addresses;
237 names.append(reg_name);
238 addresses.append(reg_addr.addr);
239 if(reg.flags & REG_HAS_SCT)
240 {
241 names.append(reg_name + "_SET");
242 names.append(reg_name + "_CLR");
243 names.append(reg_name + "_TOG");
244 addresses.append(reg_addr.addr + 4);
245 addresses.append(reg_addr.addr + 8);
246 addresses.append(reg_addr.addr + 12);
247 }
248
249 QString str;
250 str += "<table align=left>";
251 for(int i = 0; i < names.size(); i++)
252 str += "<tr><td><b>" + names[i] + "</b></td></tr>";
253 str += "</table>";
254 QLabel *label_names = new QLabel;
255 label_names->setTextFormat(Qt::RichText);
256 label_names->setText(str);
257
258 QString str_addr;
259 str_addr += "<table align=left>";
260 for(int i = 0; i < names.size(); i++)
261 str_addr += "<tr><td><b>" + QString().sprintf("0x%03x", addresses[i]) + "</b></td></tr>";
262 str_addr += "</table>";
263 QLabel *label_addr = new QLabel;
264 label_addr->setTextFormat(Qt::RichText);
265 label_addr->setText(str_addr);
266
267 QHBoxLayout *top_layout = new QHBoxLayout;
268 top_layout->addStretch();
269 top_layout->addWidget(label_names);
270 top_layout->addWidget(label_addr);
271 top_layout->addStretch();
272
273 soc_word_t value;
274 BackendHelper helper(m_io_backend, m_reg);
275 bool has_value = helper.ReadRegister(dev_addr.name.c_str(), reg_addr.name.c_str(), value);
276
277 QHBoxLayout *raw_val_layout = 0;
278 if(has_value)
279 {
280 QLabel *raw_val_name = new QLabel;
281 raw_val_name->setText("Raw value:");
282 m_raw_val_edit = new RegLineEdit;
283 m_raw_val_edit->SetReadOnly(read_only);
284 m_raw_val_edit->GetLineEdit()->setText(QString().sprintf("0x%08x", value));
285 m_raw_val_edit->GetLineEdit()->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
286 m_raw_val_edit->GetLineEdit()->setValidator(new SocFieldValidator(m_raw_val_edit));
287 m_raw_val_edit->EnableSCT(!!(reg.flags & REG_HAS_SCT));
288 connect(m_raw_val_edit->GetLineEdit(), SIGNAL(returnPressed()), this, SLOT(OnRawRegValueReturnPressed()));
289 raw_val_layout = new QHBoxLayout;
290 raw_val_layout->addStretch();
291 raw_val_layout->addWidget(raw_val_name);
292 raw_val_layout->addWidget(m_raw_val_edit);
293 raw_val_layout->addStretch();
294 }
295 else
296 m_raw_val_edit = 0;
297
298 QTableWidget *value_table = new QTableWidget;
299 value_table->setRowCount(reg.field.size());
300 value_table->setColumnCount(4);
301 int row = 0;
302 foreach(const soc_reg_field_t& field, reg.field)
303 {
304 QString bits_str;
305 if(field.first_bit == field.last_bit)
306 bits_str.sprintf("%d", field.first_bit);
307 else
308 bits_str.sprintf("%d:%d", field.last_bit, field.first_bit);
309 QTableWidgetItem *item = new QTableWidgetItem(bits_str);
310 item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
311 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
312 value_table->setItem(row, 0, item);
313 item = new QTableWidgetItem(QString(field.name.c_str()));
314 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
315 value_table->setItem(row, 1, item);
316 item = new QTableWidgetItem();
317 if(has_value)
318 {
319 soc_word_t v = (value & field.bitmask()) >> field.first_bit;
320 QString value_name;
321 foreach(const soc_reg_field_value_t& rval, field.value)
322 if(v == rval.value)
323 value_name = rval.name.c_str();
324 const char *fmt = "%lu";
325 // heuristic
326 if((field.last_bit - field.first_bit + 1) > 16)
327 fmt = "0x%lx";
328 item->setText(QString().sprintf(fmt, (unsigned long)v));
329 item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
330
331 if(value_name.size() != 0)
332 {
333 QTableWidgetItem *t = new QTableWidgetItem(value_name);
334 t->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
335 t->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
336 value_table->setItem(row, 3, t);
337 }
338 }
339 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
340 value_table->setItem(row, 2, item);
341 row++;
342 }
343 value_table->setHorizontalHeaderItem(0, new QTableWidgetItem("Bits"));
344 value_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Name"));
345 value_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Value"));
346 value_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Meaning"));
347 value_table->verticalHeader()->setVisible(false);
348 value_table->resizeColumnsToContents();
349 value_table->horizontalHeader()->setStretchLastSection(true);
350 value_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
351
352 right_layout->addLayout(top_layout);
353 if(raw_val_layout)
354 right_layout->addLayout(raw_val_layout);
355 //right_layout->addWidget(bits_label);
356 right_layout->addWidget(value_table);
357 //right_layout->addStretch();
358
359 setTitle("Register Description");
360 setLayout(right_layout);
361 AllowWrite(false);
362} 54}
363 55
364void RegDisplayPanel::AllowWrite(bool en) 56void EmptyRegTabPanel::AllowWrite(bool en)
365{ 57{
366 m_allow_write = en; 58 Q_UNUSED(en);
367 if(m_raw_val_edit)
368 m_raw_val_edit->SetReadOnly(m_io_backend->IsReadOnly() || !m_allow_write);
369} 59}
370 60
371IoBackend::WriteMode RegDisplayPanel::EditModeToWriteMode(RegLineEdit::EditMode mode) 61QWidget *EmptyRegTabPanel::GetWidget()
372{ 62{
373 switch(mode) 63 return this;
374 {
375 case RegLineEdit::Write: return IoBackend::Write;
376 case RegLineEdit::Set: return IoBackend::Set;
377 case RegLineEdit::Clear: return IoBackend::Clear;
378 case RegLineEdit::Toggle: return IoBackend::Toggle;
379 default: return IoBackend::Write;
380 }
381} 64}
382 65
383void RegDisplayPanel::OnRawRegValueReturnPressed()
384{
385 soc_word_t val;
386 QLineEdit *edit = m_raw_val_edit->GetLineEdit();
387 const SocFieldValidator *validator = dynamic_cast< const SocFieldValidator *>(edit->validator());
388 QValidator::State state = validator->parse(edit->text(), val);
389 if(state != QValidator::Acceptable)
390 return;
391 IoBackend::WriteMode mode = EditModeToWriteMode(m_raw_val_edit->GetMode());
392 BackendHelper helper(m_io_backend, m_reg);
393 helper.WriteRegister(m_reg.GetDevAddr().name.c_str(), m_reg.GetRegAddr().name.c_str(),
394 val, mode);
395 // FIXME: we should notify the UI to read value back because it has changed
396}
397 66
398/** 67/**
399 * RegTab 68 * RegTab
400 */ 69 */
401 70
402RegTab::RegTab(Backend *backend) 71RegTab::RegTab(Backend *backend, QWidget *parent)
403 :m_backend(backend) 72 :QSplitter(parent), m_backend(backend)
404{ 73{
405 QWidget *left = new QWidget; 74 QWidget *left = new QWidget;
406 this->addWidget(left); 75 this->addWidget(left);
@@ -432,7 +101,7 @@ RegTab::RegTab(Backend *backend)
432 QGroupBox *data_sel_group = new QGroupBox("Data selection"); 101 QGroupBox *data_sel_group = new QGroupBox("Data selection");
433 QHBoxLayout *data_sel_layout = new QHBoxLayout; 102 QHBoxLayout *data_sel_layout = new QHBoxLayout;
434 m_data_selector = new QComboBox; 103 m_data_selector = new QComboBox;
435 m_data_selector->addItem(QIcon::fromTheme("face-sad"), "None", QVariant(DataSelNothing)); 104 m_data_selector->addItem(QIcon::fromTheme("text-x-generic"), "Explore", QVariant(DataSelNothing));
436 m_data_selector->addItem(QIcon::fromTheme("document-open"), "File...", QVariant(DataSelFile)); 105 m_data_selector->addItem(QIcon::fromTheme("document-open"), "File...", QVariant(DataSelFile));
437#ifdef HAVE_HWSTUB 106#ifdef HAVE_HWSTUB
438 m_data_selector->addItem(QIcon::fromTheme("multimedia-player"), "Device...", QVariant(DataSelDevice)); 107 m_data_selector->addItem(QIcon::fromTheme("multimedia-player"), "Device...", QVariant(DataSelDevice));
@@ -446,7 +115,8 @@ RegTab::RegTab(Backend *backend)
446 data_sel_reload->setIcon(QIcon::fromTheme("view-refresh")); 115 data_sel_reload->setIcon(QIcon::fromTheme("view-refresh"));
447 data_sel_reload->setToolTip("Reload data"); 116 data_sel_reload->setToolTip("Reload data");
448 data_sel_layout->addWidget(m_data_selector); 117 data_sel_layout->addWidget(m_data_selector);
449 data_sel_layout->addWidget(m_data_sel_edit); 118 data_sel_layout->addWidget(m_data_sel_edit, 1);
119 data_sel_layout->addStretch(0);
450#ifdef HAVE_HWSTUB 120#ifdef HAVE_HWSTUB
451 m_dev_selector = new QComboBox; 121 m_dev_selector = new QComboBox;
452 data_sel_layout->addWidget(m_dev_selector, 1); 122 data_sel_layout->addWidget(m_dev_selector, 1);
@@ -457,12 +127,9 @@ RegTab::RegTab(Backend *backend)
457 data_sel_group->setLayout(data_sel_layout); 127 data_sel_group->setLayout(data_sel_layout);
458 m_data_soc_label->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); 128 m_data_soc_label->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
459 129
460 m_right_panel->addWidget(data_sel_group); 130 m_right_panel->addWidget(data_sel_group, 0);
461 m_right_content = new QWidget; 131 m_right_content = 0;
462 QVBoxLayout *l = new QVBoxLayout; 132 SetPanel(new EmptyRegTabPanel);
463 l->addStretch();
464 m_right_content->setLayout(l);
465 m_right_panel->addWidget(m_right_content);
466 QWidget *w = new QWidget; 133 QWidget *w = new QWidget;
467 w->setLayout(m_right_panel); 134 w->setLayout(m_right_panel);
468 this->addWidget(w); 135 this->addWidget(w);
@@ -470,21 +137,17 @@ RegTab::RegTab(Backend *backend)
470 137
471 m_io_backend = m_backend->CreateDummyIoBackend(); 138 m_io_backend = m_backend->CreateDummyIoBackend();
472 139
473 connect(m_soc_selector, SIGNAL(currentIndexChanged(const QString&)), 140 connect(m_soc_selector, SIGNAL(currentIndexChanged(int)),
474 this, SLOT(OnSocChanged(const QString&))); 141 this, SLOT(OnSocChanged(int)));
475 connect(m_backend, SIGNAL(OnSocListChanged()), this, SLOT(OnSocListChanged())); 142 connect(m_backend, SIGNAL(OnSocListChanged()), this, SLOT(OnSocListChanged()));
476 connect(m_reg_tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), 143 connect(m_reg_tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
477 this, SLOT(OnRegItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); 144 this, SLOT(OnRegItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
478 connect(m_reg_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
479 SLOT(OnRegItemClicked(QTreeWidgetItem *, int)));
480 connect(m_data_selector, SIGNAL(activated(int)), 145 connect(m_data_selector, SIGNAL(activated(int)),
481 this, SLOT(OnDataSelChanged(int))); 146 this, SLOT(OnDataSelChanged(int)));
482 connect(m_data_soc_label, SIGNAL(linkActivated(const QString&)), this, 147 connect(m_data_soc_label, SIGNAL(linkActivated(const QString&)), this,
483 SLOT(OnDataSocActivated(const QString&))); 148 SLOT(OnDataSocActivated(const QString&)));
484 connect(m_analysers_list, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), 149 connect(m_analysers_list, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
485 this, SLOT(OnAnalyserChanged(QListWidgetItem *, QListWidgetItem *))); 150 this, SLOT(OnAnalyserChanged(QListWidgetItem *, QListWidgetItem *)));
486 connect(m_analysers_list, SIGNAL(itemClicked(QListWidgetItem *)), this,
487 SLOT(OnAnalyserClicked(QListWidgetItem *)));
488#ifdef HAVE_HWSTUB 151#ifdef HAVE_HWSTUB
489 connect(m_dev_selector, SIGNAL(currentIndexChanged(int)), 152 connect(m_dev_selector, SIGNAL(currentIndexChanged(int)),
490 this, SLOT(OnDevChanged(int))); 153 this, SLOT(OnDevChanged(int)));
@@ -492,14 +155,22 @@ RegTab::RegTab(Backend *backend)
492 connect(m_readonly_check, SIGNAL(clicked(bool)), this, SLOT(OnReadOnlyClicked(bool))); 155 connect(m_readonly_check, SIGNAL(clicked(bool)), this, SLOT(OnReadOnlyClicked(bool)));
493 156
494 OnSocListChanged(); 157 OnSocListChanged();
495 OnDataSelChanged(DataSelNothing); 158 OnDataSelChanged(0);
496} 159}
497 160
498RegTab::~RegTab() 161RegTab::~RegTab()
499{ 162{
163#ifdef HAVE_HWSTUB
164 ClearDevList();
165#endif
500 delete m_io_backend; 166 delete m_io_backend;
501} 167}
502 168
169bool RegTab::Quit()
170{
171 return true;
172}
173
503void RegTab::SetDataSocName(const QString& socname) 174void RegTab::SetDataSocName(const QString& socname)
504{ 175{
505 if(socname.size() != 0) 176 if(socname.size() != 0)
@@ -533,9 +204,10 @@ void RegTab::OnDataSelChanged(int index)
533#ifdef HAVE_HWSTUB 204#ifdef HAVE_HWSTUB
534 m_dev_selector->hide(); 205 m_dev_selector->hide();
535#endif 206#endif
207 m_readonly_check->show();
536 QFileDialog *fd = new QFileDialog(m_data_selector); 208 QFileDialog *fd = new QFileDialog(m_data_selector);
537 fd->setFilter("Textual files (*.txt);;All files (*)"); 209 fd->setFilter("Textual files (*.txt);;All files (*)");
538 fd->setDirectory(Settings::Get()->value("regtab/loaddatadir", QDir::currentPath()).toString()); 210 fd->setDirectory(Settings::Get()->value("loaddatadir", QDir::currentPath()).toString());
539 if(fd->exec()) 211 if(fd->exec())
540 { 212 {
541 QStringList filenames = fd->selectedFiles(); 213 QStringList filenames = fd->selectedFiles();
@@ -545,13 +217,14 @@ void RegTab::OnDataSelChanged(int index)
545 SetDataSocName(m_io_backend->GetSocName()); 217 SetDataSocName(m_io_backend->GetSocName());
546 OnDataSocActivated(m_io_backend->GetSocName()); 218 OnDataSocActivated(m_io_backend->GetSocName());
547 } 219 }
548 Settings::Get()->setValue("regtab/loaddatadir", fd->directory().absolutePath()); 220 Settings::Get()->setValue("loaddatadir", fd->directory().absolutePath());
549 SetReadOnlyIndicator(); 221 SetReadOnlyIndicator();
550 } 222 }
551#ifdef HAVE_HWSTUB 223#ifdef HAVE_HWSTUB
552 else if(var == DataSelDevice) 224 else if(var == DataSelDevice)
553 { 225 {
554 m_data_sel_edit->hide(); 226 m_data_sel_edit->hide();
227 m_readonly_check->show();
555 m_dev_selector->show(); 228 m_dev_selector->show();
556 OnDevListChanged(); 229 OnDevListChanged();
557 } 230 }
@@ -562,13 +235,31 @@ void RegTab::OnDataSelChanged(int index)
562#ifdef HAVE_HWSTUB 235#ifdef HAVE_HWSTUB
563 m_dev_selector->hide(); 236 m_dev_selector->hide();
564#endif 237#endif
238 m_readonly_check->hide();
239
565 delete m_io_backend; 240 delete m_io_backend;
566 m_io_backend = m_backend->CreateDummyIoBackend(); 241 m_io_backend = m_backend->CreateDummyIoBackend();
242 m_readonly_check->setCheckState(Qt::Checked);
567 SetDataSocName(""); 243 SetDataSocName("");
244 UpdateSocFilename();
568 } 245 }
569 OnDataChanged(); 246 OnDataChanged();
570} 247}
571 248
249void RegTab::UpdateSocFilename()
250{
251 int index = m_data_selector->currentIndex();
252 if(index == -1)
253 return;
254 if(m_data_selector->itemData(index) != DataSelNothing)
255 return;
256 index = m_soc_selector->currentIndex();
257 if(index == -1)
258 return;
259 SocRef ref = m_soc_selector->itemData(index).value< SocRef >();
260 m_data_sel_edit->setText(ref.GetSocFile()->GetFilename());
261}
262
572void RegTab::SetReadOnlyIndicator() 263void RegTab::SetReadOnlyIndicator()
573{ 264{
574 if(m_io_backend->IsReadOnly()) 265 if(m_io_backend->IsReadOnly())
@@ -582,23 +273,30 @@ void RegTab::OnDataChanged()
582 273
583void RegTab::OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) 274void RegTab::OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
584{ 275{
585 (void) previous; 276 Q_UNUSED(previous);
586 OnRegItemClicked(current, 0); 277 OnRegItemClicked(current, 0);
587} 278}
588 279
589void RegTab::OnRegItemClicked(QTreeWidgetItem *current, int col) 280void RegTab::OnRegItemClicked(QTreeWidgetItem *current, int col)
590{ 281{
591 (void) col; 282 Q_UNUSED(col);
592 if(current == 0 || current->type() != RegTreeRegType) 283 if(current == 0)
593 return; 284 return;
594 RegTreeItem *item = dynamic_cast< RegTreeItem * >(current); 285 if(current->type() == RegTreeRegType)
595 286 {
596 DisplayRegister(item->GetRef()); 287 RegTreeItem *item = dynamic_cast< RegTreeItem * >(current);
288 DisplayRegister(item->GetRef());
289 }
290 else if(current->type() == RegTreeDevType)
291 {
292 DevTreeItem *item = dynamic_cast< DevTreeItem * >(current);
293 DisplayDevice(item->GetRef());
294 }
597} 295}
598 296
599void RegTab::OnAnalyserChanged(QListWidgetItem *current, QListWidgetItem *previous) 297void RegTab::OnAnalyserChanged(QListWidgetItem *current, QListWidgetItem *previous)
600{ 298{
601 (void) previous; 299 Q_UNUSED(previous);
602 OnAnalyserClicked(current); 300 OnAnalyserClicked(current);
603} 301}
604 302
@@ -606,33 +304,44 @@ void RegTab::OnAnalyserClicked(QListWidgetItem *current)
606{ 304{
607 if(current == 0) 305 if(current == 0)
608 return; 306 return;
609 delete m_right_content;
610 AnalyserFactory *ana = AnalyserFactory::GetAnalyserByName(current->text()); 307 AnalyserFactory *ana = AnalyserFactory::GetAnalyserByName(current->text());
611 m_right_content = ana->Create(m_cur_soc, m_io_backend)->GetWidget(); 308 SetPanel(ana->Create(m_cur_soc, m_io_backend));
612 m_right_panel->addWidget(m_right_content, 1);
613} 309}
614 310
615void RegTab::DisplayRegister(const SocRegRef& ref) 311void RegTab::DisplayRegister(const SocRegRef& ref)
616{ 312{
313 SetPanel(new RegDisplayPanel(this, m_io_backend, ref));
314}
315
316void RegTab::DisplayDevice(const SocDevRef& ref)
317{
318 SetPanel(new DevDisplayPanel(this, ref));
319}
320
321void RegTab::SetPanel(RegTabPanel *panel)
322{
617 delete m_right_content; 323 delete m_right_content;
618 RegDisplayPanel *panel = new RegDisplayPanel(this, m_io_backend, ref);
619 panel->AllowWrite(m_readonly_check->checkState() == Qt::Unchecked);
620 m_right_content = panel; 324 m_right_content = panel;
621 m_right_panel->addWidget(m_right_content); 325 m_right_content->AllowWrite(m_readonly_check->checkState() == Qt::Unchecked);
326 m_right_panel->addWidget(m_right_content->GetWidget(), 1);
622} 327}
623 328
624void RegTab::OnSocListChanged() 329void RegTab::OnSocListChanged()
625{ 330{
626 m_soc_selector->clear(); 331 m_soc_selector->clear();
627 QStringList socs = m_backend->GetSocNameList(); 332 QList< SocRef > socs = m_backend->GetSocList();
628 for(int i = 0; i < socs.size(); i++) 333 for(int i = 0; i < socs.size(); i++)
629 m_soc_selector->addItem(socs[i]); 334 {
335 QVariant v;
336 v.setValue(socs[i]);
337 m_soc_selector->addItem(QString::fromStdString(socs[i].GetSoc().name), v);
338 }
630} 339}
631 340
632#ifdef HAVE_HWSTUB 341#ifdef HAVE_HWSTUB
633void RegTab::OnDevListChanged() 342void RegTab::OnDevListChanged()
634{ 343{
635 m_dev_selector->clear(); 344 ClearDevList();
636 QList< HWStubDevice* > list = m_hwstub_helper.GetDevList(); 345 QList< HWStubDevice* > list = m_hwstub_helper.GetDevList();
637 foreach(HWStubDevice *dev, list) 346 foreach(HWStubDevice *dev, list)
638 { 347 {
@@ -659,10 +368,21 @@ void RegTab::OnDevChanged(int index)
659 OnDataSocActivated(m_io_backend->GetSocName()); 368 OnDataSocActivated(m_io_backend->GetSocName());
660 OnDataChanged(); 369 OnDataChanged();
661} 370}
371
372void RegTab::ClearDevList()
373{
374 while(m_dev_selector->count() > 0)
375 {
376 HWStubDevice *dev = reinterpret_cast< HWStubDevice* >(m_dev_selector->itemData(0).value< void* >());
377 delete dev;
378 m_dev_selector->removeItem(0);
379 }
380}
662#endif 381#endif
663 382
664void RegTab::FillDevSubTree(DevTreeItem *item) 383void RegTab::FillDevSubTree(QTreeWidgetItem *_item)
665{ 384{
385 DevTreeItem *item = dynamic_cast< DevTreeItem* >(_item);
666 const soc_dev_t& dev = item->GetRef().GetDev(); 386 const soc_dev_t& dev = item->GetRef().GetDev();
667 for(size_t i = 0; i < dev.reg.size(); i++) 387 for(size_t i = 0; i < dev.reg.size(); i++)
668 { 388 {
@@ -697,23 +417,21 @@ void RegTab::FillAnalyserList()
697 m_analysers_list->addItems(AnalyserFactory::GetAnalysersForSoc(m_cur_soc.GetSoc().name.c_str())); 417 m_analysers_list->addItems(AnalyserFactory::GetAnalysersForSoc(m_cur_soc.GetSoc().name.c_str()));
698} 418}
699 419
700void RegTab::OnSocChanged(const QString& soc) 420void RegTab::OnSocChanged(int index)
701{ 421{
702 m_reg_tree->clear(); 422 if(index == -1)
703 if(!m_backend->GetSocByName(soc, m_cur_soc))
704 return; 423 return;
424 m_reg_tree->clear();
425 m_cur_soc = m_soc_selector->itemData(index).value< SocRef >();
705 FillRegTree(); 426 FillRegTree();
706 FillAnalyserList(); 427 FillAnalyserList();
428 UpdateSocFilename();
707} 429}
708 430
709void RegTab::OnReadOnlyClicked(bool checked) 431void RegTab::OnReadOnlyClicked(bool checked)
710{ 432{
711 if(m_io_backend->IsReadOnly()) 433 if(m_io_backend->IsReadOnly())
712 return SetReadOnlyIndicator(); 434 return SetReadOnlyIndicator();
713 if(m_right_content == 0) 435 m_right_content->AllowWrite(!checked);
714 return; 436 UpdateSocFilename();
715 RegDisplayPanel *panel = dynamic_cast< RegDisplayPanel* >(m_right_content);
716 if(panel == 0)
717 return;
718 panel->AllowWrite(!checked);
719} 437}
diff --git a/utils/regtools/qeditor/regtab.h b/utils/regtools/qeditor/regtab.h
index 9fa1437119..78a10ba379 100644
--- a/utils/regtools/qeditor/regtab.h
+++ b/utils/regtools/qeditor/regtab.h
@@ -2,7 +2,6 @@
2#define REGTAB_H 2#define REGTAB_H
3 3
4#include <QComboBox> 4#include <QComboBox>
5#include <QEvent>
6#include <QTreeWidget> 5#include <QTreeWidget>
7#include <QVBoxLayout> 6#include <QVBoxLayout>
8#include <QTabWidget> 7#include <QTabWidget>
@@ -11,118 +10,41 @@
11#include <QPushButton> 10#include <QPushButton>
12#include <QLabel> 11#include <QLabel>
13#include <QListWidget> 12#include <QListWidget>
14#include <QValidator>
15#include <QGroupBox> 13#include <QGroupBox>
16#include <QToolButton> 14#include <QToolButton>
17#include <QMenu> 15#include <QMenu>
18#include <QCheckBox> 16#include <QCheckBox>
19#include <soc_desc.hpp>
20#include "backend.h" 17#include "backend.h"
21#include "settings.h" 18#include "settings.h"
19#include "mainwindow.h"
22 20
23enum 21class RegTabPanel
24{
25 RegTreeDevType = QTreeWidgetItem::UserType,
26 RegTreeRegType
27};
28
29class DevTreeItem : public QTreeWidgetItem
30{
31public:
32 DevTreeItem(const QString& string, const SocDevRef& ref)
33 :QTreeWidgetItem(QStringList(string), RegTreeDevType), m_ref(ref) {}
34
35 const SocDevRef& GetRef() { return m_ref; }
36private:
37 SocDevRef m_ref;
38};
39
40class RegTreeItem : public QTreeWidgetItem
41{ 22{
42public: 23public:
43 RegTreeItem(const QString& string, const SocRegRef& ref) 24 RegTabPanel() {}
44 :QTreeWidgetItem(QStringList(string), RegTreeRegType), m_ref(ref) {} 25 virtual ~RegTabPanel() {}
45 26 virtual void AllowWrite(bool en) = 0;
46 const SocRegRef& GetRef() { return m_ref; } 27 virtual QWidget *GetWidget() = 0;
47private:
48 SocRegRef m_ref;
49}; 28};
50 29
51class SocFieldValidator : public QValidator 30class EmptyRegTabPanel : public QWidget, public RegTabPanel
52{ 31{
53 Q_OBJECT
54public: 32public:
55 SocFieldValidator(QObject *parent = 0); 33 EmptyRegTabPanel(QWidget *parent = 0);
56 SocFieldValidator(const soc_reg_field_t& field, QObject *parent = 0);
57
58 virtual void fixup(QString& input) const;
59 virtual State validate(QString& input, int& pos) const;
60 /* validate and return the interpreted value */
61 State parse(const QString& input, soc_word_t& val) const;
62
63protected:
64 soc_reg_field_t m_field;
65};
66
67class RegLineEdit : public QWidget
68{
69 Q_OBJECT
70public:
71 enum EditMode
72 {
73 Write, Set, Clear, Toggle
74 };
75
76 RegLineEdit(QWidget *parent = 0);
77 ~RegLineEdit();
78 void SetReadOnly(bool ro);
79 void EnableSCT(bool en);
80 void SetMode(EditMode mode);
81 EditMode GetMode();
82 QLineEdit *GetLineEdit();
83
84protected slots:
85 void OnWriteAct();
86 void OnSetAct();
87 void OnClearAct();
88 void OnToggleAct();
89protected:
90 void ShowMode(bool show);
91
92 QHBoxLayout *m_layout;
93 QToolButton *m_button;
94 QLineEdit *m_edit;
95 EditMode m_mode;
96 bool m_has_sct;
97 bool m_readonly;
98 QMenu *m_menu;
99};
100
101class RegDisplayPanel : public QGroupBox
102{
103 Q_OBJECT
104public:
105 RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const SocRegRef& reg);
106 void AllowWrite(bool en); 34 void AllowWrite(bool en);
107 35 QWidget *GetWidget();
108protected:
109 IoBackend::WriteMode EditModeToWriteMode(RegLineEdit::EditMode mode);
110
111 IoBackend *m_io_backend;
112 const SocRegRef& m_reg;
113 bool m_allow_write;
114 RegLineEdit *m_raw_val_edit;
115
116private slots:
117 void OnRawRegValueReturnPressed();
118}; 36};
119 37
120class RegTab : public QSplitter 38class RegTab : public QSplitter, public DocumentTab
121{ 39{
122 Q_OBJECT 40 Q_OBJECT
123public: 41public:
124 RegTab(Backend *backend); 42 RegTab(Backend *backend, QWidget *parent = 0);
125 ~RegTab(); 43 ~RegTab();
44 virtual bool Quit();
45
46signals:
47 void OnModified(bool modified);
126 48
127protected: 49protected:
128 enum 50 enum
@@ -134,12 +56,16 @@ protected:
134 #endif 56 #endif
135 }; 57 };
136 58
137 void FillDevSubTree(DevTreeItem *item); 59 void FillDevSubTree(QTreeWidgetItem *item);
138 void FillRegTree(); 60 void FillRegTree();
139 void FillAnalyserList(); 61 void FillAnalyserList();
140 void UpdateSocList(); 62 void UpdateSocList();
141 void DisplayRegister(const SocRegRef& ref); 63 void DisplayRegister(const SocRegRef& ref);
64 void DisplayDevice(const SocDevRef& ref);
142 void SetDataSocName(const QString& socname); 65 void SetDataSocName(const QString& socname);
66 void SetPanel(RegTabPanel *panel);
67 void UpdateSocFilename();
68
143 QComboBox *m_soc_selector; 69 QComboBox *m_soc_selector;
144#ifdef HAVE_HWSTUB 70#ifdef HAVE_HWSTUB
145 QComboBox *m_dev_selector; 71 QComboBox *m_dev_selector;
@@ -149,7 +75,7 @@ protected:
149 QTreeWidget *m_reg_tree; 75 QTreeWidget *m_reg_tree;
150 SocRef m_cur_soc; 76 SocRef m_cur_soc;
151 QVBoxLayout *m_right_panel; 77 QVBoxLayout *m_right_panel;
152 QWidget *m_right_content; 78 RegTabPanel *m_right_content;
153 QLineEdit *m_data_sel_edit; 79 QLineEdit *m_data_sel_edit;
154 QCheckBox *m_readonly_check; 80 QCheckBox *m_readonly_check;
155 QLabel *m_data_soc_label; 81 QLabel *m_data_soc_label;
@@ -163,9 +89,10 @@ private slots:
163#ifdef HAVE_HWSTUB 89#ifdef HAVE_HWSTUB
164 void OnDevListChanged(); 90 void OnDevListChanged();
165 void OnDevChanged(int index); 91 void OnDevChanged(int index);
92 void ClearDevList();
166#endif 93#endif
167 void SetReadOnlyIndicator(); 94 void SetReadOnlyIndicator();
168 void OnSocChanged(const QString& text); 95 void OnSocChanged(int index);
169 void OnSocListChanged(); 96 void OnSocListChanged();
170 void OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); 97 void OnRegItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
171 void OnRegItemClicked(QTreeWidgetItem *clicked, int col); 98 void OnRegItemClicked(QTreeWidgetItem *clicked, int col);
diff --git a/utils/regtools/qeditor/std_analysers.cpp b/utils/regtools/qeditor/std_analysers.cpp
index 2cc84cb488..5847e39f7d 100644
--- a/utils/regtools/qeditor/std_analysers.cpp
+++ b/utils/regtools/qeditor/std_analysers.cpp
@@ -23,6 +23,7 @@ ClockAnalyser::ClockAnalyser(const SocRef& soc, IoBackend *backend)
23 23
24ClockAnalyser::~ClockAnalyser() 24ClockAnalyser::~ClockAnalyser()
25{ 25{
26 delete m_group;
26} 27}
27 28
28QWidget *ClockAnalyser::GetWidget() 29QWidget *ClockAnalyser::GetWidget()
@@ -287,9 +288,9 @@ void ClockAnalyser::FillTree()
287 else 288 else
288 AddClock(ref_xtal, "clk_rtc32k", INVALID); 289 AddClock(ref_xtal, "clk_rtc32k", INVALID);
289 290
290 (void) clk_x; 291 Q_UNUSED(clk_x);
291 (void) clk_gpmi; 292 Q_UNUSED(clk_gpmi);
292 (void) clk_h; 293 Q_UNUSED(clk_h);
293 294
294 m_tree_widget->expandAll(); 295 m_tree_widget->expandAll();
295 m_tree_widget->resizeColumnToContents(0); 296 m_tree_widget->resizeColumnToContents(0);
@@ -334,6 +335,7 @@ EmiAnalyser::EmiAnalyser(const SocRef& soc, IoBackend *backend)
334 335
335EmiAnalyser::~EmiAnalyser() 336EmiAnalyser::~EmiAnalyser()
336{ 337{
338 delete m_group;
337} 339}
338 340
339QWidget *EmiAnalyser::GetWidget() 341QWidget *EmiAnalyser::GetWidget()
@@ -671,6 +673,7 @@ PinAnalyser::PinAnalyser(const SocRef& soc, IoBackend *backend)
671 673
672PinAnalyser::~PinAnalyser() 674PinAnalyser::~PinAnalyser()
673{ 675{
676 delete m_group;
674} 677}
675 678
676QWidget *PinAnalyser::GetWidget() 679QWidget *PinAnalyser::GetWidget()
diff --git a/utils/regtools/qeditor/std_analysers.h b/utils/regtools/qeditor/std_analysers.h
index aae8e40207..cca8b12b99 100644
--- a/utils/regtools/qeditor/std_analysers.h
+++ b/utils/regtools/qeditor/std_analysers.h
@@ -21,7 +21,6 @@
21 21
22class ClockAnalyser : public Analyser 22class ClockAnalyser : public Analyser
23{ 23{
24 Q_OBJECT
25public: 24public:
26 ClockAnalyser(const SocRef& soc, IoBackend *backend); 25 ClockAnalyser(const SocRef& soc, IoBackend *backend);
27 virtual ~ClockAnalyser(); 26 virtual ~ClockAnalyser();
@@ -50,7 +49,7 @@ private:
50/** 49/**
51 * EMI analyser 50 * EMI analyser
52 */ 51 */
53class EmiAnalyser : public Analyser 52class EmiAnalyser : public QObject, public Analyser
54{ 53{
55 Q_OBJECT 54 Q_OBJECT
56public: 55public:
@@ -96,7 +95,6 @@ private:
96 */ 95 */
97class PinAnalyser : public Analyser 96class PinAnalyser : public Analyser
98{ 97{
99 Q_OBJECT
100public: 98public:
101 PinAnalyser(const SocRef& soc, IoBackend *backend); 99 PinAnalyser(const SocRef& soc, IoBackend *backend);
102 virtual ~PinAnalyser(); 100 virtual ~PinAnalyser();
diff --git a/utils/regtools/tester.cpp b/utils/regtools/tester.cpp
index 1fa21c6894..1beba5fe9b 100644
--- a/utils/regtools/tester.cpp
+++ b/utils/regtools/tester.cpp
@@ -21,77 +21,343 @@
21#include "soc_desc.hpp" 21#include "soc_desc.hpp"
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <map>
25#include <cstring>
24 26
25void print_value_desc(const soc_reg_field_value_t& value) 27template< typename T >
28bool build_map(const char *type, const std::vector< T >& vec,
29 std::map< std::string, size_t >& map)
26{ 30{
27 printf(" VALUE %s (%#x)\n", value.name.c_str(), value.value); 31 for(size_t i = 0; i < vec.size(); i++)
32 {
33 if(map.find(vec[i].name) != map.end())
34 {
35 printf("soc has duplicate %s '%s'\n", type, vec[i].name.c_str());
36 return false;
37 }
38 map[vec[i].name] = i;
39 }
40 return true;
28} 41}
29 42
30void print_field_desc(const soc_reg_field_t& field) 43template< typename T >
44bool build_map(const char *type, const std::vector< T >& a, const std::vector< T >& b,
45 std::vector< std::pair< size_t, size_t > >& m)
31{ 46{
32 printf(" FIELD %s (%d:%d)\n", field.name.c_str(), field.last_bit, 47 std::map< std::string, size_t > ma, mb;
33 field.first_bit); 48 if(!build_map(type, a, ma) || !build_map(type, b, mb))
34 for(size_t i = 0; i < field.value.size(); i++) 49 return false;
35 print_value_desc(field.value[i]); 50 std::map< std::string, size_t >::iterator it;
51 for(it = ma.begin(); it != ma.end(); ++it)
52 {
53 if(mb.find(it->first) == mb.end())
54 {
55 printf("%s '%s' exists in only one file\n", type, it->first.c_str());
56 return false;
57 }
58 m.push_back(std::make_pair(it->second, mb[it->first]));
59 }
60 for(it = mb.begin(); it != mb.end(); ++it)
61 {
62 if(ma.find(it->first) == ma.end())
63 {
64 printf("%s '%s' exists in only one file\n", type, it->first.c_str());
65 return false;
66 }
67 }
68 return true;
36} 69}
37 70
38std::string compute_sct(soc_reg_flags_t f) 71bool compare_value(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& reg,
72 const soc_reg_field_t& field, const soc_reg_field_value_t& a, const soc_reg_field_value_t& b)
39{ 73{
40 if(f & REG_HAS_SCT) return "SCT"; 74 if(a.value != b.value)
41 else return ""; 75 {
76 printf("register field value '%s.%s.%s.%s.%s' have different values\n", soc.name.c_str(),
77 dev.name.c_str(), reg.name.c_str(), field.name.c_str(), a.name.c_str());
78 return false;
79 }
80 if(a.desc != b.desc)
81 {
82 printf("register field value '%s.%s.%s.%s.%s' have different descriptions\n", soc.name.c_str(),
83 dev.name.c_str(), reg.name.c_str(), field.name.c_str(), a.name.c_str());
84 return false;
85 }
86 return true;
42} 87}
43 88
44void print_reg_addr_desc(const soc_reg_addr_t& reg) 89bool compare_field(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& reg,
90 const soc_reg_field_t& a, const soc_reg_field_t& b)
45{ 91{
46 printf(" ADDR %s %#x\n", reg.name.c_str(), reg.addr); 92 if(a.first_bit != b.first_bit || a.last_bit != b.last_bit)
93 {
94 printf("register address '%s.%s.%s.%s' have different bit ranges\n", soc.name.c_str(),
95 dev.name.c_str(), reg.name.c_str(), a.name.c_str());
96 return false;
97 }
98 if(a.desc != b.desc)
99 {
100 printf("register address '%s.%s.%s.%s' have different descriptions\n", soc.name.c_str(),
101 dev.name.c_str(), reg.name.c_str(), a.name.c_str());
102 return false;
103 }
104 /* values */
105 std::vector< std::pair< size_t, size_t > > map;
106 if(!build_map("field value", a.value, b.value, map))
107 return false;
108 for(size_t i = 0; i < map.size(); i++)
109 if(!compare_value(soc, dev, reg, a, a.value[map[i].first], b.value[map[i].second]))
110 return false;
111 return true;
47} 112}
48 113
49void print_reg_desc(const soc_reg_t& reg) 114bool compare_reg_addr(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& reg,
115 const soc_reg_addr_t& a, const soc_reg_addr_t& b)
50{ 116{
51 std::string sct = compute_sct(reg.flags); 117 if(a.addr != b.addr)
52 printf(" REG %s %s\n", reg.name.c_str(), sct.c_str()); 118 {
53 for(size_t i = 0; i < reg.addr.size(); i++) 119 printf("register address '%s.%s.%s.%s' have different values\n", soc.name.c_str(),
54 print_reg_addr_desc(reg.addr[i]); 120 dev.name.c_str(), reg.name.c_str(), a.name.c_str());
55 for(size_t i = 0; i < reg.field.size(); i++) 121 return false;
56 print_field_desc(reg.field[i]); 122 }
123 else
124 return true;
57} 125}
58 126
59void print_dev_addr_desc(const soc_dev_addr_t& dev) 127bool compare_reg(const soc_t& soc, const soc_dev_t& dev, const soc_reg_t& a,
128 const soc_reg_t& b)
60{ 129{
61 printf(" ADDR %s %#x\n", dev.name.c_str(), dev.addr); 130 if(a.desc != b.desc)
131 {
132 printf("register '%s.%s.%s' have different descriptions\n", soc.name.c_str(),
133 dev.name.c_str(), a.name.c_str());
134 return false;
135 }
136 if(a.flags != b.flags)
137 {
138 printf("device '%s.%s.%s' have different flags\n", soc.name.c_str(),
139 dev.name.c_str(), a.name.c_str());
140 return false;
141 }
142 if(a.formula.type != b.formula.type)
143 {
144 printf("device '%s.%s.%s' have different formula types\n", soc.name.c_str(),
145 dev.name.c_str(), a.name.c_str());
146 return false;
147 }
148 if(a.formula.string != b.formula.string)
149 {
150 printf("device '%s.%s.%s' have different formula string\n", soc.name.c_str(),
151 dev.name.c_str(), a.name.c_str());
152 return false;
153 }
154 /* addresses */
155 std::vector< std::pair< size_t, size_t > > map;
156 if(!build_map("register address", a.addr, b.addr, map))
157 return false;
158 for(size_t i = 0; i < map.size(); i++)
159 if(!compare_reg_addr(soc, dev, a, a.addr[map[i].first], b.addr[map[i].second]))
160 return false;
161 /* field */
162 map.clear();
163 if(!build_map("field", a.field, b.field, map))
164 return false;
165 for(size_t i = 0; i < map.size(); i++)
166 if(!compare_field(soc, dev, a, a.field[map[i].first], b.field[map[i].second]))
167 return false;
168 return true;
62} 169}
63 170
64void print_dev_desc(const soc_dev_t& dev) 171bool compare_dev_addr(const soc_t& soc, const soc_dev_t& dev, const soc_dev_addr_t& a,
172 const soc_dev_addr_t& b)
65{ 173{
66 printf(" DEV %s\n", dev.name.c_str()); 174 if(a.addr != b.addr)
67 for(size_t i = 0; i < dev.addr.size(); i++) 175 {
68 print_dev_addr_desc(dev.addr[i]); 176 printf("device address '%s.%s.%s' have different values\n", soc.name.c_str(),
69 for(size_t i = 0; i < dev.reg.size(); i++) 177 dev.name.c_str(), a.name.c_str());
70 print_reg_desc(dev.reg[i]); 178 return false;
179 }
180 else
181 return true;
71} 182}
72 183
73void print_soc_desc(const soc_t& soc) 184bool compare_dev(const soc_t& soc, const soc_dev_t& a, const soc_dev_t& b)
74{ 185{
75 printf("SOC %s (%s)\n", soc.name.c_str(), soc.desc.c_str()); 186 if(a.long_name != b.long_name)
76 for(size_t i = 0; i < soc.dev.size(); i++) 187 {
77 print_dev_desc(soc.dev[i]); 188 printf("device '%s.%s' have different long names\n", soc.name.c_str(),
189 a.name.c_str());
190 return false;
191 }
192 if(a.desc != b.desc)
193 {
194 printf("device '%s.%s' have different descriptions\n", soc.name.c_str(),
195 a.name.c_str());
196 return false;
197 }
198 if(a.version != b.version)
199 {
200 printf("device '%s.%s' have different versions\n", soc.name.c_str(),
201 a.name.c_str());
202 return false;
203 }
204 /* addresses */
205 std::vector< std::pair< size_t, size_t > > map;
206 if(!build_map("device address", a.addr, b.addr, map))
207 return false;
208 for(size_t i = 0; i < map.size(); i++)
209 if(!compare_dev_addr(soc, a, a.addr[map[i].first], b.addr[map[i].second]))
210 return false;
211 /* reg */
212 map.clear();
213 if(!build_map("register", a.reg, b.reg, map))
214 return false;
215 for(size_t i = 0; i < map.size(); i++)
216 if(!compare_reg(soc, a, a.reg[map[i].first], b.reg[map[i].second]))
217 return false;
218 return true;
219}
220
221bool compare_soc(const soc_t& a, const soc_t& b)
222{
223 if(a.name != b.name)
224 {
225 return printf("soc have different names\n");
226 return false;
227 }
228 if(a.desc != b.desc)
229 {
230 printf("soc '%s' have different descriptions\n", a.name.c_str());
231 return false;
232 }
233 std::vector< std::pair< size_t, size_t > > map;
234 if(!build_map("device", a.dev, b.dev, map))
235 return false;
236 for(size_t i = 0; i< map.size(); i++)
237 if(!compare_dev(a, a.dev[map[i].first], b.dev[map[i].second]))
238 return false;
239 return true;
240}
241
242int do_compare(int argc, char **argv)
243{
244 if(argc != 2)
245 return printf("compare mode expects two arguments\n");
246 soc_t soc[2];
247 if(!soc_desc_parse_xml(argv[0], soc[0]))
248 return printf("cannot read file '%s'\n", argv[0]);
249 if(!soc_desc_parse_xml(argv[1], soc[1]))
250 return printf("cannot read file '%s'\n", argv[1]);
251 if(compare_soc(soc[0], soc[1]))
252 printf("Files are identical.\n");
253 return 0;
254}
255
256int do_write(int argc, char **argv)
257{
258 if(argc != 2)
259 return printf("write mode expects two arguments\n");
260 soc_t soc;
261 if(!soc_desc_parse_xml(argv[0], soc))
262 return printf("cannot read file '%s'\n", argv[0]);
263 if(!soc_desc_produce_xml(argv[1], soc))
264 return printf("cannot write file '%s'\n", argv[1]);
265 return 0;
266}
267
268int do_check(int argc, char **argv)
269{
270 for(int i = 0; i < argc; i++)
271 {
272 soc_t soc;
273 if(!soc_desc_parse_xml(argv[i], soc))
274 {
275 printf("cannot read file '%s'\n", argv[i]);
276 continue;
277 }
278 printf("[%s]\n", argv[i]);
279 std::vector< soc_error_t > errs = soc.errors(true);
280 for(size_t i = 0; i < errs.size(); i++)
281 {
282 const soc_error_t& e = errs[i];
283 switch(e.level)
284 {
285 case SOC_ERROR_WARNING: printf("[WARN ] "); break;
286 case SOC_ERROR_FATAL: printf("[FATAL] "); break;
287 default: printf("[ UNK ] "); break;
288 }
289 printf("%s: %s\n", e.location.c_str(), e.message.c_str());
290 }
291 }
292 return 0;
293}
294
295int do_eval(int argc, char **argv)
296{
297 std::map< std::string, soc_word_t > map;
298 for(int i = 0; i < argc; i++)
299 {
300 std::string error;
301 std::string formula(argv[i]);
302 soc_word_t result;
303 if(strcmp(argv[i], "--var") == 0)
304 {
305 if(i + 1 >= argc)
306 break;
307 i++;
308 std::string str(argv[i]);
309 size_t pos = str.find('=');
310 if(pos == std::string::npos)
311 {
312 printf("invalid variable string '%s'\n", str.c_str());
313 continue;
314 }
315 std::string name = str.substr(0, pos);
316 std::string val = str.substr(pos + 1);
317 char *end;
318 soc_word_t v = strtoul(val.c_str(), &end, 0);
319 if(*end)
320 {
321 printf("invalid variable string '%s'\n", str.c_str());
322 continue;
323 }
324 printf("%s = %#lx\n", name.c_str(), (unsigned long)v);
325 map[name] = v;
326 continue;
327 }
328 if(!soc_desc_evaluate_formula(formula, map, result, error))
329 printf("error: %s\n", error.c_str());
330 else
331 printf("result: %lu (%#lx)\n", (unsigned long)result, (unsigned long)result);
332 }
333 return 0;
78} 334}
79 335
80void usage() 336void usage()
81{ 337{
82 printf("usage: tester <desc file>\n"); 338 printf("usage: tester <mode> [options]\n");
339 printf("modes:\n");
340 printf(" compare <desc file> <desc file>\n");
341 printf(" write <read file> <write file>\n");
342 printf(" check <files...>\n");
343 printf(" eval [<formula>|--var <name>=<val>]...\n");
83 exit(1); 344 exit(1);
84} 345}
85 346
86int main(int argc, char **argv) 347int main(int argc, char **argv)
87{ 348{
88 if(argc != 2) 349 if(argc < 2)
350 usage();
351 std::string mode = argv[1];
352 if(mode == "compare")
353 return do_compare(argc - 2, argv + 2);
354 else if(mode == "write")
355 return do_write(argc - 2, argv + 2);
356 else if(mode == "check")
357 return do_check(argc - 2, argv + 2);
358 else if(mode == "eval")
359 return do_eval(argc - 2, argv + 2);
360 else
89 usage(); 361 usage();
90 std::vector< soc_t > socs;
91 bool ret = soc_desc_parse_xml(argv[1], socs);
92 printf("parse result: %d\n", ret);
93 if(ret)
94 for(size_t i = 0; i < socs.size(); i++)
95 print_soc_desc(socs[i]);
96 return 0; 362 return 0;
97} \ No newline at end of file 363} \ No newline at end of file