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, and create manifests for local synthesis. Additionally, it will show you 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 continue, 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
In order to run hdlmake on your computer, you have two choices. The first (and the easiest) is downloading the binary file to a location of choice on the computer. The second choice is cloning the hdlmake repository and building hdlmake on your own. While the first choice might seem the faster solution, it is never 100% certain that the uploaded binary is conclusive with the sources, so building the tool on your own might be a wiser decision. Up to you.
Downloading the compiled binary
For downloading the compiled binary, click here. Download to a location of choice, and you're almost ready to use it! You can jump directly to the final steps.
Compile hdlmake yourself
If you prefer building it yourself (highly recommended), 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, cd to the newly created folder, then to the source folder, clean
already built files and build again. This will generate a new executable
in the file .hdlmake/hdlmake
:
$ cd .hdlmake/src/
$ make clean
$ make
Final steps
To be able to run the hdlmake
command from anywhere on your file
system, create a link to the binary from your /usr/bin/
folder (or any
folder that is on your system's $PATH). Assuming your hdlmake
binary
is under /home/user_name/.hdlmake/
:
$ cd /usr/bin
$ sudo ln -s /home/user_name/.hdlmake/hdlmake
There, now you should be able to run the command from anywhere on your file system!
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 (note: you need an SVN client for this to work):
$ mkdir play
$ cd play
$ svn co http://svn.ohwr.org/fmc-adc-100m14b4cha/trunk/play .
The output of this command should be something like:
A doc
A doc/design_description.pdf
A hdl
A hdl/tb
A hdl/tb/testbench.vhd
A hdl/design
A hdl/design/addr_dec.vhd
A hdl/design/leds_sm.vhd
A hdl/design/led_ctrl.vhd
A hdl/design/led_ctrl_top.vhd
A hdl/design/clk_div.vhd
A hdl/design/irq_controller.vhd
A hdl/design/irq_controller_regs.vhd
A sim
A sim/wave.do
A sim/run.do
A sw
A sw/python
A sw/python/bitstream_load.py
A sw/python/play_leds.py
A syn
A syn/led_ctrl.ucf
Okay, now that you have the project files, 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 for simulation assumes you are running some version of Modelsim and will create a Makefile for simulation using this software.
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"
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, and that the target is
Modelsim for Xilinx.
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:
sim-ex.png
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 (considering 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:
(red) Running make
now, the Generate Programming File flow from
the Xilinx ISE tool is run. Before that, one could 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. 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. - 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.
Closing remarks
For more details about the tool, feel free to check the introduction page as well as details about run parameters and manifest variables.
If you find any inaccuracies with the current tutorial, don't hesitate to contact the developers of this project.