Files
PeakRDL-BusDecoder/src/peakrdl_busdecoder/cpuif/base_cpuif.py
Arnav Sacheti 35015d7051 "updt"
2025-10-13 18:39:19 -07:00

93 lines
2.8 KiB
Python

from typing import TYPE_CHECKING
import inspect
import os
import jinja2 as jj
from systemrdl.node import AddressableNode
from ..utils import clog2, is_pow2, roundup_pow2
if TYPE_CHECKING:
from ..exporter import BusDecoderExporter
class BaseCpuif:
# Path is relative to the location of the class that assigns this variable
template_path = ""
def __init__(self, exp: "BusDecoderExporter") -> None:
self.exp = exp
self.reset = exp.ds.top_node.cpuif_reset
self.unroll = exp.ds.cpuif_unroll
@property
def addressable_children(self) -> list[AddressableNode]:
return [
child
for child in self.exp.ds.top_node.children(unroll=self.unroll)
if isinstance(child, AddressableNode)
]
@property
def addr_width(self) -> int:
return self.exp.ds.addr_width
@property
def data_width(self) -> int:
return self.exp.ds.cpuif_data_width
@property
def data_width_bytes(self) -> int:
return self.data_width // 8
@property
def port_declaration(self) -> str:
raise NotImplementedError()
@property
def parameters(self) -> list[str]:
"""
Optional list of additional parameters this CPU interface provides to
the module's definition
"""
array_parameters = [
f"parameter N_{child.inst_name.upper()}S = {child.n_elements}"
for child in self.addressable_children
if self.check_is_array(child)
]
return array_parameters
def _get_template_path_class_dir(self) -> str:
"""
Traverse up the MRO and find the first class that explicitly assigns
template_path. Returns the directory that contains the class definition.
"""
for cls in inspect.getmro(self.__class__):
if "template_path" in cls.__dict__:
class_dir = os.path.dirname(inspect.getfile(cls))
return class_dir
raise RuntimeError
def check_is_array(self, node: AddressableNode) -> bool:
return node.is_array and not self.unroll
def get_implementation(self) -> str:
class_dir = self._get_template_path_class_dir()
loader = jj.FileSystemLoader(class_dir)
jj_env = jj.Environment(
loader=loader,
undefined=jj.StrictUndefined,
)
jj_env.tests["array"] = self.check_is_array # type: ignore
jj_env.filters["clog2"] = clog2 # type: ignore
jj_env.filters["is_pow2"] = is_pow2 # type: ignore
jj_env.filters["roundup_pow2"] = roundup_pow2 # type: ignore
context = {
"cpuif": self,
"ds": self.exp.ds,
}
template = jj_env.get_template(self.template_path)
return template.render(context)