Introduction
This page is meant as a (hopefully) short tutorial to using hdlmake for both synthesis and simulation. For a first-time user, it is recommended to go through the whole tutorial step by step. This will show you (based on a reference project):
- how to create manifest files to ensure design modularity
- how to create simulation manifests
- create manifests for local synthesis
- how to use IP cores uploaded on a version control system (in our example we use both Git and SVN).
Once you've done this, you can migrate to your own project(s), using this page and the rest of the documentation as a reference. You may skip directly to the Simulation or Synthesis sections, for quick reference on each topic. The summary at the end provides the steps you need to take.
For the moment, this tutorial is written for Linux systems, and for Xilinx FPGAs using Xilinx ISE. While hdlmake does support Altera tools, a tutorial on this is deferred for later.
Before we begin, a few words on the test system. This can be summarized as follows:
- PC running Ubuntu 12.04 Precise Pangolin;
- Linux kernel: 3.2.0-31-generic-pae;
- Xilinx ISE v14.2;
- Modelsim v10.1d;
- hdlmake built from the latest (as of 2012-04-10) master repository;
- SPEC carrier card with an fmc-adc-100m-14b-4cha board;
- Test scripts from the PTS (Production Test Suite), run under Python 2.7.1+.
Installing hdlmake
There is no need to build hdlmake. It is entirely written in Python and the code gets interpreted on the fly. To get the code you have two choices: you might clone the repository, which contains the most recent changes (more features, more bugs too...) or download a frozen version in a form of a "binary" file.
Downloading the compiled executable
For downloading the compiled executable, click here and choose one of the files without extension. Download to a location of choice, and you're almost ready to use it! You can jump directly to the final steps.
Cloning the repository
If you prefer to get the source code, you need to have the popular Git
version control system installed on your machine; if you don't, this
page
offers details on how you can configure Git to clone our repositories.
Assuming you have Git installed, running the following will clone
(download all files in the) repository to a folder named hdlmake
under
your /home/user_name/
folder:
$ git clone git:https://www.ohwr.org/misc/hdl-make.git hdlmake
Now you're almost ready to go. You can run hdlmake by changing directory to a desired location and running
$ python path/to/hdlmake/hdlmake
The sample project
For this tutorial, we have a sample project called play. This is a design which lights some LEDs on the SPEC board's front panel and can be used to play with controlling registers from a PC using the SPEC driver and (optionally) PTS (Production Test Suite). You can see a simplified block diagram of the design below:
It contains a number of design blocks, each defined in a separate VHDL file with the name of the block. The folder hierarchy for the project is as presented below:
- play/
- doc/
- hdl/
- design/
- tb/
- sim/
- sw/
- syn/
The relevant folders in our case are:
- hdl/, where all source files are held; the tb/ folder contains testbenches for the design, and the design/ folder contains the rest of the files relevant to the design;
- sim/ is the folder where files relevant to the simulation part of the design, such as Makefiles for simulation, simulation scripts, etc., are stored;
- syn/ is the folder where files relevant to design synthesis are stored. The folder is also where the ISE project file is created.
And that is about as much detail about the sample project as is relevant
for the purpose of this tutorial. More details about the sample project
can be found in the project description .pdf, under play/doc/
.
In order to download the design files for the tutorial, clone the project repository by running the following command in your terminal:
$ git clone --depth=1 -b play git:https://www.ohwr.org/fmc-projects/fmc-adc-100m14b4cha.git
The command creates a new folder in your current folder and downloads
all files from the play
branch of the fmc-adc-100m14b4cha OHWR
repository to this new folder. The output of this command should be
something like:
Cloning into 'fmc-adc-100m14b4cha'...
remote: Counting objects: 2518, done.
remote: Compressing objects: 100% (1277/1277), done.
remote: Total 2518 (delta 1518), reused 2010 (delta 1189)
Receiving objects: 100% (2518/2518), 150.71 MiB | 9.51 MiB/s, done.
Resolving deltas: 100% (1518/1518), done.
You should now have the project files, nicely stored following the
folder structure we just described, under a new folder called play
.
If you don't, you probably don't have git installed correctly. Check here for more information.
Now let's go on and generate a makefile for simulation!
Simulation
This part of the tutorial shows you how to run hdlmake for simulation. Note that hdlmake does not handle creation of simulation scripts, nor does it run the simulation tool for you; it simply creates all settings necessary to run simulation. Therefore, you will need to write your own simulation scripts and run Modelsim to run simulation. hdlmake will try to detect which version of modelsim you're running. Make sure that your modelsim executable is in the PATH before running hdlmake.
In our case, let's say we want to see how the design behaves with only
the led_ctrl
, addr_dec
and irq_controller
blocks in the design.
Remember that the HDL files for these components are located under
(assuming you are in the play/
folder) hdl/design/
. We need to
create a few very simple Python scripts which tell the tool where to
look for files and what action it should perform. Let's see how this is
done.
Design file manifests
First, create a file called Manifest.py
, containing the following
lines of Python code:
files = [
"led_ctrl.vhd",
"irq_controller_regs.vhd", # a sub-module of irq_controller
"irq_controller.vhd",
"addr_dec.vhd",
]
When hdlmake reads this manifest, it will know that the design files
to look for under the current folder are the ones stated in the files
variable.
Next, create another Manifest.py
, this time under hdl/tb/
, with the
following contents:
files = [ "testbench.vhd" ]
modules = {
"local" : [ "../design/" ]
}
As before, the files
variable tells hldmake that within this
folder, it should look for the file testbench.vhd
and that it should
for further modules (design files) under ../design/
(which as you
might tell, is play/hdl/design/
)
Now, cd
to the play/sim/
folder and create yet another Manifest.py
here, with the following contents:
target = "xilinx"
action = "simulation"
sim_tool = "modelsim"
modules = { "local" : [ "../hdl/tb" ] }
Again, we see the modules
variable, which tells it to look for modules
under ../hdl/tb/
. Additionally, the manifest tells the tool that the
action to be performed is simulation, the target is xilinx and the
simulation tool is modelsim.
Okay, now you should be able to run the tool and generate a makefile for simulation.
Running hdlmake
From the play/sim/
folder, run (normal outputs shown under each
command):
$ hdlmake
INFO: Running automatic flow
INFO: Generating makefile for simulation.
$ make
cp /opt/modelsim_10.0d/modeltech/modelsim.ini .
(vlib work && vmap -modelsimini modelsim.ini work && touch work/.work )|| rm -rf work
Reading modelsim.ini
"work" maps to directory ./work. (Default mapping)
vcom -quiet -modelsimini modelsim.ini -work work ../hdl/tb/testbench.vhd
vcom -quiet -modelsimini modelsim.ini -work work ../hdl/design/led_ctrl.vhd
vcom -quiet -modelsimini modelsim.ini -work work ../hdl/design/irq_controller_regs.vhd
vcom -quiet -modelsimini modelsim.ini -work work ../hdl/design/irq_controller.vhd
vcom -quiet -modelsimini modelsim.ini -work work ../hdl/design/addr_dec.vhd
Let's see what happened on the previous command. When you run hdlmake
with no arguments, the tool parses the manifest under the current
folder. Since the manifest told it to look for modules in ../hdl/tb/
,
the tool goes and parses the manifest there. Here, it is told to add the
file testbench.vhd
and to look for additional modules under
../design/
. Finally, by parsing the play/hdl/design/Manifest.py
file, hdlmake can add the final files needed for simulation. In a nice
visual manner, here's how it
works:
Assuming you've followed the steps up to here and you've written your
simulation script, you should be able to run Modelsim now to simulate
this simple design. From play/sim
, run:
vsim
and in the Modelsim command line (using the provided scripts):
do run.do
should bring up a window similar to this:
If it does, and all of the signals have definite values (i.e., no 'X'-s, or 'U'-s), then congratulations, you have just performed a working simulation flow!
Synthesis
Okay, so now that you've simulated your design and are sure it works properly, you can proceed to synthesis. Using hdlmake for synthesis is as easy as using it for simulation. All you needed is a synthesis manifest (assuming the manifests for design files are already there), and you are good to go. Synthesis manifests tell the tool how to prepare your project file: what FPGA model to use, what package and speed grade it has, along with some additional information.
Design manifests
Considering our example project, cd
to the play/hdl/design/
folder
and edit Manifest.py
so that it contains the following:
files = [
"clk_div.vhd",
"leds_sm.vhd",
"led_ctrl.vhd",
"irq_controller_regs.vhd",
"irq_controller.vhd",
"addr_dec.vhd",
"led_ctrl_top.vhd"
]
modules = {
"git" : "git:https://www.ohwr.org/hdl-core-lib/general-cores.git",
"svn" : [ "http://svn.ohwr.org/ddr3-sp6-core/trunk/hdl",
"http://svn.ohwr.org/gn4124-core/trunk/hdl/gn4124core/rtl",
"http://svn.ohwr.org/gn4124-core/trunk/hdl/common/rtl"
]
}
fetchto = "../../../ip_cores"
You can see a number of extra things as opposed to the simulation case.
First, we have more design files in the current folder (you might have
noticed it when you cloned the design repository). Next, this manifest
also contains a modules
variable. This variable tells hdlmake that
we are using some IP cores (in our case, the GN4124 interface core, and
some other cores it depends on) which are stored on version control
systems using both Git and SVN servers. Last, there is a fetchto
variable; this tells hdlmake where to store the files retrieved from
the repository, in case the files are not present.
Synthesis manifest
Now, you should create a manifest in the synthesis folder, telling
hdlmake where to look for modules and what it should do. In our case,
we cd
to the synthesis folder (play/syn/
) and create the following
manifest file:
target = "xilinx"
action = "synthesis"
syn_device = "xc6slx45t"
syn_grade = "-3"
syn_package = "fgg484"
syn_top = "led_ctrl_top"
syn_project = "led_ctrl.xise"
files = "led_ctrl.ucf"
modules = {
"local" : "../hdl/design"
}
The following extra variables appear in the manifest:
-
target
: informs the tool that the target architecture is from Xilinx; -
action
: synthesis is to be performed; -
syn_device
: the FPGA device to perform synthesis for; -
syn_grade
: the speed grade of the FPGA; -
syn_top
: the top-level entity for the design; -
syn_project
: the target ISE project file.
Running hdlmake
Assuming everything is right up to now, running hdlmake
without any
arguments should download the missing files from the repository (note:
this might take quite some time, so get ready for a coffee break),
create a project file and a makefile for synthesis:
$ hdlmake
INFO: Running automatic flow
INFO: Fetching needed modules.
------------------
INFO: Fetching module: git:https://www.ohwr.org/hdl-core-lib/general-cores.git [parent: /home/tstana/Projects/play/hdl/design]
INFO: [git] Fetching to /home/tstana/Projects/ip_cores
Cloning into 'general-cores'...
remote: Counting objects: 2144, done.
remote: Compressing objects: 100% (1262/1262), done.
remote: Total 2144 (delta 1242), reused 1485 (delta 813)
Receiving objects: 100% (2144/2144), 6.79 MiB | 7.96 MiB/s, done.
Resolving deltas: 100% (1242/1242), done.
INFO: The manifest inside /home/tstana/Projects/ip_cores/general-cores/modules/genrams/Manifest.py tried to print something:
> [genrams] creating workdir /home/tstana/Projects/ip_cores/general-cores/modules/genrams/coregen_ip
> [genrams] copying ISE files...
>
------------------
INFO: Fetching module: http://svn.ohwr.org/gn4124-core/trunk/hdl/common/rtl [parent: /home/tstana/Projects/play/hdl/design]
INFO: [svn] Fetching to /home/tstana/Projects/ip_cores
A gn4124-core/trunk/hdl/common/rtl/dummy_ctrl_regs.vhd
A gn4124-core/trunk/hdl/common/rtl/dummy_stat_regs.vhd
A gn4124-core/trunk/hdl/common/rtl/wb_addr_decoder.vhd
A gn4124-core/trunk/hdl/common/rtl/Manifest.py
Checked out revision 195.
------------------
INFO: Fetching module: http://svn.ohwr.org/gn4124-core/trunk/hdl/gn4124core/rtl [parent: /home/tstana/Projects/play/hdl/design]
INFO: [svn] Fetching to /home/tstana/Projects/ip_cores
A gn4124-core/trunk/hdl/gn4124core/rtl/dma_controller.vhd
A gn4124-core/trunk/hdl/gn4124core/rtl/l2p_arbiter.vhd
A gn4124-core/trunk/hdl/gn4124core/rtl/p2l_decode32.vhd
A gn4124-core/trunk/hdl/gn4124core/rtl/dma_controller_wb_slave.vhd
A gn4124-core/trunk/hdl/gn4124core/rtl/l2p_dma_master.vhd
A gn4124-core/trunk/hdl/gn4124core/rtl/p2l_dma_master.vhd
A gn4124-core/trunk/hdl/gn4124core/rtl/wbmaster32.vhd
A gn4124-core/trunk/hdl/gn4124core/rtl/spartan3
[...]
Checked out revision 108.
INFO: Generating/updating ISE project
INFO: Generating makefile for local synthesis.
WARNING: Connection data is not given. Accessing environmental variables in the makefile
INFO: Generating makefile for remote synthesis.
As in the simulation case, the tool parses through each manifest that it
is pointed to (via modules
variables) and recursively adds files to
the project. When parsing the manifest under play/hdl/design/
and it
encounters the "git"
and "svn"
keys, hdlmake searches for design
manifests in the folder the fetchto
variable points to. If it can find
manifests there, it will continue adding files in a manner similar to
before. Otherwise, hdlmake will try to fetch the repositories listed
in the manifest. In a
nutshell:
Additionally, hdlmake will create an ISE project file and a makefile.
Running make
now, the Generate Programming File flow from the
Xilinx ISE tool is run. Before that, one can edit the flow in Xilinx ISE
to adjust for custom settings or steps. The final result of the flow
would be a programming file one can download to the FPGA RAM. (Btw,
you should get ready for another coffee break, since this flow might
take some time as well).
Summary
And that's it! That is how you use hdlmake for keeping track of your project files. A summary of what needs to be done is listed below:
- Create one manifest file for each folder where you have design
files. A manifest is a Python script (therefore, following Python
language conventions) defining variables relevant to hdlmake when
it generates your design project. When you run
hdlmake
, the manifests get read by the Python interpreter, so if need be, you can write more advanced Python code in the manifest. A simple manifest such as those we've shown here will however suffice in most cases. - Splitting design files into folders in a logical manner keeps your
design modular and maintanable. One such design folder is called a
module (in hdlmake parlance), and is indicated via the
modules
variable in the manifest; themodule
variable is a Python dictionary and the keys can have three different values:-
"local"
: the modules are located on the current machine -
"git"
: the modules are located on a git version control server -
"svn"
: the modules are located on a svn version control server
-
- Edit the manifest files if you add, remove, or modify any of your
designs. In this case, you should run
hdlmake
to update your ISE project file and/or your simulation makefile. - For simulation, create a manifest file in the simulation folder,
where you specify simulation as the
action
variable of the script. - For synthesis, create a manifest file in the synthesis folder,
where you specify synthesis as the
action
variable, along with the rest of the relevant variables. - Run
make
in your simulation or synthesis folder to prepare the design for simulation, or respectively to run the Generate Programming File flow. This step is not needed; if you are more comfortable with double-clicking Generate Programming File in the Project Navigator's flow pane, you are free to do so. Just make sure you do not switch to automatic compile order in Project Navigator. If you do, you will lose the settings made by hdlmake.
Closing remarks
Running hdlmake
with the --list
option is a pretty useful way of
checking if your design manifests have been written correctly. The
option runs hdlmake without creating makefiles or fetching anything,
instead it shows you all design files you defined in your manifests. For
example, the following is a sample of a correct output:
$ hdlmake --list
../../ip_cores/gn4124-core/trunk/hdl/gn4124core/rtl
#http://svn.ohwr.org/gn4124-core/trunk/hdl/gn4124core/rtl
dma_controller.vhd
dma_controller_wb_slave.vhd
l2p_arbiter.vhd
l2p_dma_master.vhd
p2l_decode32.vhd
p2l_dma_master.vhd
wbmaster32.vhd
../../ip_cores/gn4124-core/trunk/hdl/common/rtl
#http://svn.ohwr.org/gn4124-core/trunk/hdl/common/rtl
dummy_ctrl_regs.vhd
dummy_stat_regs.vhd
wb_addr_decoder.vhd
../../ip_cores/general-cores
#git:https://www.ohwr.org/hdl-core-lib/general-cores.git
# no files
If hdlmake had to download some files from the repository, an
#unfetched
message would appear under each of the repository links. If
something is however wrong with your manifest(s), hdlmake will exit
with an error and usually tell you where the problem is. You can use
this output to debug your manifests. Running hdlmake --verbose
can
also help in debugging what you did wrong in your manifests.
For more details about the tool, feel free to check the introduction page as well as details about run parameters and manifest variables.
Finally, if you find any inaccuracies with the current tutorial, don't hesitate to contact the developers of this project.