wishbone-tool
- All-in-one Wishbone Binary and Librarywishbone-tool
is useful for interacting with the internal Wishbone
bridge on a device.
Some of the things you can use wishbone-tool
for:
devmem2
Currently-supported Wishbone bridges include:
--baud
)wishbone-tool
) or UDP (via Etherbone)Precompiled versions of wishbone-tool
can be found in the
Releases
section.
To build wishbone-tool
:
wishbone-tool
directory.cargo build
or cargo 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
by default.
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:
sh
$ 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:
sh
$ 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:
sh
$ 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.
```python class MySoC(SoCCore): def init(self, platform, sysclkfreq): SoCCore.init(self, platform, sysclkfreq, 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.
wishbone-tool
as a LibraryYou can also use wishbone-tool
as a library from within your own program.
For example, there is a kind of device that has a USB bridge with a small random number generator at address 0xf001_7000. This device has a simple API:
1
to 0xf001_7000 to enable the device0xf001_7008
is 1
there is data available0xf001_7004
We can turn this into a command that reads from this RNG and prints to stdout:
```rust use std::io::{self, Write}; use wishbone_tool::{Bridge, BridgeError, BridgeKind, Config, UsbBridgeConfig};
fn main() -> Result<(), BridgeError> { let stdout = io::stdout(); let mut handle = stdout.lock();
// Create a configuration object with a USB bridge that
// connects to a device with the product ID of 0x5bf0.
let mut cfg = Config::default();
cfg.bridge_kind = BridgeKind::UsbBridge(UsbBridgeConfig {
pid: Some(0x5bf0),
..Default::default()
});
// Create the USB bridge and connect to it.
let bridge = Bridge::new(&cfg)?;
bridge.connect()?;
// Enable the oscillator. Note that this address may change,
// so consult the `csr.csv` for your device.
bridge.poke(0xf001_7000, 1)?;
loop {
// Wait until the `Ready` flag is `1`
while bridge.peek(0xf001_7008)? & 1 == 0 {}
// Read the random word and write it to stdout
handle
.write_all(&bridge.peek(0xf001_7004)?.to_le_bytes())
.unwrap();
}
} ```