A blog post explaining this project can be found here: Open Source Ada from Gateware to Application
-
Install Docker (if not already installed):
sudo apt update sudo apt install -y docker.io sudo systemctl enable --now docker
-
Create a working directory:
cd ~ && mkdir neorv32_workspace && cd neorv32_workspace
-
Pull the
neorv32/impl
container (includes all the required open-source tools):sudo docker pull ghcr.io/stnolting/neorv32/impl:latest
-
Run the container, mapping your current folder to
/workspace
:sudo docker run --rm -it -v "$(pwd)":/workspace ghcr.io/stnolting/neorv32/impl bash cd /workspace
-
Clone
neorv32-setups
(with submodules):git clone --recurse-submodules https://github.com/stnolting/neorv32-setups.git
-
(IMPORTANT): Modify the top-level VHDL file to adjust memory sizes for our BIOS firmware
apt-get update && apt-get install nano nano neorv32-setups/osflow/board_tops/neorv32_ULX3S_BoardTop_MinimalBoot.vhd
Change the IMEM and DMEM lines to:
MEM_INT_IMEM_SIZE => 32*1024, MEM_INT_DMEM_SIZE => 16*1024
-
Build the default SoC with minimal boot:
cd neorv32-setups/osflow make BOARD=ULX3S MinimalBoot
-
Quit the container:
exit
- Install dependencies:
sudo apt install libftdi1-dev libusb-dev cmake make build-essential
- Clone fujprog:
cd ~/neorv32_workspace git clone https://github.com/kost/fujprog cd fujprog
- Build and install fujprog:
mkdir build && cd build cmake .. make sudo make install
- Program your board (adjust the path to your bitstream if needed):
fujprog ../../neorv32-setups/osflow/neorv32_ULX3S_MinimalBoot.bit
Now the neorv32 SoC is on your ULX3S dev board. Next, build and prepare the BIOS demo to familiarize yourself with the workflow.
-
Compile
image_gen
(bundled with neorv32):cd ~/neorv32_workspace/neorv32-setups/neorv32/sw/image_gen gcc image_gen.c -o image_gen sudo cp image_gen /usr/local/bin/
Note: If you encounter a permission error while compiling, ensure you’re in a directory where you have write access or use
sudo
appropriately. -
Ensure
riscv64-elf-objcopy
is in your$PATH
:
This tool is provided when Alire installs the RISC-V cross-compiler. Check its location with:which riscv64-elf-objcopy
If nothing is returned, complete the Build the Ada Demos Firmware (BIOS) section first—Alire will install the entire RISC-V toolchain. Then add the toolchain’s directory (e.g.,
~/.local/share/alire/toolchains/gnat_riscv64_elf_[version]/bin
) to your PATH:export PATH="$PATH:~/.local/share/alire/toolchains/gnat_riscv64_elf_[version]/bin"
To make this change permanent, add that line to your
~/.bashrc
(or equivalent) and reload:source ~/.bashrc
- Move back to the root of your workspace:
cd ~/neorv32_workspace
- Clone the repository from GitHub:
(Alternatively, once it’s on Alire:)
git clone https://github.com/GNAT-Academic-Program/neorv32_hal
alr get neorv32_hal
- Build using Alire:
cd neorv32_hal/demos alr build
- Convert and package the firmware:
riscv64-elf-objcopy -O binary bin/bios bin/bios.bin image_gen -app_bin bin/bios.bin bin/bios.exe
- Install a serial terminal for raw file transfers (e.g., gtkterm):
sudo apt install gtkterm
- Open gtkterm:
gtkterm --port /dev/ttyUSB0 --speed 19200
- Configure gtkterm:
- In the Configuration menu, set
CR LF auto
.
- In the Configuration menu, set
- Upload the firmware:
- At the
CMD:>
prompt in gtkterm, typeu
, then press Ctrl+Shift+R. - Select
bios.exe
and wait for the upload to complete. - At
CMD:>
, typee
.
- At the
And voila!
- Add
neorv32_hal
as a dependency in youralire.toml
:[[depends-on]] neorv32_hal = "*"
- Modify your
your_project.gpr
:with "bare_runtime.gpr"; with "neorv32_hal.gpr"; project Your_Project is for Target use "riscv64-elf"; for Runtime ("Ada") use Bare_Runtime'Runtime ("Ada"); package Linker is for Switches ("Ada") use ("-T", neorv32_Hal'Project_Dir & "/src/link.ld"); end Linker; end Your_Project;
That’s it! You now have everything you need to generate the bitstream, program your FPGA, and start developing neorv32-based Ada projects. Happy hacking! 🚀