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/sbtcp.py
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Command-line tool that bridges Switchboard packets over TCP.
|
|
4
|
+
|
|
5
|
+
# Copyright (c) 2024 Zero ASIC Corporation
|
|
6
|
+
# This code is licensed under Apache License 2.0 (see LICENSE for details)
|
|
7
|
+
|
|
8
|
+
# reference for setting up Python TCP connections:
|
|
9
|
+
# https://realpython.com/python-sockets/#echo-client-and-server
|
|
10
|
+
|
|
11
|
+
# reference for non-blocking socket programming:
|
|
12
|
+
# https://stackoverflow.com/a/16745561
|
|
13
|
+
|
|
14
|
+
import time
|
|
15
|
+
import socket
|
|
16
|
+
import argparse
|
|
17
|
+
import numpy as np
|
|
18
|
+
|
|
19
|
+
from switchboard import PySbRx, PySbTx, PySbPacket
|
|
20
|
+
|
|
21
|
+
SB_PACKET_SIZE_BYTES = 60
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def tcp2sb(outputs, conn):
|
|
25
|
+
while True:
|
|
26
|
+
# receive data from TCP
|
|
27
|
+
data_rx_from_tcp = bytes([])
|
|
28
|
+
|
|
29
|
+
while len(data_rx_from_tcp) < SB_PACKET_SIZE_BYTES:
|
|
30
|
+
b = conn.recv(SB_PACKET_SIZE_BYTES - len(data_rx_from_tcp))
|
|
31
|
+
|
|
32
|
+
if len(b) == 0:
|
|
33
|
+
# connection is not alive anymore
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
data_rx_from_tcp += b
|
|
37
|
+
|
|
38
|
+
# convert to a switchboard packet
|
|
39
|
+
p = bytes2sb(data_rx_from_tcp)
|
|
40
|
+
|
|
41
|
+
# figure out which queue this packet is going to
|
|
42
|
+
for rule, output in outputs:
|
|
43
|
+
if rule_matches(rule, p.destination):
|
|
44
|
+
output.send(p)
|
|
45
|
+
break
|
|
46
|
+
else:
|
|
47
|
+
raise Exception(f"No rule for destination {p.destination}")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def sb2tcp(inputs, conn):
|
|
51
|
+
tcp_data_to_send = bytes([])
|
|
52
|
+
|
|
53
|
+
while True:
|
|
54
|
+
# get a switchboard packet
|
|
55
|
+
while True:
|
|
56
|
+
# select input and queue its next run as last
|
|
57
|
+
destination, sbrx = inputs.pop(0)
|
|
58
|
+
inputs.append((destination, sbrx))
|
|
59
|
+
|
|
60
|
+
# try to receive a packet from this input
|
|
61
|
+
p = sbrx.recv(blocking=False)
|
|
62
|
+
|
|
63
|
+
if p is not None:
|
|
64
|
+
if destination is not None:
|
|
65
|
+
p.destination = destination
|
|
66
|
+
break
|
|
67
|
+
|
|
68
|
+
# convert the switchboard packet to bytes
|
|
69
|
+
tcp_data_to_send = sb2bytes(p)
|
|
70
|
+
|
|
71
|
+
# send the packet out over TCP
|
|
72
|
+
while len(tcp_data_to_send) > 0:
|
|
73
|
+
n = conn.send(tcp_data_to_send)
|
|
74
|
+
|
|
75
|
+
if n == 0:
|
|
76
|
+
# connection is not alive anymore
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
tcp_data_to_send = tcp_data_to_send[n:]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def run_client(host, port, quiet=False, max_rate=None, inputs=None, outputs=None, run_once=False):
|
|
83
|
+
"""
|
|
84
|
+
Connect to a server, retrying until a connection is made.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
# initialize PySbRx/PySbTx objects if needed
|
|
88
|
+
|
|
89
|
+
inputs, outputs = normalize_inputs_and_outputs(
|
|
90
|
+
inputs=inputs, outputs=outputs, max_rate=max_rate)
|
|
91
|
+
|
|
92
|
+
# connect to the server in a loop
|
|
93
|
+
while True:
|
|
94
|
+
if not quiet:
|
|
95
|
+
print(f'Waiting for server (host={host}, port={port})')
|
|
96
|
+
while True:
|
|
97
|
+
try:
|
|
98
|
+
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
99
|
+
conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
|
100
|
+
conn.connect((host, port))
|
|
101
|
+
break
|
|
102
|
+
except ConnectionRefusedError:
|
|
103
|
+
time.sleep(1)
|
|
104
|
+
if not quiet:
|
|
105
|
+
print(f'Connected to server (host={host}, port={port})')
|
|
106
|
+
|
|
107
|
+
# communicate with the server
|
|
108
|
+
if outputs is not None:
|
|
109
|
+
tcp2sb(outputs=outputs, conn=conn)
|
|
110
|
+
elif inputs is not None:
|
|
111
|
+
sb2tcp(inputs=inputs, conn=conn)
|
|
112
|
+
|
|
113
|
+
if run_once:
|
|
114
|
+
break
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def run_server(host, port=0, quiet=False, max_rate=None, run_once=False, outputs=None, inputs=None):
|
|
118
|
+
"""
|
|
119
|
+
Accepts client connections in a loop until Ctrl-C is pressed.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
# initialize PySbRx/PySbTx objects if needed
|
|
123
|
+
|
|
124
|
+
inputs, outputs = normalize_inputs_and_outputs(
|
|
125
|
+
inputs=inputs, outputs=outputs, max_rate=max_rate)
|
|
126
|
+
|
|
127
|
+
# create the server socket
|
|
128
|
+
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
129
|
+
server_socket.setsockopt(socket.SOL_SOCKET,
|
|
130
|
+
socket.SO_REUSEADDR, 1) # allow port to be reused immediately
|
|
131
|
+
server_socket.bind((host, port))
|
|
132
|
+
server_socket.listen()
|
|
133
|
+
|
|
134
|
+
# accept client connections in a loop
|
|
135
|
+
while True:
|
|
136
|
+
# accept a client
|
|
137
|
+
if not quiet:
|
|
138
|
+
print(f'Waiting for client (host={host}, port={port})')
|
|
139
|
+
conn, _ = server_socket.accept()
|
|
140
|
+
if not quiet:
|
|
141
|
+
print(f'Connected to client (host={host}, port={port})')
|
|
142
|
+
|
|
143
|
+
# communicate with the client
|
|
144
|
+
if outputs is not None:
|
|
145
|
+
tcp2sb(outputs=outputs, conn=conn)
|
|
146
|
+
elif inputs is not None:
|
|
147
|
+
sb2tcp(inputs=inputs, conn=conn)
|
|
148
|
+
|
|
149
|
+
if run_once:
|
|
150
|
+
break
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def normalize_inputs_and_outputs(inputs, outputs, max_rate):
|
|
154
|
+
if outputs is not None:
|
|
155
|
+
assert inputs is None, 'Cannot specify both inputs and outputs'
|
|
156
|
+
outputs = normalize_outputs(outputs, max_rate)
|
|
157
|
+
else:
|
|
158
|
+
assert inputs is not None, 'Must specify either inputs or outputs'
|
|
159
|
+
inputs = normalize_inputs(inputs, max_rate)
|
|
160
|
+
|
|
161
|
+
return inputs, outputs
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def normalize_outputs(outputs, max_rate):
|
|
165
|
+
retval = []
|
|
166
|
+
|
|
167
|
+
for rule, output in outputs:
|
|
168
|
+
output = convert_to_queue(q=output, cls=PySbTx, max_rate=max_rate)
|
|
169
|
+
retval.append((rule, output))
|
|
170
|
+
|
|
171
|
+
return retval
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def normalize_inputs(inputs, max_rate):
|
|
175
|
+
retval = []
|
|
176
|
+
|
|
177
|
+
for input in inputs:
|
|
178
|
+
if not isinstance(input, (list, tuple)):
|
|
179
|
+
destination, input = None, input
|
|
180
|
+
else:
|
|
181
|
+
destination, input = input
|
|
182
|
+
|
|
183
|
+
input = convert_to_queue(q=input, cls=PySbRx, max_rate=max_rate)
|
|
184
|
+
|
|
185
|
+
retval.append((destination, input))
|
|
186
|
+
|
|
187
|
+
return retval
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def sb2bytes(p):
|
|
191
|
+
# construct a bytes object from a Switchboard packet
|
|
192
|
+
arr = np.concatenate((
|
|
193
|
+
np.array([p.destination, p.flags], dtype=np.uint32),
|
|
194
|
+
p.data.view(np.uint32)
|
|
195
|
+
))
|
|
196
|
+
return arr.tobytes()
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def bytes2sb(b):
|
|
200
|
+
# construct a Switchboard packet from a bytes object
|
|
201
|
+
arr = np.frombuffer(b, dtype=np.uint32)
|
|
202
|
+
return PySbPacket(arr[0], arr[1], arr[2:].view(np.uint8))
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def convert_to_queue(q, cls, max_rate=None):
|
|
206
|
+
if isinstance(q, cls):
|
|
207
|
+
# note that None is passed through
|
|
208
|
+
return q
|
|
209
|
+
elif isinstance(q, str):
|
|
210
|
+
kwargs = {}
|
|
211
|
+
|
|
212
|
+
if max_rate is not None:
|
|
213
|
+
kwargs['max_rate'] = max_rate
|
|
214
|
+
|
|
215
|
+
return cls(q, **kwargs)
|
|
216
|
+
else:
|
|
217
|
+
raise TypeError(f'{q} must be a string or {cls.__name__}; got {type(q)}')
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def rule_matches(rule, addr):
|
|
221
|
+
if rule == '*':
|
|
222
|
+
return True
|
|
223
|
+
elif isinstance(rule, int):
|
|
224
|
+
return addr == rule
|
|
225
|
+
elif isinstance(rule, range):
|
|
226
|
+
return rule.start <= addr < rule.stop
|
|
227
|
+
elif isinstance(rule, (list, tuple)):
|
|
228
|
+
# return True if any subrules match
|
|
229
|
+
for subrule in rule:
|
|
230
|
+
if rule_matches(subrule, addr):
|
|
231
|
+
return True
|
|
232
|
+
|
|
233
|
+
# otherwise return False
|
|
234
|
+
return False
|
|
235
|
+
else:
|
|
236
|
+
raise Exception(f'Unsupported rule type: {type(rule)}')
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def parse_rule(rule):
|
|
240
|
+
subrules = rule.split(',')
|
|
241
|
+
|
|
242
|
+
retval = []
|
|
243
|
+
|
|
244
|
+
for subrule in subrules:
|
|
245
|
+
if subrule == '*':
|
|
246
|
+
retval.append('*')
|
|
247
|
+
elif '-' in subrule:
|
|
248
|
+
start, stop = subrule.split('-')
|
|
249
|
+
start = int(start)
|
|
250
|
+
stop = int(stop)
|
|
251
|
+
retval.append(range(start, stop + 1))
|
|
252
|
+
else:
|
|
253
|
+
retval.append(int(subrule))
|
|
254
|
+
|
|
255
|
+
return retval
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def start_tcp_bridge(inputs=None, outputs=None, host='localhost', port=5555,
|
|
259
|
+
quiet=True, max_rate=None, mode='auto', run_once=False):
|
|
260
|
+
|
|
261
|
+
kwargs = dict(
|
|
262
|
+
host=host,
|
|
263
|
+
port=port,
|
|
264
|
+
quiet=quiet,
|
|
265
|
+
max_rate=max_rate,
|
|
266
|
+
run_once=run_once
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
target = None
|
|
270
|
+
|
|
271
|
+
if mode == 'client':
|
|
272
|
+
target = run_client
|
|
273
|
+
elif mode == 'server':
|
|
274
|
+
target = run_server
|
|
275
|
+
|
|
276
|
+
if outputs is not None:
|
|
277
|
+
kwargs['outputs'] = outputs
|
|
278
|
+
if mode == 'auto':
|
|
279
|
+
target = run_server
|
|
280
|
+
elif inputs is not None:
|
|
281
|
+
kwargs['inputs'] = inputs
|
|
282
|
+
if mode == 'auto':
|
|
283
|
+
target = run_client
|
|
284
|
+
else:
|
|
285
|
+
raise Exception('Must specify "outputs" or "inputs" argument.')
|
|
286
|
+
|
|
287
|
+
assert target is not None, 'Could not determine whether to run the bridge as a client or server'
|
|
288
|
+
|
|
289
|
+
import multiprocessing
|
|
290
|
+
|
|
291
|
+
p = multiprocessing.Process(target=target, kwargs=kwargs, daemon=True)
|
|
292
|
+
p.start()
|
|
293
|
+
|
|
294
|
+
return p
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def get_parser():
|
|
298
|
+
parser = argparse.ArgumentParser()
|
|
299
|
+
|
|
300
|
+
parser.add_argument('--outputs', type=str, default=None, nargs='+', help="Space-separated"
|
|
301
|
+
" dictionary of queues to write to. For example, 0:a.q 1-2:b.q 3,5-7:c.q *:d.q means"
|
|
302
|
+
" that packets sent to destination 0 are routed to a.q, packets sent to destinations 1"
|
|
303
|
+
" or 2 are routed to b.q, packets sent to destinations 3, 5, 6, or 7 are routed to c.q,"
|
|
304
|
+
" and all other packets are routed to d.q")
|
|
305
|
+
parser.add_argument('--inputs', type=str, default=None, nargs='+', help="Space-separated"
|
|
306
|
+
" list of queues to read from, for example a.q b.q c.q")
|
|
307
|
+
parser.add_argument('--port', type=int, default=5555, help="TCP port used for"
|
|
308
|
+
" sending and receiving packets.")
|
|
309
|
+
parser.add_argument('--host', type=str, default="localhost", help="IP address or hostname"
|
|
310
|
+
" used sending/receiving packets.")
|
|
311
|
+
parser.add_argument('-q', action='store_true', help="Quiet mode: doesn't print anything.")
|
|
312
|
+
parser.add_argument('--max-rate', type=float, default=None, help='Maximum rate at which'
|
|
313
|
+
' queues are read or written.')
|
|
314
|
+
parser.add_argument('--run-once', action='store_true', help="Process only one connection"
|
|
315
|
+
" in server mode, then exit.")
|
|
316
|
+
|
|
317
|
+
return parser
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def main():
|
|
321
|
+
# parse command-line arguments
|
|
322
|
+
|
|
323
|
+
parser = get_parser()
|
|
324
|
+
args = parser.parse_args()
|
|
325
|
+
|
|
326
|
+
# main logic
|
|
327
|
+
|
|
328
|
+
if args.outputs is not None:
|
|
329
|
+
# parse the output mapping
|
|
330
|
+
outputs = []
|
|
331
|
+
for output in args.outputs:
|
|
332
|
+
rule, output = output.split(':')
|
|
333
|
+
outputs.append((parse_rule(rule), output))
|
|
334
|
+
|
|
335
|
+
run_server(outputs=outputs, host=args.host, port=args.port,
|
|
336
|
+
quiet=args.q, max_rate=args.max_rate, run_once=args.run_once)
|
|
337
|
+
elif args.inputs is not None:
|
|
338
|
+
run_client(inputs=args.inputs, host=args.host, port=args.port,
|
|
339
|
+
quiet=args.q, max_rate=args.max_rate)
|
|
340
|
+
else:
|
|
341
|
+
raise ValueError("Must specify either --inputs or --outputs")
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
if __name__ == "__main__":
|
|
345
|
+
main()
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Copyright (c) 2024 Zero ASIC Corporation
|
|
2
|
+
# This code is licensed under Apache License 2.0 (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
from siliconcompiler import Task
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class UniquifyVerilogModules(Task):
|
|
8
|
+
|
|
9
|
+
def __init__(self):
|
|
10
|
+
super().__init__()
|
|
11
|
+
|
|
12
|
+
self.add_parameter(
|
|
13
|
+
name='suffix',
|
|
14
|
+
type='str',
|
|
15
|
+
help='suffix to be added to the end of module names'
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
self.add_parameter(
|
|
19
|
+
name='prefix',
|
|
20
|
+
type='str',
|
|
21
|
+
help='prefix to be added to the beginning of module names'
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def tool(self):
|
|
25
|
+
return "morty"
|
|
26
|
+
|
|
27
|
+
def task(self):
|
|
28
|
+
return "uniquify_verilog_modules"
|
|
29
|
+
|
|
30
|
+
def setup(self):
|
|
31
|
+
super().setup()
|
|
32
|
+
|
|
33
|
+
self.set_exe("morty")
|
|
34
|
+
|
|
35
|
+
self.add_input_file(ext="sv")
|
|
36
|
+
self.add_output_file(ext="sv")
|
|
37
|
+
|
|
38
|
+
def runtime_options(self):
|
|
39
|
+
options = super().runtime_options()
|
|
40
|
+
|
|
41
|
+
idirs = []
|
|
42
|
+
for lib, fileset in self.project.get_filesets():
|
|
43
|
+
idirs.extend(lib.get_idir(fileset))
|
|
44
|
+
|
|
45
|
+
cmdlist = []
|
|
46
|
+
|
|
47
|
+
prefix = self.get("var", "prefix")
|
|
48
|
+
if prefix:
|
|
49
|
+
cmdlist.extend(['--prefix', prefix])
|
|
50
|
+
|
|
51
|
+
suffix = self.get("var", "suffix")
|
|
52
|
+
if suffix:
|
|
53
|
+
cmdlist.extend(['--suffix', suffix])
|
|
54
|
+
|
|
55
|
+
out_file = f"outputs/{self.design_topmodule}.sv"
|
|
56
|
+
|
|
57
|
+
cmdlist.extend(['-o', out_file])
|
|
58
|
+
|
|
59
|
+
for value in idirs:
|
|
60
|
+
cmdlist.append('-I' + value)
|
|
61
|
+
|
|
62
|
+
input_file = f"inputs/{self.design_topmodule}.sv"
|
|
63
|
+
|
|
64
|
+
options.extend(cmdlist)
|
|
65
|
+
options.append(input_file)
|
|
66
|
+
|
|
67
|
+
return options
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Copyright (c) 2024 Zero ASIC Corporation
|
|
2
|
+
# This code is licensed under Apache License 2.0 (see LICENSE for details)
|
|
3
|
+
|
|
4
|
+
from siliconcompiler import Task
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class SedRemove(Task):
|
|
8
|
+
|
|
9
|
+
def __init__(self):
|
|
10
|
+
super().__init__()
|
|
11
|
+
|
|
12
|
+
self.add_parameter(
|
|
13
|
+
name="to_remove",
|
|
14
|
+
type="[str]",
|
|
15
|
+
help="strings to remove from the Verilog source file"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def tool(self):
|
|
19
|
+
return "sed"
|
|
20
|
+
|
|
21
|
+
def task(self):
|
|
22
|
+
return "remove"
|
|
23
|
+
|
|
24
|
+
def setup(self):
|
|
25
|
+
super().setup()
|
|
26
|
+
|
|
27
|
+
self.set_exe("sed")
|
|
28
|
+
|
|
29
|
+
self.add_input_file(ext="sv")
|
|
30
|
+
self.add_output_file(ext="sv")
|
|
31
|
+
|
|
32
|
+
def runtime_options(self):
|
|
33
|
+
options = super().runtime_options()
|
|
34
|
+
|
|
35
|
+
to_remove = self.get("var", "to_remove")
|
|
36
|
+
|
|
37
|
+
script = [f's/{elem}//g' for elem in to_remove]
|
|
38
|
+
script += [f'w outputs/{self.design_topmodule}.sv']
|
|
39
|
+
script = '; '.join(script)
|
|
40
|
+
|
|
41
|
+
options.extend(["-n", f'{script}', ])
|
|
42
|
+
|
|
43
|
+
input_file = f"inputs/{self.design_topmodule}.sv"
|
|
44
|
+
|
|
45
|
+
options.append(input_file)
|
|
46
|
+
|
|
47
|
+
return options
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from siliconcompiler import Flowgraph
|
|
2
|
+
from siliconcompiler.tools.surelog.parse import ElaborateTask
|
|
3
|
+
|
|
4
|
+
from switchboard.sc.sed.sed_remove import SedRemove
|
|
5
|
+
from switchboard.sc.morty.uniquify import UniquifyVerilogModules
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class StandaloneNetlistFlow(Flowgraph):
|
|
9
|
+
def __init__(self, name: str = None):
|
|
10
|
+
if name is None:
|
|
11
|
+
name = "standalone-netlist-flow"
|
|
12
|
+
super().__init__(name)
|
|
13
|
+
|
|
14
|
+
self.node("parse", ElaborateTask)
|
|
15
|
+
self.node("remove", SedRemove)
|
|
16
|
+
self.node("uniquify", UniquifyVerilogModules)
|
|
17
|
+
|
|
18
|
+
self.edge("parse", "remove")
|
|
19
|
+
self.edge("remove", "uniquify")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
##################################################
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
flow = StandaloneNetlistFlow()
|
|
25
|
+
flow.write_flowgraph(f"{flow.name}.png")
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Switchboard CLI
|
|
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 argparse import ArgumentParser
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def path():
|
|
11
|
+
return Path(__file__).resolve().parent
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def inspect(file, format):
|
|
15
|
+
import shutil
|
|
16
|
+
import tempfile
|
|
17
|
+
|
|
18
|
+
with tempfile.NamedTemporaryFile() as temp:
|
|
19
|
+
shutil.copyfile(file, temp.name)
|
|
20
|
+
|
|
21
|
+
if format == 'sb':
|
|
22
|
+
from switchboard import PySbRx
|
|
23
|
+
rx = PySbRx(temp.name, fresh=False)
|
|
24
|
+
elif format == 'umi':
|
|
25
|
+
from switchboard import UmiTxRx
|
|
26
|
+
rx = UmiTxRx(rx_uri=temp.name, fresh=False)
|
|
27
|
+
else:
|
|
28
|
+
raise ValueError(f'Format not supported: "{format}"')
|
|
29
|
+
|
|
30
|
+
while True:
|
|
31
|
+
rxp = rx.recv(False)
|
|
32
|
+
|
|
33
|
+
if rxp is not None:
|
|
34
|
+
print(rxp)
|
|
35
|
+
else:
|
|
36
|
+
break
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main():
|
|
40
|
+
parser = ArgumentParser()
|
|
41
|
+
parser.add_argument('--path', action='store_true')
|
|
42
|
+
parser.add_argument('-i', '--inspect', type=str, default=None, help='Print the contents'
|
|
43
|
+
' of the given switchboard queue.')
|
|
44
|
+
parser.add_argument('-f', '--format', type=str, default='sb', choices=['sb', 'umi'],
|
|
45
|
+
help='Format assumed for the contents of the switchboard queue passed via the'
|
|
46
|
+
' -i/--inspect argument.')
|
|
47
|
+
|
|
48
|
+
args = parser.parse_args()
|
|
49
|
+
|
|
50
|
+
if args.path:
|
|
51
|
+
print(path())
|
|
52
|
+
elif args.inspect is not None:
|
|
53
|
+
inspect(file=args.inspect, format=args.format)
|
switchboard/test_util.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# General utilities for working with switchboard
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2024 Zero ASIC Corporation
|
|
4
|
+
# This code is licensed under Apache License 2.0 (see LICENSE for details)
|
|
5
|
+
|
|
6
|
+
import subprocess
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_cmd(args, expected=None, path=None):
|
|
11
|
+
# determine where the command should be run
|
|
12
|
+
if path is not None:
|
|
13
|
+
path = Path(path)
|
|
14
|
+
if path.is_file():
|
|
15
|
+
cwd = path.resolve().parent
|
|
16
|
+
elif path.is_dir():
|
|
17
|
+
cwd = path.resolve()
|
|
18
|
+
else:
|
|
19
|
+
raise ValueError(f"Provided path doesn't exist: {path}")
|
|
20
|
+
else:
|
|
21
|
+
cwd = None
|
|
22
|
+
|
|
23
|
+
# run the command, capturing the output
|
|
24
|
+
if isinstance(args, str):
|
|
25
|
+
args = [args]
|
|
26
|
+
args = [str(arg) for arg in args]
|
|
27
|
+
|
|
28
|
+
process = subprocess.Popen(args, stdout=subprocess.PIPE,
|
|
29
|
+
stderr=subprocess.STDOUT, bufsize=1, text=True, cwd=cwd)
|
|
30
|
+
|
|
31
|
+
# print output while saving it
|
|
32
|
+
stdout = ''
|
|
33
|
+
for line in process.stdout:
|
|
34
|
+
print(line, end='')
|
|
35
|
+
stdout += line
|
|
36
|
+
|
|
37
|
+
# make sure that process exits cleanly
|
|
38
|
+
returncode = process.wait()
|
|
39
|
+
assert returncode == 0, f'Exited with non-zero code: {returncode}'
|
|
40
|
+
|
|
41
|
+
# check the results
|
|
42
|
+
if expected is not None:
|
|
43
|
+
if isinstance(expected, str):
|
|
44
|
+
expected = [expected]
|
|
45
|
+
for elem in expected:
|
|
46
|
+
assert elem in stdout
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2024 Zero ASIC Corporation
|
|
4
|
+
# This code is licensed under Apache License 2.0 (see LICENSE for details)
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
UMI/UART Transactor.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class uart_xactor:
|
|
14
|
+
REG_TX = 0
|
|
15
|
+
REG_RX = 4
|
|
16
|
+
REG_SR = 8
|
|
17
|
+
|
|
18
|
+
REGF_SR_RXEMPTY_MASK = 1 << 0
|
|
19
|
+
REGF_SR_RXFULL_MASK = 1 << 1
|
|
20
|
+
REGF_SR_TXEMPTY_MASK = 1 << 8
|
|
21
|
+
REGF_SR_TXFULL_MASK = 1 << 9
|
|
22
|
+
|
|
23
|
+
def __init__(self, umi, encoding='ascii'):
|
|
24
|
+
self.encoding = encoding
|
|
25
|
+
self.umi = umi
|
|
26
|
+
|
|
27
|
+
def read_byte(self):
|
|
28
|
+
c8 = None
|
|
29
|
+
while True:
|
|
30
|
+
sr = self.umi.read(self.REG_SR, np.uint32)
|
|
31
|
+
if (sr & self.REGF_SR_RXEMPTY_MASK) == 0:
|
|
32
|
+
rx = self.umi.read(self.REG_RX, np.uint32)
|
|
33
|
+
c8 = rx & 0xff
|
|
34
|
+
break
|
|
35
|
+
return bytes([c8])
|
|
36
|
+
|
|
37
|
+
def readline(self, size=-1, end='\n'):
|
|
38
|
+
line = ""
|
|
39
|
+
|
|
40
|
+
while size < 0 or len(line) < size:
|
|
41
|
+
c8 = self.read_byte()
|
|
42
|
+
if c8 == end.encode(self.encoding):
|
|
43
|
+
break
|
|
44
|
+
line += c8.decode(self.encoding)
|
|
45
|
+
return line
|
|
46
|
+
|
|
47
|
+
def write_byte(self, b):
|
|
48
|
+
while True:
|
|
49
|
+
sr = self.umi.read(self.REG_SR, np.uint32)
|
|
50
|
+
if (sr & self.REGF_SR_TXFULL_MASK) == 0:
|
|
51
|
+
self.umi.write(self.REG_TX, np.uint32(b))
|
|
52
|
+
break
|
|
53
|
+
|
|
54
|
+
# File-like ops
|
|
55
|
+
def write(self, string):
|
|
56
|
+
for b in string:
|
|
57
|
+
self.write_byte(b)
|
|
58
|
+
|
|
59
|
+
# On streaming UART, reading until EOF doesn't make sense
|
|
60
|
+
# So we default the size arg to 1
|
|
61
|
+
def read(self, size=1):
|
|
62
|
+
data = bytes(0)
|
|
63
|
+
while size < 0 or len(data) < size:
|
|
64
|
+
b = self.read_byte()
|
|
65
|
+
data += b
|
|
66
|
+
return data
|