Introduction
Sending a bitstream to the FPGA typically involves using a graphical user interface. Tools like Vivado's Hardware Manager provide this functionality, however the procedure often feels too complicated for this simple task. In particular, when there is only one FPGA connected to the computer through one single JTAG cable, the user interface requires a lot of unnecessary steps. If there is only one FPGA, why can't the computer deduce that it should write the bitstream file to this FPGA? Why is it necessary to explicitly tell the tools what we want to do? There is really only one option.
A possible solution is to use a bash script that performs this task in one step. This script finds the FPGA that is connected to the computer through a JTAG cable, and sends the bitstream file to this FPGA.
The script
This is the script that sends a bitstream file to the FPGA:
#!/bin/bash
set -e
if [ "$#" -ne 1 ]; then
echo "Usage: $0 bitstream-file.bit"
exit 1
fi
if ! which vivado >/dev/null ; then
echo Vivado is not in the execution path. Please run something like
echo source /path/to/..../Vivado/20nn.n/settings64.sh
exit 1
fi
if [ ! -f "$1" ] ; then
echo \"$1\" file doesn''t exist
exit 1
fi
if vivado -mode batch -nolog -nojournal -source /dev/stdin -tclargs "$1" <<"EOF"
# Tcl script begins here.
set bitfile [lindex $argv 0]
open_hw
connect_hw_server
open_hw_target [lindex [get_hw_targets -of_objects [get_hw_servers localhost*]] 0]
set thefpga [lindex [get_hw_devices] 0]
set_property PROGRAM.FILE "$bitfile" $thefpga
set_property PROBES.FILE {} $thefpga
current_hw_device $thefpga
refresh_hw_device -update_hw_probes false $thefpga
program_hw_devices $thefpga
# Tcl script ends here
EOF
then
echo -e "\nProgramming successful.\n"
else
echo -e "\nProgramming failed.\n"
fi
Note that this bash script contains a Tcl script. One of the arguments that is given to the "vivado" command is "-source /dev/stdin". This causes Vivado to read the Tcl script from standard input. The well-known "here document" method is used with the help of "<<".
Using the script
Write the script shown above to a file, for example with the name fpga_program. Make this file executable with a command like this:
$ chmod a+x fpga_program
Before attempting to run the script, set up the environment variables with a command similar to this:
$ source /opt/xilinx/Vivado/2023.1/settings64.sh
Change the "/opt/xilinx/Vivado/2023.1" part in this command so that the path reflects the place where Vivado is installed on your computer.
Then run the script with a command like this:
$ ./program_fpga myproj.bit
Of course, change "myproj.bit" to the name of your bitstream file.
Vivado produces a lot of output while this script is running, however the last row is either "Programming successful" or "Programming failed".
A few comments about the script
This script has been tested on Vivado 2015.2 and Vivado 2023.1, so there is a good chance that it works with all versions of Vivado. However, with recent versions of Vivado, the software prints out the following warning:
WARNING: 'open_hw' is deprecated, please use 'open_hw_manager' instead.
The script works despite this warning. However, it's possible that future versions of Vivado will not recognize the "open_hw" command. If this command causes an error, change this command in the script to "open_hw_manager".
Another possible change to the script relates to the amount of output that this script generates. If you don't want so much text output, add a redirection so that the output goes to /dev/null.
If you want this, find this row in the script:
if vivado -mode batch -nolog -nojournal -source /dev/stdin -tclargs "$1" <<"EOF"
And change it to:
if vivado -mode batch -nolog -nojournal -source /dev/stdin -tclargs "$1" > /dev/null <<"EOF"
Stopping the hardware server
If you use multiple versions of Vivado on the same computer, there might be difficulties with the connection to the JTAG cable. The reason for this problem is that Vivado uses a TCP/IP server for the purpose of talking with the hardware (listening to port 3121). Vivado starts this server automatically as necessary.
But if the server was started by one version of Vivado, and another version of Vivado attempts to connect with the FPGA, the communication might not work. The reason is that the version of the server is the same as the version of Vivado. This situation also occurs when using Hardware Manager with the graphical user interface.
When this problem occurs, the server can be stopped with this command:
$ killlall hw_server
Note that the server stops running by itself if it's not used for a period of time.