apb4 if working?

This commit is contained in:
Arnav Sacheti
2025-10-20 22:09:25 -07:00
parent f956232a62
commit 395f584f52
9 changed files with 106 additions and 57 deletions

View File

@@ -1,3 +1,5 @@
from typing import overload
from systemrdl.node import AddressableNode
from ...utils import get_indexed_path
@@ -10,11 +12,11 @@ class APB4Cpuif(BaseCpuif):
def _port_declaration(self, child: AddressableNode) -> str:
base = f"apb4_intf.master m_apb_{child.inst_name}"
if not child.is_array:
if child.array_dimensions is None:
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]"
return f"{base}_{'_'.join(map(str, child.current_idx))} {''.join(f'[{dim}]' for dim in child.array_dimensions)}"
return f"{base} {''.join(f'[{dim}]' for dim in child.array_dimensions)}"
@property
def port_declaration(self) -> str:
@@ -24,38 +26,50 @@ class APB4Cpuif(BaseCpuif):
return ",\n".join(slave_ports + master_ports)
def signal(
self,
signal: str,
node: AddressableNode | None = None,
) -> str:
if node is None:
@overload
def signal(self, signal: str, node: None = None, indexer: None = None) -> str: ...
@overload
def signal(self, signal: str, node: AddressableNode, indexer: str) -> str: ...
def signal(self, signal: str, node: AddressableNode | None = None, indexer: str | None = None) -> str:
if node is None or indexer is None:
# Node is none, so this is a slave signal
return f"s_apb.{signal}"
# Master signal
return f"m_apb_{node.inst_name}.{signal}"
return f"m_apb_{get_indexed_path(node.parent, node, indexer, skip_kw_filter=True)}.{signal}"
def fanout(self, node: AddressableNode) -> str:
fanout: dict[str, str] = {}
fanout[f"m_apb_{get_indexed_path(node.parent, node, 'gi')}.PSEL"] = (
f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node)}|cpuif_rd_sel.{get_indexed_path(self.exp.ds.top_node, node)}"
fanout[self.signal("PSEL", node, "gi")] = (
f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}|cpuif_rd_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}"
)
fanout[f"m_apb_{get_indexed_path(node.parent, node, 'gi')}.PSEL"] = self.signal("PSEL")
fanout[f"m_apb_{get_indexed_path(node.parent, node, 'gi')}.PWRITE"] = (
fanout[self.signal("PENABLE", node, "gi")] = self.signal("PENABLE")
fanout[self.signal("PWRITE", node, "gi")] = (
f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node, 'gi')}"
)
fanout[f"m_apb_{get_indexed_path(node.parent, node, 'gi')}.PADDR"] = self.signal("PADDR")
fanout[f"m_apb_{get_indexed_path(node.parent, node, 'gi')}.PPROT"] = self.signal("PPROT")
fanout[f"m_apb_{get_indexed_path(node.parent, node, 'gi')}.PWDATA"] = "cpuif_wr_data"
fanout[f"m_apb_{get_indexed_path(node.parent, node, 'gi')}.PSTRB"] = "cpuif_wr_byte_en"
fanout[self.signal("PADDR", node, "gi")] = self.signal("PADDR")
fanout[self.signal("PPROT", node, "gi")] = self.signal("PPROT")
fanout[self.signal("PWDATA", node, "gi")] = "cpuif_wr_data"
fanout[self.signal("PSTRB", node, "gi")] = "cpuif_wr_byte_en"
return "\n".join(map(lambda kv: f"assign {kv[0]} = {kv[1]};", fanout.items()))
def fanin(self, node: AddressableNode) -> str:
def fanin(self, node: AddressableNode | None = None) -> str:
fanin: dict[str, str] = {}
fanin["cpuif_rd_data"] = self.signal("PRDATA", node)
fanin["cpuif_rd_ack"] = self.signal("PREADY", node)
fanin["cpuif_rd_err"] = self.signal("PSLVERR", node)
if node is None:
fanin["cpuif_rd_ack"] = "'0"
fanin["cpuif_rd_err"] = "'0"
else:
fanin["cpuif_rd_ack"] = self.signal("PREADY", node, "i")
fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, "i")
return "\n".join(map(lambda kv: f"{kv[0]} = {kv[1]};", fanin.items()))
def readback(self, node: AddressableNode | None = None) -> str:
fanin: dict[str, str] = {}
if node is None:
fanin["cpuif_rd_data"] = "'0"
else:
fanin["cpuif_rd_data"] = self.signal("PRDATA", node, "i")
return "\n".join(map(lambda kv: f"{kv[0]} = {kv[1]};", fanin.items()))

View File

