peakrdl-busdecoder 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. peakrdl_busdecoder/__init__.py +3 -0
  2. peakrdl_busdecoder/__peakrdl__.py +136 -0
  3. peakrdl_busdecoder/body/__init__.py +14 -0
  4. peakrdl_busdecoder/body/body.py +22 -0
  5. peakrdl_busdecoder/body/combinational_body.py +10 -0
  6. peakrdl_busdecoder/body/for_loop_body.py +16 -0
  7. peakrdl_busdecoder/body/if_body.py +91 -0
  8. peakrdl_busdecoder/body/struct_body.py +25 -0
  9. peakrdl_busdecoder/cpuif/__init__.py +3 -0
  10. peakrdl_busdecoder/cpuif/apb3/__init__.py +4 -0
  11. peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py +67 -0
  12. peakrdl_busdecoder/cpuif/apb3/apb3_cpuif_flat.py +68 -0
  13. peakrdl_busdecoder/cpuif/apb3/apb3_interface.py +56 -0
  14. peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv +33 -0
  15. peakrdl_busdecoder/cpuif/apb4/__init__.py +4 -0
  16. peakrdl_busdecoder/cpuif/apb4/apb4_cpuif.py +70 -0
  17. peakrdl_busdecoder/cpuif/apb4/apb4_cpuif_flat.py +70 -0
  18. peakrdl_busdecoder/cpuif/apb4/apb4_interface.py +60 -0
  19. peakrdl_busdecoder/cpuif/apb4/apb4_tmpl.sv +36 -0
  20. peakrdl_busdecoder/cpuif/axi4lite/__init__.py +4 -0
  21. peakrdl_busdecoder/cpuif/axi4lite/axi4_lite_cpuif.py +84 -0
  22. peakrdl_busdecoder/cpuif/axi4lite/axi4_lite_cpuif_flat.py +86 -0
  23. peakrdl_busdecoder/cpuif/axi4lite/axi4lite_interface.py +84 -0
  24. peakrdl_busdecoder/cpuif/axi4lite/axi4lite_tmpl.sv +60 -0
  25. peakrdl_busdecoder/cpuif/base_cpuif.py +118 -0
  26. peakrdl_busdecoder/cpuif/fanin_gen.py +64 -0
  27. peakrdl_busdecoder/cpuif/fanout_gen.py +50 -0
  28. peakrdl_busdecoder/cpuif/interface.py +190 -0
  29. peakrdl_busdecoder/decode_logic_gen.py +152 -0
  30. peakrdl_busdecoder/design_scanner.py +46 -0
  31. peakrdl_busdecoder/design_state.py +74 -0
  32. peakrdl_busdecoder/exporter.py +142 -0
  33. peakrdl_busdecoder/identifier_filter.py +263 -0
  34. peakrdl_busdecoder/listener.py +58 -0
  35. peakrdl_busdecoder/module_tmpl.sv +79 -0
  36. peakrdl_busdecoder/package_tmpl.sv +21 -0
  37. peakrdl_busdecoder/py.typed +0 -0
  38. peakrdl_busdecoder/struct_gen.py +57 -0
  39. peakrdl_busdecoder/sv_int.py +21 -0
  40. peakrdl_busdecoder/udps/__init__.py +5 -0
  41. peakrdl_busdecoder/utils.py +80 -0
  42. peakrdl_busdecoder/validate_design.py +185 -0
  43. peakrdl_busdecoder-0.2.0.dist-info/METADATA +40 -0
  44. peakrdl_busdecoder-0.2.0.dist-info/RECORD +48 -0
  45. peakrdl_busdecoder-0.2.0.dist-info/WHEEL +5 -0
  46. peakrdl_busdecoder-0.2.0.dist-info/entry_points.txt +2 -0
  47. peakrdl_busdecoder-0.2.0.dist-info/licenses/LICENSE +165 -0
  48. peakrdl_busdecoder-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,263 @@
