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
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 
Reading data file
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: