47 KiB
RISCV(picorv32) baremetal on FPGA on Windows and Linux
Cross-Compiling for RISCV on Linux or WSL for the DE0-NANO FPGA
1. installation
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.
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.
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.
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
<span style="color:red">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</span>
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 one of the servers was down, or you could not build it.