news

[Published in Electronics For You (EFY) magazine, June 2014 edition.] Source

HCT stands for HDL Complexity Tool, where HDL stands for Hardware Description Language. HCT provides scores that represent the complexity of modules present in integrated circuit (IC) designs. It is written in Perl and released under the GPLv3 and LGPLv3 license. It employs McCabe Cyclomatic Complexity that uses the control flow graph of the program source code to determine the complexity.

There are various factors for measuring the complexity of HDL models such as size, nesting, modularity, and timing. The measured metrics can help designers in refactoring their code, and also help managers to plan project schedules, and allocate resources, accordingly. You can run the tool from the GNU/Linux terminal for Verilog, VHDL, and CDL (Computer Design Language) files or directory sources. HCT can be installed on Fedora using the command:

$ sudo yum install hct

After installation, consider the example project of uart2spi written in Verilog, which is included in this month’s EFY DVD. It implements a simple core for a UART interface, and an internal SPI bus. The uart2spi folder contains rtl/spi under the file directory in your PC: /home/guest/uart2spi/trunk/rtl/spi. Run the HCT tool on the rtl/spi Verilog sources as follows:

$ hct rtl/spi

We get the output:

Directory: /home/guest/uart2spi/trunk/rtl/spi

verilog, 4 file(s)
+--------------------+--------------+------+-------+----------+--------+
| FILENAME           | MODULE       | IO   | NET   | MCCABE   | TIME   |
+--------------------+--------------+------+-------+----------+--------+
| spi_ctl.v                           20     1       1          0.1724 |
|                      spi_ctl        20     1       1                 |
+----------------------------------------------------------------------+
| spi_core.v                          0      0       1          0.0076 |
|                      spi_core       0      0       1                 |
+----------------------------------------------------------------------+
| spi_cfg.v                           0      0       1          0.0076 |
|                      spi_cfg        0      0       1                 |
+----------------------------------------------------------------------+
| spi_if.v                            15     3       1          0.0994 |
|                      spi_if         15     3       1                 |
+----------------------------------------------------------------------+

The output includes various attributes that are described below:

  • FILENAME is the file that is being parsed. The parser uses the file name extension to recognize the programming language.

  • MODULE refers to the specific module present in the file. A file can contain many modules.

  • IO refers to the input/output registers used in the module.

  • NET includes the network entities declared in the given module. For Verilog, it can be ‘wire’, ‘tri’, ‘supply0’ etc.

  • MCCABE provides the McCabe Cyclomatic Complexity of the module or file.

  • TIME refers to the time taken to process the file.

A specific metric can be excluded from the output using the “–output-exclude=LIST” option. For example, type the following command on a GNU/Linux terminal:

$ hct --output-exclude=TIME rtl/spi 

The output will be;

Directory: /home/guest/uart2spi/trunk/rtl/spi

verilog, 4 file(s)
+----------------------+----------------+--------+---------+-----------+
| FILENAME             | MODULE         | IO     | NET     | MCCABE    |
+----------------------+----------------+--------+---------+-----------+
| spi_ctl.v                               20       1         1         |
|                        spi_ctl          20       1         1         |
+----------------------------------------------------------------------+
| spi_core.v                              0        0         1         |
|                        spi_core         0        0         1         |
+----------------------------------------------------------------------+
| spi_cfg.v                               0        0         1         |
|                        spi_cfg          0        0         1         |
+----------------------------------------------------------------------+
| spi_if.v                                15       3         1         |
|                        spi_if           15       3         1         |
+----------------------------------------------------------------------+

If you want only the score to be listed, you can remove the MODULE listing with the “–output-no-modules” option:

$ hct --output-no-modules rtl/spi

Directory: /home/guest/uart2spi/trunk/rtl/spi

