switchboard-hw 0.3.0__cp314-cp314-macosx_11_0_arm64.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.
- _switchboard.cpython-314-darwin.so +0 -0
- switchboard/__init__.py +24 -0
- switchboard/ams.py +668 -0
- switchboard/apb.py +278 -0
- switchboard/autowrap.py +1000 -0
- switchboard/axi.py +571 -0
- switchboard/axil.py +348 -0
- switchboard/bitvector.py +112 -0
- switchboard/cmdline.py +142 -0
- switchboard/cpp/Makefile +13 -0
- switchboard/cpp/bitutil.h +39 -0
- switchboard/cpp/pagemap.h +91 -0
- switchboard/cpp/pciedev.h +86 -0
- switchboard/cpp/router.cc +89 -0
- switchboard/cpp/spsc_queue.h +267 -0
- switchboard/cpp/switchboard.hpp +257 -0
- switchboard/cpp/switchboard_pcie.hpp +234 -0
- switchboard/cpp/switchboard_tlm.hpp +98 -0
- switchboard/cpp/umilib.h +144 -0
- switchboard/cpp/umilib.hpp +113 -0
- switchboard/cpp/umisb.hpp +364 -0
- switchboard/cpp/xyce.hpp +90 -0
- switchboard/deps/__init__.py +0 -0
- switchboard/deps/verilog_axi.py +23 -0
- switchboard/dpi/__init__.py +0 -0
- switchboard/dpi/switchboard_dpi.cc +119 -0
- switchboard/dpi/switchboard_dpi.py +13 -0
- switchboard/dpi/xyce_dpi.cc +43 -0
- switchboard/gpio.py +108 -0
- switchboard/icarus.py +85 -0
- switchboard/loopback.py +157 -0
- switchboard/network.py +714 -0
- switchboard/pytest_plugin.py +11 -0
- switchboard/sbdesign.py +55 -0
- switchboard/sbdut.py +744 -0
- switchboard/sbtcp.py +345 -0
- switchboard/sc/__init__.py +0 -0
- switchboard/sc/morty/__init__.py +0 -0
- switchboard/sc/morty/uniquify.py +67 -0
- switchboard/sc/sed/__init__.py +0 -0
- switchboard/sc/sed/sed_remove.py +47 -0
- switchboard/sc/standalone_netlist_flow.py +25 -0
- switchboard/switchboard.py +53 -0
- switchboard/test_util.py +46 -0
- switchboard/uart_xactor.py +66 -0
- switchboard/umi.py +793 -0
- switchboard/util.py +131 -0
- switchboard/verilator/__init__.py +0 -0
- switchboard/verilator/config.vlt +13 -0
- switchboard/verilator/testbench.cc +143 -0
- switchboard/verilator/verilator.py +13 -0
- switchboard/verilator_run.py +31 -0
- switchboard/verilog/__init__.py +0 -0
- switchboard/verilog/common/__init__.py +0 -0
- switchboard/verilog/common/common.py +26 -0
- switchboard/verilog/common/switchboard.vh +429 -0
- switchboard/verilog/common/uart_xactor.sv +247 -0
- switchboard/verilog/common/umi_gpio.v +236 -0
- switchboard/verilog/fpga/__init__.py +0 -0
- switchboard/verilog/fpga/axi_reader.sv +82 -0
- switchboard/verilog/fpga/axi_writer.sv +111 -0
- switchboard/verilog/fpga/config_registers.sv +249 -0
- switchboard/verilog/fpga/fpga.py +21 -0
- switchboard/verilog/fpga/include/sb_queue_regmap.vh +21 -0
- switchboard/verilog/fpga/include/spsc_queue.vh +7 -0
- switchboard/verilog/fpga/memory_fault.sv +40 -0
- switchboard/verilog/fpga/sb_fpga_queues.sv +416 -0
- switchboard/verilog/fpga/sb_rx_fpga.sv +303 -0
- switchboard/verilog/fpga/sb_tx_fpga.sv +294 -0
- switchboard/verilog/fpga/umi_fpga_queues.sv +146 -0
- switchboard/verilog/sim/__init__.py +0 -0
- switchboard/verilog/sim/auto_stop_sim.sv +25 -0
- switchboard/verilog/sim/perf_meas_sim.sv +97 -0
- switchboard/verilog/sim/queue_to_sb_sim.sv +176 -0
- switchboard/verilog/sim/queue_to_umi_sim.sv +66 -0
- switchboard/verilog/sim/sb_apb_m.sv +146 -0
- switchboard/verilog/sim/sb_axi_m.sv +199 -0
- switchboard/verilog/sim/sb_axil_m.sv +180 -0
- switchboard/verilog/sim/sb_axil_s.sv +180 -0
- switchboard/verilog/sim/sb_clk_gen.sv +89 -0
- switchboard/verilog/sim/sb_jtag_rbb_sim.sv +148 -0
- switchboard/verilog/sim/sb_rx_sim.sv +55 -0
- switchboard/verilog/sim/sb_to_queue_sim.sv +196 -0
- switchboard/verilog/sim/sb_tx_sim.sv +55 -0
- switchboard/verilog/sim/switchboard_sim.py +49 -0
- switchboard/verilog/sim/umi_rx_sim.sv +61 -0
- switchboard/verilog/sim/umi_to_queue_sim.sv +66 -0
- switchboard/verilog/sim/umi_tx_sim.sv +61 -0
- switchboard/verilog/sim/xyce_intf.sv +67 -0
- switchboard/vpi/switchboard_vpi.cc +431 -0
- switchboard/vpi/xyce_vpi.cc +200 -0
- switchboard/warn.py +14 -0
- switchboard/xyce.py +27 -0
- switchboard_hw-0.3.0.dist-info/METADATA +303 -0
- switchboard_hw-0.3.0.dist-info/RECORD +99 -0
- switchboard_hw-0.3.0.dist-info/WHEEL +6 -0
- switchboard_hw-0.3.0.dist-info/entry_points.txt +6 -0
- switchboard_hw-0.3.0.dist-info/licenses/LICENSE +190 -0
- switchboard_hw-0.3.0.dist-info/top_level.txt +2 -0
switchboard/autowrap.py
ADDED
|
@@ -0,0 +1,1000 @@
|
|
|
1
|
+
# Tool for automatically wrapping a DUT with switchboard interfaces
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2024 Zero ASIC Corporation
|
|
4
|
+
# This code is licensed under Apache License 2.0 (see LICENSE for details)
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from copy import deepcopy
|
|
8
|
+
|
|
9
|
+
from .umi import UmiTxRx
|
|
10
|
+
from .axi import AxiTxRx
|
|
11
|
+
from .axil import AxiLiteTxRx
|
|
12
|
+
from switchboard.apb import ApbTxRx
|
|
13
|
+
from .bitvector import slice_to_msb_lsb
|
|
14
|
+
|
|
15
|
+
from _switchboard import PySbTx, PySbRx
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class WireExpr:
|
|
19
|
+
def __init__(self, width):
|
|
20
|
+
self.width = width
|
|
21
|
+
self.bindings = []
|
|
22
|
+
|
|
23
|
+
def bind(self, slice, wire):
|
|
24
|
+
# extract msb, lsb
|
|
25
|
+
msb, lsb = slice_to_msb_lsb(start=slice.start, stop=slice.stop, step=slice.step)
|
|
26
|
+
|
|
27
|
+
# make sure that the slice fits in the width
|
|
28
|
+
assert 0 <= lsb <= self.width - 1
|
|
29
|
+
assert 0 <= msb <= self.width - 1
|
|
30
|
+
|
|
31
|
+
if len(self.bindings) == 0:
|
|
32
|
+
self.bindings.append(((msb, lsb), wire))
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
for idx in range(len(self.bindings) - 1, -1, -1):
|
|
36
|
+
(msb_i, lsb_i), _ = self.bindings[idx]
|
|
37
|
+
if lsb < lsb_i:
|
|
38
|
+
assert msb < lsb_i, \
|
|
39
|
+
f'bit assignments {msb_i}:{lsb_i} and {msb}:{lsb} overlap'
|
|
40
|
+
self.bindings.insert(idx + 1, ((msb, lsb), wire))
|
|
41
|
+
break
|
|
42
|
+
else:
|
|
43
|
+
(msb_i, lsb_i), _ = self.bindings[0]
|
|
44
|
+
assert lsb > msb_i, \
|
|
45
|
+
f'bit assignments {msb_i}:{lsb_i} and {msb}:{lsb} overlap'
|
|
46
|
+
self.bindings.insert(0, ((msb, lsb), wire))
|
|
47
|
+
|
|
48
|
+
def padded(self):
|
|
49
|
+
retval = []
|
|
50
|
+
|
|
51
|
+
for idx, ((msb, lsb), wire) in enumerate(self.bindings):
|
|
52
|
+
if idx == 0:
|
|
53
|
+
if msb != self.width - 1:
|
|
54
|
+
msb_pad = (self.width - 1) - msb
|
|
55
|
+
retval.append(f"{msb_pad}'b0")
|
|
56
|
+
|
|
57
|
+
retval.append(wire)
|
|
58
|
+
|
|
59
|
+
if idx < len(self.bindings) - 1:
|
|
60
|
+
lsb_pad = (lsb - 1) - self.bindings[idx + 1][0][0]
|
|
61
|
+
else:
|
|
62
|
+
lsb_pad = lsb
|
|
63
|
+
|
|
64
|
+
if lsb_pad > 0:
|
|
65
|
+
retval.append(f"{lsb_pad}'b0")
|
|
66
|
+
|
|
67
|
+
return retval
|
|
68
|
+
|
|
69
|
+
def __str__(self):
|
|
70
|
+
padded = self.padded()
|
|
71
|
+
|
|
72
|
+
if len(padded) == 1:
|
|
73
|
+
return padded[0]
|
|
74
|
+
else:
|
|
75
|
+
return '{' + ', '.join(padded) + '}'
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def normalize_interface(name, value):
|
|
79
|
+
# copy before modifying
|
|
80
|
+
value = deepcopy(value)
|
|
81
|
+
|
|
82
|
+
assert isinstance(value, dict)
|
|
83
|
+
|
|
84
|
+
if 'type' not in value:
|
|
85
|
+
value['type'] = 'sb'
|
|
86
|
+
|
|
87
|
+
if 'wire' not in value:
|
|
88
|
+
value['wire'] = name
|
|
89
|
+
|
|
90
|
+
assert 'type' in value
|
|
91
|
+
value['type'] = normalize_intf_type(value['type'])
|
|
92
|
+
type = value['type']
|
|
93
|
+
|
|
94
|
+
if 'external' not in value:
|
|
95
|
+
if type == 'plusarg':
|
|
96
|
+
value['external'] = False
|
|
97
|
+
else:
|
|
98
|
+
value['external'] = True
|
|
99
|
+
|
|
100
|
+
if (type == 'plusarg') and ('direction' not in value):
|
|
101
|
+
value['direction'] = 'input'
|
|
102
|
+
|
|
103
|
+
assert 'direction' in value
|
|
104
|
+
value['direction'] = normalize_direction(type=type, direction=value['direction'])
|
|
105
|
+
|
|
106
|
+
if type == 'sb':
|
|
107
|
+
if 'dw' not in value:
|
|
108
|
+
value['dw'] = 256
|
|
109
|
+
if 'uri' not in value:
|
|
110
|
+
value['uri'] = f'{name}.q'
|
|
111
|
+
elif type == 'umi':
|
|
112
|
+
if 'dw' not in value:
|
|
113
|
+
value['dw'] = 256
|
|
114
|
+
if 'aw' not in value:
|
|
115
|
+
value['aw'] = 64
|
|
116
|
+
if 'cw' not in value:
|
|
117
|
+
value['cw'] = 32
|
|
118
|
+
if 'txrx' not in value:
|
|
119
|
+
value['txrx'] = None
|
|
120
|
+
if 'uri' not in value:
|
|
121
|
+
value['uri'] = f'{name}.q'
|
|
122
|
+
elif type in ['axi', 'axil', 'apb']:
|
|
123
|
+
if 'dw' not in value:
|
|
124
|
+
value['dw'] = 32
|
|
125
|
+
if 'aw' not in value:
|
|
126
|
+
value['aw'] = 16
|
|
127
|
+
if 'uri' not in value:
|
|
128
|
+
value['uri'] = name
|
|
129
|
+
|
|
130
|
+
if type == 'axi':
|
|
131
|
+
# settings that only apply to AXI, not AXI-Lite
|
|
132
|
+
|
|
133
|
+
if 'idw' not in value:
|
|
134
|
+
value['idw'] = 8
|
|
135
|
+
elif type == 'gpio':
|
|
136
|
+
if 'width' not in value:
|
|
137
|
+
value['width'] = 1
|
|
138
|
+
elif type == 'plusarg':
|
|
139
|
+
if 'width' not in value:
|
|
140
|
+
value['width'] = 1
|
|
141
|
+
if 'default' not in value:
|
|
142
|
+
value['default'] = 0
|
|
143
|
+
if 'plusarg' not in value:
|
|
144
|
+
value['plusarg'] = name
|
|
145
|
+
else:
|
|
146
|
+
raise ValueError(f'Unsupported interface type: "{type}"')
|
|
147
|
+
|
|
148
|
+
return name, value
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def normalize_interfaces(interfaces):
|
|
152
|
+
if interfaces is None:
|
|
153
|
+
interfaces = {}
|
|
154
|
+
|
|
155
|
+
retval = {}
|
|
156
|
+
|
|
157
|
+
for name, value in interfaces.items():
|
|
158
|
+
name, value = normalize_interface(name, value)
|
|
159
|
+
retval[name] = value
|
|
160
|
+
|
|
161
|
+
return retval
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def normalize_clock(clock):
|
|
165
|
+
# copy before modifying
|
|
166
|
+
clock = deepcopy(clock)
|
|
167
|
+
|
|
168
|
+
if isinstance(clock, str):
|
|
169
|
+
clock = dict(name=clock)
|
|
170
|
+
|
|
171
|
+
assert isinstance(clock, dict)
|
|
172
|
+
|
|
173
|
+
return clock
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def normalize_clocks(clocks):
|
|
177
|
+
if clocks is None:
|
|
178
|
+
clocks = ['clk']
|
|
179
|
+
|
|
180
|
+
if isinstance(clocks, str):
|
|
181
|
+
clocks = [clocks]
|
|
182
|
+
|
|
183
|
+
retval = []
|
|
184
|
+
|
|
185
|
+
for clock in clocks:
|
|
186
|
+
clock = normalize_clock(clock)
|
|
187
|
+
retval.append(clock)
|
|
188
|
+
|
|
189
|
+
return retval
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def normalize_reset(reset):
|
|
193
|
+
# copy before modifying
|
|
194
|
+
reset = deepcopy(reset)
|
|
195
|
+
|
|
196
|
+
if isinstance(reset, str):
|
|
197
|
+
reset = {'name': reset}
|
|
198
|
+
|
|
199
|
+
assert 'name' in reset
|
|
200
|
+
|
|
201
|
+
name = reset['name']
|
|
202
|
+
|
|
203
|
+
if 'polarity' not in reset:
|
|
204
|
+
if (('nreset' in name) or ('resetn' in name)
|
|
205
|
+
or ('nrst' in name) or ('rstn' in name)):
|
|
206
|
+
reset['polarity'] = 'negative'
|
|
207
|
+
else:
|
|
208
|
+
reset['polarity'] = 'positive'
|
|
209
|
+
else:
|
|
210
|
+
reset['polarity'] = normalize_polarity(reset['polarity'])
|
|
211
|
+
|
|
212
|
+
if 'delay' not in reset:
|
|
213
|
+
reset['delay'] = 0
|
|
214
|
+
|
|
215
|
+
return reset
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def normalize_resets(resets):
|
|
219
|
+
if resets is None:
|
|
220
|
+
resets = []
|
|
221
|
+
|
|
222
|
+
if isinstance(resets, str):
|
|
223
|
+
resets = [resets]
|
|
224
|
+
|
|
225
|
+
retval = []
|
|
226
|
+
|
|
227
|
+
for reset in resets:
|
|
228
|
+
reset = normalize_reset(reset)
|
|
229
|
+
retval.append(reset)
|
|
230
|
+
|
|
231
|
+
return retval
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def normalize_tieoff(key, value):
|
|
235
|
+
if isinstance(value, dict):
|
|
236
|
+
value = deepcopy(value)
|
|
237
|
+
else:
|
|
238
|
+
value = {'value': value}
|
|
239
|
+
|
|
240
|
+
if 'width' not in value:
|
|
241
|
+
value['width'] = 1
|
|
242
|
+
|
|
243
|
+
if 'wire' not in value:
|
|
244
|
+
value['wire'] = None
|
|
245
|
+
|
|
246
|
+
return key, value
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def normalize_tieoffs(tieoffs):
|
|
250
|
+
if tieoffs is None:
|
|
251
|
+
tieoffs = {}
|
|
252
|
+
|
|
253
|
+
retval = {}
|
|
254
|
+
|
|
255
|
+
for key, value in tieoffs.items():
|
|
256
|
+
key, value = normalize_tieoff(key, value)
|
|
257
|
+
retval[key] = value
|
|
258
|
+
|
|
259
|
+
return retval
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def normalize_parameter(key, value):
|
|
263
|
+
# placeholder for doing more interesting things in the future
|
|
264
|
+
return key, value
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def normalize_parameters(parameters):
|
|
268
|
+
if parameters is None:
|
|
269
|
+
parameters = {}
|
|
270
|
+
|
|
271
|
+
retval = {}
|
|
272
|
+
|
|
273
|
+
for key, value in parameters.items():
|
|
274
|
+
key, value = normalize_parameter(key, value)
|
|
275
|
+
retval[key] = value
|
|
276
|
+
|
|
277
|
+
return retval
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def autowrap(
|
|
281
|
+
instances,
|
|
282
|
+
toplevel='testbench',
|
|
283
|
+
parameters=None,
|
|
284
|
+
interfaces=None,
|
|
285
|
+
clocks=None,
|
|
286
|
+
resets=None,
|
|
287
|
+
tieoffs=None,
|
|
288
|
+
filename=None,
|
|
289
|
+
nl='\n',
|
|
290
|
+
tab=' '
|
|
291
|
+
):
|
|
292
|
+
# normalize inputs
|
|
293
|
+
|
|
294
|
+
parameters = {k: normalize_parameters(v) for k, v in parameters.items()}
|
|
295
|
+
interfaces = {k: normalize_interfaces(v) for k, v in interfaces.items()}
|
|
296
|
+
clocks = {k: normalize_clocks(v) for k, v in clocks.items()}
|
|
297
|
+
resets = {k: normalize_resets(v) for k, v in resets.items()}
|
|
298
|
+
tieoffs = {k: normalize_tieoffs(v) for k, v in tieoffs.items()}
|
|
299
|
+
|
|
300
|
+
# build up output lines
|
|
301
|
+
|
|
302
|
+
lines = []
|
|
303
|
+
|
|
304
|
+
lines += [
|
|
305
|
+
'`default_nettype none',
|
|
306
|
+
'',
|
|
307
|
+
'`include "switchboard.vh"',
|
|
308
|
+
'',
|
|
309
|
+
f'module {toplevel} (',
|
|
310
|
+
tab + '`ifdef VERILATOR',
|
|
311
|
+
(2 * tab) + 'input clk',
|
|
312
|
+
tab + '`endif',
|
|
313
|
+
');',
|
|
314
|
+
tab + '`ifndef VERILATOR',
|
|
315
|
+
(2 * tab) + '`SB_CREATE_CLOCK(clk)',
|
|
316
|
+
tab + '`endif',
|
|
317
|
+
''
|
|
318
|
+
]
|
|
319
|
+
|
|
320
|
+
# wire declarations
|
|
321
|
+
|
|
322
|
+
wires = {}
|
|
323
|
+
|
|
324
|
+
lines += ['']
|
|
325
|
+
|
|
326
|
+
# declare all GPIO output wires (makes things easier when an output is
|
|
327
|
+
# sent to multiple places or slices of it are used)
|
|
328
|
+
|
|
329
|
+
wires['gpio'] = set()
|
|
330
|
+
|
|
331
|
+
for instance in instances:
|
|
332
|
+
for name, value in interfaces[instance].items():
|
|
333
|
+
type = value['type']
|
|
334
|
+
direction = value['direction']
|
|
335
|
+
|
|
336
|
+
if not ((type == 'gpio') and (direction == 'output')):
|
|
337
|
+
continue
|
|
338
|
+
|
|
339
|
+
wire = value['wire']
|
|
340
|
+
|
|
341
|
+
if wire is None:
|
|
342
|
+
# means that the output is unused
|
|
343
|
+
continue
|
|
344
|
+
|
|
345
|
+
assert wire not in wires['gpio']
|
|
346
|
+
|
|
347
|
+
width = value['width']
|
|
348
|
+
|
|
349
|
+
lines += [tab + f'wire [{width - 1}:0] {wire};']
|
|
350
|
+
|
|
351
|
+
wires['gpio'].add(wire)
|
|
352
|
+
|
|
353
|
+
lines += ['']
|
|
354
|
+
|
|
355
|
+
for instance in instances:
|
|
356
|
+
# declare wires for tieoffs
|
|
357
|
+
|
|
358
|
+
for key, value in tieoffs[instance].items():
|
|
359
|
+
if value['value'] is None:
|
|
360
|
+
continue
|
|
361
|
+
|
|
362
|
+
if value['wire'] is None:
|
|
363
|
+
value['wire'] = f'{instance}_tieoff_{key}'
|
|
364
|
+
|
|
365
|
+
width = value['width']
|
|
366
|
+
wire = value["wire"]
|
|
367
|
+
|
|
368
|
+
lines += [tab + f'wire [{width - 1}:0] {wire};']
|
|
369
|
+
|
|
370
|
+
lines += [tab + f'assign {wire} = {value["value"]};']
|
|
371
|
+
|
|
372
|
+
lines += ['']
|
|
373
|
+
|
|
374
|
+
# declare wires for interfaces
|
|
375
|
+
|
|
376
|
+
for name, value in interfaces[instance].items():
|
|
377
|
+
type = value['type']
|
|
378
|
+
|
|
379
|
+
if type not in wires:
|
|
380
|
+
wires[type] = set()
|
|
381
|
+
|
|
382
|
+
wire = value['wire']
|
|
383
|
+
|
|
384
|
+
if (type != 'gpio') and (wire not in wires[type]):
|
|
385
|
+
decl_wire = True
|
|
386
|
+
wires[type].add(wire)
|
|
387
|
+
else:
|
|
388
|
+
decl_wire = False
|
|
389
|
+
|
|
390
|
+
direction = value['direction']
|
|
391
|
+
|
|
392
|
+
external = value['external']
|
|
393
|
+
|
|
394
|
+
if type == 'sb':
|
|
395
|
+
dw = value['dw']
|
|
396
|
+
|
|
397
|
+
if decl_wire:
|
|
398
|
+
lines += [tab + f'`SB_WIRES({wire}, {dw});']
|
|
399
|
+
|
|
400
|
+
if external:
|
|
401
|
+
if direction_is_input(direction):
|
|
402
|
+
lines += [tab + f'`QUEUE_TO_SB_SIM({wire}, {dw}, "");']
|
|
403
|
+
elif direction_is_output(direction):
|
|
404
|
+
lines += [tab + f'`SB_TO_QUEUE_SIM({wire}, {dw}, "");']
|
|
405
|
+
else:
|
|
406
|
+
raise Exception(f'Unsupported SB direction: {direction}')
|
|
407
|
+
elif type == 'umi':
|
|
408
|
+
dw = value['dw']
|
|
409
|
+
cw = value['cw']
|
|
410
|
+
aw = value['aw']
|
|
411
|
+
|
|
412
|
+
if decl_wire and (wire is not None):
|
|
413
|
+
lines += [tab + f'`SB_UMI_WIRES({wire}, {dw}, {cw}, {aw});']
|
|
414
|
+
|
|
415
|
+
if external:
|
|
416
|
+
if direction_is_input(direction):
|
|
417
|
+
lines += [tab + f'`QUEUE_TO_UMI_SIM({wire}, {dw}, {cw}, {aw}, "");']
|
|
418
|
+
elif direction_is_output(direction):
|
|
419
|
+
lines += [tab + f'`UMI_TO_QUEUE_SIM({wire}, {dw}, {cw}, {aw}, "");']
|
|
420
|
+
else:
|
|
421
|
+
raise Exception(f'Unsupported UMI direction: {direction}')
|
|
422
|
+
elif type == 'axi':
|
|
423
|
+
dw = value['dw']
|
|
424
|
+
aw = value['aw']
|
|
425
|
+
idw = value['idw']
|
|
426
|
+
|
|
427
|
+
if decl_wire:
|
|
428
|
+
lines += [tab + f'`SB_AXI_WIRES({wire}, {dw}, {aw}, {idw});']
|
|
429
|
+
|
|
430
|
+
if external:
|
|
431
|
+
if direction_is_subordinate(direction):
|
|
432
|
+
lines += [tab + f'`SB_AXI_M({wire}, {dw}, {aw}, {idw}, "");']
|
|
433
|
+
elif direction_is_manager(direction):
|
|
434
|
+
lines += [tab + f'`SB_AXI_S({wire}, {dw}, {aw}, "");']
|
|
435
|
+
else:
|
|
436
|
+
raise Exception(f'Unsupported AXI direction: {direction}')
|
|
437
|
+
elif type == 'axil':
|
|
438
|
+
dw = value['dw']
|
|
439
|
+
aw = value['aw']
|
|
440
|
+
|
|
441
|
+
if decl_wire:
|
|
442
|
+
lines += [tab + f'`SB_AXIL_WIRES({wire}, {dw}, {aw});']
|
|
443
|
+
|
|
444
|
+
if external:
|
|
445
|
+
if direction_is_subordinate(direction):
|
|
446
|
+
lines += [tab + f'`SB_AXIL_M({wire}, {dw}, {aw}, "");']
|
|
447
|
+
elif direction_is_manager(direction):
|
|
448
|
+
lines += [tab + f'`SB_AXIL_S({wire}, {dw}, {aw}, "");']
|
|
449
|
+
else:
|
|
450
|
+
raise Exception(f'Unsupported AXI-Lite direction: {direction}')
|
|
451
|
+
elif type == 'gpio':
|
|
452
|
+
if direction == 'input':
|
|
453
|
+
width = value['width']
|
|
454
|
+
new_wire = f'{instance}_input_{name}'
|
|
455
|
+
lines += [
|
|
456
|
+
tab + f'wire [{width - 1}:0] {new_wire};',
|
|
457
|
+
tab + f'assign {new_wire} = {wire};'
|
|
458
|
+
]
|
|
459
|
+
value['wire'] = new_wire
|
|
460
|
+
else:
|
|
461
|
+
pass
|
|
462
|
+
elif type == 'plusarg':
|
|
463
|
+
width = value['width']
|
|
464
|
+
|
|
465
|
+
plusarg = value['plusarg']
|
|
466
|
+
assert plusarg is not None
|
|
467
|
+
|
|
468
|
+
plusarg_wire = f'{wire}_plusarg'
|
|
469
|
+
plusarg_width = 32 # TODO use long or another format?
|
|
470
|
+
|
|
471
|
+
lines += [
|
|
472
|
+
tab + f'reg [{plusarg_width - 1}:0] {plusarg_wire} = {value["default"]};',
|
|
473
|
+
tab + 'initial begin',
|
|
474
|
+
2 * tab + f"void'($value$plusargs(\"{plusarg}=%d\", {plusarg_wire}));",
|
|
475
|
+
tab + 'end'
|
|
476
|
+
]
|
|
477
|
+
|
|
478
|
+
lines += [tab + f'wire [{width - 1}:0] {wire};']
|
|
479
|
+
|
|
480
|
+
if width <= plusarg_width:
|
|
481
|
+
lines += [tab + f'assign {wire} = {plusarg_wire}[{width - 1}:0];']
|
|
482
|
+
else:
|
|
483
|
+
lines += [tab + f'assign {wire}[{plusarg_width - 1}:0] = {plusarg_wire};']
|
|
484
|
+
else:
|
|
485
|
+
raise Exception(f'Unsupported interface type: "{type}"')
|
|
486
|
+
|
|
487
|
+
lines += ['']
|
|
488
|
+
|
|
489
|
+
max_rst_dly = None
|
|
490
|
+
|
|
491
|
+
for inst_resets in resets.values():
|
|
492
|
+
if len(inst_resets) > 0:
|
|
493
|
+
# find the max reset delay for this instance
|
|
494
|
+
inst_max_rst_dly = max(reset['delay'] for reset in inst_resets)
|
|
495
|
+
|
|
496
|
+
# update the overall max reset delay
|
|
497
|
+
if (max_rst_dly is None) or (inst_max_rst_dly > max_rst_dly):
|
|
498
|
+
max_rst_dly = inst_max_rst_dly
|
|
499
|
+
|
|
500
|
+
if max_rst_dly is not None:
|
|
501
|
+
lines += [
|
|
502
|
+
tab + f"reg [{max_rst_dly}:0] rstvec = '1;"
|
|
503
|
+
'',
|
|
504
|
+
tab + 'always @(posedge clk) begin'
|
|
505
|
+
]
|
|
506
|
+
|
|
507
|
+
if max_rst_dly > 0:
|
|
508
|
+
lines += [(2 * tab) + f"rstvec <= {{rstvec[{max_rst_dly - 1}:0], 1'b0}};"]
|
|
509
|
+
else:
|
|
510
|
+
lines += [(2 * tab) + "rstvec <= 1'b0;"]
|
|
511
|
+
|
|
512
|
+
lines += [
|
|
513
|
+
tab + 'end',
|
|
514
|
+
''
|
|
515
|
+
]
|
|
516
|
+
|
|
517
|
+
for instance, module in instances.items():
|
|
518
|
+
# start of the instantiation
|
|
519
|
+
|
|
520
|
+
if len(parameters[instance]) > 0:
|
|
521
|
+
lines += [tab + f'{module} #(']
|
|
522
|
+
for n, (key, value) in enumerate(parameters[instance].items()):
|
|
523
|
+
line = (2 * tab) + f'.{key}({value})'
|
|
524
|
+
|
|
525
|
+
if n != len(parameters[instance]) - 1:
|
|
526
|
+
line += ','
|
|
527
|
+
|
|
528
|
+
lines += [line]
|
|
529
|
+
lines += [tab + f') {instance} (']
|
|
530
|
+
else:
|
|
531
|
+
lines += [tab + f'{module} {instance} (']
|
|
532
|
+
|
|
533
|
+
connections = []
|
|
534
|
+
|
|
535
|
+
# interfaces
|
|
536
|
+
|
|
537
|
+
for name, value in interfaces[instance].items():
|
|
538
|
+
type = value['type']
|
|
539
|
+
wire = value['wire']
|
|
540
|
+
|
|
541
|
+
if type_is_sb(type):
|
|
542
|
+
assert wire is not None
|
|
543
|
+
connections += [f'`SB_CONNECT({name}, {wire})']
|
|
544
|
+
elif type_is_umi(type):
|
|
545
|
+
if wire is None:
|
|
546
|
+
if value['direction'] == 'input':
|
|
547
|
+
connections += [f'`SB_TIEOFF_UMI_INPUT({name})']
|
|
548
|
+
elif value['direction'] == 'output':
|
|
549
|
+
connections += [f'`SB_TIEOFF_UMI_OUTPUT({name})']
|
|
550
|
+
else:
|
|
551
|
+
raise Exception(f'Unsupported UMI direction: {value["direction"]}')
|
|
552
|
+
else:
|
|
553
|
+
connections += [f'`SB_UMI_CONNECT({name}, {wire})']
|
|
554
|
+
elif type_is_axi(type):
|
|
555
|
+
assert wire is not None
|
|
556
|
+
connections += [f'`SB_AXI_CONNECT({name}, {wire})']
|
|
557
|
+
elif type_is_axil(type):
|
|
558
|
+
assert wire is not None
|
|
559
|
+
connections += [f'`SB_AXIL_CONNECT({name}, {wire})']
|
|
560
|
+
elif type_is_gpio(type) or type_is_plusarg(type):
|
|
561
|
+
if wire is None:
|
|
562
|
+
# unused output
|
|
563
|
+
connections += [f'.{name}()']
|
|
564
|
+
else:
|
|
565
|
+
connections += [f'.{name}({wire})']
|
|
566
|
+
|
|
567
|
+
# clocks
|
|
568
|
+
|
|
569
|
+
for clock in clocks[instance]:
|
|
570
|
+
connections += [f'.{clock["name"]}(clk)']
|
|
571
|
+
|
|
572
|
+
# resets
|
|
573
|
+
|
|
574
|
+
for reset in resets[instance]:
|
|
575
|
+
name = reset['name']
|
|
576
|
+
polarity = reset['polarity']
|
|
577
|
+
delay = reset['delay']
|
|
578
|
+
|
|
579
|
+
if polarity_is_positive(polarity):
|
|
580
|
+
value = f'rstvec[{delay}]'
|
|
581
|
+
elif polarity_is_negative(polarity):
|
|
582
|
+
value = f'~rstvec[{delay}]'
|
|
583
|
+
else:
|
|
584
|
+
raise ValueError(f'Unsupported reset polarity: "{polarity}"')
|
|
585
|
+
|
|
586
|
+
connections += [f'.{name}({value})']
|
|
587
|
+
|
|
588
|
+
# tieoffs
|
|
589
|
+
|
|
590
|
+
for key, value in tieoffs[instance].items():
|
|
591
|
+
wire = value.get('wire')
|
|
592
|
+
|
|
593
|
+
if wire is None:
|
|
594
|
+
wire = ''
|
|
595
|
+
|
|
596
|
+
connections += [f'.{key}({wire})']
|
|
597
|
+
|
|
598
|
+
for n, connection in enumerate(connections):
|
|
599
|
+
if n != len(connections) - 1:
|
|
600
|
+
connection += ','
|
|
601
|
+
lines += [(2 * tab) + connection]
|
|
602
|
+
|
|
603
|
+
lines += [tab + ');']
|
|
604
|
+
lines += ['']
|
|
605
|
+
|
|
606
|
+
# initialize queue connections for this instance
|
|
607
|
+
|
|
608
|
+
lines += [
|
|
609
|
+
tab + 'string uri_sb_value;',
|
|
610
|
+
'',
|
|
611
|
+
tab + 'initial begin',
|
|
612
|
+
(2 * tab) + '/* verilator lint_off IGNOREDRETURN */'
|
|
613
|
+
]
|
|
614
|
+
|
|
615
|
+
for inst_interfaces in interfaces.values():
|
|
616
|
+
for value in inst_interfaces.values():
|
|
617
|
+
external = value['external']
|
|
618
|
+
|
|
619
|
+
if not external:
|
|
620
|
+
continue
|
|
621
|
+
|
|
622
|
+
wire = value['wire']
|
|
623
|
+
|
|
624
|
+
lines += [
|
|
625
|
+
(2 * tab) + f'if($value$plusargs("{wire}=%s", uri_sb_value)) begin',
|
|
626
|
+
(3 * tab) + f'{wire}_sb_inst.init(uri_sb_value);',
|
|
627
|
+
(2 * tab) + 'end'
|
|
628
|
+
]
|
|
629
|
+
|
|
630
|
+
lines += [
|
|
631
|
+
(2 * tab) + '/* verilator lint_on IGNOREDRETURN */',
|
|
632
|
+
tab + 'end'
|
|
633
|
+
]
|
|
634
|
+
|
|
635
|
+
lines += ['']
|
|
636
|
+
|
|
637
|
+
lines += [tab + '`SB_SETUP_PROBES();']
|
|
638
|
+
lines += ['']
|
|
639
|
+
|
|
640
|
+
lines += ['endmodule']
|
|
641
|
+
|
|
642
|
+
lines += ['']
|
|
643
|
+
|
|
644
|
+
lines += ['`default_nettype wire']
|
|
645
|
+
|
|
646
|
+
if filename is None:
|
|
647
|
+
filename = 'testbench.sv'
|
|
648
|
+
|
|
649
|
+
filename = Path(filename).resolve()
|
|
650
|
+
|
|
651
|
+
with open(filename, 'w') as f:
|
|
652
|
+
for line in lines:
|
|
653
|
+
f.write(line + nl)
|
|
654
|
+
|
|
655
|
+
return filename
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def direction_is_input(direction):
|
|
659
|
+
return direction.lower() in ['i', 'in', 'input']
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
def direction_is_output(direction):
|
|
663
|
+
return direction.lower() in ['o', 'out', 'output']
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def direction_is_inout(direction):
|
|
667
|
+
return direction.lower() in ['inout']
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
def direction_is_manager(direction):
|
|
671
|
+
return direction.lower() in ['m', 'manager', 'master', 'indicator']
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
def direction_is_subordinate(direction):
|
|
675
|
+
return direction.lower() in ['s', 'subordinate', 'slave', 'target']
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def normalize_direction(type, direction):
|
|
679
|
+
if type_is_const(type):
|
|
680
|
+
if direction_is_output(direction):
|
|
681
|
+
return 'output'
|
|
682
|
+
else:
|
|
683
|
+
raise Exception(f'Unsupported direction for interface type "{type}": "{direction}"')
|
|
684
|
+
elif type_is_plusarg(type):
|
|
685
|
+
if direction_is_input(direction):
|
|
686
|
+
return 'input'
|
|
687
|
+
else:
|
|
688
|
+
raise Exception(f'Unsupported direction for interface type "{type}": "{direction}"')
|
|
689
|
+
elif type_is_sb(type) or type_is_umi(type) or type_is_gpio(type):
|
|
690
|
+
if direction_is_input(direction):
|
|
691
|
+
return 'input'
|
|
692
|
+
elif direction_is_output(direction):
|
|
693
|
+
return 'output'
|
|
694
|
+
elif direction_is_inout(direction):
|
|
695
|
+
return 'inout'
|
|
696
|
+
else:
|
|
697
|
+
raise Exception(f'Unsupported direction for interface type "{type}": "{direction}"')
|
|
698
|
+
elif type_is_axi(type) or type_is_axil(type) or type_is_apb(type):
|
|
699
|
+
if direction_is_manager(direction):
|
|
700
|
+
return 'manager'
|
|
701
|
+
elif direction_is_subordinate(direction):
|
|
702
|
+
return 'subordinate'
|
|
703
|
+
else:
|
|
704
|
+
raise Exception(f'Unsupported direction for interface type "{type}": "{direction}"')
|
|
705
|
+
else:
|
|
706
|
+
raise Exception(f'Unsupported interface type: "{type}"')
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
def directions_are_compatible(type_a, a, type_b, b):
|
|
710
|
+
a = normalize_direction(type_a, a)
|
|
711
|
+
b = normalize_direction(type_b, b)
|
|
712
|
+
|
|
713
|
+
if a == 'input':
|
|
714
|
+
return b in ['output', 'inout']
|
|
715
|
+
elif a == 'output':
|
|
716
|
+
return b in ['input', 'inout']
|
|
717
|
+
elif a == 'inout':
|
|
718
|
+
return b in ['input', 'output', 'inout']
|
|
719
|
+
elif a == 'manager':
|
|
720
|
+
return b == 'subordinate'
|
|
721
|
+
elif a == 'subordinate':
|
|
722
|
+
return b == 'manager'
|
|
723
|
+
else:
|
|
724
|
+
raise Exception(f'Cannot determine if directions are compatible: {a} and {b}')
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
def types_are_compatible(a, b):
|
|
728
|
+
a = normalize_intf_type(a)
|
|
729
|
+
b = normalize_intf_type(b)
|
|
730
|
+
|
|
731
|
+
if type_is_const(a):
|
|
732
|
+
return type_is_gpio(b)
|
|
733
|
+
elif type_is_const(b):
|
|
734
|
+
return type_is_gpio(a)
|
|
735
|
+
else:
|
|
736
|
+
return a == b
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
def flip_intf(a):
|
|
740
|
+
type = normalize_intf_type(a['type'])
|
|
741
|
+
direction = normalize_direction(type=type, direction=a['direction'])
|
|
742
|
+
|
|
743
|
+
retval = deepcopy(a)
|
|
744
|
+
|
|
745
|
+
if type_is_sb(type) or type_is_umi(type):
|
|
746
|
+
if direction == 'input':
|
|
747
|
+
retval['direction'] = 'output'
|
|
748
|
+
elif direction == 'output':
|
|
749
|
+
retval['direction'] = 'input'
|
|
750
|
+
else:
|
|
751
|
+
raise Exception(f'Unsupported direction: {direction}')
|
|
752
|
+
elif type_is_axi(type) or type_is_axil(type):
|
|
753
|
+
if direction == 'manager':
|
|
754
|
+
retval['direction'] = 'subordinate'
|
|
755
|
+
elif direction == 'subordinate':
|
|
756
|
+
retval['direction'] = 'manager'
|
|
757
|
+
else:
|
|
758
|
+
raise Exception(f'Unsupported direction: {direction}')
|
|
759
|
+
else:
|
|
760
|
+
raise Exception(f'Unsupported interface type: "{type}"')
|
|
761
|
+
|
|
762
|
+
return retval
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
def polarity_is_positive(polarity):
|
|
766
|
+
return polarity.lower() in ['+', 'p', 'plus', 'positive']
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
def polarity_is_negative(polarity):
|
|
770
|
+
return polarity.lower() in ['-', 'n', 'minus', 'negative']
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
def normalize_polarity(polarity):
|
|
774
|
+
if polarity_is_positive(polarity):
|
|
775
|
+
return 'positive'
|
|
776
|
+
elif polarity_is_negative(polarity):
|
|
777
|
+
return 'negative'
|
|
778
|
+
else:
|
|
779
|
+
raise ValueError(f'Unsupported reset polarity: "{polarity}"')
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
def type_is_sb(type):
|
|
783
|
+
return type.lower() in ['sb', 'switchboard']
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
def type_is_umi(type):
|
|
787
|
+
return type.lower() in ['umi']
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
def type_is_axi(type):
|
|
791
|
+
return type.lower() in ['axi']
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
def type_is_axil(type):
|
|
795
|
+
return type.lower() in ['axil']
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
def type_is_apb(type):
|
|
799
|
+
return type.lower() in ['apb']
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
def type_is_input(type):
|
|
803
|
+
return type.lower() in ['i', 'in', 'input']
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
def type_is_output(type):
|
|
807
|
+
return type.lower() in ['o', 'out', 'output']
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
def type_is_gpio(type):
|
|
811
|
+
return type.lower() in ['gpio']
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
def type_is_const(type):
|
|
815
|
+
return type.lower() in ['const', 'constant']
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
def type_is_plusarg(type):
|
|
819
|
+
return type.lower() in ['plusarg']
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def normalize_intf_type(type):
|
|
823
|
+
if type_is_sb(type):
|
|
824
|
+
return 'sb'
|
|
825
|
+
elif type_is_umi(type):
|
|
826
|
+
return 'umi'
|
|
827
|
+
elif type_is_axi(type):
|
|
828
|
+
return 'axi'
|
|
829
|
+
elif type_is_axil(type):
|
|
830
|
+
return 'axil'
|
|
831
|
+
elif type_is_apb(type):
|
|
832
|
+
return 'apb'
|
|
833
|
+
elif type_is_input(type):
|
|
834
|
+
return 'input'
|
|
835
|
+
elif type_is_output(type):
|
|
836
|
+
return 'output'
|
|
837
|
+
elif type_is_gpio(type):
|
|
838
|
+
return 'gpio'
|
|
839
|
+
elif type_is_const(type):
|
|
840
|
+
return 'const'
|
|
841
|
+
elif type_is_plusarg(type):
|
|
842
|
+
return 'plusarg'
|
|
843
|
+
else:
|
|
844
|
+
raise ValueError(f'Unsupported interface type: "{type}"')
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
def create_intf_objs(intf_defs, fresh=True, max_rate=-1):
|
|
848
|
+
intf_objs = {}
|
|
849
|
+
|
|
850
|
+
umi_txrx = {}
|
|
851
|
+
|
|
852
|
+
for name, value in intf_defs.items():
|
|
853
|
+
type = value['type']
|
|
854
|
+
|
|
855
|
+
if type == 'plusarg':
|
|
856
|
+
continue
|
|
857
|
+
|
|
858
|
+
if type.lower() in ['umi']:
|
|
859
|
+
txrx = value['txrx']
|
|
860
|
+
|
|
861
|
+
if txrx is not None:
|
|
862
|
+
if txrx not in umi_txrx:
|
|
863
|
+
umi_txrx[txrx] = dict(tx_uri=None, rx_uri=None)
|
|
864
|
+
|
|
865
|
+
if 'srcaddr' in value:
|
|
866
|
+
umi_txrx[txrx]['srcaddr'] = value['srcaddr']
|
|
867
|
+
|
|
868
|
+
if 'posted' in value:
|
|
869
|
+
umi_txrx[txrx]['posted'] = value['posted']
|
|
870
|
+
|
|
871
|
+
if 'max_bytes' in value:
|
|
872
|
+
umi_txrx[txrx]['max_bytes'] = value['max_bytes']
|
|
873
|
+
|
|
874
|
+
if 'max_rate' in value:
|
|
875
|
+
umi_txrx[txrx]['max_rate'] = value['max_rate']
|
|
876
|
+
else:
|
|
877
|
+
# use default if not set for this particular interface
|
|
878
|
+
umi_txrx[txrx]['max_rate'] = max_rate
|
|
879
|
+
|
|
880
|
+
direction = value['direction']
|
|
881
|
+
|
|
882
|
+
if direction.lower() in ['i', 'in', 'input']:
|
|
883
|
+
umi_txrx[txrx]['tx_uri'] = value['uri']
|
|
884
|
+
elif direction.lower() in ['o', 'out', 'output']:
|
|
885
|
+
umi_txrx[txrx]['rx_uri'] = value['uri']
|
|
886
|
+
else:
|
|
887
|
+
raise Exception(f'Unsupported UMI direction: {direction}')
|
|
888
|
+
else:
|
|
889
|
+
intf_objs[name] = create_intf_obj(value, fresh=fresh, max_rate=max_rate)
|
|
890
|
+
else:
|
|
891
|
+
intf_objs[name] = create_intf_obj(value, fresh=fresh, max_rate=max_rate)
|
|
892
|
+
|
|
893
|
+
for key, value in umi_txrx.items():
|
|
894
|
+
intf_objs[key] = UmiTxRx(**value, fresh=fresh)
|
|
895
|
+
|
|
896
|
+
return intf_objs
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
def create_intf_obj(value, fresh=True, max_rate=-1):
|
|
900
|
+
type = value['type']
|
|
901
|
+
direction = value['direction']
|
|
902
|
+
|
|
903
|
+
if type_is_sb(type):
|
|
904
|
+
kwargs = {}
|
|
905
|
+
|
|
906
|
+
if 'max_rate' in value:
|
|
907
|
+
kwargs['max_rate'] = value['max_rate']
|
|
908
|
+
else:
|
|
909
|
+
# use default if not set for this particular interface
|
|
910
|
+
kwargs['max_rate'] = max_rate
|
|
911
|
+
|
|
912
|
+
if direction_is_input(direction):
|
|
913
|
+
obj = PySbTx(value['uri'], fresh=fresh, **kwargs)
|
|
914
|
+
elif direction_is_output(direction):
|
|
915
|
+
obj = PySbRx(value['uri'], fresh=fresh, **kwargs)
|
|
916
|
+
else:
|
|
917
|
+
raise Exception(f'Unsupported SB direction: "{direction}"')
|
|
918
|
+
elif type_is_umi(type):
|
|
919
|
+
kwargs = {}
|
|
920
|
+
|
|
921
|
+
if 'max_rate' in value:
|
|
922
|
+
kwargs['max_rate'] = value['max_rate']
|
|
923
|
+
else:
|
|
924
|
+
# use default if not set for this particular interface
|
|
925
|
+
kwargs['max_rate'] = max_rate
|
|
926
|
+
|
|
927
|
+
if direction_is_input(direction):
|
|
928
|
+
obj = UmiTxRx(tx_uri=value['uri'], fresh=fresh, **kwargs)
|
|
929
|
+
elif direction_is_output(direction):
|
|
930
|
+
obj = UmiTxRx(rx_uri=value['uri'], fresh=fresh, **kwargs)
|
|
931
|
+
else:
|
|
932
|
+
raise Exception(f'Unsupported UMI direction: "{direction}"')
|
|
933
|
+
elif type_is_axi(type):
|
|
934
|
+
kwargs = {}
|
|
935
|
+
|
|
936
|
+
if 'prot' in value:
|
|
937
|
+
kwargs['prot'] = value['prot']
|
|
938
|
+
|
|
939
|
+
if 'id' in value:
|
|
940
|
+
kwargs['id'] = value['id']
|
|
941
|
+
|
|
942
|
+
if 'size' in value:
|
|
943
|
+
kwargs['size'] = value['size']
|
|
944
|
+
|
|
945
|
+
if 'max_beats' in value:
|
|
946
|
+
kwargs['max_beats'] = value['max_beats']
|
|
947
|
+
|
|
948
|
+
if 'max_rate' in value:
|
|
949
|
+
kwargs['max_rate'] = value['max_rate']
|
|
950
|
+
else:
|
|
951
|
+
# use default if not set for this particular interface
|
|
952
|
+
kwargs['max_rate'] = max_rate
|
|
953
|
+
|
|
954
|
+
if direction_is_subordinate(direction):
|
|
955
|
+
obj = AxiTxRx(uri=value['uri'], data_width=value['dw'],
|
|
956
|
+
addr_width=value['aw'], id_width=value['idw'], **kwargs)
|
|
957
|
+
else:
|
|
958
|
+
raise Exception(f'Unsupported AXI direction: "{direction}"')
|
|
959
|
+
elif type_is_axil(type):
|
|
960
|
+
kwargs = {}
|
|
961
|
+
|
|
962
|
+
if 'prot' in value:
|
|
963
|
+
kwargs['prot'] = value['prot']
|
|
964
|
+
|
|
965
|
+
if 'max_rate' in value:
|
|
966
|
+
kwargs['max_rate'] = value['max_rate']
|
|
967
|
+
else:
|
|
968
|
+
# use default if not set for this particular interface
|
|
969
|
+
kwargs['max_rate'] = max_rate
|
|
970
|
+
|
|
971
|
+
if direction_is_subordinate(direction):
|
|
972
|
+
obj = AxiLiteTxRx(uri=value['uri'], data_width=value['dw'],
|
|
973
|
+
addr_width=value['aw'], **kwargs)
|
|
974
|
+
else:
|
|
975
|
+
raise Exception(f'Unsupported AXI-Lite direction: "{direction}"')
|
|
976
|
+
elif type_is_apb(type):
|
|
977
|
+
kwargs = {}
|
|
978
|
+
|
|
979
|
+
if 'prot' in value:
|
|
980
|
+
kwargs['prot'] = value['prot']
|
|
981
|
+
|
|
982
|
+
if 'max_rate' in value:
|
|
983
|
+
kwargs['max_rate'] = value['max_rate']
|
|
984
|
+
else:
|
|
985
|
+
# use default if not set for this particular interface
|
|
986
|
+
kwargs['max_rate'] = max_rate
|
|
987
|
+
|
|
988
|
+
if direction_is_subordinate(direction):
|
|
989
|
+
obj = ApbTxRx(
|
|
990
|
+
uri=value['uri'],
|
|
991
|
+
data_width=value['dw'],
|
|
992
|
+
addr_width=value['aw'],
|
|
993
|
+
**kwargs
|
|
994
|
+
)
|
|
995
|
+
else:
|
|
996
|
+
raise Exception(f'Unsupported APB direction: "{direction}"')
|
|
997
|
+
else:
|
|
998
|
+
raise Exception(f'Unsupported interface type: "{type}"')
|
|
999
|
+
|
|
1000
|
+
return obj
|