81 lines
2.9 KiB
Python
81 lines
2.9 KiB
Python
from systemrdl.node import AddressableNode
|
|
from ..base_cpuif import BaseCpuif
|
|
|
|
|
|
class APB4Cpuif(BaseCpuif):
|
|
template_path = "apb4_tmpl.sv"
|
|
is_interface = True
|
|
|
|
def _port_declaration(self, child: AddressableNode) -> str:
|
|
base = f"apb4_intf.master m_apb_{child.inst_name}"
|
|
if not child.is_array:
|
|
return base
|
|
if child.current_idx is not None:
|
|
return f"{base}_{'_'.join(map(str, child.current_idx))} [N_{child.inst_name.upper()}S]"
|
|
return f"{base} [N_{child.inst_name.upper()}S]"
|
|
|
|
@property
|
|
def port_declaration(self) -> str:
|
|
"""Returns the port declaration for the APB4 interface."""
|
|
slave_ports: list[str] = ["apb4_intf.slave s_apb"]
|
|
master_ports: list[str] = list(
|
|
map(self._port_declaration, self.addressable_children)
|
|
)
|
|
|
|
return ",\n".join(slave_ports + master_ports)
|
|
|
|
def signal(
|
|
self,
|
|
signal: str,
|
|
node: AddressableNode | None = None,
|
|
idx: str | int | None = None,
|
|
) -> str:
|
|
"""Returns the signal name for the given signal and node."""
|
|
if node is None:
|
|
# Node is none, so this is a slave signal
|
|
return f"s_apb.{signal}"
|
|
|
|
# Master signal
|
|
base = f"m_apb_{node.inst_name}"
|
|
if not node.is_array:
|
|
return f"{base}.{signal}"
|
|
if node.current_idx is not None:
|
|
# This is a specific instance of an array
|
|
return f"{base}_{'_'.join(map(str, node.current_idx))}.{signal}"
|
|
if idx is not None:
|
|
return f"{base}[{idx}].{signal}"
|
|
|
|
raise ValueError("Must provide an index for arrayed interface signals")
|
|
|
|
def get_address_predicate(self, node: AddressableNode) -> str:
|
|
"""
|
|
Returns a SystemVerilog expression that evaluates to true when the
|
|
address on the bus matches the address range of the given node.
|
|
"""
|
|
|
|
addr_mask = (1 << self.addr_width) - 1
|
|
addr = node.absolute_address & addr_mask
|
|
size = node.size
|
|
if size == 0:
|
|
raise ValueError("Node size must be greater than 0")
|
|
if (addr % size) != 0:
|
|
raise ValueError("Node address must be aligned to its size")
|
|
|
|
# Calculate the address range of the node
|
|
addr_start = addr
|
|
addr_end = addr + size - 1
|
|
if addr_end > addr_mask:
|
|
raise ValueError("Node address range exceeds address width")
|
|
|
|
if addr_start == addr_end:
|
|
return f"({self.signal('PADDR')} == 'h{addr_start:X})"
|
|
|
|
return f"({self.signal('PADDR')} >= 'h{addr_start:X} && {self.signal('PADDR')} <= 'h{addr_end:X})"
|
|
|
|
def get_address_decode_condition(self, node: AddressableNode) -> str:
|
|
"""
|
|
Returns a SystemVerilog expression that evaluates to true when the
|
|
address on the bus matches the address range of the given node.
|
|
"""
|
|
addr_pred = self.get_address_predicate(node)
|
|
return addr_pred |