User Guide
Introduction
The process of developing a new application with RISC-V Steel involves two main steps:
-
Building the application
The first step is to write the source code for the new application and build it with the RISC-V GNU Toolchain. The build process generates a
.hex
file that is later used to initialize the memory of RISC-V Steel. -
Running on an FPGA
Once you have built the application, you can run it on RISC-V Steel. To do this, you need to implement an instance of RISC-V Steel on an FPGA and initialize it with the
.hex
file generated in the first step.
Prerequisites
To build software for RISC-V you need the RISC-V GNU Toolchain, a suite of compilers and development tools for the RISC-V architecture.
Run the commands below to install and configure the RISC-V GNU Toolchain for RISC-V Steel:
git clone https://github.com/riscv-collab/riscv-gnu-toolchain
cd riscv-gnu-toolchain && ./configure --with-arch=rv32izicsr --with-abi=ilp32 --prefix=/opt/riscv
Important: The --prefix
option defines the installation folder. You need to set it to a folder where you have rwx
permissions. The command above assumes you have rwx
permissions on /opt
.
Building the application
RISC-V Steel offers two template projects to help you start developing new applications: a bare-metal template and a more sophisticated FreeRTOS template.
Both templates include a main.c
file where you place the source code for the new application. These projects use CMake to configure the RISC-V GNU Toolchain for RISC-V Steel, which simplifies the process of compiling and linking the software.
To start a new application, follow the steps below.
Find the main.c
file in the project folder and write the code for the new application in this file.
The PREFIX
variable must specify the folder where the RISC-V GNU Toolchain is installed. For the FreeRTOS template, you also need to set the CLOCK_FREQUENCY
variable to match the clock frequency of the FPGA board where the application will run.
A successfull build ends with a message like this:
Memory init file: build/freertos.hex
Binary executable: build/freertos.elf
Disassembly: build/freertos.objdump
Memory usage report (MEMORY_SIZE = 32K)
text data bss total filename
14092 304 9196 23592 freertos.elf
The .hex
file generated by the build process will be used in the next step to initialize the memory of RISC-V Steel.
Running on an FPGA
Once you have generated the .hex
file you can implement RISC-V Steel on an FPGA to run the application. This process consists of two steps:
-
First, create a wrapper module that includes an instance of RISC-V Steel, configure it for the target FPGA, and initialize it with the application to be run using the
.hex
file. -
Next, use the EDA software provided by your FPGA vendor to synthesize the wrapper module and program the FPGA with it.
1. Creating the wrapper module
Using your preferred text editor, create a Verilog file called rvsteel_wrapper.v
and add the code provided below. Make sure to modify the file according to the instructions in the comments.
module rvsteel_wrapper (
input wire clock ,
input wire reset ,
input wire halt ,
// UART pins
// You can remove them if your application does not use the UART controller
input wire uart_rx ,
output wire uart_tx ,
// General Purpose I/O pins
// You can remove them if your application does not use the GPIO controller
input wire [3:0] gpio_input ,
output wire [3:0] gpio_oe ,
output wire [3:0] gpio_output ,
// Serial Peripheral Interface (SPI) pins
// You can remove them if your application does not use the SPI controller
output wire sclk ,
output wire pico ,
input wire poci ,
output wire [0:0] cs
);
reg reset_debounced;
always @(posedge clock) reset_debounced <= reset;
reg halt_debounced;
always @(posedge clock) halt_debounced <= halt;
rvsteel #(
// Frequency (in Hertz) of the `clock` pin
.CLOCK_FREQUENCY (50000000 ),
// Absolute path to the .hex file generated by the build
.MEMORY_INIT_FILE ("/path/to/myapp.hex" ),
// The size you want for the memory (in bytes)
.MEMORY_SIZE (8192 ),
// The UART baud rate (in bauds per second)
.UART_BAUD_RATE (9600 ),
// Don't change it unless you explicitly modified the boot address
.BOOT_ADDRESS (32'h00000000 ),
// Width of the gpio_* ports
.GPIO_WIDTH (4 ),
// Width of the cs port
.SPI_NUM_CHIP_SELECT (1 ))
rvsteel_instance (
.clock (clock ),
.reset (reset_debounced ),
.halt (halt_debounced ),
.uart_rx (uart_rx ),
.uart_tx (uart_tx ),
.gpio_input (gpio_input ),
.gpio_oe (gpio_oe ),
.gpio_output (gpio_output ),
.sclk (sclk ),
.pico (pico ),
.poci (poci ),
.cs (cs ));
endmodule
2. Synthesizing rvsteel_wrapper.v
The steps to synthesize a Verilog module can differ based on the FPGA model and vendor, but they generally follow this sequence:
-
Start a new project: Open the EDA tool provided by your FPGA vendor (e.g., AMD Vivado, Intel Quartus, Lattice iCEcube).
-
Add files to the project: Include
rvsteel_wrapper.v
to the project and all files in thehardware/
folder of RISC-V Steel repository. -
Create a design constraints file: Map the ports of
rvsteel_wrapper.v
to the corresponding devices on the FPGA board. -
Run the synthesis process: This includes placing and routing, as well as any other necessary steps to generate a bitstream for the FPGA.
-
Generate the bitstream: Once completed, program the FPGA with the generated bitstream.
The application will start running immediately after you program the FPGA!