Software apps and online services
The VexRiscV is a CPU Softcore based on the RISC-V ISA that has been gaining significant attention since it won the SoftCPU contest at the RISC-V Summit. No wonder there are already a lot of good blog articles and documentation available, a lot of which will be linked throughout or at the end of this article. I chose to present my experience nevertheless for the sake of having a summary to look back on. If it ends up interesting more people in VexRiscV...even better! Now, what makes me so fond of this Softcore CPU? After thinking about it I compiled the following reasons:
- Configurability: The VexRiscV Core is incredibly modular and possesses many configuration options to tune it to specific project requirements in terms of resource usage, performance, and functionality. From a small core with a few hundred LUTs to an extensive Linux-capable CPU, chances are VexRiscV can fulfill your needs for any System-on-Chip based project. The Softcore is written in SpinalHDL, a new Hardware Description Language based on Scala that is translated into VHDL or Verilog. The creator of VexRiscV, who is also the creator of SpinalHDL, leverages the general-purpose programming paradigms of SpinalHDL to create high configurability and modularity. This blog looks at the "fascinating way" the VexRiscV Core is structured and this article explains how SpinalHDL overcomes the shortcomings of the "traditional" HDLs (VHDL, Verilog and, SystemVerilog)
- Ecosystem and Ease of Use: A CPU is only as good as its software and ecosystem. RISC-V is on the rise and so is its ecosystem. GCC Toolchains, OpenOCD for GDB debugging, and more. 2022 is a good year to adopt RISC-V. In addition, VexRiscV itself offers example code (e.g. Dhrystone and FreeRTOS ports), ready to use SoCs, a simulation environment using Verilator a,nd good documentation. VexRiscV is truly quick and easy to get up and running.
- Portability: While Softcore CPUs like Microblaze, NIOS, and Mico32 by the likes of Xilinx, Intel, and Lattice do come with extensive ecosystems and can be integrated quickly into projects, they cannot be ported to FPGAs of other manufacturers as they are proprietary and their netlists are encrypted. VexRiscV on the other hand can be and has been ported to many different platforms.
Beyond that VexRiscV of course promises good performance at low resource usage. However, I will have to explore more soft CPU options as a comparison (possibly in future articles).The Project
In this project, I want to generate a small SoC using the VexRiscV, be able to debug code on it and test it using the Coremark benchmark. An obvious starting point is the VexRiscV GitHub repository. It comes with a very helpful readme file. First, we need to install the Scala Build Tool and the Java JDK 8:
# On Ubuntu:
git clone https://github.com/SpinalHDL/VexRiscv.git
# JAVA JDK 8
sudo add-apt-repository -y ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-8-jdk -y
sudo update-alternatives --config java
sudo update-alternatives --config javac
# Install SBT - https://www.scala-sbt.org/
echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | sudo tee /etc/apt/sources.list.d/sbt.list
echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | sudo tee /etc/apt/sources.list.d/sbt_old.list
curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add
sudo apt-get update
sudo apt-get install sbt
The readme also has instructions on how to simulate the CPU using Verilator, but for now I just want to get it up and running on my Nexys A7 Board. The repository comes with two SoC implementations: the small Murax and the more extensive Briey. I go with Murax as it has everything I need: An APB-bus controlled UART for a serial console, on-chip memory to hold the program, and a timer, which I need for my Coremark measurements. By running
sbt "runMain vexriscv.demo.MuraxWithRamInit" a Verilog file is generated, which I plug into a Vivado project like this:
The Synthesis and Implementation actually completed first try and upon programming the Artix 7 FPGA on my board I am greeted by blinking LEDs (a binary counter) and some traffic via UART (I use minicom). Nice!
Now let's get to actually running Coremark on the Murax SoC. First I do some modifications to
MuraxUtilities.scala (see src/main/scala/vexriscv/demo). I change "SpinalVerilog" calls to "SpinalVhdl" because I prefer to generate VHDL instead of Verilog. In the object definition of
MuraxWithRamInit I also change the CPU Frequency to 100 MHz, the on-chip RAM size to 32 kB and the location of the hex file to be put into the on-chip RAM.
Now we can look at the software side of things. Obviously, we need a RISC-V toolchain. I choose the prebuilt xPack GCC toolchain and install it like this:
# RISC-V toolchain
sudo wget https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/download/v$VERSION/xpack-riscv-none-embed-gcc-$VERSION-linux-x64.tar.gz
sudo tar -xvf xpack-riscv-none-embed-gcc-$VERSION-linux-x64.tar.gz
sudo rm xpack-riscv-none-embed-gcc-$VERSION-linux-x64.tar.gz
sudo mv xpack-riscv-none-embed-gcc-$VERSION xpack-riscv-none-embed-gcc
echo 'export PATH=/opt/xpack-riscv-none-embed-gcc/bin:$PATH' >> ~/.bashrc
I then modify the Coremark example of the NEORV32 CPU by adding the drivers for the timer included in the Murax SoC and borrowing the makefile from a "hello world" project of the VexRiscV. Upon running the Coremark the first time I realized that the 32-bit timer is overflowing too fast at 100 MHz so I end up increasing the Prescaler width from 16 to 32 bits in
MuraxUtilities.scala to achieve a timer tick frequency of 100 Hz.
I compiled the small Murax SoC design at 100 MHz without any optimization for area or speed. The utilization results for my Artix-7 were as follows: 1043 LUTs, 1328 FF, and 9 BRAMs. I am also left with a Worst-Case Negative Slack (WNS) of 1.68 ns (resulting in a theoretical FMax of 120 MHz). After programming the design onto the FPGA I receive the Coremark results via UART: 42 Coremark iterations per second and therefore 0.42 Coremark/MHz. The base Murax SoC impresses with its small size but I want to test the VexRiscV for its maximum Coremark performance.
Therefore, I modify Murax to include data and instruction caches and replicate the VexRiscV configuration for maximum performance advertised in the original GitHub repository. For this design I measured the following results:
- Utilization: 2388 LUT, 2168 FF, 22.5 BRAM
- WNS 0.938 (theoretical FMax of 110 MHz)
- 250 Coremark per second or 2.5 Coremark/MHz
Finally, I wanted to check out the debugging capabilities of VexRiscV. The VexRiscV DebugPlugin allows for debugging via the JTAG interface. Using a custom Risc-V OpenOCD version we can connect gdb to this DebugPlugin. However, I do not own a JTAG adapter. Luckily, there is a great GitHub repository explaining how to set up this gdb --> OpenOCD --> VexRiscV chain via the FTDI chip integrated in Artix-7 FPGAs. No additional cable needed! To not make this blog article even longer I will skip past my process of getting a working debugging setup. Instead, I recommend the mentioned GitHub repository and this blog article. In the end, I was able to single-step my code with this Eclipse-based IDE as a graphical interface.Summary
In the end, I successfully generated two VexRiscV SoC designs: One small and simple and the other one higher performing. I also got a working gdb debugging setup. All of that in a fairly short amount of time and not too many struggles. You find the results of my tests in this GitHub repository (README is a work in progress). I'm definitely planning on working with VexRiscV in the future. In future blog posts, I might also look at other CPU softcores as a comparison.
Sources & Interesting Links: