Setting up on-chip debugging for a Litex based SoC

Swethaa A
Thoughtworks: e4r™ Tech Blogs
4 min readFeb 27, 2024

In the evolving landscape of FPGA based SoC designs, on-chip debugging plays a significant role in ensuring correct and robust design. On-chip debugging provides more control like, it lets us monitor flow of data, the state of internal registers and pause the execution at specific points.

I’m going to cover how to set up on-chip debugging for a LiteX based SoC and will also elaborate on what are the challenges I faced and how I resolved them.

Photo by Vishnu Mohanan on Unsplash

LiteX-based SoC design

LiteX is an open source framework which allows us to design FPGA based System on Chip (SoC). It provides the infrastructure required to create a SoC. It also enables developers to experiment and test their designs quickly and has support of various soft cores CPUs, peripherals, platforms, and toolchains with no dependencies on proprietary IP blocks or generators.

LiteX is based on Migen, which is a Python based tool, used to generate RTL from Python code.

A SoC is an entire system on a single chip or a group of processing units on a single chip, which makes an Integrated Circuit (IC). The SoC component includes CPU, internal memory, input output ports all are integrated into one IC.

Image credits: LiteX: SoC builder framework, slide no.11 link

In this example I will be using OpenOCD, an open source software for on-chip debugging.

Installing OpenOCD

Before we begin, make sure OpenOCD and GDB are installed in your machine. For this example we need a specific version of OpenOCD that supports the Vexriscv CPU (which we will be using). It can be done by the following steps.

git clone https://github.com/SpinalHDL/openocd_riscv.git
cd openocd_riscv
wget https://raw.githubusercontent.com/litex-hub/pythondata-cpu-vexriscv/master/pythondata_cpu_vexriscv/verilog/VexRiscv_Debug.yaml
mv VexRiscv_Debug.yaml cpu0.yaml
./bootstrap
./configure --enable-dummy
make

Now that installation is done, let’s get into building the SoC.

Setting up the debugging

We need to create a SoC on the target board (in this case, Arty A7 board) with a debug variant of the CPU enabled, which provides the special features for debugging.

We are going to communicate with the FPGA via UART port so we need to set up a UARTBone bridge to the SoC. Enable crossover mode, since we are going to use the same UART port for debugging and to interact with the board.

python3 -m litex_boards.targets.digilent_arty \
--cpu-type=vexriscv \
--cpu-variant=standard+debug \
--uart-name="crossover" \
--with-uartbone \
--csr-csv=csr.csv \
--build \
--load

Once the bit stream is loaded, start the litex_server with the specific UART port which is connected to the board. litex_serveris going to facilitate the communication between the host and FPGA board.

litex_server --uart --uart-port=/dev/ttyUSB1

Now start OpenOCD

      openocd -c 'interface dummy' \
-c 'adapter speed 1' \
-c 'jtag newtap lx cpu -irlen 4' \
-c 'target create lx.cpu0 vexriscv -endian little -chain-position lx.cpu -dbgbase 0xF00F0000' \
-c 'vexriscv cpuConfigFile cpu0.yaml' \
-c 'vexriscv networkProtocol etherbone' \
-c 'init' \
-c 'reset halt'

In my case, after OpenOCD has started, it threw an error saying

I tried to resolve this error and dove deeper into what was causing this error. And I came across this issue, it explained why this is occurring. So this error is caused due to the difference in packet size which is sent by the Litex server and received by OpenOCD, hence OpenOCD is unable to receive the packet of that size. A temporary fix to this issue is commenting out the line self._send_socket_info(client_socket)from litex_server.py, this will not impact the debugging sessions.

Now OpenOCD should output that it has accepted the GDB connection.

Using GDB, load the firmware bios.elf through the OpenOCD connection into the SoC.

riscv32-unknown-elf-gdb build/digilent_arty/software/bios/bios.elf -ex 'target remote localhost:3333'

This will start the remote debugging session.

litex_term crossover

Using GDB we can now set breakpoints on a particular line, go to the next instructions, print the value of a variable and many more.

Conclusion

I’ve shared my experience of setting up OpenOCD and GDB for debugging purposes from which I’ve gained valuable insights. I encourage you to explore and leverage them for deeper insights into your projects.

References

  1. Kermarrec, F., Bourdeauducq, S., Lann, J.L., & Badier, H. (2020). LiteX: an open-source SoC builder and library based on Migen Python DSL. ArXiv, abs/2005.02506.
  2. https://github.com/enjoy-digital/litex/wiki/Use-GDB-with-VexRiscv-CPU

Disclaimer: The statements and opinions expressed in this blog are those of the author(s) and do not necessarily reflect the positions of Thoughtworks.

--

--