Main Content

This example shows how to reuse an existing Simulink® model to verify HDL Coder™ generated hardware designs using an HDL Verifier™ cosimulation test bench.

Introduction

Cosimulation is a challenging task, especially with automatically generated code. It is important to keep in-sync various aspects of the source model including sample rates, feedforward/feedthrough systems, and other various parameters and settings used during code generation, while setting up the HDL Verifier cosimulation block and the target HDL simulator.

The automated cosimulation model generation takes the guess-work out of the HDL cosimulation block and simulator setup by deciphering all the compiled model and code generation information. All of the automated settings are documented in the generated scripts. The end result is a cosimulation model that is ready to verify the generated code.

The main examples show using Mentor Graphics® ModelSim®/Questa®, but other supported simulators include Cadence® Xcelium™ (formerly Incisive®) and Xilinx® Vivado™ Simulator. Specific makehdltb examples are given for those simulators at the end.

Generating HDL and the Cosimulation Model

This sections shows a basic multiply-accumulate design in Simulink. We generate the HDL design and generate a cosimulation test bench model. We then go through some details of how the test bench model operates.

Generate the HDL Design

Take a simple accumulator design in Simulink and automatically generate a cosimulation model for it as a part of test bench generation.

% Generate VHDL code using the |makehdl| function.
makehdl('hdl_cosim_demo1/MAC', 'targetlang', 'vhdl')
### Generating HDL for 'hdl_cosim_demo1/MAC'.
### Using the config set for model <a href="matlab:configset.showParameterGroup('hdl_cosim_demo1', { 'HDL Code Generation' } )">hdl_cosim_demo1</a> for HDL code generation parameters.
### Running HDL checks on the model 'hdl_cosim_demo1'.
### Begin compilation of the model 'hdl_cosim_demo1'...
### Working on the model 'hdl_cosim_demo1'...
### Working on... <a href="matlab:configset.internal.open('hdl_cosim_demo1', 'GenerateModel')">GenerateModel</a>
### Begin model generation 'gm_hdl_cosim_demo1' ....
### Copying DUT to the generated model....
### Model generation complete.
### Begin VHDL Code Generation for 'hdl_cosim_demo1'.
### Working on hdl_cosim_demo1/MAC as hdlsrc/hdl_cosim_demo1/MAC.vhd.
### Code Generation for 'hdl_cosim_demo1' completed.
### Creating HDL Code Generation Check Report file:///tmp/Bdoc23b_2361005_1096937/tpcc840b07/hdlcoder-ex48550583/hdlsrc/hdl_cosim_demo1/MAC_report.html
### HDL check for 'hdl_cosim_demo1' complete with 0 errors, 0 warnings, and 0 messages.
### HDL code generation complete.

Generate the Cosimulation Model as an HDL Test Bench

Using the model used for creating the Simulink design as a starting point, generate a cosimulation model to use as an HDL test bench. Set the makehdl parameter GenerateCosimModel to choose the HDL simulator. Supported values include ModelSim, Incisive, or Vivado Simulator.

% Generate the cosimulation test bench for the MAC HDL
makehdltb('hdl_cosim_demo1/MAC', 'targetlang', 'vhdl', 'GenerateCosimModel', 'ModelSim')
### Begin TestBench generation.
### Generating HDL TestBench for 'hdl_cosim_demo1/MAC'.
### Begin compilation of the model 'hdl_cosim_demo1'...
### Begin compilation of the model 'gm_hdl_cosim_demo1'...
### Generating new cosimulation model: <a href="matlab:open_system('gm_hdl_cosim_demo1_mq')">gm_hdl_cosim_demo1_mq</a>.
### Generating new cosimulation tcl script: hdlsrc/hdl_cosim_demo1/gm_hdl_cosim_demo1_mq_tcl.m.
### Generating new cosimulation tcl script: hdlsrc/hdl_cosim_demo1/gm_hdl_cosim_demo1_mq_batch_tcl.m.
### Note: Option 'Allow direct feedthrough' has been set to 'on' on 'gm_hdl_cosim_demo1_mq/MAC_mq'
### Begin simulation of the model 'gm_hdl_cosim_demo1'...

### Collecting data...
### Generating test bench data file: hdlsrc/hdl_cosim_demo1/In1.dat.
### Generating test bench data file: hdlsrc/hdl_cosim_demo1/In2.dat.
### Generating test bench data file: hdlsrc/hdl_cosim_demo1/Out1_expected.dat.
### Working on MAC_tb as hdlsrc/hdl_cosim_demo1/MAC_tb.vhd.
### Generating package file hdlsrc/hdl_cosim_demo1/MAC_tb_pkg.vhd.
### HDL TestBench generation complete.
 

New Code Generation Messages

