• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

arnavsacheti / PeakRDL-BusDecoder / 21841289452

09 Feb 2026 09:27PM UTC coverage: 92.308%. First build
21841289452

Pull #44

github

Pull Request #44: Feature/array port parameters

248 of 271 new or added lines in 18 files covered. (91.51%)

1404 of 1521 relevant lines covered (92.31%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.51
/src/peakrdl_busdecoder/cpuif/interface.py
1
"""Interface abstraction for handling flat and non-flat signal declarations."""
2

3
import re
1✔
4
from abc import ABC, abstractmethod
1✔
5
from typing import TYPE_CHECKING
1✔
6

7
from systemrdl.node import AddressableNode
1✔
8

9
from ..utils import get_indexed_path
1✔
10

11
if TYPE_CHECKING:
12
    from .base_cpuif import BaseCpuif
13

14

15
class Interface(ABC):
1✔
16
    """Abstract base class for interface signal handling."""
17

18
    def __init__(self, cpuif: "BaseCpuif") -> None:
1✔
19
        self.cpuif = cpuif
1✔
20

21
    @property
1✔
22
    @abstractmethod
1✔
23
    def is_interface(self) -> bool:
1✔
24
        """Whether this uses SystemVerilog interfaces."""
25
        ...
26

27
    @abstractmethod
1✔
28
    def get_port_declaration(self, slave_name: str, master_prefix: str) -> str:
1✔
29
        """
30
        Generate port declarations for the interface.
31

32
        Args:
33
            slave_name: Name of the slave interface/signal prefix
34
            master_prefix: Prefix for master interfaces/signals
35

36
        Returns:
37
            Port declarations as a string
38
        """
39
        ...
40

41
    @abstractmethod
1✔
42
    def signal(
1✔
43
        self,
44
        signal: str,
45
        node: AddressableNode | None = None,
46
        indexer: str | int | None = None,
47
    ) -> str:
48
        """
49
        Generate signal reference.
50

51
        Args:
52
            signal: Signal name
53
            node: Optional addressable node for master signals
54
            indexer: Optional indexer for arrays.
55
                     For SVInterface: str like "i" or "gi" for loop indices
56
                     For FlatInterface: str or int for array subscript
57

58
        Returns:
59
            Signal reference as a string
60
        """
61
        ...
62

63

64
class SVInterface(Interface):
1✔
65
    """SystemVerilog interface-based signal handling."""
66

67
    slave_modport_name = "slave"
1✔
68
    master_modport_name = "master"
1✔
69

70
    @property
1✔
71
    def is_interface(self) -> bool:
1✔
72
        return True
1✔
73

74
    def get_port_declaration(self, slave_name: str, master_prefix: str) -> str:
1✔
75
        """Generate SystemVerilog interface port declarations."""
76
        slave_ports: list[str] = [f"{self.get_interface_type()}.{self.slave_modport_name} {slave_name}"]
1✔
77
        master_ports: list[str] = []
1✔
78

79
        for child in self.cpuif.addressable_children:
1✔
80
            base = f"{self.get_interface_type()}.{self.master_modport_name} {master_prefix}{child.inst_name}"
1✔
81

82
            # When unrolled, current_idx is set - append it to the name
83
            if child.current_idx is not None:
1✔
84
                base = f"{base}_{'_'.join(map(str, child.current_idx))}"
1✔
85

86
            # Only add array dimensions if this should be treated as an array
87
            if self.cpuif.check_is_array(child):
1✔
88
                assert child.array_dimensions is not None
1✔
89
                base = f"{base} {''.join(f'[{dim}]' for dim in child.array_dimensions)}"
1✔
90

1✔
91
            master_ports.append(base)
92

1✔
93
        return ",\n".join(slave_ports + master_ports)
94

1✔
95
    def signal(
96
        self,
1✔
97
        signal: str,
98
        node: AddressableNode | None = None,
1✔
99
        indexer: str | int | None = None,
100
    ) -> str:
101
        """Generate SystemVerilog interface signal reference."""
102

103
        # SVInterface only supports string indexers (loop variable names like "i", "gi")
104
        if indexer is not None and not isinstance(indexer, str):
105
            raise TypeError(f"SVInterface.signal() requires string indexer, got {type(indexer).__name__}")
106

1✔
107
        if node is None or indexer is None:
108
            # Node is none, so this is a slave signal
1✔
109
            slave_name = self.get_slave_name()
1✔
110
            return f"{slave_name}.{signal}"
111

1✔
NEW
112
        # Master signal
×
113
        master_prefix = self.get_master_prefix()
114
        return f"{master_prefix}{get_indexed_path(node.parent, node, indexer, skip_kw_filter=True)}.{signal}"
1✔
115

1✔
116
    @abstractmethod
1✔
117
    def get_interface_type(self) -> str:
118
        """Get the SystemVerilog interface type name."""
1✔
119
        ...
1✔
120

121
    @abstractmethod
122
    def get_slave_name(self) -> str:
123
        """Get the slave interface instance name."""
1✔
124
        ...
1✔
125

126
    @abstractmethod
127
    def get_master_prefix(self) -> str:
128
        """Get the master interface name prefix."""
1✔
129
        ...
1✔
130

131

132
class FlatInterface(Interface):
133
    """Flat signal-based interface handling."""
134

1✔
135
    @property
136
    def is_interface(self) -> bool:
137
        return False
1✔
138

1✔
139
    def get_port_declaration(self, slave_name: str, master_prefix: str) -> str:
1✔
140
        """Generate flat port declarations."""
141
        slave_ports = self._get_slave_port_declarations(slave_name)
1✔
142
        master_ports: list[str] = []
143

1✔
144
        for child in self.cpuif.addressable_children:
1✔
145
            master_ports.extend(self._get_master_port_declarations(child, master_prefix))
146

1✔
147
        return ",\n".join(slave_ports + master_ports)
1✔
148

149
    def signal(
1✔
150
        self,
151
        signal: str,
1✔
152
        node: AddressableNode | None = None,
153
        indexer: str | int | None = None,
154
    ) -> str:
155
        """Generate flat signal reference."""
156
        if node is None:
157
            # Node is none, so this is a slave signal
158
            slave_prefix = self.get_slave_prefix()
1✔
159
            return f"{slave_prefix}{signal}"
160

1✔
161
        # Master signal
1✔
162
        master_prefix = self.get_master_prefix()
163
        base = f"{master_prefix}{node.inst_name}"
164

1✔
165
        if not self.cpuif.check_is_array(node):
1✔
166
            # Not an array or an unrolled element
167
            if node.current_idx is not None:
1✔
168
                # This is a specific instance of an unrolled array
169
                return f"{base}_{signal}_{'_'.join(map(str, node.current_idx))}"
1✔
170
            return f"{base}_{signal}"
171

×
172
        # Is an array
1✔
173
        if indexer is not None:
174
            if isinstance(indexer, str):
175
                indexed_path = get_indexed_path(node.parent, node, indexer, skip_kw_filter=True)
1✔
176
                pattern = r"\[.*?\]"
1✔
177
                indexes = re.findall(pattern, indexed_path)
1✔
178

1✔
179
                return f"{base}_{signal}{''.join(indexes)}"
1✔
180

181
            return f"{base}_{signal}[{indexer}]"
1✔
182
        return f"{base}_{signal}[N_{node.inst_name.upper()}S]"
183

×
184
    @abstractmethod
1✔
185
    def _get_slave_port_declarations(self, slave_prefix: str) -> list[str]:
186
        """Get slave port declarations."""
1✔
187
        ...
1✔
188

189
    @abstractmethod
190
    def _get_master_port_declarations(self, child: AddressableNode, master_prefix: str) -> list[str]:
191
        """Get master port declarations for a child node."""
1✔
192
        ...
1✔
193

194
    @abstractmethod
195
    def get_slave_prefix(self) -> str:
196
        """Get the slave signal name prefix."""
1✔
197
        ...
1✔
198

199
    @abstractmethod
200
    def get_master_prefix(self) -> str:
201
        """Get the master signal name prefix."""
1✔
202
        ...
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc