The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

Tutorial for using Hardware::Vhdl::Automake

Step 1: Installing the modules

First ensure that you have the required dependency modules installed. These are:

Hardware::Vhdl::Lexer (version 1.0 or later)
YAML (version 0.62 or later)
Test::More
File::Spec::Functions
File::Path
File::Temp
File::Copy
File::Temp
File::Basename
Digest::MD5
Math::Expression
List::Util
Carp

Installation of Hardware::Vhdl::Automake should be done in the usual way for unpacking a CPAN distribution:

  • Unzip and untar the distribution archive

  • Change dir to the location where the files were unpacked and run the following commands:

        perl Makefile.PL
        make
        make test
        make install

Step 2: Set up a VHDL project

  • Create a working directory for the VHDL project, for example C:\hva_tutorial.

  • Copy the example source file folder tutorial\src into the working directory, so that you have a folder called C:\hva_tutorial\src containing some .vhd files.

  • Create an empty directory called ‘hdl’ in the working directory.

  • Copy the file create_project.pl from the tutorial folder into C:\hva_tutorial.

  • Edit C:\hva_tutorial\create_project.pl, and change the definition of $project_dir to match the name of your working directory.

Let’s look at what create_project.pl does.

  • It creates a new Hardware::Vhdl::Automake::Project object

  • It calls a method add_sourcefiles, which tells the project to ensure that the given source files are included when compiling the project. The first file is specified simply by its filename, but the second also has some other settings given: the library that it is to be compiled into (‘work’ is the default) and the language (there are some hooks in the code to handle Verilog, but support isn’t complete because I don’t use Verilog).

  • If calls a method save(filename) to save the project.

  • If calls a method hdl_dir(dir_name) to set where the generated HDL is saved. “Generated HDL” is the set of VHDL files, one per design unit, which is generated from the source code that you write. These files are the ones that are used by the compiler or synthesiser tools, and are not meant to be edited by hand.

  • It calls the save() method without arguments: this saves the changes to the project, using the same filename as before. (There was no need to save the project twice, this was just to demonstrate that save() can remember the filename.)

Run the create_project.pl script.

It should not generate any console output, but a file called C:\hva_tutorial\ tutorial.hdlproj should be created.

Step 3: Generating the HDL files

  • Copy the file create generate_hdl.pl from the tutorial folder into C:\hva_tutorial.

  • Edit C:\hva_tutorial\generate_hdl.pl, and change the definition of $project_dir to match the name of your working directory.

This perl script loads the project that we created in step 2, tells the project how to output the status reports that it generates (for now it just prints the basic information to STDOUT, but I’ll provide something more user-friendly in a later step), and then tells it to generate all the HDL files. It then saves the project again: this is important, as the project file stores information about the code that has been compiled, so that it will know whether it needs recompiling later.

  • Run generate_hdl.pl. You should get output like this:

        Considering generating (pass 1): C:/hva_tutorial/src/adder.vhd
        Generating (pass 1): C:/hva_tutorial/src/adder.vhd
        New design unit code generated: entity work.adder
        New design unit code generated: architecture work.adder(rtl)
        Considering generating (pass 1): C:/hva_tutorial/src/count_up.vhd
        Generating (pass 1): C:/hva_tutorial/src/count_up.vhd
        New design unit code generated: entity work.count_up
        New design unit code generated: architecture work.count_up(struct)
        Considering generating (pass 2): architecture work.count_up(struct)
        Generating (pass 2): architecture work.count_up(struct)
        Considering generating (pass 2): architecture work.adder(rtl)
        New design unit code copied to HDL dir: entity work.count_up: C:\hva_tutorial\hdl\entity work count_up.vhd
        New design unit code copied to HDL dir: architecture work.count_up(struct): C:\hva_tutorial\hdl\architecture work count_up struct.vhd
        New design unit code copied to HDL dir: entity work.adder: C:\hva_tutorial\hdl\entity work adder.vhd
        New design unit code copied to HDL dir: architecture work.adder(rtl): C:\hva_tutorial\hdl\architecture work adder rtl.vhd 
  • Look in the hdl directory. You should see four files, one for each design unit in the two original files. Each file is simply named after the type of design unit it is, the library name, and the design unit name(s).

  • Look at ‘hdl/architecture work count_up struct.vhd’, and compare to src/count_up.vhd. Note that the specially formed comment “--< COMPONENT work.adder -->” has been replaced by a full definition of the interface for ‘adder’, taken from its entity declaration. This is a good labour-saver if you use component instantiations. (This is why there are two passes to the generation: the second pass inserts the component declarations.)

  • Run generate_hdl.pl again. You should get output like this:

        Considering generating (pass 1): C:/hva_tutorial/src/adder.vhd
        Considering generating (pass 1): C:/hva_tutorial/src/count_up.vhd
        Considering generating (pass 2): architecture work.count_up(struct)
        Considering generating (pass 2): architecture work.adder(rtl)
  • Note that it considers some generation, but decides that it doesn’t need to do any: this is because it has worked out that nothing has changed in the source files.

