Add support for user-extending cpuif for PeakRDL command-line

This commit is contained in:
Alex Mykyta
2022-11-08 22:10:35 -08:00
parent 232faba417
commit 17afaf13ff
3 changed files with 67 additions and 2 deletions

View File

@@ -76,3 +76,39 @@ you can define your own.
3. Use your new CPUIF definition when exporting. 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! 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 <https://peakrdl.readthedocs.io>`_,
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.

View File

@@ -1,15 +1,15 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from .exporter import RegblockExporter 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 .udps import ALL_UDPS
from . import entry_points
if TYPE_CHECKING: if TYPE_CHECKING:
import argparse import argparse
from systemrdl.node import AddrmapNode from systemrdl.node import AddrmapNode
# TODO: make this user-extensible
CPUIF_DICT = { CPUIF_DICT = {
"apb3": apb3.APB3_Cpuif, "apb3": apb3.APB3_Cpuif,
"apb3-flat": apb3.APB3_Cpuif_flattened, "apb3-flat": apb3.APB3_Cpuif_flattened,
@@ -20,6 +20,16 @@ CPUIF_DICT = {
"passthrough": passthrough.PassthroughCpuif "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: class Exporter:
short_desc = "Generate a SystemVerilog control/status register (CSR) block" short_desc = "Generate a SystemVerilog control/status register (CSR) block"

View File

@@ -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)