Welcome to part one of RISC-V from scratch! Throughout RISC-V from scratch we will explore various low-level concepts (compilation and linking, primitive runtimes, assembly, and more), typically through the lens of RISC-V and its ecosystem. I am a web developer by trade, and as such I’m not exposed to these things on a daily basis. However, I think they are very interesting - hence this series! Join me on a very much unstructured journey into the depths of all things low-level.
In this first post, we’ll talk a little bit about what RISC-V is and why it’s important, set up a RISC-V toolchain, and finish up with building and running a simple C program on emulated RISC-V hardware.
So what is RISC-V?
RISC-V is an open-source, free-to-use ISA that began as a project at UC-Berkeley in 2010. The free-to-use aspect has been instrumental in its success and is quite a stark contrast to many other architectures. Take ARM for example - in order to create an ARM-compatible processor, you must pay an upfront fee of $1M - $10M as well as a 0.5% - 2% royalty fee per-chip. This free and open model makes RISC-V an attractive option to many groups of people - hardware startups who can’t foot the bill to create an ARM or other licensing-required processor, academic institutions, and (obviously) the open-source community.
RISC-V’s meteoric rise in popularity hasn’t gone unnoticed. ARM launched a now-taken down website that attempted (rather unsuccessfully) to highlight supposed benefits of ARM over RISC-V. RISC-V is backed by a ton of major companies, including Google, Nvidia, and Western Digital.
QEMU and RISC-V toolchain setup
We won’t be able to run any code on a RISC-V processor until we have an environment to do it in. Fortunately, we don’t need a physical RISC-V processor to do this - we’ll instead be using qemu. To install
qemu, follow the instructions for your operating system here. I’m using MacOS, so for me this was as easy as:
The instance of
qemu we just installed comes with a few machines (specified via the
qemu-system-riscv32 -machine option) ready to go, which is a nice convenience.
Next, let’s install a RISC-V compatible copy of OpenOCD and the RISC-V toolchain.
- Download prebuilt versions of the RISC-V OpenOCD and the RISC-V toolchain from here: https://www.sifive.com/boards
- Move and extract these files into a directory of your choosing. I elected to create one called
~/usys/riscvfor this and other RISC-V toolchain / QEMU needs. Remember the directory you choose as we’ll be using it both in this post and in the next.
- Set the
RISCV_PATHenvironment variables so other programs can find our toolchain. This may look different depending on your OS and shell - I had to add these exports to my
- We’ll also create a symbolic link into
/usr/local/binfor this executable so that we can run it without specifying the full path to
~/usys/riscv/riscv64-unknown-elf-gcc-<date>-<version>/bin/riscv64-unknown-elf-gccwhenever we want to use it.
Et voilà, we have a working RISC-V toolchain! All our executables, such as
riscv64-unknown-elf-ld, etc, are located in
Update to this section as of May 26, 2019:
Unfortunately, due to a bug introduced in RISC-V QEMU, running the freedom-e-sdk “hello world” program via QEMU no longer works. A patch has been introduced to address the issue, but for now you can feel free to skip this section. The
freedom-e-sdk is not necessary for future posts in this series. I will keep a watch on this issue and update this post after it’s fixed.
For more information, see this comment: https://github.com/sifive/freedom-e-sdk/issues/260#issuecomment-496037827
Now that we have our toolchain setup, let’s run an example RISC-V program. I previously linked a SiFive repository called freedom-e-sdk, which provides various programs we can try out. Begin by recursively cloning this repository:
As is tradition, let’s start with the “Hello, world” program provided by
freedom-e-sdk. We’ll use the
Makefile they provide to compile this program in debug mode against the “sifive-hifive1” target:
And finish by running it in QEMU:
This is a great start, but my goal with these blog posts is to truly shave the yak, and while we have confirmed that we have a working toolchain, there is a lot of magic hidden by the niceties of the
freedom-e-sdk examples. Note that we didn’t have to set up any linker files or startup code - SiFive’s provided board-support linker scripts, various Makefiles, and the freedom-metal library take care of this for us.
In part two of this series we’ll break free from the
freedom-e-sdk and make our own way. We’ll use
dtc to examine the hardware layout of a
qemu virtual machine, craft and examine a linker script, create a basic runtime to set up our stack, learn about some basic RISC-V assembly, and more.
The next post in this series has been posted, click here to check it out.