From 17afaf13ffde99108484a009b302455b569e64bc Mon Sep 17 00:00:00 2001 From: Alex Mykyta Date: Tue, 8 Nov 2022 22:10:35 -0800 Subject: [PATCH] Add support for user-extending cpuif for PeakRDL command-line --- docs/cpuif/customizing.rst | 36 ++++++++++++++++++++++++++++ src/peakrdl_regblock/__peakrdl__.py | 14 +++++++++-- src/peakrdl_regblock/entry_points.py | 19 +++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 src/peakrdl_regblock/entry_points.py diff --git a/docs/cpuif/customizing.rst b/docs/cpuif/customizing.rst index 8792534..b9a2c6e 100644 --- a/docs/cpuif/customizing.rst +++ b/docs/cpuif/customizing.rst @@ -76,3 +76,39 @@ you can define your own. 3. Use your new CPUIF definition when exporting. 4. If you think the CPUIF protocol is something others might find useful, let me know and I can add it to PeakRDL! + + +Entry point for the PeakRDL command line tool +--------------------------------------------- +To make your custom CPUIF class visible to the `PeakRDL command-line tool `_, +provide an entry point linkage in your package's ``setup.py``. This advertises +your custom CPUIF class to the PeakRDL-regblock tool as a plugin that should be +loaded, and made available as a command-line option in PeakRDL. + + +.. code-block:: python + :emphasize-lines: 7-11 + + import setuptools + + setuptools.setup( + name="my_package", + packages=["my_package"], + # ... + entry_points = { + "peakrdl_regblock.cpuif": [ + 'my-cpuif = my_package.__peakrdl_regblock__:MyCPUIF' + ] + } + ) + + +* ``my_package``: The name of your installable Python module +* ``peakrdl-regblock.cpuif``: This is the namespace that PeakRDL-regblock will + search. Any cpuif plugins you create must be enclosed in this namespace in + order to be discovered. +* ``my_package.__peakrdl_regblock__:MyCPUIF``: This is the import path that + points to your CPUIF class definition. +* ``my-cpuif``: The lefthand side of the assignment is your cpuif's name. This + text is what the end-user uses in the command line interface to select your + CPUIF implementation. diff --git a/src/peakrdl_regblock/__peakrdl__.py b/src/peakrdl_regblock/__peakrdl__.py index d75789f..ad69375 100644 --- a/src/peakrdl_regblock/__peakrdl__.py +++ b/src/peakrdl_regblock/__peakrdl__.py @@ -1,15 +1,15 @@ from typing import TYPE_CHECKING from .exporter import RegblockExporter -from .cpuif import apb3, apb4, axi4lite, passthrough +from .cpuif import apb3, apb4, axi4lite, passthrough, CpuifBase from .udps import ALL_UDPS +from . import entry_points if TYPE_CHECKING: import argparse from systemrdl.node import AddrmapNode -# TODO: make this user-extensible CPUIF_DICT = { "apb3": apb3.APB3_Cpuif, "apb3-flat": apb3.APB3_Cpuif_flattened, @@ -20,6 +20,16 @@ "passthrough": passthrough.PassthroughCpuif } +# Load any user-plugins +for ep in entry_points.get_entry_points("peakrdl_regblock.cpuif"): # type: ignore + name = ep.name + cpuif = ep.load() + if name in CPUIF_DICT: + raise RuntimeError(f"A plugin for 'peakrdl-regblock' tried to load cpuif '{name}' but it already exists") + if not issubclass(cpuif, CpuifBase): + raise RuntimeError(f"A plugin for 'peakrdl-regblock' tried to load cpuif '{name}' but it not a CpuifBase class") + CPUIF_DICT[name] = cpuif + class Exporter: short_desc = "Generate a SystemVerilog control/status register (CSR) block" diff --git a/src/peakrdl_regblock/entry_points.py b/src/peakrdl_regblock/entry_points.py new file mode 100644 index 0000000..48cdb14 --- /dev/null +++ b/src/peakrdl_regblock/entry_points.py @@ -0,0 +1,19 @@ +# type: ignore +import sys + +if sys.version_info >= (3,10,0): + from importlib import metadata + + def get_entry_points(group_name): + return metadata.entry_points().select(group=group_name) + +elif sys.version_info >= (3,8,0): + from importlib import metadata + + def get_entry_points(group_name): + return metadata.entry_points().get(group_name, tuple()) + +else: + import pkg_resources + def get_entry_points(group_name): + return pkg_resources.iter_entry_points(group_name)