Main Content

DPI Component Generation with Simulink

DPI Generation Overview

If you have a Simulink® Coder™ license, you can generate SystemVerilog DPI components using one of two methods.

Export SystemVerilog DPI Component for Subsystem

HDL Verifier™ integrates with Simulink Coder to export a subsystem as generated C code inside a SystemVerilog component with a direct programming interface (DPI). You can integrate this component into your HDL simulation as a behavioral model. The coder provides options to customize the generated SystemVerilog structure. The component generator supports test point access and tunable parameters. The coder optionally generates a SystemVerilog test bench that verifies the generated DPI component against data vectors from your Simulink subsystem. This feature is available in the Model Configuration Parameters dialog box, under Code Generation. See Generate SystemVerilog DPI Component.

Generate SystemVerilog Test Bench in HDL Coder

From HDL Coder™, you can generate a SystemVerilog DPI test bench. Use the test bench to verify your generated HDL code using C code generated from your entire Simulink model, including the DUT and data sources. To use this feature, your entire model must support C code generation with Simulink Coder. You can access this feature in HDL Workflow Advisor under HDL Code Generation > Set Testbench Options, or in the Model Configuration Parameters dialog box, under HDL Code Generation > Test Bench. Alternatively, for command-line access, set the GenerateSVDPITestBench property of makehdltb (HDL Coder). See Verify HDL Design Using SystemVerilog DPI Test Bench (HDL Coder).

Supported Simulink Data Types

Supported Simulink data types are converted to SystemVerilog data types, as shown in this table.

You can choose a bit vector, logic vector, or a compatible C type. Choose in Configuration Parameters dialog box, in the Code Generation > SystemVerilog DPI section, under SystemVerilog Ports > Ports data type.

Generated SystemVerilog Types

MATLAB®SystemVerilog
Compatible C TypeLogic VectorBit Vector
uint8byte unsignedlogic [7:0] bit [7:0]
uint16shortint unsignedlogic [15:0] bit [15:0]
uint32int unsignedlogic [31:0]bit [31:0]
uint64longint unsignedlogic [63:0]bit [63:0]
int8bytelogic signed [7:0]bit signed [7:0]
int16shortintlogic signed [15:0]bit signed [15:0]
int32intlogic signed [31:0]bit signed [31:0]
int64longintlogic signed [63:0]bit signed [63:0]
booleanbyte unsignedlogic [0:0]bit [0:0]
fixed-point

The port is sign extended to a built-in C type, such as int, int unsigned, byte, byte unsigned, etc.

logic [n-1:0]

logic signed [n-1:0]

The logic vector length (n) is equal to the wordlength. The sign is inherited from the fixed point type.

bit [n-1:0]

bit signed [n-1:0]

The bit vector length (n) is equal to the wordlength. The sign is inherited from the fixed point type.

singleshortreal
doublereal
complex

You can choose between a SystemVerilog struct data type or flattened ports for real and imaginary parts in the SystemVerilog interface. To choose between these options, in the left pane of the Configuration Parameters dialog box, select Code Generation > SystemVerilog DPI, and then set the Composite data type parameter to structure or flattened.

vectors, matrices

You can choose between SystemVerilog arrays or scalar ports. To choose between these options, in the left pane of the Configuration Parameters dialog box, select Code Generation > SystemVerilog DPI, and then select the Scalarize matrix and vector ports parameter.

For example, a two-element vector of type uint32 in Simulink generates this SystemVerilog vector port:

input logic [31:0] vecInput [0:1]

When you select Scalarize matrix and vector ports, the generated SystemVerilog includes these two ports, each of type logic [31:0]:

input logic [31:0] vecInput_0,
input logic [31:0] vecInput_1

When generating vector and array ports, the coder flattens matrices in column-major order.

nonvirtual bus

You can choose between a SystemVerilog struct type or flattened ports for separate component signals in the SystemVerilog interface. To choose between these options, in the left pane of the Configuration Parameters dialog box, select Code Generation > SystemVerilog DPI section, and set Composite data type to structure or flattened.

enumerated data typesenum

Generated SystemVerilog Wrapper

Generated Control Signals

All SystemVerilog code generated by the SystemVerilog DPI generator contains these control signals:

  • clk – synchronization clock

  • clk_enable – clock enable

  • reset – asynchronous reset

