[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.