From bb1ac6bde906fe51cd9e2d28b2293fc1008fde19 Mon Sep 17 00:00:00 2001 From: Arnav Sacheti <36746504+arnavsacheti@users.noreply.github.com> Date: Sun, 19 Oct 2025 00:06:45 -0700 Subject: [PATCH] decoder compiles --- src/peakrdl_busdecoder/__peakrdl__.py | 4 +- src/peakrdl_busdecoder/body/__init__.py | 13 +- src/peakrdl_busdecoder/body/body.py | 3 + .../body/combinational_body.py | 6 +- src/peakrdl_busdecoder/body/for_loop_body.py | 5 +- src/peakrdl_busdecoder/body/if_body.py | 16 +- src/peakrdl_busdecoder/body/struct_body.py | 15 ++ .../body/while_loop_body.py | 13 -- .../cpuif/apb3/apb3_cpuif.py | 35 +--- .../cpuif/apb3/apb3_tmpl.sv | 20 +-- .../cpuif/apb4/apb4_cpuif.py | 34 +--- .../cpuif/apb4/apb4_cpuif_flat.py | 1 + .../cpuif/apb4/apb4_tmpl.sv | 99 +++++++----- src/peakrdl_busdecoder/cpuif/base_cpuif.py | 37 ++--- src/peakrdl_busdecoder/decoder.py | 153 ++++++++++-------- .../{scan_design.py => design_scanner.py} | 12 +- src/peakrdl_busdecoder/design_state.py | 72 +++++++++ src/peakrdl_busdecoder/exporter.py | 102 ++++-------- src/peakrdl_busdecoder/module_tmpl.sv | 35 +--- src/peakrdl_busdecoder/utils.py | 59 +------ src/peakrdl_busdecoder/validate_design.py | 17 +- 21 files changed, 335 insertions(+), 416 deletions(-) create mode 100644 src/peakrdl_busdecoder/body/struct_body.py delete mode 100644 src/peakrdl_busdecoder/body/while_loop_body.py rename src/peakrdl_busdecoder/{scan_design.py => design_scanner.py} (79%) create mode 100644 src/peakrdl_busdecoder/design_state.py diff --git a/src/peakrdl_busdecoder/__peakrdl__.py b/src/peakrdl_busdecoder/__peakrdl__.py index c2b4718..23493aa 100644 --- a/src/peakrdl_busdecoder/__peakrdl__.py +++ b/src/peakrdl_busdecoder/__peakrdl__.py @@ -65,13 +65,13 @@ class Exporter(ExporterSubcommandPlugin): return cpuifs - def add_exporter_arguments(self, arg_group: "argparse._ActionsContainer") -> None: + def add_exporter_arguments(self, arg_group: "argparse.ArgumentParser") -> None: # type: ignore cpuifs = self.get_cpuifs() arg_group.add_argument( "--cpuif", choices=cpuifs.keys(), - default="apb3", + default="apb4", help="Select the CPU interface protocol to use [apb3]", ) diff --git a/src/peakrdl_busdecoder/body/__init__.py b/src/peakrdl_busdecoder/body/__init__.py index 1584657..d8c7574 100644 --- a/src/peakrdl_busdecoder/body/__init__.py +++ b/src/peakrdl_busdecoder/body/__init__.py @@ -1,15 +1,12 @@ from .body import Body, SupportsStr -from .for_loop_body import ForLoopBody -from .while_loop_body import WhileLoopBody -from .if_body import IfBody from .combinational_body import CombinationalBody - +from .for_loop_body import ForLoopBody +from .if_body import IfBody __all__ = [ "Body", - "SupportsStr", - "ForLoopBody", - "WhileLoopBody", - "IfBody", "CombinationalBody", + "ForLoopBody", + "IfBody", + "SupportsStr", ] diff --git a/src/peakrdl_busdecoder/body/body.py b/src/peakrdl_busdecoder/body/body.py index d37f337..203f325 100644 --- a/src/peakrdl_busdecoder/body/body.py +++ b/src/peakrdl_busdecoder/body/body.py @@ -15,3 +15,6 @@ class Body: def __add__(self, other: SupportsStr) -> Self: self.lines.append(other) return self + + def __bool__(self) -> bool: + return bool(self.lines) diff --git a/src/peakrdl_busdecoder/body/combinational_body.py b/src/peakrdl_busdecoder/body/combinational_body.py index 8c090a4..75fa6ad 100644 --- a/src/peakrdl_busdecoder/body/combinational_body.py +++ b/src/peakrdl_busdecoder/body/combinational_body.py @@ -1,8 +1,10 @@ from textwrap import indent + from .body import Body + class CombinationalBody(Body): def __str__(self) -> str: return f"""always_comb begin - {indent(super().__str__(), "\t")} - end""" \ No newline at end of file + {indent(super().__str__(), " ")} + end""" diff --git a/src/peakrdl_busdecoder/body/for_loop_body.py b/src/peakrdl_busdecoder/body/for_loop_body.py index fdf28e1..560aad0 100644 --- a/src/peakrdl_busdecoder/body/for_loop_body.py +++ b/src/peakrdl_busdecoder/body/for_loop_body.py @@ -1,9 +1,10 @@ from textwrap import indent + from .body import Body class ForLoopBody(Body): - def __init__(self, type: str, iterator: str, dim: int): + def __init__(self, type: str, iterator: str, dim: int) -> None: super().__init__() self._type = type self._iterator = iterator @@ -11,5 +12,5 @@ class ForLoopBody(Body): def __str__(self) -> str: return f"""for ({self._type} {self._iterator} = 0; {self._iterator} < {self._dim}; {self._iterator}++) begin -{indent(super().__str__(), "\t")} +{indent(super().__str__(), " ")} end""" diff --git a/src/peakrdl_busdecoder/body/if_body.py b/src/peakrdl_busdecoder/body/if_body.py index 7fb89d5..13d0f06 100644 --- a/src/peakrdl_busdecoder/body/if_body.py +++ b/src/peakrdl_busdecoder/body/if_body.py @@ -1,16 +1,18 @@ from __future__ import annotations + +from textwrap import indent from types import EllipsisType from typing import Self + from .body import Body, SupportsStr class IfBody(Body): - def __init__(self, *, indent: int = 4) -> None: + def __init__(self) -> None: super().__init__() # (None means 'else') self._branches: list[tuple[SupportsStr | None, Body]] = [] self._has_else = False - self._indent = " " * indent # --- Item access: if/else-if via condition; else via Ellipsis/None --- def __getitem__(self, condition: SupportsStr | EllipsisType | None) -> Body: @@ -63,7 +65,7 @@ class IfBody(Body): ) -> bool: return False - def cm(self, condition: SupportsStr | None) -> "IfBody._BranchCtx": + def cm(self, condition: SupportsStr | None) -> IfBody._BranchCtx: """Use with: with ifb.cm('cond') as b: ... ; use None for else.""" return IfBody._BranchCtx(self, condition) @@ -79,6 +81,12 @@ class IfBody(Body): out.append("else begin") body_str = str(body) if body_str: - out.extend(self._indent + ln for ln in body_str.splitlines()) + out.extend(indent(ln, " ") for ln in body_str.splitlines()) out.append("end") return "\n".join(out) + + def __len__(self) -> int: + return len(self._branches) + + def __bool__(self) -> bool: + return bool(self._branches) diff --git a/src/peakrdl_busdecoder/body/struct_body.py b/src/peakrdl_busdecoder/body/struct_body.py new file mode 100644 index 0000000..215d955 --- /dev/null +++ b/src/peakrdl_busdecoder/body/struct_body.py @@ -0,0 +1,15 @@ +from textwrap import indent + +from .body import Body + + +class StructBody(Body): + def __init__(self, name: str, packed: bool = True) -> None: + super().__init__() + self._name = name + self._packed = packed + + def __str__(self) -> str: + return f"""typedef struct {"packed " if self._packed else ""} {{ +{indent(super().__str__(), " ")} +}} {self._name};""" diff --git a/src/peakrdl_busdecoder/body/while_loop_body.py b/src/peakrdl_busdecoder/body/while_loop_body.py deleted file mode 100644 index 980c2bd..0000000 --- a/src/peakrdl_busdecoder/body/while_loop_body.py +++ /dev/null @@ -1,13 +0,0 @@ -from textwrap import indent -from .body import Body - - -class WhileLoopBody(Body): - def __init__(self, condition: str): - super().__init__() - self._condition = condition - - def __str__(self) -> str: - return f"""while ({self._condition}) begin - {indent(super().__str__(), "\t")} - end""" diff --git a/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py b/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py index 524a490..9e68009 100644 --- a/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py +++ b/src/peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py @@ -42,37 +42,4 @@ class APB3Cpuif(BaseCpuif): 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 \ No newline at end of file + raise ValueError("Must provide an index for arrayed interface signals") \ No newline at end of file diff --git a/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv b/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv index 4067454..7495ff3 100644 --- a/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv +++ b/src/peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv @@ -16,14 +16,14 @@ assign cpuif_rd_en = !{{cpuif.signal("PWRITE")}}; {%- for child in cpuif.addressable_children -%} {%- if child is array -%} -for (genvar g_idx = 0; g_idx < N_{{child.inst_name|upper}}S; g_idx++) begin : g_passthrough_{{child.inst_name|lower}} - assign {{cpuif.signal("PCLK", child, "g_idx")}} = {{cpuif.signal("PCLK")}}; - assign {{cpuif.signal("PRESETn", child, "g_idx")}} = {{cpuif.signal("PRESETn")}}; - assign {{cpuif.signal("PSELx", child, "g_idx")}} = (cpuif_wr_req[{{loop.index}}] || cpuif_rd_req[{{loop.index}}]) ? 1'b1 : 1'b0; - assign {{cpuif.signal("PENABLE", child, "g_idx")}} = {{cpuif.signal("PENABLE")}}; - assign {{cpuif.signal("PWRITE", child, "g_idx")}} = (cpuif_wr_req[{{loop.index}}]) ? 1'b1 : 1'b0; - assign {{cpuif.signal("PADDR", child, "g_idx")}} = cpuif_wr_addr{{child|address_slice}}; - assign {{cpuif.signal("PWDATA", child, "g_idx")}} = cpuif_wr_data; +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)}}; @@ -31,10 +31,10 @@ 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("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)}} = cpuif_wr_addr{{child|address_slice}}; +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)}}; diff --git a/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif.py b/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif.py index da46846..7705c0b 100644 --- a/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif.py +++ b/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif.py @@ -1,4 +1,5 @@ from systemrdl.node import AddressableNode + from ..base_cpuif import BaseCpuif @@ -44,36 +45,3 @@ class APB4Cpuif(BaseCpuif): 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 diff --git a/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif_flat.py b/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif_flat.py index 7f28645..c97b202 100644 --- a/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif_flat.py +++ b/src/peakrdl_busdecoder/cpuif/apb4/apb4_cpuif_flat.py @@ -1,4 +1,5 @@ from systemrdl.node import AddressableNode + from ..base_cpuif import BaseCpuif diff --git a/src/peakrdl_busdecoder/cpuif/apb4/apb4_tmpl.sv b/src/peakrdl_busdecoder/cpuif/apb4/apb4_tmpl.sv index d0a8c88..670ae7c 100644 --- a/src/peakrdl_busdecoder/cpuif/apb4/apb4_tmpl.sv +++ b/src/peakrdl_busdecoder/cpuif/apb4/apb4_tmpl.sv @@ -1,4 +1,4 @@ -{%- if cpuif.is_interface -%} +{%- if cpuif.is_interface %} `ifndef SYNTHESIS initial begin assert_bad_addr_width: assert($bits({{cpuif.signal("PADDR")}}) >= {{ds.package_name}}::{{ds.module_name|upper}}_MIN_ADDR_WIDTH) @@ -7,55 +7,76 @@ 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 `endif -{% endif -%} +{%- endif %} 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 g_{{child.inst_name|lower}}_idx = 0; g_{{child.inst_name|lower}}_idx < N_{{child.inst_name|upper}}S; g_{{child.inst_name|lower}}_idx++) begin : g_passthrough_{{child.inst_name|lower}} - assign {{self.signal("PCLK", child, f"g_{child.inst_name.lower()}_idx")}} = {{self.signal("PCLK")}}; - assign {{self.signal("PRESETn", child, f"g_{child.inst_name.lower()}_idx")}} = {{self.signal("PRESETn")}}; - assign {{self.signal("PSELx", child, f"g_{child.inst_name.lower()}_idx")}} = (cpuif_wr_sel[{{loop.index}}] || cpuif_rd_sel[{{loop.index}}]) ? 1'b1 : 1'b0; - assign {{self.signal("PENABLE", child, f"g_{child.inst_name.lower()}_idx")}} = {{self.signal("PENABLE")}}; - assign {{self.signal("PWRITE", child, f"g_{child.inst_name.lower()}_idx")}} = (cpuif_wr_sel[{{loop.index}}]) ? 1'b1 : 1'b0; - assign {{self.signal("PADDR", child, f"g_{child.inst_name.lower()}_idx")}} = {{cpuif.get_address_slice(cpuif_wr_addr, child)}}; - assign {{self.signal("PPROT", child, f"g_{child.inst_name.lower()}_idx")}} = {{self.signal("PPROT")}}; - assign {{self.signal("PWDATA", child, f"g_{child.inst_name.lower()}_idx")}} = cpuif_wr_data; - assign {{self.signal("PSTRB", child, f"g_{child.inst_name.lower()}_idx")}} = {{self.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)}}; -end -{%- else -%} -assign {{self.signal("PCLK", child)}} = {{self.signal("PCLK")}}; -assign {{self.signal("PRESETn", child)}} = {{self.signal("PRESETn")}}; -assign {{self.signal("PSELx", child)}} = (cpuif_wr_sel[{{loop.index0}}] || cpuif_rd_sel[{{loop.index0}}]) ? 1'b1 : 1'b0; -assign {{self.signal("PENABLE", child)}} = {{self.signal("PENABLE")}}; -assign {{self.signal("PWRITE", child)}} = cpuif_wr_sel[{{loop.index}}] ? 1'b1 : 1'b0; -assign {{self.signal("PADDR", child)}} = {{cpuif.get_address_slice(cpuif_wr_addr, child)}}; -assign {{self.signal("PPROT", child)}} = {{self.signal("PPROT")}}; -assign {{self.signal("PWDATA", child)}} = cpuif_wr_data; -assign {{self.signal("PSTRB", child)}} = {{self.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 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 %} + + +//-------------------------------------------------------------------------- +// Fanin CPU Bus interface signals +//-------------------------------------------------------------------------- always_comb begin {{cpuif.signal("PREADY")}} = 1'b0; {{cpuif.signal("PRDATA")}} = '0; {{cpuif.signal("PSLVERR")}} = 1'b0; - 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 + +{%- 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 diff --git a/src/peakrdl_busdecoder/cpuif/base_cpuif.py b/src/peakrdl_busdecoder/cpuif/base_cpuif.py index 72e9028..13bf734 100644 --- a/src/peakrdl_busdecoder/cpuif/base_cpuif.py +++ b/src/peakrdl_busdecoder/cpuif/base_cpuif.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING import jinja2 as jj from systemrdl.node import AddressableNode -from ..utils import clog2, is_pow2, roundup_pow2 +from ..utils import clog2, get_indexed_path, is_pow2, roundup_pow2 if TYPE_CHECKING: from ..exporter import BusDecoderExporter @@ -83,6 +83,7 @@ class BaseCpuif: jj_env.filters["is_pow2"] = is_pow2 # type: ignore 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 context = { "cpuif": self, @@ -92,33 +93,13 @@ class BaseCpuif: template = jj_env.get_template(self.template_path) return template.render(context) - def get_address_slice(self, node: AddressableNode) -> str: - """ - Returns a SystemVerilog expression that extracts the address bits - relevant to the given node. - """ - addr_mask = (1 << self.addr_width) - 1 - addr = node.absolute_address & addr_mask + def get_address_slice(self, node: AddressableNode, cpuif_addr: str = "cpuif_addr") -> str: + addr = node.raw_absolute_address - self.exp.ds.top_node.raw_absolute_address size = node.size - if size == 0: - raise ValueError(f"Node size '{size:#X}' must be greater than 0") - if (addr % size) != 0: - raise ValueError(f"Node address '{addr:#X}' must be aligned to its size '{size:#X}'") - # 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") + addr_msb = clog2(addr + size) - 1 + addr_lsb = clog2(addr) - # Calculate the number of bits needed to represent the size - size_bits = size.bit_length() - 1 - if size_bits < 0: - size_bits = 0 - - if size_bits >= self.addr_width: - # Node covers entire address space, so return full address - return "" - - # Extract the relevant bits from PADDR - return f"[{self.addr_width - 1}:{size_bits}]" + if addr_msb == addr_lsb: + return f"{cpuif_addr}[{addr_lsb}]" + return f"{cpuif_addr}[{addr_msb}:{addr_lsb}]" diff --git a/src/peakrdl_busdecoder/decoder.py b/src/peakrdl_busdecoder/decoder.py index 4b49232..38330b9 100644 --- a/src/peakrdl_busdecoder/decoder.py +++ b/src/peakrdl_busdecoder/decoder.py @@ -1,72 +1,92 @@ from collections import deque +from enum import Enum from systemrdl.node import AddressableNode from systemrdl.walker import RDLListener, RDLSimpleWalker, WalkerAction from .body import Body, ForLoopBody, IfBody +from .design_state import DesignState from .sv_int import SVInt +from .utils import get_indexed_path + + +class DecodeLogicFlavor(Enum): + READ = "rd" + WRITE = "wr" + + @property + def cpuif_address(self) -> str: + return f"cpuif_{self.value}_addr" + + @property + def cpuif_select(self) -> str: + return f"cpuif_{self.value}_sel" class AddressDecode: - def __init__(self, node: AddressableNode, addr_width: int) -> None: - self._node = node - self._addr_width = addr_width + def __init__(self, flavor: DecodeLogicFlavor, ds: DesignState) -> None: + self._flavor = flavor + self._ds = ds def walk(self) -> str: walker = RDLSimpleWalker() - dlg = DecodeLogicGenerator(self) - walker.walk(self._node, dlg, skip_top=True) + dlg = DecodeLogicGenerator(self._flavor, self._ds) + walker.walk(self._ds.top_node, dlg, skip_top=True) return str(dlg) - @property - def node(self) -> AddressableNode: - return self._node - - @property - def addr_width(self) -> int: - return self._addr_width - class DecodeLogicGenerator(RDLListener): - cpuif_addr_signal = "addr" - cpuif_sel_prefix = "cpuif_" - def __init__( self, - address_decoder: AddressDecode, - max_depth: int = 1, + flavor: DecodeLogicFlavor, + ds: DesignState, ) -> None: - self._address_decoder = address_decoder - self._depth = 0 - self._max_depth = max_depth + self._ds = ds + self._flavor = flavor - self._stack: list[Body] = [IfBody()] - self._conditions: deque[str] = deque() - self._select_signal = [f"{self.cpuif_sel_prefix}{address_decoder.node.inst_name}"] + self._decode_stack: deque[Body] = deque() # Tracks decoder body + self._cond_stack: deque[str] = deque() # Tracks conditions nested for loops + self._array_stride_stack: deque[int] = deque() # Tracks nested array strids - # Stack to keep track of array strides for nested arrayed components - self._array_stride_stack: list[int] = [] + # Initial Stack Conditions + self._decode_stack.append(IfBody()) - def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None: + def cpuif_addr_predicate(self, node: AddressableNode) -> list[str]: # Generate address bounds - addr_width = self._address_decoder.addr_width + addr_width = self._ds.addr_width l_bound = SVInt( - node.raw_absolute_address - self._address_decoder.node.raw_absolute_address, + node.raw_address_offset, addr_width, ) u_bound = l_bound + SVInt(node.total_size, addr_width) # Handle arrayed components - l_bound_str = str(l_bound) - u_bound_str = str(u_bound) + l_bound_comp = [str(l_bound)] + u_bound_comp = [str(u_bound)] for i, stride in enumerate(self._array_stride_stack): - l_bound_str += f" + (({addr_width})'(i{i}) * {SVInt(stride, addr_width)})" - u_bound_str += f" + (({addr_width})'(i{i}) * {SVInt(stride, addr_width)})" + l_bound_comp.append(f"({addr_width}'(i{i})*{SVInt(stride, addr_width)})") + u_bound_comp.append(f"({addr_width}'(i{i})*{SVInt(stride, addr_width)})") - # Generate condition string - condition = ( - f"({self.cpuif_addr_signal} >= ({l_bound_str})) && ({self.cpuif_addr_signal} < ({u_bound_str}))" - ) + # Generate Conditions + return [ + f"{self._flavor.cpuif_address} >= ({'+'.join(l_bound_comp)})", + f"{self._flavor.cpuif_address} < ({'+'.join(u_bound_comp)})", + ] + + def cpuif_prot_predicate(self, node: AddressableNode) -> list[str]: + if self._flavor == DecodeLogicFlavor.READ: + # Can we have PROT on read? (axi full?) + return [] + + # TODO: Implement + return [] + + def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None: + conditions: list[str] = [] + conditions.extend(self.cpuif_addr_predicate(node)) + conditions.extend(self.cpuif_prot_predicate(node)) + + condition = " && ".join(f"({c})" for c in conditions) if node.array_dimensions: assert node.array_stride is not None, "Array stride should be defined for arrayed components" @@ -80,26 +100,25 @@ class DecodeLogicGenerator(RDLListener): self._array_stride_stack.extend(strides) # Generate condition string and manage stack - signal = node.inst_name - if isinstance(self._stack[-1], IfBody) and node.array_dimensions: + if isinstance(self._decode_stack[-1], IfBody) and node.array_dimensions: # arrayed component with new if-body - self._conditions.append(condition) - for dim in node.array_dimensions: + self._cond_stack.append(condition) + for i, dim in enumerate( + node.array_dimensions, + start=len(self._array_stride_stack) - len(node.array_dimensions), + ): fb = ForLoopBody( "int", - f"i{self._depth}", + f"i{i}", dim, ) - self._stack.append(fb) - signal += f"[i{self._depth}]" - self._depth += 1 + self._decode_stack.append(fb) - self._stack.append(IfBody()) - elif isinstance(self._stack[-1], IfBody): + self._decode_stack.append(IfBody()) + elif isinstance(self._decode_stack[-1], IfBody): # non-arrayed component with if-body - with self._stack[-1].cm(condition) as b: - b += f"{'.'.join([*self._select_signal, signal])} = 1'b1;" - self._select_signal.append(signal) + 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;" # if node.external: # return WalkerAction.SkipDescendants @@ -107,26 +126,34 @@ class DecodeLogicGenerator(RDLListener): return WalkerAction.Continue def exit_AddressableComponent(self, node: AddressableNode) -> None: - self._select_signal.pop() - if not node.array_dimensions: return - ifb = self._stack.pop() - self._stack[-1] += ifb + ifb = self._decode_stack.pop() + if ifb: + self._decode_stack[-1] += ifb + else: + self._decode_stack[-1] += ( + f"{self._flavor.cpuif_select}.{get_indexed_path(self._ds.top_node, node)} = 1'b1;" + ) for _ in node.array_dimensions: - self._depth -= 1 + b = self._decode_stack.pop() + if not b: + continue - b = self._stack.pop() - if b.lines: - if isinstance(self._stack[-1], IfBody): - with self._stack[-1].cm(self._conditions.pop()) as parent_b: - parent_b += b - else: - self._stack[-1] += b + if isinstance(self._decode_stack[-1], IfBody): + with self._decode_stack[-1].cm(self._cond_stack.pop()) as parent_b: + parent_b += b + else: + self._decode_stack[-1] += b self._array_stride_stack.pop() def __str__(self) -> str: - return str(self._stack[-1]) + body = self._decode_stack[-1] + if isinstance(body, IfBody): + with body.cm(...) as b: + b += f"{self._flavor.cpuif_select}.bad_addr = 1'b1;" + + return str(body) diff --git a/src/peakrdl_busdecoder/scan_design.py b/src/peakrdl_busdecoder/design_scanner.py similarity index 79% rename from src/peakrdl_busdecoder/scan_design.py rename to src/peakrdl_busdecoder/design_scanner.py index 0ba2bfd..871b4b7 100644 --- a/src/peakrdl_busdecoder/scan_design.py +++ b/src/peakrdl_busdecoder/design_scanner.py @@ -1,12 +1,10 @@ from typing import TYPE_CHECKING -from systemrdl.node import RegNode +from systemrdl.node import AddressableNode, AddrmapNode, Node, RegNode from systemrdl.walker import RDLListener, RDLWalker, WalkerAction if TYPE_CHECKING: - from systemrdl.node import AddressableNode, AddrmapNode, Node - - from .exporter import DesignState + from .design_state import DesignState class DesignScanner(RDLListener): @@ -22,7 +20,7 @@ class DesignScanner(RDLListener): self.msg = self.top_node.env.msg @property - def top_node(self) -> "AddrmapNode": + def top_node(self) -> AddrmapNode: return self.ds.top_node def do_scan(self) -> None: @@ -30,7 +28,7 @@ class DesignScanner(RDLListener): if self.msg.had_error: self.msg.fatal("Unable to export due to previous errors") - def enter_Component(self, node: "Node") -> WalkerAction | None: + def enter_Component(self, node: Node) -> WalkerAction: if node.external and (node != self.top_node): # Do not inspect external components. None of my business return WalkerAction.SkipDescendants @@ -41,7 +39,7 @@ class DesignScanner(RDLListener): return WalkerAction.Continue - def enter_AddressableComponent(self, node: "AddressableNode") -> None: + def enter_AddressableComponent(self, node: AddressableNode) -> None: if node.external and node != self.top_node: self.ds.has_external_addressable = True if not isinstance(node, RegNode): diff --git a/src/peakrdl_busdecoder/design_state.py b/src/peakrdl_busdecoder/design_state.py new file mode 100644 index 0000000..05263cb --- /dev/null +++ b/src/peakrdl_busdecoder/design_state.py @@ -0,0 +1,72 @@ +from typing import TypedDict + +from systemrdl.node import AddrmapNode +from systemrdl.rdltypes.user_enum import UserEnum + +from .design_scanner import DesignScanner +from .identifier_filter import kw_filter as kwf +from .utils import clog2 + + +class DesignStateKwargs(TypedDict, total=False): + reuse_hwif_typedefs: bool + module_name: str + package_name: str + address_width: int + cpuif_unroll: bool + + +class DesignState: + """ + Dumping ground for all sorts of variables that are relevant to a particular + design. + """ + + def __init__(self, top_node: AddrmapNode, kwargs: DesignStateKwargs) -> None: + self.top_node = top_node + msg = top_node.env.msg + + # ------------------------ + # Extract compiler args + # ------------------------ + self.reuse_hwif_typedefs: bool = kwargs.pop("reuse_hwif_typedefs", True) + self.module_name: str = kwargs.pop("module_name", None) or kwf(self.top_node.inst_name) + self.package_name: str = kwargs.pop("package_name", None) or f"{self.module_name}_pkg" + user_addr_width: int | None = kwargs.pop("address_width", None) + + self.cpuif_unroll: bool = kwargs.pop("cpuif_unroll", False) + + # ------------------------ + # Info about the design + # ------------------------ + self.cpuif_data_width = 0 + + # Track any referenced enums + self.user_enums: list[type[UserEnum]] = [] + + self.has_external_addressable = False + self.has_external_block = False + + # Scan the design to fill in above variables + DesignScanner(self).do_scan() + + if self.cpuif_data_width == 0: + # Scanner did not find any registers in the design being exported, + # so the width is not known. + # Assume 32-bits + msg.warning( + "Addrmap being exported only contains external components. Unable to infer the CPUIF bus width. Assuming 32-bits.", + self.top_node.inst.def_src_ref, + ) + self.cpuif_data_width = 32 + + # ------------------------ + # Min address width encloses the total size AND at least 1 useful address bit + self.addr_width = max(clog2(self.top_node.size), clog2(self.cpuif_data_width // 8) + 1) + + if user_addr_width is None: + return + + if user_addr_width < self.addr_width: + msg.fatal(f"User-specified address width shall be greater than or equal to {self.addr_width}.") + self.addr_width = user_addr_width diff --git a/src/peakrdl_busdecoder/exporter.py b/src/peakrdl_busdecoder/exporter.py index 82dcae0..fbeeb14 100644 --- a/src/peakrdl_busdecoder/exporter.py +++ b/src/peakrdl_busdecoder/exporter.py @@ -1,53 +1,63 @@ import os from datetime import datetime from importlib.metadata import version -from typing import TYPE_CHECKING, Any +from pathlib import Path +from typing import TYPE_CHECKING, TypedDict import jinja2 as jj from systemrdl.node import AddrmapNode, RootNode -from systemrdl.rdltypes.user_enum import UserEnum +from typing_extensions import Unpack from .cpuif import BaseCpuif from .cpuif.apb4 import APB4Cpuif -from .decoder import AddressDecode +from .decoder import AddressDecode, DecodeLogicFlavor +from .design_state import DesignState from .identifier_filter import kw_filter as kwf -from .scan_design import DesignScanner from .sv_int import SVInt -from .utils import clog2 from .validate_design import DesignValidator + +class ExporterKwargs(TypedDict, total=False): + cpuif_cls: type[BaseCpuif] + module_name: str + package_name: str + address_width: int + cpuif_unroll: bool + reuse_hwif_typedefs: bool + + if TYPE_CHECKING: pass class BusDecoderExporter: cpuif: BaseCpuif - address_decode: AddressDecode - ds: "DesignState" + address_decode: type[AddressDecode] + ds: DesignState - def __init__(self, **kwargs: Any) -> None: + def __init__(self, **kwargs: Unpack[ExporterKwargs]) -> None: # Check for stray kwargs if kwargs: raise TypeError(f"got an unexpected keyword argument '{next(iter(kwargs.keys()))}'") - loader = jj.ChoiceLoader( + fs_loader = jj.FileSystemLoader(Path(__file__).parent) + c_loader = jj.ChoiceLoader( [ - jj.FileSystemLoader(os.path.dirname(__file__)), + fs_loader, jj.PrefixLoader( - { - "base": jj.FileSystemLoader(os.path.dirname(__file__)), - }, + {"base": fs_loader}, delimiter=":", ), ] ) self.jj_env = jj.Environment( - loader=loader, + loader=c_loader, undefined=jj.StrictUndefined, ) + self.jj_env.filters["kwf"] = kwf - def export(self, node: RootNode | AddrmapNode, output_dir: str, **kwargs: Any) -> None: + def export(self, node: RootNode | AddrmapNode, output_dir: str, **kwargs: Unpack[ExporterKwargs]) -> None: """ Parameters ---------- @@ -68,7 +78,7 @@ class BusDecoderExporter: address_width: int Override the CPU interface's address width. By default, address width is sized to the contents of the busdecoder. - unroll: bool + cpuif_unroll: bool Unroll arrayed addressable nodes into separate instances in the CPU interface. By default, arrayed nodes are kept as arrays. """ @@ -88,7 +98,7 @@ class BusDecoderExporter: # Construct exporter components self.cpuif = cpuif_cls(self) - self.address_decode = AddressDecode(top_node, self.ds.addr_width) + self.address_decode = AddressDecode # Validate that there are no unsupported constructs DesignValidator(self).do_validate() @@ -99,8 +109,8 @@ class BusDecoderExporter: "version": version("peakrdl-busdecoder"), "cpuif": self.cpuif, "address_decode": self.address_decode, + "DecodeLogicFlavor": DecodeLogicFlavor, "ds": self.ds, - "kwf": kwf, "SVInt": SVInt, } @@ -115,59 +125,3 @@ class BusDecoderExporter: template = self.jj_env.get_template("module_tmpl.sv") stream = template.stream(context) stream.dump(module_file_path) - - -class DesignState: - """ - Dumping ground for all sorts of variables that are relevant to a particular - design. - """ - - def __init__(self, top_node: AddrmapNode, kwargs: Any) -> None: - self.top_node = top_node - msg = top_node.env.msg - - # ------------------------ - # Extract compiler args - # ------------------------ - self.reuse_hwif_typedefs: bool = kwargs.pop("reuse_hwif_typedefs", True) - self.module_name: str = kwargs.pop("module_name", None) or kwf(self.top_node.inst_name) - self.package_name: str = kwargs.pop("package_name", None) or (self.module_name + "_pkg") - user_addr_width: int | None = kwargs.pop("address_width", None) - - self.cpuif_unroll: bool = kwargs.pop("cpuif_unroll", False) - - # ------------------------ - # Info about the design - # ------------------------ - self.cpuif_data_width = 0 - - # Track any referenced enums - self.user_enums: list[type[UserEnum]] = [] - - self.has_external_addressable = False - self.has_external_block = False - - # Scan the design to fill in above variables - DesignScanner(self).do_scan() - - if self.cpuif_data_width == 0: - # Scanner did not find any registers in the design being exported, - # so the width is not known. - # Assume 32-bits - msg.warning( - "Addrmap being exported only contains external components. Unable to infer the CPUIF bus width. Assuming 32-bits.", - self.top_node.inst.def_src_ref, - ) - self.cpuif_data_width = 32 - - # ------------------------ - # Min address width encloses the total size AND at least 1 useful address bit - self.addr_width = max(clog2(self.top_node.size), clog2(self.cpuif_data_width // 8) + 1) - - if user_addr_width is not None: - if user_addr_width < self.addr_width: - msg.fatal( - f"User-specified address width shall be greater than or equal to {self.addr_width}." - ) - self.addr_width = user_addr_width diff --git a/src/peakrdl_busdecoder/module_tmpl.sv b/src/peakrdl_busdecoder/module_tmpl.sv index 402051a..9f6cb7b 100644 --- a/src/peakrdl_busdecoder/module_tmpl.sv +++ b/src/peakrdl_busdecoder/module_tmpl.sv @@ -39,8 +39,11 @@ module {{ds.module_name}} //-------------------------------------------------------------------------- // Child instance signals //-------------------------------------------------------------------------- - logic [{{cpuif.addressable_children | length}}-1:0] cpuif_wr_sel; - logic [{{cpuif.addressable_children | length}}-1:0] cpuif_rd_sel; + typedef struct packed { + + } cpuif_sel_t; + cpuif_sel_t cpuif_wr_sel; + cpuif_sel_t cpuif_rd_sel; //-------------------------------------------------------------------------- // Slave <-> Internal CPUIF <-> Master @@ -56,19 +59,7 @@ module {{ds.module_name}} if (cpuif_req && cpuif_wr_en) begin // A write request is pending - {%- for child in cpuif.addressable_children -%} - {%- if loop.first -%} - if {{child|address_decode}} begin - {%- else -%} - end else if {{child|address_decode}} begin - {%- endif -%} - // Address matched for {{child.inst_name}} - cpuif_wr_sel[{{loop.index}}] = 1'b1; - {%- endfor -%} - end else begin - // No address match, all select signals remain 0 - cpuif_wr_err = 1'b1; // Indicate error on no match - end + {{address_decode(DecodeLogicFlavor.WRITE, ds).walk()|indent(12)}} end else begin // No write request, all select signals remain 0 end @@ -83,19 +74,7 @@ module {{ds.module_name}} if (cpuif_req && cpuif_rd_en) begin // A read request is pending - {%- for child in cpuif.addressable_children -%} - {%- if loop.first -%} - if {{child|address_decode}} begin - {%- else -%} - end else if {{child|address_decode}} begin - {%- endif -%} - // Address matched for {{child.inst_name}} - cpuif_rd_sel[{{loop.index}}] = 1'b1; - {%- endfor -%} - end else begin - // No address match, all select signals remain 0 - cpuif_rd_err = 1'b1; // Indicate error on no match - end + {{address_decode(DecodeLogicFlavor.READ, ds).walk()|indent(12)}} end else begin // No read request, all select signals remain 0 end diff --git a/src/peakrdl_busdecoder/utils.py b/src/peakrdl_busdecoder/utils.py index c42c991..0f838c5 100644 --- a/src/peakrdl_busdecoder/utils.py +++ b/src/peakrdl_busdecoder/utils.py @@ -1,17 +1,16 @@ import re from re import Match -from typing import overload from systemrdl.node import AddrmapNode, Node from systemrdl.rdltypes.references import PropertyReference from .identifier_filter import kw_filter as kwf -from .sv_int import SVInt -def get_indexed_path(top_node: Node, target_node: Node) -> str: +def get_indexed_path(top_node: Node, target_node: Node, indexer: str = "i") -> str: """ - TODO: Add words about indexing and why i'm doing this. Copy from logbook + Get the relative path from top_node to target_node, replacing any unknown + array indexes with incrementing iterators (i0, i1, ...). """ path = target_node.get_rel_path(top_node, empty_array_suffix="[!]") @@ -21,7 +20,7 @@ def get_indexed_path(top_node: Node, target_node: Node) -> str: self.i = 0 def __call__(self, match: Match[str]) -> str: - s = f"i{self.i}" + s = f"{indexer}{self.i}" self.i += 1 return s @@ -54,13 +53,10 @@ def ref_is_internal(top_node: AddrmapNode, ref: Node | PropertyReference) -> boo For the sake of this exporter, root signals are treated as internal. """ - # current_node: Optional[Node] - if isinstance(ref, Node): - current_node = ref - elif isinstance(ref, PropertyReference): + if isinstance(ref, PropertyReference): current_node = ref.node else: - raise RuntimeError + current_node = ref while current_node is not None: if current_node == top_node: @@ -77,46 +73,3 @@ def ref_is_internal(top_node: AddrmapNode, ref: Node | PropertyReference) -> boo # A root signal was referenced, which dodged the top addrmap # This is considered internal for this exporter return True - - -@overload -def do_slice(value: SVInt, high: int, low: int) -> SVInt: ... -@overload -def do_slice(value: str, high: int, low: int) -> str: ... -def do_slice(value: SVInt | str, high: int, low: int) -> SVInt | str: - if isinstance(value, str): - # If string, assume this is an identifier. Append bit-slice - if high == low: - return f"{value}[{low}]" - else: - return f"{value}[{high}:{low}]" - else: - # it is an SVInt literal. Slice it down - mask = (1 << (high + 1)) - 1 - v = (value.value & mask) >> low - - if value.width is not None: - w = high - low + 1 - else: - w = None - - return SVInt(v, w) - - -@overload -def do_bitswap(value: SVInt) -> SVInt: ... -@overload -def do_bitswap(value: str) -> str: ... -def do_bitswap(value: SVInt | str) -> SVInt | str: - if isinstance(value, str): - # If string, assume this is an identifier. Wrap in a streaming operator - return "{<<{" + value + "}}" - else: - # it is an SVInt literal. bitswap it - assert value.width is not None # width must be known! - v = value.value - vswap = 0 - for _ in range(value.width): - vswap = (vswap << 1) + (v & 1) - v >>= 1 - return SVInt(vswap, value.width) diff --git a/src/peakrdl_busdecoder/validate_design.py b/src/peakrdl_busdecoder/validate_design.py index c0b9b77..4528b15 100644 --- a/src/peakrdl_busdecoder/validate_design.py +++ b/src/peakrdl_busdecoder/validate_design.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING from systemrdl.node import AddressableNode, AddrmapNode, FieldNode, Node, RegfileNode, RegNode, SignalNode -from systemrdl.rdltypes import PropertyReference +from systemrdl.rdltypes.references import PropertyReference from systemrdl.walker import RDLListener, RDLWalker, WalkerAction from .utils import is_pow2, ref_is_internal, roundup_pow2 @@ -148,21 +148,6 @@ class DesignValidator(RDLListener): node.inst.inst_src_ref, ) - # Check for unsynthesizable reset - reset = node.get_property("reset") - if not (reset is None or isinstance(reset, int)): - # Has reset that is not a constant value - resetsignal = node.get_property("resetsignal") - if resetsignal: - is_async_reset = resetsignal.get_property("async") - else: - is_async_reset = self.ds.default_reset_async - - if is_async_reset: - self.msg.error( - "A field that uses an asynchronous reset cannot use a dynamic reset value. This is not synthesizable.", - node.inst.inst_src_ref, - ) def exit_AddressableComponent(self, node: AddressableNode) -> None: if not isinstance(node, RegNode):