Skip to main content

A low-latency communication library for RTL simulation and emulation.

Project description

Switchboard

Actions Status Documentation Status PyPI version License

Switchboard (SB) is a framework for communication between distinct hardware models, such as RTL simulations, RTL implemented on FPGAs, and fast SW models. This makes it possible to simulate large hardware systems in a distributed fashion, using whatever models are available for the different components.

In such a simulation, each hardware model has one or more SB ports. Each is unidirectional: it may act as an input or an output, but not both. In addition, each SB connection is single-producer, single-consumer (SPSC): an output port may not drive more than one input port, and an input port may not be driven by more than one output port.

Here's an example of what a switchboard connection topology might look like:

image

The method for adding a switchboard port depends on the language that a HW model is implemented in. For RTL-based models, SB ports are instantiated as Verilog models, whereas for C++ and Python-based models, these ports are instantiated as objects. We provide both a low-level interface for moving data directly between SB ports, as well as a higher-level interface for running UMI transactions over SB connections.

Under the hood, communication happens through shared-memory queues, where an SB output port is driving packets into the queue, and an SB input port is reading from that queue. This standardization is what allows any two kinds of models to talk to each other. A shared-memory SPSC queue is an appealing common interface because it is one of the fastest interprocess communication techniques, with latencies on the order of hundreds of nanoseconds; no system calls are required to transmit and receive data. At the same time, this type of queue is straightforward to implement for FPGA platforms, with queue read and write operations only requiring a handful of memory transactions.

Installation

The fastest way to install this package is from PyPI:

pip install switchboard-hw

