| Products & Services | Solutions | Academia | Support | User Community | Company |
| Download Product Updates | | | Get Pricing | | | Trial Software |
| Documentation → Simulink |
| Contents | Index |
| Learn more about Simulink |
You can integrate existing C (or C++) functions—for example, device drivers, lookup tables, and general functions and interfaces—into Simulink models by using the Legacy Code Tool. Using specifications that you supply as M-code, the tool transforms existing functions into C MEX S-functions that you can include in Simulink models. If you use the Real-Time Workshop product to generate code from a model, the Legacy Code Tool can insert an appropriate call to your C function into the generated code (for details, see Automating the Generation of Files for Fully Inlined S-Functions Using Legacy Code Tool in the Real-Time Workshop documentation) .
In comparison to using the S-Function Builder or writing an S-function, the Legacy Code Tool can be easier to use and it generates optimized code (does not generate wrapper code) often required by embedded systems. However, you should consider one of the alternate approaches for a hybrid system, such as a system that includes a plant and controller, or a system component written in a language other than C or C++. Alternative approaches are more flexible in that they support more features and programming languages.
To interact with the Legacy Code Tool, you
Use a Legacy Code Tool data structure to specify
A name for the S-function
Specifications for the existing C functions
Files and paths required for compilation
Options for the generated S-function
Use the legacy_code function to
Initialize the Legacy Code Tool data structure for a given C function
Generate an S-function for use during simulation
Compile and link the generated S-function into a dynamically loadable executable
Generate a masked S-function block for calling the generated S-function
Generate a TLC block file and, if necessary, an rtwmakecfg.m file for code generation (Real-Time Workshop product license required)
Note Before you can use legacy_code, you must ensure that a C compiler is set up for your MATLAB installation. If you need to set up a compiler, enter the command mex -setup in the MATLAB Command Window. |
The following diagram illustrates a general procedure for using the Legacy Code Tool. Example of Integrating Existing C Functions into Simulink Models with the Legacy Code Tool provides an example that uses the Legacy Code Tool to transform an existing C function into a C MEX S-function.

If you have a Real-Time Workshop product license, see Automating the Generation of Files for Fully Inlined S-Functions Using Legacy Code Tool in the Real-Time Workshop documentation for information on using the Legacy Code Tool for code generation.
Suppose you have an existing C function that outputs the value of its floating-point input multiplied by two. The function is defined in a source file named doubleIt.c, and its declaration exists in a header file named doubleIt.h as shown here.

To use the Legacy Code Tool to incorporate this C function into a Simulink model as a C MEX S-function:
Use the legacy_code function to initialize a MATLAB structure with fields that represent Legacy Code Tool properties. For example, create a Legacy Code Tool data structure named def by entering the following command at the MATLAB command prompt:
def = legacy_code('initialize')The Legacy Code Tool data structure named def displays its fields in the MATLAB Command Window as shown here:
def =
SFunctionName: ''
InitializeConditionsFcnSpec: ''
OutputFcnSpec: ''
StartFcnSpec: ''
TerminateFcnSpec: ''
HeaderFiles: {}
SourceFiles: {}
HostLibFiles: {}
TargetLibFiles: {}
IncPaths: {}
SrcPaths: {}
LibPaths: {}
SampleTime: 'inherited'
Options: [1x1 struct]Specify appropriate values for fields in the Legacy Code Tool data structure to identify properties of the existing C function. For example, specify the C function source and header filenames by entering the following commands at the MATLAB command prompt:
def.SourceFiles = {'doubleIt.c'};
def.HeaderFiles = {'doubleIt.h'};You must also specify information about the S-function that the Legacy Code Tool produces from the C code. For example, specify a name for the S-function and its output function declaration by entering:
def.SFunctionName = 'ex_sfun_doubleit'; def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';
See the legacy_code reference page for information about the various data structure fields. For more information about assigning values to fields in a structure, see Structures in the MATLAB documentation.
Use the legacy_code function to generate an S-function source file from the existing C function. At the MATLAB command prompt, type:
legacy_code('sfcn_cmex_generate', def);The Legacy Code Tool uses the information specified in def to create the S-function source file named ex_sfun_doubleit.c in the current MATLAB directory.
Make sure a C compiler is set up for your MATLAB installation. If you need to set up a compiler, enter the command mex -setup in the MATLAB Command Window.
Use the legacy_code function to compile and link the S-function source file into a dynamically loadable executable that the Simulink software can use. At the MATLAB command prompt, type:
legacy_code('compile', def);The following messages appear in the MATLAB Command Window:
### Start Compiling ex_sfun_doubleit
mex('ex_sfun_doubleit.c', 'd:\work\lct_demos\doubleIt.c',
'-Id:\work\lct\lct_demos')
### Finish Compiling ex_sfun_doubleit
### ExitOn a 32-bit Microsoft Windows system, the resulting S-function executable is named ex_sfun_doubleit.mexw32.
Use the legacy_code function to insert a masked S-Function block into a Simulink model. The Legacy Code Tool configures the block to use the C MEX S-function created in the previous step. Also, the tool masks the block such that it displays the value of its OutputFcnSpec property (see the description of the legacy_code function). For example, create a new model containing a masked S-Function block by issuing the following command at the MATLAB command prompt:
legacy_code('slblock_generate', def);The block appears in an empty model editor window as shown here:

