One of the most annoying things when working on an early design on an FPGA development kit is a lack of run-time register interfaces without a lot of effort.
While looking for an interface that would work on basically any Vivado supported Xilinx FPGA I came across the JTAG to AXI Master core supplied by Xilinx. Unfortunately it has a cumbersome interface that is intended for the user to drive from Vivado’s TCL console which is not always the most convenient. Others have been looking for a C API to interact with the hw_server directly. There seems to be someone that has had put together a C library but I was unable to get the files. I wanted something easier to use anyways so I began to look elsewhere for a solution.
Accessing JTAG2AXI from XSDB
I remembered that XSDK, XSCT and XSDB has the ability to read/write memory on the Xilinx SoCs so I thought to try the mrd
and mwr
in XSDB.
Running xsdb in a terminal.
$> xsdb
Connecting to the hw_server and JTAG cable.
xsdb% connect tcfchan#0
Searching for debug target.
xsdb% targets 1 APU 2 ARM Cortex-A9 MPCore #0 (Running) 3 ARM Cortex-A9 MPCore #1 (Running) 4 xc7z010 5 Legacy Debug Hub 6 JTAG2AXI
We see above that the JTAG2AXI core we put in our design which we have already programmed to the board shows up so we select it.
xsdb% target 6
Trying the mrd
command results in a valid read!
xsdb% mrd 0 0: 0000000A
Accessing JTAG2AXI from Python
While performing memory read and write without the TCL commands in Vivado but from XSDB is great… I wanted a way to interact with the JTAG2AXI bridge from other software. While looking for a solution I found pysct, a Python interface to XSDB and Vivado!
After installing pysct, connecting to XSDB is as easy as starting xsdb in a terminal then creating a server and connecting to it from Python.
$> xsdb xsdb% xsdbserver start -port 3010
from pysct.core import * xsct = Xsct('localhost', 3010) xsct.do("connect") xsct.do("target 6") print(xsct.do("mrd -value 0")) # xsct.do("mrd -value 0 256") performs a read burst of 256 words instead of 1.
By default the mrd
command returns data formatted for human reading with addresses and data in HEX format. This slows stuff down a lot. Using the -value
or -bin
option is recommended for higher speed.
I noticed some issues in pysct and had to modify the recv() function in the Xsct class to have a much larger buffer size, setting it to 32768 allowed AXI4 bursts of 256 to work.
Performance Testing
With the JTAG cable on the Digilent Zybo board set to 30 MHz I ran some performance tests.
Running some performance tests on an AXI4Lite variant of the core in Python results in about 9 kilobytes/s of read transfers.
If we use the AXI4 variant of the core and use mrd -value 0 256
to perform max length bursts we get about 1.2 megabytes/s of read transfers! Pretty decent!
I would get the following errors when I try to connect – xsct.do(‘connect’)
Traceback (most recent call last):
File “C:\Anaconda3\envs\py3dev\lib\site-packages\IPython\core\interactiveshell.py”, line 3326, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File “”, line 1, in
xsct.do(‘connect’)
File “C:\Anaconda3\envs\py3dev\lib\site-packages\pysct\core.py”, line 221, in do
ans = self.recv()
File “C:\Anaconda3\envs\py3dev\lib\site-packages\pysct\core.py”, line 205, in recv
data = self._socket.recv(bufsize)
socket.timeout: timed out
How can I get this to work?
I am able to connect from the xsdb terminal the port is not the issue.
Maybe try in a regular Python 3 instance instead of in an ipython interactive shell?