switchboard-hw 0.3.0__cp314-cp314-macosx_10_15_x86_64.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 (99) hide show
  1. _switchboard.cpython-314-darwin.so +0 -0
  2. switchboard/__init__.py +24 -0
  3. switchboard/ams.py +668 -0
  4. switchboard/apb.py +278 -0
  5. switchboard/autowrap.py +1000 -0
  6. switchboard/axi.py +571 -0
  7. switchboard/axil.py +348 -0
  8. switchboard/bitvector.py +112 -0
  9. switchboard/cmdline.py +142 -0
  10. switchboard/cpp/Makefile +13 -0
  11. switchboard/cpp/bitutil.h +39 -0
  12. switchboard/cpp/pagemap.h +91 -0
  13. switchboard/cpp/pciedev.h +86 -0
  14. switchboard/cpp/router.cc +89 -0
  15. switchboard/cpp/spsc_queue.h +267 -0
  16. switchboard/cpp/switchboard.hpp +257 -0
  17. switchboard/cpp/switchboard_pcie.hpp +234 -0
  18. switchboard/cpp/switchboard_tlm.hpp +98 -0
  19. switchboard/cpp/umilib.h +144 -0
  20. switchboard/cpp/umilib.hpp +113 -0
  21. switchboard/cpp/umisb.hpp +364 -0
  22. switchboard/cpp/xyce.hpp +90 -0
  23. switchboard/deps/__init__.py +0 -0
  24. switchboard/deps/verilog_axi.py +23 -0
  25. switchboard/dpi/__init__.py +0 -0
  26. switchboard/dpi/switchboard_dpi.cc +119 -0
  27. switchboard/dpi/switchboard_dpi.py +13 -0
  28. switchboard/dpi/xyce_dpi.cc +43 -0
  29. switchboard/gpio.py +108 -0
  30. switchboard/icarus.py +85 -0
  31. switchboard/loopback.py +157 -0
  32. switchboard/network.py +714 -0
  33. switchboard/pytest_plugin.py +11 -0
  34. switchboard/sbdesign.py +55 -0
  35. switchboard/sbdut.py +744 -0
  36. switchboard/sbtcp.py +345 -0
  37. switchboard/sc/__init__.py +0 -0
  38. switchboard/sc/morty/__init__.py +0 -0
  39. switchboard/sc/morty/uniquify.py +67 -0
  40. switchboard/sc/sed/__init__.py +0 -0
  41. switchboard/sc/sed/sed_remove.py +47 -0
  42. switchboard/sc/standalone_netlist_flow.py +25 -0
  43. switchboard/switchboard.py +53 -0
  44. switchboard/test_util.py +46 -0
  45. switchboard/uart_xactor.py +66 -0
  46. switchboard/umi.py +793 -0
  47. switchboard/util.py +131 -0
  48. switchboard/verilator/__init__.py +0 -0
  49. switchboard/verilator/config.vlt +13 -0
  50. switchboard/verilator/testbench.cc +143 -0
  51. switchboard/verilator/verilator.py +13 -0
  52. switchboard/verilator_run.py +31 -0
  53. switchboard/verilog/__init__.py +0 -0
  54. switchboard/verilog/common/__init__.py +0 -0
  55. switchboard/verilog/common/common.py +26 -0
  56. switchboard/verilog/common/switchboard.vh +429 -0
  57. switchboard/verilog/common/uart_xactor.sv +247 -0
  58. switchboard/verilog/common/umi_gpio.v +236 -0
  59. switchboard/verilog/fpga/__init__.py +0 -0
  60. switchboard/verilog/fpga/axi_reader.sv +82 -0
  61. switchboard/verilog/fpga/axi_writer.sv +111 -0
  62. switchboard/verilog/fpga/config_registers.sv +249 -0
  63. switchboard/verilog/fpga/fpga.py +21 -0
  64. switchboard/verilog/fpga/include/sb_queue_regmap.vh +21 -0
  65. switchboard/verilog/fpga/include/spsc_queue.vh +7 -0
  66. switchboard/verilog/fpga/memory_fault.sv +40 -0
  67. switchboard/verilog/fpga/sb_fpga_queues.sv +416 -0
  68. switchboard/verilog/fpga/sb_rx_fpga.sv +303 -0
  69. switchboard/verilog/fpga/sb_tx_fpga.sv +294 -0
  70. switchboard/verilog/fpga/umi_fpga_queues.sv +146 -0
  71. switchboard/verilog/sim/__init__.py +0 -0
  72. switchboard/verilog/sim/auto_stop_sim.sv +25 -0
  73. switchboard/verilog/sim/perf_meas_sim.sv +97 -0
  74. switchboard/verilog/sim/queue_to_sb_sim.sv +176 -0
  75. switchboard/verilog/sim/queue_to_umi_sim.sv +66 -0
  76. switchboard/verilog/sim/sb_apb_m.sv +146 -0
  77. switchboard/verilog/sim/sb_axi_m.sv +199 -0
  78. switchboard/verilog/sim/sb_axil_m.sv +180 -0
  79. switchboard/verilog/sim/sb_axil_s.sv +180 -0
  80. switchboard/verilog/sim/sb_clk_gen.sv +89 -0
  81. switchboard/verilog/sim/sb_jtag_rbb_sim.sv +148 -0
  82. switchboard/verilog/sim/sb_rx_sim.sv +55 -0
  83. switchboard/verilog/sim/sb_to_queue_sim.sv +196 -0
  84. switchboard/verilog/sim/sb_tx_sim.sv +55 -0
  85. switchboard/verilog/sim/switchboard_sim.py +49 -0
  86. switchboard/verilog/sim/umi_rx_sim.sv +61 -0
  87. switchboard/verilog/sim/umi_to_queue_sim.sv +66 -0
  88. switchboard/verilog/sim/umi_tx_sim.sv +61 -0
  89. switchboard/verilog/sim/xyce_intf.sv +67 -0
  90. switchboard/vpi/switchboard_vpi.cc +431 -0
  91. switchboard/vpi/xyce_vpi.cc +200 -0
  92. switchboard/warn.py +14 -0
  93. switchboard/xyce.py +27 -0
  94. switchboard_hw-0.3.0.dist-info/METADATA +303 -0
  95. switchboard_hw-0.3.0.dist-info/RECORD +99 -0
  96. switchboard_hw-0.3.0.dist-info/WHEEL +6 -0
  97. switchboard_hw-0.3.0.dist-info/entry_points.txt +6 -0
  98. switchboard_hw-0.3.0.dist-info/licenses/LICENSE +190 -0
  99. 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)
@@ -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