Source code for ifgen.svd.task

"""
A module implementing an SVD-processing task interface.
"""

# built-in
from dataclasses import dataclass
from logging import getLogger
from pathlib import Path
from typing import Callable, Iterable, Iterator
from xml.etree import ElementTree

# third-party
from vcorelib.io import ARBITER
from vcorelib.logging import LoggerType
from vcorelib.paths import rel

# internal
from ifgen.config.svd import SvdConfig
from ifgen.svd.group import handle_group, peripheral_groups
from ifgen.svd.model import SvdModel

TagProcessor = Callable[
    [ElementTree.Element, "SvdProcessingTask", LoggerType], None
]
TagProcessorMap = dict[str, TagProcessor]
TAG_PROCESSORS: TagProcessorMap = {}


[docs] def filter_includes( config: SvdConfig, model: SvdModel, paths: Iterable[Path], filtered: dict[str, str], ) -> Iterator[str]: """Filter includes based on configuration.""" config_data = config.data.setdefault("devices", {}).setdefault( model.device_name.lower(), {"ignore_peripherals": []} ) for path in paths: item = str(path) reason = None # Determine a possible reason to filter this include. for ignore in config_data["ignore_peripherals"]: if path.parts[0] == ignore["name"]: reason = ignore["reason"] if reason is not None: filtered[item] = reason else: yield item
[docs] @dataclass class SvdProcessingTask: """A container for SVD-processing state.""" model: SvdModel min_enum_width: int
[docs] def process(self, elem: ElementTree.Element) -> None: """Process a single element.""" TAG_PROCESSORS[elem.tag](elem, self, getLogger(elem.tag))
[docs] @staticmethod def svd(path: Path, min_enum_width: int) -> "SvdProcessingTask": """Process a single SVD file.""" task = SvdProcessingTask(SvdModel({}), min_enum_width) task.process(ElementTree.parse(path).getroot()) return task
[docs] def generate_configs(self, path: Path, config: SvdConfig) -> None: """Generate output configuration files.""" path.mkdir(exist_ok=True, parents=True) includes: set[Path] = set() # Organize peripherals into groups based on ones derived from others # and process them. for group in peripheral_groups(self.model.peripherals).values(): output_dir = path.joinpath(group.root.base_name()) output_dir.mkdir(exist_ok=True) handle_group(output_dir, group, includes, self.min_enum_width) # Write metadata that doesn't currently get used for generation. meta = self.model.metadata() # Indicate includes that were filtered out in metadata. filtered: dict[str, str] = {} meta["filtered_includes"] = filtered ARBITER.encode( path.joinpath("ifgen.yaml"), { "includes": sorted( # type: ignore filter_includes( config, self.model, (rel(x.resolve(), base=path) for x in includes), filtered, ) ), "namespace": self.model.namespace(), # type: ignore "struct": { "stream": False, "codec": False, "methods": False, "unit_test": False, "packed": False, }, "enum": {"use_map": False, "identifier": False}, }, ) ARBITER.encode(path.joinpath("metadata.json"), meta)