Generated SystemVerilog Module Interface

Choose between a port-list, or an interface declaration. Set this option in the Configuration Parameters, under Code Generation > SystemVerilog ports > Connection.

  • Port list - generates a SystemVerilog module with a port list in the header, representing its interface.

    For example:

    module MyMod_dpi(
        input bit clk,
        input bit clk_enable,
        input bit reset,
        /* Simulink signal name: 'in1' */
        input real in1 ,
        /* Simulink signal name: 'out1' */
        output real out1 
    );
    
    ...
    endmodule

  • Interface - generates a SystemVerilog module with an interface name in the header, and a separate declaration of the interface.

    For example:

    interface simple_if;
        bit clk;
        bit clk_enable;
        bit reset;
        /* Simulink signal name: 'in1' */
        real in1 ;
        /* Simulink signal name: 'out1' */
        real out1 ;
    endinterface
    
    module MyMod_dpi(
        simple_if vif
    );
    ...
    endmodule

Command-Line Alternative: Use the set_param (Simulink) function and set the DPIPortConnection parameter to either 'Interface' or 'Port List'.

For example:

set_param(bdroot, 'DPIPortConnection','Interface')

Generated Component Functions

SystemVerilog code generated by the SystemVerilog DPI generator contains these functions:

    // Declare imported C functions
    import "DPI" function chandle DPI_subsystemname_initialize(chandle existhandle);
    import "DPI" function chandle DPI_subsystemname_reset(input chandle objhandle,...
            input real In1, inout real Out1);
    import "DPI" function void DPI_subsystemname_output(input chandle objhandle, ...
            input real In1, inout real Out1);
    import "DPI" function void DPI_subsystemname_update(input chandle objhandle, input real In1);
    import "DPI" function void DPI_subsystemname_terminate(input chandle objhandle);

Here, subsystemname is the name of the subsystem you generated code for.

If your model also contains tunable parameters, see Parameter Tuning.

  • Initialize function — The Initialize function is called at the beginning of the simulation.

    For example, for a subsystem titled dut:

        initial begin
            objhandle = DPI_dut_initialize(objhandle);
        end
    
  • Reset function — Call the reset function when you would like to reset the simulation to a known reset state.

    For example, for a subsystem titled dut:

        initial begin
            objhandle = DPI_dut_reset(objhandle, 0, 0);
        end
    
  • Output function — At the positive edge of clock, if clk_enable is high, the output function is called first, followed by the update function.

    For example, for a subsystem titled dut:

    if(clk_enable) begin
        DPI_dut_output(objhandle, dut_In1, dut_Out1);
        DPI_dut_update(objhandle, dut_In1);
    end
    
  • Update function

    At the positive edge of clock, if clk_enable is high, the update function is called after the output function.

    For example, for a subsystem titled dut:

    if(clk_enable) begin
        DPI_dut_output(objhandle, dut_In1, dut_Out1);
        DPI_dut_update(objhandle, dut_In1);
    end
    
  • Terminate function

    Set specific conditions for early termination of simulation.

    For example, for a subsystem titled dut:

    if (condition for termination) begin
       DPI_dut_terminate(objhandle);
    end

The function details in the SystemVerilog code generated from your system vary. You can examine the generated code for specifics. For an example of the generated functions in context, see Get Started with SystemVerilog DPI Component Generation.

Parameter Tuning

You can run different simulations with various values for the parameters in your Simulink model. If your system has tunable parameters, the generated SystemVerilog code also contains a Set Parameter function for each tunable parameter.

The DPI component generator generates a Set Parameter function for each tunable parameter in the format DPI_subsystemname_setparam_tunableparametername.

In this example, the tunable gain parameter has its own setparam_gain function.

import "DPI" function void DPI_dut_setparam_gain(input chandle objhandle, input real dut_P_gain);

The generated SystemVerilog code does not call this function. Instead, the default parameters are used. To change those parameters during simulation, explicitly call the specific setparam function. For example, in the subsystem titled dut, you can change the gain during simulation to a value of 6 by inserting the following call:

DPI_dut_setparam_gain(objhandle, 6);

To make a parameter tunable, create a data object from your subsystem before generating the SystemVerilog code. See Tune Gain Parameter During Simulation.