As seen from the additional code generation messages in the command window a cosimulation model gm_hdl_cosim_demo1_mq is generated; In addition to the code generated in the target directory, hdlsrc, an additional cosimulation script gm_hdl_cosim_demo1_mq_tcl.m is generated to prepare the target simulator for cosimulation with Simulink.

### Generating new cosimulation model: gm_hdl_cosim_demo1_mq
### Generating new cosimulation tcl script: hdlsrc/gm_hdl_cosim_demo1_mq_tcl.m
### Cosimulation Model Generation Complete.

(Optional) Generate HDL Code Coverage Report and Database

To instrument the HDL Simulator to generate a code coverage database, either:

a) On the HDL Code Generation > Test Bench pane, select the check box labeled HDL code coverage.

b) When you call makehdltb, set HDLCodeCoverage to on. For example:

makehdltb('hdl_cosim_demo1/MAC', 'targetlang', 'vh', 'GenerateCosimModel', 'ModelSim','HDLCodeCoverage','on');

The HDL code coverage artifacts are generated in the source directory after the test bench is simulated.

Examining the Cosimulation Model Test Bench Features

Stimulus and Response Capture

As you can see from the cosimulation model the original device under test (DUT) is intercepted by two subsystems ToCosimSrc and ToCosimSink. The purpose of these two subsystems is to capture the stimulus and the response of the DUT and use it for driving the cosimulation using Goto blocks. The number of Goto blocks in each of the following subsystems match the number of inputs and outputs of the DUT.

ToCosimSrc:

ToCosimSink:

Stimulus to the HDL Cosimulation Block

The stimulus that is originally driving the DUT is fed to the fully configured HDL cosimulation block using the From block as shown below. In some cases input stimulus signals cannot be directly fed to the HDL Cosimulation block. For example, the HDL design might have flattened structured datatypes such as complex signals and vectored signals and the HDL cosimulation block reflects the RTL interface. In such cases further transformation of the input stimulus signals is done automatically. In the current model, the From blocks directly feed the contents of corresponding Goto blocks.

FromCosimSrc:

Comparison of the Results

The response from the original DUT is compared with the response from the HDL Cosimulation block in HDL Verifier using the Sink blocks provided by Simulink for visualization of the response data.

Compare:

Assertion Checking in the Generated Model

For each output of the device under test subsystem the following assertion-checking model is generated that checks the original output (dut ref) with cosimulation output (cosim) and generates assertion messages when the input to the assertion block detects a mismatch.

Assert_Out1:

Using Assertion Blocks

Assertions are enabled in the Assertion block but do not stop simulation. If as a part of cosimulation there are any assertions from the following block you should see a warning from the Assertion block:

Warning: Assertion detected in 'gm_hdl_cosim_demo1_mq/Compare/Assert_Out1/AssertEq' at time 1.000000

Examining the HDL Simulator Specific Support

HDL Cosimulation Block Setup

The HDL Cosimulation block is automatically populated with the compiled input output interface of the DUT. The Ports panel is fully populated with Full HDL Name, Sample Time and Data type information. Similarly, various HDL Cosimulation block setup parameters such as Timescale and tcl port panes are automatically populated. Note that Connection method of the cosimulation model is always configured as Shared Memory.

MAC_mq:

Warning: Expected localHostName to be a row vector. 

Target Simulator Launch and Setup

Now look at the automation associated with the launch and setup of the target simulator (ModelSim/Questa, Incisive/Xcelium, or Vivado Simulator). As can be seen in the top level of the generated model, a subsystem with the name Start Simulator is generated with the following callback function. This subsystem is used to launch the target simulator of choice.

OpenFcn:

ans =

    'try
        cosimDirName = pwd;
        cd 'hdlsrc/hdl_cosim_demo1';
        vsim('tclstart',gm_hdl_cosim_demo1_mq_tcl);
        cd (cosimDirName);
        clear cosimDirName;
     catch me
        disp('Failed to launch cosimulator with "vsim"');
        disp (me.message);
        cd (cosimDirName);
        clear cosimDirName;
     end'

Simulation of the Cosimulation Model

The code associated with the callback is simulator specific and executes the necessary commands to get the HDL simulator up and running. For ModelSim/Questa an invocation of vsim is made. For Incisive/Xcelium, an invocation of nclaunch is made. For Vivado Simulator, there is no separate process or debug environment; instead a system command compiles the design into a shared-library for the cosimulation.

The following show the details for ModelSim/Questa.

vsim('tclstart',gm_hdl_cosim_demo1_mq_tcl)

The MATLAB command vsim for ModelSim launches the target simulator from within MATLAB environment with the necessary setup for cosimulation. The vsim command is invoked with the tclstart option that accepts an tcl string that configures the simulator on its launch. The file gm_hdl_cosim_demo1_mq_tcl is also automatically generated by HDL Coder along with the cosimulation model.

