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 testbench 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 testbench 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 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 Xcelium: 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 Xcelium:
The resulting waveforms in HDL:
The Tcl force commands are used to generate waveforms for the control signals:
The clock period is 10 ns
The clock enable signal is active at 37 ns.
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 Xcelium:
% Commands to compile and invoke Xcelium with code coverage enabled. tclCmds = { 'exec xmvhdl -64bit -v93 cruise_hdlsrc/PI_Controller.vhd',... % Compile VHDL code 'exec xmvhdl -64bit -v93 cruise_hdlsrc/Controller.vhd',... % Compile VHDL code 'exec xmelab -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'); 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 testbench 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 get_param([modelName '/Inputs'],'ActiveScenario'); % get ActiveScenario parameter for changing test scenarios set_param([modelName '/Inputs'],'ActiveScenario',['Test_Case_' num2str(k)]) % set a Test case 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 Xcelium: 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 &');