Call Custom HLS Code from the Generated HLS Code
From within your MATLAB® code, you can directly call external HLS code, also called custom code or legacy
code. To call external functions, use coder.ceval
. The code generator integrates your custom HLS code into the HLS
code generated from MATLAB. Integrate code when there are external libraries or optimized code
developed in HLS that you want to use with your generated code.
MATLAB to HLS workflow enables providing additional build information via coder.updateBuildInfo
to compile the generated HLS code. This includes —
Source files
Include files
Source paths
Include paths
Non-build files
Compile flags
Note
Use coder.ceval
only in MATLAB code intended for HLS code generation. coder.ceval
generates an error in uncompiled MATLAB code. To determine if a MATLAB function is executing in MATLAB, use coder.target
. If the function is executing in
MATLAB, call the MATLAB version of the external HLS function.
Following are some of the primary workflows for external code integration. For more
examples, see the coder.ceval
.
Call C++ Code
This example shows how to integrate a simple HLS C++ function with MATLAB® code by using coder.ceval
. Consider the MATLAB® function, mathAdd
:
function [added, multed] = mathAdd(in1, in2) added = in1+in2; multed = in1*in2; end
For this example, suppose that you want to implement the addition operation by using external C++ code. Consider the C++ function, adder, implemented in the file adder.cpp
:
#include "adder.h"
sc_int<10> adder(sc_int<9> a, sc_int<9> b) {
return a + b;
}
To integrate adder with your MATLAB® code, you need a header file that contains the function prototype. See the file adder.h
:
#include <systemc.h>
sc_int<10> adder(sc_int<9> a, sc_int<9> b);
Use the coder.ceval
command to call the C++ function in mathAddIntegrated.m
. Specify the header file and source/include file information by using coder.cinclude
and coder.updateBuildInfo
respectively.
function [added, multed] = mathAddIntegrated(in1, in2) %#codegen % For code generation, preinitialize the output variable data type, size, and complexity added = zeros(size(in1), 'like', in1+in2); multed = zeros(size(in1), 'like', in1*in2); if coder.target('HLS') % Generate an include in the HLS code coder.cinclude('adder.h'); % Specify the external source/include file information coder.updateBuildInfo('addSourceFiles', 'adder.cpp'); coder.updateBuildInfo('addIncludeFiles', 'adder.h'); % Use absolute paths for the source files and include files coder.updateBuildInfo('addSourcePaths', '/systemc/Documentation/R2024b/src'); coder.updateBuildInfo('addIncludePaths', '/systemc/Documentation/R2024b/inc'); % Evaluate the external C++ function added = coder.ceval('adder', in1, in2); multed = in1*in2; else % MATLAB simulation behavior [added, multed] = mathAdd(in1,in2); end end % mathAddIntegrated_tb.m a = fi(27,1,9,0,hdlfimath); b = fi(25,1,9,0,hdlfimath); out = mathAddIntegrated(a,b);
To generate HLS code, use the codegen
command as shown below.
cfg = coder.config('hdl'); cfg.Workflow = "High Level Synthesis"; cfg.TestBenchName = "mathAddIntegrated_tb"; codegen -config cfg mathAddIntegrated -report
### Begin HLS Code Generation ### Working on mathAddIntegratedClass.hpp as mathAddIntegratedClass.hpp. ### Working on mathAddIntegratedModule.hpp as mathAddIntegratedModule.hpp. ### Generating Resource Utilization Report resource_report.html. ### Generating HDL Conformance Report mathAddIntegrated_hdl_conformance_report.html. ### HDL Conformance check complete with 0 errors, 0 warnings, and 0 messages. ### Code generation successful: To view the report, open('codegen/mathAddIntegrated/hdlsrc/html/report.mldatx')
Call Library Function
This example shows how to call a library function inside MATLAB® code by using coder.ceval. Consider the MATLAB® function, mycosh where you would like to call the cmath
library function for cosh
. Specify the header file using coder.cinclude
. Since cmath
is a built-in library, there is no need to specify include paths using coder.updateBuildInfo
.
function out = mycosh(in) %#codegen out = coder.nullcopy(zeros('like', cosh(in))); if coder.target('HLS') coder.cinclude('cmath'); out = coder.ceval("std::cosh", in); else out = cosh(in); end end % mycosh_tb for i = 1:10 out = mycosh(rand(1,1)); end
To generate HLS code, use the codegen
command as shown below.
cfg = coder.config('hdl'); cfg.Workflow = "High Level Synthesis"; cfg.TestBenchName = "mycosh_tb"; codegen -config cfg mycosh -report
### Begin HLS Code Generation ### Working on mycoshClass.hpp as mycoshClass.hpp. ### Working on mycoshModule.hpp as mycoshModule.hpp. ### Generating Resource Utilization Report resource_report.html. ### Generating HDL Conformance Report mycosh_hdl_conformance_report.html. ### HDL Conformance check complete with 0 errors, 0 warnings, and 0 messages. ### Code generation successful: To view the report, open('codegen/mycosh/hdlsrc/html/report.mldatx')
Return Multiple Values from a C++ Function
The C language restricts functions from returning multiple outputs. Instead, they return
only a single, scalar value. The MATLAB functions coder.ref
, coder.rref
and coder.wref
allow you to return multiple outputs
from an external HLS function.
For example, suppose you write a MATLAB function foo that takes two inputs x and y and returns three outputs a, b, and c. In MATLAB, you call this function as follows:
[a,b,c] = foo(x,y)
If you rewrite foo as a C++ function, you cannot return three separate values a, b, and c through a return statement. Instead, create a C++ function with multiple pointer type arguments and pass the output parameters by reference. For example:
void foo(sc_int<10> x, sc_int<10> y, sc_int<10> *a, sc_int<10> *b, sc_int<10> *c)
Then you can call the C++ function from a MATLAB function by using the coder.ceval
function.
coder.ceval('foo',x,y,coder.ref(a),coder.ref(b),coder.ref(c));
If your external C function only writes to or only reads from the memory that is passed
by reference, you can use the coder.wref
or
coder.rref
functions instead of coder.ref
. Under
certain circumstances, these functions can enable further optimization of the generated code.
Note
When you use coder.wref(arg)
to pass arg
by
reference, your external C++ function must fully initialize the memory referenced by
arg
.
Pass Data by Reference
This example shows how to pass data by reference to and from an external C++ function.
Pass by reference is an important technique for C++ code integration. When you pass data by reference, the program does not need to copy data from one function to another. With pass by value, C code can return only a single scalar variable. With pass by reference, C code can return multiple variables, including arrays.
Consider the MATLAB function adderRef
. This function uses external C++ code to add two arrays. The coder.rref
and coder.wref
commands instruct the code generator to pass pointers to the arrays, rather than copy them.
function out = adderRef(a,b) %#codegen out = fi(zeros(size(a)),1,10,0,hdlfimath); if coder.target('HLS') coder.cinclude('hlsAdd.h'); coder.updateBuildInfo('addSourceFiles', 'hlsAdd.cpp'); coder.updateBuildInfo('addIncludeFiles', 'hlsAdd.h'); coder.updateBuildInfo('addSourcePaths', '/mathworks/devel/sandbox/psikakol/work/systemc/Documentation/R2024b/src'); coder.updateBuildInfo('addIncludePaths', '/mathworks/devel/sandbox/psikakol/work/systemc/Documentation/R2024b/inc'); % Pass a, b and out by reference. coder.ceval('hlsAdd', coder.rref(a), coder.rref(b), coder.wref(out), int32(numel(a))); else out = a + b; end end % adderRef_tb a = fi(1:10,1,9,0,hdlfimath); b = fi(11:20,1,9,0,hdlfimath); out = adderRef(a,b);
The C++ code, hlsAdd.cpp
, uses linear indexing to access the elements of the arrays:
#include "hlsAdd.h"
void hlsAdd(const sc_int<9>* in1, const sc_int<9>* in2, sc_int<10>* out, int numel)
{
for (int i=0; i<numel; i++) {
out[i] = in1[i] + in2[i]; }
}
To build the HLS code you must provide a header file, hlsAdd.h
, with the function signature:
#include<systemc.h>
void hlsAdd(const sc_int<9>* in1, const sc_int<9>* in2, sc_int<10>* out, int numel);
To generate the HLS code, use these codegen
commands.
cfg = coder.config('hdl'); cfg.Workflow = "High Level Synthesis"; cfg.TestBenchName = "adderRef_tb"; codegen -config cfg adderRef -report
### Begin HLS Code Generation ### Working on adderRefClass.hpp as adderRefClass.hpp. ### Working on adderRefModule.hpp as adderRefModule.hpp. ### Generating Resource Utilization Report resource_report.html. ### Generating HDL Conformance Report adderRef_hdl_conformance_report.html. ### HDL Conformance check complete with 0 errors, 0 warnings, and 0 messages. ### Code generation successful: To view the report, open('codegen/adderRef/hdlsrc/html/report.mldatx')