Skip to content

User Guide

Introduction

The process of developing a new application with RISC-V Steel involves two main steps:

  1. 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.

  2. 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:

1. Clone the RISC-V GNU Toolchain repository
git clone https://github.com/riscv-collab/riscv-gnu-toolchain
2. Install dependencies (Ubuntu)
sudo apt-get install \
    autoconf automake autotools-dev curl python3 python3-pip libmpc-dev libmpfr-dev \
    libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc \
    zlib1g-dev libexpat-dev ninja-build git cmake libglib2.0-dev libslirp-dev
2. Install dependencies (Fedora/CentOS/RHEL/Rocky)
sudo yum install \
    autoconf automake python3 libmpc-devel mpfr-devel gmp-devel gawk  bison flex \
    texinfo patchutils gcc gcc-c++ zlib-devel expat-devel libslirp-devel
2. Install dependencies (Arch Linux)
sudo pacman -Syyu \
    autoconf automake curl python3 libmpc mpfr gmp gawk base-devel bison flex texinfo \
    gperf libtool patchutils bc zlib expat libslirp
2. Install dependencies (OS X)
brew install python3 gawk gnu-sed gmp mpfr libmpc isl zlib expat texinfo flock libslirp
3. Configure the RISC-V GNU Toolchain for RISC-V Steel
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.

4. Compile and install
make -j $(nproc)

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.

1. Clone RISC-V Steel repository
git clone https://github.com/riscv-steel/riscv-steel
2. Copy the template project (Bare-metal)
cp -r riscv-steel/templates/baremetal my_project/
2. Copy the template project (FreeRTOS)
cp -r riscv-steel/templates/freertos my_project/

Find the main.c file in the project folder and write the code for the new application in this file.

3. Build the application (Bare-metal)
cd my_project/ && make PREFIX=/opt/riscv
3. Build the application (FreeRTOS)
cd my_project/ && make PREFIX=/opt/riscv CLOCK_FREQUENCY=<freq_in_hertz>

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:

Successful build report
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.

rvsteel_wrapper.v
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:

  1. Start a new project: Open the EDA tool provided by your FPGA vendor (e.g., AMD Vivado, Intel Quartus, Lattice iCEcube).

  2. Add files to the project: Include rvsteel_wrapper.v to the project and all files in the hardware/ folder of RISC-V Steel repository.

  3. Create a design constraints file: Map the ports of rvsteel_wrapper.v to the corresponding devices on the FPGA board.

  4. Run the synthesis process: This includes placing and routing, as well as any other necessary steps to generate a bitstream for the FPGA.

  5. Generate the bitstream: Once completed, program the FPGA with the generated bitstream.

The application will start running immediately after you program the FPGA!