Setting Up a VHDL Development Environment on Ubuntu & Windows
Introduction
In this blog, I’m going to show how to set up a VHDL development environment on both Ubuntu and Windows.
I’m going to use only open-source software. Of course, for synthesis and uploading to actual hardware, you’ll need to use the corresponding proprietary tools.
The purpose of this blog is to help beginners, but also to serve as my own reference so that when I’m setting up a new environment, I don’t have to figure out the process all over again.
I’ll update this post with new or better tools and configurations as I find them. You can find the last update date at the bottom of this page.
This is the setup I personally use.
Tools
Here is the list of tools I’m using. I’ll show how to set them up on Ubuntu and Windows. For other distributions, refer to the corresponding tool’s documentation. However, my recommendation is that if you plan to work with software from Xilinx or Altera, you should install Ubuntu, as it’s officially supported and works much more smoothly compared to other distributions.
NVC – VHDL compiler & simulator
GTKWave – Waveform viewer
VUnit – Testing framework for VHDL
Visual Studio Code (VSCode)
Thiea IDE If you need VSCode alternative and open source
Before running pacman -S mingw-w64-ucrt-x86_64-gcc, as suggested in their documentation after installation, I recommend running this command multiple times (usually twice) until there are no more updates:
1
pacman -Syuu
Note
Don’t forget to use MSYS2 UCRT. The one with the golden icon, not the others.
You can paste the command by right-clicking and selecting Paste; it’s different from the usual paste method in a normal terminal.
Install GTKWave
In MSYS2, paste the following command to install GTKWave:
1
pacman -S mingw-w64-ucrt-x86_64-gtkwave
Now you need to specify its installation path. For me, it’s:
C:\msys64\ucrt64\bin
Add this to the PATH variable under System Variables in the Windows Environment Variables settings.
For VHDL by HGB, go to its settings and configure the following:
In Non Projects Files set it to ignore like image below:
In Generation set it to manual like image below:
You can also set the indentation to four spaces if you like:
Everything should hopefully be working now. Next, we’re going to create two files for our VHDL development: one called run.py for the VUnit script, and another called vhdl_ls.toml for the VHDL Language Server to locate the VHDL source files.
run.py
I have my VHDL project folder structure set up as follows:
src for sources
tb for testbenches
and the run.py and vhdl_ls.toml are in the main project folder.
project_folder/
src/
tb/
run.py
vhdl_ls.toml
In Ubuntu
Note
If you are not using the UVVM library remove these lines:
from vunit_helpers import add_uvvm_sourcesadd_uvvm_sources(VU, Path.home()/"Projects/UVVM")
I’ve assumed that your UVVM files exist in ~/Projects/UVVM. I’ve also included a template for GHDL to support VHDL 2008, remove either of these if you don’t need them.
First, we need to locate the VUnit installation using the command below in the Windows Terminal:
1
pip show vunit_hdl
For me, it’s located at:
C:\Users\my_username\AppData\Local\Programs\Python\Python313\Lib\site-packages
Replace this inside the run.py, and change the \ characters to /.
Note
If you are not using the UVVM library remove these lines:
from vunit_helpers import add_uvvm_sourcesadd_uvvm_sources(VU, Path.home()/"Projects/UVVM")
I’ve assumed that your UVVM files exist in ~/Projects/UVVM. I’ve also included a template for GHDL to support VHDL 2008, remove either of these if you don’t need them.
This is required for the VHDL by HGB extension to recognize your own and any external libraries. I’ve added the VUnit and UVVM libraries to it, but you’ll need to replace the paths for both with those from your system.
I’ve assumed that your UVVM files exist in ~/Projects/UVVM, and you can find the location of your VUnit installation by running the following command in your terminal:
1
pip show vunit_hdl
Note
You’ll need to add any other libraries or new ones you use. I’ll update these if necessary.
# File names are either absolute or relative to the parent folder of the# vhdl_ls.toml file and supports glob-style patterns.[libraries]lib_name.files=['src/**/*.vhd']lib_name_tb.files=['tb/**/*.vhdl']############################################## VUnit libraries###########################################vunit_lib.files=["vunit_path/vunit/vhdl/data_types/src/dict_pkg-2008p.vhd","vunit_path/vunit/vhdl/data_types/src/dict_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/id_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/event_private_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/event_common_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/event_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/queue_pool_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/integer_array_pkg-body.vhd","vunit_path/vunit/vhdl/data_types/src/codec_builder-2008p.vhd","vunit_path/vunit/vhdl/data_types/src/integer_array_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/queue_pkg-2008p.vhd","vunit_path/vunit/vhdl/data_types/src/string_ptr_pool_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/types.vhd","vunit_path/vunit/vhdl/data_types/src/string_ptr_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/codec.vhd","vunit_path/vunit/vhdl/data_types/src/queue_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/integer_vector_ptr_pool_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/data_types_private_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/string_ptr_pkg-body-2002p.vhd","vunit_path/vunit/vhdl/data_types/src/integer_vector_ptr_pkg-body-2002p.vhd","vunit_path/vunit/vhdl/data_types/src/data_types_context.vhd","vunit_path/vunit/vhdl/data_types/src/codec-2008p.vhd","vunit_path/vunit/vhdl/data_types/src/byte_vector_ptr_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/queue_pkg-body.vhd","vunit_path/vunit/vhdl/data_types/src/dict_pkg-body.vhd","vunit_path/vunit/vhdl/data_types/src/codec_builder.vhd","vunit_path/vunit/vhdl/data_types/src/integer_vector_ptr_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/api/external_string_pkg.vhd","vunit_path/vunit/vhdl/data_types/src/api/external_integer_vector_pkg.vhd","vunit_path/vunit/vhdl/logging/src/location_pkg-body-2008m.vhd","vunit_path/vunit/vhdl/logging/src/log_handler_pkg-body.vhd","vunit_path/vunit/vhdl/logging/src/log_handler_pkg.vhd","vunit_path/vunit/vhdl/logging/src/print_pkg-body.vhd","vunit_path/vunit/vhdl/logging/src/log_deprecated_pkg.vhd","vunit_path/vunit/vhdl/logging/src/log_levels_pkg.vhd","vunit_path/vunit/vhdl/logging/src/location_pkg.vhd","vunit_path/vunit/vhdl/logging/src/ansi_pkg.vhd","vunit_path/vunit/vhdl/logging/src/print_pkg.vhd","vunit_path/vunit/vhdl/logging/src/logger_pkg-body.vhd","vunit_path/vunit/vhdl/logging/src/log_levels_pkg-body.vhd","vunit_path/vunit/vhdl/logging/src/logger_pkg.vhd","vunit_path/vunit/vhdl/logging/src/file_pkg.vhd","vunit_path/vunit/vhdl/vunit_run_context.vhd","vunit_path/vunit/vhdl/vunit_context.vhd","vunit_path/vunit/vhdl/core/src/stop_pkg.vhd","vunit_path/vunit/vhdl/core/src/core_pkg.vhd","vunit_path/vunit/vhdl/core/src/stop_body_2008p.vhd","vunit_path/vunit/vhdl/string_ops/src/string_ops.vhd","vunit_path/vunit/vhdl/check/src/checker_pkg-body.vhd","vunit_path/vunit/vhdl/check/src/check.vhd","vunit_path/vunit/vhdl/check/src/checker_pkg.vhd","vunit_path/vunit/vhdl/check/src/check_deprecated_pkg.vhd","vunit_path/vunit/vhdl/check/src/check_api.vhd","vunit_path/vunit/vhdl/dictionary/src/dictionary.vhd","vunit_path/vunit/vhdl/run/src/runner_pkg.vhd","vunit_path/vunit/vhdl/run/src/run.vhd","vunit_path/vunit/vhdl/run/src/run_api.vhd","vunit_path/vunit/vhdl/run/src/run_types.vhd","vunit_path/vunit/vhdl/run/src/run_deprecated_pkg.vhd","vunit_path/vunit/vhdl/path/src/path.vhd",]vunit_lib.is_third_party=true############################################## UVVM libraries###########################################uvvm_util.files=['~/Projects/UVVM/uvvm_util/**/*.vhd']uvvm_util.is_third_party=trueuvvm_vvc_framework.files=['~/Projects/UVVM/uvvm_vvc_framework/src/*.vhd']uvvm_vvc_framework.is_third_party=truebitvis_vip_avalon_mm.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_avalon_mm/**/*.vhd',]bitvis_vip_avalon_mm.is_third_party=truebitvis_vip_avalon_st.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_avalon_st/**/*.vhd',]bitvis_vip_avalon_st.is_third_party=truebitvis_vip_axi.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_axi/**/*.vhd',]bitvis_vip_axi.is_third_party=truebitvis_vip_axilite.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_axilite/**/*.vhd',]bitvis_vip_axilite.is_third_party=truebitvis_vip_axistream.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_axistream/**/*.vhd',]bitvis_vip_axistream.is_third_party=truebitvis_vip_clock_generator.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_clock_generator/**/*.vhd',]bitvis_vip_clock_generator.is_third_party=truebitvis_vip_error_injection.files=['~/Projects/UVVM/bitvis_vip_error_injection/**/*.vhd',]bitvis_vip_error_injection.is_third_party=truebitvis_vip_ethernet.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_ethernet/**/*.vhd',]bitvis_vip_ethernet.is_third_party=truebitvis_vip_gmii.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_gmii/**/*.vhd',]bitvis_vip_gmii.is_third_party=truebitvis_vip_gpio.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_gpio/**/*.vhd',]bitvis_vip_gpio.is_third_party=truebitvis_vip_hvvc_to_vvc_bridge.files=['~/Projects/UVVM/bitvis_vip_hvvc_to_vvc_bridge/**/*.vhd',]bitvis_vip_hvvc_to_vvc_bridge.is_third_party=truebitvis_vip_i2c.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_i2c/**/*.vhd',]bitvis_vip_i2c.is_third_party=truebitvis_vip_rgmii.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_rgmii/**/*.vhd',]bitvis_vip_rgmii.is_third_party=truebitvis_vip_sbi.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_sbi/**/*.vhd',]bitvis_vip_sbi.is_third_party=truebitvis_vip_spec_cov.files=['~/Projects/UVVM/bitvis_vip_spec_cov/src/*.vhd']bitvis_vip_spec_cov.is_third_party=truebitvis_vip_scoreboard.files=['~/Projects/UVVM/bitvis_vip_scoreboard/**/*.vhd']bitvis_vip_scoreboard.is_third_party=truebitvis_vip_spi.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_spi/**/*.vhd',]bitvis_vip_spi.is_third_party=truebitvis_vip_uart.files=['~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd','~/Projects/UVVM/bitvis_vip_uart/**/*.vhd',]bitvis_vip_uart.is_third_party=truebitvis_uart.files=['~/Projects/UVVM/bitvis_uart/**/*.vhd']bitvis_uart.is_third_party=truebitvis_irqc.files=['~/Projects/UVVM/bitvis_irqc/**/*.vhd']bitvis_irqc.is_third_party=true