wishbone-tool
is useful for interacting with the internal Wishbone
bridge on a device.
Some of the things you can use wishbone-tool
for:
- Peeking and poking memory, similar to using
devmem2
- Testing memory and bridge link quality
- Exposing a Wishbone bridge to Ethernet
- Attaching a GDB server to a softcore
Currently-supported Wishbone bridges include:
- USB - For use with Valentyusb such as on Fomu
- Serial - Generic UART, nominally running at 115200 (but can be
changed with
--baud
) - SPI - Using 2-, 3-, or 4-wire SPI from spibone
- Ethernet - Both TCP (e.g. a remote copy of
wishbone-tool
) or UDP (via Etherbone) - PCI Express - Using a PCIe softcore with the CSR register bank exposed
Precompiled versions of wishbone-tool
can be found in the
Releases
section.
To build wishbone-tool
:
- Install Rust and Cargo. The easiest way to do this is to go to https://rustup.rs/ and follow the instructions.
- Enter the
wishbone-tool
directory. - Run
cargo build
orcargo build --release
The wishbone-tool
binary will be located under target/debug/
or
target/release/
.
By default, wishbone-tool
will communicate via USB, attempting to
open a device with PID 0x5bf0
. It will also run the peek/poke
server, allowing basic manipulation of memory addresses on the target device.
Simply run wishbone-tool [ADDRESS]
to peek at a particular address.
To specify a particular vendor ID, pass --vid [ID]
, for example --vid 0xb0f1
.
To read from an area of memory (such as 0x10000000), run:
$ # Read from address 0x10000000 via USB
$ wishbone-tool 0x10000000
INFO [wishbone_tool::usb_bridge] waiting for target device
INFO [wishbone_tool::usb_bridge] opened USB device device 019 on bus 001
Value at 00000000: 6f80106f
$
To write a value to memory, add an additional parameter:
$ wishbone-tool 0x10000000 0x12345678
INFO [wishbone_tool::usb_bridge] opened USB device device 019 on bus 001
$ wishbone-tool 0x10000000
INFO [wishbone_tool::usb_bridge] opened USB device device 019 on bus 001
Value at 00000000: 12345678
$
You can connect to a serial port by specifying the --serial
argument:
$ wishbone-tool --serial COM4: 0x00000000
Value at 00000000: ffffffff
$ wishbone-tool --serial /dev/ttyUSB0 0x00000000
Value at 00000000: ffffffff
Ensure that you have write permission to the serial port. On some Linux
systems you may need to add your user to the dialout
group.
To connect to an Ethernet device, pass the --ethernet-host
parameter:
$ wishbone-tool --ethernet 192.168.100.50 0x00000000
Value at 00000000: ffffffff
To connect to a different port, add --ethernet-port PORT_NUMBER
. Finally,
if you would like to connect to another copy of wishbone-tool
or to a copy of lxserver
, add --ethernet-tcp
to switch the connection from Etherbone to TCP.
If your device is connected via PCI Express, you can specify a PCIe BAR with --pcie-bar FILE_PATH
. This will be a device under /sys/bus
.
Note that when running in PCIe mode, only a small portion of the memory space
is exposed. This means that you may need to specify --register-offset OFFSET
, because e.g. address 0 in the PCIe BAR may actually correspond to address 0xe0000000, and wishbone-tool
needs to know how to perform the translation.
If you specify --spi-pins
, wishbone-tool
will communicate with the target device via SPI. This is currently only supported on Raspberry Pi. Specify the physical Broadcom Pin numbers. Consult Pinout.xyz for more details. For example, assume you want to connect COPI,CPIO,CLK, and CS_N to pins 3,5,7, and 12 on the Raspberry Pi header. If you consult that website, you'll see pin 3 is BCM2, pin 5 is BCM3, pin 7 is BCM4, and pin 12 is BCM18. Therefore, the argument you would provide to wishbone-tool
is --spi-pins 2,3,4,18
If your bridge is over a UART, then that means your UART is already in use,
and isn't available for use as a console. Or if you're connecting via some
other medium and you only have a single cable connecting the two devices. LiteX supports creating a
"crossover" UART that wishbone-tool
can interact with and present a
local terminal on.
To add a UART bridge and a crossover UART to your design, instantiate the
main SoC object with uart_name="crossover"
and add a separate Wishbone
bridge.
class MySoC(SoCCore):
def __init__(self, platform, sys_clk_freq):
SoCCore.__init__(self, platform, sys_clk_freq, uart_name="crossover")
# Add a bridge with the real UART pins
self.submodules.uart_bridge = UARTWishboneBridge(
platform.request("serial"),
sys_clk_freq,
baudrate=115200)
self.add_wb_master(self.uart_bridge.wishbone)
Then, to interact with the terminal, run wishbone-tool
and provide it
with the csr.csv
file from your build, and add the -s terminal
flag:
$ wishbone-tool -s terminal --csr-csv build/csr.csv
$
Note that you can run multiple wishbone-tool
servers at the same time.
For example, to run the gdb
server as well, run:
$ wishbone-tool -s gdb -s terminal --csr-csv build/csr.csv
$
To exit the session, press Ctrl-C
.
If your softcore has a Vexriscv CPU in it, you can enable debug mode
and use wishbone-tool
to act as a gdbserver.
You can generate auto-completion for wishbone-tool
with the -c
option. For example, to generate auto-completion for bash, run:
$ wishbone-tool -c bash > wishbone-tool.bash
$ . wishbone-tool.bash
$
Auto-completion is available for zsh, bash, fish, powershell, and elvish.
You can also use wishbone-bridge
as a library from within your own program.
For more information, see the wishbone-bridge documentation.