Contents of the Generated tclstart Command File

The generated tclstart file contains commands for configuring the launched simulator as well as comments about how various settings of Cosimulation model are generated.

hdlsrc/hdl_cosim_demo1/gm_hdl_cosim_demo1_mq_tcl:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Auto generated cosimulation 'tclstart' script 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  Source Model         : hdl_cosim_demo1
%  Generated Model      : gm_hdl_cosim_demo1
%  Cosimulation Model   : gm_hdl_cosim_demo1_mq
%
%  Source DUT           : gm_hdl_cosim_demo1_mq/MAC
%  Cosimulation DUT     : gm_hdl_cosim_demo1_mq/MAC_mq
%
%  File Location        : hdlsrc/hdl_cosim_demo1/gm_hdl_cosim_demo1_mq_tcl.m
%  Created              : 2023-08-19 13:19:14
%
%  Generated by MATLAB 23.2, HDL Coder 23.2, and Simulink 23.2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  ClockName           : clk
%  ResetName           : reset 
%  ClockEnableName     : clk_enable
%
%  ClockLowTime        : 5ns
%  ClockHighTime       : 5ns
%  ClockPeriod         : 10ns
%
%  ResetLength         : 20ns
%  ClockEnableDelay    : 10ns
%  HoldTime            : 2ns
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  ModelBaseSampleTime   : 1
%  DutBaseSampleTime     : 1
%  OverClockFactor     : 1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  Mapping of DutBaseSampleTime to ClockPeriod
%
%  N = (ClockPeriod / DutBaseSampleTime) * OverClockFactor
%  1 sec in Simulink corresponds to 10ns in the HDL Simulator(N = 10)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  ResetHighAt          : (ClockLowTime + ResetLength + HoldTime)
%  ResetRiseEdge        : 27ns
%  ResetType            : async
%  ResetAssertedLevel   : 1
%
%  ClockEnableHighAt    : (ClockLowTime + ResetLength + ClockEnableDelay + HoldTime)
%  ClockEnableRiseEdge  : 37ns
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function tclCmds = gm_hdl_cosim_demo1_mq_tcl
tclCmds = {
    'do MAC_compile.do',...% Compile the generated code
    'vsimulink -voptargs=+acc  work.MAC',...% Initiate cosimulation
    'add wave  /MAC/clk',...% Add wave commands for chip input signals
    'add wave  /MAC/reset',...
    'add wave  /MAC/clk_enable',...
    'add wave  /MAC/In1',...
    'add wave  /MAC/In2',...
    'add wave  /MAC/ce_out',...% Add wave commands for chip output signals
    'add wave  /MAC/Out1',...
    'set UserTimeUnit ns',...% Set simulation time unit
    'puts ""',...
    'puts "Ready for cosimulation..."',...
};
end

Header Comments in the tclstart File

The comments in the tclstart file specify the source model, generated model, cosimulation model, and the source and cosimulation DUT subsystems. The cosimulation DUT is placed in parallel with the source model DUT in the cosimulation model to capture any differences between the generated HDL code and the source model DUT. The cosimulation model validates the cycle-accurate and bit-true behavior of the generated code.

Visualizing HDL Signals

Wave commands are added for all top-level interface signals.

Pre-simulation Commands

In the HDL Cosimulation block, the Pre-simulation Tcl commands parameter contains force commands that drive the clock bundle (clock, clock-enable, reset). The Time to run HDL simulator before cosimulation starts parameter initiates simulation with a run time necessary to bring the chip out of reset.

Cosim block TclPreSimCommand:

ans =

    'puts "Running Simulink Cosimulation block.";
      puts "Chip Name: --> hdl_cosim_demo1/MAC";
      puts "Target language: --> vhdl";
      puts "Target directory: --> hdlsrc/hdl_cosim_demo1";
      puts [clock format [clock seconds]];
     # Clock force command;
     force /MAC/clk 0 0ns, 1 5ns -r 10ns;
     # Clock enable force command;
     force /MAC/clk_enable 0 0ns, 1 37ns;
     # Reset force command;
     force /MAC/reset 1 0ns, 0 27ns;
     
     '

Test Bench Options Affecting Cosimulation Model Generation

The next part of the tclstart script file shows all the makehdltb test bench parameters supported by HDL Coder and their initial values used in cosimulation scripts.

ClockName, ResetName, ClockEnableName
ClockLowTime, ClockHighTime, ClockPeriod
ResetLength, ClockEnableDelay, HoldTime

Model Sample Times and Mapping of DutBaseSampleTime to ClockPeriod

The next part of the comment section covers sample times in the model and how they influenced clocking of the HDL Cosimulation block in HDL Verifier.

  N = (ClockPeriod / DutBaseSampleTime) * OverClockFactor
  1 sec in Simulink corresponds to 10ns in the HDL Simulator(N = 10)

