Fix APB PREADY signal to assert during error conditions Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>
105 lines
4.3 KiB
Python
105 lines
4.3 KiB
Python
from collections import deque
|
|
from typing import TYPE_CHECKING, overload
|
|
|
|
from systemrdl.node import AddressableNode
|
|
|
|
from ...sv_int import SVInt
|
|
from ...utils import clog2, get_indexed_path
|
|
from ..base_cpuif import BaseCpuif
|
|
from .axi4_lite_interface import AXI4LiteFlatInterface
|
|
|
|
if TYPE_CHECKING:
|
|
from ...exporter import BusDecoderExporter
|
|
|
|
|
|
class AXI4LiteCpuifFlat(BaseCpuif):
|
|
"""Verilator-friendly variant that flattens the AXI4-Lite interface ports."""
|
|
|
|
template_path = "axi4_lite_tmpl.sv"
|
|
|
|
def __init__(self, exp: "BusDecoderExporter") -> None:
|
|
super().__init__(exp)
|
|
self._interface = AXI4LiteFlatInterface(self)
|
|
|
|
@property
|
|
def is_interface(self) -> bool:
|
|
return self._interface.is_interface
|
|
|
|
@property
|
|
def port_declaration(self) -> str:
|
|
"""Returns the port declaration for the AXI4-Lite interface."""
|
|
return self._interface.get_port_declaration("s_axil_", "m_axil_")
|
|
|
|
@overload
|
|
def signal(self, signal: str, node: None = None, indexer: None = None) -> str: ...
|
|
@overload
|
|
def signal(self, signal: str, node: AddressableNode, indexer: str | None = None) -> str: ...
|
|
def signal(self, signal: str, node: AddressableNode | None = None, indexer: str | None = None) -> str:
|
|
return self._interface.signal(signal, node, indexer)
|
|
|
|
def fanout(self, node: AddressableNode, array_stack: deque[int]) -> str:
|
|
fanout: dict[str, str] = {}
|
|
waddr_comp = [f"{self.signal('AWADDR')}"]
|
|
raddr_comp = [f"{self.signal('ARADDR')}"]
|
|
for i, stride in enumerate(array_stack):
|
|
offset = f"(gi{i}*{SVInt(stride, self.addr_width)})"
|
|
waddr_comp.append(offset)
|
|
raddr_comp.append(offset)
|
|
|
|
wr_sel = f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}"
|
|
rd_sel = f"cpuif_rd_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}"
|
|
|
|
# Write address channel
|
|
fanout[self.signal("AWVALID", node, "gi")] = wr_sel
|
|
fanout[self.signal("AWADDR", node, "gi")] = f"{{{'-'.join(waddr_comp)}}}[{clog2(node.size) - 1}:0]"
|
|
fanout[self.signal("AWPROT", node, "gi")] = self.signal("AWPROT")
|
|
|
|
# Write data channel
|
|
fanout[self.signal("WVALID", node, "gi")] = wr_sel
|
|
fanout[self.signal("WDATA", node, "gi")] = "cpuif_wr_data"
|
|
fanout[self.signal("WSTRB", node, "gi")] = "cpuif_wr_byte_en"
|
|
|
|
# Write response channel (master -> slave)
|
|
fanout[self.signal("BREADY", node, "gi")] = self.signal("BREADY")
|
|
|
|
# Read address channel
|
|
fanout[self.signal("ARVALID", node, "gi")] = rd_sel
|
|
fanout[self.signal("ARADDR", node, "gi")] = f"{{{'-'.join(raddr_comp)}}}[{clog2(node.size) - 1}:0]"
|
|
fanout[self.signal("ARPROT", node, "gi")] = self.signal("ARPROT")
|
|
|
|
# Read data channel (master -> slave)
|
|
fanout[self.signal("RREADY", node, "gi")] = self.signal("RREADY")
|
|
|
|
return "\n".join(f"assign {lhs} = {rhs};" for lhs, rhs in fanout.items())
|
|
|
|
def fanin_wr(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
|
fanin: dict[str, str] = {}
|
|
if node is None:
|
|
fanin["cpuif_wr_ack"] = "'0"
|
|
fanin["cpuif_wr_err"] = "'0"
|
|
if error:
|
|
fanin["cpuif_wr_ack"] = "'1"
|
|
fanin["cpuif_wr_err"] = "cpuif_wr_sel.cpuif_err"
|
|
else:
|
|
# Read side: ack comes from RVALID; err if RRESP[1] is set (SLVERR/DECERR)
|
|
fanin["cpuif_wr_ack"] = self.signal("BVALID", node, "i")
|
|
fanin["cpuif_wr_err"] = f"{self.signal('BRESP', node, 'i')}[1]"
|
|
|
|
return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items())
|
|
|
|
def fanin_rd(self, node: AddressableNode | None = None, *, error: bool = False) -> str:
|
|
fanin: dict[str, str] = {}
|
|
if node is None:
|
|
fanin["cpuif_rd_ack"] = "'0"
|
|
fanin["cpuif_rd_err"] = "'0"
|
|
fanin["cpuif_rd_data"] = "'0"
|
|
if error:
|
|
fanin["cpuif_rd_ack"] = "'1"
|
|
fanin["cpuif_rd_err"] = "cpuif_rd_sel.cpuif_err"
|
|
else:
|
|
fanin["cpuif_rd_ack"] = self.signal("RVALID", node, "i")
|
|
fanin["cpuif_rd_err"] = f"{self.signal('RRESP', node, 'i')}[1]"
|
|
fanin["cpuif_rd_data"] = self.signal("RDATA", node, "i")
|
|
|
|
return "\n".join(f"{lhs} = {rhs};" for lhs, rhs in fanin.items())
|