Code the MATLAB® function you want to export to a SystemVerilog environment. For information about coding MATLAB functions, see "Function Basics" in the MATLAB documentation.
Consider adding the compilation directive %#codegen
to
your function. This directive can help you diagnose and fix violations
that would result in errors during code generation. See Compilation Directive %#codegen (MATLAB Coder).
While you code your function, keep in mind the Limitations, which describe the various aspects of DPI component generation that you must know. These aspects include which data types are valid, what files are generated, and how the shared libraries are compiled.
In this example, the MATLAB function fun.m
takes
a single input and multiplies it by 2. The function includes the compilation
directive %#codegen
.
function y = fun(x); %#codegen y = x * 2;
The process of creating the MATLAB includes writing the code, creating the test bench, and running the test bench in an iterative process. When you are satisfied that your function does what you intend it to do, continue on to Generate SystemVerilog DPI Component.
Create a test bench to exercise the function. In this example,
the test bench applies a test vector against fun.m
and
plots the output.
function sample=fun_tb % Testbench should not require input, however you can give an output. % Define a test vector tVecIn = [1,2,3,4,5]; % Exercise fun.m and plot results to make sure function is working correctly tVecOut = arrayfun(@(in) fun(in),tVecIn); plot(tVecIn,tVecOut); grid on; % Get my sample input to use it with function dpigen. sample = tVecIn(1);
Note that a test bench should not have inputs. The test bench can load test vectors using MAT files or any other data file, so it does not require inputs.
The output of fun_tb
, sample
,
is going to be used as the function inputs argument for fun.m
during
the call to dpigen
, which is why it is a single
element. See Generate SystemVerilog DPI Component.
fun_tb
ans = 1
Next, generate the SystemVerilog DPI component. See Generate SystemVerilog DPI Component.
dpigen
FunctionUse the function dpigen
to generate the DPI
component. This function has several optional input arguments. At a minimum,
specify the MATLAB function you want to generate a component for and the function
inputs. If you also want to generate a test bench to exercise the generated
component, use the -testbench
option.
dpigen func -args input_arg -testbench test_bench_name
Define the inputs as required by the function. In this example,
sample
is a scalar value of type double.
sample = 1;
Call the DPI component generator function:
dpigen fun -args sample -testbench fun_tb
The command, issued as shown, performs the following tasks:
Generates fun_dpi.sv
– a SystemVerilog
component for the function fun.m
.The function
inputs for fun.m
are specified in
sample.
Generates fun_dpi_pkg.sv
– a SystemVerilog
package file. This file contains all the imported function
declarations.
Creates a test bench for the generated component.
For this call to dpigen
, MATLAB outputs the following messages:
### Generating DPI Wrapper fun_dpi.c ### Generating DPI Wrapper header file fun_dpi.h ### Generating SystemVerilog module package fun_dpi_pkg.sv ### Generating SystemVerilog module fun_dpi.sv ### Generating makefiles for: fun_dpi ### Compiling the DPI Component ### Generating SystemVerilog test bench fun_tb.sv ### Generating test bench simulation script for Mentor Graphics QuestaSim/Modelsim run_tb_mq.do ### Generating test bench simulation script for Cadence Incisive run_tb_incisive.sh ### Generating test bench simulation script for Cadence Xcelium run_tb_xcelium.sh ### Generating test bench simulation script for Synopsys VCS run_tb_vcs.sh ### Generating test bench simulation script for Vivado Simulator run_tb_vivado.bat
The function shown in the previous example generates the following folders and files:
Examine the generated package file. Note the declarations of the
initialize
, reset
,
terminate
, and fun
functions.
This example shows the code generated for
fun_dpi_pkg.sv
.
// File: C:\fun_example\codegen\dll\fun\fun_dpi_pkg.sv // Created: 2017-12-19 09:18:00 // Generated by MATLAB 9.5 and HDL Verifier 5.4 `timescale 1ns / 1ns package fun_dpi_pkg; // Declare imported C functions import "DPI" function chandle DPI_fun_initialize(input chandle existhandle); import "DPI" function chandle DPI_fun_reset(input chandle objhandle,input real x,output real y); import "DPI" function void DPI_fun(input chandle objhandle,input real x,output real y); import "DPI" function void DPI_fun_terminate(input chandle existhandle); endpackage : fun_dpi_pkg
Examine the generated component so that you can understand how the
dpigen
function converted MATLAB code to SystemVerilog code. For more information on what the
function includes, see Generated SystemVerilog Wrapper.
This example shows the code generated for
fun_dpi.sv
.
// File: C:\fun_example\codegen\dll\fun\fun_dpi.sv // Created: 2017-12-19 09:18:00 // Generated by MATLAB 9.5 and HDL Verifier 5.4 `timescale 1ns / 1ns import fun_dpi_pkg::*; module fun_dpi( input bit clk, input bit clk_enable, input bit reset, input real x, output real y ); chandle objhandle=null; real y_temp; initial begin objhandle=DPI_fun_initialize(objhandle); end final begin DPI_fun_terminate(objhandle); end always @(posedge clk or posedge reset) begin if(reset== 1'b1) begin objhandle=DPI_fun_reset(objhandle,x,y_temp); y<=y_temp; end else if(clk_enable) begin DPI_fun(objhandle,x,y_temp); y<=y_temp; end end endmodule
Examine the generated test bench so you can see how function
dpigen
created this test bench from the MATLAB code. For more information on the generated test bench, see Generated Test Bench.
This example shows the code generated for fun_tb.sv
.
// File: C:\fun_example\codegen\dll\fun\dpi_tb\fun_tb.sv // Created: 2017-12-19 09:18:13 // Generated by MATLAB 9.5 and HDL Verifier 5.4 `timescale 1ns / 1ns module fun_tb; real x; real y_ref; real y_read; real y; // File Handles integer fid_x; integer fid_y; // Other test bench variables bit clk; bit clk_enable; bit reset; integer fscanf_status; reg testFailure; reg tbDone; bit[63:0] real_bit64; bit[31:0] shortreal_bit64; parameter CLOCK_PERIOD= 10; parameter CLOCK_HOLD= 2; parameter RESET_LEN= 2*CLOCK_PERIOD+CLOCK_HOLD; // Initialize variables initial begin clk = 1; clk_enable = 0; testFailure = 0; tbDone = 0; reset = 1; fid_x = $fopen("dpig_in1.dat","r"); fid_y = $fopen("dpig_out1.dat","r"); // Initialize multirate counters #RESET_LEN reset = 0; end // Clock always #(CLOCK_PERIOD/2) clk = ~ clk; always@(posedge clk) begin if (reset == 0) begin #CLOCK_HOLD clk_enable <= 1; fscanf_status = $fscanf(fid_x, "%h", real_bit64); x = $bitstoreal(real_bit64); if ($feof(fid_x)) tbDone = 1; fscanf_status = $fscanf(fid_y, "%h", real_bit64); y_read = $bitstoreal(real_bit64); if ($feof(fid_y)) tbDone = 1; y_ref <= y_read; if (clk_enable == 1) begin assert ( ((y_ref - y) < 2.22045e-16) && ((y_ref - y) > -2.22045e-16) ) else begin testFailure = 1; $display("ERROR in output y_ref at time %0t :", $time); $display("Expected %e; Actual %e; Difference %e", y_ref, y, y_ref-y); end if (tbDone == 1) begin if (testFailure == 0) $display("**************TEST COMPLETED (PASSED)**************"); else $display("**************TEST COMPLETED (FAILED)**************"); $finish; end end end end // Instantiate DUT fun_dpi u_fun_dpi( .clk(clk), .clk_enable(clk_enable), .reset(reset), .x(x), .y(y) ); endmodule
Next, run the generated test bench in the HDL simulator. See Run Generated Test Bench in HDL Simulator. If you plan to port the component and optional test bench from Windows® to Linux®, see Port Generated Component and Test Bench to Linux.
This section includes instructions for running the generated test bench in one of the supported HDL simulators: Mentor Graphics® ModelSim® and Questa®Sim, Cadence Incisive®, and Synopsys® VCS®. It is possible that this code will work in other (unsupported) HDL simulators but it is not guaranteed.
Choose the workflow for your HDL simulator.
Start ModelSim or QuestaSim in GUI mode.
Change your current directory to the dpi_tb
folder
under the code generation directory in MATLAB.
Enter the following command in the shell to start your simulation:
do run_tb_mq.do
This generated script contains the name of the component and test bench, and instructions to the HDL simulator for running the test bench.
When the simulation finishes, you should see the following text displayed in your console:
**************TEST COMPLETED (PASSED)**************
This message tells you that the test bench was run against the generated component successfully.
The following wave form image from this example demonstrates that the generated test bench was successfully exercised in the HDL simulator.
Next, import your component. See Use Generated DPI Functions in SystemVerilog.
Launch Incisive®.
Start your terminal shell.
Change the current directory to dpi_tb
under
the code generation directory in MATLAB.
Enter the following command in the shell to start the simulation:
sh run_tb_ncsim.sh
This generated script contains the name of the component and test bench, and instructions to the HDL simulator for running the test bench.
When the simulation finishes, you should see the following text displayed in your console:
**************TEST COMPLETED (PASSED)**************
This message tells you that the test bench was run against the generated component successfully.
Launch VCS.
Start your terminal shell.
Change the current directory to dpi_tb
under
the code generation directory in MATLAB.
Enter the following command in your shell to start the simulation:
sh run_tb_vcs.sh
This generated script contains the name of the component and test bench, and instructions to the HDL simulator for running the test bench.
When the simulation finishes, you should see the following text displayed in your console:
**************TEST COMPLETED (PASSED)**************
This message tells you that the test bench was run against the generated component successfully.
To use the generated DPI component in a SystemVerilog test bench, first you must include the package file in your SystemVerilog environment. This will have the DPI functions available within the scope of your SystemVerilog module. Then, you must call the generated functions. When you compile the SystemVerilog code that contains the imported generated functions, use a DPI-aware SystemVerilog compiler and specify the component and package file names along with the SystemVerilog code.
The following example demonstrates adding the generated DPI component for
fun.m
to a SystemVerilog module.
Call the Initialize
function.
DPI_fun_initialize();
Call the function generated from fun.m
.
DPI_fun(x,y);
You can now modify the generated code as needed.
module test_twofun_tb; initial begin DPI_fun_initialize(); end always@(posedge clk) begin #1 DPI_fun(x,y); end
To port the component and optional test bench from a Windows operating system to a Linux operating system, follow these instructions.
Note
You must have an Embedded Coder® license for the Windows to Linux port. Although it is possible the port will work without the Embedded Coder license, that usage is not supported.
Create a MATLAB
Coder™ config
object.
Change the target HW device type to LP64
for the Linux operating
system.
cfg=coder.config('dll');
cfg.HardwareImplementation.TargetHWDeviceType='Generic->64-bit Embedded Processor (LP64)';
Run the dpigen
command using
option -config
to use the config
object
that you created in step 1. Use option -c
so that
function dpigen
generates only code. For example:
dpigen -config cfg DataTypes.m -args InputSample -c
To generate a zip file to port to Linux, change
folder to the source folder (where the buildInfo.mat
file
is generated), and execute the following commands at the command prompt:
load buildInfo buildInfo.packNGo()
To copy the file for porting, return to the top level folder. Find the zip file generated in the previous step (same name as the MATLAB function). Copy the zip file to the Linux machine.
Unzip the file using the -j
option
to extract all the files with a flattened folder structure. You can
unzip into any folder. For example:
unzip -j DataTypes.zip
Copy this generic makefile script into an empty file:
SRC=$(wildcard *.c) OBJ=$(SRC:.c=.o) SHARE_LIB_NAME=DPI_Component.so all: $(SRC) $(SHARE_LIB_NAME) @echo "### Successfully generated all binary outputs." $(SHARE_LIB_NAME): $(OBJ) gcc -shared -lm $(OBJ) -o $@ .c.o: gcc -c -fPIC -Wall -pedantic -Wno-long-long -fwrapv -O0 $< -o $@
Replace DPI_Component.so
with the
name of the shared library you want to create.
Save the script as Porting_DPIC.mk
in
the folder where the zip files were extracted.
Build the shared library with the following command:
make -f Porting_DPIC.mk all
To use the generated component with SystemVerilog, see Use Generated DPI Functions in SystemVerilog.
(Optional) Run the test bench that was automatically generated in Windows.
Copy the contents of the dpi_tb
folder
from the Windows host machine to the Linux target machine.
Run the test bench.
To run the test bench in an HDL simulator, see Run Generated Test Bench in HDL Simulator.