Rvfpga Getting Started Guide: The Imagination University Programme
Rvfpga Getting Started Guide: The Imagination University Programme
RVfpga
Getting Started Guide
RVfpga Getting Started Guide
Acknowledgements
AUTHORS
- Prof. Sarah Harris (https://www.linkedin.com/in/sarah-harris-12720697/)
- Prof. Daniel Chaver (https://www.linkedin.com/in/daniel-chaver-a5056a156/)
ADVISER
- Prof. David Patterson (https://www.linkedin.com/in/dave-patterson-408225/)
CONTRIBUTORS
- Robert Owen (https://www.linkedin.com/in/robert-owen-4335931/)
- Zubair Kakakhel (https://www.linkedin.com/in/zubairlk/)
- Olof Kindgren (https://www.linkedin.com/in/olofkindgren/)
- Prof. Luis Piñuel (https://www.linkedin.com/in/lpinuel/)
- Ivan Kravets (https://www.linkedin.com/in/ivankravets/)
- Valerii Koval (https://www.linkedin.com/in/valeros/)
- Ted Marena (https://www.linkedin.com/in/tedmarena/)
- Prof. Roy Kravitz (https://www.linkedin.com/in/roy-kravitz-4725963/)
ASSOCIATES
- Prof. Daniel León (www.linkedin.com/in/danileon-ufv)
- Prof. José Ignacio Gómez (https://www.linkedin.com/in/jos%C3%A9-ignacio-gomez-182b981/)
- Prof. Katzalin Olcoz (https://www.linkedin.com/in/katzalin-olcoz-herrero-5724b0200/)
- Prof. Alberto del Barrio (https://www.linkedin.com/in/alberto-antonio-del-barrio-garc%C3%ADa-
1a85586a/)
- Prof. Fernando Castro (https://www.linkedin.com/in/fernando-castro-5993103a/)
- Prof. Manuel Prieto (https://www.linkedin.com/in/manuel-prieto-matias-02470b8b/)
- Prof. Christian Tenllado (https://www.linkedin.com/in/christian-tenllado-31578659/)
- Prof. Francisco Tirado (https://www.linkedin.com/in/francisco-tirado-fern%C3%A1ndez-40a45570/)
- Prof. Román Hermida (https://www.linkedin.com/in/roman-hermida-correa-a4175645/)
- Cathal McCabe (https://www.linkedin.com/in/cathalmccabe/)
- Dan Hugo (https://www.linkedin.com/in/danhugo/)
- Braden Harwood (https://www.linkedin.com/in/braden-harwood/ )
- David Burnett (https://www.linkedin.com/in/david-burnett-3b03778/)
- Gage Elerding (https://www.linkedin.com/in/gage-elerding-052b16106/)
- Brian Cruickshank (https://www.linkedin.com/in/bcruiksh/)
- Deepen Parmar (https://www.linkedin.com/in/deepen-parmar/)
- Thong Doan (https://www.linkedin.com/in/thong-doan/)
- Oliver Rew (https://www.linkedin.com/in/oliver-rew/)
- Niko Nikolay (https://www.linkedin.com/in/roy-kravitz-4725963/)
- Guanyang He (https://www.linkedin.com/in/guanyang-he-5775ba109/)
- Prof. Ataur Patwary (https://www.linkedin.com/in/ataurpatwary/)
Table of Contents
Acknowledgements ............................................................................................................... 2
1. INTRODUCTION ........................................................................................................... 4
2. QUICK START GUIDE................................................................................................... 7
3. RISC-V ARCHITECTURE OVERVIEW ........................................................................ 16
4. RVFPGA OVERVIEW .................................................................................................. 18
5. INSTALLING SOFTWARE TOOLS .............................................................................. 36
6. RUNNING AND PROGRAMMING RVFPGA ................................................................ 42
7. SIMULATION IN VERILATOR ..................................................................................... 72
8. SIMULATION IN WHISPER ......................................................................................... 78
9. APPENDICES .............................................................................................................. 80
1. INTRODUCTION
RISC-V FPGA, also written RVfpga, is a package that includes instructions, tools, and labs
for targeting a commercial RISC-V processor to a field programmable gate array (FPGA)
and then using and expanding it to learn about computer architecture, digital design,
embedded systems, and programming. The term RVfpga also refers to the RISC-V system-
on-chip (SoC) that we introduce and then use throughout this guide and the accompanying
labs.
This RVfpga Getting Started Guide has the following main sections, as described briefly
below:
• Quick Start Guide (Section 2)
• Background and Overview
o RISC-V Architecture (Section 3)
o RVfpga (Section 4)
• Using RVfpga in Hardware
o Installing Software Tools (Section 5)
o Running and Programming RVfpga (Section 6)
• Simulating RVfpga
o Using Verilator, an HDL Simulator (Section 7)
o Using Whisper, Western Digital’s Instruction Set Simulator (Section 8)
• Appendices
o Using the native RISC-V toolchain and OpenOCD (Appendix A)
o Installing drivers in Windows to use PlatformIO (Appendix B)
o Installing Verilator and GTKWave in Windows (Appendix C)
o Installing Verilator and GTKWave in macOS (Appendix D)
o Using Vivado to download RVfpga onto an FPGA (Appendix E)
o Example: Using RVfpga in an industrial IoT application (Appendix F)
The Quick Start Guide (Section 2) describes the minimal software installation needed for
RVfpga and then shows how to download and execute a simple example program on
RVfpga. To understand RVfpga more fully, skip Section 2 and start with the complete guide
that starts in Section 3.
Sections 3 and 4 give a brief introduction to the RISC-V computer architecture and RVfpga,
the RISC-V system-on-chip (SoC) that you will use throughout this course. RVfpga uses the
SweRVolf SoC which, in turn, uses Western Digital’s (WD’s) open-source RISC-V SweRV
EH1 Core. Section 4 describes RVfpga and the organization of the Verilog files that make up
the RVfpga system (Section 4.D).
The remaining sections show how to use RVfpga in both hardware and in simulation.
Section 5 shows how to install the software tools needed to use RVfpga. Section 6 shows
how to use PlatformIO to both download the RVfpga SoC onto the Nexys A7 FPGA board
(Section 6.A) and download and run several example programs on RVfpga (Section 6.B-
6.H). Sections 7 and 8 show how to simulate RVfpga HDL using Verilator (Section 7), an
open-source HDL simulator, and Whisper (Section 8), Western Digital’s RISC-V Instruction
Set Simulator (ISS).
Finally, the appendices show how to use RVfpga at the command prompt in Linux (Appendix
A), how to install needed drivers and software on Windows and macOS machines
(Appendices B-D), and how to use Vivado to download RVfpga onto an FPGA using Vivado
(Appendix E). The last appendix, Appendix F, shows how to use RVfpga in an industrial IoT
application (Appendix F).
Table 1 lists the software and hardware needed for RVfpga. This guide shows how to install
and use these tools and hardware on the Ubuntu 18.04 operating system (OS). Other
operating systems (such as Windows or macOS), follow similar (if not exactly the same)
steps. When instructions differ, we insert specific instructions for Windows and macOS
using this highlighting.
Note: if you do not have access to the Nexys A7 FPGA board, the labs can still be
completed in simulation using Whisper, Western Digital’s instruction set simulator (ISS), and
Verilator, an open-source HDL simulator. In this case, you do not need to install Vivado
(Section 5.A); you need only install VSCode/PlatformIO (as explained in Section 2.A) and
Verilator/GTKWave (as explained in Section 5.C).
IMPORTANT: Before beginning, copy the RVfpga folder that you downloaded from
Imagination’s University Programme to your Ubuntu/Windows/macOS machine. We will refer
to the absolute path of the directory where you place this RVfpga folder as [RVfpgaPath].
RVfpga contains five folders: (1) examples: example programs that you will run while using
this guide, (2) src: contains the source code (Verilog and SystemVerilog) for RVfpga, (3)
verilatorSIM: contains the scripts for running the simulation of the SoC in Verilator, (4)
driversLinux_NexysA7: contains the Linux drivers for the Nexys A7 FPGA board, and (5)
Labs: contains programs that you will use during RVfpga Labs 1-10.
These topics are covered in the textbook Digital Design and Computer Architecture: RISC-V
Edition, Harris & Harris, © Morgan Kaufmann, which has an expected publication date of
summer 2021. Other textbooks, including Computer Organization and Design RISC-V
Edition, Patterson & Hennessy, © Morgan Kaufmann 2017, cover some of these topics.
This section shows how to install the minimal tools needed to use RVfpga and then shows
how to use PlatformIO to both download RVfpga onto the Nexys A7 FPGA board and then
run a program on RVfpga. You will need to purchase the FPGA board (see Table 1). These
steps also work for the Nexys4-DDR FPGA board, an earlier version of the board.
The instructions below are for an Ubuntu 18.04 system. They also work for Windows 10 and
macOS operating systems – when instructions differ from Ubuntu, we insert boxes with
specific instructions for Windows and macOS. If you are using Ubuntu, you can just ignore
those boxes. Paths are written as Linux paths using forward slashes (/), but Windows paths
are typically the same but with backward slashes (\).
VSCode and PlatformIO Installation: You will use PlatformIO, an integrated development
environment (IDE) to download the RVfpga system onto the Nexys A7 board and also to
download and run programs on RVfpga. PlatformIO is built as an extension of Microsoft’s
Visual Studio Code (VSCode). PlatformIO is cross-platform and includes a built-in debugger.
Windows / macOS: VSCode packages are also available for Windows (.exe file) and
macOS (.zip file) at https://code.visualstudio.com/Download. Follow the usual steps used for
installing and executing an application in these operating systems.
Windows / macOS: this step (2.a) is not required in Windows. As for macOS, you can use
homebrew to install python3: brew install python3
b. If not yet open, start VSCode by selecting the Start button and typing “VSCode” in
the search menu, then select VSCode, or type code in an Ubuntu terminal.
c. In VSCode, click on the Extensions icon located on the left side bar of VSCode
(see Figure 1).
d. Type PlatformIO in the search box and install the PlatformIO IDE by clicking on the
install button next to it (see Figure 2).
e. The OUTPUT window on the bottom will inform you about the installation process.
Once finished, click “Reload Now” on the bottom right side window, and PlatformIO
will finish installing inside VSCode (see Figure 3).
Nexys A7 cable drivers installation: you need to manually install the drivers for the Nexys
A7 board.
o Open a terminal.
o Go into directory [RVfpgaPath]/RVfpga/driversLinux_NexysA7. (For simplicity, we
provide these drivers inside the RVfpga folder. When you install Vivado in Section 5
of this guide, you can also find these drivers inside the downloaded package as
described in that section.)
o Run the installation script:
chmod 777 *
sudo ./install_drivers
o Unplug the Nexys A7 board from your computer and restart the computer for the
changes to have effect.
Windows: follow the instructions provided in Appendix B for installing the drivers for the
Nexys A7 board.
Download RVfpga onto the Nexys A7 FPGA board by completing the following steps:
Step 1. Connect Nexys A7 FPGA board to computer and turn the board on
Step 2. Open PlatformIO and C program
Step 3. Download RVfpga to Nexys A7 board
Step 4. Download and run program on RVfpga
Step 1. Connect Nexys A7 FPGA board to computer and turn the board on
Connect the Nexys A7 board to your computer using the provided USB cable. Figure 4
shows the physical locations of the LEDs and switches on the Nexys A7 FPGA board as well
as the USB connector, on switch, pushbuttons, and 7-segment displays. Connect a cable
between the USB connector port on the Nexys A7 board and turn on the board.
On Switch
USB
Connector
Pushbuttons
7-Segment
LEDs Displays
Switches
If the PlatformIO Home (PIO Home) window does not automatically open, click on the
PlatformIO icon in the left ribbon menu: . Then expand PIO Home and click on Open.
Now PIO Home will open to the Welcome window (see Figure 6).
Now click on File → Open Folder from the top file menu and select:
[RVfpgaPath]\RVfpga\examples\LedsSwitches_C-Lang
Select the folder, but do not open it (see Figure 7). PlatformIO will now open this program,
LedsSwitches_C-Lang, that reads the switch values on the Nexys A7 board and writes their
value onto the LEDs on the board.
You can view the LedsSwitches_C-Lang program by expanding the src folder and double-
clicking on LedsSwitches_C-Lang.c (Figure 8). We discuss this program in detail later in this
Getting Started Guide. For this Quick Start Guide, we will simply download this program onto
RVfpga, which will be running on the Nexys A7 board.
Note that the first time that an RVfpga example is opened in PlatformIO, the Chips Alliance
platform gets automatically installed (you can view it inside PIO Home → Platforms, as
shown in Figure 9). This platform includes several tools that you will use later, such as the
pre-built RISC-V toolchain, OpenOCD for RISC-V, an RVfpga bitfile and RVfpgaSIM,
JavaScript and Python scripts, and several examples. If, for any reason, the Chips Alliance
platform did not get installed automatically, you could install it manually, as will be explained
in Section 6.A.
board_build.bitstream_file = [RVfpgaPath]/RVfpga/src/rvfpga.bit
Many commands exist for the Project Configuration File (platformio.ini); more information
about these options are available at: https://docs.platformio.org/en/latest/projectconf/.
Download RVfpga (as defined by this bitfile) onto the Nexys A7 board:
• Click on the PlatformIO icon in the left menu ribbon (see Figure 11).
• In case the Project Tasks window is empty (Figure 12), you must refresh the Project
Tasks first by clicking on . This can take several minutes.
Debug” button: , which is available in the left side bar. Start the debugger by clicking on
the play button (make sure that the ”PIO Debug” option is selected).
You can find this button near the top of the window (see Figure 14). The program will first
compile and then debugging will start.
Figure 14. Compile and download the program and start the debugger
To control your debugging session, you can use the debugging toolbar which appears near
the top of the editor (see Figure 15). We will describe and test all the options later in this
Getting Started Guide.
PlatformIO sets a temporary breakpoint at the beginning of the main function. So, click on
the Continue button to run the program. Now toggle the switches on the Nexys A7 FPGA
board and view as the corresponding LEDs light up.
RISC-V is an Instruction Set Architecture (ISA) that was created in 2011 in the Par Lab at
the University of California, Berkeley. The goal was for RISC-V to become a “Universal ISA”
for processors used for the entire range of applications, from small, constrained, low-
resource IoT devices to supercomputers. RISC-V architects established five principles for
the architecture to achieve this goal:
• It must be compatible with a wide range of software packages and programming
languages.
• Its implementation must be feasible in all technology options, from FPGAs to ASICs
(application specific integrated circuits) as well as emerging technologies.
• It must be efficient in the various microarchitecture scenarios, including those
implementing microcode or hardwired control, in-order or out-of-order pipelines,
various types of parallelism, etc.
• It must be able to be tailored to specific tasks to achieve the required maximum
performance without drawbacks imposed by the ISA itself.
• Its base instruction set must be stable and long-lasting, offering a common and solid
framework for developers.
RISC-V is an open standard, in fact, the specification is public domain, and it has been
managed since 2015 by the RISC-V Foundation, now called RISC-V International, a non-
profit organization promoting the development of hardware and software for RISC-V
architectures. In 2018, the RISC-V Foundation began an ongoing collaboration with the
Linux Foundation, and in March 2020 the RISC-V Foundation became RISC-V International
headquartered in Switzerland. This transition dissipated any concern the community might
have had about future openness of the standard. As of 2020, RISC-V International is
supported by more than 200 key players from research, academia, and industry, including
Microchip, NXP, Samsung, Qualcomm, Micron, Google, Alibaba, Hitachi, Nvidia, Huawei,
Western Digital, ETH Zurich, KU Leuven, UNLV, and UCM.
RISC-V is one of the few, and probably the only, globally relevant ISAs created in the past
10-20 years because of it being an open standard and modular, instead of incremental. Its
modularity makes it both flexible and sleek. Processors implement the base ISA and only
those extensions that are used. This modular approach differs from traditional ISAs, such as
x86 or ARM, that have incremental architectures, where previous ISAs are expanded and
each new processor must implement all instructions, even those that are tagged as
“obsolete”, to ensure compatibility with older software programs. As an example, x86, that
started with 80 instructions, has now over 1300, or 3600 if you consider all different opcodes
available in machine code. This large number of instructions and the requirement of
backward compatibility result in large, power-hungry processors that must support long
instructions, because most of the short opcodes, or small instructions, are already in use.
RISC-V has four base ISA options: two 32-bit versions (integer and embedded versions,
RV32I and RV32E) and 64- and 128-bit versions (RV64I and RV128I), as shown in Table 2.
The ISA modules marked Ratified have been ratified at this time. The modules marked
Frozen are not expected to change significantly before being put up for ratification. The
modules marked Draft are expected to change before ratification. The ability to build small
processors is a particularly key requirement for cost-, space-, and energy-constrained
devices. Instruction extensions can be added on top of these base ISAs to enable specific
tasks, for example floating point operations, multiplication and division, and vector
operations. These specialized hardware extensions are also included in the standard and
known by the compilers, so enabling the desired options in a compiler will allow for a
targeted binary code generation. Each of these extensions is identified by a letter that must
be added to the core ISA to represent the hardware capabilities of the implementation, as
shown in Table 3. For example, RVM is the multiply/divide extension, RVF is the floating-
point extension, and so on.
The letter G, that denotes “general”, is used to denote the inclusion of all MAFD extensions.
Note that a company or an individual may develop proprietary extensions using opcodes that
are guaranteed to be unused in the standard modules. This allows third-party
implementations to be developed in a faster time-to-market.
For example, a 64-bit RISC-V implementation, including all four general ISA extensions plus
Bit Manipulation and User Level Interrupts, is referred to as an RV64GBN ISA. All these
modules are covered in the unprivileged or user specification. The RISC-V foundation also
covers a set of requirements and instructions for privileged operations required for running
general-purpose operating systems.
4. RVFPGA OVERVIEW
In this section we describe the entire RVfpga system from the core up to the FPGA board
interface. Figure 16 illustrates the typical hierarchical organization of an embedded system
starting with the processor core, then the SoC built around the core, and finally the system
and board interface. We start by describing the processor core (Western Digital’s SweRV
EH1 Core), which executes the RISC-V instructions; then, in Section B, we describe the
SweRVolf SoC, which integrates the system’s hardware components (core, memory, and
input/output), and the extensions performed for using it within RVfpga; in Section C we
describe the SweRVolf SoC implemented on the Nexys A7 FPGA board (RVfpga) and also
describe the SweRVolf SoC used in simulation (RVfpgaSIM). Finally, we explain the file
structure of the whole RVfpga system in Section D.
Out of the three cores, the SweRV EH1 Core (provided with the RVfpga package and also
available from https://github.com/chipsalliance/Cores-SweRV) is preferred for its high
performance/MHz and its simple thread structure. Moreover, Chips Alliance, a group
committed to providing open-source hardware, provides a complete and verified SoC, called
SweRVolf (provided with the RVfpga package and also available from
https://github.com/chipsalliance/Cores-SweRVolf). RVfpga uses an extension of the
SweRVolf SoC that, in turn, uses Western Digital’s SweRV EH1 Core version 1.6.
The SweRV EH1 Core is a machine-mode (M-mode) only, 32-bit CPU core which supports
RISC-V’s integer (I), compressed instruction (C), and integer multiplication and division (M)
extensions. The Programmer’s Reference Manual (https://github.com/chipsalliance/Cores-
SweRV/blob/master/docs/RISC-V_SweRV_EH1_PRM.pdf) describes in detail all aspects of
the core, from its structure to timing information and memory maps. SweRV EH1 is a
superscalar core, with a dual-issue 9-stage pipeline (see Figure 17) that supports four
arithmetic logic units (ALUs), labelled EX1 to EX4 in two pipelines, I0 and I1. Both ways of
the pipeline support ALU operations. One way of the pipeline supports loads/stores and the
other way has a 3-cycle latency multiplier. The processor also has one out-of-pipeline 34-
cycle latency divider. Four stall points exist in the pipeline: ‘Fetch 1’, ‘Align’, ‘Decode’, and
‘Commit’. The ‘Fetch 1’ stage includes a Gshare branch predictor. In the ‘Align’ stage,
instructions are retrieved from three fetch buffers. In the ‘Decode’ stage, up to two
instructions from four instruction buffers are decoded. In the ‘Commit’ stage, up to two
instructions per cycle are committed. Finally, in the ‘Writeback’ stage, the architectural
registers are updated.
Figure 18 shows a comparison of different current cores and processors. The SweRV EH1
Core performance per MHz is impressively high at 4.9 CM/MHz (CoreMark per MHz): it is
twice as fast as the ARM Cortex A8 and its performance even surpasses the ARM Cortex
A15 performance.
Western Digital also provides an extension to the SweRV EH1 Core called the SweRV EH1
Core Complex (see Figure 19), which adds the following elements to the EH1 Core
described above and coloured in blue in the figure:
• Two dedicated memories, one for instructions (ICCM) and the other for data (DCCM),
which are tightly coupled to the core. These memories provide low-latency access
and SECDED ECC (single-error correction and double-error detection error
correcting codes) protection. Each of the memories can be configured as 4, 8, 16, 32,
48, 64, 128, 256, or 512KB.
• An optional 4-way set-associative instruction cache with parity or ECC protection.
• An optional Programmable Interrupt Controller (PIC), that supports up to 255 external
interrupts.
• Four system bus interfaces for instruction fetch (IFU Bus Master), data accesses
(LSU Bus Master), debug accesses (Debug Bus Master), and external DMA
accesses (DMA Slave Port) to closely coupled memories (configurable as 64-bit AXI4
or AHB-Lite buses).
• Core Debug Unit compliant with the RISC-V Debug specification.
In addition to the SweRV EH1 Core Complex (see Figure 19), the SweRVolf SoC also
includes a Boot ROM, a UART, a System Controller and an SPI controller (Figure 20 shows
these elements in white). In this course we extend the SweRVolf SoC with some more
functionality, such as another SPI controller (SPI2), a GPIO (General Purpose Input/Output),
8-digit 7-Segment Displays and a timer (Figure 20 shows these peripherals in red, except for
the 7-Segment Displays, which are included in the System Controller). Given that the
SweRV EH1 Core uses an AXI bus and the peripherals use a Wishbone bus, the SoC also
has an AXI-Wishbone Bridge.
AXI Interconnect
RAM Memory
AXI-Wishbone Bridge
Wishbone Interconnect
Table 5 shows the memory-mapped addresses of the peripherals connected to the core via
the Wishbone interconnect.
i. Input/Output
The SweRVolf SoC uses two kinds of hardware controllers for communicating with the
peripherals: custom controllers written in Verilog and open-source controllers from
OpenCores [https://opencores.org/], an online community for the development of
gateware IP (Intellectual Properties) cores in the spirit of free and open source
collaboration. The extended version of SweRVolf SoC that we use in this course includes
the I/O interfaces listed below, which we will use, explain in detail and even extend in
RVfpga Labs 6-10.
ii. Memory
The SweRVolf SoC includes a Boot ROM memory and the necessary hardware to
enable the user to include RAM and SPI Flash memories.
• Boot ROM: a Boot ROM contains a first-stage bootloader. After system reset, the
SweRVolf SoC will start fetching the initial instructions from this area, which occupies
addresses 0x80000000 to 0x80000FFF.
• RAM: the SweRVolf SoC does not include a memory controller, but it reserves the
first 128MiB of its memory map (0x00000000-0x07FFFFFF) and exposes the AXI
bus, so that the user can access RAM memory by using a memory controller.
• SPI Flash: an SPI Flash memory can also be included using the SPI1 controller
described in the previous section (address range: 0x80001040-0x8000107F).
iii. Interconnection
The SweRV EH1 Core uses an AXI4 bus to connect the core and memory. The bus
could also be configured as an AHB-Lite bus, but we will not use that option in these
materials. All of the peripherals (I/O devices) are connected to a Wishbone bus, an open
source bus that is heavily used in OpenCore CPU’s and peripherals. The system
includes an AXI to Wishbone Bridge (as shown in Figure 20) to connect the core to the
peripherals.
In this section, we briefly describe the operation of an AXI4 bus and a Wishbone bus. If
you are interested in extending your knowledge about the specification of these buses,
you can use the references provided below.
In the following subsections, we briefly explain some of the main aspects of the AXI4
interconnect. You can find the whole AXI specification in the following document:
https://static.docs.arm.com/ihi0022/e/IHI0022E_amba_axi_and_ace_protocol_spec.pdf
• AXI Architecture
The AXI protocol defines the following independent transaction channels:
▪ Read address
▪ Read data
▪ Write address
▪ Write data
▪ Write response
Figure 21 shows how a read transaction uses the read address and read data
channels. First the address and control bits are sent from the master device, then the
slave device responds with the data on the read data channel.
Figure 22 shows how a write transaction uses the write address, write data, and write
response channels. Similar to a read, the master device sends the address and
control bits. Then the master device sends the data on the write data channel and the
slave device sends a response.
The AXI address channel carries addresses and control information that describes
the nature of the data to be transferred. The data is transferred between the master
and slave using either:
• A read data channel to transfer data from the slave to the master (Figure
21).
• A write data channel to transfer data from the master to the slave (Figure
22). In a write transaction, the slave uses the write response channel to
signal the completion of the transfer to the master (Figure 22).
• AXI Signals
Table 6. shows the main signals used in the AXI bus and a brief description of each
of them. The signals are organized in five groups, which correspond to the five
channels described in the previous section:
• Write address channel signals, whose names start with AW
• Write data channel signals, whose names start with W
• Write response channel signals, whose names start with B
• Read address channel signals, whose names start with AR
• Read data channel signals, whose names start with R
i. RVfpga
RVfpga is the Extended SweRVolf SoC (Figure 20) targeted to the Nexys A7 FPGA
board and its peripherals. (Recall that the Nexys 4 DDR FPGA board can also be used).
The main elements used by RVfpga are illustrated in Figure 24:
• Hardware programmed onto the FPGA:
➢ Extended SweRVolf SoC
➢ Lite DRAM controller
➢ Clock Generator: the Nexys A7 board includes a single 100 MHz crystal
oscillator that is used by the Lite DRAM controller. The frequency of this
clock is scaled down to 50 MHz to use in the SweRVolf SoC.
➢ Clock Domain Crossing module: connection of 2 clock domains:
SweRVolf SoC and Lite DRAM.
➢ BSCAN logic for the JTAG port
• Memory/Peripherals used in RVfpga from the Nexys A7 (or Nexys4 DDR) FPGA
board:
➢ DDR2 memory (accessed through the Lite DRAM controller mentioned
above)
➢ USB connection
➢ SPI Flash memory
➢ SPI Accelerometer
➢ 16 LEDs and 16 Switches
➢ 8-digit 7-Segment Displays
100 MHz
Clock
Generator
50 MHz
Extended
SweRVolf SoC bscan TAP
CRC
AXI Interconnect
RAM Memory Lite DRAM
AXI-Wishbone Bridge controller
Wishbone Interconnect
The Nexys A7 board (Figure 25) is a recommended trainer board for electrical and
computer engineering curricula. This board costs $265 (or a discounted price of $198.75
with academic pricing – sign up for a Digilent account with a .edu email address).
Digilent provides an extensive reference manual of the Nexys A7 board at:
https://reference.digilentinc.com/_media/reference/programmable-logic/nexys-a7/nexys-
a7_rm.pdf. This board may be powered from a 5V wall wart (not provided with the board)
or from a PC via the microUSB connector on the board. A Microchip PIC24
microcontroller manages the loading process onto the FPGA, making this board a user-
friendly option. The board is programmable using Xilinx’s Vivado Design Suite or
OpenOCD. The desired configuration can be downloaded to the FPGA using one of four
different sources: a FAT32 formatted MicroSD card, a FAT32 formatted USB pendrive,
the internal flash memory, or a JTAG interface.
The Nexys A7-100T FPGA board includes the following interfaces and devices:
• 128 MiB DDR RAM
• 128 Mibit SPI Flash Memory
• 8-digit 7-Segment Displays
• 16 Switches
• 16 LEDs
• Sensors and connectors, including a microphone, audio jack, VGA 25 port, USB
host port, RGB-LEDs, I2C temperature sensor, SPI accelerometer, among other.
• Xilinx Artix-7 FPGA, which has the following features:
➢ 15.850 Logic slices of four 6-input LUTs and 8 flip-flops.
➢ 4.860 Kibits of total block RAM
➢ 6 clock management tiles (CMTs)
➢ 170 I/O pins
➢ 450 MHz internal clock frequency
ii. RVfpgaSIM
The SweRVolf SoC can also include a Verilog wrapper to enable simulation. This is
referred to as RVfpgaSIM, which is a simulation target that wraps the Extended
SweRVolf SoC in a testbench to be used by HDL simulators. It can be used in two ways:
• For full-system simulations in Verilator (or other HDL simulators)
• For connecting to a debugger through OpenOCD and JTAG VPI
D. File Structure
In the previous sections we have shown the high-level organization of the system that we
use in these materials, from the SweRV EH1 Core Complex (Figure 19), to the Extended
SweRVolf SoC (Figure 20) and, finally, to RVfpga (Figure 24) and RVfpgaSIM
implementations.
In this section, we describe the file structure of the whole system. While reading these
explanations, open the files and view them on your PC. The files are available at
[RVfpgaPath]/RVfpga/src.
The Verilog files for the SweRV EH1 Core Complex are available in this folder:
[RVfpgaPath]/RVfpga/src/SweRVolfSoC/SweRVEh1CoreComplex
Find that directory on your PC to view the files as we refer to them in this section.
The top file for the SweRV EH1 Core Complex is in the file: swerv_wrapper.sv; the
top module is called swerv_wrapper, and it instantiates two modules that
correspond to the two blocks highlighted in grey and red in Figure 26:
• mem (implemented inside mem.sv): this module instantiates the modules for the
implementation of the DCCM (lsu_dccm_mem, implemented in file
lsu/lsu_dccm_mem.sv), the ICCM (ifu_iccm_mem, implemented in file
ifu/ifu_iccm_mem.sv) and the Instruction Cache (ifu_ic_mem, implemented in file
ifu/ifu_ic_mem.sv).
• swerv (implemented inside swerv.sv): this module instantiates the units that
SweRVolf SoC
(swervolf_core.v)
SweRVEh1CoreComplex/
swerv_wrapper
swerv_wrapper.sv
Interconnect/
AxiInterconnect/ axi_intercon
axi_intercon.sv
Interconnect/
AxiToWb/ axi2wb
axi2wb.v
wb_intercon
Interconnect/
WishboneInterconnect/
wb_intercon.v
Find that directory on your PC to view the files as we refer to them in this section.
The top module for the Extended SweRVolf SoC is available at:
[RVfpgaPath]/RVfpga/src/SweRVolfSoC/swervolf_core.v. Open that file, and notice
that it includes the modules contained within the Extended SweRVolf SoC (Figure 20),
specifically:
SIMULATION:
RVfpgaSIM is a simulation target that wraps the Extended SweRVolf SoC in a
testbench that is used by HDL simulators. It is available at
[RVfpgaPath]/RVfpga/src/rvfpgasim.v.
ON BOARD EXECUTION:
RVfpga (available at: [RVfpgaPath]/RVfpga/src/rvfpga.v) wraps the Extended SweRVolf
SoC in a wrapper that targets it to the Nexys A7 FPGA board and its peripherals (see
Figure 24). This module instantiates, in addition to some other modules (such as a clock
generator module, clk_gen_nexys, a clock domain crossing module, axi_cdc_intf, or a
BSCAN module for the JTAG port, bscan_tap), the two main SoC structures:
As a summary, Figure 28 shows the hierarchy for the whole system implementation on
the Nexys A7 FPGA board.
The instructions below are for an Ubuntu 18.04 OS, but other Linux operating systems,
as well as Windows or macOS, follow similar (if not exactly the same) steps. In some cases,
we insert boxes with specific instructions for those different OSs. If you are using Ubuntu,
you can just ignore those boxes.
Note that, for most things that you will do in this GSG and in the Labs, installing VSCode and
PlatformIO would be enough. However, we recommend you to install the other tools now as
well (Vivado, Verilator and GTKWave), so that no more installations are required later.
This process can take several hours (or more, depending on your download speed), but
most of the time is spent waiting while the programs are downloaded and installed.
A. Install Vivado
Vivado is a Xilinx tool for viewing, modifying, and synthesizing the Verilog code for RISC-V
FPGA. You will use it extensively in later labs. The installation instructions are available at
https://reference.digilentinc.com/vivado/installing-vivado/start and are summarized below.
macOS: Vivado is not supported in macOS; thus, you need a Linux/Windows Virtual
Machine for running Vivado in this OS.
1. Navigate to https://reference.digilentinc.com/vivado/installing-vivado/start
3. It is recommended that you install the “Self Extracting Web Installer”. At the time of writing
this document, it is at this link on the download page: Xilinx Unified Installer 2019.2: Linux
Self Extracting Web Installer
WINDOWS: At the time of writing this document, the “Self Extracting Web Installer” for
Windows is at this link on the download page: Xilinx Unified Installer 2019.2: Windows Self
Extracting Web Installer
5. Execute the binary file. Open a terminal and make it root (type “sudo su”). Then drag the
binary file (Xilinx_Unified_2019.2_1106_2127_Lin64.bin) into the terminal. If it prompts you
to make the file executable and run it, select OK.
• Troubleshooting: If the terminal says permission denied, type the following in the
terminal (in the same directory as the binary file):
> sudo chmod +x ./Xilinx_Unified_2019.2_1106_2127_Lin64.bin
> sudo ./Xilinx_Unified_2019.2_1106_2127_Lin64.bin
WINDOWS: In Windows you can simply execute the .exe file that you downloaded in steps 3
and 4 by double-clicking on it.
6. The Vivado installer will walk you through the installation process. Important notes:
• Select Vivado (not Vitis) as the Product to install.
• Select Vivado HL Webpack (not Vivado HL System Edition); Webpack is free.
• Otherwise, defaults should be selected.
Hint: If you changed the installation directory of Vivado, you will need to modify the path
appropriately in the following steps.
WINDOWS: Steps 7 and 8, are not necessary in Windows. You can simply ignore these two
steps and go directly to step 9.
7. After Vivado has installed, you need to set up the environment. Open a terminal and type:
source /tools/Xilinx/Vivado2019.2/settings64.sh
vivado
Troubleshooting:
• If your system cannot find that executable, you’ll need to add the following to your
path:
/tools/Xilinx/DocNav
/tools/Xilinx/Vivado/2019.2/bin
9. You will need to manually install the cable drivers for the Nexys A7 FPGA board.
Type the following at a terminal window:
sudo ./install_drivers
WINDOWS: Vivado installation in Windows automatically installs drivers for the Nexys A7
board which are not compatible with PlatformIO. Thus, if you are using Windows, you must
update the drivers as explained in Appendix B. You must do this even if you already
did it in the Quick Start Guide section because the drivers were overwritten by the
Vivado installation.
10. You will also need to manually install the Digilent Board Files.
• Download the archive of the vivado-boards from the Github repository and extract it.
• Open the folder extracted from the archive and navigate to its new/board_files
directory. Select all folders within this directory and copy them.
• Open the folder that Vivado was installed into (/tools/Xilinx/Vivado by default). Under
this folder, navigate to its <version>/data/boards/board_files directory, then paste the
board files into this directory.
• You can also use the terminal, by going into the new/board_files directory and typing:
sudo cp -r *
/tools/Xilinx/Vivado/2019.2/data/boards/board_files
WINDOWS: copy/paste the downloaded folders as explained in Step 10. In Windows, you
can find Vivado’s board_files folder at: C:\Xilinx\Vivado\2019.2\data\boards\board_files
1. Install VSCode:
Follow these steps to install VSCode:
a. Download the .deb file from the following link:
https://code.visualstudio.com/Download
Windows / macOS: VSCode packages are also available for Windows (.exe file) and
macOS (.zip file) at https://code.visualstudio.com/Download. Follow the common steps used
for installing and executing an application in these operating systems.
Windows / macOS: this step (2.a) is not required in Windows. As for macOS, you can use
homebrew to install python3: brew install python3
b. If not yet open, start VSCode by selecting the Start button and typing “VSCode” in
the search menu, then select VSCode, or by typing code in a terminal.
c. In VSCode, click on the Extensions icon located on the left side bar of VSCode
(see Figure 29).
d. Type PlatformIO in the search box and install the PlatformIO IDE by clicking on the
install button next to it (see Figure 30).
e. The OUTPUT window on the bottom will inform you about the installation process.
Once finished, click “Reload Now” on the bottom right side window, and PlatformIO
will be installed inside VSCode (see Figure 31).
Follow the next steps to install Verilator (instructions are available at:
https://www.veripool.org/projects/verilator/wiki/Installing but are also summarized below) and
GTKWave in your Ubuntu 18.04 Linux system. This process takes a long time.
➢ sudo apt-get install git make autoconf g++ flex bison libfl2 libfl-
dev
➢ sudo apt-get install -y gtkwave
➢ git clone https://git.veripool.org/git/verilator
➢ cd verilator
➢ git pull
➢ git checkout v4.020
➢ autoconf
➢ ./configure
➢ make (alternatively you can use make -j$(nproc) to make it go faster)
➢ sudo make install
To add /usr/local/bin permanently to your path, add the last line to your ~/.bashrc file.
In this section, we show how to run seven simple programs on RVfpga, the Extended
SweRVolf SoC (Figure 20) targeted and downloaded onto the Digilent Nexys A7 FPGA
Board (see Figure 24).
LINUX / Windows / macOS: All the instructions described in this section should work for the
three operating systems, assuming that all the required tools and drivers were installed
correctly as explained in Section 5. In some cases, you may need to modify some minor
details, such as the slash, used in Linux, for a backslash, used in Windows.
We demonstrate how to use RVfpga by showing how to run the seven example programs
listed in Table 8. The first three programs are written in RISC-V assembly language and the
last four programs are written in C. Directions for running each of the programs on RVfpga
are described below.
Note that, before being able to execute any of these seven examples, you must program
the FPGA with the RVfpga SoC, as explained in the following section.
(If you are interested in using Vivado for programming the FPGA, you can follow the
instructions provided at Appendix E of this guide instead of the following instructions below.
However, the method described there is only possible for Linux and Windows systems (not
macOS) – and, overall, the method of using Vivado to download RVfpga onto the FPGA is
e. Select the PlatformIO project that you are going to use. In this section, as an example,
we use AL_Operations, the first example mentioned in Table 8, that you will debug in the
next section, but you could follow the same steps with any other example. Thus, select
directory AL_Operations (do not open it, but just select it – see Figure 33) and click OK
at the top of the window. PlatformIO will now open the example.
f. Open file platformio.ini, by clicking on platformio.ini in the left sidebar (see Figure 34).
Establish the path to the RVfpga bitstream in your system by editing the following line
(see Figure 34). Note that a pre-synthesized bitstream of RVfpga SoC is provided in the
RVfpga folder at: [RVfpgaPath]/RVfpga/src/rvfpga.bit.
board_build.bitstream_file = [RVfpgaPath]/RVfpga/src/rvfpga.bit
There are many different commands that you can use in the Project Configuration File
(platformio.ini), and for which you can find information at:
https://docs.platformio.org/en/latest/projectconf/.
g. Click on the PlatformIO icon in the left menu ribbon (see Figure 35).
In case the Project Tasks window is empty (Figure 36), you must refresh the Project
Tasks first by clicking on . This can take several minutes.
Figure 38. Upload RVfpga onto Nexys A7 FPGA Board using PlatformIO
Note that the first time that an RVfpga example is opened in PlatformIO, the Chips Alliance
platform gets automatically installed (you can view it inside the PIO Home, as shown in
Figure 39). This platform includes several tools that you will use later, such as the pre-built
RISC-V toolchain, OpenOCD for RISC-V, an RVfpga bitfile and RVfpgaSIM, JavaScript and
Python scripts, and several examples.
If, for any reason, the Chips Alliance platform did not install automatically, you can install it
manually following the next steps (normally, you can simply skip this procedure and continue
with Section B):
- View the Quick Access menu by clicking on the button, located in the left side bar
(see Figure 40). Then, in the PIO Home, click on the button and then on the
tab (Figure 40). Look for Chipsalliance (the platform that we use in
- After clicking on the button, you will see the details of the Chips Alliance
platform (as in Figure 41). Install it by clicking on the button (Figure 41).
- Once installation completes, a summary of the tools that have been installed is shown,
B. AL_Operations program
The first example program, AL_Operations.s (see Figure 43), is an assembly program that
performs three arithmetic-logic instructions (addition, subtraction, and logical and) on the
same register, t3 (also called x28), within an infinite loop.
1 .globl main
2 main:
3
4 # Register t3 is also called register 28 (x28)
5 li t3, 0x0 # t3 = 0
6
7 REPEAT:
8 addi t3, t3, 6 # t3 = t3 + 6
9 addi t3, t3, -1 # t3 = t3 - 1
10 andi t3, t3, 3 # t3 = t3 AND 3
11 beq zero, zero, REPEAT # Repeat the loop
Follow these steps to run and debug this code on the Nexys A7 FPGA board using
PlatformIO:
1. Program the FPGA as explained in the previous section. Note that you already have the
AL_Operations project opened in PlatformIO.
2. Open the assembly program, AL_Operations.S, by clicking on the Explorer icon in the
left menu ribbon , expanding src under AL_OPERATIONS in the left sidebar and
clicking on AL_Operations.S (see Figure 44).
3. VSCode and PlatformIO provide different ways of compiling, cleaning and debugging the
program. In the bottom part of VSCode, you can find some buttons that provide useful
functionalities: . For example, can be used to build the
project, or can be used to clean it. In the left side bar (see Figure 29), the “Run”
button can be used to compile the program and then open the debugger.
4. Click on the “Run” button . Start the debugger by clicking on the play button
5. To control your debugging session, you can use the debugging toolbar that appears near
the top of the editor (see Figure 46). Below are the options:
• Continue executes the program until the next breakpoint.
• Breakpoints can be added by clicking to the left of the line number in the editor.
• Step Over executes the current line and then stop.
• Step Into executes the current line and if the current line includes a function call, it will
jump into that function and stop.
• Step Out executes all of the code in the function you are in and then stops once that
function returns.
• Restart restarts the debugging session from the beginning of the program.
• Stop stops the debugging session and returns to normal editing mode.
• Pause pauses execution. When the program is running, the Continue button is
replaced by the Pause button.
6. On the left sidebar, you can view the Debugger options. The following options are
available:
• Variables: lists local, global, and static variables present in your program along with
their values.
• Call Stack: shows you the current function being run, the calling function (if any),
and the location of the current instruction in memory.
• Breakpoints: show any set breakpoints and highlight their line number. Breakpoints
can be managed in this section. Breakpoints can also be temporarily deactivated
without removing them by toggling the checkbox.
7. Expand the Registers option in the Debugger Side Bar and continue the execution step-
by-step . You will observe that register x28 (also called t3,
as shown in the REGISTERS section) stores the results of the three arithmetic-logic
operations: addition, subtraction, and logical AND. See Figure 47.
8. Before calling the main function, a start-up file, provided by Western Digital at
~/.platformio/packages/framework-wd-riscv-sdk/board/nexys_a7_eh1/startup.S, is
executed. This file configures the core: Instruction Cache set-up, registers initialization
Windows: The .platformio folder is located inside your user folder (C:\Users\<USER>). Note
that you may need to enable the system for viewing hidden files/folders.
macOS: Like in Linux, the .platformio folder is located inside your home folder
(~/.platformio).
by clicking on , which you can find in the top of the left-most side bar. On the top
menu bar, click on File → Close Folder.
C. Blinky program
The second example program, blinky.S, is an assembly program that makes the Nexys A7
board’s right-most LED blink (see Figure 48). The program repeatedly inverts the value
connected to the right-most LED with a delay between each inversion.
Follow the next steps to run and debug this code on RVfpga, the RISC-V SoC loaded onto
the FPGA board:
2. On the top bar, click on File → Open Folder, and browse into directory
[RVfpgaPath]/RVfpga/examples/
4. Open the assembly code of the example, file blinky.S, in the editor, by clicking on it
(Figure 50).
5. Click on to run and debug the program; then start debugging by clicking on the
6. On the board, you will see the right-most LED start to blink.
8. Establish a breakpoint by clicking to the left of line number 18. A red dot will appear and
the breakpoint will be added to the BREAKPOINTS tab (see Figure 51).
. Execution will continue and it will stop after the store byte
(sb) instruction, which writes 1 (or 0) to the right-most LED.
10. Continue execution several times; you will see that the value driven to the right-most
LED changes each time.
D. LedsSwitches program
The third assembly example communicates with the LEDs and the switches available on the
board (see Figure 52).
Follow the next steps for running and debugging this code on the FPGA board:
1. RVfpga is already programmed on the FPGA board if you executed the previous
examples, so you should not need to program it again. However, if you do need to
reprogram RVfpga onto the board again, do it as explained in Section A, using the
LedsSwitches example instead of the AL_Operations example.
2. On the top bar, click on File → Open Folder, and browse to directory
[RVfpgaPath]/RVfpga/examples/. Select directory LedsSwitches and click OK.
3. The program LedsSwitches.S has an infinite loop where the switches are read and then
their state is shown on the LEDs.
4. After launching the debugger as explained for prior programs, the program starts to run.
PlatformIO sets a temporary breakpoint at the beginning of the main function. So, click
on the Continue button to run the program.
5. Toggle the switches on the bottom of the Nexys A7 board. You will immediately see on
the board that the LEDs show the new value of the switches. You can pause the
execution, run step-by-step and inspect the registers as explained above. When you are
finished, close the project by clicking on File → Close Folder.
6. Sometimes, it can be very useful to inspect the values stored in memory. For that
purpose, PlatformIO provides a Memory Display.
b. The initial memory address will be requested (see Figure 55). Insert the initial
address where the Switches are mapped, in our case 0x80001400.
c. Then, the number of bytes that you want to inspect is requested (see Figure
56), so insert a value of 0xc (we want to inspect three 4-byte I/O registers,
d. The Memory Display will open to the right, showing the 12 bytes that we have
requested (see Figure 57). The value that we have in the 16 switches is
0x123C (see bytes at addresses 0x80001402 and 0x80001403). Taking into
account that RISC-V architecture is little endian, the value shown in the figure
is coherent with that. The 16 LEDs (stored at addresses 0x80001404 and
0x80001405) show the same value.
e. Change the values of the switches on the board, for example to 0x5555, and
execute one more iteration of the loop step-by-step. The value of the switches
in memory should change immediately after executing the first instruction
(Figure 58, top), and the value of the LEDs should change accordingly after
executing the sw instruction (Figure 58, bottom).
f. You can also view other memory locations, such as the RAM addresses that
store the machine instructions of your program. Open another memory range
starting at 0x0 (initial address assigned to the RAM memory) and occupying
0x100 bytes (Figure 59). You will see the instructions from the LedsSwitches
program stored in the address range 0x90-0xC4, right after the startup
program (Startup.S).
g. You can view the machine code for the program’s instructions by opening the
disassembly of the program available at:
[RVfpgaPath]/RVfpga/examples/LedsSwitches/.pio/build/swervolf_nexys/firm
ware.dis (see Figure 60). Compare the two figures and try to identify the
instructions of the program.
E. LedsSwitches_C-Lang program
Program LedsSwitches_C-Lang.c (Figure 61) does the same as the LedsSwitches.s
program shown previously (Figure 52) but it is written in C instead of assembly.
Follow the next steps for running and debugging this program on the FPGA board:
1. RVfpga is already programmed on the FPGA board if you executed the previous
examples, so you should not need to program it again. However, if you do need to
reprogram RVfpga onto the board again, do it as explained in Section A, using the
LedsSwitches_C-Lang example instead of the AL_Operations example.
2. On the top menu bar, click on File → Open Folder, and browse into directory
[RVfpgaPath]/RVfpga/examples/. Select directory LedsSwitches_C-Lang and click OK.
4. Then, start debugging. The program will start executing and will stop at the breakpoint
(Figure 62).
6. You can view the execution of the program in C as above or you can view the execution
of the assembly program generated by the compiler, by clicking on Switch to assembly
highlighted in Figure 63.
7. The program in assembly (Figure 64) first reads the value in the Switches with a load
instruction (lw a5,1024(a4)) and then writes it to the LEDs with a store instruction (sw
a5,1028(a4)). Execute it step by step, change the switches and verify that the LEDs
change to reflect the new switch values.
F. HelloWorld_C-Lang program
The second C example prints a short message to your shell through the serial port. To view
this message, you could use any terminal emulator such as gtkterm, minicom, etc.; however,
PlatformIO provides its own serial monitor, so here we show how to use this monitor.
For configuring PlatformIO serial monitor some parameters must be configured; specifically,
the data rate (in bits per second, or bauds) for serial data transmission must be established,
which we can do by using the monitor_speed parameter in file platformio.ini (note that this
file is part of your PlatformIO projects). See Figure 65.
In addition, you need to add yourself to the dialout, tty and uucp groups by typing the
following commands in a terminal:
sudo usermod -a -G dialout $USER
sudo usermod -a -G tty $USER
sudo usermod -a -G uucp $USER
After the three commands, restart your computer so that the changes in groups can take
effect.
Windows/macOS: Windows and macOS users do not need to complete the above step.
Furthermore, this program uses the Processor Support Package (PSP) and Board Support
Package (BSP) provided by WD within its Firmware Package
(https://github.com/westerndigitalcorporation/riscv-fw-infrastructure). These libraries are
included in the project using a specific command in platformio.ini (framework = wd-
riscv-sdk), as shown in Figure 65, and by including the proper files at the beginning of the
C program, as shown in Figure 66. You can find the complete libraries in your system in the
following paths:
- PSP: ~/.platformio/packages/framework-wd-riscv-sdk/psp/
- BSP: ~/.platformio/packages/framework-wd-riscv-
sdk/board/nexys_a7_eh1/bsp/
These libraries provide many functions and macros that allow you do many things such as
using interrupts, printing a string, reading/writing individual registers… In this example, we
will use the printfNexys function for printing a message on the serial monitor. In
subsequent examples and in the labs we will show how to use other functions and macros
for different purposes.
Follow the next steps for running and debugging this code on the FPGA board:
1. RVfpga is already programmed on the FPGA board if you executed the previous
examples, so you should not need to program it again. However, if you do need to
reprogram RVfpga onto the board again, do it as explained in Section A, using the
HelloWorld_C-Lang example instead of the AL_Operations example.
2. Open VSCode. PlatformIO should automatically open within VSCode when you open
VSCode. On the top bar, click on File → Open Folder, and browse to directory
[RVfpgaPath]/RVfpga/examples/. Select the HelloWorld_C-Lang folder and click OK.
3. The program HelloWorld_C-Lang.C (Figure 67) initializes the UART (function uartInit)
and then sends the string through the serial port, using function printfNexys (you can
find the implementation of these functions in file ~/.platformio/packages/framework-wd-
riscv-sdk/board/nexys_a7_eh1/bsp/bsp_printf.c). It then delays some time before going
back to the beginning of the loop.
4. Launch the debugger in PlatformIO. When the program starts to run, open the serial
monitor, by clicking on the plug button available on the bottom of VS Code (Figure 68).
5. The serial monitor repeatedly prints the message “HELLO WORLD !!!”, as shown in
Figure 69.
G. VectorSorting_C-Lang program
Finally, we show another C program that sorts the elements of a vector, A, from largest to
smallest and places the sorted values in a second vector, B. Vector A values are replaced
with zeroes. Figure 70 shows the program.
1 #define N 8
2
3 int A[N]={7,3,25,4,75,2,1,1};
4 int B[N];
5
6 int main ( void )
7 {
8 int max, ind, i, j;
9
10 for(j=0; j<N; j++){
11 max=0;
12 for(i=0; i<N; i++){
13 if(A[i]>max){
14 max=A[i];
15 ind=i;
16 }
Follow the next steps for running and debugging this program on the FPGA board:
1. RVfpga is already programmed on the FPGA board if you executed the previous
examples, so you should not need to program it again. However, if you do need to
reprogram RVfpga onto the board again, do it as explained in Section A, using the
VectorSorting_C-Lang example instead of the AL_Operations example.
2. On the top menu bar, click on File → Open Folder, and browse into directory
[RVfpgaPath]/RVfpga/examples/. Select the VectorSorting_C-Lang folder and click OK.
3. Place a breakpoint at line 10 and start debugging. The execution will stop at the
beginning of the for loop (Figure 71). Expand the VARIABLES section in the Debugger
Side Bar and analyse the values of the A and B arrays (highlighted in red in Figure 71).
4. Now place another breakpoint at line 18 and continue execution by clicking on (see
Figure 72). Open the Memory Display (as explained for the LedsSwitches program,
Figure 54) and show 0x50 bytes starting from address 0x2148 (see Figure 72), which is
the address where vector A is stored in memory for this program. You can view the initial
values of vectors A (in the range 0x2148-0x2167) and B (in the range 0x2178-0x2197).
Note that you can easily find out the address where vectors A and B are stored in memory
by switching to assembly, as explained in Figure 63, and analysing any of the instructions
that access these vectors (Figure 73). As you see in the figure, in most cases the comments
provide this information; however, you could also step up to those instructions and see the
value that is stored in the register.
Click twice on the Step Over button ( ), and you will see the first component of B
stored in memory and the corresponding value in A set to 0 (see Figure 74).
5. Remove all breakpoints, continue execution and pause it after several seconds – at
which point the program will have finished executing. Again, analyse the values stored in
the A and B arrays. As shown in Figure 75, vector B holds the values from the original
vector A sorted from largest to smallest and vector A holds all zeroes (you can see this
both at the variables list on the left and at the memory console on the right).
H. DotProduct_C-Lang
The last example program, DotProduct_C-Lang.c, computes the dot product of two vectors.
The program has two functions: main and dotproduct. The first function invokes the second
one with three input arguments: vector size, and the initial addresses of two vectors. Then,
the dotproduct function computes the dot product of the two vectors and returns the result.
In this example we operate with real numbers (note that the data type for the variables x, y
and dot, is double). However, the SweRV EH1 processor does not include floating-point
support. Thus, the example uses floating point emulation through the software floating point
library provided by gcc (https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html).
This library is used whenever -msoft-float is included to disable generation of floating
point instructions.
Follow the next steps for running and debugging this code on the FPGA board:
1. RVfpga is already programmed on the FPGA board if you executed the previous
examples, so you should not need to program it again. However, if you do need to
reprogram RVfpga onto the board again, do it as explained in Section A, using the
DotProduct_C-Lang example instead of the AL_Operations example.
2. On the top menu bar, click on File → Open Folder, and browse into directory
[RVfpgaPath]/RVfpga/examples/. Select directory DotProduct_C-Lang and click OK.
3. Before calling the debugger, set a breakpoint at line 10 and another one at line 19 (see
Figure 77).
4. Then, start debugging. The program will start executing; stop it at the first breakpoint
(see Figure 77).
5. On the Debugger sidebar, expand the Variables section (see Figure 77). The two vectors
contain the initial values assigned in main. The dot variable is initialized to 0.
7. Switch to assembly (as you did in Figure 63). You can see the floating point emulation
routines and analyse them in detail by stepping into them (see Figure 78).
8. Switch back to C and delete the two breakpoints. Continue execution and pause it. You
will see that the value of variable dot will change to the dot product of the two vectors
(Figure 79).
9. Once you are finished exploring this program, close the project by clicking on File →
Close Folder.
In this section, you will run the first program used in the previous section (AL_Operations) on
RVfpgaSIM using Verilator. Verilator is a hardware description language (HDL) Simulator
that simulates the Verilog that defines RVfpga (available at [RVfpgaPath]/RVfpga/src). This
way of running the SoC allows you to analyse the internal signals of the system, which is
especially useful for future labs and exercises where we add internal operations or new
hardware to the SoC.
Here we show how to use Verilator to view the cycle-by-cycle instructions and register
values of the AL_Operations, the first simple assembly program that you executed and
debugged in Section 5 (Figure 43). You will generate the simulation trace using PlatformIO
and then add the clock, instructions for both ways of the super-scalar processor, and register
x28 (i.e., register t3) signals to the simulation waveform, and view with GTKWave the
instruction and register signals change as the program executes.
cd [RVfpgaPath]/RVfpga/verilatorSIM
make clean
make
File Vrvfpgasim (the RVfpga simulation binary), should be generated inside directory
[RVfpgaPath]/RVfpga/verilatorSIM.
Windows: if you are using Windows, you must do these same steps inside the Cygwin
terminal (refer to Appendix C for the detailed instructions). Note that the C: Windows folder
can be found inside Cygwin at: /cygdrive/c. All the other instructions from this section are the
same as those described for Linux.
Once the simulator binary (Vrvfpgasim) has been generated, you will use it inside PlatformIO
for generating the simulation trace (trace.vcd) of program AL_Operations.
3. On the top bar, click on File→Open Folder... (Figure 80), and browse into directory
[RVfpgaPath]/RVfpga/examples/
4. Select directory AL_Operations (do not open it, but just select it) and click OK. The
example will open in PlatformIO.
5. Open file platformio.ini. Establish the path to the RVfpga simulation binary generated in
the first step (Vrvfpgasim) by editing the following line (see Figure 81).
board_debug.verilator.binary =
[RVfpgaPath]/RVfpga/verilatorSIM/Vrvfpgasim
6. Run the simulation by clicking on the PlatformIO icon in the left menu ribbon , then
expand Project Tasks → env:swervolf_nexys → Platform and click on Generate Trace,
as shown in Figure 82.
As an alternative, you can generate the trace from a PlatformIO terminal window. For
that purpose, click on the button (PlatformIO: New Terminal button) at the bottom of
the PlatformIO window for opening a new terminal window, and then type (or copy) the
following command into the PlatformIO terminal: pio run --target
generate_trace
7. A few seconds after the previous step, file trace.vcd should have been generated inside
[RVfpgaPath]/RVfpga/examples/AL_Operations/.pio/build/swervolf_nexys, and you can
open it with GTKWave.
gtkwave [RVfpgaPath]/RVfpga/examples/AL_Operations/.pio/build/swervolf_nexys/trace.vcd
8. Now you will add clock, instruction, and register signals. On the top left pane of
GTKWave, expand the hierarchy of the SoC so that you can add signals to the graph.
Expand the hierarchy into TOP → rvfpgasim → swervolf → swerv_eh1 → swerv, and
click on module ifu (it will highlight as shown in the Figure 83), select signal clk (which is
the clock used for the core) and drag it into the white Signals pane or the black Waves
pane on the right.
9. Do a Zoom Fit and then Zoom in several times so that you can view the clock signal
change (Figure 84).
10. Now add the signals that show the instructions that execute in each way of the two-way
superscalar RISC-V core. In the same module (ifu) look for signals ifu_i0_instr[31:0] and
ifu_i1_instr[31:0] (Figure 85), and drag them into the black Waves pane. The prefix ifu
indicates the instruction fetch unit, i0 indicates superscalar way 0 and i1 indicates
superscalar way 1; instr[31:0] indicates the 32-bit instruction.
Figure 85. Add signals ifu_i0_instr[31:0] and ifu_i1_instr[31:0] to the timing waveform
11. Now add the signal that holds the value of register t3 (i.e., register number 28, x28).
Figure 87 shows the AL_Operations.S program and its equivalent machine instructions.
REPEAT:
addi t3, t3, 6 # t3 = t3 + 6 # 0x006E0E13
addi t3, t3, -1 # t3 = t3 – 1 # 0xFFFE0E13
andi t3, t3, 3 # t3 = t3 AND 3 # 0x003E7E13
Now view the signals change as the program executes. We expect the instructions and t3
(register x28) to become the values shown in Figure 88 as the program runs:
12. Zoom in around 10100 ns, where you will analyse the execution of the three arithmetic-
logic instructions of the first and second iterations of the loop (Figure 89). The first two
instructions (li t3, 0x0 = 0x00000E13 and addi t3, t3, 6 = 0x006E0E13) are
fetched first, one in each way of the superscalar RISC-V processor as shown on signals
ifu_i0_instr[31:0] and ifu_i1_instr[31:0]. The next two instructions (addi t3, t3, -1 =
0xFFFE0E13 and and.i t3, t3, 3 = 0x003E7E13) are fetched in the next cycle.
The last two instructions are fetched (beq zero, zero, REPEAT = 0xFE000CE3
and nop = 0x00000013) in the next cycle.
Because of the SweRV core’s 9-stage pipelined processor and dependencies, the
effects of the instructions are seen eight or more cycles after the instructions are fetched.
Eight cycles after the first and second instructions are fetched, x28 (t3) becomes 0
(which it was already) because of the first instruction: li t3, 0x0 (0x00000E13). One
cycle later, x28 is updated to 0x6 because of the next instruction: addi t3, t3, 6
(0x006E0E13). Next, x28 updates to 5 because of the next instruction: addi t3, t3,
-1 (0xFFFE0E13). Finally, x28 updates to 1 because of the next instruction: andi t3,
t3, 3 (0x003E7E13). Then the next two instructions are fetched: beq zero, zero,
REPEAT (0xFE000CE3) and nop (0x00000013), the branch is taken and the loop
repeats. This is as predicted in Figure 88. Using a similar reasoning, you can analyse the
second iteration, which is also highlighted in Figure 84 and predicted in Figure 83.
Figure 89. Execution of the three Arithmetic-Logic instructions from the example
Windows: All the instructions described in this section should work for Windows (we’d like to
thank Jean-François Monestier, who was the first to port Whisper to Windows: https://jean-
francois.monestier.me/porting-western-digital-swerv-iss-to-windows/). Note that a pop-up
window may ask you to allow Whisper through the Windows firewall.
macOS: All the instructions described in this section also work for macOS.
Whisper can be executed both using the command line or using an IDE (integrated
development environment) such as Eclipse or PlatformIO. In this section we demonstrate
one example to show how to simulate a program with Whisper in PlatformIO. You can then
use the same steps as the ones described here to simulate other programs.
We start by using the Whisper ISS to simulate AL_Operations, the first simple assembly
program that you executed and debugged in Section 5 (see Figure 43). Follow the next
steps for running and debugging this code on Whisper:
1. Open VSCode (and PlatformIO). On the top menu bar, click on File → Open Folder and
browse into directory [RVfpgaPath]/RVfpga/examples/, select (but do not open) directory
AL_Operations and then click OK.
The following appendices show how to use the native RISC-V toolchain and OpenOCD
(instead of PlatformIO) in Linux, how to install in Windows the drivers to download the
bitstream using PlatformIO, how to install Verilator and GTKWave on Windows and Mac OS
machines, and how to program RVfpga using Vivado. Table 9 lists all of the appendices
available in this RVfpga Getting Started Guide.
Appendix A should be used by those who want to natively compile and run/debug programs
using the native gcc/gdb tools and OpenOCD. However, it is recommended that RVfpga
users use PlatformIO instead, as described in this Getting Started Guide.
macOS users must follow instructions in Appendix D in order to simulate the RVfpga
RTL using Verilator and GTKWave.
The following steps are not needed if you are using PlatformIO, as described earlier in this
guide. Using PlatformIO, Vivado, and Verilator or Whisper is the recommended method for
running, debugging, and simulating RISC-V programs, but the following instructions are
provided for anyone who is interested in using the native RISC-V toolchain and OpenOCD in
place of PlatformIO and the Vivado Hardware Manager.
In this section we describe how to install natively in your Ubuntu 18.04 machine the RISC-V
toolchain, OpenOCD and Whisper. These tools only substitute PlatformIO; installing Vivado
and Verilator is still required as explained in Section 5 of this GSG.
RISC-V Toolchain
Here we show how to install the complete RISC-V Toolchain – i.e., gnu compiler, debugger,
etc. – on your computer. Installation instructions are provided by RISC-V International at:
https://github.com/riscv/riscv-gnu-toolchain. These instructions are summarized below.
NOTE: Installing the RISC-V toolchain and OpenOCD could take several hours – mostly
waiting while the toolchain downloads, compiles, and installs
At a terminal, type the following (the process can take more than an hour, but most of the
time is spent waiting while the programs are downloaded and installed):
• sudo apt-get install git autoconf automake autotools-dev curl libmpc-
dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo
gperf libtool patchutils bc zlib1g-dev libexpat-dev
• git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
• cd riscv-gnu-toolchain/
• ./configure --prefix=/opt/riscv --with-arch=rv32imc
• sudo make (If possible use sudo make -j$(nproc) as it significantly decreases
compile time)
• export PATH=$PATH:/opt/riscv/bin (change the path in your system)
OpenOCD
OpenOCD is an open on-chip debugger that allows users to program and debug embedded
target devices. Follow the next steps to install RISC-V OpenOCD onto your computer:
• sudo apt-get install libusb-1.*
• sudo apt-get install pkg-config
• git clone https://github.com/riscv/riscv-openocd.git
• cd riscv-openocd/
• ./bootstrap
• ./configure --prefix=/opt/riscv --program-prefix=riscv- --enable-ftdi
Whisper
Follow the next steps to install Whisper onto your computer (instructions are available at:
https://github.com/chipsalliance/SweRV-ISS but are also summarized below):
➢ apt-cache policy libboost-all-dev
➢ sudo apt-get install libboost-all-dev
➢ cd [RVfpgaPath]
➢ git clone https://github.com/chipsalliance/SweRV-ISS
➢ cd SweRV-ISS
➢ make BOOST_DIR=/usr/include/boost
➢ export PATH=$PATH:[RVfpgaPath]/SweRV-ISS/build-Linux (replace
[RVfpgaPath] as required).
II. Executing a program on RVfpga using the Nexys A7 FPGA board using
OpenOCD
1. Go into the project directory that contains the bitfile for RVfpga:
cd [RVfpgaPath]/RVfpga/src
Step B. Execute LedsSwitches, the program that reads the Switches and prints their
state on the LEDs
In that directory you will find the Makefile for compiling the sources, the link script, a
python script, and a symbolic link to the LedsSwitches.S program.
Once OpenOCD starts running, you will see several messages including one that
says:
Info : Listening on port 4444 for telnet connections
These three commands (1) load the LedsSwitches.elf program onto RVfpga, (2) set
the program counter (PC) to 0 (the address location of the program’s first instruction),
and (3) resume execution.
The program will start to run on RVfpga, the RISC-V SweRVolf SoC that was already
downloaded onto the Nexys A7 FPGA board in Step 2. The program makes the
LEDs show the state of the switches. As you toggle the switches, the LEDs should
immediately change to reflect the value of the switches.
8. In the other terminal where telnet is running (from Step 6), exit the telnet connection
by typing:
exit
In that directory you will find the Makefile for compiling the sources, the link script, a
python script, and a symbolic link to the AL_Operations.S program.
This will connect to OpenOCD and load the AL_Operations.elf program into memory.
13. You should now be able to debug the program. Type the following sequence and
analyse the outputs:
i. disas 0,20
This shows the assembly code from address 0 to 20 (not including address
20).
ii. i r t3
This displays the contents of register t3. Alternately, you could type the
longer version: info reg t3.
iii. i r pc
Figure 94. Print the value contained in register PC, that points to the first instruction
iv. stepi
i r t3
stepi
i r t3
stepi
i r t3
stepi
i r t3
Figure 95. Execute several instructions one by one and view the t3 register
cd [RVfpgaPath]/RVfpga/verilatorSIM
make clean
make
File Vrvfpgasim (the RVfpga simulation binary), should be generated inside directory
[RVfpgaPath]/RVfpga/verilatorSIM.
After a few seconds, stop the simulation by entering ^C in the terminal. File trace.vcd
should have been generated, and you can open it with GTKWave.
gtkwave trace.vcd
6. Follow the instructions provided in steps 8 to 12 of Section 7 for adding signals to the
graph and analysing them.
<_start>:
0: 00000e13 li t3,0
whisper> step
#1 0 00000000 00000e13 r 1c 00000000 addi x28, x0, 0x0
whisper> step
#2 0 00000004 006e0e13 r 1c 00000006 addi x28, x28, 0x6
whisper> step
#3 0 00000008 fffe0e13 r 1c 00000005 addi x28, x28, -0x1
whisper> step
#4 0 0000000c 003e7e13 r 1c 00000001 andi x28, x28, 0x3
Once you are finished debugging and exploring the program and registers using whisper,
exit by typing quit in the terminal.
https://zadig.akeo.ie/
Click on Zadig 2.5 and save the executable. Then run it (zadig-2.5.exe), which is located
where you downloaded it. You can also type zadig into the Start menu to find it. You will
probably be asked if you want to allow Zadig to make changes to your computer and if you
will let it check for updates. Click Yes both times.
Connect the Nexys A7 Board to your computer and switch it on. In Zadig, click on Options →
List All Devices (see Figure 97).
If you click on the drop-down menu, you will see Digilent USB Device (Interface 0) and
Digilent USB Device (Interface 1) listed. You will install new drivers for only Digilent USB
Device (Interface 0) (see Figure 98).
Figure 98. Install WinUSB driver for Digilent USB Device (Interface 0)
You will now replace the FTDI driver with the WinUSB driver, as shown in Figure 99. Click
on Replace Driver (or Install Driver) for Digilent USB Device (Interface 0). You are installing
the driver for the Nexys A7 board or, if you previously installed Vivado, you are replacing the
FTDI driver used by Vivado with the WinUSB driver used by PlatformIO.
Next time you use PlatformIO you do not need to re-install the driver. However, note that
this driver is not compatible with Vivado in Windows. So you can no longer use Vivado
to download bitfiles to the FPGA board. If you wanted to use Vivado to download bitfiles (not
recommended) you would need to revert the driver back to the original driver installed with
Vivado, as described in Appendix E.
Cygwin installation:
2. Execute the setup file in your machine by double-clicking on it (Figure 101). Click Next
several times, maintaining the default options. The installer will ask you to Choose a
Download Site (Figure 102), you can choose any one of them.
3. After several steps, you will reach the Select Packages window (Figure 103). Select the
Full view, as shown in Figure 103.
4. The complete list of packages that you can install will appear (Figure 104). In the Search
box, select the specific packages that you want to install.
To be able to compile Verilator and generate a new simulator binary, you need to install the
following packages:
Include at least these packages in your Cygwin installation. Select them one-by-one
following the steps below (we only show the detailed steps for the first package in the list,
git; the process is the same for the other packages):
- Look for the git package in the Search box (Figure 105).
- Select the most up-to-date version in the dropdown menu and tick the box (Figure
106).
Figure 106. Select the most up-to-date version and tick the box
5. Once you have selected the nine packages, click Next in the subsequent windows to
include these packages in your Cygwin installation (the installation process, see Figure
107, may take several minutes) and finalize the installation by clicking Finish (Figure
108).
6. If you need to add a package to your Cygwin installation, repeat steps 2-5 for that
package.
Verilator installation:
1. Open the Cygwin terminal (Figure 109), available on your Windows Desktop or from the
Start menu.
2. Build and install Verilator by following these steps. This may take some time (even
hours), depending on the speed of your computer:
GTKWave installation:
gcc installation:
In order to build a new simulator using Verilator, a compiler toolchain needs to be installed in
the system. There are many ways to install a valid compiler toolchain. We cite two of them
below:
1. Install the XCode Command Line Tools. Note that this will install LLVM, but a gcc
command will be anyhow available after installation. To do so, type the following
command in a Terminal window:
▪ xcode-select -install
Verilator installation:
Installing Verilator with Homebrew is as simple as typing the following command in an open
Terminal:
gtkwave installation:
Once again, we will use Homebrew to install gtkwave. But this time we need to use cask
because it is a GUI macOS application. Type the following commands in an open Terminal:
After the installation, an icon for gtkwave.app should appear in the Application folder. In
order to use it from the command line, you may need to install Perl’s Switch module:
WINDOWS: Before following the next steps, in Windows you need to revert the drivers back
to the ones used by Vivado as explained at the end of this Appendix (Appendix E).
e. The Hardware Manager opens and informs you that no hardware target is open. Open
the target by clicking on Open target – Auto connect (Figure 111).
h. After a few seconds, the FPGA will be programmed with RVfpga, the SweRVolf SoC
targeted to an FPGA (see Figure 24).
i. Finally, close the Hardware Manager by clicking on the X button on the top right of the
Hardware Manager pane in Vivado (Figure 113), so that Vivado releases the board.
Next, expand Universal Serial Bus Devices, right-click on Digilent USB Device, and select
Properties (see Figure 115).
Figure 115. Open driver properties for Digilent’s Nexys A7 FPGA board
In the Properties window, click on the Driver tab and select Roll Back Driver (see Figure
116).
A window will pop up asking why you are rolling back the driver. Select a reason and click
Yes (see Figure 117).
Now you can load bitfiles onto the FPGA board using Vivado. However, you will still need to
use Zadig to replace the Nexys A7 board’s driver, so that PlatformIO can download the
program onto RVfpga. Thus, it is recommended that you use PlatformIO to download bitfiles
as well (instead of using Vivado) – this will keep you from continually having to swap drivers.
Abstract: Node devices for IoT need to be energy efficient and cost effective, but they do not
require a high computing power in a large number of scenarios. This changes substantially in
an Industrial IoT environment, where massive sensor utilization and the fast pace of events
require more processing power. A custom developed node, using an efficient processor and a
high performance and feature-full operating system, may balance these requirements and
offer an optimal solution. This project addresses the hardware implementation, using an
Artix-7 FPGA, of a prototype IoT node based on the RISC-V processor architecture. The
project presents the implemented custom SoC and the development of the necessary Zephyr
OS drivers to support a proof-of-concept application, which is deployed in a star network
around a custom border router. End-to-end messages can be sent and received between the
node and the ThingSpeak cloud platform. This thesis includes an analysis of the existing
RISC-V processor implementations, a description of the required elements, and a detailed
guide to environment configuration and project design.