However, if you want to run the examples below (or if you're a switchboard developer), clone this repository and install the Python package in-place:

$ git clone https://github.com/zeroasiccorp/switchboard.git
$ cd switchboard
$ git submodule update --init
$ pip install --upgrade pip
$ pip install -e .

Examples

Various examples demonstrating the features of switchboard are in the examples folder. If you'd like to run them yourself, please run this command first:

./examples/get_deps.py

This clones some additional repositories that are needed by the examples.

A good starting point is the python example, where a Python script sends packets to and receives packets from a Verilator RTL simulation. The configuration is simple: there is a small RTL simulation that accepts an SB packet, increments the data payload, and transmits the result on its SB output port. On the other side, a Python script sends an SB packet to the simulation, and checks that the packet it gets back has been incremented.

image

To run this example, you'll need verilator (sudo apt install verilator for Ubuntu, brew install verilator for macOS). You can then run the example by changing directory to examples/python and then typing make. That should produce output similar to the following:

*** TX packet ***
dest: 123456789
last: 1
data: [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 24 25 26 27 28 29 30 31]

*** RX packet ***
dest: 123456789
last: 1
data: [ 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 25 26 27 28 29 30 31 32]

- ../verilog/testbench.sv:72: Verilog $finish
PASS!

To get a sense of how this works, open the Python script examples/python/test.py. The core logic is essentially:

from switchboard import PySbPacket, PySbTx, PySbRx
...
tx = PySbTx("to_rtl.q")
rx = PySbRx("from_rtl.q")
...
txp = PySbPacket(...)
tx.send(txp)
...
rxp = rx.recv()

In other words, we create an SB output port (tx) and an SB input port (rx). An SB packet is then created (txp) and sent via the output port. Finally, a new SB packet is received from the input port.

To get a sense of how switchboard is used in RTL, have a look at the Verilog part of this example in examples/python/testbench.sv. The core logic is the instantiation of queue_to_sb_sim (SB input port) and sb_to_queue_sim (SB output port), along with the initialization step to define the name of each SB connection. Notice that the Python output port is matched to the Verilog input port (to_rtl.q) and similarly the Python input port is matched to the Verilog output port (from_rtl.q).

// ...

queue_to_sb_sim rx_i (
    .clk(clk),
    .data(sb_rx_data),
    .dest(sb_rx_dest),
    .last(sb_rx_last),
    .ready(sb_rx_ready),
    .valid(sb_rx_valid)
);

sb_to_queue_sim tx_i (
    .clk(clk),
    .data(sb_tx_data),
    .dest(sb_tx_dest),
    .last(sb_tx_last),
    .ready(sb_tx_ready),
    .valid(sb_tx_valid)
);

// ...

initial begin
    rx_i.init("to_rtl.q");
    tx_i.init("from_rtl.q");
end

// ...

Using the same name for two ports is what establishes a connection between them. You can use any name that you like for a SB connection, as long as it is a valid file name. The reason is that SB connections are visible as files on your file system. After this example runs, it will leave behind files called to_rtl.q and from_rtl.q. It's convenient to name SB connections in a way that is amenable to pattern matching, so that you can do things like rm *.q to clean up old connections.

We encourage you to explore the other examples, which demonstrate simulation with Icarus Verilog and switchboard's C++ library (minimal), bridging SB connections via TCP (tcp), and switchboard's UMI abstraction (umiram).

Build automation

We also provide build automation powered by SiliconCompiler that makes it easy to build RTL simulations with switchboard infrastructure (queue_to_sb_sim, sb_to_queue_sim, etc.). This is mainly important because Verilog DPI and VPI are used under the hood, requiring certain flags to be passed to the RTL simulator during the build. Using our build automation lets you focus on specifying RTL sources, without having to deal with these details.

As an example, we return to examples/python. The basic logic for a Verilator build is:

from switchboard import SbDut

dut = SbDut('name-of-top-level-module', default_main=True)

dut.input('path/to/file/1')
dut.input('path/to/file/2')
...

dut.build()

dut.simulate()

In other words, create an SbDut object, input() files, build() it to compile the Verilator simulator, and use simulate() to start the simulator. SbDut is a subclass of siliconcompiler.Chip, which allows you to invoke a range of features to control the simulator build, such as specifying include paths and `define macros. More information about siliconcompiler.Chip can be found here.

Packet format

An SB packet is a simple data structure with three parts, defined in switchboard/cpp/switchboard.hpp.

  1. A 32-bit destination.
  2. A 32-bit flags bit vector. Currently only bit "0" is used, providing the last flag.
  3. A 416-bit data payload. This width was chosen to accommodate a UMI packet with a 256 bit payload, 64-bit source and destination addresses, and a 32-bit command. In the future, we may support parameterizable data widths for switchboard connections.

destination and flags control how the packet is routed. destination indicates the intended recipient of the packet as a flat, unsigned 32-bit integer. This provides a mechanism where a packet can be routed through multiple hops before reaching its final destination.

For example, consider using switchboard to build a simple topology in which packets can be sent from one HW block to one of two other blocks. One could indicate which block should receive the packet using the destination field, with a router transmitting the packet to the right one.

image

The last indicator (part of the flags bit vector) indicates whether there is more to come as part of a transaction. The rule is that a transmission cannot be interrupted as long as as last is zero. As an example, consider the system below, where Block A and Block B are both sending SB packets to the same port on Block C, using a router to multiplex between the two. Following the rule of unbroken transmissions, if the router starts sending a sequence of packets from Block A to Block C, it cannot switch to sending packets from Block B to Block C until it gets a packet from Block A that has last set to one. It is legal to have last=1 set in all packets, meaning that packets can be interspersed at any time.

image

The purpose of last is two-fold. For one, it simplifies the process of transmitting "burstable" protocols such as UMI through switchboard. It also provides opportunities for performance optimization. For example, if a long sequence of SB packets is being sent over TCP, the TCP bridge knows it can wait to fill up its transmission buffer as long as last=0. Without the last bit, the bridge would have to send each packet one at a time (or speculatively wait for more packets), since any given packet may be the last one.

UMI interface

In addition to supporting data movement directly through SB packets, we provide a higher-level interface for running UMI transactions over switchboard connections. The mechanisms for this can be seen in the examples/umi* examples. Here's a sketch of what UMI transactions look like, adapted from the definition of python_intf() in examples/umiram/test.py:

from switchboard import UmiTxRx

umi = UmiTxRx(from_client, to_client, fresh=True)

wrbuf = np.array([elem1, elem2, ...], dtype)
umi.write(wraddr, wrbuf)

rdbuf = umi.read(rdaddr, num, dtype)  # also a numpy array

We are no longer creating PySbTx and PySbRx objects, but rather a single UmiTxRx object with two SB ports: from_client, and to_client. Transactions are sent by the Python script through the from_client port, and responses are received back through the to_client port.

UMI write transactions are generated with the umi.write() method, which accepts an address and numpy array or scalar as arguments. This sends out one or more SUMI packets to implement the write request, packing the data, source address, destination address, and command into SB packets. Since an SB packet is 416 bits, and the two addresses + command take up 160 bits, each SB packet contains up to 256b data. Switchboard automatically splits up larger transactions into multiple SUMI packets as needed, incrementing the source and destination addresses automatically. Optional arguments to write() control where a ack'd or non-ack'd (posted) write is used and the maximum amount of data to send in a single SUMI packet. If an ack'd write is used, write() blocks until the response is received.

In a similar fashion, umi.read() reads a certain number of words from a given address. For example, umi.read(0x1234, 4, np.uint16) will send out a UMI read request with dstaddr=0x1234, LEN=3, SIZE=1 from the SB port from_client. When it gets the response to that query on to_client, it will return an array of 4 np.uint16 words to the Python script. A umi.atomic() method is also provided to generate UMI atomic transactions.

Sometimes it is convenient to work directly with SUMI packets, for example when testing a UMI FIFO or UMI router. For that situation, we provide send() and recv() methods for UmiTxRx, highlighted in examples/umi_fifo/test.py. In that exampe, we are sending SUMI packets into a UMI FIFO, and want to make sure that the sequence of packets read out of the FIFO is the same as the sequence of packets written in.

The main while loop is essentially:

txq = []

while ...:
    txp = random_umi_packet()
    if umi.send(txp, blocking=False):
        txq.append(txp)

    rxp = umi.recv(blocking=False)
    if rxp is not None:
        assert rxp == txq[0]
        txq.pop(0)

In other words, first try to write a random packet into the FIFO. If successful, add it to the back of a list of outstanding packets. Then, try to read a packet from the FIFO. If successful, make sure that the packet is equal to the oldest outstanding packet (since this is a first-in, first-out queue) and remove that outstanding packet from our records. Continue in a loop until a sufficient number of transactions have been checked.

This code example demonstrates several features:

  1. send() and recv() for working with SUMI packets, represented using PyUmiPacket objects.
  2. blocking=False for non-blocking transactions. send() returns True if successful and False otherwise; recv() returns a PyUmiPacket if successful, and None otherwise. A transaction might be unsuccessful if the underlying UMI FIFO is full or empty. For example, if we don't call umi.recv(), eventually the FIFO will fill, and subsequent send() invocations will fail (returning False). Similarly, if we keep calling umi.recv() without calling umi.send(), eventually the FIFO will be empty, and umi.recv() will fail (returning None).
  3. The ability to generate random SUMI packets with random_umi_packet(). Various optional arguments can constrain the opcodes, addresses, and data.
  4. PyUmiPacket objects can be compared using Python == and != operators. This checks if two packets have equal commands, addresses, and data.

Queue format

Under the hood, SB ports are implemented using shared memory queues. The data structure used is made simple enough that RTL running on FPGAs can directly read and write to these queues, without the need for bridge programs. In fact, if two FPGAs have access to the same memory space, they can communicate through a shared memory queue without any involvement from the host operating system, after the initial setup.

The layout of the queue is:

  • Bytes 0-3: head (int32)
  • Bytes 64-67: tail (int32)
  • Bytes 128-179: SB packet
  • Bytes 256-307: SB packet
  • Bytes 320-371: SB packet
  • ...
  • Bytes 4,032-4,095: SB packet

To write an SB packet to the queue, compute next_head = head + 1. If next_head equals 62 (the end of the queue), then set next_head to 0. If next_head equals tail, then the write fails - the queue is full. Otherwise, write the SB packet to address 128 + (64 * head), and then set head to next_head.

Reading an SB packet works in a similar fashion. If tail equals head, the read fails - the queue is empty. Otherwise, read the SB packet from address 128 + (64 * tail), and then increment tail. If tail equals 62 (the end of the queue), then set tail to 0.

The queue implementation in C is in switchboard/cpp/spsc_queue.h, with care taken to avoid memory ordering hazards, and various cache-oriented optimizations. The queue implementation in Verilog (intended for FPGA-based emulation) can be found in switchboard/verilog/fpga/sb_rx_fpga.sv and switchboard/verilog/fpga/sb_tx_fpga.sv.

License

Apache 2.0

Contributing

switchboard is an open-source project and welcomes contributions. To find out how to contribute to the project, see our Contributing Guidelines.

Issues / Bugs

We use GitHub Issues for tracking requests and bugs.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

switchboard_hw-0.0.37-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (292.1 kB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

switchboard_hw-0.0.37-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (283.8 kB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARM64

switchboard_hw-0.0.37-cp311-cp311-macosx_11_0_arm64.whl (253.6 kB view details)

Uploaded CPython 3.11 macOS 11.0+ ARM64

switchboard_hw-0.0.37-cp311-cp311-macosx_10_13_x86_64.whl (257.9 kB view details)

Uploaded CPython 3.11 macOS 10.13+ x86-64

switchboard_hw-0.0.37-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (290.7 kB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

switchboard_hw-0.0.37-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (282.1 kB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARM64

switchboard_hw-0.0.37-cp310-cp310-macosx_11_0_arm64.whl (252.2 kB view details)

Uploaded CPython 3.10 macOS 11.0+ ARM64

switchboard_hw-0.0.37-cp310-cp310-macosx_10_13_x86_64.whl (256.7 kB view details)

Uploaded CPython 3.10 macOS 10.13+ x86-64

switchboard_hw-0.0.37-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (290.8 kB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

switchboard_hw-0.0.37-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (282.5 kB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARM64

switchboard_hw-0.0.37-cp39-cp39-macosx_11_0_arm64.whl (252.4 kB view details)

Uploaded CPython 3.9 macOS 11.0+ ARM64

switchboard_hw-0.0.37-cp39-cp39-macosx_10_13_x86_64.whl (256.9 kB view details)

Uploaded CPython 3.9 macOS 10.13+ x86-64

switchboard_hw-0.0.37-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (290.8 kB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

switchboard_hw-0.0.37-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (282.1 kB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARM64

switchboard_hw-0.0.37-cp38-cp38-macosx_11_0_arm64.whl (252.2 kB view details)

Uploaded CPython 3.8 macOS 11.0+ ARM64

switchboard_hw-0.0.37-cp38-cp38-macosx_10_13_x86_64.whl (256.6 kB view details)

Uploaded CPython 3.8 macOS 10.13+ x86-64

switchboard_hw-0.0.37-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (292.9 kB view details)

Uploaded CPython 3.7m manylinux: glibc 2.17+ x86-64

switchboard_hw-0.0.37-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (285.8 kB view details)

Uploaded CPython 3.7m manylinux: glibc 2.17+ ARM64

switchboard_hw-0.0.37-cp37-cp37m-macosx_10_13_x86_64.whl (252.8 kB view details)

Uploaded CPython 3.7m macOS 10.13+ x86-64

File details

Details for the file switchboard_hw-0.0.37-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0b25be69cb16a8ee06863f4af08d5a51340e0b9aee47abd7a959368c20e317e3
MD5 110ce4d07d14b7f266bd334a9cec1723
BLAKE2b-256 e5533e3fc835684f7a501be925fd921e3ececf8b1fc8513533a17e08232f21d4

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 a2b17222b07cdca33ac8a0d648ae49d0c16f7d9f879cc5f62fbbd6df1de5775c
MD5 4778a744b5a8174f5f549a6e7c267673
BLAKE2b-256 04cddf9797dee3507ba4486217ee0c53c94e45e3434ef91eeacbabe779e4dbac

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 03aed30af146d76d46fa0f758f03d062a2276e98ef179d0c70415cfe184884b3
MD5 5377b1bc63210120ae1d3cd49da12115
BLAKE2b-256 fea3b3140c02a4a2838197926409909f1ffe7f75ba297ce11de9a550eddc061d

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp311-cp311-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp311-cp311-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 787d738e79e7b3a0a924d135843e0204219460e81740af8cb9c139713ad4fdfa
MD5 7b6aa8be65941af827f486489a04226f
BLAKE2b-256 cd644930a09704601ad96628deff612dd4bccf8047847a22a3cbd1418c58068b

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1e685f11b5f60352d3553edfe9aeb0e47eae9a36165b03e9389ac67ebf68f69f
MD5 be0345c2a4501c4aa61d8b1b11e94b41
BLAKE2b-256 c7f9f76bcbd504aeaccad0bdc9231428e1306127f1cba1da5b16437e70c1c7be

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 8792acbbf99ffa97b29be5441fa2e88ed29e0a5596e9493272cb332fa8d72f7c
MD5 493119fe387d2833678835db616bc41a
BLAKE2b-256 aff6a2ba7d4b432200dfe74b749ad0e4f83ee2d00a89daed1b07818b6e5538e1

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b53a8e1a39d9315ecf838254133dafa713c446cdae0673d7edcba48debad2c66
MD5 4877fb03d5b41a3e0120d65a5a0d650c
BLAKE2b-256 1f5ac0f3da05c64f10de31e6edb59ab02004a2c9790d0d6ea4364c6f6b2a6491

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp310-cp310-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp310-cp310-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 ce26b231c9fedcfde529e8ae80ddfda86afd32bea09f745f412fbd487441d5fa
MD5 fc13c9fc96ead2cf0e22355e0aa9894e
BLAKE2b-256 385cf49c7c0ee1b45853fbf60ba3c328165d9756d530f83283c2e29bd635069c

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 592a6afdefdae640d3f16b4ea9b9891d3bca76997b522ae863d2c24de1c4da5c
MD5 4882e61d42c281fe720b505d08e55017
BLAKE2b-256 033b9b5e325bbf2d34f37f555e6025c4151484aef5123a4ec99486429a449946

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 00150fe923b8a07a70094da35c3f57d442b3c7b8f0b9b253b9af81404d3d036e
MD5 42da78f2119ee9742dcd90b93d3d81f5
BLAKE2b-256 8807028d798e40701ac47606f7bb1a6a96aafaae0e8ab7500d68ad9ec9263cb0

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 396bd9c26f5e25295b23ceb4e74aa427008935f68f67bb955ebcef7af59c6d33
MD5 5d79f3b666e57f8e20e14ddd7c6cccf4
BLAKE2b-256 2bef7cb1bea223116b22303bed3b18d8818f0a00b7981870b79fe7edbc0bdfcf

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp39-cp39-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp39-cp39-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 16467cc9054a31a3cf8f616581dd8ed40f5b32135e3bbb8c6054f3fea375784f
MD5 a18e0778af37842363a0fbc962d2041e
BLAKE2b-256 11adc98935be5996bbcac5c0d98c50fdb89b3757afaf5f0414a2eb2d489ceaa9

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9f4864fbb753ae6b4f6d6a856203108094b91979b32167b653759234c0442913
MD5 d3738e82ffeb13d933cc086d5b3d1726
BLAKE2b-256 26e5c477ef2382f6c606fc3b69208aa14921ee1d2e298349859165191fe7d9e5

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 cb9cd6575105de76013baac4ba88486f7ecc41c170af43d506e1027be0b71af8
MD5 25cfae85199591129095360d1e432a27
BLAKE2b-256 7dfb74e18757269333b1e6d3db4a9d9cfa8620ccc63989710f711aa6979cbdb9

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp38-cp38-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2755242f2266f1ea81747e82d2e8176e29854a6aabff8abbabe3491265fe4554
MD5 09fa25f3890a543821022d63e9ccffac
BLAKE2b-256 4238ff82204a52aed904cd083ab308acbd73cef44206963cacd735865b64efdf

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp38-cp38-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp38-cp38-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 3fa07095278b8eb3cf6dfa0ef6b12d1ddc07a28033589787574317862547a622
MD5 702f989580145b2d39ce11bce54e6bd0
BLAKE2b-256 c6a0c285734c6270bee671b78b85be0a46ef86239b219f9fac7d60a9e0c24003

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fa6c1726f22a855c28edd1daa6e42ef4a64a3f32cf65177b71d9ae36f060e75e
MD5 477f9a44a835a144f2de6fadab28c56a
BLAKE2b-256 23566d55bbd4621d86fc703fefe24030e6d2fac12d3f767dfd3534d2e549d25f

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 1bab9df8b421b783f2637b2f2f6c01465a72b4a4e49f1006bec4d3a882c57242
MD5 224c54365db91424d9fef13af41a1869
BLAKE2b-256 dc0f62964d531d0ca5984dda7c5e9892569220f4e2453d65dc62d18cc777178f

See more details on using hashes here.

File details

Details for the file switchboard_hw-0.0.37-cp37-cp37m-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for switchboard_hw-0.0.37-cp37-cp37m-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 284f95d7d597ab227a5d698435f55386b12144ecd5fc721dd452d6658c9f3c67
MD5 a1ff13604a2ab0f0241ac8cfde891813
BLAKE2b-256 13f901921a931cf49d4d14d59babb875afad3e278b5c17ae5102735b07138cfc

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page