verilog, 4 file(s)
+-----------------------+---------+----------+-------------+-----------+
| FILENAME              | IO      | NET      | MCCABE      | TIME      |
+-----------------------+---------+----------+-------------+-----------+
| spi_ctl.v               20        1          1             0.16803   |
+----------------------------------------------------------------------+
| spi_core.v              0         0          1             0.007434  |
+----------------------------------------------------------------------+
| spi_cfg.v               0         0          1             0.00755   |
+----------------------------------------------------------------------+
| spi_if.v                15        3          1             0.097721  |
+----------------------------------------------------------------------+

The tool can be run on individual files, or recursively on subdirectories with the “-R” option. The output the entire uart2spi project sources is given below:

$ hct -R rtl

Directory: /home/guest/uart2spi/trunk/rtl/uart_core

verilog, 4 file(s)
+--------------------+--------------+------+-------+----------+--------+
| FILENAME           | MODULE       | IO   | NET   | MCCABE   | TIME   |
+--------------------+--------------+------+-------+----------+--------+
| uart_rxfsm.v                        10     0       1          0.1379 |
|                      uart_rxfsm     10     0       1                 |
+----------------------------------------------------------------------+
| clk_ctl.v                           0      0       1          0.0146 |
|                      clk_ctl        0      0       1                 |
+----------------------------------------------------------------------+
| uart_core.v                         18     1       1          0.1291 |
|                      uart_core      18     1       1                 |
+----------------------------------------------------------------------+
| uart_txfsm.v                        9      0       1          0.1129 |
|                      uart_txfsm     9      0       1                 |
+----------------------------------------------------------------------+

Directory: /home/guest/uart2spi/trunk/rtl/top

verilog, 1 file(s)
+--------------------+--------------+------+-------+----------+--------+
| FILENAME           | MODULE       | IO   | NET   | MCCABE   | TIME   |
+--------------------+--------------+------+-------+----------+--------+
| top.v                               16     0       1          0.0827 |
|                      top            16     0       1                 |
+----------------------------------------------------------------------+

Directory: /home/guest/uart2spi/trunk/rtl/spi

verilog, 4 file(s)
+--------------------+--------------+------+-------+----------+--------+
| FILENAME           | MODULE       | IO   | NET   | MCCABE   | TIME   |
+--------------------+--------------+------+-------+----------+--------+
| spi_ctl.v                           20     1       1          0.1645 |
|                      spi_ctl        20     1       1                 |
+----------------------------------------------------------------------+
| spi_core.v                          0      0       1          0.0074 |
|                      spi_core       0      0       1                 |
+----------------------------------------------------------------------+
| spi_cfg.v                           0      0       1          0.0073 |
|                      spi_cfg        0      0       1                 |
+----------------------------------------------------------------------+
| spi_if.v                            15     3       1          0.0983 |
|                      spi_if         15     3       1                 |
+----------------------------------------------------------------------+

Directory: /home/guest/uart2spi/trunk/rtl/lib

verilog, 1 file(s)
+--------------------+--------------+------+-------+----------+--------+
| FILENAME           | MODULE       | IO   | NET   | MCCABE   | TIME   |
+--------------------+--------------+------+-------+----------+--------+
| registers.v                         5      0       1          0.0382 |
|                      bit_register   5      0       1                 |
+----------------------------------------------------------------------+

Directory: /home/guest/uart2spi/trunk/rtl/msg_hand

verilog, 1 file(s)
+--------------------+--------------+------+-------+----------+--------+
| FILENAME           | MODULE       | IO   | NET   | MCCABE   | TIME   |
+--------------------+--------------+------+-------+----------+--------+
| uart_msg_handler.v                  0      0       1          0.0192 |
|                      uart_m~ndler   0      0       1                 |
+----------------------------------------------------------------------+

The default behaviour is to dump the output to the terminal. It can be redirected to a file with the “–output-file=FILE” option. You can also specify an output file format, such as “csv” with the “–output-format=FORMAT” option:

$ hct --output-file=/home/guest/project-metrics.csv --output-format=csv rtl/spi 

$ cat /home/guest/project-metrics.csv

