Measuring code coverage with GHDL

I have recently switched to using GHDL as my VHDL simulator of choice. GHDL (currently) supports three different backends: GCC, LLVM and a builtin code generator.

The GCC backend got me thinking… since my VHDL test benches are now native ELF binaries compiled with GCC, I should be able to instrument them with Gcov support – and measure code coverage for each unit under test (UUT).

Turns out to be pretty simple – just a matter of using the right compiler and linker flags, just like building a Gcov-instrumented binary from C code.

Take for instance the full adder example from the GHDL documentation – once the adder.vhdl and adder_tb.vhdl files are saved to disk, it is just a matter of modifying the GHDL commands a bit to instrument the final binary with Gcov support.

First analyze the design files with -fprofile-arcs and -ftest-coverage added to CFLAGS for all the VHDL files, that should be instrumented. Here, I have only instrumented the UUT, not the test bench:

$ ghdl -a  -Wc,-fprofile-arcs -Wc,-ftest-coverage adder.vhdl
$ ghdl -a  adder_tb.vhdl  

Next, elaborate the test bench and link the binary against libgcov:

$ ghdl -e -Wl,-lgcov adder_tb

Run the test bench as usual:

$ ghdl -r adder_tb
adder_tb.vhdl:53:7:@8ns:(assertion note): end of test

Generate a code coverage report using the gcov(1) tool:

$ gcov -s $PWD adder.vhdl 
File 'adder.vhdl'
Lines executed:100.00% of 4
Creating 'adder.vhdl.gcov'

The Gcov code coverage details can be found in the adder.vhdl.gcov file. Details on the file format can be found in the gcov(1) man page:

$ cat adder.vhdl.gcov 
        -:    0:Source:adder.vhdl
        -:    0:Graph:adder.gcno
        -:    0:Data:adder.gcda
        -:    0:Runs:1
        -:    0:Programs:1
       13:    1:entity adder is
        -:    2:  -- `i0`, `i1` and the carry-in `ci` are inputs of the adder.
        -:    3:  -- `s` is the sum output, `co` is the carry-out.
        -:    4:  port (i0, i1 : in bit; ci : in bit; s : out bit; co : out bit);
        -:    5:end adder;
        -:    6:
        2:    7:architecture rtl of adder is
        -:    8:begin
        -:    9:   --  This full-adder architecture contains two concurrent assignment.
        -:   10:   --  Compute the sum.
       17:   11:   s <= i0 xor i1 xor ci;
        -:   12:   --  Compute the carry.
       10:   13:   co <= (i0 and i1) or (i0 and ci) or (i1 and ci);
        -:   14:end rtl;

Another option is to use a tool like Lcov, which can produce nice looking HTML pages with the Gcov code coverage details:

$ lcov -c -d . -o adder_tb.info
Capturing coverage data from .
Found gcov version: 4.9.4
Scanning . for .gcda files ...
Found 1 data files in .
Processing adder.gcda
Finished .info-file creation
$ genhtml -o html adder_tb.info 
Reading data file adder_tb.info
Found 1 entries.
Found common filename prefix "/home/brix/tmp"
Writing .css and .png files.
Generating output.
Processing file adder/adder.vhdl
Writing directory view page.
Overall coverage rate:
  lines......: 100.0% (4 of 4 lines)
  functions..: 100.0% (7 of 7 functions)

The Lcov code coverage details can be found in the html/index.html file:

6 thoughts on “Measuring code coverage with GHDL”

  1. Hi Brix,

    Is there a way we can extract branch coverage from lcov?

    Thanks!

    Best regards,
    Anirudh

  2. Hello!
    When I try your instruction I get this error on the elaborate:

    adder.o: In function `_GLOBAL__sub_D_00100_1_work__adder__i0__RTI’:
    adder.vhd:(.text+0x5d6): undefined reference to `__gcov_exit’
    collect2: error: ld returned 1 exit status
    ghdl:error: compilation error

    I appreciate some help.

  3. I’m experiencing the exact same error as Pedro, and I’m copying and pasting the exact commands from your article. Are we missing something? Do we need to compile the GCC backend with gcov support or something?

Leave a Reply

Your email address will not be published. Required fields are marked *