specware 1.3.4__tar.gz → 1.3.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {specware-1.3.4 → specware-1.3.6}/PKG-INFO +1 -1
- {specware-1.3.4 → specware-1.3.6}/pyproject.toml +1 -1
- {specware-1.3.4 → specware-1.3.6}/src/specware/__init__.py +1 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/cliview.py +20 -13
- {specware-1.3.4 → specware-1.3.6}/src/specware/contentc.py +2 -1
- {specware-1.3.4 → specware-1.3.6}/src/specware/interface.py +138 -73
- specware-1.3.6/src/specware/registerblock.py +300 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/rtems.py +45 -27
- {specware-1.3.4 → specware-1.3.6}/src/specware/spec.pickle +0 -0
- {specware-1.3.4 → specware-1.3.6}/README.md +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/applconfig.py +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/build.py +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/cliexport.py +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/cliexportheader.py +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/clifind.py +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/interfacedoc.py +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/interfacemapper.py +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/py.typed +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/transitionmap.py +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/util.py +0 -0
- {specware-1.3.4 → specware-1.3.6}/src/specware/validation.py +0 -0
|
@@ -30,6 +30,7 @@ from .contentc import * # noqa: F401, F403
|
|
|
30
30
|
from .interface import * # noqa: F401, F403
|
|
31
31
|
from .interfacedoc import * # noqa: F401, F403
|
|
32
32
|
from .interfacemapper import * # noqa: F401, F403
|
|
33
|
+
from .registerblock import * # noqa: F401, F403
|
|
33
34
|
from .rtems import * # noqa: F401, F403
|
|
34
35
|
from .transitionmap import * # noqa: F401, F403
|
|
35
36
|
from .util import * # noqa: F401, F403
|
|
@@ -38,9 +38,9 @@ from specitems import (COL_SPAN, CommonMarkContent, Item, ItemCache,
|
|
|
38
38
|
from specware import (exit_on_config_file_error, open_tree,
|
|
39
39
|
augment_with_test_case_links, augment_with_test_links,
|
|
40
40
|
gather_api_items, gather_build_files,
|
|
41
|
-
get_register_bits_run,
|
|
42
|
-
|
|
43
|
-
validate)
|
|
41
|
+
get_register_bits_run, get_register_block_layout,
|
|
42
|
+
get_register_member_name, recursive_is_enabled,
|
|
43
|
+
Transition, TransitionMap, validate)
|
|
44
44
|
|
|
45
45
|
_DOC_FORMAT = {
|
|
46
46
|
"commonmark": CommonMarkContent,
|
|
@@ -56,8 +56,8 @@ _CHILD_ROLES = [
|
|
|
56
56
|
|
|
57
57
|
_PARENT_ROLES = [
|
|
58
58
|
"function-implementation", "interface-enumerator",
|
|
59
|
-
"performance-runtime-limits-provider",
|
|
60
|
-
"verification-provider"
|
|
59
|
+
"interface-group-member", "performance-runtime-limits-provider",
|
|
60
|
+
"test-timeouts", "verification-provider"
|
|
61
61
|
]
|
|
62
62
|
|
|
63
63
|
|
|
@@ -122,7 +122,8 @@ def _visit_item(item: Item, mapper: ItemMapper, level: int,
|
|
|
122
122
|
|
|
123
123
|
def _view_interface_placment(item: Item, mapper: ItemMapper, level: int,
|
|
124
124
|
validated_filter: str) -> None:
|
|
125
|
-
for link in item.links_to_children("interface-placement")
|
|
125
|
+
for link in itertools.chain(item.links_to_children("interface-placement"),
|
|
126
|
+
item.links_to_parents("register-block-host")):
|
|
126
127
|
if _visit_item(link.item, mapper, level, link, validated_filter):
|
|
127
128
|
_view_interface_placment(link.item, mapper, level + 1,
|
|
128
129
|
validated_filter)
|
|
@@ -507,12 +508,12 @@ def _register_member(place: str, definition: dict[str, Any],
|
|
|
507
508
|
print(" ".join(parts))
|
|
508
509
|
|
|
509
510
|
|
|
510
|
-
def _register_placed(
|
|
511
|
+
def _register_placed(members: list[Any], includes: dict[str, Item],
|
|
511
512
|
registers: dict[str,
|
|
512
513
|
Any], seen: set[str]) -> tuple[int, int]:
|
|
513
514
|
count = 0
|
|
514
515
|
unclassified = 0
|
|
515
|
-
for member in
|
|
516
|
+
for member in members:
|
|
516
517
|
for definition in _register_definitions(member):
|
|
517
518
|
name, alias = get_register_member_name(definition)
|
|
518
519
|
if name in includes:
|
|
@@ -550,13 +551,14 @@ def _register_block(item: Item) -> tuple[int, int]:
|
|
|
550
551
|
parts.extend(link.item["title"]
|
|
551
552
|
for link in item.links_to_parents("reference", _any_link))
|
|
552
553
|
print(" ".join(parts))
|
|
554
|
+
layout = get_register_block_layout(item)
|
|
553
555
|
includes = dict(
|
|
554
|
-
(
|
|
555
|
-
for link in item.links_to_parents("register-block-include", _any_link))
|
|
556
|
+
(part.data["name"], part.data.item) for part in layout.includes)
|
|
556
557
|
registers = dict(
|
|
557
|
-
(
|
|
558
|
+
(part.data["name"], part.data) for part in layout.registers)
|
|
558
559
|
seen: set[str] = set()
|
|
559
|
-
placed = _register_placed(
|
|
560
|
+
placed = _register_placed([part.data for part in layout.definition],
|
|
561
|
+
includes, registers, seen)
|
|
560
562
|
unplaced = _register_unplaced(registers, seen)
|
|
561
563
|
return placed[0] + unplaced[0], placed[1] + unplaced[1]
|
|
562
564
|
|
|
@@ -572,7 +574,12 @@ def _register_blocks(item: Item, blocks: list[Item],
|
|
|
572
574
|
visited.add(item.uid)
|
|
573
575
|
if item.get("interface-type", None) == "register-block":
|
|
574
576
|
blocks.append(item)
|
|
575
|
-
|
|
577
|
+
return
|
|
578
|
+
for link in itertools.chain(
|
|
579
|
+
item.links_to_children(is_link_enabled=_any_link),
|
|
580
|
+
item.links_to_parents(
|
|
581
|
+
["interface-group-member", "register-block-host"],
|
|
582
|
+
is_link_enabled=_any_link)):
|
|
576
583
|
_register_blocks(link.item, blocks, visited)
|
|
577
584
|
|
|
578
585
|
|
|
@@ -589,7 +589,8 @@ def get_value_params(ctx: ItemGetValueContext) -> Any:
|
|
|
589
589
|
def forward_declaration(item: Item) -> str:
|
|
590
590
|
""" Gets the forward declare for the item. """
|
|
591
591
|
target = item.parent("interface-target")
|
|
592
|
-
|
|
592
|
+
kind = target["interface-type"].removeprefix("unspecified-")
|
|
593
|
+
return f"{kind} {target['name']}"
|
|
593
594
|
|
|
594
595
|
|
|
595
596
|
def get_value_forward_declaration(ctx: ItemGetValueContext) -> Any:
|
|
@@ -48,6 +48,11 @@ from .contentc import (CContent, CInclude, DEFAULT_ITEM_MARKER,
|
|
|
48
48
|
get_value_forward_declaration, get_value_hash,
|
|
49
49
|
get_value_header_file, get_value_params,
|
|
50
50
|
get_value_unspecified_type)
|
|
51
|
+
from .registerblock import (
|
|
52
|
+
RegisterBlockPart, get_register_block_group, get_interface_groups,
|
|
53
|
+
get_register_block_host_of_domain, get_register_block_hosts,
|
|
54
|
+
get_register_block_identifier, get_register_block_layout,
|
|
55
|
+
get_register_block_prefixes)
|
|
51
56
|
from .rtems import is_export_affected
|
|
52
57
|
from .util import get_register_bits_run, get_register_member_name
|
|
53
58
|
|
|
@@ -57,13 +62,19 @@ _GetLines = Callable[["_Node", Item, str, Any], GenericContent]
|
|
|
57
62
|
|
|
58
63
|
def _get_ingroups(item: Item) -> _ItemMap:
|
|
59
64
|
ingroups: _ItemMap = {}
|
|
60
|
-
for group in item
|
|
65
|
+
for group in get_interface_groups(item):
|
|
61
66
|
ingroups[group.uid] = group
|
|
62
67
|
return ingroups
|
|
63
68
|
|
|
64
69
|
|
|
70
|
+
def _get_group_identifier(item: Item) -> str:
|
|
71
|
+
if item.type == "interface/register-block":
|
|
72
|
+
return get_register_block_identifier(item)
|
|
73
|
+
return item["identifier"]
|
|
74
|
+
|
|
75
|
+
|
|
65
76
|
def _get_group_identifiers(groups: _ItemMap) -> list[str]:
|
|
66
|
-
return [item
|
|
77
|
+
return [_get_group_identifier(item) for item in groups.values()]
|
|
67
78
|
|
|
68
79
|
|
|
69
80
|
def _get_cite(ctx: ItemGetValueContext) -> str:
|
|
@@ -269,6 +280,7 @@ class _RegisterMemberContext(NamedTuple):
|
|
|
269
280
|
regs: dict[str, Any]
|
|
270
281
|
reg_counts: dict[str, int]
|
|
271
282
|
reg_indices: dict[str, int]
|
|
283
|
+
parts: list[RegisterBlockPart]
|
|
272
284
|
|
|
273
285
|
|
|
274
286
|
def _add_register_padding(content: CContent, new_offset: int, old_offset: int,
|
|
@@ -409,11 +421,10 @@ def _get_register_bits_shift(start: int, stride: int, first: int) -> str:
|
|
|
409
421
|
return f"( {start} {'+' if stride > 0 else '-'} {term} )"
|
|
410
422
|
|
|
411
423
|
|
|
412
|
-
def _get_register_bits_prefix(item: Item,
|
|
424
|
+
def _get_register_bits_prefix(item: Item, host: Optional[Link],
|
|
425
|
+
reg_name: str) -> str:
|
|
413
426
|
""" Get the define prefix of the bit fields of a register. """
|
|
414
|
-
prefix = item
|
|
415
|
-
if prefix is None:
|
|
416
|
-
prefix = item["name"]
|
|
427
|
+
prefix, _ = get_register_block_prefixes(item, host)
|
|
417
428
|
prefix = f"{prefix}_{reg_name}_" if prefix else f"{reg_name}_"
|
|
418
429
|
return prefix.upper()
|
|
419
430
|
|
|
@@ -507,9 +518,13 @@ class _Node:
|
|
|
507
518
|
""" Nodes of a header file. """
|
|
508
519
|
|
|
509
520
|
# pylint: disable=too-many-instance-attributes
|
|
510
|
-
def __init__(self,
|
|
521
|
+
def __init__(self,
|
|
522
|
+
header_file: "_HeaderFile",
|
|
523
|
+
item: Item,
|
|
524
|
+
host: Optional[Link] = None):
|
|
511
525
|
self.header_file = header_file
|
|
512
526
|
self.item = item
|
|
527
|
+
self.host = host
|
|
513
528
|
self.ingroups = _get_ingroups(item)
|
|
514
529
|
self.dependents: set[_Node] = set()
|
|
515
530
|
self.depends_on: set[_Node] = set()
|
|
@@ -580,22 +595,17 @@ class _Node:
|
|
|
580
595
|
def generate_enum(self) -> None:
|
|
581
596
|
""" Generate an enum. """
|
|
582
597
|
with self._enum_struct_or_union():
|
|
583
|
-
|
|
584
|
-
for parent in
|
|
585
|
-
|
|
586
|
-
|
|
598
|
+
parents = list(self.item.parents("interface-enumerator"))
|
|
599
|
+
for index, parent in enumerate(parents):
|
|
600
|
+
if index > 0:
|
|
601
|
+
self.content.append("")
|
|
602
|
+
self.content.append(self._get_description(parent, {}))
|
|
603
|
+
get_lines = _Node._get_enumerator_definition
|
|
604
|
+
if index < len(parents) - 1:
|
|
605
|
+
get_lines = _Node._get_enumerator_definition_comma
|
|
606
|
+
self.content.append(
|
|
587
607
|
_add_definition(self, parent, "definition",
|
|
588
|
-
parent["definition"],
|
|
589
|
-
_Node._get_enumerator_definition))
|
|
590
|
-
enumerators.append(enumerator)
|
|
591
|
-
for enumerator in enumerators[0:-1]:
|
|
592
|
-
enumerator.last += ","
|
|
593
|
-
enumerator.append("")
|
|
594
|
-
self.content.append(enumerator)
|
|
595
|
-
try:
|
|
596
|
-
self.content.append(enumerators[-1])
|
|
597
|
-
except IndexError:
|
|
598
|
-
pass
|
|
608
|
+
parent["definition"], get_lines))
|
|
599
609
|
|
|
600
610
|
def generate_define(self) -> None:
|
|
601
611
|
""" Generate a define. """
|
|
@@ -623,10 +633,16 @@ class _Node:
|
|
|
623
633
|
""" Generate a macro. """
|
|
624
634
|
self._add_generic_definition(_Node._get_macro_definition)
|
|
625
635
|
|
|
636
|
+
def _new_register_member_context(self) -> _RegisterMemberContext:
|
|
637
|
+
layout = get_register_block_layout(self.item)
|
|
638
|
+
return _RegisterMemberContext({}, {}, collections.defaultdict(int),
|
|
639
|
+
collections.defaultdict(int),
|
|
640
|
+
layout.definition)
|
|
641
|
+
|
|
626
642
|
def _add_register_bits(self, group: str) -> _RegisterMemberContext:
|
|
627
|
-
ctx =
|
|
628
|
-
|
|
629
|
-
|
|
643
|
+
ctx = self._new_register_member_context()
|
|
644
|
+
for part in get_register_block_layout(self.item).registers:
|
|
645
|
+
register = part.data
|
|
630
646
|
name = register["name"]
|
|
631
647
|
group_ident = group + to_camel_case(name)
|
|
632
648
|
width = register["width"]
|
|
@@ -636,17 +652,17 @@ class _Node:
|
|
|
636
652
|
"type": f"uint{width}_t",
|
|
637
653
|
"group": group_ident
|
|
638
654
|
}
|
|
639
|
-
brief = self.substitute_text(register["brief"])
|
|
655
|
+
brief = self.substitute_text(register["brief"], part.item)
|
|
640
656
|
with self.content.defgroup_block(group_ident, f"{brief} ({name})"):
|
|
641
657
|
self.content.add_brief_description(
|
|
642
658
|
"This group contains register bit definitions.")
|
|
643
|
-
self.content.wrap(
|
|
644
|
-
register["description"]))
|
|
659
|
+
self.content.wrap(
|
|
660
|
+
self.substitute_text(register["description"], part.item))
|
|
645
661
|
self.content.add("@{")
|
|
646
662
|
for index_2, bits in enumerate(register["bits"]):
|
|
647
663
|
self.content.add(
|
|
648
664
|
_add_definition(
|
|
649
|
-
self,
|
|
665
|
+
self, part.item, f"{part.prefix}/bits[{index_2}]",
|
|
650
666
|
bits,
|
|
651
667
|
functools.partial(_Node._get_register_bits_definition,
|
|
652
668
|
reg_name=name,
|
|
@@ -656,16 +672,17 @@ class _Node:
|
|
|
656
672
|
|
|
657
673
|
def _add_register_block_includes(self,
|
|
658
674
|
ctx: _RegisterMemberContext) -> None:
|
|
659
|
-
for
|
|
675
|
+
for part in get_register_block_layout(self.item).includes:
|
|
676
|
+
link = part.data
|
|
660
677
|
name = link["name"]
|
|
661
678
|
ctx.regs[name] = {}
|
|
662
679
|
ctx.regs[name]["size"] = link.item["register-block-size"]
|
|
663
680
|
ctx.regs[name]["type"] = link.item["name"]
|
|
664
|
-
ctx.regs[name]["group"] = link.item
|
|
681
|
+
ctx.regs[name]["group"] = get_register_block_identifier(link.item)
|
|
665
682
|
|
|
666
683
|
def _get_register_member_info(self, ctx: _RegisterMemberContext) -> None:
|
|
667
684
|
offset = -1
|
|
668
|
-
for index, member in enumerate(
|
|
685
|
+
for index, member in enumerate(part.data for part in ctx.parts):
|
|
669
686
|
assert member["offset"] > offset
|
|
670
687
|
offset = member["offset"]
|
|
671
688
|
default = [member["default"]] if member["default"] else []
|
|
@@ -689,13 +706,13 @@ class _Node:
|
|
|
689
706
|
self.substitute_text(self.item["brief"]))
|
|
690
707
|
self.content.wrap(self.substitute_text(self.item["description"]))
|
|
691
708
|
self.content.add("@{")
|
|
692
|
-
for
|
|
709
|
+
for part in ctx.parts:
|
|
693
710
|
self.content.add(
|
|
694
711
|
_add_definition(
|
|
695
|
-
self,
|
|
712
|
+
self, part.item, part.prefix, part.data,
|
|
696
713
|
functools.partial(_Node._get_register_define_definition,
|
|
697
714
|
ctx=ctx,
|
|
698
|
-
offset=
|
|
715
|
+
offset=part.data["offset"])))
|
|
699
716
|
self.content.add_close_group()
|
|
700
717
|
|
|
701
718
|
def _add_register_struct(self, ctx: _RegisterMemberContext,
|
|
@@ -708,13 +725,13 @@ class _Node:
|
|
|
708
725
|
default_padding = min(*ctx.sizes.values(), 8)
|
|
709
726
|
offset = 0
|
|
710
727
|
with self.content.indent():
|
|
711
|
-
for index,
|
|
712
|
-
member_offset =
|
|
728
|
+
for index, part in enumerate(ctx.parts):
|
|
729
|
+
member_offset = part.data["offset"]
|
|
713
730
|
_add_register_padding(self.content, member_offset, offset,
|
|
714
731
|
default_padding)
|
|
715
732
|
self.content.add(
|
|
716
733
|
_add_definition(
|
|
717
|
-
self,
|
|
734
|
+
self, part.item, part.prefix, part.data,
|
|
718
735
|
functools.partial(
|
|
719
736
|
_Node._get_register_member_definition, ctx=ctx)))
|
|
720
737
|
offset = member_offset + ctx.sizes[index]
|
|
@@ -729,14 +746,18 @@ class _Node:
|
|
|
729
746
|
else:
|
|
730
747
|
self._add_register_struct(ctx, size)
|
|
731
748
|
|
|
749
|
+
def _add_register_block_dependencies(self) -> None:
|
|
750
|
+
for part in get_register_block_layout(self.item).includes:
|
|
751
|
+
parent = part.data.item
|
|
752
|
+
self.header_file.add_includes(parent)
|
|
753
|
+
self.header_file.add_dependency(self, parent)
|
|
754
|
+
|
|
732
755
|
def generate_register_block(self) -> None:
|
|
733
756
|
""" Generate a register block. """
|
|
734
757
|
self.header_file.add_includes(self.item.map("/c/if/uint32_t"))
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
group = self.item["identifier"]
|
|
739
|
-
name = self.item["register-block-group"]
|
|
758
|
+
self._add_register_block_dependencies()
|
|
759
|
+
group = get_register_block_identifier(self.item, self.host)
|
|
760
|
+
name = get_register_block_group(self.item, self.host)
|
|
740
761
|
with self.content.defgroup_block(group, name):
|
|
741
762
|
self.content.add_ingroup(_get_group_identifiers(self.ingroups))
|
|
742
763
|
self.content.add_brief_description(
|
|
@@ -811,6 +832,11 @@ class _Node:
|
|
|
811
832
|
return f"{name} = {self.substitute_code(definition, prefix)}"
|
|
812
833
|
return f"{name}"
|
|
813
834
|
|
|
835
|
+
def _get_enumerator_definition_comma(self, item: Item, prefix: str,
|
|
836
|
+
definition: Any) -> GenericContent:
|
|
837
|
+
# The comma ends the enumerator line inside each branch of a variant.
|
|
838
|
+
return f"{self._get_enumerator_definition(item, prefix, definition)},"
|
|
839
|
+
|
|
814
840
|
def _get_define_definition(self, item: Item, prefix: str,
|
|
815
841
|
definition: Any) -> GenericContent:
|
|
816
842
|
name = item["name"]
|
|
@@ -865,7 +891,7 @@ class _Node:
|
|
|
865
891
|
definition: Any, reg_name: str,
|
|
866
892
|
reg_width: int) -> GenericContent:
|
|
867
893
|
lines = [] # list[str]
|
|
868
|
-
prefix = _get_register_bits_prefix(self.item, reg_name)
|
|
894
|
+
prefix = _get_register_bits_prefix(self.item, self.host, reg_name)
|
|
869
895
|
for index, bit in enumerate(definition):
|
|
870
896
|
if index != 0:
|
|
871
897
|
lines.append("")
|
|
@@ -875,7 +901,13 @@ class _Node:
|
|
|
875
901
|
bit))
|
|
876
902
|
return lines
|
|
877
903
|
|
|
878
|
-
def
|
|
904
|
+
def _get_offset_prefix(self) -> str:
|
|
905
|
+
prefix = self.item["name"]
|
|
906
|
+
if self.host is not None:
|
|
907
|
+
prefix = self.host.data.get("prefix", None) or prefix
|
|
908
|
+
return prefix.upper()
|
|
909
|
+
|
|
910
|
+
def _get_register_define_definition(self, _item: Item, _prefix: str,
|
|
879
911
|
definition: Any,
|
|
880
912
|
ctx: _RegisterMemberContext,
|
|
881
913
|
offset: int) -> GenericContent:
|
|
@@ -886,7 +918,7 @@ class _Node:
|
|
|
886
918
|
with content.doxygen_block():
|
|
887
919
|
content.add(f"@brief See @ref {ctx.regs[name]['group']}.")
|
|
888
920
|
content.append(
|
|
889
|
-
f"#define {
|
|
921
|
+
f"#define {self._get_offset_prefix()}_{alias.upper()} {offset:#x}")
|
|
890
922
|
return content
|
|
891
923
|
|
|
892
924
|
def _get_register_member_definition(
|
|
@@ -1004,7 +1036,7 @@ class _ZephyrNode(_Node):
|
|
|
1004
1036
|
definition: Any, reg_name: str,
|
|
1005
1037
|
reg_width: int) -> GenericContent:
|
|
1006
1038
|
lines = [] # list[str]
|
|
1007
|
-
prefix = _get_register_bits_prefix(self.item, reg_name)
|
|
1039
|
+
prefix = _get_register_bits_prefix(self.item, self.host, reg_name)
|
|
1008
1040
|
for bit in sorted(definition, key=lambda x: x["start"]):
|
|
1009
1041
|
lines.extend(
|
|
1010
1042
|
_get_zephyr_register_bits_lines(
|
|
@@ -1013,9 +1045,9 @@ class _ZephyrNode(_Node):
|
|
|
1013
1045
|
return lines
|
|
1014
1046
|
|
|
1015
1047
|
def _add_register_bits(self, group: str) -> _RegisterMemberContext:
|
|
1016
|
-
ctx =
|
|
1017
|
-
|
|
1018
|
-
|
|
1048
|
+
ctx = self._new_register_member_context()
|
|
1049
|
+
for part in get_register_block_layout(self.item).registers:
|
|
1050
|
+
register = part.data
|
|
1019
1051
|
name = register["name"]
|
|
1020
1052
|
width = register["width"]
|
|
1021
1053
|
assert width in [8, 16, 32, 64]
|
|
@@ -1024,7 +1056,7 @@ class _ZephyrNode(_Node):
|
|
|
1024
1056
|
for index_2, bits in enumerate(register["bits"]):
|
|
1025
1057
|
self.content.append(
|
|
1026
1058
|
_add_definition(
|
|
1027
|
-
self,
|
|
1059
|
+
self, part.item, f"{part.prefix}/bits[{index_2}]",
|
|
1028
1060
|
bits,
|
|
1029
1061
|
functools.partial(
|
|
1030
1062
|
_ZephyrNode._get_register_bits_definition,
|
|
@@ -1032,34 +1064,36 @@ class _ZephyrNode(_Node):
|
|
|
1032
1064
|
reg_width=width)))
|
|
1033
1065
|
return ctx
|
|
1034
1066
|
|
|
1035
|
-
def
|
|
1067
|
+
def _get_offset_prefix(self) -> str:
|
|
1068
|
+
_, prefix = get_register_block_prefixes(self.item, self.host)
|
|
1069
|
+
return prefix.upper()
|
|
1070
|
+
|
|
1071
|
+
def _get_register_define_definition(self, _item: Item, _prefix: str,
|
|
1036
1072
|
definition: Any,
|
|
1037
1073
|
ctx: _RegisterMemberContext,
|
|
1038
1074
|
offset: int) -> GenericContent:
|
|
1039
1075
|
name, alias = get_register_member_name(definition)
|
|
1040
|
-
|
|
1041
|
-
if prefix is None:
|
|
1042
|
-
prefix = item["name"]
|
|
1043
|
-
define = f"#define {prefix.upper()}_{alias.upper()}"
|
|
1076
|
+
define = f"#define {self._get_offset_prefix()}_{alias.upper()}"
|
|
1044
1077
|
count = definition["count"]
|
|
1045
1078
|
if count == 1:
|
|
1046
1079
|
return f"{define} {offset:#x}U"
|
|
1047
1080
|
return f"{define}(i) ({offset:#x}U + {ctx.regs[name]['size']}U * (i))"
|
|
1048
1081
|
|
|
1049
1082
|
def _add_register_defines(self, ctx: _RegisterMemberContext) -> None:
|
|
1050
|
-
for
|
|
1083
|
+
for part in ctx.parts:
|
|
1051
1084
|
self.content.append(
|
|
1052
1085
|
_add_definition(
|
|
1053
|
-
self,
|
|
1086
|
+
self, part.item, part.prefix, part.data,
|
|
1054
1087
|
functools.partial(
|
|
1055
1088
|
_ZephyrNode._get_register_define_definition,
|
|
1056
1089
|
ctx=ctx,
|
|
1057
|
-
offset=
|
|
1090
|
+
offset=part.data["offset"])))
|
|
1058
1091
|
|
|
1059
1092
|
def _add_register_block_includes(self,
|
|
1060
1093
|
ctx: _RegisterMemberContext) -> None:
|
|
1061
1094
|
super()._add_register_block_includes(ctx)
|
|
1062
|
-
for
|
|
1095
|
+
for part in get_register_block_layout(self.item).includes:
|
|
1096
|
+
link = part.data
|
|
1063
1097
|
# Register block structures are not typedefed in this style
|
|
1064
1098
|
ctx.regs[link["name"]]["type"] = f"struct {link.item['name']}"
|
|
1065
1099
|
|
|
@@ -1089,13 +1123,13 @@ class _ZephyrNode(_Node):
|
|
|
1089
1123
|
default_padding = min(*ctx.sizes.values(), 8)
|
|
1090
1124
|
offset = 0
|
|
1091
1125
|
with self.content.indent():
|
|
1092
|
-
for index,
|
|
1093
|
-
member_offset =
|
|
1126
|
+
for index, part in enumerate(ctx.parts):
|
|
1127
|
+
member_offset = part.data["offset"]
|
|
1094
1128
|
self._append_register_padding(member_offset, offset,
|
|
1095
1129
|
default_padding)
|
|
1096
1130
|
self.content.append(
|
|
1097
1131
|
_add_definition(
|
|
1098
|
-
self,
|
|
1132
|
+
self, part.item, part.prefix, part.data,
|
|
1099
1133
|
functools.partial(
|
|
1100
1134
|
_ZephyrNode._get_register_member_definition,
|
|
1101
1135
|
ctx=ctx)))
|
|
@@ -1106,19 +1140,17 @@ class _ZephyrNode(_Node):
|
|
|
1106
1140
|
|
|
1107
1141
|
def generate_register_block(self) -> None:
|
|
1108
1142
|
domain, size = _get_register_domain_and_size(self.item)
|
|
1109
|
-
self.header_file.add_includes(
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
group = self.item["identifier"]
|
|
1114
|
-
name = self.item["register-block-group"]
|
|
1115
|
-
ctx = self._add_register_bits(group)
|
|
1143
|
+
self.header_file.add_includes(
|
|
1144
|
+
self.item.map(self.header_file.register_bit_macros))
|
|
1145
|
+
self._add_register_block_dependencies()
|
|
1146
|
+
ctx = self._add_register_bits("")
|
|
1116
1147
|
self._add_register_block_includes(ctx)
|
|
1117
1148
|
self._get_register_member_info(ctx)
|
|
1118
1149
|
if domain == "memory":
|
|
1119
1150
|
self.header_file.add_includes(self.item.map("/c/if/uint32_t"))
|
|
1120
1151
|
self._add_register_struct(ctx, size)
|
|
1121
1152
|
else:
|
|
1153
|
+
name = get_register_block_group(self.item, self.host)
|
|
1122
1154
|
self.content.add(f"/* {name} address offsets */")
|
|
1123
1155
|
self._add_register_defines(ctx)
|
|
1124
1156
|
|
|
@@ -1173,6 +1205,9 @@ def _merge_enabled_by(options: dict[str, Item], link: Link) -> Any:
|
|
|
1173
1205
|
return {"and": [enabled_by, enabled_by_2]}
|
|
1174
1206
|
|
|
1175
1207
|
|
|
1208
|
+
DEFAULT_REGISTER_BIT_MACROS = "/zephyr/kernel/sys-util/if/genmask"
|
|
1209
|
+
|
|
1210
|
+
|
|
1176
1211
|
class _HeaderFile:
|
|
1177
1212
|
""" A header file. """
|
|
1178
1213
|
|
|
@@ -1184,7 +1219,8 @@ class _HeaderFile:
|
|
|
1184
1219
|
context: ContentContext,
|
|
1185
1220
|
option_expressions: OptionExpressions,
|
|
1186
1221
|
formatter: Optional[ClangFormatter] = None,
|
|
1187
|
-
item_marker: str = DEFAULT_ITEM_MARKER
|
|
1222
|
+
item_marker: str = DEFAULT_ITEM_MARKER,
|
|
1223
|
+
register_bit_macros: str = DEFAULT_REGISTER_BIT_MACROS):
|
|
1188
1224
|
# pylint: disable=too-many-arguments
|
|
1189
1225
|
# pylint: disable=too-many-positional-arguments
|
|
1190
1226
|
self._item = item
|
|
@@ -1197,6 +1233,7 @@ class _HeaderFile:
|
|
|
1197
1233
|
self.options = options
|
|
1198
1234
|
self.enabled = enabled
|
|
1199
1235
|
self.item_marker = item_marker
|
|
1236
|
+
self.register_bit_macros = register_bit_macros
|
|
1200
1237
|
self._option_expressions = option_expressions
|
|
1201
1238
|
|
|
1202
1239
|
def option_expression(self, option: str) -> str:
|
|
@@ -1204,18 +1241,42 @@ class _HeaderFile:
|
|
|
1204
1241
|
return self._option_expressions.get_expression(self._item, option)
|
|
1205
1242
|
|
|
1206
1243
|
def add_includes(self, item: Item) -> None:
|
|
1207
|
-
"""
|
|
1244
|
+
"""
|
|
1245
|
+
Add the includes of the item to the header file includes.
|
|
1246
|
+
|
|
1247
|
+
A register block which header files host adds the host of the domain
|
|
1248
|
+
of this header file.
|
|
1249
|
+
"""
|
|
1208
1250
|
for parent in item.parents("interface-placement"):
|
|
1209
1251
|
if parent.type in [
|
|
1210
1252
|
"interface/header-file",
|
|
1211
1253
|
"interface/unspecified-header-file"
|
|
1212
1254
|
]:
|
|
1213
1255
|
self._includes.append(parent)
|
|
1256
|
+
if get_register_block_hosts(item):
|
|
1257
|
+
self._includes.append(
|
|
1258
|
+
get_register_block_host_of_domain(
|
|
1259
|
+
item, self._item.parent("interface-placement")).item)
|
|
1214
1260
|
|
|
1215
1261
|
def add_node(self, item: Item) -> None:
|
|
1216
1262
|
""" Add a node for the item. """
|
|
1217
1263
|
self._nodes[item.uid] = _Node(self, item)
|
|
1218
1264
|
|
|
1265
|
+
def add_hosted_node(self, link: Link) -> None:
|
|
1266
|
+
""" Add a node for the register block of the host link. """
|
|
1267
|
+
item = link.item
|
|
1268
|
+
if item.type != "interface/register-block":
|
|
1269
|
+
raise ValueError(f"header file '{self._item.uid}' hosts "
|
|
1270
|
+
f"'{item.uid}' which is no register block")
|
|
1271
|
+
if any(True for _ in item.parents("interface-placement")):
|
|
1272
|
+
raise ValueError(f"register block '{item.uid}' has an interface "
|
|
1273
|
+
"placement and header file "
|
|
1274
|
+
f"'{self._item.uid}' hosts it")
|
|
1275
|
+
get_register_block_host_of_domain(
|
|
1276
|
+
item, self._item.parent("interface-placement"))
|
|
1277
|
+
node_type = _ZephyrNode if link["style"] == "zephyr" else _Node
|
|
1278
|
+
self._nodes[item.uid] = node_type(self, item, link)
|
|
1279
|
+
|
|
1219
1280
|
def add_dependency(self, node: _Node, item: Item) -> None:
|
|
1220
1281
|
"""
|
|
1221
1282
|
Add a dependency from a node to another node identified by an item if
|
|
@@ -1231,6 +1292,9 @@ class _HeaderFile:
|
|
|
1231
1292
|
for child in self._item.children("interface-placement"):
|
|
1232
1293
|
self.add_node(child)
|
|
1233
1294
|
self.content.register_license_and_copyrights_of_item(child)
|
|
1295
|
+
for link in self._item.links_to_parents("register-block-host"):
|
|
1296
|
+
self.add_hosted_node(link)
|
|
1297
|
+
self.content.register_license_and_copyrights_of_item(link.item)
|
|
1234
1298
|
for node in self._nodes.values():
|
|
1235
1299
|
node.generate()
|
|
1236
1300
|
|
|
@@ -1362,7 +1426,8 @@ def _generate_header_file(item: Item, config: dict, options: dict[str, Item],
|
|
|
1362
1426
|
header_file = _HEADER_FILE[config.get("style", "default")](
|
|
1363
1427
|
item, options, config["enabled"], context,
|
|
1364
1428
|
OptionExpressions(config["option-expressions"]), formatter,
|
|
1365
|
-
config.get("item-marker", DEFAULT_ITEM_MARKER)
|
|
1429
|
+
config.get("item-marker", DEFAULT_ITEM_MARKER),
|
|
1430
|
+
config.get("register-bit-macros", DEFAULT_REGISTER_BIT_MACROS))
|
|
1366
1431
|
header_file.generate_nodes()
|
|
1367
1432
|
header_file.finalize()
|
|
1368
1433
|
header_file.write(domain_path, file_path)
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-2-Clause
|
|
2
|
+
""" Provides the placement and the layout of register blocks. """
|
|
3
|
+
|
|
4
|
+
# Copyright (C) 2026 embedded brains GmbH & Co. KG
|
|
5
|
+
#
|
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
|
7
|
+
# modification, are permitted provided that the following conditions
|
|
8
|
+
# are met:
|
|
9
|
+
# 1. Redistributions of source code must retain the above copyright
|
|
10
|
+
# notice, this list of conditions and the following disclaimer.
|
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
|
12
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
13
|
+
# documentation and/or other materials provided with the distribution.
|
|
14
|
+
#
|
|
15
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
16
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
17
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
18
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
19
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
20
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
21
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
22
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
23
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
24
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
25
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
|
26
|
+
|
|
27
|
+
from typing import Any, NamedTuple, Optional
|
|
28
|
+
|
|
29
|
+
from specitems import Item, Link
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"RegisterBlockLayout", "RegisterBlockPart", "get_group_members",
|
|
33
|
+
"get_interface_container", "get_interface_groups", "get_interface_members",
|
|
34
|
+
"get_register_block_base", "get_register_block_group",
|
|
35
|
+
"get_register_block_host_of_domain", "get_register_block_hosts",
|
|
36
|
+
"get_register_block_identifier", "get_register_block_layout",
|
|
37
|
+
"get_register_block_prefixes"
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_register_block_hosts(item: Item) -> list[Link]:
|
|
42
|
+
"""
|
|
43
|
+
Get the links of the header files which host the register block.
|
|
44
|
+
|
|
45
|
+
Each link is a link from the header file to the register block, so
|
|
46
|
+
``link.item`` is the header file. The links are sorted by the UID of the
|
|
47
|
+
header file.
|
|
48
|
+
"""
|
|
49
|
+
return sorted(item.links_to_children("register-block-host"),
|
|
50
|
+
key=lambda link: link.item.uid)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_register_block_host_of_domain(item: Item, domain: Item) -> Link:
|
|
54
|
+
"""
|
|
55
|
+
Get the link of the header file of the domain which hosts the register
|
|
56
|
+
block.
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
ValueError: No header file or more than one header file of the domain
|
|
60
|
+
hosts the register block.
|
|
61
|
+
"""
|
|
62
|
+
hosts = [
|
|
63
|
+
link for link in get_register_block_hosts(item)
|
|
64
|
+
if link.item.parent("interface-placement") == domain
|
|
65
|
+
]
|
|
66
|
+
if not hosts:
|
|
67
|
+
raise ValueError(f"no header file of domain '{domain.uid}' hosts "
|
|
68
|
+
f"register block '{item.uid}'")
|
|
69
|
+
if len(hosts) > 1:
|
|
70
|
+
raise ValueError(f"more than one header file of domain "
|
|
71
|
+
f"'{domain.uid}' hosts register block '{item.uid}': "
|
|
72
|
+
f"{', '.join(link.item.uid for link in hosts)}")
|
|
73
|
+
return hosts[0]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_interface_members(item: Item) -> list[Item]:
|
|
77
|
+
"""
|
|
78
|
+
Get the interfaces which the interface container places.
|
|
79
|
+
|
|
80
|
+
These are the children of the ``interface-placement`` links and the
|
|
81
|
+
register blocks of the ``register-block-host`` links of the container.
|
|
82
|
+
"""
|
|
83
|
+
return list(item.children("interface-placement")) + list(
|
|
84
|
+
item.parents("register-block-host"))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_interface_groups(item: Item) -> list[Item]:
|
|
88
|
+
"""
|
|
89
|
+
Get the interface groups of the interface.
|
|
90
|
+
|
|
91
|
+
These are the parents of the ``interface-ingroup`` links of the interface
|
|
92
|
+
and the groups which link to the interface through the
|
|
93
|
+
``interface-group-member`` role.
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
ValueError: A group links to an interface which is no register block.
|
|
97
|
+
"""
|
|
98
|
+
members = list(item.children("interface-group-member"))
|
|
99
|
+
if members and item.type != "interface/register-block":
|
|
100
|
+
raise ValueError(f"group '{members[0].uid}' has the member "
|
|
101
|
+
f"'{item.uid}' which is no register block")
|
|
102
|
+
groups = dict(
|
|
103
|
+
(group.uid, group) for group in item.parents("interface-ingroup"))
|
|
104
|
+
groups.update((group.uid, group) for group in members)
|
|
105
|
+
return list(groups.values())
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_group_members(item: Item) -> list[Item]:
|
|
109
|
+
"""
|
|
110
|
+
Get the members of the interface group.
|
|
111
|
+
|
|
112
|
+
These are the children of the ``interface-ingroup`` links of the group
|
|
113
|
+
and the parents of its ``interface-group-member`` links.
|
|
114
|
+
"""
|
|
115
|
+
return list(item.children("interface-ingroup")) + list(
|
|
116
|
+
item.parents("interface-group-member"))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def get_interface_container(item: Item) -> Item:
|
|
120
|
+
"""
|
|
121
|
+
Get the interface container of the interface.
|
|
122
|
+
|
|
123
|
+
The container is the parent of the ``interface-placement`` link. A
|
|
124
|
+
register block without such a link resides in the first header file which
|
|
125
|
+
hosts it.
|
|
126
|
+
|
|
127
|
+
Raises:
|
|
128
|
+
IndexError: The interface resides in no container.
|
|
129
|
+
"""
|
|
130
|
+
try:
|
|
131
|
+
return item.parent("interface-placement")
|
|
132
|
+
except IndexError:
|
|
133
|
+
hosts = get_register_block_hosts(item)
|
|
134
|
+
if not hosts:
|
|
135
|
+
raise
|
|
136
|
+
return hosts[0].item
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _get_block_value(item: Item, host: Optional[Link], key: str) -> Any:
|
|
140
|
+
if host is not None:
|
|
141
|
+
value = host.data.get(key, None)
|
|
142
|
+
if value is not None:
|
|
143
|
+
return value
|
|
144
|
+
else:
|
|
145
|
+
values = set(link.data[key] for link in get_register_block_hosts(item)
|
|
146
|
+
if link.data.get(key, None) is not None)
|
|
147
|
+
if len(values) > 1:
|
|
148
|
+
raise ValueError(f"the header files which host register block "
|
|
149
|
+
f"'{item.uid}' state different values for "
|
|
150
|
+
f"'{key}': {', '.join(sorted(values))}")
|
|
151
|
+
if values:
|
|
152
|
+
return values.pop()
|
|
153
|
+
value = item.get(key, None)
|
|
154
|
+
if value is None:
|
|
155
|
+
raise ValueError(f"register block '{item.uid}' has no '{key}' and no "
|
|
156
|
+
"host link states one")
|
|
157
|
+
return value
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def get_register_block_identifier(item: Item,
|
|
161
|
+
host: Optional[Link] = None) -> str:
|
|
162
|
+
"""
|
|
163
|
+
Get the interface group identifier of the register block.
|
|
164
|
+
|
|
165
|
+
The value of the host link takes precedence over the value of the block.
|
|
166
|
+
Without a host link, the value of the host links of the block takes
|
|
167
|
+
precedence.
|
|
168
|
+
"""
|
|
169
|
+
return _get_block_value(item, host, "identifier")
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def get_register_block_group(item: Item, host: Optional[Link] = None) -> str:
|
|
173
|
+
"""
|
|
174
|
+
Get the interface group name of the register block.
|
|
175
|
+
|
|
176
|
+
The value of the host link takes precedence over the value of the block.
|
|
177
|
+
Without a host link, the value of the host links of the block takes
|
|
178
|
+
precedence.
|
|
179
|
+
"""
|
|
180
|
+
return _get_block_value(item, host, "register-block-group")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def get_register_block_prefixes(item: Item,
|
|
184
|
+
host: Optional[Link] = None
|
|
185
|
+
) -> tuple[str, str]:
|
|
186
|
+
"""
|
|
187
|
+
Get the register prefix and the offset prefix of the register block.
|
|
188
|
+
|
|
189
|
+
The prefix of the host link replaces both prefixes of the block. A
|
|
190
|
+
missing prefix of the block is the name of the block.
|
|
191
|
+
"""
|
|
192
|
+
if host is not None:
|
|
193
|
+
prefix = host.data.get("prefix", None)
|
|
194
|
+
if prefix is not None:
|
|
195
|
+
return prefix, prefix
|
|
196
|
+
register_prefix = item["register-prefix"]
|
|
197
|
+
if register_prefix is None:
|
|
198
|
+
register_prefix = item["name"]
|
|
199
|
+
offset_prefix = item.get("offset-prefix", None)
|
|
200
|
+
if offset_prefix is None:
|
|
201
|
+
offset_prefix = item["name"]
|
|
202
|
+
return register_prefix, offset_prefix
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def get_register_block_base(item: Item) -> Optional[Item]:
|
|
206
|
+
"""
|
|
207
|
+
Get the base of the register block.
|
|
208
|
+
|
|
209
|
+
Raises:
|
|
210
|
+
ValueError: The block has more than one base.
|
|
211
|
+
"""
|
|
212
|
+
bases = list(item.parents("register-block-base"))
|
|
213
|
+
if len(bases) > 1:
|
|
214
|
+
raise ValueError(f"register block '{item.uid}' has more than one "
|
|
215
|
+
"base")
|
|
216
|
+
return bases[0] if bases else None
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class RegisterBlockPart(NamedTuple):
|
|
220
|
+
"""
|
|
221
|
+
Is a register, a member or an include link of a register block layout.
|
|
222
|
+
"""
|
|
223
|
+
item: Item
|
|
224
|
+
prefix: str
|
|
225
|
+
data: Any
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class RegisterBlockLayout(NamedTuple):
|
|
229
|
+
"""
|
|
230
|
+
Is the layout of a register block which includes the parts of its bases.
|
|
231
|
+
"""
|
|
232
|
+
registers: list[RegisterBlockPart]
|
|
233
|
+
definition: list[RegisterBlockPart]
|
|
234
|
+
includes: list[RegisterBlockPart]
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _own_layout(item: Item) -> RegisterBlockLayout:
|
|
238
|
+
return RegisterBlockLayout([
|
|
239
|
+
RegisterBlockPart(item, f"registers[{index}]", register)
|
|
240
|
+
for index, register in enumerate(item["registers"])
|
|
241
|
+
], [
|
|
242
|
+
RegisterBlockPart(item, f"definition[{index}]", member)
|
|
243
|
+
for index, member in enumerate(item["definition"])
|
|
244
|
+
], [
|
|
245
|
+
RegisterBlockPart(item, "", link)
|
|
246
|
+
for link in item.links_to_parents("register-block-include")
|
|
247
|
+
])
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _derive_layout(item: Item, base: RegisterBlockLayout,
|
|
251
|
+
own: RegisterBlockLayout) -> RegisterBlockLayout:
|
|
252
|
+
include_names = set(part.data["name"] for part in base.includes)
|
|
253
|
+
for part in own.includes:
|
|
254
|
+
name = part.data["name"]
|
|
255
|
+
if name in include_names or any(part_2.data["name"] == name
|
|
256
|
+
for part_2 in base.registers):
|
|
257
|
+
raise ValueError(f"register block '{item.uid}' includes a "
|
|
258
|
+
f"register block named '{name}' which its base "
|
|
259
|
+
"defines")
|
|
260
|
+
registers = list(base.registers)
|
|
261
|
+
for part in own.registers:
|
|
262
|
+
name = part.data["name"]
|
|
263
|
+
if name in include_names:
|
|
264
|
+
raise ValueError(f"register '{name}' of register block "
|
|
265
|
+
f"'{item.uid}' has the name of a register block "
|
|
266
|
+
"which its base includes")
|
|
267
|
+
for index, part_2 in enumerate(registers):
|
|
268
|
+
if part_2.data["name"] == name:
|
|
269
|
+
registers[index] = part
|
|
270
|
+
break
|
|
271
|
+
else:
|
|
272
|
+
registers.append(part)
|
|
273
|
+
members = dict((part.data["offset"], part) for part in base.definition)
|
|
274
|
+
members.update((part.data["offset"], part) for part in own.definition)
|
|
275
|
+
return RegisterBlockLayout(registers,
|
|
276
|
+
[members[offset] for offset in sorted(members)],
|
|
277
|
+
base.includes + own.includes)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _get_layout(item: Item, visited: set[str]) -> RegisterBlockLayout:
|
|
281
|
+
if item.uid in visited:
|
|
282
|
+
raise ValueError(f"register block '{item.uid}' is its own base")
|
|
283
|
+
visited.add(item.uid)
|
|
284
|
+
own = _own_layout(item)
|
|
285
|
+
base = get_register_block_base(item)
|
|
286
|
+
if base is None:
|
|
287
|
+
return own
|
|
288
|
+
return _derive_layout(item, _get_layout(base, visited), own)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def get_register_block_layout(item: Item) -> RegisterBlockLayout:
|
|
292
|
+
"""
|
|
293
|
+
Get the layout of the register block.
|
|
294
|
+
|
|
295
|
+
A derivative starts with the layout of its base. A register of the name
|
|
296
|
+
of a base register replaces the base register. A member at the offset of
|
|
297
|
+
a base member replaces the base member. The derivative adds its other
|
|
298
|
+
registers, members and includes.
|
|
299
|
+
"""
|
|
300
|
+
return _get_layout(item, set())
|
|
@@ -31,6 +31,8 @@ from typing import Any, Callable, Iterable
|
|
|
31
31
|
from specitems import (EnabledSet, Item, ItemCache, create_unique_link,
|
|
32
32
|
link_is_enabled, to_iterable)
|
|
33
33
|
|
|
34
|
+
from .registerblock import get_interface_members
|
|
35
|
+
|
|
34
36
|
_NOT_PRE_QUALIFIED = frozenset((
|
|
35
37
|
"/acfg/constraint/option-not-pre-qualified",
|
|
36
38
|
"/constraint/constant-not-pre-qualified",
|
|
@@ -49,6 +51,10 @@ _ENABLEMENT_ROLES = ("interface-function", "interface-ingroup",
|
|
|
49
51
|
"interface-ingroup-hidden", "requirement-refinement",
|
|
50
52
|
"validation")
|
|
51
53
|
|
|
54
|
+
# An item is enabled through the items which link to it by these roles.
|
|
55
|
+
_ENABLEMENT_CHILD_ROLES = ("interface-group-member", "register-block-base",
|
|
56
|
+
"register-block-host", "register-block-include")
|
|
57
|
+
|
|
52
58
|
|
|
53
59
|
def recursive_is_enabled(enabled_set: EnabledSet, item: Item) -> bool:
|
|
54
60
|
"""
|
|
@@ -58,8 +64,10 @@ def recursive_is_enabled(enabled_set: EnabledSet, item: Item) -> bool:
|
|
|
58
64
|
if not item.is_enabled(enabled_set):
|
|
59
65
|
return False
|
|
60
66
|
result = True
|
|
61
|
-
for parent in
|
|
62
|
-
|
|
67
|
+
for parent in itertools.chain(
|
|
68
|
+
item.parents(_ENABLEMENT_ROLES, is_link_enabled=link_is_enabled),
|
|
69
|
+
item.children(_ENABLEMENT_CHILD_ROLES,
|
|
70
|
+
is_link_enabled=link_is_enabled)):
|
|
63
71
|
if recursive_is_enabled(enabled_set, parent):
|
|
64
72
|
return True
|
|
65
73
|
result = False
|
|
@@ -123,21 +131,25 @@ _CHILD_ROLES = ("requirement-refinement", "interface-ingroup",
|
|
|
123
131
|
_PARENT_ROLES = ("function-implementation", "interface-enumerator",
|
|
124
132
|
"performance-runtime-limits")
|
|
125
133
|
|
|
126
|
-
#
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
#
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
# Through this role, a group is the child of each of its members.
|
|
135
|
+
_VALIDATION_PARENT_ROLES = _PARENT_ROLES + ("interface-group-member", )
|
|
136
|
+
|
|
137
|
+
# WARNING: These role sets work only with _visit_tree() which stops the
|
|
138
|
+
# recursion once it sees an item the second time. The appl-config-group-member
|
|
139
|
+
# role supports older versions of the RTEMS specification which used this group
|
|
140
|
+
# membership role.
|
|
141
|
+
_VISIT_CHILD_ROLES = _CHILD_ROLES + ("appl-config-group-member",
|
|
142
|
+
"interface-placement")
|
|
143
|
+
|
|
144
|
+
_VISIT_PARENT_ROLES = _VALIDATION_PARENT_ROLES + ("register-block-host", )
|
|
132
145
|
|
|
133
146
|
|
|
134
147
|
def _visit_tree(item: Item, related_items: set[Item]) -> None:
|
|
135
148
|
if item in related_items:
|
|
136
149
|
return
|
|
137
150
|
related_items.add(item)
|
|
138
|
-
for item_2 in itertools.chain(
|
|
139
|
-
|
|
140
|
-
item.parents(_PARENT_ROLES)):
|
|
151
|
+
for item_2 in itertools.chain(item.children(_VISIT_CHILD_ROLES),
|
|
152
|
+
item.parents(_VISIT_PARENT_ROLES)):
|
|
141
153
|
_visit_tree(item_2, related_items)
|
|
142
154
|
|
|
143
155
|
|
|
@@ -158,14 +170,15 @@ _EXPORT_CHILD_ROLES = ("interface-function", "interface-placement",
|
|
|
158
170
|
"requirement-disposition", "requirement-refinement",
|
|
159
171
|
"test-case", "validation")
|
|
160
172
|
|
|
161
|
-
_EXPORT_PARENT_ROLES = _PARENT_ROLES + (
|
|
162
|
-
|
|
173
|
+
_EXPORT_PARENT_ROLES = _PARENT_ROLES + (
|
|
174
|
+
"constraint", "errno", "register-block-base", "register-block-host",
|
|
175
|
+
"register-block-include")
|
|
163
176
|
|
|
164
177
|
# Items reached through the shallow roles contribute to the generated content
|
|
165
178
|
# of the visiting item, however, the items related to them do not. Expanding
|
|
166
179
|
# them would relate a header file to every item of each included header file
|
|
167
180
|
# and to every member of each interface group.
|
|
168
|
-
_EXPORT_SHALLOW_CHILD_ROLES = ("placement-order"
|
|
181
|
+
_EXPORT_SHALLOW_CHILD_ROLES = ("interface-group-member", "placement-order")
|
|
169
182
|
|
|
170
183
|
_EXPORT_SHALLOW_PARENT_ROLES = ("interface-include", "interface-ingroup",
|
|
171
184
|
"interface-ingroup-hidden", "interface-target")
|
|
@@ -420,8 +433,9 @@ def _validate_tree(item: Item, validator: Callable[[Item, bool], bool],
|
|
|
420
433
|
validation_dependencies: list[tuple[str, str]] = []
|
|
421
434
|
for index, link in enumerate(
|
|
422
435
|
sorted(
|
|
423
|
-
itertools.chain(
|
|
424
|
-
|
|
436
|
+
itertools.chain(
|
|
437
|
+
item.links_to_children(_CHILD_ROLES),
|
|
438
|
+
item.links_to_parents(_VALIDATION_PARENT_ROLES)))):
|
|
425
439
|
item_2 = link.item
|
|
426
440
|
validated = _validate_tree(item_2, validator, order[:-1] +
|
|
427
441
|
(order[-1] + index + 1, 0),
|
|
@@ -430,7 +444,8 @@ def _validate_tree(item: Item, validator: Callable[[Item, bool], bool],
|
|
|
430
444
|
role = _VALIDATION_METHOD[item_2.type]
|
|
431
445
|
elif link.role == "requirement-refinement":
|
|
432
446
|
role = "refinement"
|
|
433
|
-
elif link.role.startswith("interface-ingroup")
|
|
447
|
+
elif link.role.startswith("interface-ingroup") or (
|
|
448
|
+
link.role == "interface-group-member"):
|
|
434
449
|
role = "group member"
|
|
435
450
|
else:
|
|
436
451
|
role = link.role.replace("-", " ")
|
|
@@ -445,7 +460,7 @@ def _validate_tree(item: Item, validator: Callable[[Item, bool], bool],
|
|
|
445
460
|
if type_name in _CONTAINER_TYPE:
|
|
446
461
|
validation_dependencies.extend(
|
|
447
462
|
(item_2.uid, "interface placement")
|
|
448
|
-
for item_2 in item
|
|
463
|
+
for item_2 in get_interface_members(item))
|
|
449
464
|
validated = validator(item, validated)
|
|
450
465
|
item.view["validated"] = validated
|
|
451
466
|
item.view["validation-dependencies"] = sorted(validation_dependencies)
|
|
@@ -457,7 +472,7 @@ def _validate_containers(item: Item) -> bool:
|
|
|
457
472
|
if item.type in _CONTAINER_TYPE:
|
|
458
473
|
# If at least one not validated child exists, then the container is not
|
|
459
474
|
# validated
|
|
460
|
-
for item_2 in item
|
|
475
|
+
for item_2 in get_interface_members(item):
|
|
461
476
|
try:
|
|
462
477
|
if not item_2.view["validated"]:
|
|
463
478
|
validated = False
|
|
@@ -468,19 +483,20 @@ def _validate_containers(item: Item) -> bool:
|
|
|
468
483
|
f"{item.uid} container member "
|
|
469
484
|
f"{item_2.uid} has no validated status") from err
|
|
470
485
|
for item_2 in itertools.chain(item.children(_CHILD_ROLES),
|
|
471
|
-
item.parents(
|
|
486
|
+
item.parents(_VALIDATION_PARENT_ROLES)):
|
|
472
487
|
validated = _validate_containers(item_2) and validated
|
|
473
488
|
return validated
|
|
474
489
|
|
|
475
490
|
|
|
476
|
-
def _fixup_pre_qualified(
|
|
477
|
-
|
|
491
|
+
def _fixup_pre_qualified(
|
|
492
|
+
item: Item, types: list[str],
|
|
493
|
+
get_members: Callable[[Item], Iterable[Item]]) -> None:
|
|
478
494
|
for type_name in types:
|
|
479
495
|
for item_2 in item.cache.items_by_type.get(type_name, []):
|
|
480
496
|
# Count of not pre-qualified (index 0) and pre-qualified (index 1)
|
|
481
497
|
# children
|
|
482
498
|
count = [0, 0]
|
|
483
|
-
for item_3 in item_2
|
|
499
|
+
for item_3 in get_members(item_2):
|
|
484
500
|
count[int(item_3.view["pre-qualified"])] += 1
|
|
485
501
|
# If at least one not pre-qualified child exists and no
|
|
486
502
|
# pre-qualified child exists, then the item is not pre-qualified.
|
|
@@ -497,11 +513,13 @@ def validate(root: Item, validator: Callable[[Item, bool], bool]) -> set[Item]:
|
|
|
497
513
|
related_items: set[Item] = set()
|
|
498
514
|
_validate_tree(root, validator, (0, ), related_items)
|
|
499
515
|
_validate_containers(root)
|
|
500
|
-
_fixup_pre_qualified(
|
|
501
|
-
|
|
502
|
-
|
|
516
|
+
_fixup_pre_qualified(
|
|
517
|
+
root, ["interface/appl-config-group", "interface/group"],
|
|
518
|
+
lambda item_2: itertools.chain(
|
|
519
|
+
item_2.children(["interface-ingroup", "interface-ingroup-hidden"]),
|
|
520
|
+
item_2.parents("interface-group-member")))
|
|
503
521
|
_fixup_pre_qualified(root, ["interface/header-file"],
|
|
504
|
-
|
|
522
|
+
get_interface_members)
|
|
505
523
|
return related_items
|
|
506
524
|
|
|
507
525
|
|
|
index 0fbcbe6..51e706e 100644
|
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|