Generated tclstart Script Output

The function in gm_hdl_cosim_demo1_mq_tcl generates the necessary tcl command string (tclCmds).

If the EDAScriptGeneration option is turned on and compilation do files are generated for ModelSim as part of makehdl, then a single do command is generated. If the EDAScriptGeneration option is turned off, then explicit compilation commands are added for compiling the generated HDL code for the DUT.

Launching the Simulator and Running the Cosimulation Test Bench

Double clicking the Start Simulator block launches the simulator with the tcl commands in the generated tclstart MATLAB script. Once the simulator is launched all the generated code is compiled and the HDL Cosimulation block is ready for simulation.

To run the test bench, press the Run button. Any data value or cycle timing differences between the original Simulink design and the HDL design are flagged via assertions.

Support for Other HDL Interface Translations

Support for Complex Signals

The model hdl_cosim_demo2 contains a MAC subsystem using complex data types. The cosimulation test bench generation automatically handles translating the Simulink types to match the HDL port interface.

% Generate the HDL for a MAC design using complex data types and its
% corresponding cosimulation test bench model:
load_system('hdl_cosim_demo2');
open_system('hdl_cosim_demo2/Complex MAC');
makehdl('hdl_cosim_demo2/Complex MAC', 'targetlang', 'vh');
makehdltb('hdl_cosim_demo2/Complex MAC', 'targetlang', 'vh', 'GenerateCosimModel', 'ModelSim')

Observe the FromCosimSrc subsystems: the input complex signal is automatically broken into real and imaginary pieces before driving the HDL Cosimulation block.

Observe that the comparison section checks the results for real and imaginary parts of complex outputs separately.

Support for Vector Signals

The model hdl_cosim_demo3 contains a MAC subsystem using vectored data signals. The cosimulation test bench generation automatically handles translating the Simulink types to match the flattened HDL port interface.

% Generate the HDL for a MAC design using vectored signals and its
% corresponding cosimulation test bench model:
load_system('hdl_cosim_demo3');
open_system('hdl_cosim_demo3/Vector MAC');
makehdl('hdl_cosim_demo3/Vector MAC', 'targetlang', 've');
makehdltb('hdl_cosim_demo3/Vector MAC', 'targetlang', 've', 'GenerateCosimModel', 'ModelSim')

Observe how vectored signals are handled in the FromCosimSrc and Compare subsystems.

Support for Local Multi-Rate

The model hdl_cosim_demo4 contains a MAC subsystem with a Sum of Elements block that is configured with a Cascade implementation and requires overclocking as can be seen in the code generation messages. The cosimulation test bench generation automatically handles translating the timing interface in Simulink to that required of the HDL implementation.

% Generate the HDL for a MAC design with 5x overclocking and its
% corresponding cosimulation test bench model:
load_system('hdl_cosim_demo4');
open_system('hdl_cosim_demo4/LocalMR MAC');
makehdl('hdl_cosim_demo4/LocalMR MAC', 'targetlang', 'vh');
makehdltb('hdl_cosim_demo4/LocalMR MAC', 'targetlang', 'vh', 'GenerateCosimModel', 'ModelSim');

Note how the time-scale settings change to offset the overclocking in the multi-rate system.

The code generation messages show an overclocking that require a five times faster clock with respect to base rate of the model. This info is encapsulated in the cosimulation model as a part of the time scale setting as per the following message:

N = (ClockPeriod / DutBaseSampleTime) * OverClockFactor
1 sec in Simulink corresponds to 50ns in the HDL Simulator(N = 50)

Support for Incisive/Xcelium

The following are the concrete commands to create an Incisive/Xcelium cosimulation test bench for the first model.

% Generate the HDL and cosimulation model for Incisive/Xcelium
load_system('hdl_cosim_demo1')
makehdl('hdl_cosim_demo1/MAC', 'targetlang', 'vh')
makehdltb('hdl_cosim_demo1/MAC', 'targetlang', 'vh', 'GenerateCosimModel', 'Incisive')
type hdlsrc/hdl_cosim_demo1/gm_hdl_cosim_demo1_in_tcl

Support for Vivado Simulator

The following are the concrete commands to create a Vivado Simulator cosimulation test bench for the first model.

% Generate the HDL and cosimulation model for Vivado Simulator
load_system('hdl_cosim_demo1')
makehdl('hdl_cosim_demo1/MAC', 'targetlang', 'vh')
makehdltb('hdl_cosim_demo1/MAC', 'targetlang', 'vh', 'GenerateCosimModel', 'Vivado Simulator')
type hdlsrc/hdl_cosim_demo1/gm_hdl_cosim_demo1_vs.tcl