Contents

VHDL Environment Setup

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.

  1. NVC – VHDL compiler & simulator
  2. GTKWave – Waveform viewer
  3. VUnit – Testing framework for VHDL
  4. Visual Studio Code (VSCode)
  5. Thiea IDE If you need VSCode alternative and open source

Setup on Linux

Install NVC

Go to the repository’s release page, then download and install the .deb file. https://github.com/nickg/nvc/releases

1
sudo apt install ./nvc_version.deb

Install GTKWave

1
sudo apt install gtkwave

Install VUnit

Go to the installation page: https://vunit.github.io/installing.html

You will need to install it using pip like this:

1
 pip install vunit_hdl

Also, install the VUnit helpers:

1
pip install vunit_helpers

Now, in order to tell VUnit to use NVC for compilation, you have to set an environment variable, as explained on this page: https://vunit.github.io/cli.html#environment-variables

First, find where NVC is installed on your system using the command below:

1
 which nvc

For me, it’s installed under /usr/bin/nvc, so I added this line to my .zshrc so that VUnit can find it and use it for compilation and simulation.

export VUNIT_NVC_PATH="/usr/bin/"

Setup on Windows

Install NVC

Go to the repository’s release page, then download and install the .msi file. https://github.com/nickg/nvc/releases

Check if it’s installed on Windows by running the following command in the Windows Terminal:

1
nvc --version

Install Python

Go to the Python website and install Python: https://www.python.org/downloads/

Choose Add python.exe to PATH, then click Next and wait for the installation to finish. When prompted, disable the path length limit.

Now you have Python installed along with pip.

Install VUnit

Go to the installation page: https://vunit.github.io/installing.html

You need to install it using pip in the Windows Terminal like this:

1
 pip install vunit_hdl

Also, install the VUnit helpers using:

1
pip install vunit_helpers

Now, in order to tell VUnit to use NVC for compilation, you need to set an environment variable, as explained on this page: https://vunit.github.io/cli.html#environment-variables

First, find where NVC is installed on your Windows system from the previous step.

For me, the default installation path was:

C:\Program Files\NVC\bin

Now, edit your system environment variables in Windows.

Go to Environment Variables from there, then under System variables, click New and add the following:

Variable name: VUNIT_NVC_PATH

Variable value: C:\Program Files\NVC\bin

Install MSYS2

For many tasks, you’re going to use MSYS2. If you don’t already have it, install it. https://www.msys2.org/#installation

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.

VScode/Thiea VHDL config and extension install

The extensions I recommend for VHDL development are VHDL by HGB and VHDL by VHDLwhiz.

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_sources add_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.

The following line:

VU.set_compile_option("nvc.a_flags",["--relaxed"])

is used for UVVM to suppress certain errors.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from pathlib import Path
from vunit import VUnit
from vunit_helpers import add_uvvm_sources

VU = VUnit.from_argv(compile_builtins=False)
VU.add_vhdl_builtins()
add_uvvm_sources(VU, Path.home()/"Projects/UVVM")


SRC_PATH = Path(__file__).parent / "src"
TESTBENCH_PATH = Path(__file__).parent / "tb"

VU.add_library("lib_name").add_source_files(SRC_PATH / "**" / "*.vhd")
VU.add_library("lib_name_tb").add_source_files(TESTBENCH_PATH / "**" / "*.vhdl")

VU.set_compile_option("nvc.a_flags",["--relaxed"])

VU.set_compile_option("ghdl.a_flags", ["--std=08"])
VU.set_sim_option("ghdl.elab_flags", ["--std=08"])

VU.main()

In Windows

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_sources add_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.

The following line:

VU.set_compile_option("nvc.a_flags",["--relaxed"])

is used for UVVM to suppress certain errors.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import sys
sys.path.append("C:/Users/my_username/AppData/Local/Programs/Python/Python313/Lib/site-packages")
from pathlib import Path
from vunit import VUnit
from vunit_helpers import add_uvvm_sources

VU = VUnit.from_argv(compile_builtins=False)
VU.add_vhdl_builtins()
add_uvvm_sources(VU, Path.home()/"Projects/UVVM")


SRC_PATH = Path(__file__).parent / "src"
TESTBENCH_PATH = Path(__file__).parent / "tb"

VU.add_library("lib_name").add_source_files(SRC_PATH / "**" / "*.vhd")
VU.add_library("lib_name_tb").add_source_files(TESTBENCH_PATH / "**" / "*.vhdl")

VU.set_compile_option("nvc.a_flags",["--relaxed"])

VU.set_compile_option("ghdl.a_flags", ["--std=08"])
VU.set_sim_option("ghdl.elab_flags", ["--std=08"])

VU.main()

vhdl_ls.toml

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.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# 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 = true

uvvm_vvc_framework.files = ['~/Projects/UVVM/uvvm_vvc_framework/src/*.vhd']
uvvm_vvc_framework.is_third_party = true

bitvis_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 = true

bitvis_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 = true

bitvis_vip_axi.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_axi/**/*.vhd',
]
bitvis_vip_axi.is_third_party = true

bitvis_vip_axilite.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_axilite/**/*.vhd',
]
bitvis_vip_axilite.is_third_party = true

bitvis_vip_axistream.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_axistream/**/*.vhd',
]
bitvis_vip_axistream.is_third_party = true

bitvis_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 = true

bitvis_vip_error_injection.files = [
    '~/Projects/UVVM/bitvis_vip_error_injection/**/*.vhd',
]
bitvis_vip_error_injection.is_third_party = true

bitvis_vip_ethernet.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_ethernet/**/*.vhd',
]
bitvis_vip_ethernet.is_third_party = true

bitvis_vip_gmii.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_gmii/**/*.vhd',
]
bitvis_vip_gmii.is_third_party = true

bitvis_vip_gpio.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_gpio/**/*.vhd',
]
bitvis_vip_gpio.is_third_party = true

bitvis_vip_hvvc_to_vvc_bridge.files = [
    '~/Projects/UVVM/bitvis_vip_hvvc_to_vvc_bridge/**/*.vhd',
]
bitvis_vip_hvvc_to_vvc_bridge.is_third_party = true

bitvis_vip_i2c.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_i2c/**/*.vhd',
]
bitvis_vip_i2c.is_third_party = true

bitvis_vip_rgmii.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_rgmii/**/*.vhd',
]
bitvis_vip_rgmii.is_third_party = true

bitvis_vip_sbi.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_sbi/**/*.vhd',
]
bitvis_vip_sbi.is_third_party = true

bitvis_vip_spec_cov.files = ['~/Projects/UVVM/bitvis_vip_spec_cov/src/*.vhd']
bitvis_vip_spec_cov.is_third_party = true

bitvis_vip_scoreboard.files = ['~/Projects/UVVM/bitvis_vip_scoreboard/**/*.vhd']
bitvis_vip_scoreboard.is_third_party = true

bitvis_vip_spi.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_spi/**/*.vhd',
]
bitvis_vip_spi.is_third_party = true

bitvis_vip_uart.files = [
    '~/Projects/UVVM/uvvm_vvc_framework/src_target_dependent/*.vhd',
    '~/Projects/UVVM/bitvis_vip_uart/**/*.vhd',
]
bitvis_vip_uart.is_third_party = true

bitvis_uart.files = ['~/Projects/UVVM/bitvis_uart/**/*.vhd']
bitvis_uart.is_third_party = true

bitvis_irqc.files = ['~/Projects/UVVM/bitvis_irqc/**/*.vhd']
bitvis_irqc.is_third_party = true