Main Content

Comparing HDL and Simulink Code Coverage using Cosimulation

This example shows how to achieve complete code coverage of an HDL cruise controller design using Simulink® and an HDL Simulator.

Introduction

The HDL code associated with this model is generated via HDL Coder™ from a Simulink behavioral model of the cruise controller. A test bench model is provided to verify the correctness of the HDL code by comparing the output of the HDL cosimulation block with that of the original behavioral block. The testcases in the test bench model are generated through Simulink Design Verifier™ from the original behavioral model for achieving complete model coverage. This example shows that those automatically generated testcases also achieve complete HDL code coverage. You do not need Simulink Design Verifier installed to run this example.

Open the Simulink Model

If you are using ModelSim or QuestaSim, the model cruise_control_modelsim.slx should be open. If you are using Incisive or Xcelium, close the ModelSim model and open the model cruise_control_incisive.slx.

Note that the code coverage function is an optional feature in ModelSim PE. Make sure that your version of ModelSim has the proper code coverage license to run this example.

% For ModelSim:
modelName = 'cruise_control_modelsim';
open_system(modelName);
% For Incisive:
modelName = 'cruise_control_incisive';
open_system(modelName);

Setting up Clocks, Resets, and Clock Enables in the HDL Simulation

The clock, reset, and clock enable signals are not part of the Simulink simulation. We define drivers for them using the "Pre-simulation Tcl commands" in the "Simulation" tab of the cosimulation block mask. We also set the "Time to run HDL simulator before cosimulation starts" such that the HDL has successfully gotten out of reset before any input and output data values are exchanged.

For ModelSim:

For Incisive:

The resulting waveforms in HDL:

The Tcl force commands are used to generate waveforms for the control signals:

  1. The clock period is 10 ns

  2. The clock enable signal is active at 37 ns.

  3. The reset signal is asserted from 0 to 27 ns.

The cosimulation starting time should be aligned with the falling edge of the HDL clock to avoid a race condition since the HDL signals change their values at the rising edge of the HDL clock. Therefore, the value of this parameter should be an integer multiple of the 10 ns clock period.

We also want to run the HDL design past reset, but stop before the first active clock edge enabled by clk_enable. This is to match the behavioral block, which updates its internal states right after the simulation starts.

Based on the above considerations, the option "Time to run HDL simulator before cosimulation starts" is set to 40 ns. When running each testcase, the "Pre-simulation Tcl commands" are applied in the HDL simulator first. Then the HDL simulator advances its time by 40 ns to apply the reset, clock, and clk_enable signals before the cosimulation starts.

Launch HDL Simulator for Cosimulation

For Modelsim:

% Commands to compile and invoke Modelsim with code coverage enabled.
tclCmds = {
    'vlib work',...                             % Create ModelSim library
    'vcom +cover cruise_hdlsrc/PI_Controller.vhd',...       % Compile VHDL code with code coverage enabled
    'vcom +cover cruise_hdlsrc/Controller.vhd',...          % Compile VHDL code with code coverage enabled
    'vsimulink  -coverage work.Controller',...  % Load simulation
    'puts "Ready for cosimulation..."',...
};
% Now we launch the HDL simulator and wait for it to be ready.
vsim('tclstart',tclCmds);
disp('Waiting for HDL simulator to start ...');
processid = pingHdlSim(240);
disp('HDL simulator is ready to cosimulate.');

For Incisive:

% Commands to compile and invoke Incisive with code coverage enabled.
tclCmds = {
    'exec ncvhdl -64bit -v93 cruise_hdlsrc/PI_Controller.vhd',...      % Compile VHDL code
    'exec ncvhdl -64bit -v93 cruise_hdlsrc/Controller.vhd',...         % Compile VHDL code
    'exec ncelab -64bit -coverage all -vhdl_time_precision 1ns -access +wc Controller',... % Elaborate design with coverage enabled
    'hdlsimulink -covoverwrite Controller',...           % Load simulation
    'puts "Ready for cosimulation..."',...
};
% Now we launch the HDL simulator and wait for it to be ready.
nclaunch('tclstart',tclCmds,'runmode','CLI','libfile','liblfihdls_gcc44.so');
disp('Waiting for HDL simulator to start ...');
processid = pingHdlSim(240);
disp('HDL simulator is ready to cosimulate.');

Run Simulation

There are nine testcases in the test bench model. This example runs this model with all testcases to produce the code coverage result. After finishing each cosimulation session, there is no need to restart the HDL simulator since the HDL signal is reset properly at the beginning of each simulation. After each simulation, a short pause is added to ensure time for the HDL simulator to update the coverage result before the next iteration.

% Run the cosimulation
for k = 1 : 9
   signalbuilder([modelName '/Inputs'], 'activegroup', k); % Select a testcase
   sim(modelName); % Run simulation
   pause(5); % pause for writing coverage to database
end

Observe Code Coverage Result

The HDL simulator accumulates coverage as we iterate through all the testcases. When the simulation is finished, 100% code coverage is achieved.

For ModelSim: You can examine the coverage result in the "Coverage" tab of the UI.

For Incisive: We dump the coverage results and use the "imc" tool to visualize the results.

% Dump and visualize the coverage results
tclHdlSim('coverage -dump test');
system('imc -gui -load test &');