The following Simulink model demonstrates that the C MEX S-function produced by the Legacy Code Tool behaves like the C function doubleIt. In particular, the S-Function block named ex_sfun_doubleit returns the value of its floating-point input multiplied by two.

The first step to using the Legacy Code Tool is to register one or more MATLAB structures with fields that represent properties of the existing C code and the S-function being generated. The registration process is flexible. You can choose to set up resources and initiate registration in a variety of ways, including
Placing all required header and source files in the current working directory or in a hierarchical directory structure
Generating and placing one or more S-functions in the current working directory
Having one or more registration files in the same directory
To register a Legacy Code Tool data structure:
Use the legacy_code function, specifying 'initialize' as the first argument.
lct_spec = legacy_code('initialize')The Legacy Code Tool data structure named lct_spec displays its fields in the MATLAB Command Window as shown below:
lct_spec =
SFunctionName: ''
InitializeConditionsFcnSpec: ''
OutputFcnSpec: ''
StartFcnSpec: ''
TerminateFcnSpec: ''
HeaderFiles: {}
SourceFiles: {}
HostLibFiles: {}
TargetLibFiles: {}
IncPaths: {}
SrcPaths: {}
LibPaths: {}
SampleTime: 'inherited'
Options: [1x1 struct]Define values for the data structure fields (properties) that apply to your existing C function and the S-function you intend to generate. Minimally, you must specify
Source and header files for the existing C function (SourceFiles and HeaderFiles)
A name for the S-function (SFunctionName)
At least one function specification for the S-function (InitializeConditionsFcnSpec, OutputFcnSpec, StartFcnSpec, TerminateFcnSpec)
For a complete list and descriptions of the fields in the structure, see the legacy_code function reference page.
If you define fields that specify compilation resources and you specify relative paths, the Legacy Code Tool searches for the resources relative to the following directories, in the following order:
Current working directory
C-MEX S-function directory, if different than the current working directory
Directories you specify
IncPaths for header files
SrcPaths for source files
LibPaths for target and host libraries
Directories on the MATLAB search path, excluding toolbox directories
The InitializeConditionsFcnSpec, OutputFcnSpec, StartFcnSpec, and TerminateFcnSpec fields defined in the Legacy Code Tool data structure (see the description of the legacy_code function) require string values that adhere to a specific syntax format. The required syntax format enables the Legacy Code Tool to map the return value and arguments of an existing C function to the return value, inputs, outputs, parameters, and work vectors of the S-function that the tool generates.
General syntax
return-spec = function-name(argument-spec)
For example, the following string specifies a function named doubleIt with return specification double y1 and input argument specification double u1.
def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';
For more detail on declaring function specifications, see
The return specification defines the data type and variable name for the return value of the existing C function.
return-type return-variable
| return-type | A data type listed in Supported Data Types. |
| return-variable | Token of the form y1, y2, ..., yn, where n is the total number of output arguments. |
If the function does not return a value, you can omit the return specification or specify it as void.
The following table shows valid function specification syntax for an integer return value. Use the table to identify the syntax you should use for your C function prototype.
| Return Type | C Function Prototype | Legacy Code Tool Function Specification |
|---|---|---|
| No return value | void myfunction(...) | void myfunction(...) |
| Scalar value | int = myfunction(...) | int16 y1 = myfunction(...) |
The function name that you specify must be the same as your existing C function name.
For example, consider the following C function prototype:
float doubleIt(float inVal);
In this case, the function name in the Legacy Code Tool function specification must be doubleIt.
You should not specify the name of a C macro. If you must, set the field Options.isMacro to 1 to ensure that the generated code remains safe in the event that expression folding is enabled.
The argument specification defines one or more data type and token pairs that represent the input, output, parameter, and work vector arguments of the existing C function. The function input and output arguments map to block input and output ports and parameters map to workspace parameters.
argument-type argument-token
| argument-type | A data type listed in Supported Data Types. |
| argument-token | Token of one of the following forms:
|
If the function has no arguments, you can omit the argument specification or specify it as void.
Consider the following C function prototype:
float powerIt(float inVal, int exponent);
To generate an S-function that calls the preceding function at each time step, you would set the Legacy Code Tool data structure field OutputFcnSpec to the following string:
'double y1 = powerIt(double u1, int16 p1)'
Using this function specification, the Legacy Code Tool maps the following:
| Return Value or Argument... | of C Type... | To Token... | of Data Type... |
|---|---|---|---|
| Return value | float | y1 | double |
| inVal | float | u1 | double |
| exponent | int | p1 | int16 |
The following table shows valid function specification syntax for arguments of type integer. Use the table to identify and then adapt the syntax you should use for your C function prototype.
| Argument Type | C Function Prototype | Legacy Code Tool Function Specification |
|---|---|---|
| Input Arguments | ||
| No arguments | function(void) | function(void) |
| Scalar pass by value | function(int in1) | function(int16 u1) |
| Scalar pass by pointer | function(int *in1) | function(int16 u1[1]) |
| Fixed vector | function(int in1[10]) or function(int *in1) | function(int16 u1[10]) |
| Variable vector | function(int in1[]) or function(int *in1) | function(int16 u1[]) |
| Fixed matrix | function(int in1[15]) or function(int in1[]) or function(int *in1) | function(int16 u1[3][5]) |
| Variable matrix | function(int in1[]) or function(int *in1) | function(int16 u1[][]) |
| Output Arguments | ||
| Scalar pointer | function(int *y1) | function(int16 y1[1]) |
| Fixed vector | function(int y1[10]) or function(int *y1) | function(int16 y1[10]) |
| Fixed matrix | function(int y1[15]) or function(int y1[]) or function(int *y1) | function(int16 y1[3][5]) |
| Parameter Arguments | ||
| Scalar pass by value | function(int p1) | function(int16 p1) |
| Scalar pass by pointer | function(int *p1) | function(int16 p1[1]) |
| Fixed vector | function(int p1[10]) or function(int *p1) | function(int16 p1[10]) |
| Variable vector | function(int p1[]) or function(int *p1) | function(int16 p1[]) |
| Fixed matrix | function(int p1[15]) or function(int p1[]) or function(int *p1) | function(int16 p1[3][5]) |
| Variable matrix | function(int p1[]) or function(int *p1) | function(int16 p1[][]) |
| Work Vector Arguments | ||
| Scalar pointer | function(int *work1) function(void *work1) function(void **work1) | function(int16 work1[1]) void function(void *work1) void function(void **work1) |
| Fixed vector | function(int work1[10]) or function(int *work1) | function(int16 work1[10]) |
| Fixed matrix | function(int work1[15]) or function(int work1[]) or function(int *work1) | function(int16 work1[3][5]) |
| Data Type | Supported for Input and Output? | Supported for Parameters? | Supported for Work Vectors? |
|---|---|---|---|
| Data Types Supported by Simulink | Yes | Yes | Yes |
| Simulink.Bus1 (scalar only) | Yes | N/A | Yes |
| Simulink.NumericType2 | Yes | Yes | Yes |
| Simulink.AliasType1 | Yes | Yes | Yes |
| Fixed-point3 | Yes | Yes | Yes |
| Fi objects | N/A | Yes | N/A |
| Complex numbers4 | Yes | Yes | Yes |
| 1-D array | Yes | Yes | Yes |
| 2-D array5 | Yes | Yes | Yes |
| n-D array6 | Yes | Yes | Yes |
| void * | No | No | Yes |
| void ** | No | No | Yes |
You must supply the header file that declares the structure of the bus or the header file that defines the data type with the same name as an alias. The structure of the bus declared in the header file must match the structure of the bus object (for example, the number and order of elements, data types and widths of elements, and so on). For an example, see sldemo_lct_bus.
You must supply the header file that defines the data type only if the numeric data type is also an alias.
You must declare the data as a Simulink.NumericType object (unspecified scaling is not supported). For examples, see sldemo_lct_fixpt_signals and sldemo_lct_fixpt_params.
Limited to use with Simulink built-in data types. To specify a complex data type, enclose the built-in data type within angle brackets (<>) and prepend the word complex (for example, complex<double>). For an example, see sldemo_lct_cplxgain.
The MATLAB, Simulink, and Real-Time Workshop products store two-dimensional matrix data in column-major format as a vector. If your external function code is written for row-major data, transpose the matrix data in the MATLAB environment.
For a multidimensional signal, you can use the size function to determine the number of elements in the signal. For examples, see sldemo_lct_lut and sldemo_lct_ndarray.
For more information, see Data Types Supported by Simulinkin Using Simulink.
Legacy Code Tool function specifications must adhere to the following rules:
If an argument is not scalar, you must pass the argument by reference.
The function must not change the value of input arguments.
The function's return value cannot be a pointer.
Function specifications you define for the StartFcnSpec, InitializeConditionsFcnSpec, or TerminateFcnSpec cannot access input or output arguments.
The numbering of input, output, parameter, and work vector argument tokens must start at 1 and increase monotonically.
For a given Legacy Code Tool data structure, the data type and size of input, output, parameter, and work vector arguments must be the same across function specifications for StartFcnSpec, InitializeConditionsFcnSpec, OutputFcnSpec, and TerminateFcnSpec.
You can use the size function to
Get the size of any input, output, parameter, or work vector argument and pass the size as input to the legacy function
Specify the input argument dimensions as a function of other parameter argument dimensions
Specify the output or work vector argument dimensions as a function of other input or parameter argument dimensions
Consider the following example, which demonstrates both uses of the function:
def.OutputFcnSpec= 'void foo(double p1[][], double u1[size(p1,2)], double y1[size(u1,1)], ... double work1[size(u1,1)], int32 size(u1,1))'
p1 is a two-dimensional parameter that is sized dynamically
u1 is a one-dimensional vector with the same number of elements as the second dimension of p1
y1 is a one-dimensional vector with the same number of element as u1
work1 is a one-dimensional vector with the same number of element as u1
int32 size(u1,1) returns the number of elements in the vector u1 as the fifth input argument
After you register a Legacy Code Tool data structure for an existing C function, use the legacy_code function as explained below to generate, compile, and link the S-function.
Generate a C MEX S-function based on the information defined in the structure. Call legacy_code with 'sfcn_cmex_generate' as the first argument and the name of the data structure as the second argument.
legacy_code('sfcn_cmex_generate', lct_spec);Make sure a C compiler is set up for your MATLAB installation. If you need to set up a compiler, enter the command mex -setup in the MATLAB Command Window.
Compile and link the S-function. This step assumes that a C compiler is set up for your MATLAB installation. Call legacy_code with 'compile' as the first argument and the name of the data structure as the second argument.
legacy_code('compile', lct_spec);
Informational messages similar to the following appear in the MATLAB Command Window and a dynamically loadable executable results. On a 32-bit Windows system, the Simulink software names the file ex_sfun_doubleit.mexw32.
### Start Compiling ex_sfun_doubleit mex ex_sfun_doubleit.c -Id:\work\lct\lct_demos ### Finish Compiling ex_sfun_doubleit ### Exit
As a convenience, you can generate, compile, and link the S-function in a single step by calling legacy_code with the string 'generate_for_sim'. The function also generates a TLC file for accelerated simulations, if the Options.useTlcWithAccel field of the Legacy Code Tool data structure is set to 1.
Once you have generated a dynamically loadable executable, you or others can use it in a model by adding an S-Function block that specifies the compiled S-function.
You have the option of using the Legacy Code Tool to generate a masked S-function block (graphical representation) that is configured to call a generated C MEX S-function. To generate such a block, call legacy_code with 'slblock_generate' as the first argument and the name of the Legacy Code Tool data structure as the second argument.
legacy_code('slblock_generate', lct_spec);
The tool masks the block such that it displays the value of the OutputFcnSpec field. You can then add the block to a model manually.
If you prefer that the Legacy Code Tool add the block to a model automatically, specify the name of the model as a third argument. For example:
legacy_code('slblock_generate', lct_spec, 'myModel');
If the specified model (for example, myModel.mdl) exists, legacy_code opens the model and adds the masked S-function block described by the Legacy Code Tool data structure. If the model does not exist, the function creates a new model with the specified name and adds the masked S-function block.
If you are using Simulink Accelerator mode, you can generate and force the use of TLC inlining code for the S-function generated by the Legacy Code Tool. To do this:
Generate a TLC block file for the S-function by calling the legacy_code function with 'sfcn_tlc_generate' as the first argument and the name of the Legacy Code Tool data structure as the second argument.
legacy_code('sfcn_tlc_generate', lct_spec);Consider the example in Example of Integrating Existing C Functions into Simulink Models with the Legacy Code Tool. To generate a TLC file for the model shown at the end of that example, enter the following command:
legacy_code('sfcn_tlc_generate', def);Force Accelerator mode to use the TLC file by using the ssSetOptions SimStruct function to set the S-function option SS_OPTION_USE_TLC_WITH_ACCELERATOR.
To call a legacy C++ function after initializing the Legacy Code Tool data structure, assign the value 'C++' to the Options.language field. For example,
def = legacy_code('initialize');
def.Options.language = 'C++';To verify the new setting, enter
def.Options.language
Note The Legacy Code Tool can interface with C++ functions, but not C++ objects. For a work around, see Legacy Code Tool Limitations in the Simulink documentation. |
You can have multiple registration files in the same directory and generate an S-function for each file with a single call to legacy_code. Likewise, you can use a single call to legacy_code to compile and link the S-functions and another to generate corresponding TLC block files, if appropriate.
Consider the following example, where lct_register_1, lct_register_2, and lct_register_3 each create and initialize fields of a Legacy Code Tool structure.
defs1 = lct_register_1; defs2 = lct_register_2; defs3 = lct_register_3; defs = [desfs1(:);defs2(:);defs3(:)];
You can then use the following sequence of calls to legacy_code to generate files based on the three registration files:
legacy_code('sfcn_cmex_generate', defs);
legacy_code('compile', defs);
legacy_code('sfcn_tlc_generate', defs);Alternatively, you can process each registration file separately. For example:
defs1 = lct_register1;
legacy_code('sfcn_cmex_generate', defs1);
legacy_code('compile', defs1);
legacy_code('sfcn_tlc_generate', defs1);
.
.
.
defs2 = lct_register2;
legacy_code('sfcn_cmex_generate', defs2);
legacy_code('compile', defs2);
legacy_code('sfcn_tlc_generate', defs2);
.
.
.
defs3 = lct_register3;
legacy_code('sfcn_cmex_generate', defs3);
legacy_code('compile', defs3);
legacy_code('sfcn_tlc_generate', defs3);You can deploy the S-functions that you generate with the Legacy Code Tool for use by others. To deploy an S-function for simulation use only, you need to share only the compiled dynamically loadable executable.
The Simulink product provides a set of demos that show applications of the Legacy Code Tool. To review the list of the demos, enter the following command in MATLAB Command Window and review the demos listed under the heading "Calling Legacy C and C++ Functions."
demo('simulink', 'modeling features')
Legacy Code Tool
Generates C MEX S-functions for existing functions written in C or C++. The tool does not support transformation of MATLAB or Fortran functions.
Can interface with C++ functions, but not C++ objects. One way of working around this limitation is to use the S-Function Builder to generate the shell of an S-function and then call the legacy C++ code from the S-function's mdlOutputs callback function.
Does not support simulating continuous or discrete states. This prevents you from using the mdlUpdate and mdlDerivatives callback functions. If your application requires this support, see Using the S-Function Builder to Incorporate Legacy Code in the Simulink S-function documentation.
Always sets the S-functions flag for direct feedthrough (sizes.DirFeedthrough) to true. Due to this setting and the preceding limitation, the generated S-function cannot break algebraic loops.
Supports only the continuous, but fixed in minor time step, sample time and offset option.
Supports complex numbers, but only with Simulink built-in data types.
Does not support use of function pointers as the output of the legacy function being called.
Does not support the following S-function features:
Work vectors, other then general DWork vectors
Frame-based input and output signals
Port-based sample times
Multiple block-based sample times
![]() | Templates for C S-Functions | How the Simulink Engine Interacts with C S-Functions | ![]() |

Learn more about Simulink through this collection of videos, articles, technical literature and the Getting Started with Simulink Guide.
| © 1984-2009- The MathWorks, Inc. - Site Help - Patents - Trademarks - Privacy Policy - Preventing Piracy - RSS |