RISCV example project on TinyFPGA BX


Hello everyone! I’ve put together a bare-bones RISCV SOC based on Clifford Wolf’s excellent picorv32/picosoc. It will get you up and running with a 32-bit CPU executing instructions directly from SPI flash.

The code can be found in the new examples directory of the TinyFPGA BX repository: https://github.com/tinyfpga/TinyFPGA-BX/tree/master/examples/picosoc

You’ll need to install the icestorm toolchain if you want to build this project. The icestorm_template goes through this process: https://github.com/tinyfpga/TinyFPGA-BX/blob/master/icestorm_template/README.md

You’ll also need the RISCV GCC toolchain installed to build the firmware: https://github.com/cliffordwolf/picorv32/blob/master/README.md#building-a-pure-rv32i-toolchain

Once you have both icestorm and RISCV gcc installed, you’ll be able to build and upload the SOC onto your TinyFPGA BX board with the following command:

make upload

The example itself is pretty simple. It gets you to a blinking LED using C code running on the PicoRV32 core. It is an excellent starting point for any project for which you would like to include a CPU core running C code along side your own custom hardware.

There are a few things I am looking for help with on this example:

  1. I’m not too sure the GCC linker script is correct. The instructions are executed directly from SPI flash, but statically initialized variables may not be getting initialized properly. I don’t have much experience with GCC linker scripts so any help is appreciated.
  2. It doesn’t currently support C++, but this is a limitation of the initialization code and linker script.
  3. There are two user peripherals built in: the hardware UART, and GPIO output. It would be nice to have the USB bootloader present as a serial peripheral as well and I may add it later.
  4. The Makefile could use some TLC to make it easier to add additional source files.

Have fun!


It works for me!

By the way, I had to make this patch to the latest Git version of tinyprog to make it work, because flash_id is a bytearray so its elements were already ints:

diff --git a/programmer/tinyprog/__init__.py b/programmer/tinyprog/__init__.py
index 4f49017..a725987 100644
--- a/programmer/tinyprog/__init__.py
+++ b/programmer/tinyprog/__init__.py
@@ -201,7 +201,7 @@ class TinyProg(object):
         flash_id = self.read_id()
-        flash_id = [ord(b) for b in flash_id]
         # temporary hack, should have better database as well as SFPD reading
         if flash_id[0:2] == [0x9D, 0x60]:
             # ISSI


Great! I fixed this issue in tinyprog version 1.0.17. I’ll have it up in github too.


Also, on Mac it complains about how objcopy uses /dev/stdout. This seems equivalent and doesn’t generate warnings for me.

diff --git a/examples/picosoc/Makefile b/examples/picosoc/Makefile
index d174349..1f713ad 100644
--- a/examples/picosoc/Makefile
+++ b/examples/picosoc/Makefile
@@ -18,7 +18,7 @@ firmware.elf: sections.lds start.S firmware.c
        riscv32-unknown-elf-gcc -march=rv32imc -nostartfiles -Wl,-Bstatic,-T,sections.lds,--strip-debug,-Map=firmware.map,--cref  -ffreestanding -nostdlib -o firmware.elf start.S firmware.c
 firmware.bin: firmware.elf
-       riscv32-unknown-elf-objcopy -O binary firmware.elf /dev/stdout > firmware.bin
+       riscv32-unknown-elf-objcopy -O binary firmware.elf firmware.bin


This is a great example, thanks!

I am using multilib riscv64 gcc 8.2.0 and was able to get the firmware to build and run with the following quick change:

diff --git a/examples/picosoc/Makefile b/examples/picosoc/Makefile
index d174349..5675ec8 100644
--- a/examples/picosoc/Makefile
+++ b/examples/picosoc/Makefile
@@ -15,10 +15,10 @@ hardware.bin: hardware.asc
 firmware.elf: sections.lds start.S firmware.c 
-       riscv32-unknown-elf-gcc -march=rv32imc -nostartfiles -Wl,-Bstatic,-T,sections.lds,--strip-debug,-Map=firmware.map,--cref  -ffreestanding -nostdlib -o firmware.elf start.S firmware.c
+       riscv64-unknown-elf-gcc -march=rv32imc -mabi=ilp32 -nostartfiles -Wl,-Bstatic,-T,sections.lds,--strip-debug,-Map=firmware.map,--cref  -ffreestanding -nostdlib -o firmware.elf start.S firmware.c
 firmware.bin: firmware.elf
-       riscv32-unknown-elf-objcopy -O binary firmware.elf /dev/stdout > firmware.bin
+       riscv64-unknown-elf-objcopy -O binary firmware.elf /dev/stdout > firmware.bin