RISCV_picorv32_fpga/README.md

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.