diff --git a/src/peakrdl_busdecoder/__peakrdl__.py b/src/peakrdl_busdecoder/__peakrdl__.py index 36096cc..f78efdd 100644 --- a/src/peakrdl_busdecoder/__peakrdl__.py +++ b/src/peakrdl_busdecoder/__peakrdl__.py @@ -16,9 +16,7 @@ if TYPE_CHECKING: @functools.lru_cache -def get_cpuifs( - config: dict[str, Any], -) -> dict[str, type[BaseCpuif]]: +def get_cpuifs(config: list[tuple[str, Any]]) -> dict[str, type[BaseCpuif]]: # All built-in CPUIFs cpuifs: dict[str, type[BaseCpuif]] = { # "passthrough": passthrough.PassthroughCpuif, @@ -45,7 +43,7 @@ def get_cpuifs( cpuifs[name] = cpuif # Load any CPUIFs via config import - for name, cpuif in config.items(): + for name, cpuif in config: if name in cpuifs: raise RuntimeError( f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it already exists" @@ -69,7 +67,7 @@ class Exporter(ExporterSubcommandPlugin): } def get_cpuifs(self) -> dict[str, type[BaseCpuif]]: - return get_cpuifs(self.cfg["cpuifs"]) + return get_cpuifs(map(tuple, self.cfg["cpuifs"].items())) def add_exporter_arguments(self, arg_group: "argparse.ArgumentParser") -> None: # type: ignore cpuifs = self.get_cpuifs() diff --git a/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py b/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py index 1defbd4..c511c7f 100644 --- a/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py +++ b/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py @@ -1,5 +1,6 @@ from systemrdl.node import AddressableNode +from ...utils import get_indexed_path from ..base_cpuif import BaseCpuif @@ -26,20 +27,32 @@ class APB3Cpuif(BaseCpuif): self, signal: str, node: AddressableNode | None = None, - idx: str | int | None = None, ) -> str: 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}" + return f"m_apb_{node.inst_name}.{signal}" - raise ValueError("Must provide an index for arrayed interface signals") + def fanout(self, node: AddressableNode, idx: str | None = None) -> str: + fanout: dict[str, str] = {} + fanout[self.signal("PSEL", node, idx)] = ( + 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, idx)] = self.signal("PSEL") + fanout[self.signal("PWRITE", node, idx)] = ( + f"cpuif_wr_sel.{get_indexed_path(self.exp.ds.top_node, node)}" + ) + fanout[self.signal("PADDR", node, idx)] = self.signal("PADDR") + fanout[self.signal("PWDATA", node, idx)] = "cpuif_wr_data" + + return "\n".join(map(lambda kv: f"assign {kv[0]} = {kv[1]};", fanout.items())) + + def fanin(self, node: AddressableNode, idx: str | None = None) -> str: + fanin: dict[str, str] = {} + fanin["cpuif_rd_data"] = self.signal("PRDATA", node, idx) + fanin["cpuif_rd_ack"] = self.signal("PREADY", node, idx) + fanin["cpuif_rd_err"] = self.signal("PSLVERR", node, idx) + + return "\n".join(map(lambda kv: f"{kv[0]} = {kv[1]};", fanin.items())) diff --git a/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv b/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv index 7495ff3..98ddbdc 100644 --- a/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv +++ b/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv @@ -11,47 +11,20 @@ assign cpuif_req = {{cpuif.signal("PSELx")}}; assign cpuif_wr_en = {{cpuif.signal("PWRITE")}}; -assign cpuif_wr_data = {{cpuif.signal("PWDATA")}}; assign cpuif_rd_en = !{{cpuif.signal("PWRITE")}}; -{%- for child in cpuif.addressable_children -%} -{%- if child is array -%} -for (genvar gi = 0; gi < N_{{child.inst_name|upper}}S; gi++) begin : g_passthrough_{{child.inst_name|lower}} - assign {{cpuif.signal("PCLK", child, "gi")}} = {{cpuif.signal("PCLK")}}; - assign {{cpuif.signal("PRESETn", child, "gi")}} = {{cpuif.signal("PRESETn")}}; - assign {{cpuif.signal("PSELx", child, "gi")}} = (cpuif_wr_req[{{loop.index}}] || cpuif_rd_req[{{loop.index}}]) ? 1'b1 : 1'b0; - assign {{cpuif.signal("PENABLE", child, "gi")}} = {{cpuif.signal("PENABLE")}}; - assign {{cpuif.signal("PWRITE", child, "gi")}} = (cpuif_wr_req[{{loop.index}}]) ? 1'b1 : 1'b0; - assign {{cpuif.signal("PADDR", child, "gi")}} = {{child|address_slice(cpuif_addr="cpuif_wr_addr")}}; - assign {{cpuif.signal("PWDATA", child, "gi")}} = cpuif_wr_data; - assign cpuif_rd_ack[loop.index] = {{cpuif.signal("PREADY", child)}}; - assign cpuif_rd_data[loop.index] = {{cpuif.signal("PRDATA", child)}}; - assign cpuif_rd_err[loop.index] = {{cpuif.signal("PSLVERR", child)}}; -end -{%- else -%} -assign {{cpuif.signal("PCLK", child)}} = {{cpuif.signal("PCLK")}}; -assign {{cpuif.signal("PRESETn", child)}} = {{cpuif.signal("PRESETn")}}; -assign {{cpuif.signal("PSELx", child)}} = (cpuif_wr_sel[{{loop.index0}}] || cpuif_rd_sel[{{loop.index0}}]) ? 1'b1 : 1'b0; -assign {{cpuif.signal("PENABLE", child)}} = {{cpuif.signal("PENABLE")}}; -assign {{cpuif.signal("PWRITE", child)}} = (cpuif_wr_req[{{loop.index}}]) ? 1'b1 : 1'b0; -assign {{cpuif.signal("PADDR", child)}} = {{child|address_slice(cpuif_addr="cpuif_wr_addr")}}; -assign {{cpuif.signal("PWDATA", child)}} = cpuif_wr_data; -assign cpuif_rd_ack[loop.index] = {{cpuif.signal("PREADY", child)}}; -assign cpuif_rd_data[loop.index] = {{cpuif.signal("PRDATA", child)}}; -assign cpuif_rd_err[loop.index] = {{cpuif.signal("PSLVERR", child)}}; -{%- endif -%} -{%- endfor%} +assign cpuif_wr_data = {{cpuif.signal("PWDATA")}}; -always_comb begin - {{cpuif.signal("PREADY")}} = 1'b0; - {{cpuif.signal("PRDATA")}} = '0; - {{cpuif.signal("PSLVERR")}} = 1'b0; +assign {{cpuif.signal("PRDATA")}} = cpuif_rd_data; +assign {{cpuif.signal("PREADY")}} = cpuif_rd_ack; +assign {{cpuif.signal("PSLVERR")}} = cpuif_rd_err; - for(int i = 0; i < {{cpuif.addressable_children | length}}; i++) begin - if (cpuif_rd_sel[i]) begin - {{cpuif.signal("PREADY")}} = cpuif_rd_ack[i]; - {{cpuif.signal("PRDATA")}} = cpuif_rd_data[i]; - {{cpuif.signal("PSLVERR")}} = cpuif_rd_err[i]; - end - end -end \ No newline at end of file +//-------------------------------------------------------------------------- +// Fanout CPU Bus interface signals +//-------------------------------------------------------------------------- +{{fanout|walk(cpuif=cpuif)}} + +//-------------------------------------------------------------------------- +// Fanin CPU Bus interface signals +//-------------------------------------------------------------------------- +{{fanin|walk(cpuif=cpuif)}} \ No newline at end of file diff --git a/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif.py b/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif.py index 7705c0b..85b2941 100644 --- a/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif.py +++ b/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif.py @@ -1,5 +1,6 @@ from systemrdl.node import AddressableNode +from ...utils import get_indexed_path from ..base_cpuif import BaseCpuif @@ -27,21 +28,34 @@ class APB4Cpuif(BaseCpuif): 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}" + return f"m_apb_{node.inst_name}.{signal}" - raise ValueError("Must provide an index for arrayed interface signals") + 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[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"] = ( + 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" + + return "\n".join(map(lambda kv: f"assign {kv[0]} = {kv[1]};", fanout.items())) + + def fanin(self, node: AddressableNode) -> 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) + + return "\n".join(map(lambda kv: f"{kv[0]} = {kv[1]};", fanin.items())) diff --git a/src/peakrdl_busdecoder/cpuif/apb4/apb4_tmpl.sv b/src/peakrdl_busdecoder/cpuif/apb4/apb4_tmpl.sv index 670ae7c..a115c46 100644 --- a/src/peakrdl_busdecoder/cpuif/apb4/apb4_tmpl.sv +++ b/src/peakrdl_busdecoder/cpuif/apb4/apb4_tmpl.sv @@ -11,72 +11,21 @@ assign cpuif_req = {{cpuif.signal("PSELx")}}; assign cpuif_wr_en = {{cpuif.signal("PWRITE")}}; -assign cpuif_wr_data = {{cpuif.signal("PWDATA")}}; assign cpuif_rd_en = !{{cpuif.signal("PWRITE")}}; +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; + //-------------------------------------------------------------------------- // Fanout CPU Bus interface signals //-------------------------------------------------------------------------- - -// {%- for child in cpuif.addressable_children -%} -// {%- if child is array %} -// for (genvar gi = 0; gi < N_{{child.inst_name|upper}}S; gi++) begin : g_passthrough_{{child.inst_name|lower}} -// assign {{cpuif.signal("PCLK", child, "gi")}} = {{cpuif.signal("PCLK")}}; -// assign {{cpuif.signal("PRESETn", child, "gi")}} = {{cpuif.signal("PRESETn")}}; -// assign {{cpuif.signal("PSELx", child, "gi")}} = (cpuif_wr_sel[{{loop.index}}] || cpuif_rd_sel[{{loop.index}}]) ? 1'b1 : 1'b0; -// assign {{cpuif.signal("PENABLE", child, "gi")}} = {{cpuif.signal("PENABLE")}}; -// assign {{cpuif.signal("PWRITE", child, "gi")}} = (cpuif_wr_sel[{{loop.index}}]) ? 1'b1 : 1'b0; -// assign {{cpuif.signal("PADDR", child, "gi")}} = {{child|address_slice(cpuif_addr="cpuif_wr_addr")}}; -// assign {{cpuif.signal("PPROT", child, "gi")}} = {{cpuif.signal("PPROT")}}; -// assign {{cpuif.signal("PWDATA", child, "gi")}} = cpuif_wr_data; -// assign {{cpuif.signal("PSTRB", child, "gi")}} = {{cpuif.signal("PSTRB")}}; -// assign cpuif_rd_ack[{{loop.index}}] = {{cpuif.signal("PREADY", child, "gi")}}; -// assign cpuif_rd_data[{{loop.index}}] = {{cpuif.signal("PRDATA", child, "gi")}}; -// assign cpuif_rd_err[{{loop.index}}] = {{cpuif.signal("PSLVERR", child, "gi")}}; -// end -// {%- else %} -// assign {{cpuif.signal("PCLK", child)}} = {{cpuif.signal("PCLK")}}; -// assign {{cpuif.signal("PRESETn", child)}} = {{cpuif.signal("PRESETn")}}; -// assign {{cpuif.signal("PSELx", child)}} = (cpuif_wr_sel[{{loop.index}}] || cpuif_rd_sel[{{loop.index}}]) ? 1'b1 : 1'b0; -// assign {{cpuif.signal("PENABLE", child)}} = {{cpuif.signal("PENABLE")}}; -// assign {{cpuif.signal("PWRITE", child)}} = cpuif_wr_sel[{{loop.index}}] ? 1'b1 : 1'b0; -// assign {{cpuif.signal("PADDR", child)}} = {{child|address_slice(cpuif_addr="cpuif_wr_addr")}}; -// assign {{cpuif.signal("PPROT", child)}} = {{cpuif.signal("PPROT")}}; -// assign {{cpuif.signal("PWDATA", child)}} = cpuif_wr_data; -// assign {{cpuif.signal("PSTRB", child)}} = {{cpuif.signal("PSTRB")}}; -// assign cpuif_rd_ack[{{loop.index}}] = {{cpuif.signal("PREADY", child)}}; -// assign cpuif_rd_data[{{loop.index}}] = {{cpuif.signal("PRDATA", child)}}; -// assign cpuif_rd_err[{{loop.index}}] = {{cpuif.signal("PSLVERR", child)}}; -// {%- endif -%} -// {%- endfor %} - +{{fanout|walk(cpuif=cpuif)}} //-------------------------------------------------------------------------- // Fanin CPU Bus interface signals //-------------------------------------------------------------------------- -always_comb begin - {{cpuif.signal("PREADY")}} = 1'b0; - {{cpuif.signal("PRDATA")}} = '0; - {{cpuif.signal("PSLVERR")}} = 1'b0; - - -{%- for child in cpuif.addressable_children -%} -{%- if loop.first %} - if (cpuif_rd_sel.{{child|get_path}}) begin -{%- else %} - end else if (cpuif_rd_sel.{{child|get_path}}) begin -{%- endif %} - {{cpuif.signal("PREADY")}} = cpuif_rd_ack[{{loop.index}}]; - {{cpuif.signal("PRDATA")}} = cpuif_rd_data[{{loop.index}}]; - {{cpuif.signal("PSLVERR")}} = cpuif_rd_err[{{loop.index}}]; -{%- endfor %} - end - - // for(int i = 0; i < {{cpuif.addressable_children | length}}; i++) begin - // if (cpuif_rd_sel[i]) begin - // {{cpuif.signal("PREADY")}} = cpuif_rd_ack[i]; - // {{cpuif.signal("PRDATA")}} = cpuif_rd_data[i]; - // {{cpuif.signal("PSLVERR")}} = cpuif_rd_err[i]; - // end - // end -end \ No newline at end of file +{{fanin|walk(cpuif=cpuif)}} \ No newline at end of file diff --git a/src/peakrdl_busdecoder/cpuif/base_cpuif.py b/src/peakrdl_busdecoder/cpuif/base_cpuif.py index 3ffbf73..852d9bd 100644 --- a/src/peakrdl_busdecoder/cpuif/base_cpuif.py +++ b/src/peakrdl_busdecoder/cpuif/base_cpuif.py @@ -106,8 +106,14 @@ class BaseCpuif: return f"({cpuif_addr} - 'h{addr:x})[{clog2(size) - 1}:0]" - def walk(self, listener_cls: type[BusDecoderListener], **kwargs: Any) -> str: + 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: + raise NotImplementedError diff --git a/src/peakrdl_busdecoder/cpuif/fanin_gen.py b/src/peakrdl_busdecoder/cpuif/fanin_gen.py index 2e31a5b..219f820 100644 --- a/src/peakrdl_busdecoder/cpuif/fanin_gen.py +++ b/src/peakrdl_busdecoder/cpuif/fanin_gen.py @@ -1,19 +1,49 @@ +from collections import deque +from typing import TYPE_CHECKING + from systemrdl.node import AddressableNode from systemrdl.walker import WalkerAction +from ..body import Body, CombinationalBody, ForLoopBody from ..design_state import DesignState from ..listener import BusDecoderListener -from .base_cpuif import BaseCpuif + +if TYPE_CHECKING: + from .base_cpuif import BaseCpuif class FaninGenerator(BusDecoderListener): - def __init__(self, ds: DesignState, cpuif: BaseCpuif) -> None: + def __init__(self, ds: DesignState, cpuif: "BaseCpuif") -> None: super().__init__(ds) self._cpuif = cpuif + self._stack: deque[Body] = deque() + self._stack.append(CombinationalBody()) + def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None: action = super().enter_AddressableComponent(node) + + if node.array_dimensions: + for i, dim in enumerate(node.array_dimensions): + fb = ForLoopBody( + "int", + f"i{i}", + dim, + ) + self._stack.append(fb) + + self._stack[-1] += self._cpuif.fanin(node) return action def exit_AddressableComponent(self, node: AddressableNode) -> None: + if node.array_dimensions: + for _ in node.array_dimensions: + b = self._stack.pop() + if not b: + continue + self._stack[-1] += b + super().exit_AddressableComponent(node) + + def __str__(self) -> str: + return "\n".join(map(str, self._stack)) diff --git a/src/peakrdl_busdecoder/cpuif/fanout_gen.py b/src/peakrdl_busdecoder/cpuif/fanout_gen.py index 12dbd63..6b79805 100644 --- a/src/peakrdl_busdecoder/cpuif/fanout_gen.py +++ b/src/peakrdl_busdecoder/cpuif/fanout_gen.py @@ -1,19 +1,49 @@ +from collections import deque +from typing import TYPE_CHECKING + from systemrdl.node import AddressableNode from systemrdl.walker import WalkerAction +from ..body import Body, ForLoopBody from ..design_state import DesignState from ..listener import BusDecoderListener -from .base_cpuif import BaseCpuif + +if TYPE_CHECKING: + from .base_cpuif import BaseCpuif class FanoutGenerator(BusDecoderListener): - def __init__(self, ds: DesignState, cpuif: BaseCpuif) -> None: + def __init__(self, ds: DesignState, cpuif: "BaseCpuif") -> None: super().__init__(ds) self._cpuif = cpuif + self._stack: deque[Body] = deque() + self._stack.append(Body()) + def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None: action = super().enter_AddressableComponent(node) + + if node.array_dimensions: + for i, dim in enumerate(node.array_dimensions): + fb = ForLoopBody( + "genvar", + f"gi{i}", + dim, + ) + self._stack.append(fb) + + self._stack[-1] += self._cpuif.fanout(node) return action def exit_AddressableComponent(self, node: AddressableNode) -> None: + if node.array_dimensions: + for _ in node.array_dimensions: + b = self._stack.pop() + if not b: + continue + self._stack[-1] += b + super().exit_AddressableComponent(node) + + def __str__(self) -> str: + return "\n".join(map(str, self._stack)) diff --git a/src/peakrdl_busdecoder/decode_logic_gen.py b/src/peakrdl_busdecoder/decode_logic_gen.py index 84e2ae6..8c96cfb 100644 --- a/src/peakrdl_busdecoder/decode_logic_gen.py +++ b/src/peakrdl_busdecoder/decode_logic_gen.py @@ -83,7 +83,7 @@ class DecodeLogicGenerator(BusDecoderListener): condition = " && ".join(f"({c})" for c in conditions) # Generate condition string and manage stack - if isinstance(self._decode_stack[-1], IfBody) and node.array_dimensions: + if node.array_dimensions: # arrayed component with new if-body self._cond_stack.append(condition) for i, dim in enumerate( @@ -101,6 +101,8 @@ class DecodeLogicGenerator(BusDecoderListener): # non-arrayed component with if-body with self._decode_stack[-1].cm(condition) as b: b += f"{self._flavor.cpuif_select}.{get_indexed_path(self._ds.top_node, node)} = 1'b1;" + else: + raise RuntimeError("Invalid decode stack state") return action