To debug a program, GDB is the de facto standard tool. At the software level, it relies on signal and hardware-assisted mechanisms to halt the execution of a program on predefined events and allow deep inspection of the machine state (register, RAM). In the hardware world, the JTAG standard (initially used for verification and test of integrated circuits) allow direct access to the core, and specifies a test access port that can be used to query and set CPU and memory states. However, several hardware and software components are needed to interact with the CVA6 over JTAG:
In our case, we will use the PS-side Linux to interact with the JTAG interface using MMIO-mapped registers through an AXI bus. The idea is the following:
Warning: The AXI bus is NOT resilient to faults and unexpected disconnection. Therefore, if you flash the bitstream with an active OpenOCD connexion, then all PS-side IPs will be bricked, and you will have to reboot the board to access PS-side Linux again!
In this section, we will:
In the block design, customize the “ZYNQ7 Procesing System” and tick the “M AXI GP0 interface” to be able to use the PS AXI port.
Add an AXI-to-JTAG Converter block, and connect the AXI port to the newly created M_AXI_GP0
port on the ZYNQ7 PS using the connection automaton (pop-up message). In the address editor, it creates a new “Network 2” entry. auto-assign the AXI JTAG address: it should be mapped at 0x43C00000
.
Connect the other part of the AXI-to-JTAG Converter block to a new debug_mode_wrapper
block (to add it, use right click -> Add Module…). Its signals must be connected to:
aclk
is tied to the 25 MHz clockaresetn
to the interconnect_aresetn
signal (Processor System Reset block)s_axi_dmi_jtag_awatop
is either left unconnected (will give a critical warning at synthesis) or tied to the constant block atop_tieoff_0
jtag_trst_n
to the peripheral_aresetn
signal (Processor System Reset block)m_axi_dmi_jtag_awatop
is left unconnected (constant) blockdebug_req_irq
output pin must be connected to the CVA6 core debug_req_irq
(which you need to disconnect first, as it is by default tied to a constant 0)jtag_xxx
signals are tied to corresponding signal of the AXI to JTAG Converter blockAs the debug module have an AXI master, it creates another addressing space, that we have to configure. Therefore, use the following address mapping: - debug_mode_wrapper
(slave) is at 0x0
, size 64k
on the CVA6 address space (usual axi_riscv_atomic_wrapper
addressing section) - debug_mode_wrapper
master address mapping must be identical to the CVA6 address space (new debug_module_wrapper
addressing section)
To use this new debug mode, log on to the PS in SSH and flash the bitstream.
A precompiled version of OpenOCD patched to support AXI-mapped JTAG register is provided in ~/openocd
. Launch it using:
sudo openocd/src/openocd -f ariane.cfg
You can look into the ariane.cfg
file to see that OpenOCD is called with xlnx_axi_xvc
driver, reading at the address configured in block design: 0x43C00000
.
Launching OpenOCD will halt the CVA6 execution. Resume it by using GDB in another teminal: launch
/opt/xpack-riscv-none-elf-gcc-14.2.0-3/bin/riscv-none-elf-gdb
This will execute a RISC-V compatible GDB on the arm PS. GDB will autoload .gdbinit
, which connects to OpenOCD using port :3333
. GDB will then interact normally: use c
to resume execution, <CTRL+C> to break, etc.