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.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (291.9 kB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

switchboard_hw-0.0.36-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (283.6 kB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARM64

switchboard_hw-0.0.36-cp311-cp311-macosx_11_0_arm64.whl (253.4 kB view details)

Uploaded CPython 3.11 macOS 11.0+ ARM64

switchboard_hw-0.0.36-cp311-cp311-macosx_10_13_x86_64.whl (257.7 kB view details)

Uploaded CPython 3.11 macOS 10.13+ x86-64

switchboard_hw-0.0.36-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (290.4 kB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

switchboard_hw-0.0.36-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (281.9 kB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARM64

switchboard_hw-0.0.36-cp310-cp310-macosx_11_0_arm64.whl (252.0 kB view details)

Uploaded CPython 3.10 macOS 11.0+ ARM64

switchboard_hw-0.0.36-cp310-cp310-macosx_10_13_x86_64.whl (256.5 kB view details)

Uploaded CPython 3.10 macOS 10.13+ x86-64

switchboard_hw-0.0.36-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (290.6 kB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

switchboard_hw-0.0.36-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (282.2 kB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARM64

switchboard_hw-0.0.36-cp39-cp39-macosx_11_0_arm64.whl (252.2 kB view details)

Uploaded CPython 3.9 macOS 11.0+ ARM64

switchboard_hw-0.0.36-cp39-cp39-macosx_10_13_x86_64.whl (256.7 kB view details)

Uploaded CPython 3.9 macOS 10.13+ x86-64

switchboard_hw-0.0.36-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (290.5 kB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

switchboard_hw-0.0.36-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (281.9 kB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARM64

switchboard_hw-0.0.36-cp38-cp38-macosx_11_0_arm64.whl (252.0 kB view details)

Uploaded CPython 3.8 macOS 11.0+ ARM64

switchboard_hw-0.0.36-cp38-cp38-macosx_10_13_x86_64.whl (256.4 kB view details)

Uploaded CPython 3.8 macOS 10.13+ x86-64

switchboard_hw-0.0.36-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (292.7 kB view details)

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

switchboard_hw-0.0.36-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (285.6 kB view details)

Uploaded CPython 3.7m manylinux: glibc 2.17+ ARM64

switchboard_hw-0.0.36-cp37-cp37m-macosx_10_13_x86_64.whl (252.6 kB view details)

Uploaded CPython 3.7m macOS 10.13+ x86-64

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9b03bb7b5f088aa5941bf440dd99847ee4bf71f3549f8062f0d9718181dcfc6c
MD5 2a8072a56dc3b12ebd2ec1dd840dce70
BLAKE2b-256 39231d390574e1359df942d68ea1b1d868ed5a59108345e2bd56797bc1a3cec1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c20f48836a70d67591f2463c31d0e67c0a4fd0450a4174e61ca6ff5c3fa1ae7d
MD5 391747f15c035e0d7dce24873fa30353
BLAKE2b-256 948c5a1a98e1badc2f0508d257c01c418a65fb71b6192797d4c8c3a8ff8758c9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 44d2fc9f88d5a8028a162b010e6944fcc5634e377f7f45bb4a557af91840bab9
MD5 9dd615c9e5515f818e8d21f5a6daf9a0
BLAKE2b-256 d68d7d87e91b868a93afdb23f90b95cc886b31507f3edf64cd44f6d9e2daa934

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp311-cp311-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 23493eb6889de23fdc2037212668165586af6b7d3df0d0fb146cadcb284ecb57
MD5 dd93ef98347e77da8dadbf3786b90b16
BLAKE2b-256 aba5fb5abb2fb0c66e1e2595634ece2940647d62059035786546500ac04c90ef

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b84015b534d7da8da36e5c12ee669c2eb802d4b6fac1d1a1ca0da6e9f9abec1c
MD5 78cc69aa22467d3c2db15dc17d11b2e2
BLAKE2b-256 709aaeae4cb7a2e625b73975e8b4ad7bb5f59aba116ddcbd9f0d19b70a3c970f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e5e41125eeb759d5c5da794cab205afd120666a51215851e82f107bcb6e94c36
MD5 ab211a1de610b7ad16ae760263ff554e
BLAKE2b-256 c36760d8eca1feb4e8945c19721f2d66bc3ce5432791a25d952759161688b223

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 fef2b8f6d15318c3e31df20185040ed5da1a2702ed4e8a37ad3fa43ac75a4073
MD5 3488ddb5eda85cbb2dd9d7e32bb2709b
BLAKE2b-256 b310cd4f5b72f25e74ffb93345ecf186039925e9f3a056d810766c3b897872ae

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp310-cp310-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 7c383ba13714b556ab46240665f89ac76eb3bfa493ac54e5ce877284682b83b2
MD5 24be38263f0630f8ae9004c7e67ba0d8
BLAKE2b-256 1364a4b133997ce4edc54ac5625bb59005e83e395c53d01d95445bd241822056

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a4fccc2df92e4ad17c7b0bd678f1af20ce781c3fca5299b30fe4c3a7932d4b1a
MD5 bd009c52d3ae18f60e71d48557afdd53
BLAKE2b-256 35ab7397cc6effd4f7d3964494809e95721df5515afff365aad12389e18d1ec1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c164ddb97237ae5b29c6ea01d4b398d08a5014f8c8a5475899cb14ad352aaea2
MD5 698cc8b1c5400428306a054428dbd140
BLAKE2b-256 4baa454ecb3eb6fbe41b040afab246209f84b7ded34cb7da1841fe65bc6a9307

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 e2642530f811bfaf2879fe16445caee1b561f77fe3bf9b2cc9454cb59142d415
MD5 28c2ade4ba76307de440f8e536b22843
BLAKE2b-256 a3d5c34a1e05eb90bcbe00b1bd7b29583b5f5d06d537aa796f0d648367912a12

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp39-cp39-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 d93c54ba1d2ae286f613b82f53e95f431fb4327b7a4aa3f00c40d6232cd61f0b
MD5 48e54997ade5b33f213e12507d0c29ed
BLAKE2b-256 7e409ce946804df1780181c619651f6cc333ed38548f67db919849cc599b18c0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 440ec3ca74f86710f1595f3c1ca9d6806fec96a541e602c838ce4c360add9973
MD5 e35941d0125f5cf700c9d73eaae37e99
BLAKE2b-256 c52adf934b18571160182ae9015ae56ebd5471d564e566ba2ef73820b9348e12

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 363662165aa46228291247eb5d9b85ae5bf45fe17b36e3ab13763ca23d2458e4
MD5 f0952aa55cc0dee4f8fd1c7cd1ff0a5f
BLAKE2b-256 92043ab4d168d9747c48efb47267f649871445d463fbb9138bd456db5e126aa5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 86d73676743128cfb597e5b3071f046efdf5a77232b89fa3875d75f65a325b39
MD5 4c298c08b6c8e38c23c312dce574060b
BLAKE2b-256 68ec8d8101a5c616a4cecc593140b9eab41ee7f3d9390273d2482e59d7352d93

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp38-cp38-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 f68173983d4ed5b9d0b2b7188f2cd4fde0289d82e453a4ca9afa60cbec27e73b
MD5 182b7cfa37c385c2b4dad72efc3728de
BLAKE2b-256 873aa71b643a6664320d74593a1c8cbcf1d48375e18656de2dec9c44c9dc4c22

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9ff252269e0a0dd5a973300929d269248b80f9c3557333073f82e0e29142404d
MD5 b14aa0fe7c0632aefca33a99274cfd01
BLAKE2b-256 56209997d47a6f4cc621bc08ebc51aadcfea6c39a573d36fd0a16ee7f49db05e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e11feadb1358dbe2055e4a805a8ab82c46ee140c23190c67c44266bd9449522b
MD5 83405d5379bbda54a7a98610bf2ba076
BLAKE2b-256 40c8d498f88fe05abd9c3efbe15162178c42c2112fd20f4a45a2a4ab6d7c8ffa

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for switchboard_hw-0.0.36-cp37-cp37m-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 d3f6bd85878efdc8a93ff35e0297b6a0191b56360010734443a08163c4d4a219
MD5 2e02553aa4782b5d5e3c94cfb86bd488
BLAKE2b-256 f30e70e4b59f171c7e142194734ebda1693a7ed2763ceb93f76b98401341799c

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