@@ -6,19 +6,24 @@
assert_bad_data_width: assert($bits({{cpuif.signal("PWDATA")}}) == {{ds.package_name}}::{{ds.module_name|upper}}_DATA_WIDTH)
else $error("Interface data width of %0d is incorrect. Shall be %0d bits", $bits({{cpuif.signal("PWDATA")}}), {{ds.package_name}}::{{ds.module_name|upper}}_DATA_WIDTH);
end
assert_wr_sel: assert (@(posedge {{cpuif.signal("PCLK")}}) {{cpuif.signal("PSEL")}} && {{cpuif.signal("PWRITE")}} |-> ##1 ({{cpuif.signal("PREADY")}} || {{cpuif.signal("PSLVERR")}}))
else $error("APB4 Slave port SEL implies that cpuif_wr_sel must be one-hot encoded");
`endif
{%- endif %}
assign cpuif_req = {{cpuif.signal("PSELx")}};
assign cpuif_req = {{cpuif.signal("PSEL")}};
assign cpuif_wr_en = {{cpuif.signal("PWRITE")}};
assign cpuif_rd_en = !{{cpuif.signal("PWRITE")}};
assign cpuif_wr_addr = {{cpuif.signal("PADDR")}};
assign cpuif_rd_addr = {{cpuif.signal("PADDR")}};
assign cpuif_wr_data = {{cpuif.signal("PWDATA")}};
assign cpuif_wr_byte_en = {{cpuif.signal("PSTRB")}};
assign {{cpuif.signal("PRDATA")}} = cpuif_rd_data;
assign {{cpuif.signal("PREADY")}} = cpuif_rd_ack;
assign {{cpuif.signal("PSLVERR")}} = cpuif_rd_err;
assign {{cpuif.signal("PSLVERR")}} = cpuif_rd_err | cpuif_rd_sel.cpuif_err | cpuif_wr_sel.cpuif_err;
//--------------------------------------------------------------------------
// Fanout CPU Bus interface signals

View File

@@ -1,12 +1,10 @@
import inspect
import os
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING
import jinja2 as jj
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 .fanin_gen import FaninGenerator
from .fanout_gen import FanoutGenerator
@@ -55,7 +53,7 @@ class BaseCpuif:
the module's definition
"""
array_parameters = [
f"parameter N_{child.inst_name.upper()}S = {child.n_elements}"
f"localparam N_{child.inst_name.upper()}S = {child.n_elements}"
for child in self.addressable_children
if self.check_is_array(child)
]
@@ -88,7 +86,7 @@ class BaseCpuif:
jj_env.filters["roundup_pow2"] = roundup_pow2 # 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["walk"] = self.walk # type: ignore
jj_env.filters["walk"] = self.exp.walk # type: ignore
context = { # type: ignore
"cpuif": self,
@@ -106,14 +104,11 @@ class BaseCpuif:
return f"({cpuif_addr} - 'h{addr:x})[{clog2(size) - 1}:0]"
def walk(self, listener_cls: type[BusDecoderListener], **kwargs: Any) -> str: # noqa: ANN401
walker = RDLSteerableWalker()
listener = listener_cls(self.exp.ds, **kwargs)
walker.walk(self.exp.ds.top_node, listener, skip_top=True)
return str(listener)
def fanout(self, node: AddressableNode) -> str:
raise NotImplementedError
def fanin(self, node: AddressableNode) -> str:
def fanin(self, node: AddressableNode | None = None) -> str:
raise NotImplementedError
def readback(self, node: AddressableNode | None = None) -> str:
raise NotImplementedError

View File

@@ -4,9 +4,10 @@ from typing import TYPE_CHECKING
from systemrdl.node import AddressableNode
from systemrdl.walker import WalkerAction
from ..body import Body, CombinationalBody, ForLoopBody
from ..body import Body, CombinationalBody, ForLoopBody, IfBody
from ..design_state import DesignState
from ..listener import BusDecoderListener
from ..utils import get_indexed_path
if TYPE_CHECKING:
from .base_cpuif import BaseCpuif
@@ -18,7 +19,10 @@ class FaninGenerator(BusDecoderListener):
self._cpuif = cpuif
self._stack: deque[Body] = deque()
self._stack.append(CombinationalBody())
cb = CombinationalBody()
cb += cpuif.fanin()
cb += cpuif.readback()
self._stack.append(cb)
def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None:
action = super().enter_AddressableComponent(node)
@@ -32,7 +36,19 @@ class FaninGenerator(BusDecoderListener):
)
self._stack.append(fb)
self._stack[-1] += self._cpuif.fanin(node)
if action == WalkerAction.Continue:
ifb = IfBody()
with ifb.cm(
f"cpuif_rd_sel.{get_indexed_path(self._cpuif.exp.ds.top_node, node)} || cpuif_wr_sel.{get_indexed_path(self._cpuif.exp.ds.top_node, node)}"
) as b:
b += self._cpuif.fanin(node)
self._stack[-1] += ifb
ifb = IfBody()
with ifb.cm(f"cpuif_rd_sel.{get_indexed_path(self._cpuif.exp.ds.top_node, node)}") as b:
b += self._cpuif.readback(node)
self._stack[-1] += ifb
return action
def exit_AddressableComponent(self, node: AddressableNode) -> None:

View File

@@ -32,7 +32,9 @@ class FanoutGenerator(BusDecoderListener):
)
self._stack.append(fb)
self._stack[-1] += self._cpuif.fanout(node)
if action == WalkerAction.Continue:
self._stack[-1] += self._cpuif.fanout(node)
return action
def exit_AddressableComponent(self, node: AddressableNode) -> None: