93 lines
2.8 KiB
Python
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)
|