Directory: /home/guest/uart2spi/trunk/rtl/spi

verilog, 4 file(s)

 FILENAME    , MODULE    , IO   , NET  , MCCABE  , SLOC  , COMMENT_LINES  , TIME
 spi_ctl.v   ,           , 20   , 1    , 1       , 110   , 48             , 0.1644
             , spi_ctl   , 20   , 1    , 1       , 68    , 6              ,
 spi_core.v  ,           , 0    , 0    , 1       , 46    , 43             , 0.0073
             , spi_core  , 0    , 0    , 1       , 4     , 1              ,
 spi_cfg.v   ,           , 0    , 0    , 1       , 46    , 43             , 0.0075
             , spi_cfg   , 0    , 0    , 1       , 4     , 1              ,
 spi_if.v    ,           , 15   , 3    , 1       , 80    , 44             , 0.0948
             , spi_if    , 15   , 3    , 1       , 38    , 2              ,

There are various yyparse options that are helpful to understand the lexical parsing of the source code. They can be invoked using the following command:

$ hct --yydebug=NN sources

The NN options and their meaning is listed below:

0x01 Lexical tokens
0x02 Information on States
0x04 Shift, reduce, accept driver actions
0x08 Dump of the parse stack
0x16 Tracing for error recovery
0x31 Complete output for debugging

HCT can also be used with VHDL, and Cyclicity CDL (Cycle Description Language) programs. For VHDL, the filenames must end with a .vhdl extension. You can rename .vhd files recursively in a directory (in Bash, for example) using the following script:

for file in `find $1 -name "*.vhd"`
do
  mv $file ${file/.vhd/.vhdl}
done

The “$1” refers to the project source directory that is passed as an argument to the script. Let us take the example of sha256 core written in VHDL, which is also included in this month’s EFY DVD. The execution of HCT on the sha256core project is as follows:

 $  hct rtl

Directory: /home/guest/sha256core/trunk/rtl

vhdl, 6 file(s)
+--------------------+--------------+------+-------+----------+--------+
| FILENAME           | MODULE       | IO   | NET   | MCCABE   | TIME   |
+--------------------+--------------+------+-------+----------+--------+
| sha_256.vhdl                        29     0       1          0.9847 |
|                      sha_256        29     0       1                 |
+----------------------------------------------------------------------+
| sha_fun.vhdl                        1      1       1          0.3422 |
|                                     1      1       1                 |
+----------------------------------------------------------------------+
| msg_comp.vhdl                       20     0       1          0.4169 |
|                      msg_comp       20     0       1                 |
+----------------------------------------------------------------------+
| dual_mem.vhdl                       7      0       3          0.0832 |
|                      dual_mem       7      0       3                 |
+----------------------------------------------------------------------+
| ff_bank.vhdl                        3      0       2          0.0260 |
|                      ff_bank        3      0       2                 |
+----------------------------------------------------------------------+
| sh_reg.vhdl                         19     0       1          0.6189 |
|                      sh_reg         19     0       1                 |
+----------------------------------------------------------------------+

The “-T” option enables the use of threads to speed up computation. The LZRW1 (Lempel–Ziv Ross Williams) compressor core project implements a lossless data compression algorithm. The output of HCT on this project, without threading and with threads enabled, is shown below:

$ time hct HDL

Directory: /home/guest/lzrw1-compressor-core/trunk/hw/HDL

vhdl, 8 file(s)
...
real	0m3.725s
user	0m3.612s
sys     0m0.013s

$ time hct HDL -T

Directory: /home/guest/lzrw1-compressor-core/trunk/hw/HDL

vhdl, 8 file(s)
...
real	0m2.301s
user	0m7.029s
sys     0m0.051s

The supported input options for HCT can be viewed with the “-h” option.

The invocation of HCT can be automated, rechecked for each code check-in that happens to a project repository. The complexity measure is thus recorded periodically. The project team will then be able to monitor, analyse the complexity of each module and decide on any code refactoring strategies.