Summary
Here is how you can set up a hardware server (hw_server
) in AMD Vivado 2023.2, in such a way that you can move your workbench to a virtual machine in your cloud of choice - mine is GCP - but program a device which is attached to a machine that’s close to you.
The FPGA device in question is an AMD Artix-7 A200T. I suspect any other device supported by Vivado will work too. This is a much more advanced setup than what is described on the AMD help site. That setup assumes a local server, a local hardware attachment point, and it does no authentication. In contrast, this setup uses ssh
tunneling to set up a secure connection between the workbench machine and the programming host, so that it can be used between any two machines on the Internet so long as they can see each other via a TCP connection.
NOTE 2024-11-04: In this article, am using a programming host which is an Intel
x86_64
machine, and a workbench host which is also an Intelx86_64
machine. This makes it possible for the programming host to usehw_server
binaries and libraries directly from a Vivado distribution. That, of course, will not work if your programming host is an ARM machine. If you have a non-Intel programming host, you might need to find a different programming solution.
Why?
Here is why I wanted do this, and why you may want to do it too:
- Remove the need for a local workbench. You don’t need a beefy local machine.
- Hardware development is notoriously memory and CPU hungry. If you need to, you can beef up your GCP machine way easier than any physical hardware you have locally.
- If you got to a point where you needed a build farm for more efficient compilations, you can do that as well.
- You can access your hardware from anywhere. I can be at the poolside in Florida, and program my FPGA which sits in my California home. (I should be relaxing at the poolside, yes. But sometimes my brain just goes places.)
Background
I wanted to have a remote programming setup, because I wanted to have my Vivado workbench in a virtual machine on GCP, while the actual device to be programmed would be attached locally to my development server.
You may want to do that if you have large designs which you need a lot of horsepower to synthesize. By moving your workbench to the cloud, you can set up a large enough machine that synthesis lasts a reasonable amount of time.
I originally wanted to use usbip, but I could not make it work. I got pretty far, but this low level approach just didn’t seem to work well for unreliable connections.
Luckily I realized that the hardware server utility hw_server
which you can find in Vivado’s bin
directory can be used from a remote machine. This is the setup I used to make this a reality.
Procedure
This procedure is for a noname programming device that uses the FTD FT232H device, plugged into a local port on my local Linux server running Ubuntu 22.04. Here’s the output of lsusb
:
╰─>$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 8087:8001 Intel Corp. Integrated Hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 004: ID 8087:0a2a Intel Corp. Bluetooth wireless interface
Bus 002 Device 005: ID 5986:0366 Bison Electronics Inc. Integrated Camera
Bus 002 Device 012: ID 0403:6014 Future Technology Devices International, Ltd FT232H Single HS USB-UART/FIFO IC
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 002: ID 0bc2:ab24 Seagate RSS LLC Backup Plus Portable Drive
The device listed at Bus 002 Device 012 is our programmer.
The first thing to do is to install the Digilent runtime on the Linux machine This does two things: it adds an entry into /etc/udev/rules.d
, and adds a utility that prevents the Linux FTDI driver from activating for the programmer. You do not want this driver to get activated.
The correct activation log in /var/run/dmesg
is as follows:
2024-06-19T09:57:15.043323+00:00 filmar kernel: ftdi_sio 2-1:1.0: FTDI USB Serial Device converter detected
2024-06-19T09:57:15.043339+00:00 filmar kernel: usb 2-1: Detected FT232H
2024-06-19T09:57:15.043341+00:00 filmar kernel: usb 2-1: FTDI USB Serial Device converter now attached to ttyUSB0
2024-06-19T09:57:15.056319+00:00 filmar kernel: ftdi_sio ttyUSB0: FTDI USB Serial Device converter now disconnected from ttyUSB0
2024-06-19T09:57:15.056332+00:00 filmar kernel: ftdi_sio 2-1:1.0: device disconnected
You specifically want that last line to appear. The last two lines mean that the Linux’s fdti_sio
driver has attached to the USB device, but is then immediately detached. This will allow hw_server
to open the device later. No matter how counter-intuitive, this disconnection means that the programmer is ready to be used.
Another thing you must use is to remove the “manufacturer” line from /etc/udev/rules.d/52-digilent-usb.rules
. This allows any device, no matter the manufacturer, to be treated as a Digilent device. Here’s how the file looks like on my machine:
ATTR{idVendor}=="1443", MODE:="666"
ACTION=="add", ATTR{idVendor}=="0403", MODE:="666", RUN+="/usr/sbin/dftdrvdtch %s{busnum} %s{devnum}"
NOTE: This works only because practically all JTAG programming interfaces on these boards use the exact same FTDI chip. If you are unlucky enough to have something else there, then you will need to find a different solution.
Next, you need to excavate the hw_server
and libraries from your Vivado installation on your workbench, and move them to your local Linux machine. Here is the minimum list of files you need to be able to run the server locally. You can just dump them into some directory. Here is how I did it:
╰─>$ ls -al
total 41420
drwxrwxr-x 1 f f 280 Jun 19 02:51 ./
drwxrwxr-x 1 f f 194 Jun 26 22:10 ../
-rw-rw-r-- 1 f f 2500398 Mar 19 17:17 digilent.adept.runtime_2.27.9-amd64.deb
-rwxr-xr-x 1 f f 33311200 Jun 19 01:01 hw_server*
-rwxr-xr-x 1 f f 136352 Jun 19 01:13 libdabs.so.2*
-rwxr-xr-x 1 f f 18112 Jun 19 01:14 libdftd2xx.so.1*
-rwxr-xr-x 1 f f 20808 Jun 19 01:05 libdjtg.so.2*
-rwxr-xr-x 1 f f 12064 Jun 19 01:13 libdmgr.so.2*
-rwxr-xr-x 1 f f 2347192 Jun 19 01:04 libdpcomm.so.2*
-rwxr-xr-x 1 f f 52256 Jun 19 01:03 libxftdi.so*
-rwxr-xr-x 1 f f 3995096 Jun 19 01:13 libXil_lmgr11.so*
This will allow you to run the hw_server
from this directory as follows:
/usr/bin/ld.so --library-path $PWD \
./hw_server -stcp::3121 \
-L- -l jtag -l jtag2 \
-l events -l slave -l proxy
The startup is a bit convoluted because for some reason my installation does not honor LD_LIBRARY_PATH, so I had to pass the --library-path
directly to the ld.so
interpreter. The server will be started attached to port 3121 on your local machine.
NOTE: This only works because my programming host is a 64-bit Intel machine. If you want your programming host to be something else, you will need to figure it out yourself.
Next is to open up the ssh
port on your local machine, and possibly your router, so that you can start the tunnel.
From your workbench GCP you can tunnel the port 3121 on your machine to port 3122 on GCP:
ssh -L 3122:localhost:3121 \
f@myserver.xyz -p 8022
I use port 8022 for ssh to avoid exposing the standard SSH port 22. This should log you into your local Linux machine from your GCP workbench, and also tunnel the port 3121 on your local Linux machine to port 3122 on your GCP workbench.
This will allow you to attach a “remote” programmer from the Vivado hardware manager, by attaching to localhost:3122
. You should be able to see the JTAG chain just as if the device had been attached to the GCP workbench. I have found this setup to work quite reliably.