HiFive1 RISC-V Assembly

Posted: January 27, 2018


A couple years ago I started adding RISC-V to naken_asm but I never had any way to test the assembler. Recently I got a HiFive1 board and finally this weekend I wrote some code and got it uploaded to the board. The first program on here is just an LED blinking program. I'll put more projects on this page if/when I finish more.

Related Projects

ASM: SSE Image Processing, JIT Compiler, ARM Assembly, Easy Match, Mandelbots With SIMD


This a video showing load / store / jump / branch instructions are working and the code assembled by naken_asm can be uploaded to the board.


So the first steps in this project were just getting the assembler working. I started out with a riscv-spec 2.0 and found out later there was a 2.1 version of the spec. This threw me off a bit since they remapped the register aliasing. I also got thrown off a bit by the GNU version of the RISC-V assembler. I wrote a Python script (like I do for most of the other assemblers in naken_asm) that assembles all of the instructions with the GNU assembler and stores the hex file output in a file. The test will then assemble the same instruction with naken_asm and checks to make sure the hex output is the same. Jumps and branches on some CPUs do some weird stuff with GNU assmebler, and this one of those CPUs. I did notice that (as of this writing) I left out aliased and compressed instructions. I'll add those in soon.

The RISC-V chip itself is pretty interesting. It reminds me a lot of MIPS with some kind of odd changes. One difference noticable to the assembly language programmer is the "lui" and immediate instructions. On MIPS the "lui" instruction will load the upper 16 bits and the immediate instructions take 16 bits. In RISC-V, the "lui" instruction is 20 bit and the immediate instructions are 12. I'm not sure if there is some kind of programming advantage for the 20/12 bits, to me it seems like the 16/16 would be better. The other thing I found strange in RISC-V is the many of the instruction encodings are very... awkward. For example, when encoding instructions that have immediate values, on most CPUs it's as easy as just a simple [ mask, shift, or ] into the opcode. With RISC-V the immediate values are broken up by their bits and permutated all over the place. Almost reminds me of an encription algorithm. I'm not sure if this was done to make the CPU's circuitry simpler (seems to me like it would do the opposite) or to get around patents by trying to make it look different than MIPS? Either way, it makes writing an assembler for the RISC-V much more difficult than MIPS and much more error prone. A good example of this is the "jal" instruction, find it in the RISC-V instruction set manual.

The next step here is to program the HiFive1 board. I wrote a small program (source code linked to below) that simply cycles through the 3 LEDs on the board with a short delay between each. The hard part was uploading the code to the board. I git cloned the FreedomSDK linked to on the SiFive website and compiled it. It has some openocd program that uploads the program to the board, but I couldn't get it to work. Not even their sample programs with the simple "make" command they gave in the documentation. I kept getting this error:

error: the specified debug interface was not found (ftdi)

So I ended up downloading the FreedomStudio tarball (some IDE based on Eclipse I believe, also linked to from the SiFive website) and I was able to compile and upload the demo apps that came with it. In my Makefile, I pointed to the compiled versions of openocd and RISC-V gdb from FreedomStudio instead of the FreedomSDK and now the Makefile I included with the hifive_blink.asm program uploads to the board.

Source code


Copyright 1997-2024 - Michael Kohn