Skip to content

Instantly share code, notes, and snippets.

@hsandid
Last active November 20, 2023 16:42
Show Gist options
  • Save hsandid/7ba675b75c47a3e0460878e92318f69d to your computer and use it in GitHub Desktop.
Save hsandid/7ba675b75c47a3e0460878e92318f69d to your computer and use it in GitHub Desktop.

Cross-Compilation Tutorial : C to RISC-V (+ Vector Extension)

To cross-compile C code to a RISC-V target, we need to following compiler toolchains :

  • EPI Fork of the LLVM/Clang Toolchain, which is modified to offer experimental support for RISC-V Vector instructions, as well as vector intrinsics which can be directly called in C code.

  • RISC-V GNU Toolchain, which is needed to supplement the missing library/include dependencies in the LLVM/Clang toolchain when cross-compiling.

Installation Instructions

Step 1 :

Clone the RISC-V GNU Toolchain, along with its submodules (6.5 GB download) :

$ git clone --recurse-submodules https://github.com/riscv/riscv-gnu-toolchain

Step 2 :

Install all standard packages required to build the toolchain.

On Ubuntu, you should run the following commands :

$ sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev

Step 3 :

Build the Newlib cross-compiler available in the RISC-V GNU Toolchain. You can change the prefix argument to your desired installation path :

./configure --prefix=/opt/riscv
make

Make sure to remember the location of your build folder or save it as an environment variable, as we'll use it later.

Step 4 :

Clone the EPI fork of the LLVM/Clang toolchain (1.5 GB download) :

$ git clone https://repo.hca.bsc.es/gitlab/rferrer/llvm-epi.git

Step 5 :

To build the fork of the LLVM/Clang toolchain, we need to install the ninja build system. You can find a reference to either build it from source, or download it with your package manager here.

Step 6 :

Before building the fork the LLVM/Clang toolchain, make sure to specify that'd you'd only like to build for RISC-V/X86 target by adding the line -DLLVM_TARGETS_TO_BUILD="X86" \ right after line 261 -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="RISCV" \. The build process might take a long time :

$ mkdir build
$ cd build
$ ../setup-cmake-llvm-clang debug
$ make

If you encounter an error related to gcc-index during the build process, open the file setup-cmake-llvm-clang.sh on the root of the folder, and edit the word -gdb-index on line 229 to --gdb-index (i.e. add a '-').

Step 7 (Optional) :

If you'd like to use the SPIKE simulator to debug RISC-V binaries with Vector Instructions, you must do the following :

Clone the RISC-V Proxy kernel, which can host statically-linked RISC-V ELF binaries, and build it :

# Clone PK repository
$ git clone https://github.com/riscv/riscv-pk.git

# Open a terminal in the cloned directory
$ mkdir build
$ cd build

# Here, the $RISCV symbol is a variable representing
# your RISC-V build path
$ ../configure --prefix=$RISCV
$ make
$ make install

Clone the RISC-V SPIKE simulator, install required dependencies, and build it :

# Clone SPIKE repository
$ git clone https://github.com/riscv/riscv-isa-sim.git

# Open a terminal in the cloned directory
$ apt-get install device-tree-compiler
$ mkdir build
$ cd build

# Here, the $RISCV symbol is a variable representing
# your RISC-V build path
$ ../configure --prefix=$RISCV
$ make
$ make install

Cross-compilation Example

  • Reference for C vector intrinsics offered by the LLVM/Clang EPI fork : Link

  • C Code Examples making use of the vector intrinsics : Link

The command line options --gcc-toolchain and ---sysroot are there to specify additional Includes and Libraries which are present in the RISC-V GNU Toolchain.

  • --gcc-toolchain=/path/to/risc-v-toolchain-build
  • --sysroot=/path/to/risc-v-toolchain-build/riscv64-unknown-elf/lib

Using the clang binaries in the llvm-epi/build/bin folder, you can cross-compile C to RISC-V with vector instruction support using the following command :

$ clang --target=riscv64 -march=rv64gcv0p9 -mepi -menable-experimental-extensions --gcc-toolchain=</path/to/risc-v-toolchain-build> --sysroot=</path/to/risc-v-toolchain-build/riscv64-unknown-elf> <C-Filename> -v -o <Desired-Object-Name>

To check if you have obtained proper RISC-V binaries, you can use the file command in linux, or the riscv64-unknown-elf-objdump binary in the risc-v-toolchain-build/bin folder :

$ file <RISC-V-Object-name>

# Or

$ riscv64-unknown-elf-objdump -d <RISC-V-Object-name>

If you'd like to obtain RISC-V assembly from your code, you can use the following command, which contains the -S argument :

$ clang --target=riscv64 -march=rv64gcv0p9 -mepi -menable-experimental-extensions --gcc-toolchain=</path/to/risc-v-toolchain-build> --sysroot=</path/to/risc-v-toolchain-build/riscv64-unknown-elf> -S <C-Filename> -v 

Using the SPIKE simulator

If you have followed Step 7 in the installation process, you will have a build of both RISC-V PK and the SPIKE simulator. To simulate a RISC-V program atop the proxy kernel, use the following command :

$ spike pk <RISC-V-Object-name>

More information about SPIKE's interactive debug mode can be found on it's repository here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment