diff --git a/src/peakrdl_busdecoder/__peakrdl__.py b/src/peakrdl_busdecoder/__peakrdl__.py index 2f59c7f..36096cc 100644 --- a/src/peakrdl_busdecoder/__peakrdl__.py +++ b/src/peakrdl_busdecoder/__peakrdl__.py @@ -1,5 +1,5 @@ import functools -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from peakrdl.config import schema from peakrdl.plugins.entry_points import get_entry_points @@ -15,55 +15,61 @@ if TYPE_CHECKING: from systemrdl.node import AddrmapNode +@functools.lru_cache +def get_cpuifs( + config: dict[str, Any], +) -> dict[str, type[BaseCpuif]]: + # All built-in CPUIFs + cpuifs: dict[str, type[BaseCpuif]] = { + # "passthrough": passthrough.PassthroughCpuif, + "apb3": apb3.APB3Cpuif, + "apb3-flat": apb3.APB3CpuifFlat, + "apb4": apb4.APB4Cpuif, + "apb4-flat": apb4.APB4CpuifFlat, + # "axi4-lite": axi4lite.AXI4Lite_Cpuif, + # "axi4-lite-flat": axi4lite.AXI4Lite_Cpuif_flattened, + } + + # Load any cpuifs specified via entry points + for ep, _ in get_entry_points("peakrdl_busdecoder.cpuif"): + name = ep.name + cpuif = ep.load() + if name in cpuifs: + raise RuntimeError( + f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it already exists" + ) + if not issubclass(cpuif, BaseCpuif): + raise RuntimeError( + f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it not a BaseCpuif class" + ) + cpuifs[name] = cpuif + + # Load any CPUIFs via config import + for name, cpuif in config.items(): + if name in cpuifs: + raise RuntimeError( + f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it already exists" + ) + if not issubclass(cpuif, BaseCpuif): + raise RuntimeError( + f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it not a BaseCpuif class" + ) + cpuifs[name] = cpuif + + return cpuifs + + class Exporter(ExporterSubcommandPlugin): short_desc = "Generate a SystemVerilog control/status register (CSR) block" udp_definitions = ALL_UDPS - cfg_schema = { + cfg_schema = { # noqa: RUF012 "cpuifs": {"*": schema.PythonObjectImport()}, } - @functools.lru_cache def get_cpuifs(self) -> dict[str, type[BaseCpuif]]: - # All built-in CPUIFs - cpuifs: dict[str, type[BaseCpuif]] = { - # "passthrough": passthrough.PassthroughCpuif, - "apb3": apb3.APB3Cpuif, - "apb3-flat": apb3.APB3CpuifFlat, - "apb4": apb4.APB4Cpuif, - "apb4-flat": apb4.APB4CpuifFlat, - # "axi4-lite": axi4lite.AXI4Lite_Cpuif, - # "axi4-lite-flat": axi4lite.AXI4Lite_Cpuif_flattened, - } - - # Load any cpuifs specified via entry points - for ep, _ in get_entry_points("peakrdl_busdecoder.cpuif"): - name = ep.name - cpuif = ep.load() - if name in cpuifs: - raise RuntimeError( - f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it already exists" - ) - if not issubclass(cpuif, BaseCpuif): - raise RuntimeError( - f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it not a BaseCpuif class" - ) - cpuifs[name] = cpuif - - # Load any CPUIFs via config import - for name, cpuif in self.cfg["cpuifs"].items(): - if name in cpuifs: - raise RuntimeError( - f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it already exists" - ) - if not issubclass(cpuif, BaseCpuif): - raise RuntimeError( - f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it not a BaseCpuif class" - ) - cpuifs[name] = cpuif - - return cpuifs + return get_cpuifs(self.cfg["cpuifs"]) def add_exporter_arguments(self, arg_group: "argparse.ArgumentParser") -> None: # type: ignore cpuifs = self.get_cpuifs() diff --git a/src/peakrdl_busdecoder/cpuif/base_cpuif.py b/src/peakrdl_busdecoder/cpuif/base_cpuif.py index 33d1161..3ffbf73 100644 --- a/src/peakrdl_busdecoder/cpuif/base_cpuif.py +++ b/src/peakrdl_busdecoder/cpuif/base_cpuif.py @@ -1,11 +1,15 @@ import inspect import os -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import jinja2 as jj from systemrdl.node import AddressableNode +from systemrdl.walker import RDLSteerableWalker +from ..listener import BusDecoderListener from ..utils import clog2, get_indexed_path, is_pow2, roundup_pow2 +from .fanin_gen import FaninGenerator +from .fanout_gen import FanoutGenerator if TYPE_CHECKING: from ..exporter import BusDecoderExporter @@ -84,10 +88,13 @@ class BaseCpuif: jj_env.filters["roundup_pow2"] = roundup_pow2 # type: ignore jj_env.filters["address_slice"] = self.get_address_slice # type: ignore jj_env.filters["get_path"] = lambda x: get_indexed_path(self.exp.ds.top_node, x, "i") # type: ignore + jj_env.filters["walk"] = self.walk # type: ignore - context = { + context = { # type: ignore "cpuif": self, "ds": self.exp.ds, + "fanout": FanoutGenerator, + "fanin": FaninGenerator, } template = jj_env.get_template(self.template_path) @@ -98,3 +105,9 @@ class BaseCpuif: size = node.size return f"({cpuif_addr} - 'h{addr:x})[{clog2(size) - 1}:0]" + + def walk(self, listener_cls: type[BusDecoderListener], **kwargs: Any) -> str: + walker = RDLSteerableWalker() + listener = listener_cls(self.exp.ds, **kwargs) + walker.walk(self.exp.ds.top_node, listener, skip_top=True) + return str(listener) diff --git a/src/peakrdl_busdecoder/cpuif/fanin_gen.py b/src/peakrdl_busdecoder/cpuif/fanin_gen.py new file mode 100644 index 0000000..2e31a5b --- /dev/null +++ b/src/peakrdl_busdecoder/cpuif/fanin_gen.py @@ -0,0 +1,19 @@ +from systemrdl.node import AddressableNode +from systemrdl.walker import WalkerAction + +from ..design_state import DesignState +from ..listener import BusDecoderListener +from .base_cpuif import BaseCpuif + + +class FaninGenerator(BusDecoderListener): + def __init__(self, ds: DesignState, cpuif: BaseCpuif) -> None: + super().__init__(ds) + self._cpuif = cpuif + + def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None: + action = super().enter_AddressableComponent(node) + return action + + def exit_AddressableComponent(self, node: AddressableNode) -> None: + super().exit_AddressableComponent(node) diff --git a/src/peakrdl_busdecoder/cpuif/fanout_gen.py b/src/peakrdl_busdecoder/cpuif/fanout_gen.py new file mode 100644 index 0000000..12dbd63 --- /dev/null +++ b/src/peakrdl_busdecoder/cpuif/fanout_gen.py @@ -0,0 +1,19 @@ +from systemrdl.node import AddressableNode +from systemrdl.walker import WalkerAction + +from ..design_state import DesignState +from ..listener import BusDecoderListener +from .base_cpuif import BaseCpuif + + +class FanoutGenerator(BusDecoderListener): + def __init__(self, ds: DesignState, cpuif: BaseCpuif) -> None: + super().__init__(ds) + self._cpuif = cpuif + + def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None: + action = super().enter_AddressableComponent(node) + return action + + def exit_AddressableComponent(self, node: AddressableNode) -> None: + super().exit_AddressableComponent(node) diff --git a/src/peakrdl_busdecoder/decoder.py b/src/peakrdl_busdecoder/decode_logic_gen.py similarity index 100% rename from src/peakrdl_busdecoder/decoder.py rename to src/peakrdl_busdecoder/decode_logic_gen.py diff --git a/src/peakrdl_busdecoder/exporter.py b/src/peakrdl_busdecoder/exporter.py index 0e4accb..8dfc61a 100644 --- a/src/peakrdl_busdecoder/exporter.py +++ b/src/peakrdl_busdecoder/exporter.py @@ -11,11 +11,11 @@ from typing_extensions import Unpack from .cpuif import BaseCpuif from .cpuif.apb4 import APB4Cpuif -from .decoder import DecodeLogicFlavor, DecodeLogicGenerator +from .decode_logic_gen import DecodeLogicFlavor, DecodeLogicGenerator from .design_state import DesignState from .identifier_filter import kw_filter as kwf from .listener import BusDecoderListener -from .struct_generator import StructGenerator +from .struct_gen import StructGenerator from .sv_int import SVInt from .validate_design import DesignValidator @@ -57,8 +57,8 @@ class BusDecoderExporter: loader=c_loader, undefined=jj.StrictUndefined, ) - self.jj_env.filters["kwf"] = kwf - self.jj_env.filters["walk"] = self.walk + self.jj_env.filters["kwf"] = kwf # type: ignore + self.jj_env.filters["walk"] = self.walk # type: ignore def export(self, node: RootNode | AddrmapNode, output_dir: str, **kwargs: Unpack[ExporterKwargs]) -> None: """ @@ -106,7 +106,7 @@ class BusDecoderExporter: DesignValidator(self).do_validate() # Build Jinja template context - context = { + context = { # type: ignore "current_date": datetime.now().strftime("%Y-%m-%d"), "version": version("peakrdl-busdecoder"), "cpuif": self.cpuif, @@ -129,7 +129,7 @@ class BusDecoderExporter: stream = template.stream(context) stream.dump(module_file_path) - def walk(self, listener_cls: type[BusDecoderListener], **kwargs: Any) -> BusDecoderListener: + def walk(self, listener_cls: type[BusDecoderListener], **kwargs: Any) -> str: walker = RDLSteerableWalker() listener = listener_cls(self.ds, **kwargs) walker.walk(self.ds.top_node, listener, skip_top=True) diff --git a/src/peakrdl_busdecoder/struct_generator.py b/src/peakrdl_busdecoder/struct_gen.py similarity index 100% rename from src/peakrdl_busdecoder/struct_generator.py rename to src/peakrdl_busdecoder/struct_gen.py