typecheck + fanout/fanin
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import functools
|
import functools
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from peakrdl.config import schema
|
from peakrdl.config import schema
|
||||||
from peakrdl.plugins.entry_points import get_entry_points
|
from peakrdl.plugins.entry_points import get_entry_points
|
||||||
@@ -15,55 +15,61 @@ if TYPE_CHECKING:
|
|||||||
from systemrdl.node import AddrmapNode
|
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):
|
class Exporter(ExporterSubcommandPlugin):
|
||||||
short_desc = "Generate a SystemVerilog control/status register (CSR) block"
|
short_desc = "Generate a SystemVerilog control/status register (CSR) block"
|
||||||
|
|
||||||
udp_definitions = ALL_UDPS
|
udp_definitions = ALL_UDPS
|
||||||
|
|
||||||
cfg_schema = {
|
cfg_schema = { # noqa: RUF012
|
||||||
"cpuifs": {"*": schema.PythonObjectImport()},
|
"cpuifs": {"*": schema.PythonObjectImport()},
|
||||||
}
|
}
|
||||||
|
|
||||||
@functools.lru_cache
|
|
||||||
def get_cpuifs(self) -> dict[str, type[BaseCpuif]]:
|
def get_cpuifs(self) -> dict[str, type[BaseCpuif]]:
|
||||||
# All built-in CPUIFs
|
return get_cpuifs(self.cfg["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
|
|
||||||
|
|
||||||
def add_exporter_arguments(self, arg_group: "argparse.ArgumentParser") -> None: # type: ignore
|
def add_exporter_arguments(self, arg_group: "argparse.ArgumentParser") -> None: # type: ignore
|
||||||
cpuifs = self.get_cpuifs()
|
cpuifs = self.get_cpuifs()
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
import jinja2 as jj
|
import jinja2 as jj
|
||||||
from systemrdl.node import AddressableNode
|
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 ..utils import clog2, get_indexed_path, is_pow2, roundup_pow2
|
||||||
|
from .fanin_gen import FaninGenerator
|
||||||
|
from .fanout_gen import FanoutGenerator
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..exporter import BusDecoderExporter
|
from ..exporter import BusDecoderExporter
|
||||||
@@ -84,10 +88,13 @@ class BaseCpuif:
|
|||||||
jj_env.filters["roundup_pow2"] = roundup_pow2 # type: ignore
|
jj_env.filters["roundup_pow2"] = roundup_pow2 # type: ignore
|
||||||
jj_env.filters["address_slice"] = self.get_address_slice # 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["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,
|
"cpuif": self,
|
||||||
"ds": self.exp.ds,
|
"ds": self.exp.ds,
|
||||||
|
"fanout": FanoutGenerator,
|
||||||
|
"fanin": FaninGenerator,
|
||||||
}
|
}
|
||||||
|
|
||||||
template = jj_env.get_template(self.template_path)
|
template = jj_env.get_template(self.template_path)
|
||||||
@@ -98,3 +105,9 @@ class BaseCpuif:
|
|||||||
size = node.size
|
size = node.size
|
||||||
|
|
||||||
return f"({cpuif_addr} - 'h{addr:x})[{clog2(size) - 1}:0]"
|
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)
|
||||||
|
|||||||
19
src/peakrdl_busdecoder/cpuif/fanin_gen.py
Normal file
19
src/peakrdl_busdecoder/cpuif/fanin_gen.py
Normal file
@@ -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)
|
||||||
19
src/peakrdl_busdecoder/cpuif/fanout_gen.py
Normal file
19
src/peakrdl_busdecoder/cpuif/fanout_gen.py
Normal file
@@ -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)
|
||||||
@@ -11,11 +11,11 @@ from typing_extensions import Unpack
|
|||||||
|
|
||||||
from .cpuif import BaseCpuif
|
from .cpuif import BaseCpuif
|
||||||
from .cpuif.apb4 import APB4Cpuif
|
from .cpuif.apb4 import APB4Cpuif
|
||||||
from .decoder import DecodeLogicFlavor, DecodeLogicGenerator
|
from .decode_logic_gen import DecodeLogicFlavor, DecodeLogicGenerator
|
||||||
from .design_state import DesignState
|
from .design_state import DesignState
|
||||||
from .identifier_filter import kw_filter as kwf
|
from .identifier_filter import kw_filter as kwf
|
||||||
from .listener import BusDecoderListener
|
from .listener import BusDecoderListener
|
||||||
from .struct_generator import StructGenerator
|
from .struct_gen import StructGenerator
|
||||||
from .sv_int import SVInt
|
from .sv_int import SVInt
|
||||||
from .validate_design import DesignValidator
|
from .validate_design import DesignValidator
|
||||||
|
|
||||||
@@ -57,8 +57,8 @@ class BusDecoderExporter:
|
|||||||
loader=c_loader,
|
loader=c_loader,
|
||||||
undefined=jj.StrictUndefined,
|
undefined=jj.StrictUndefined,
|
||||||
)
|
)
|
||||||
self.jj_env.filters["kwf"] = kwf
|
self.jj_env.filters["kwf"] = kwf # type: ignore
|
||||||
self.jj_env.filters["walk"] = self.walk
|
self.jj_env.filters["walk"] = self.walk # type: ignore
|
||||||
|
|
||||||
def export(self, node: RootNode | AddrmapNode, output_dir: str, **kwargs: Unpack[ExporterKwargs]) -> None:
|
def export(self, node: RootNode | AddrmapNode, output_dir: str, **kwargs: Unpack[ExporterKwargs]) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -106,7 +106,7 @@ class BusDecoderExporter:
|
|||||||
DesignValidator(self).do_validate()
|
DesignValidator(self).do_validate()
|
||||||
|
|
||||||
# Build Jinja template context
|
# Build Jinja template context
|
||||||
context = {
|
context = { # type: ignore
|
||||||
"current_date": datetime.now().strftime("%Y-%m-%d"),
|
"current_date": datetime.now().strftime("%Y-%m-%d"),
|
||||||
"version": version("peakrdl-busdecoder"),
|
"version": version("peakrdl-busdecoder"),
|
||||||
"cpuif": self.cpuif,
|
"cpuif": self.cpuif,
|
||||||
@@ -129,7 +129,7 @@ class BusDecoderExporter:
|
|||||||
stream = template.stream(context)
|
stream = template.stream(context)
|
||||||
stream.dump(module_file_path)
|
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()
|
walker = RDLSteerableWalker()
|
||||||
listener = listener_cls(self.ds, **kwargs)
|
listener = listener_cls(self.ds, **kwargs)
|
||||||
walker.walk(self.ds.top_node, listener, skip_top=True)
|
walker.walk(self.ds.top_node, listener, skip_top=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user