1
+ # All SystemVerilog 2017 keywords
2
+ SV_KEYWORDS = {
3
+ "accept_on",
4
+ "alias",
5
+ "always",
6
+ "always_comb",
7
+ "always_ff",
8
+ "always_latch",
9
+ "and",
10
+ "assert",
11
+ "assign",
12
+ "assume",
13
+ "automatic",
14
+ "before",
15
+ "begin",
16
+ "bind",
17
+ "bins",
18
+ "binsof",
19
+ "bit",
20
+ "break",
21
+ "buf",
22
+ "bufif0",
23
+ "bufif1",
24
+ "byte",
25
+ "case",
26
+ "casex",
27
+ "casez",
28
+ "cell",
29
+ "chandle",
30
+ "checker",
31
+ "class",
32
+ "clocking",
33
+ "cmos",
34
+ "config",
35
+ "const",
36
+ "constraint",
37
+ "context",
38
+ "continue",
39
+ "cover",
40
+ "covergroup",
41
+ "coverpoint",
42
+ "cross",
43
+ "deassign",
44
+ "default",
45
+ "defparam",
46
+ "design",
47
+ "disable",
48
+ "dist",
49
+ "do",
50
+ "edge",
51
+ "else",
52
+ "end",
53
+ "endcase",
54
+ "endchecker",
55
+ "endclass",
56
+ "endclocking",
57
+ "endconfig",
58
+ "endfunction",
59
+ "endgenerate",
60
+ "endgroup",
61
+ "endinterface",
62
+ "endmodule",
63
+ "endpackage",
64
+ "endprimitive",
65
+ "endprogram",
66
+ "endproperty",
67
+ "endspecify",
68
+ "endsequence",
69
+ "endtable",
70
+ "endtask",
71
+ "enum",
72
+ "event",
73
+ "eventually",
74
+ "expect",
75
+ "export",
76
+ "extends",
77
+ "extern",
78
+ "final",
79
+ "first_match",
80
+ "for",
81
+ "force",
82
+ "foreach",
83
+ "forever",
84
+ "fork",
85
+ "forkjoin",
86
+ "function",
87
+ "generate",
88
+ "genvar",
89
+ "global",
90
+ "highz0",
91
+ "highz1",
92
+ "if",
93
+ "iff",
94
+ "ifnone",
95
+ "ignore_bins",
96
+ "illegal_bins",
97
+ "implements",
98
+ "implies",
99
+ "import",
100
+ "incdir",
101
+ "include",
102
+ "initial",
103
+ "inout",
104
+ "input",
105
+ "inside",
106
+ "instance",
107
+ "int",
108
+ "integer",
109
+ "interconnect",
110
+ "interface",
111
+ "intersect",
112
+ "join",
113
+ "join_any",
114
+ "join_none",
115
+ "large",
116
+ "let",
117
+ "liblist",
118
+ "library",
119
+ "local",
120
+ "localparam",
121
+ "logic",
122
+ "longint",
123
+ "macromodule",
124
+ "matches",
125
+ "medium",
126
+ "modport",
127
+ "module",
128
+ "nand",
129
+ "negedge",
130
+ "nettype",
131
+ "new",
132
+ "nexttime",
133
+ "nmos",
134
+ "nor",
135
+ "noshowcancelled",
136
+ "not",
137
+ "notif0",
138
+ "notif1",
139
+ "null",
140
+ "or",
141
+ "output",
142
+ "package",
143
+ "packed",
144
+ "parameter",
145
+ "pmos",
146
+ "posedge",
147
+ "primitive",
148
+ "priority",
149
+ "program",
150
+ "property",
151
+ "protected",
152
+ "pull0",
153
+ "pull1",
154
+ "pulldown",
155
+ "pullup",
156
+ "pulsestyle_ondetect",
157
+ "pulsestyle_onevent",
158
+ "pure",
159
+ "rand",
160
+ "randc",
161
+ "randcase",
162
+ "randsequence",
163
+ "rcmos",
164
+ "real",
165
+ "realtime",
166
+ "ref",
167
+ "reg",
168
+ "reject_on",
169
+ "release",
170
+ "repeat",
171
+ "restrict",
172
+ "return",
173
+ "rnmos",
174
+ "rpmos",
175
+ "rtran",
176
+ "rtranif0",
177
+ "rtranif1",
178
+ "s_always",
179
+ "s_eventually",
180
+ "s_nexttime",
181
+ "s_until",
182
+ "s_until_with",
183
+ "scalared",
184
+ "sequence",
185
+ "shortint",
186
+ "shortreal",
187
+ "showcancelled",
188
+ "signed",
189
+ "small",
190
+ "soft",
191
+ "solve",
192
+ "specify",
193
+ "specparam",
194
+ "static",
195
+ "string",
196
+ "strong",
197
+ "strong0",
198
+ "strong1",
199
+ "struct",
200
+ "super",
201
+ "supply0",
202
+ "supply1",
203
+ "sync_accept_on",
204
+ "sync_reject_on",
205
+ "table",
206
+ "tagged",
207
+ "task",
208
+ "this",
209
+ "throughout",
210
+ "time",
211
+ "timeprecision",
212
+ "timeunit",
213
+ "tran",
214
+ "tranif0",
215
+ "tranif1",
216
+ "tri",
217
+ "tri0",
218
+ "tri1",
219
+ "triand",
220
+ "trior",
221
+ "trireg",
222
+ "type",
223
+ "typedef",
224
+ "union",
225
+ "unique",
226
+ "unique0",
227
+ "unsigned",
228
+ "until",
229
+ "until_with",
230
+ "untyped",
231
+ "use",
232
+ "uwire",
233
+ "var",
234
+ "vectored",
235
+ "virtual",
236
+ "void",
237
+ "wait",
238
+ "wait_order",
239
+ "wand",
240
+ "weak",
241
+ "weak0",
242
+ "weak1",
243
+ "while",
244
+ "wildcard",
245
+ "wire",
246
+ "with",
247
+ "within",
248
+ "wor",
249
+ "xnor",
250
+ "xor",
251
+ }
252
+
253
+
254
+ def kw_filter(s: str) -> str:
255
+ """
256
+ Make all user identifiers 'safe' and ensure they do not collide with
257
+ SystemVerilog keywords.
258
+
259
+ If an SV keyword is encountered, add an underscore suffix
260
+ """
261
+ if s in SV_KEYWORDS:
262
+ s += "_"
263
+ return s
@@ -0,0 +1,58 @@
1
+ from collections import deque
2
+
3
+ from systemrdl.node import AddressableNode, RegNode
4
+ from systemrdl.walker import RDLListener, WalkerAction
5
+
6
+ from .design_state import DesignState
7
+
8
+
9
+ class BusDecoderListener(RDLListener):
10
+ def __init__(self, ds: DesignState) -> None:
11
+ self._array_stride_stack: deque[int] = deque() # Tracks nested array strides
12
+ self._ds = ds
13
+ self._depth = 0
14
+
15
+ def should_skip_node(self, node: AddressableNode) -> bool:
16
+ """Check if this node should be skipped (not decoded)."""
17
+ # Check if current depth exceeds max depth
18
+ if self._depth > self._ds.max_decode_depth:
19
+ return True
20
+
21
+ # Check if this node only contains external addressable children
22
+ if node != self._ds.top_node and not isinstance(node, RegNode):
23
+ if any(isinstance(c, AddressableNode) for c in node.children()) and all(
24
+ c.external for c in node.children() if isinstance(c, AddressableNode)
25
+ ):
26
+ return True
27
+
28
+ return False
29
+
30
+ def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None:
31
+ if node.array_dimensions:
32
+ assert node.array_stride is not None, "Array stride should be defined for arrayed components"
33
+ current_stride = node.array_stride
34
+ self._array_stride_stack.append(current_stride)
35
+
36
+ # Work backwards from rightmost to leftmost dimension (fastest to slowest changing)
37
+ # Each dimension's stride is the product of its size and the previous dimension's stride
38
+ for dim in node.array_dimensions[-1:0:-1]:
39
+ current_stride = current_stride * dim
40
+ self._array_stride_stack.appendleft(current_stride)
41
+
42
+ self._depth += 1
43
+
44
+ # Check if we should skip this node's descendants
45
+ if self.should_skip_node(node):
46
+ return WalkerAction.SkipDescendants
47
+
48
+ return WalkerAction.Continue
49
+
50
+ def exit_AddressableComponent(self, node: AddressableNode) -> None:
51
+ if node.array_dimensions:
52
+ for _ in node.array_dimensions:
53
+ self._array_stride_stack.pop()
54
+
55
+ self._depth -= 1
56
+
57
+ def __str__(self) -> str:
58
+ return ""
@@ -0,0 +1,79 @@
1
+ //==========================================================
2
+ // Module: {{ds.module_name}}
3
+ // Description: CPU Interface Bus Decoder
4
+ // Author: PeakRDL-BusDecoder
5
+ // License: LGPL-3.0
6
+ // Date: {{current_date}}
7
+ // Version: {{version}}
8
+ // Links:
9
+ // - https://github.com/arnavsacheti/PeakRDL-BusDecoder
10
+ //==========================================================
11
+
12
+
13
+ module {{ds.module_name}}
14
+ {%- if cpuif.parameters %} #(
15
+ {{cpuif.parameters|join(",\n")|indent(4)}}
16
+ ) {%- endif %} (
17
+ {{cpuif.port_declaration|indent(4)}}
18
+ );
19
+ //--------------------------------------------------------------------------
20
+ // CPU Bus interface logic
21
+ //--------------------------------------------------------------------------
22
+ logic cpuif_req;
23
+ logic cpuif_wr_en;
24
+ logic cpuif_rd_en;
25
+ logic [{{cpuif.addr_width-1}}:0] cpuif_wr_addr;
26
+ logic [{{cpuif.addr_width-1}}:0] cpuif_rd_addr;
27
+
28
+ logic cpuif_wr_ack;
29
+ logic cpuif_wr_err;
30
+ logic [{{cpuif.data_width-1}}:0] cpuif_wr_data;
31
+ logic [{{cpuif.data_width//8-1}}:0] cpuif_wr_byte_en;
32
+
33
+ logic cpuif_rd_ack;
34
+ logic cpuif_rd_err;
35
+ logic [{{cpuif.data_width-1}}:0] cpuif_rd_data;
36
+
37
+ //--------------------------------------------------------------------------
38
+ // Child instance signals
39
+ //--------------------------------------------------------------------------
40
+ {{cpuif_select|walk|indent(4)}}
41
+ cpuif_sel_t cpuif_wr_sel;
42
+ cpuif_sel_t cpuif_rd_sel;
43
+
44
+ //--------------------------------------------------------------------------
45
+ // Slave <-> Internal CPUIF <-> Master
46
+ //--------------------------------------------------------------------------
47
+ {{cpuif.get_implementation()|indent(4)}}
48
+
49
+ //--------------------------------------------------------------------------
50
+ // Write Address Decoder
51
+ //--------------------------------------------------------------------------
52
+ always_comb begin
53
+ // Default all write select signals to 0
54
+ cpuif_wr_sel = '0;
55
+
56
+ if (cpuif_req && cpuif_wr_en) begin
57
+ // A write request is pending
58
+ {{cpuif_decode|walk(flavor=cpuif_decode_flavor.WRITE)|indent(12)}}
59
+ end else begin
60
+ // No write request, all select signals remain 0
61
+ end
62
+ end
63
+
64
+ //--------------------------------------------------------------------------
65
+ // Read Address Decoder
66
+ //--------------------------------------------------------------------------
67
+ always_comb begin
68
+ // Default all read select signals to 0
69
+ cpuif_rd_sel = '0;
70
+
71
+ if (cpuif_req && cpuif_rd_en) begin
72
+ // A read request is pending
73
+ {{cpuif_decode|walk(flavor=cpuif_decode_flavor.READ)|indent(12)}}
74
+ end else begin
75
+ // No read request, all select signals remain 0
76
+ end
77
+ end
78
+ endmodule
79
+ {# (eof newline anchor) #}
@@ -0,0 +1,21 @@
1
+ //==========================================================
2
+ // Package: {{ds.package_name}}
3
+ // Description: CPU Interface Bus Decoder Package
4
+ // Author: PeakRDL-BusDecoder
5
+ // License: LGPL-3.0
6
+ // Date: {{current_date}}
7
+ // Version: {{version}}
8
+ // Links:
9
+ // - https://github.com/arnavsacheti/PeakRDL-BusDecoder
10
+ //==========================================================
11
+
12
+
13
+ package {{ds.package_name}};
14
+ localparam {{ds.module_name.upper()}}_DATA_WIDTH = {{ds.cpuif_data_width}};
15
+ localparam {{ds.module_name.upper()}}_MIN_ADDR_WIDTH = {{ds.addr_width}};
16
+ localparam {{ds.module_name.upper()}}_SIZE = {{SVInt(ds.top_node.size)}};
17
+ {%- for child in cpuif.addressable_children %}
18
+ localparam {{ds.module_name.upper()}}_{{child.inst_name.upper()}}_ADDR_WIDTH = {{child.size|clog2}};
19
+ {%- endfor %}
20
+ endpackage
21
+ {# (eof newline anchor) #}
File without changes
@@ -0,0 +1,57 @@
1
+ from collections import deque
2
+
3
+ from systemrdl.node import AddressableNode
4
+ from systemrdl.walker import WalkerAction
5
+
6
+ from .body import Body, StructBody
7
+ from .design_state import DesignState
8
+ from .identifier_filter import kw_filter as kwf
9
+ from .listener import BusDecoderListener
10
+
11
+
12
+ class StructGenerator(BusDecoderListener):
13
+ def __init__(
14
+ self,
15
+ ds: DesignState,
16
+ ) -> None:
17
+ super().__init__(ds)
18
+
19
+ self._stack: deque[Body] = deque()
20
+ self._stack.append(StructBody("cpuif_sel_t", True, True))
21
+
22
+ def enter_AddressableComponent(self, node: AddressableNode) -> WalkerAction | None:
23
+ action = super().enter_AddressableComponent(node)
24
+
25
+ self._skip = False
26
+ if action == WalkerAction.SkipDescendants:
27
+ self._skip = True
28
+
29
+ if node.children():
30
+ # Push new body onto stack
31
+ body = StructBody(f"cpuif_sel_{node.inst_name}_t", True, True)
32
+ self._stack.append(body)
33
+
34
+ return action
35
+
36
+ def exit_AddressableComponent(self, node: AddressableNode) -> None:
37
+ type = "logic"
38
+
39
+ if node.children():
40
+ body = self._stack.pop()
41
+ if body and isinstance(body, StructBody) and not self._skip:
42
+ self._stack.appendleft(body)
43
+ type = body.name
44
+
45
+ name = kwf(node.inst_name)
46
+
47
+ if node.array_dimensions:
48
+ for dim in node.array_dimensions:
49
+ name = f"[{dim - 1}:0]{name}"
50
+
51
+ self._stack[-1] += f"{type} {name};"
52
+
53
+ super().exit_AddressableComponent(node)
54
+
55
+ def __str__(self) -> str:
56
+ self._stack[-1] += "logic cpuif_err;"
57
+ return "\n".join(map(str, self._stack))
@@ -0,0 +1,21 @@
1
+ class SVInt:
2
+ def __init__(self, value: int, width: int | None = None) -> None:
3
+ self.value = value
4
+ self.width = width
5
+
6
+ def __str__(self) -> str:
7
+ if self.width is not None:
8
+ # Explicit width
9
+ return f"{self.width}'h{self.value:x}"
10
+ elif self.value.bit_length() > 32:
11
+ # SV standard only enforces that unsized literals shall be at least 32-bits
12
+ # To support larger literals, they need to be sized explicitly
13
+ return f"{self.value.bit_length()}'h{self.value:x}"
14
+ else:
15
+ return f"'h{self.value:x}"
16
+
17
+ def __add__(self, other: "SVInt") -> "SVInt":
18
+ if self.width is not None and other.width is not None:
19
+ return SVInt(self.value + other.value, max(self.width, other.width))
20
+ else:
21
+ return SVInt(self.value + other.value, None)
@@ -0,0 +1,5 @@
1
+ from systemrdl.udp import UDPDefinition
2
+
3
+ ALL_UDPS: list[type[UDPDefinition]] = []
4
+
5
+ __all__ = ["ALL_UDPS"]
@@ -0,0 +1,80 @@
1
+ import re
2
+ from re import Match
3
+
4
+ from systemrdl.node import AddrmapNode, Node
5
+ from systemrdl.rdltypes.references import PropertyReference
6
+
7
+ from .identifier_filter import kw_filter as kwf
8
+
9
+
10
+ def get_indexed_path(
11
+ top_node: Node, target_node: Node, indexer: str = "i", skip_kw_filter: bool = False
12
+ ) -> str:
13
+ """
14
+ Get the relative path from top_node to target_node, replacing any unknown
15
+ array indexes with incrementing iterators (i0, i1, ...).
16
+ """
17
+ path = target_node.get_rel_path(top_node, empty_array_suffix="[!]")
18
+
19
+ # replace unknown indexes with incrementing iterators i0, i1, ...
20
+ class ReplaceUnknown:
21
+ def __init__(self) -> None:
22
+ self.i = 0
23
+
24
+ def __call__(self, match: Match[str]) -> str:
25
+ s = f"{indexer}{self.i}"
26
+ self.i += 1
27
+ return s
28
+
29
+ path = re.sub(r"!", ReplaceUnknown(), path)
30
+
31
+ # Sanitize any SV keywords
32
+ def kw_filter_repl(m: Match[str]) -> str:
33
+ return kwf(m.group(0))
34
+
35
+ if not skip_kw_filter:
36
+ path = re.sub(r"\w+", kw_filter_repl, path)
37
+
38
+ return path
39
+
40
+
41
+ def clog2(n: int) -> int:
42
+ return (n - 1).bit_length()
43
+
44
+
45
+ def is_pow2(x: int) -> bool:
46
+ return (x > 0) and ((x & (x - 1)) == 0)
47
+
48
+
49
+ def roundup_pow2(x: int) -> int:
50
+ return 1 << (x - 1).bit_length()
51
+
52
+
53
+ def ref_is_internal(top_node: AddrmapNode, ref: Node | PropertyReference) -> bool:
54
+ """
55
+ Determine whether the reference is internal to the top node.
56
+
57
+ For the sake of this exporter, root signals are treated as internal.
58
+ """
59
+ current_node: Node | None
60
+ if isinstance(ref, PropertyReference):
61
+ current_node = ref.node
62
+ else:
63
+ current_node = ref
64
+
65
+ # pyrefly: ignore[bad-assignment] - false positive due to circular type checking
66
+ while current_node is not None:
67
+ if current_node == top_node:
68
+ # reached top node without finding any external components
69
+ # is internal!
70
+ return True
71
+
72
+ if current_node.external:
73
+ # not internal!
74
+ return False
75
+
76
+ current_node = current_node.parent
77
+
78
+ # A root signal was referenced, which dodged the top addrmap
79
+ # This is considered internal for this exporter
80
+ return True