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.
- peakrdl_busdecoder/__init__.py +3 -0
- peakrdl_busdecoder/__peakrdl__.py +136 -0
- peakrdl_busdecoder/body/__init__.py +14 -0
- peakrdl_busdecoder/body/body.py +22 -0
- peakrdl_busdecoder/body/combinational_body.py +10 -0
- peakrdl_busdecoder/body/for_loop_body.py +16 -0
- peakrdl_busdecoder/body/if_body.py +91 -0
- peakrdl_busdecoder/body/struct_body.py +25 -0
- peakrdl_busdecoder/cpuif/__init__.py +3 -0
- peakrdl_busdecoder/cpuif/apb3/__init__.py +4 -0
- peakrdl_busdecoder/cpuif/apb3/apb3_cpuif.py +67 -0
- peakrdl_busdecoder/cpuif/apb3/apb3_cpuif_flat.py +68 -0
- peakrdl_busdecoder/cpuif/apb3/apb3_interface.py +56 -0
- peakrdl_busdecoder/cpuif/apb3/apb3_tmpl.sv +33 -0
- peakrdl_busdecoder/cpuif/apb4/__init__.py +4 -0
- peakrdl_busdecoder/cpuif/apb4/apb4_cpuif.py +70 -0
- peakrdl_busdecoder/cpuif/apb4/apb4_cpuif_flat.py +70 -0
- peakrdl_busdecoder/cpuif/apb4/apb4_interface.py +60 -0
- peakrdl_busdecoder/cpuif/apb4/apb4_tmpl.sv +36 -0
- peakrdl_busdecoder/cpuif/axi4lite/__init__.py +4 -0
- peakrdl_busdecoder/cpuif/axi4lite/axi4_lite_cpuif.py +84 -0
- peakrdl_busdecoder/cpuif/axi4lite/axi4_lite_cpuif_flat.py +86 -0
- peakrdl_busdecoder/cpuif/axi4lite/axi4lite_interface.py +84 -0
- peakrdl_busdecoder/cpuif/axi4lite/axi4lite_tmpl.sv +60 -0
- peakrdl_busdecoder/cpuif/base_cpuif.py +118 -0
- peakrdl_busdecoder/cpuif/fanin_gen.py +64 -0
- peakrdl_busdecoder/cpuif/fanout_gen.py +50 -0
- peakrdl_busdecoder/cpuif/interface.py +190 -0
- peakrdl_busdecoder/decode_logic_gen.py +152 -0
- peakrdl_busdecoder/design_scanner.py +46 -0
- peakrdl_busdecoder/design_state.py +74 -0
- peakrdl_busdecoder/exporter.py +142 -0
- peakrdl_busdecoder/identifier_filter.py +263 -0
- peakrdl_busdecoder/listener.py +58 -0
- peakrdl_busdecoder/module_tmpl.sv +79 -0
- peakrdl_busdecoder/package_tmpl.sv +21 -0
- peakrdl_busdecoder/py.typed +0 -0
- peakrdl_busdecoder/struct_gen.py +57 -0
- peakrdl_busdecoder/sv_int.py +21 -0
- peakrdl_busdecoder/udps/__init__.py +5 -0
- peakrdl_busdecoder/utils.py +80 -0
- peakrdl_busdecoder/validate_design.py +185 -0
- peakrdl_busdecoder-0.2.0.dist-info/METADATA +40 -0
- peakrdl_busdecoder-0.2.0.dist-info/RECORD +48 -0
- peakrdl_busdecoder-0.2.0.dist-info/WHEEL +5 -0
- peakrdl_busdecoder-0.2.0.dist-info/entry_points.txt +2 -0
- peakrdl_busdecoder-0.2.0.dist-info/licenses/LICENSE +165 -0
- 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,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
|