diff options
Diffstat (limited to 'utils/regtools/lib/soc_desc.cpp')
-rw-r--r-- | utils/regtools/lib/soc_desc.cpp | 700 |
1 files changed, 693 insertions, 7 deletions
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp index 6a6d47648f..1c9eaf7972 100644 --- a/utils/regtools/lib/soc_desc.cpp +++ b/utils/regtools/lib/soc_desc.cpp | |||
@@ -21,8 +21,12 @@ | |||
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 | ||
85 | namespace | ||
86 | { | ||
87 | |||
81 | bool validate_string_hook(const std::string& str, std::string& s) | 88 | bool 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 | ||
259 | bool parse_root_elem(xmlNode *node, std::vector< soc_t >& soc) | 267 | bool 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 | ||
267 | bool soc_desc_parse_xml(const std::string& filename, std::vector< soc_t >& socs) | 282 | } |
283 | |||
284 | bool 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 | |||
301 | namespace | ||
302 | { | ||
303 | |||
304 | int 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 | |||
336 | int 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 | |||
386 | int 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 | |||
422 | bool 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 | ||
450 | Lerr: | ||
451 | xmlFreeTextWriter(writer); | ||
452 | return false; | ||
453 | } | ||
454 | |||
455 | namespace | ||
456 | { | ||
457 | |||
458 | struct 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 | |||
493 | void normalize(soc_reg_field_t& field) | ||
494 | { | ||
495 | std::sort(field.value.begin(), field.value.end(), soc_sorter()); | ||
496 | } | ||
497 | |||
498 | void 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 | |||
506 | void 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 | |||
516 | void 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 | |||
523 | namespace | ||
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 | |||
585 | std::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 | |||
596 | std::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 | |||
629 | std::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 | |||
640 | std::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 | |||
649 | namespace | ||
650 | { | ||
651 | |||
652 | bool 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 | |||
659 | std::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 | |||
704 | std::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 | |||
715 | std::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 | |||
755 | std::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 | |||
775 | namespace | ||
776 | { | ||
777 | |||
778 | struct 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 | |||
942 | struct 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 | |||
964 | bool 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 | } | ||