Step 4: Compiling the HDL

  • Copy the file create compile_hdl.pl from the tutorial folder into C:\hva_tutorial.

  • Create an empty directory called ‘sim’ in the working directory. This will be ModelSim’s working directory for the project, into which it will compile all its libraries.

  • In compile_hdl.pl, change the definition of $project_dir to match the name of your working directory.

  • In compile_hdl.pl, change the definition of $modelsim_path to match the name of the directory where the ModelSim executables for ‘vlib’, ‘vcom’ etc. can be found.

    The compile_hdl.pl script does the following things:

    • It loads the project file again

    • It creates a Hardware::Vhdl::Automake::Compiler::ModelSim object, and tells it where its working directory is.

    • It tells the compiler object where the ModelSim binaries are.

    • It tells both the project and the compiler objects how to report status

    • It tells the compiler object to compile the project, using the compiler object that we have just created and configured.

    • It saves the project again. This is necessary because the project object stores information about the compilation status.

  • Run compile_hdl.pl. You should get output like this:

        Starting ModelSim compilation
        Updating modelsim.ini
        Creating ModelSim library
        Updating modelsim.ini
        Doing ModelSim compile: entity work.count_up: C:\hva_tutorial\hdl\entity work count_up.vhd
        Doing ModelSim compile: entity work.adder: C:\hva_tutorial\hdl\entity work adder.vhd
        Doing ModelSim compile: architecture work.count_up(struct): C:\hva_tutorial\hdl\architecture work count_up struct.vhd
        ModelSim compile warning;  (vcom-1074) Non-locally static OTHERS choice is allowed only if it is the only choice of the only association.: architecture work.count_up(struct)
        Doing ModelSim compile: architecture work.adder(rtl): C:\hva_tutorial\hdl\architecture work adder rtl.vhd
        Finished ModelSim compilation 
  • Note that the tool has created the ‘work’ library, and a modelsim.ini file that holds the library mappings, and then compiles all the design units.

  • Run compile_hdl.pl again. You should get output like this:

        Starting ModelSim compilation
        Updating modelsim.ini
        Skipping ModelSim compile: entity work.count_up: C:\hva_tutorial\hdl\entity work count_up.vhd
        Skipping ModelSim compile: entity work.adder: C:\hva_tutorial\hdl\entity work adder.vhd
        Skipping ModelSim compile: architecture work.count_up(struct): C:\hva_tutorial\hdl\architecture work count_up struct.vhd
        Skipping ModelSim compile: architecture work.adder(rtl): C:\hva_tutorial\hdl\architecture work adder rtl.vhd
        Finished ModelSim compilation
  • Note that the tool has done no library creation or compilation, because everything is up-to date.

  • You should be able to load the design into ModelSim: start ModelSim, cd to C:\hva_tutorial\sim, and ‘vsim work.count_up’.

  • Try making changes to the files in src/, then running the generate_hdl.pl and compile_hdl.pl scripts again. You should find that the hdl files are updated and recompiled only when they need to be.

Step 5: A script to generate and compile

Usually there is no need to generate and compile separately: you want to generate all the hdl, and then compile any new or changed design units. The script generate_compile.pl does a load-generate-compile-save sequence, and also reports more detail on the process and any error reports.

  • Copy the file generate_compile.pl from the tutorial folder into C:\hva_tutorial.

  • In generate_compile.pl, change the definition of $project_dir to match the name of your working directory.

  • In generate_compile.pl, change the definition of $modelsim_path to match the name of the directory where the ModelSim executables for ‘vlib’, ‘vcom’ etc. can be found.

  • Delete the contents of C:\hva_tutorial\hdl and C:\hva_tutorial\sim, leaving them as empty directories. This is so that you can see the generation and compilation of all files happening again.

  • Run generate_compile.pl. You should get output like this:

        Generating HDL from source file C:/hva_tutorial/src/adder.vhd
          generated entity work.adder
          generated architecture work.adder(rtl)
        Generating HDL from source file C:/hva_tutorial/src/count_up.vhd
          generated entity work.count_up
          generated architecture work.count_up(struct)
        Generating (pass 2) architecture work.count_up(struct)
        copying new HDL for entity work.count_up at C:\hva_tutorial\hdl\entity work count_up.vhd line 1
        copying new HDL for architecture work.count_up(struct) at C:\hva_tutorial\hdl\architecture work count_up struct.vhd line 1
        copying new HDL for entity work.adder at C:\hva_tutorial\hdl\entity work adder.vhd line 1
        copying new HDL for architecture work.adder(rtl) at C:\hva_tutorial\hdl\architecture work adder rtl.vhd line 1
    
        Starting ModelSim compilation
        Updating modelsim.ini
        Creating ModelSim library
        Updating modelsim.ini
          compiling entity work.count_up    (because design unit is not listed in library info)
          compiling entity work.adder       (because design unit is not listed in library info)
          compiling architecture work.count_up(struct)      (because design unit is not listed in library info)
        WARNING: ModelSim compile warning;  (vcom-1074) Non-locally static OTHERS choice is allowed only if it is the only choice of the only association.
            line:      const_1 <= (0 => '1', others => '0');
            src: at C:\hva_tutorial\src\count_up.vhd line 30
            gen: at C:\hva_tutorial\hdl\architecture work count_up struct.vhd line 24
          compiling architecture work.adder(rtl)    (because design unit is not listed in library info)
        Finished ModelSim compilation 
  • Note that the messages are a now bit more human-readable. Note also that the warning from the compiler is accompanied by the line in error, the source file and line number, and the generated HDL file and line number. This output format was optimised for use with the ‘SciTE’ text editor, which recognises lines that end with “at <filename> line <number>” and allows you to double-click on these to load the file and jump to the line.

  • The project knows how to map a line number in any generated hdl file to a line in a source file. This is especially important if you start using the pre-processor, and #include other files.

What's not been covered

I still haven't shown you:

  • How your source code can be fed through a preprocessor during the generation stage

  • How you can set ModelSim compiler options in your source code.

Just email me at <michaelattenborough at yahoo doht co doht uk> - knowing that someone is interested will spur me to writing further documentation.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 70:

Non-ASCII character seen before =encoding in '‘hdl’'. Assuming CP1252