# RISCV(picorv32) baremetal on FPGA on Windows and Linux ## Cross-Compiling for RISCV on Linux or WSL for the DE0-NANO FPGA ### 1. installation ```html sudo apt-get update 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 git clone https://github.com/riscv/riscv-gnu-toolchain cd riscv-gnu-toolchain/ mkdir build/ cd build sudo mkdir /opt/riscv32im sudo chown $USER /opt/riscv32im ./configure --with-arch=rv32im --prefix=/opt/riscv32im make -j$(nproc) ``` #### For other architectures or variations of RISC-V | Command | ISA | |:---------------------------------------- |:-------- | |`./configure --with-arch=rv32i --prefix=/opt/riscv32i/ `| `RV32I `| |`./configure --with-arch=rv32ic --prefix=/opt/riscv32ic/ `| `RV32IC `| |`./configure --with-arch=rv32im --prefix=/opt/riscv32im/` | `RV32IM `| |`./configure --with-arch=rv32imc --prefix=/opt/riscv32imc/`| `RV32IMC `| ### 2. Corss-Compiling C code for the RISCV picorv32 on WSL or on Linux. ```html git clone https://gitea.squirrelnut.synology.me:5001/FPGALover/RISCV_picorv32_fpga cd RISCV_picorv32_fpga/sw make clean make firmware/firmware.fpga cp firmware/Memory.v_toplevel_memory_1_symbol* ../rtl/DE0-NANO ``` *Now you can compile or synthesize the FPGA harware using Quartus or any other Design tool* ### 3. Syhtesize the project on Quartus. Open Quartus, and run the synthesis of the system, the project you can find it under "\RISCV_picorv32_fpga\rtl\DE0-NANO", and the memories generated in binaries: ``` $ ls -l ./rtl/DE0-NANO/ | grep "Memory" Memory.v_toplevel_memory_1_symbol0.bin Memory.v_toplevel_memory_1_symbol1.bin Memory.v_toplevel_memory_1_symbol2.bin Memory.v_toplevel_memory_1_symbol3.bin ``` So everytime you want to change your RISCV C code(sw\firmware\main.c), you would need to generate Memories to load them to the embedded memories, or find a way to change their content during runtime. you can find that that these binaries are used by the file memory.v(xoro_top->Memory) which, on lines 32 to 35 of the Verilog description ``` initial begin $readmemb("Memory.v_toplevel_memory_1_symbol0.bin",memory_1_symbol0); $readmemb("Memory.v_toplevel_memory_1_symbol1.bin",memory_1_symbol1); $readmemb("Memory.v_toplevel_memory_1_symbol2.bin",memory_1_symbol2); $readmemb("Memory.v_toplevel_memory_1_symbol3.bin",memory_1_symbol3); end ``` ## Cross-Compiling for RISCV on Windows ### 1. Installation You must download the latest RISCV precompiled binaries for your platform from: https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/ in this case the architecture x64 for windows binaries(https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-darwin-x64.tar.gz), then extract these under the folder C:\riscv_precompiled\ Note: If you change the location where you installed the RISC-V precompiled binaries, you need to modify line 3 of the file \sw\Makefile. This will be explained further in this manual Your precompiled binaries should look like this on your file system:
### 2. Clone this repository Open a CMD Clone this repository, or just simply download it somewhere on your hardrive. ```html git clone https://gitea.squirrelnut.synology.me:5001/FPGALover/RISCV_picorv32_fpga ``` ### 3. Install Python Before you can cross compile, you need to have Python installed on your windows machine, make sure you install Python2.7 or Python3, in case you install python3, you would need to modify the variable "PYTHON_VER" at the line # 8 of the file \sw\Makefile. Also make sure that your python is register under the *Path* enviroment variables open a CMD and check that you can summon python when you type "python" or "python3", just make sure it correspond to the Makefile name ``` > python Python 3.11.7 (main, Dec 7 2023, 09:09:57) [GCC UCRT 13.2.0 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> exit() ``` ### 4. Cross compile Go to the directory RISCV_picorv32_fpga/sw using a CMD. ```html cd RISCV_picorv32_fpga/sw ``` then write the command "make clean" to clean all the binaries downloaded with this repository, you should see: ``` > make clean rm -vrf firmware/start.o firmware/irq.o firmware/print.o firmware/inch.o firmware/timer.o firmware/prng.o firmware/leds.o firmware/fftbench.o firmware/main.o \ firmware/firmware.elf firmware/firmware.bin firmware/firmware.hex firmware/firmware.mif firmware/firmware.map firmware/Memory.v_toplevel_memory_1_symbol* removed `firmware/start.o' removed `firmware/irq.o' removed `firmware/print.o' removed `firmware/inch.o' removed `firmware/timer.o' removed `firmware/prng.o' removed `firmware/leds.o' removed `firmware/fftbench.o' removed `firmware/main.o' removed `firmware/firmware.elf' removed `firmware/firmware.bin' removed `firmware/firmware.hex' removed `firmware/firmware.mif' removed `firmware/firmware.map' removed `firmware/Memory.v_toplevel_memory_1_symbol0.bin' removed `firmware/Memory.v_toplevel_memory_1_symbol1.bin' removed `firmware/Memory.v_toplevel_memory_1_symbol2.bin' removed `firmware/Memory.v_toplevel_memory_1_symbol3.bin' ``` after cleaning, you can simple write the command "make firmware/firmware.fpga" and you will see: ``` > make firmware/firmware.fpga C:\riscv_precompiled/bin/riscv-none-elf-gcc -c -march=rv32im -o firmware/start.o firmware/start.S C:\riscv_precompiled/bin/riscv-none-elf-gcc -c -march=rv32im -Os -W --std=c99 -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic -ffreestanding -nostdlib -o firmware/irq.o firmware/irq.c C:\riscv_precompiled/bin/riscv-none-elf-gcc -c -march=rv32im -Os -W --std=c99 -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic -ffreestanding -nostdlib -o firmware/print.o firmware/print.c C:\riscv_precompiled/bin/riscv-none-elf-gcc -c -march=rv32im -Os -W --std=c99 -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic -ffreestanding -nostdlib -o firmware/inch.o firmware/inch.c C:\riscv_precompiled/bin/riscv-none-elf-gcc -c -march=rv32im -Os -W --std=c99 -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic -ffreestanding -nostdlib -o firmware/timer.o firmware/timer.c C:\riscv_precompiled/bin/riscv-none-elf-gcc -c -march=rv32im -Os -W --std=c99 -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic -ffreestanding -nostdlib -o firmware/prng.o firmware/prng.c C:\riscv_precompiled/bin/riscv-none-elf-gcc -c -march=rv32im -Os -W --std=c99 -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic -ffreestanding -nostdlib -o firmware/leds.o firmware/leds.c C:\riscv_precompiled/bin/riscv-none-elf-gcc -c -march=rv32im -Os -W --std=c99 -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic -ffreestanding -nostdlib -o firmware/fftbench.o firmware/fftbench.c firmware/fftbench.c: In function 'fft_bench': firmware/fftbench.c:109:9: warning: variable 'slices' set but not used [-Wunused-but-set-variable] 109 | int slices; | ^~~~~~ firmware/fftbench.c:108:9: warning: unused variable 'slice' [-Wunused-variable] 108 | int slice; | ^~~~~ firmware/fftbench.c:107:9: warning: variable 'lastLevel' set but not used [-Wunused-but-set-variable] 107 | int lastLevel; | ^~~~~~~~~ firmware/fftbench.c:106:9: warning: variable 'firstLevel' set but not used [-Wunused-but-set-variable] 106 | int firstLevel; | ^~~~~~~~~~ firmware/fftbench.c:105:12: warning: unused variable 'slen' [-Wunused-variable] 105 | int s, slen; | ^~~~ firmware/fftbench.c:105:9: warning: unused variable 's' [-Wunused-variable] 105 | int s, slen; | ^ firmware/fftbench.c: In function 'butterflies': firmware/fftbench.c:266:27: warning: declaration of 'bx' shadows a global declaration [-Wshadow] 266 | void butterflies(int32_t* bx, int32_t* by, int32_t firstLevel, int32_t lastLevel, int32_t slices, int32_t slen) { | ^ firmware/fftbench.c:65:16: note: shadowed declaration is here 65 | static int32_t bx[FFT_SIZE]; | ^~ firmware/fftbench.c:266:40: warning: declaration of 'by' shadows a global declaration [-Wshadow] 266 | void butterflies(int32_t* bx, int32_t* by, int32_t firstLevel, int32_t lastLevel, int32_t slices, int32_t slen) { | ^ firmware/fftbench.c:66:16: note: shadowed declaration is here 66 | static int32_t by[FFT_SIZE]; | ^~ C:\riscv_precompiled/bin/riscv-none-elf-gcc -c -march=rv32im -Os -W --std=c99 -Wall -Wextra -Wshadow -Wundef -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wredundant-decls -Wstrict-prototypes -Wmissing-prototypes -pedantic -ffreestanding -nostdlib -o firmware/main.o firmware/main.c C:\riscv_precompiled/bin/riscv-none-elf-gcc -Os -ffreestanding -nostdlib -o firmware/firmware.elf \ -Wl,-Bstatic,-T,firmware/sections.lds,-Map,firmware/firmware.map,--strip-debug \ firmware/start.o firmware/irq.o firmware/print.o firmware/inch.o firmware/timer.o firmware/prng.o firmware/leds.o firmware/fftbench.o firmware/main.o -lgcc c:/riscv_precompiled/bin/../lib/gcc/riscv-none-elf/12.3.0/../../../../riscv-none-elf/bin/ld: warning: firmware/firmware.elf has a LOAD segment with RWX permissions chmod -x firmware/firmware.elf C:\riscv_precompiled/bin/riscv-none-elf-objcopy -O binary firmware/firmware.elf firmware/firmware.bin chmod -x firmware/firmware.bin python firmware/makehex.py firmware/firmware.bin 16384 firmware > firmware/firmware.hex python firmware/makebin.py firmware/firmware.hex 16384 > firmware/firmware.fpga ``` Note: if you changed the location of the precompiled RISCV binaries, you need to modify the variable "RISCV_GNU_TOOLCHAIN_INSTALL_PREFIX" of file "\sw\Makefile" at the line # 3 if you built the files successfuly, you would able to see under the folder "sw\firmware" the memories binaries: ``` >ls firmware custom_ops.S leds.o fftbench.c main.c fftbench.o main.o firmware.bin makebin.py firmware.elf makehex.py firmware.fpga makemif.py firmware.h Memory.v_toplevel_memory_1_symbol0.bin firmware.hex Memory.v_toplevel_memory_1_symbol1.bin firmware.map Memory.v_toplevel_memory_1_symbol2.bin firmware.mif Memory.v_toplevel_memory_1_symbol3.bin firmware0.hex print.c firmware1.hex print.o firmware2.hex prng.c firmware3.hex prng.o inch.c sections.lds inch.o start.o irq.c start.S irq.o timer.c leds.c timer.o ``` ### 4.Syhtesize the project on Quartus. Open Quartus, and run the synthesis of the system, the project you can find it under "RISCV_picorv32_fpga\rtl\DE0-NANO", and the memories generated in binaries: ``` Memory.v_toplevel_memory_1_symbol0.bin Memory.v_toplevel_memory_1_symbol1.bin Memory.v_toplevel_memory_1_symbol2.bin Memory.v_toplevel_memory_1_symbol3.bin ``` So everytime you want to change your RISCV C code(sw\firmware\main.c), you would need to generate Memories to load them to the embedded memories, or find a way to change their content during runtime. you can find that that these binaries are used by the file memory.v(xoro_top->Memory) which, on lines 32 to 35 of the Verilog description ``` initial begin $readmemb("Memory.v_toplevel_memory_1_symbol0.bin",memory_1_symbol0); $readmemb("Memory.v_toplevel_memory_1_symbol1.bin",memory_1_symbol1); $readmemb("Memory.v_toplevel_memory_1_symbol2.bin",memory_1_symbol2); $readmemb("Memory.v_toplevel_memory_1_symbol3.bin",memory_1_symbol3); end ``` ## Other Linux and Windows precompiled Toolchains just in case - https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/ for mingw64 - https://gnutoolchains.com/risc-v/ under this repo you can also find some prebuilt binaries for Linux and Windows, in case any of the servers was down, or you could not build it.