Test Point Access Functions

This feature enables you to access internal signals of the SystemVerilog DPI component in your HDL simulator. You can designate internal signals in your model as test points and configure the SystemVerilog DPI generator to create individual or grouped access functions.

You can also enable logging on test points. With logging enabled, you can use the generated test bench to compare logged data from Simulink with values observed while running the SystemVerilog component.

See SystemVerilog DPI Component Test Point Access and Get Started with SystemVerilog DPI Component Generation.

Extra Sample Delay

Compared with the original Simulink model, the generated SystemVerilog module introduces one extra sample delay at the output. For example, in the following Simulink model, the output is one-sample delayed version of the input signal.

The generated C code preserves this behavior, and the output comprises a one-sample delayed version of the input signal. However, in the SystemVerilog wrapper file, the clock signal is used to synchronize the input and output signals:

always @(posedge clk) begin
    DPI_blk2_output(blk2_In1, blk2_Out1);
    DPI_blk2_update();
end

The output of the SystemVerilog module can only be updated on the rising edge of the clock. This requirement introduces an extra sample delay.

Multirate System Behavior

By default, Simulink subsystems have a fundamental sample time variable (FundST) that indicates when, during simulation, the subsystem produces outputs and updates its internal state. With multirate systems, you can specify different sample times for different ports. For additional information, see What Is Sample Time? (Simulink).

When a multirate subsystem generates a DPI component, the DPI component runs at a sample time that is equal to the greatest common divisor of all sample times in the subsystem.

For example, assume a subsystem has a fundamental sample time of 0.01 (that is, FundST is 0.01) and sample times ST1 and ST2 of 0.5 and 0.7, respectively.

ST1=0.5, ST2=0.7. The DPI component runs at a sample time of 0.1 (because 0.1 is the greatest common divisor of 0.5 and 0.7). To successfully acquire a signal with a sample time of 0.5 (ST1) or 0.7 (ST2), the HDL clock signal must toggle five or seven times, respectively.

When a DPI component is generated from the top level, the component executes at the fundamental sample time.

This diagram shows the relationship between the HDL input clock and sample times ST1, and ST2.

Customization

You can customize the generated SystemVerilog wrapper by modifying the template included with HDL Verifier (svdpi_grt_template.vgt). Alternatively, you can create your own custom template. Provide anchors for the generated code in your template to verify that the template generates valid SystemVerilog code.

The default SystemVerilog template, provided by HDL Verifier, is svdpi_grt_template.vgt. In this template, special clken_in and clken_out control signals are added to the SystemVerilog module interface.

You can generate SystemVerilog DPI components from multiple subsystems and connect them together in an HDL simulator. When you do so, these control signals determine the execution order of those components. They also minimize the delay between the Simulink signal and the SystemVerilog signal.

You can also specify your own template file with the following conditions:

  • The file must be on the MATLAB path and searchable.

  • The file must have a .vgt extension.

You can use these optional tokens to customize the generated code by inserting them inside comment statements throughout the template:

  • %<FileName>

  • %<PortList>

  • %<EnumDataTypeDefinitions>

  • %<ImportInitFunction>

  • %<ImportOutputFunction>

  • %<ImportUpdateFunction>

  • %<ImportSetParamFunction>

  • %<CallInitFunction>

  • %<CallUpdateFunction>

  • %<CallOutputFunction>

  • %<IsLibContinuous>

  • %<ObjHandle>

See Customize Generated SystemVerilog Code for instructions on customizing your code.

Note

The SystemVerilog DPI component generator does not generate test benches for customized components.

Limitations

  • By default, HDL Verifier converts matrices and vectors to one-dimensional arrays in SystemVerilog. For example, a 4-by-2 matrix in Simulink converts to a one-dimensional array of eight elements in SystemVerilog. To generate multiple scalar ports in the SystemVerilog interface, select Scalarize matrix and vector ports in the configuration parameters.

  • SystemVerilog DPI component generation supports the following subsystems for code generation only. There is no test bench support for these subsystems.

    • Triggered subsystem

    • Enabled subsystem

    • Subsystem with action port

For best results, avoid exporting multiple subsystems separately because it can be difficult to achieve the correct execution order. Instead, combine multiple subsystems into one and generate code from the newly created, single subsystem.

Related Topics