Products & Services Solutions Academia Support User Community Company

Learn more about Real-Time Workshop Embedded Coder   

Creating Function Replacement Tables

Overview of Function Replacement Table Creation

To create a TFL table containing replacement information for supported functions and operators, you perform the following steps:

  1. Create a table definition M-file containing a function definition in the following general form:

    function hTable = tfl_table_name()
    %TFL_TABLE_NAME - Describe entries for a Target Function Library table.
    .
    .
    .

    For example, the following sample function definition is from the Target Function Libraries Quick-Start Example:

    function hTable = tfl_table_sinfcn()
    %TFL_TABLE_SINFCN - Describe function entries for a Target Function Library table.
    .
    .
    .
  2. Within the function body, instantiate a TFL table with a command such as the following:

    hTable = RTW.TflTable;
  3. Use the TFL table creation functions (listed in the table below) to add table entries representing your replacements for supported functions and operators. For each individual function or operator entry, you issue one or more function calls to

    1. Instantiate a table entry.

    2. Add conceptual arguments, implementation arguments, and other attributes to the entry.

    3. Add the entry to the table.

    Creating Table Entries describes this procedure in detail, including two methods for creating function entries. The following sample function entry is from the Target Function Libraries Quick-Start Example:

    % Create entry for double data type sine function replacement
    hTable.registerCFunctionEntry(100, 1, 'sin', 'double', 'sin_dbl', ...
                                                 'double', '<sin_dbl.h>','','');
  4. Save the table definition M-file using the name of the table definition function, for example, tfl_table_sinfcn.m.

After you have created a table definition M-file, you can do the following:

After you register a TFL with the Simulink software, it appears in the Simulink GUI and can be selected for use in building models.

The following table provides a functional grouping of the TFL table creation functions.

FunctionDescription
Table entry creation
addEntryAdd table entry to collection of table entries registered in TFL table
copyConceptualArgsToImplementationCopy conceptual argument specifications to matching implementation arguments for TFL table entry
createAndAddConceptualArgCreate conceptual argument from specified properties and add to conceptual arguments for TFL table entry
createAndAddImplementationArgCreate implementation argument from specified properties and add to implementation arguments for TFL table entry
createAndSetCImplementationReturnCreate implementation return argument from specified properties and add to implementation for TFL table entry
setTflCFunctionEntryParametersSet specified parameters for function entry in TFL table
setTflCOperationEntryParametersSet specified parameters for operator entry in TFL table
Alternative method for conceptual argument creation
addConceptualArgAdd conceptual argument to array of conceptual arguments for TFL table entry
getTflArgFromStringCreate TFL argument based on specified name and built-in data type
Alternative method for function entry creation
registerCFunctionEntryCreate TFL function entry based on specified parameters and register in TFL table
registerCPromotableMacroEntryCreate TFL promotable macro entry based on specified parameters and register in TFL table (for abs function replacement only)
Build information
addAdditionalHeaderFileAdd additional header file to array of additional header files for TFL table entry
addAdditionalIncludePathAdd additional include path to array of additional include paths for TFL table entry
addAdditionalLinkObjAdd additional link object to array of additional link objects for TFL table entry
addAdditionalLinkObjPathAdd additional link object path to array of additional link object paths for TFL table entry
addAdditionalSourceFileAdd additional source file to array of additional source files for TFL table entry
addAdditionalSourcePathAdd additional source path to array of additional source paths for TFL table entry
Reserved identifiers
setReservedIdentifiersRegister specified reserved identifiers to be associated with TFL table

Creating Table Entries

Overview of Table Entry Creation

You define TFL table entries by issuing TFL table creation function calls inside a table definition M-file. The function calls must follow a function declaration and a TFL table instantiation, such as the following:

function hTable = tfl_table_sinfcn()
%TFL_TABLE_SINFCN - Describe function entries for a Target Function Library table.

hTable = RTW.TflTable;

Within the function body, you use the TFL table creation functions to add table entries representing your replacements for supported functions and operators. For each individual function or operator entry, you issue one or more function calls to

  1. Instantiate a table entry.

  2. Add conceptual arguments, implementation arguments, and other attributes to the entry.

  3. Add the entry to the table.

The general method for creating function and operator entries, described in General Method for Creating Function and Operator Entries, uses the functions shown in the following table.

FunctionDescription
Table entry creation
addEntryAdd table entry to collection of table entries registered in TFL table
copyConceptualArgsToImplementationCopy conceptual argument specifications to matching implementation arguments for TFL table entry
createAndAddConceptualArgCreate conceptual argument from specified properties and add to conceptual arguments for TFL table entry
createAndAddImplementationArgCreate implementation argument from specified properties and add to implementation arguments for TFL table entry
createAndSetCImplementationReturnCreate implementation return argument from specified properties and add to implementation for TFL table entry
setTflCFunctionEntryParametersSet specified parameters for function entry in TFL table
setTflCOperationEntryParametersSet specified parameters for operator entry in TFL table
Alternative method for conceptual argument creation
addConceptualArgAdd conceptual argument to array of conceptual arguments for TFL table entry
getTflArgFromStringCreate TFL argument based on specified name and built-in data type

A simpler alternative creation method is available for function entries, with the constraints that input types must be uniform and implementation arguments must use default Simulink naming. The alternative method uses the following functions and is described in Alternative Method for Creating Function Entries.

FunctionDescription
Alternative method for function entry creation
registerCFunctionEntryCreate TFL function entry based on specified parameters and register in TFL table
registerCPromotableMacroEntryCreate TFL promotable macro entry based on specified parameters and register in TFL table (for abs function replacement only)

General Method for Creating Function and Operator Entries

The general workflow for creating TFL table entries applies equally to function and operator replacements, and involves the following steps.

  1. Within the function body of your table definition M-file, instantiate a TFL table entry for a function or operator, using one of the following lines of code:

    fcn_entry = RTW.TflCFunctionEntry;Supports function replacement
    op_entry = RTW.TflCOperationEntry;Supports operator replacement
    op_entry = RTW.TflCOperationEntryGenerator;Provides relative scaling factor (RSF) fixed-point parameters, described in Mapping Fixed-Point Operators to Target-Specific Implementations, that are not available in RTW.TflCOperationEntry
    op_entry = RTW.TflCOperationEntryGenerator_NetSlope;Provides net slope parameters, described in Mapping Fixed-Point Operators to Target-Specific Implementations, that are not available in RTW.TflCOperationEntry
    op_entry = RTW.TflBlasEntryGenerator;Supports replacement of nonscalar operators with MathWorks BLAS functions, described in Mapping Nonscalar Operators to Target-Specific Implementations
    op_entry = RTW.TflCBlasEntryGenerator;Supports replacement of nonscalar operators with ANSI/ISO C BLAS functions, described in Mapping Nonscalar Operators to Target-Specific Implementations

  2. Set the table entry parameters, which are passed in parameter/value pairs to one of the following functions:

    For example:

    setTflCFunctionEntryParameters(fcn_entry, ...
                                   'Key',                 'sin', ...
                                   'Priority',            30, ...
                                   'ImplementationName',  'mySin', ...
                                   'ImplementationHeaderFile', 'basicMath.h',...
                                   'ImplementationSourceFile', 'basicMath.c');

    For detailed descriptions of the settable function and operator attributes, see the setTflCFunctionEntryParameters and setTflCOperationEntryParameters reference pages in the Real-Time Workshop Embedded Coder documentation.

  3. Create and add conceptual arguments to the function or operator entry. Output arguments must precede input arguments, and the function signature (including argument naming, order, and attributes) must fulfill the signature match sought by function or operator callers. Conceptual argument names follow the default Simulink naming convention:

    • For return argument, y1

    • For input argument names, u1, u2, ..., un

    You can create and add conceptual arguments in either of two ways:

    • Call the createAndAddConceptualArg function to create the argument and add it to the table entry. For example:

      createAndAddConceptualArg(fcn_entry, 'RTW.TflArgNumeric', ...
                                'Name',         'y1',... 
                                'IOType',       'RTW_IO_OUTPUT',...
                                'DataTypeMode', 'double');
    • Call the getTflArgFromString function to create an argument based on a built-in data type, and then call the addConceptualArg function to add the argument to the table entry.

        Note   If you use getTflArgFromString, the IOType property of the created argument defaults to 'RTW_IO_INPUT', indicating an input argument. For an output argument, you must change the IOType value to 'RTW_IO_OUTPUT' by directly assigning the argument property, as shown in the following example.

      arg = getTflArgFromString(hTable, 'y1', 'int16');
      arg.IOType = 'RTW_IO_OUTPUT';
      addConceptualArg(op_entry, arg);

  4. Create and add implementation arguments, representing the signature of your implementation function, to the function or operator entry. The implementation argument order must match the conceptual argument order. You can create and add implementation arguments in either of two ways:

    • Call the copyConceptualArgsToImplementation function to populate all of the implementation arguments as copies of the previously created conceptual arguments. For example:

      copyConceptualArgsToImplementation(fcn_entry);
    • Call the createAndSetCImplementationReturn function to create the implementation return argument and add it to the table entry, and then call the createAndAddImplementationArg function to individually create and add each of your implementation arguments. This method allows you to vary argument attributes, including argument naming, as long as conceptual argument order is maintained. For example:

      createAndSetCImplementationReturn(op_entry, 'RTW.TflArgNumeric', ...
                                        'Name',       'y1', ...
                                        'IOType',     'RTW_IO_OUTPUT', ...
                                        'IsSigned',   true, ...
                                        'WordLength', 32, ...
                                        'FractionLength', 0);
                                        
      createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                                    'Name',       'u1', ...
                                    'IOType',     'RTW_IO_INPUT',...
                                    'IsSigned',   true,...
                                    'WordLength', 32, ...
                                    'FractionLength', 0 );
                                     
      createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                                    'Name',       'u2', ...
                                    'IOType',     'RTW_IO_INPUT',...
                                    'IsSigned',   true,...
                                    'WordLength', 32, ...
                                    'FractionLength', 0 );

  5. Add the function or operator entry to the TFL table using the addEntry function. For example:

    addEntry(hTable, fcn_entry);

For complete examples of function entries and operator entries created using the general method, see Example: Mapping Math Functions to Target-Specific Implementations and Example: Mapping Scalar Operators to Target-Specific Implementations. For syntax examples, see the examples in the TFL table creation function reference pages in the Real-Time Workshop Embedded Coder documentation.

Alternative Method for Creating Function Entries

You can use a simpler alternative method for creating TFL function entries if your function implementation meets the following criteria:

The alternative method for creating function entries involves a single step. Call one of the following functions to create and add conceptual and implementation arguments and register the function entry:

For example:

hTable = RTW.TflTable;

registerCFunctionEntry(hTable, 100, 1, 'sqrt', 'double', ...
                       'sqrt', 'double', '<math.h>', '', '');

For detailed descriptions of the function arguments, see the registerCFunctionEntry and registerCPromotableMacroEntry reference pages in the Real-Time Workshop Embedded Coder documentation.

Example: Mapping Math Functions to Target-Specific Implementations

The Real-Time Workshop Embedded Coder software supports the following math functions for replacement with custom library functions using target function library (TFL) tables.

Math FunctionSimulink SupportStateflow SupportEmbedded MATLAB and Embedded MATLAB Coder Support
abs
  • Floating-point

  • Integer

  • Floating-point

  • Integer

Floating-point
acosFloating-pointFloating-pointFloating-point
acoshFloating-pointNot available (NA)Not replaceable (NR)
asinFloating-pointFloating-pointFloating-point
asinhFloating-pointNANR
atanFloating-pointFloating-pointFloating-point
atan2Floating-pointFloating-pointFloating-point
atanhFloating-pointNANR
ceilFloating-pointFloating-pointFloating-point
cosFloating-pointFloating-pointFloating-point
coshFloating-pointFloating-pointFloating-point
exactrSqrt
  • Floating-point

  • Integer

NANA
expFloating-pointFloating-pointFloating-point
fixFloating-pointNANR
floorFloating-pointFloating-pointFloating-point
hypotFloating-pointNANR
ldexpFloating-pointFloating-pointFloating-point
lnFloating-pointNANA
logFloating-pointFloating-pointFloating-point
log10Floating-pointFloating-pointFloating-point
max
  • Floating-point

  • Integer

  • Floating-point

  • Integer

  • Floating-point

  • Integer

min
  • Floating-point

  • Integer

  • Floating-point

  • Integer

  • Floating-point

  • Integer

mod/fmod
  • Floating-point (mod)

  • Integer (mod)

Floating-point (fmod)NR
powFloating-pointFloating-pointFloating-point
remFloating-pointNAFloating-point
roundFloating-pointNANR
rSqrt
  • Floating-point

  • Integer

NANA
saturate
  • Floating-point

  • Integer

NANA
sign
  • Floating-point

  • Integer

NANR
sinFloating-pointFloating-pointFloating-point
sinhFloating-pointFloating-pointFloating-point
sqrtFloating-pointFloating-pointFloating-point
tanFloating-pointFloating-pointFloating-point
tanhFloating-pointFloating-pointFloating-point

The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry for the sin function.

  1. Create and save the following TFL table definition file, tfl_table_sinfcn2.m. This file defines a TFL table containing a function replacement entry for the sin function.

    The function body sets selected sine function entry parameters, creates the y1 and u1 conceptual arguments individually, and then copies the conceptual arguments to the implementation arguments. Finally the function entry is added to the table.

    function hTable = tfl_table_sinfcn2()
    %TFL_TABLE_SINFCN2 - Describe function entry for a Target Function Library table.
    
    hTable = RTW.TflTable;
    
    % Create entry for sine function replacement
    fcn_entry = RTW.TflCFunctionEntry;
    setTflCFunctionEntryParameters(fcn_entry, ...
                                   'Key',                 'sin', ...
                                   'Priority',            30, ...
                                   'ImplementationName',  'mySin', ...
                                   'ImplementationHeaderFile', 'basicMath.h',...
                                   'ImplementationSourceFile', 'basicMath.c');
    
    createAndAddConceptualArg(fcn_entry, 'RTW.TflArgNumeric', ...
                              'Name',         'y1',... 
                              'IOType',       'RTW_IO_OUTPUT',...
                              'DataTypeMode', 'double');
    
    createAndAddConceptualArg(fcn_entry, 'RTW.TflArgNumeric', ...
                              'Name',         'u1', ...
                              'IOType',       'RTW_IO_INPUT',...
                              'DataTypeMode', 'double');
    
    copyConceptualArgsToImplementation(fcn_entry);
    
    addEntry(hTable, fcn_entry);
  2. Optionally, perform a quick check of the validity of the function entry by invoking the table definition file at the MATLAB command line (>> tbl = tfl_table_sinfcn2) and by viewing it in the TFL Viewer (>> RTW.viewTfl(tfl_table_sinfcn2)). For more information about validating TFL tables, see Examining and Validating Function Replacement Tables.

  3. Create and save the following TFL registration file, which references the tfl_table_sinfcn2 table.

    The file specifies that the TFL to be registered is named 'Sine Function Example 2' and consists of tfl_table_sinfcn2, with the default ANSI[1] math library as the base TFL table.

    function sl_customization(cm)
    % sl_customization function to register a target function library (TFL)
    
      % Register the TFL defined in local function locTflRegFcn
      cm.registerTargetInfo(@locTflRegFcn);
    
    end % End of SL_CUSTOMIZATION
    
    
    % Local function to define a TFL containing tfl_table_sinfcn2
    function thisTfl = locTflRegFcn
    
      % Instantiate a TFL registry entry
      thisTfl = RTW.TflRegistry;
    
      % Define the TFL properties
      thisTfl.Name = 'Sine Function Example 2'; 
      thisTfl.Description = 'Demonstration of sine function replacement';
      thisTfl.TableList = {'tfl_table_sinfcn2'};
      thisTfl.BaseTfl = 'C89/C90 (ANSI)';
      thisTfl.TargetHWDeviceType = {'*'};
    
    end % End of LOCTFLREGFCN

    Place this sl_customization.m file in the MATLAB search path or in the current working directory, so that the TFL is registered at each Simulink startup.

      Tip   To refresh Simulink customizations within the current MATLAB session, use the command sl_refresh_customizations. (To refresh Embedded MATLAB Coder TFL registration information within a MATLAB session, use the command RTW.TargetRegistry.getInstance('reset');.)

    For more information about registering TFLs with Simulink or Embedded MATLAB Coder software, see Registering Target Function Libraries.

  4. With your sl_customization.m file in the MATLAB search path or in the current working directory, open an ERT-based Simulink model and navigate to the Interface pane of the Configuration Parameters dialog box. Verify that the Target function library option lists the TFL name you specified and select it.

      Note   If you hover over the selected library with the cursor, a tool tip appears. This tip provides information derived from your TFL registration file, such as the TFL description and the list of tables it contains.

    Optionally, you can relaunch the TFL Viewer, using the MATLAB command RTW.viewTFL with no argument, to examine all registered TFLs, including Sine Function Example 2.

  5. Create an ERT-based model with a Trigonometric Function block set to the sine function, such as the following:

    Make sure that the TFL you registered, Sine Function Example 2, is selected for this model.

  6. Go to the Real-Time Workshop > Report pane of the Configuration Parameters dialog box and select the options Create code generation report and Model-to-code. Then go to the Real-Time Workshop pane, select the Generate code only option, and generate code for the model.

  7. Go to the model window and use model-to-code highlighting to trace the code generated using your TFL entry. For example, right-click the Trigonometric Function block and select Real-Time Workshop > Navigate to Code. This selection highlights the sin function code within the model step function in sinefcn.c. In this case, sin has been replaced with mySin in the generated code.

Example: Mapping the memcpy Function to a Target-Specific Implementation

The Real-Time Workshop Embedded Coder software supports the memcpy function for replacement with custom library functions using target function library (TFL) tables.

The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry for the memcpy function.

  1. Create and save the following TFL table definition file, tfl_table_memcpy.m. This file defines a TFL table containing a function replacement entry for the memcpy function.

    The function body sets selected memcpy function entry parameters, creates the y1, u1, u2, and u3 conceptual arguments individually, adds each argument to the conceptual arguments array for the function, and then copies the conceptual arguments to the implementation arguments. Finally the function entry is added to the table.

    function hTable = tfl_table_memcpy()
    %TFL_TABLE_MEMCPY - Describe memcpy function entry for a TFL table.
    
    hTable = RTW.TflTable;
    
    % Create function replacement entry for void* memcpy(void*, void*, size_t)
    fcn_entry = RTW.TflCFunctionEntry;
    setTflCFunctionEntryParameters(fcn_entry, ...
                                   'Key',                 'memcpy', ...
                                   'Priority',            90, ...
                                   'ImplementationName',  'memcpy_int', ...
                                   'ImplementationHeaderFile', 'memcpy_int.h',...
                                   'SideEffects',         true);
    % Set SideEffects to 'true' for function returning void to prevent it being
    % optimized away
    
    arg = getTflArgFromString(hTable, 'y1', 'void*');
    arg.IOType = 'RTW_IO_OUTPUT';
    addConceptualArg(fcn_entry, arg);
    
    arg = getTflArgFromString(hTable, 'u1', 'void*');
    addConceptualArg(fcn_entry, arg);
    
    arg = getTflArgFromString(hTable, 'u2', 'void*');
    addConceptualArg(fcn_entry, arg);
    
    arg = getTflArgFromString(hTable, 'u3', 'size_t');
    addConceptualArg(fcn_entry, arg);
    
    copyConceptualArgsToImplementation(fcn_entry);
    addEntry(hTable, fcn_entry);
  2. Optionally, perform a quick check of the validity of the memcpy entry by invoking the table definition file at the MATLAB command line (>> tbl = tfl_table_memcpy) and by viewing it in the TFL Viewer (>> RTW.viewTfl(tfl_table_memcpy)). For more information about validating TFL tables, see Examining and Validating Function Replacement Tables.

  3. Create and save the following TFL registration file, which references the tfl_table_memcpy table.

    The file specifies that the TFL to be registered is named 'Memcpy Function Example' and consists of tfl_table_memcpy, with the default ANSI[2] math library as the base TFL table.

    function sl_customization(cm)
    % sl_customization function to register a target function library (TFL)
    
      % Register the TFL defined in local function locTflRegFcn
      cm.registerTargetInfo(@locTflRegFcn);
    
    end % End of SL_CUSTOMIZATION
    
    
    % Local function to define a TFL containing tfl_table_memcpy
    function thisTfl = locTflRegFcn
    
      % Instantiate a TFL registry entry
      thisTfl = RTW.TflRegistry;
    
      % Define the TFL properties
      thisTfl.Name = 'Memcpy Function Example'; 
      thisTfl.Description = 'Demonstration of memcpy function replacement';
      thisTfl.TableList = {'tfl_table_memcpy'};
      thisTfl.BaseTfl = 'C89/C90 (ANSI)';
      thisTfl.TargetHWDeviceType = {'*'};
    
    end % End of LOCTFLREGFCN

    Place this sl_customization.m file in the MATLAB search path or in the current working directory, so that the TFL is registered at each Simulink startup.

      Tip   To refresh Simulink customizations within the current MATLAB session, use the command sl_refresh_customizations. (To refresh Embedded MATLAB Coder TFL registration information within a MATLAB session, use the command RTW.TargetRegistry.getInstance('reset');.)

    For more information about registering TFLs with Simulink or Embedded MATLAB Coder software, see Registering Target Function Libraries.

  4. With your sl_customization.m file in the MATLAB search path or in the current working directory, open an ERT-based Simulink model and navigate to the Interface pane of the Configuration Parameters dialog box. Verify that the Target function library option lists the TFL name you specified and select it.

      Note   If you hover over the selected library with the cursor, a tool tip appears. This tip provides information derived from your TFL registration file, such as the TFL description and the list of tables it contains.

    Optionally, you can relaunch the TFL Viewer, using the MATLAB command RTW.viewTFL with no argument, to examine all registered TFLs, including Memcpy Function Example.

  5. Create an ERT-based model that uses memcpy for vector assignments. For example,

    1. Use In, Out, and Mux blocks to create the following model. (Alternatively, you can open rtwdemo_tflmath/Subsystem1 and copy the subsystem contents to a new model.)

    2. Select the diagram and use Edit > Subsystem to make it a subsystem.

    3. Select an ERT-based system target file on the Real-Time Workshop pane of the Configuration Parameters dialog box, and select the TFL you registered, Memcpy Function Example, on the Interface pane. You should also select a fixed-step solver on the Solver pane. Leave the memcpy options on the Optimization pane at their default settings, that is, Use memcpy for vector assignment selected, and Memcpy threshold (bytes) at 64. Apply the changes.

    4. Open Model Explorer and configure the Signal Attributes for the In1, In2, and In3 source blocks. For each, set Port dimensions to [1,100], and set Data type to int32. Apply the changes. Save the model. In this example, the model is saved to the name memcpyfcn.mdl.

  6. Go to the Real-Time Workshop > Report pane of the Configuration Parameters dialog box and select the Create code generation report. Then go to the Real-Time Workshop pane, select the Generate code only option, and generate code for the model. When code generation completes, the HTML code generation report is displayed.

  7. In the HTML code generation report, click on the model.c section (for example, memcpyfcn.c) and inspect the model step function to confirm that memcpy has been replaced with memcpy_int in the generated code.

Example: Mapping Nonfinite Support Utility Functions to Target-Specific Implementations

The Real-Time Workshop Embedded Coder software supports the following nonfinite support utility functions for replacement with custom library functions using target function library (TFL) tables.

GetInf
GetMinusInf
GetNaN

The following example uses the method described in General Method for Creating Function and Operator Entries to create TFL table entries for the nonfinite functions.

  1. Create and save the following TFL table definition file, tfl_table_nonfinite.m. This file defines a TFL table containing function replacement entries for the nonfinite functions.

    For each nonfinite function, the function body uses the local function locAddFcnEnt to create entries for single and double replacement. For each entry, the local function sets selected function entry parameters, creates the y1 and u1 conceptual arguments individually, and then copies the conceptual arguments to the implementation arguments. Finally the function entry is added to the table.

    function hTable = tfl_table_nonfinite()
    %TFL_TABLE_NONFINITE - Describe function entries for a TFL table.
    
    hTable = RTW.TflTable;
    
    %% Create entries for nonfinite support utility functions
    %locAddFcnEnt(hTable, key,          implName,        out,      in1,    hdr )
    locAddFcnEnt(hTable, 'getNaN',      'getNaN',       'double', 'void', 'nonfin.h');
    locAddFcnEnt(hTable, 'getNaN',      'getNaNF',      'single', 'void', 'nonfin.h');
    locAddFcnEnt(hTable, 'getInf',      'getInf',       'double', 'void', 'nonfin.h');
    locAddFcnEnt(hTable, 'getInf',      'getInfF',      'single', 'void', 'nonfin.h');
    locAddFcnEnt(hTable, 'getMinusInf', 'getMinusInf',  'double', 'void', 'nonfin.h');
    locAddFcnEnt(hTable, 'getMinusInf', 'getMinusInfF', 'single', 'void', 'nonfin.h');
    
    %% Local Function
    function locAddFcnEnt(hTable, key, implName, out, in1, hdr)
      if isempty(hTable)
        return;
      end
      
      fcn_entry = RTW.TflCFunctionEntry;
      setTflCFunctionEntryParameters(fcn_entry, ...
                                     'Key', key, ...
                                     'Priority', 90, ...
                                     'ImplementationName', implName, ...
                                     'ImplementationHeaderFile', hdr);
    
      arg = getTflArgFromString(hTable, 'y1', out);
      arg.IOType = 'RTW_IO_OUTPUT';
      addConceptualArg(fcn_entry, arg);
    
      arg = getTflArgFromString(hTable, 'u1', in1);
      addConceptualArg(fcn_entry, arg);
    
      copyConceptualArgsToImplementation(fcn_entry);
    
      addEntry(hTable, fcn_entry);
    
      %EOF
  2. Optionally, perform a quick check of the validity of the nonfinite function entries by invoking the table definition file at the MATLAB command line (>> tbl = tfl_table_nonfinite) and by viewing it in the TFL Viewer (>> RTW.viewTfl(tfl_table_nonfinite)). For more information about validating TFL tables, see Examining and Validating Function Replacement Tables.

  3. Create and save the following TFL registration file, which references the tfl_table_nonfinite table.

    The file specifies that the TFL to be registered is named 'Nonfinite Functions Example' and consists of tfl_table_nonfinite, with the default ANSI[3] math library as the base TFL table.

    function sl_customization(cm)
    % sl_customization function to register a target function library (TFL)
    
      % Register the TFL defined in local function locTflRegFcn
      cm.registerTargetInfo(@locTflRegFcn);
    
    end % End of SL_CUSTOMIZATION
    
    
    % Local function to define a TFL containing tfl_table_nonfinite
    function thisTfl = locTflRegFcn
    
      % Instantiate a TFL registry entry
      thisTfl = RTW.TflRegistry;
    
      % Define the TFL properties
      thisTfl.Name = 'Nonfinite Functions Example'; 
      thisTfl.Description = 'Demonstration of nonfinite functions replacement';
      thisTfl.TableList = {'tfl_table_nonfinite'};
      thisTfl.BaseTfl = 'C89/C90 (ANSI)';
      thisTfl.TargetHWDeviceType = {'*'};
    
    end % End of LOCTFLREGFCN

    Place this sl_customization.m file in the MATLAB search path or in the current working directory, so that the TFL is registered at each Simulink startup.

      Tip   To refresh Simulink customizations within the current MATLAB session, use the command sl_refresh_customizations. (To refresh Embedded MATLAB Coder TFL registration information within a MATLAB session, use the command RTW.TargetRegistry.getInstance('reset');.)

    For more information about registering TFLs with Simulink or Embedded MATLAB Coder software, see Registering Target Function Libraries.

  4. With your sl_customization.m file in the MATLAB search path or in the current working directory, open an ERT-based Simulink model and navigate to the Interface pane of the Configuration Parameters dialog box. Verify that the Target function library option lists the TFL name you specified and select it.

      Note   If you hover over the selected library with the cursor, a tool tip appears. This tip provides information derived from your TFL registration file, such as the TFL description and the list of tables it contains.

    Optionally, you can relaunch the TFL Viewer, using the MATLAB command RTW.viewTFL with no argument, to examine all registered TFLs, including Nonfinite Functions Example.

  5. Create an ERT-based model with a Math Function block set to the rem function, such as the following:

    Open Model Explorer. Select the Support: non-finite numbers parameter on the Real-Time Workshop > Interface pane of the Configuration Parameters dialog box and configure the Signal Attributes for the In1 and Constant source blocks. For each source block, set Data type to double. Apply the changes. Save the model. In this example, the model is saved to the name nonfinitefcns.mdl.

    Make sure that the TFL you registered, Nonfinite Functions Example, is selected for this model.

  6. Go to the Real-Time Workshop > Report pane of the Configuration Parameters dialog box and select the option Create code generation report. Then go to the Real-Time Workshop pane, select the Generate code only option, and generate code for the model.

  7. In the HTML code generation report, click on the rtnonfinite.c link and inspect the rt_InitInfAndNaN function to confirm that your replacements for nonfinite support functions are present in the generated code.

Example: Mapping Scalar Operators to Target-Specific Implementations

The Real-Time Workshop Embedded Coder software supports the following scalar operators for replacement with custom library functions using target function library (TFL) tables:

The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry for the + (addition) operator.

  1. Create and save the following TFL table definition file, tfl_table_add_uint8.m. This file defines a TFL table containing an operator replacement entry for the + (addition) operator.

    The function body sets selected addition operator entry parameters, creates the y1, u1, and u2 conceptual arguments individually, and then copies the conceptual arguments to the implementation arguments. Finally, the operator entry is added to the table.

    function hTable = tfl_table_add_uint8
    %TFL_TABLE_ADD_UINT8 - Describe operator entry for a Target Function Library table.
    
    hTable = RTW.TflTable;
    
    % Create entry for addition of built-in uint8 data type
    % Saturation on, Rounding no preference
    op_entry = RTW.TflCOperationEntry;
    setTflCOperationEntryParameters(op_entry, ...
                        'Key',                      'RTW_OP_ADD', ...
                        'Priority',                 90, ...
                        'SaturationMode',           'RTW_SATURATE_ON_OVERFLOW', ...
                        'RoundingMode',             'RTW_ROUND_UNSPECIFIED', ...
                        'ImplementationName',       'u8_add_u8_u8', ...
                        'ImplementationHeaderFile', 'u8_add_u8_u8.h', ...
                        'ImplementationSourceFile', 'u8_add_u8_u8.c' );
    
    arg = getTflArgFromString(hTable, 'y1', 'uint8');
    arg.IOType = 'RTW_IO_OUTPUT';
    addConceptualArg(op_entry, arg);
    
    arg = getTflArgFromString(hTable, 'u1', 'uint8');
    addConceptualArg(op_entry, arg );
    
    arg = getTflArgFromString(hTable, 'u2', 'uint8');
    addConceptualArg(op_entry, arg );
    
    copyConceptualArgsToImplementation(op_entry);
    
    addEntry(hTable, op_entry);
  2. Optionally, perform a quick check of the validity of the operator entry by invoking the table definition file at the MATLAB command line (>> tbl = tfl_table_add_uint8) and by viewing it in the TFL Viewer (>> RTW.viewTfl(tfl_table_add_uint8)).

    For more information about validating TFL tables, see Examining and Validating Function Replacement Tables.

  3. Create and save the following TFL registration file, which references the tfl_table_add_uint8 table.

    The file specifies that the TFL to be registered is named 'Addition Operator Example' and consists of tfl_table_add_uint8, with the default ANSI math library as the base TFL table.

    function sl_customization(cm)
    % sl_customization function to register a target function library (TFL)
    
      % Register the TFL defined in local function locTflRegFcn
      cm.registerTargetInfo(@locTflRegFcn);
    
    end % End of SL_CUSTOMIZATION
    
    
    % Local function to define a TFL containing tfl_table_add_uint8
    function thisTfl = locTflRegFcn
    
      % Instantiate a TFL registry entry
      thisTfl = RTW.TflRegistry;
    
      % Define the TFL properties
      thisTfl.Name = 'Addition Operator Example'; 
      thisTfl.Description = 'Demonstration of addition operator replacement';
      thisTfl.TableList = {'tfl_table_add_uint8'};
      thisTfl.BaseTfl = 'C89/C90 (ANSI)';
      thisTfl.TargetHWDeviceType = {'*'};
    
    end % End of LOCTFLREGFCN

    Place this sl_customization.m file in the MATLAB search path or in the current working directory, so that the TFL is registered at each Simulink startup.

      Tip   To refresh Simulink customizations within the current MATLAB session, use the command sl_refresh_customizations. (To refresh Embedded MATLAB Coder TFL registration information within a MATLAB session, use the command RTW.TargetRegistry.getInstance('reset');.)

    For more information about registering TFLs with Simulink or Embedded MATLAB Coder software, see Registering Target Function Libraries.

  4. With your sl_customization.m file in the MATLAB search path or in the current working directory, open an ERT-based Simulink model and navigate to the Interface pane of the Configuration Parameters dialog box. Verify that the Target function library option lists the TFL name you specified and select it.

      Note   If you hover over the selected library with the cursor, a tool tip appears. This tip provides information derived from your TFL registration file, such as the TFL description and the list of tables it contains.

    Optionally, you can relaunch the TFL Viewer, using the MATLAB command RTW.viewTFL with no argument, to examine all registered TFLs, including Addition Operator Example.

  5. Create an ERT-based model with an Add block, such as the following:

    Make sure that the TFL you registered, Addition Operator Example, is selected for this model.

  6. Go to the Real-Time Workshop > Report pane of the Configuration Parameters dialog box and select the options Create code generation report and Model-to-code. Then go to the Real-Time Workshop pane, select the Generate code only option, and generate code for the model.

  7. Go to the model window and use model-to-code highlighting to trace the code generated using your TFL entry. For example, right-click the Add block and select Real-Time Workshop > Navigate to Code. This selection highlights the Sum block code within the model step function in add8.c. In this case, code containing the + operator has been replaced with u8_add_u8_u8 in the generated code.

Mapping Nonscalar Operators to Target-Specific Implementations

The Real-Time Workshop Embedded Coder software supports the following nonscalar operators for replacement with custom library functions using target function library (TFL) tables:

+ (addition)
(subtraction)
* (matrix multiplication)
.* (array multiplication)
' (matrix transposition)
.' (array transposition)

Supported data types include single, double, int8, uint8, int16, uint16, int32, and uint32, their complex equivalents (for example, cint32), and fixed-point integers.

Example: Mapping Small Matrix Operations to Processor-Specific Intrinsic Functions

You can efficiently implement small matrix operations by invoking processor-specific intrinsic functions. The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry mapping small matrix sum operations to implementation functions that could invoke processor-specific intrinsic functions.

  1. Create and save the following TFL table definition file, tfl_table_matrix_add_double.m. This file defines a TFL table containing two matrix operator replacement entries for the + (addition) operator and the double data type.

    The function body sets selected addition operator entry parameters, creates the y1, u1, and u2 conceptual arguments individually, and then configures the implementation arguments. Finally, the operator entry is added to the table.

    To specify a matrix argument to createAndAddConceptualArg, use the TFL argument class RTW.TflArgMatrix and specify the base type and the dimensions for which the argument is valid. In this example, the first table entry specifies [2 2] and the second table entry specifies [3 3].

    function hTable = tfl_table_matrix_add_double
    %TFL_TABLE_MATRIX_ADD_DOUBLE - Describe two matrix operator entries for a TFL table.
    
    hTable = RTW.TflTable;
    
    LibPath = fullfile(matlabroot, 'toolbox', 'rtw', 'rtwdemos', 'tfl_demo');
    
    % Create table entry for matrix_sum_2x2_double
    op_entry = RTW.TflCOperationEntry;
    setTflCOperationEntryParameters(op_entry, ...
        'Key',                      'RTW_OP_ADD', ...
        'Priority',                 30, ...
        'SaturationMode',           'RTW_WRAP_ON_OVERFLOW', ...
        'ImplementationName',       'matrix_sum_2x2_double', ...
        'ImplementationHeaderFile', 'MatrixMath.h', ...
        'ImplementationSourceFile', 'MatrixMath.c', ...
        'ImplementationHeaderPath', LibPath, ...
        'ImplementationSourcePath', LibPath, ...
        'AdditionalIncludePaths',   {LibPath}, ...
        'GenCallback',              'RTW.copyFileToBuildDir', ...
        'SideEffects',              true);
    
    % Specify operands and result
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'y1', ...
                              'IOType',       'RTW_IO_OUTPUT', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix',...
                              'Name',         'u1', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix',...
                              'Name',         'u2', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2]);
    
    % Specify replacement function signature
    arg = getTflArgFromString(hTable, 'y2', 'void');
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.setReturn(arg);
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.addArgument(arg);
    
    addEntry(hTable, op_entry);
    
    % Create table entry for matrix_sum_3x3_double
    op_entry = RTW.TflCOperationEntry;
    setTflCOperationEntryParameters(op_entry, ...
        'Key',                      'RTW_OP_ADD', ...
        'Priority',                 30, ...
        'SaturationMode',           'RTW_WRAP_ON_OVERFLOW', ...
        'ImplementationName',       'matrix_sum_3x3_double', ...
        'ImplementationHeaderFile', 'MatrixMath.h', ...
        'ImplementationSourceFile', 'MatrixMath.c', ...
        'ImplementationHeaderPath', LibPath, ...
        'ImplementationSourcePath', LibPath, ...
        'AdditionalIncludePaths',   {LibPath}, ...
        'GenCallback',              'RTW.copyFileToBuildDir', ...
        'SideEffects',              true);
    
    % Specify operands and result
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'y1', ...
                              'IOType',       'RTW_IO_OUTPUT', ...
                              'BaseType',     'double', ...
                              'DimRange',     [3 3]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix',...
                              'Name',         'u1', ...
                              'BaseType',     'double', ...
                              'DimRange',     [3 3]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix',...
                              'Name',         'u2', ...
                              'BaseType',     'double', ...
                              'DimRange',     [3 3]);
    
    % Specify replacement function signature
    arg = getTflArgFromString(hTable, 'y2', 'void');
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.setReturn(arg);
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.addArgument(arg);
    
    addEntry(hTable, op_entry);
  2. Optionally, perform a quick check of the validity of the operator entries by invoking the table definition file at the MATLAB command line (>> tbl = tfl_table_matrix_add_double) and by viewing it in the TFL Viewer (>> RTW.viewTfl(tfl_table_matrix_add_double)).

    For more information about validating TFL tables, see Examining and Validating Function Replacement Tables.

  3. Create and save the following TFL registration file, which references the tfl_table_matrix_add_double table.

    The file specifies that the TFL to be registered is named 'Matrix Addition Operator Example' and consists of tfl_table_matrix_add_double, with the default ANSI math library as the base TFL table.

    function sl_customization(cm)
    % sl_customization function to register a target function library (TFL)
    
      % Register the TFL defined in local function locTflRegFcn
      cm.registerTargetInfo(@locTflRegFcn);
    
    end % End of SL_CUSTOMIZATION
    
    
    % Local function to define a TFL containing tfl_table_matrix_add_double
    function thisTfl = locTflRegFcn
    
      % Instantiate a TFL registry entry
      thisTfl = RTW.TflRegistry;
    
      % Define the TFL properties
      thisTfl.Name = 'Matrix Addition Operator Example'; 
      thisTfl.Description = 'Demonstration of matrix addition operator replacement';
      thisTfl.TableList = {'tfl_table_matrix_add_double'};
      thisTfl.BaseTfl = 'C89/C90 (ANSI)';
      thisTfl.TargetHWDeviceType = {'*'};
    
    end % End of LOCTFLREGFCN

    Place this sl_customization.m file in the MATLAB search path or in the current working directory, so that the TFL is registered at each Simulink startup.

      Tip   To refresh Simulink customizations within the current MATLAB session, use the command sl_refresh_customizations. (To refresh Embedded MATLAB Coder TFL registration information within a MATLAB session, use the command RTW.TargetRegistry.getInstance('reset');.)

    For more information about registering TFLs with Simulink or Embedded MATLAB Coder software, see Registering Target Function Libraries.

  4. With your sl_customization.m file in the MATLAB search path or in the current working directory, open an ERT-based Simulink model and navigate to the Interface pane of the Configuration Parameters dialog box. Verify that the Target function library option lists the TFL name you specified and select it.

      Note   If you hover over the selected library with the cursor, a tool tip appears. This tip provides information derived from your TFL registration file, such as the TFL description and the list of tables it contains.

    Optionally, you can relaunch the TFL Viewer, using the MATLAB command RTW.viewTFL with no argument, to examine all registered TFLs, including Matrix Addition Operator Example.

  5. Create an ERT-based model with an Add block, such as the following:

    Configure the Signal Attributes for the In1 and In2 source blocks. For each source block, set Port dimensions to [3 3] and set the Data type to double. Also, go to the Solver pane of the Configuration Parameters dialog box and select a fixed-step, discrete solver with a fixed-step size such as 0.1. Apply the changes. Save the model. In this example, the model is saved to the name matrixadd.mdl.

    Make sure that the TFL you registered, Matrix Addition Operator Example, is selected for this model.

  6. Go to the Real-Time Workshop > Report pane of the Configuration Parameters dialog box and select the options Create code generation report and Model-to-code. Then go to the Real-Time Workshop pane, select the Generate code only option, and generate code for the model.

  7. Go to the model window and use model-to-code highlighting to trace the code generated using your TFL entry. For example, right-click the Add block and select Real-Time Workshop > Navigate to Code. This selection highlights the Sum block code within the model step function in matrixadd.c. In this case, code containing the + operator has been replaced with matrix_sum_3x3_double in the generated code.

      Note   Optionally, you can reconfigure the In1 and In2 block Port dimensions to [2 2], regenerate code, and observe that code containing the + operator is replaced with matrix_sum_2x2_double.

Example: Mapping Matrix Multiplication to MathWorks BLAS Functions

You can use TFL tables to map nonscalar multiplication operations to the Basic Linear Algebra Subroutine (BLAS) multiplication functions xgemm and xgemv. The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry mapping floating-point matrix/matrix and matrix/vector multiplication operations to MathWorks BLAS library multiplication functions.

Although BLAS libraries support matrix/matrix multiplication in the form of , TFLs support only the limited case of . Correspondingly, although BLAS libraries support matrix/vector multiplication in the form of , TFLs support only the limited case of .

  1. Create and save the following TFL table definition file, tfl_table_tmwblas_mmult_double.m. This file defines a TFL table containing dgemm and dgemv replacement entries for the matrix multiplication operator and the double data type.

    For each entry, the function body sets selected matrix multiplication operator entry parameters, creates the y1, u1, and u2 conceptual arguments individually, and then configures special implementation arguments that are required for dgemm and dgemv replacements. Finally, each operator entry is added to the table.

    To specify a matrix argument to createAndAddConceptualArg, use the TFL argument class RTW.TflArgMatrix and specify the base type and the dimensions for which the argument is valid. This type of table entry supports a range of dimensions specified in the format [Dim1Min Dim2Min ... DimNMin; Dim1Max Dim2Max ... DimNMax]. For example, [2 2; inf inf] means any two-dimensional matrix of size 2x2 or larger. In this example, the conceptual output argument for the dgemm32 entry for matrix/matrix multiplication replacement specifies dimensions [2 2; inf inf], while the conceptual output argument for the dgemv32 entry for matrix/vector multiplication replacement specifies dimensions [2 1; inf 1].

    function hTable = tfl_table_tmwblas_mmult_double
    %TFL_TABLE_TMWBLAS_MMULT_DOUBLE - Describe two mmult operator entries for TFL table.
    
    hTable = RTW.TflTable;
    
    % Define library path for Windows or UNIX
    arch = computer('arch');
    if ~ispc
        LibPath = fullfile('$(MATLAB_ROOT)', 'bin', arch);
    else
        % Use Stateflow to get the compiler info
        compilerInfo = sf('Private','compilerman','get_compiler_info');
        compilerName = compilerInfo.compilerName;
        if strcmp(compilerName, 'msvc90') || ...
                strcmp(compilerName, 'msvc80') || ...
                strcmp(compilerName, 'msvc71') || ...
                strcmp(compilerName, 'msvc60'), ...
                compilerName = 'microsoft';
        end
        LibPath = fullfile('$(MATLAB_ROOT)', 'extern', 'lib', arch, compilerName);
    end
    
    % Create table entry for dgemm32
    op_entry = RTW.TflBlasEntryGenerator;
    if ispc
        libExt = 'lib';
    elseif ismac
        libExt = 'dylib';
    else
        libExt = 'so';
    end
    setTflCOperationEntryParameters(op_entry, ...
        'Key',                      'RTW_OP_MUL', ...
        'Priority',                 100, ...
        'ImplementationName',       'dgemm32', ...
        'ImplementationHeaderFile', 'blascompat32.h', ...
        'ImplementationHeaderPath', fullfile('$(MATLAB_ROOT)','extern','include'), ...
        'AdditionalLinkObjs',       {['libmwblascompat32.' libExt]}, ...
        'AdditionalLinkObjsPaths',  {LibPath}, ...
        'SideEffects',              true);
    
    % Specify operands and result
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'y1', ...
                              'IOType',       'RTW_IO_OUTPUT', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'u1', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'u2', ...
                              'BaseType',     'double', ...
                              'DimRange',     [1 1; inf inf]);
    
    % Using RTW.TflBlasEntryGenerator for xgemm requires the following
    % implementation signature:
    %
    % void f(char* TRANSA, char* TRANSB, int* M, int* N, int* K,
    %        type* ALPHA, type* u1, int* LDA, type* u2, int* LDB,
    %        type* BETA, type* y, int* LDC)
    %
    % Upon a successful match, the TFL entry will compute the correct
    % values for M, N, K, LDA, LDB, and LDC and insert them into the
    % generated code. TRANSA and TRANSB both will be set to 'N'.
    
    % Specify replacement function signature
    
    arg = getTflArgFromString(hTable, 'y2', 'void');
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.setReturn(arg);
    
    arg = RTW.TflArgCharConstant('TRANSA');
    % Possible values for PassByType property are
    %  RTW_PASSBY_AUTO, RTW_PASSBY_POINTER,
    %  RTW_PASSBY_VOID_POINTER, RTW_PASSBY_BASE_POINTER
    arg.PassByType = 'RTW_PASSBY_POINTER';
    op_entry.Implementation.addArgument(arg);
    
    arg = RTW.TflArgCharConstant('TRANSB');
    arg.PassByType = 'RTW_PASSBY_POINTER';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'M', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'N', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'K', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'ALPHA', 'double', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDA', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDB', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'BETA', 'double', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    arg.PassByType = 'RTW_PASSBY_POINTER';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDC', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);  
    
    addEntry(hTable, op_entry);
    
    % Create table entry for dgemv32
    op_entry = RTW.TflBlasEntryGenerator;
    if ispc
        libExt = 'lib';
    elseif ismac
        libExt = 'dylib';
    else
        libExt = 'so';
    end
    setTflCOperationEntryParameters(op_entry, ...
        'Key',                      'RTW_OP_MUL', ...
        'Priority',                 100, ...
        'ImplementationName',       'dgemv32', ...
        'ImplementationHeaderFile', 'blascompat32.h', ...
        'ImplementationHeaderPath', fullfile('$(MATLAB_ROOT)','extern','include'), ...
        'AdditionalLinkObjs',       {['libmwblascompat32.' libExt]}, ...
        'AdditionalLinkObjsPaths',  {LibPath},...
        'SideEffects',              true);
    
    % Specify operands and result
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'y1', ...
                              'IOType',       'RTW_IO_OUTPUT', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 1; inf 1]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'u1', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix',...
                              'Name',         'u2', ...
                              'BaseType',     'double', ...
                              'DimRange',     [1 1; inf 1]);
    
    % Using RTW.TflBlasEntryGenerator for xgemv requires the following
    % implementation signature:
    %
    % void f(char* TRANS, int* M, int* N,
    %        type* ALPHA, type* u1, int* LDA, type* u2, int* INCX,
    %        type* BETA, type* y, int* INCY)
    %
    % Upon a successful match, the TFL entry will compute the correct
    % values for M, N, LDA, INCX, and INCY, and insert them into the
    % generated code. TRANS will be set to 'N'.
    
    % Specify replacement function signature
    
    arg = getTflArgFromString(hTable, 'y2', 'void');
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.setReturn(arg);
    
    arg = RTW.TflArgCharConstant('TRANS');
    arg.PassByType = 'RTW_PASSBY_POINTER';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'M', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'N', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'ALPHA', 'double', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDA', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'INCX','integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'BETA', 'double', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    arg.PassByType = 'RTW_PASSBY_POINTER';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'INCY', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg); 
    
    addEntry(hTable, op_entry);
  2. Optionally, perform a quick check of the validity of the operator entries by invoking the table definition file at the MATLAB command line (>> tbl = tfl_table_tmwblas_mmult_double) and by viewing it in the TFL Viewer (>> RTW.viewTfl(tfl_table_tmwblas_mmult_double)).

    For more information about validating TFL tables, see Examining and Validating Function Replacement Tables.

  3. Create and save the following TFL registration file, which references the tfl_table_tmwblas_mmult_double table.

    The file specifies that the TFL to be registered is named 'MathWorks BLAS Matrix Multiplication Operator Example' and consists of tfl_table_tmwblas_mmult_double, with the default ANSI math library as the base TFL table.

    function sl_customization(cm)
    % sl_customization function to register a target function library (TFL)
    
      % Register the TFL defined in local function locTflRegFcn
      cm.registerTargetInfo(@locTflRegFcn);
    
    end % End of SL_CUSTOMIZATION
    
    
    % Local function to define a TFL containing tfl_table_tmwblas_mmult_double
    function thisTfl = locTflRegFcn
    
      % Instantiate a TFL registry entry
      thisTfl = RTW.TflRegistry;
    
      % Define the TFL properties
      thisTfl.Name = 'MathWorks BLAS Matrix Multiplication Operator Example'; 
      thisTfl.Description = 'Demonstration of MathWorks BLAS mmult operator replacement';
      thisTfl.TableList = {'tfl_table_tmwblas_mmult_double'};
      thisTfl.BaseTfl = 'C89/C90 (ANSI)';
      thisTfl.TargetHWDeviceType = {'*'};
    
    end % End of LOCTFLREGFCN

    Place this sl_customization.m file in the MATLAB search path or in the current working directory, so that the TFL is registered at each Simulink startup.

      Tip   To refresh Simulink customizations within the current MATLAB session, use the command sl_refresh_customizations. (To refresh Embedded MATLAB Coder TFL registration information within a MATLAB session, use the command RTW.TargetRegistry.getInstance('reset');.)

    For more information about registering TFLs with Simulink or Embedded MATLAB Coder software, see Registering Target Function Libraries.

  4. With your sl_customization.m file in the MATLAB search path or in the current working directory, open an ERT-based Simulink model and navigate to the Interface pane of the Configuration Parameters dialog box. Verify that the Target function library option lists the TFL name you specified and select it.

      Note   If you hover over the selected library with the cursor, a tool tip appears. This tip provides information derived from your TFL registration file, such as the TFL description and the list of tables it contains.

    Optionally, you can relaunch the TFL Viewer, using the MATLAB command RTW.viewTFL with no argument, to examine all registered TFLs, including MathWorks BLAS Matrix Multiplication Operator Example.

  5. Create an ERT-based model with two Product blocks, such as the following:

    1. For each Product block, set the block parameter Multiplication to the value Matrix(*).

    2. Configure the Signal Attributes for the In1, In2, and In3 source blocks. For In1 and In2, set Port dimensions to [3 3] and set the Data type to double. For In3, set Port dimensions to [3 1] and set the Data type to double.

    3. Also, go to the Solver pane of the Configuration Parameters dialog box and select a fixed-step, discrete solver with a fixed-step size such as 0.1. Apply the changes.

    4. Save the model. In this example, the model is saved to the name tmwblas_mmult.mdl.

    5. Make sure that the TFL you registered, MathWorks BLAS Matrix Multiplication Operator Example, is selected for this model.

  6. Go to the Real-Time Workshop > Report pane of the Configuration Parameters dialog box and select the options Create code generation report and Model-to-code. Then go to the Real-Time Workshop pane, select the Generate code only option, and generate code for the model.

  7. Go to the model window and use model-to-code highlighting to trace the code generated using your TFL entry. For example, right-click the top Product block and select Real-Time Workshop > Navigate to Code. This selection highlights the Product block code within the model step function in tmwblas_mmult.c. In this case, code containing the matrix multiplication operator has been replaced with a call to dgemm32 in the generated code.

Example: Mapping Matrix Multiplication to ANSI/ISO C BLAS Functions

You can use TFL tables to map nonscalar multiplication operations to the ANSI/ISO C BLAS multiplication functions xgemm and xgemv. The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry mapping floating-point matrix/matrix and matrix/vector multiplication operations to ANSI/ISO C BLAS library multiplication functions.

Although BLAS libraries support matrix/matrix multiplication in the form of , TFLs support only the limited case of . Correspondingly, although BLAS libraries support matrix/vector multiplication in the form of , TFLs support only the limited case of .

  1. Create and save the following TFL table definition file, tfl_table_cblas_mmult_double.m. This file defines a TFL table containing dgemm and dgemv replacement entries for the matrix multiplication operator and the double data type.

    For each entry, the function body sets selected matrix multiplication operator entry parameters, creates the y1, u1, and u2 conceptual arguments individually, and then configures special implementation arguments that are required for dgemm and dgemv replacements. Finally, each operator entry is added to the table.

    To specify a matrix argument to createAndAddConceptualArg, use the TFL argument class RTW.TflArgMatrix and specify the base type and the dimensions for which the argument is valid. This type of table entry supports a range of dimensions specified in the format [Dim1Min Dim2Min ... DimNMin; Dim1Max Dim2Max ... DimNMax]. For example, [2 2; inf inf] means any two-dimensional matrix of size 2x2 or larger. In this example, the conceptual output argument for the cblas_dgemm entry for matrix/matrix multiplication replacement specifies dimensions [2 2; inf inf], while the conceptual output argument for the cblas_dgemv entry for matrix/vector multiplication replacement specifies dimensions [2 1; inf 1].

    function hTable = tfl_table_cblas_mmult_double
    %TFL_TABLE_CBLAS_MMULT_DOUBLE - Describe two mmult operator entries for TFL table.
    
    hTable = RTW.TflTable;
    
    LibPath = fullfile(matlabroot, 'toolbox', 'rtw', 'rtwdemos', 'tfl_demo');
    
    % Create table entry for cblas_dgemm
    op_entry = RTW.TflCBlasEntryGenerator;
    setTflCOperationEntryParameters(op_entry, ...
        'Key',                      'RTW_OP_MUL', ...
        'Priority',                 100, ...
        'ImplementationName',       'cblas_dgemm', ...
        'ImplementationHeaderFile', 'cblas.h', ...
        'ImplementationHeaderPath', LibPath, ...
        'AdditionalIncludePaths',   {LibPath}, ...
        'GenCallback',              'RTW.copyFileToBuildDir', ...
        'SideEffects',              true);
    
    % Specify operands and result
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'y1', ...
                              'IOType',       'RTW_IO_OUTPUT', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'u1', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'u2', ...
                              'BaseType',     'double', ...
                              'DimRange',     [1 1; inf inf]);
    
    % Using RTW.TflCBlasEntryGenerator for xgemm requires the following
    % implementation signature:
    %
    % void f(enum ORDER, enum TRANSA, enum TRANSB, int M, int N, int K,
    %        type ALPHA, type* u1, int LDA, type* u2, int LDB,
    %        type BETA, type* y, int LDC)
    %
    % Since TFLs do not have the ability to specify enums, you must
    % use integer.  (This will cause problems with C++ code generation,
    % so for C++, use a wrapper function to cast each int to the
    % appropriate enumeration type.)
    %
    % Upon a successful match, the TFL entry will compute the correct
    % values for M, N, K, LDA, LDB, and LDC and insert them into the
    % generated code.
    
    % Specify replacement function signature
    
    arg = getTflArgFromString(hTable, 'y2', 'void');
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.setReturn(arg);
    
    arg = getTflArgFromString(hTable, 'ORDER', 'integer', 102);
    %arg.Type.ReadOnly=true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'TRANSA', 'integer', 111);
    %arg.Type.ReadOnly=true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'TRANSB', 'integer', 111);
    %arg.Type.ReadOnly=true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'M', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'N', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'K', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'ALPHA', 'double', 1);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDA', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDB', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'BETA', 'double', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDC', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    addEntry(hTable, op_entry);
    
    % Create table entry for cblas_dgemv
    op_entry = RTW.TflCBlasEntryGenerator;
    setTflCOperationEntryParameters(op_entry, ...
        'Key',                      'RTW_OP_MUL', ...
        'Priority',                 100, ...
        'ImplementationName',       'cblas_dgemv', ...
        'ImplementationHeaderFile', 'cblas.h', ...
        'ImplementationHeaderPath', LibPath, ...
        'AdditionalIncludePaths',   {LibPath}, ...
        'GenCallback',              'RTW.copyFileToBuildDir', ...
        'SideEffects',              true);
    
    % Specify operands and result
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'y1', ...
                              'IOType',       'RTW_IO_OUTPUT', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 1; inf 1]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'u1', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix',...
                              'Name',         'u2', ...
                              'BaseType',     'double', ...
                              'DimRange',     [1 1; inf 1]);
    
    % Using RTW.TflCBlasEntryGenerator for xgemv requires the following
    % implementation signature:
    %
    % void f(enum ORDER, enum TRANSA, int M, int N,
    %        type ALPHA, type* u1, int LDA, type* u2, int INCX,
    %        type BETA, type* y, int INCY)
    %
    % Since TFLs do not have the ability to specify enums, you must
    % use integer.  (This will cause problems with C++ code generation,
    % so for C++, use a wrapper function to cast each int to the
    % appropriate enumeration type.)
    %
    % Upon a successful match, the TFL entry will compute the correct
    % values for M, N, LDA, INCX, and INCY and insert them into the
    % generated code.
    
    % Specify replacement function signature
    
    arg = getTflArgFromString(hTable, 'y2', 'void');
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.setReturn(arg);
    
    arg = getTflArgFromString(hTable, 'ORDER', 'integer', 102);
    %arg.Type.ReadOnly=true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'TRANSA', 'integer', 111);
    %arg.Type.ReadOnly=true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'M','integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'N', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'ALPHA', 'double', 1);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDA', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'INCX', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'BETA', 'double', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'INCY', 'integer', 0);
    op_entry.Implementation.addArgument(arg); 
    
    addEntry(hTable, op_entry);
  2. Optionally, perform a quick check of the validity of the operator entries by invoking the table definition file at the MATLAB command line (>> tbl = tfl_table_cblas_mmult_double) and by viewing it in the TFL Viewer (>> RTW.viewTFL(tfl_table_cblas_mmult_double)).

    For more information about validating TFL tables, see Examining and Validating Function Replacement Tables.

  3. Create and save the following TFL registration file, which references the tfl_table_cblas_mmult_double table.

    The file specifies that the TFL to be registered is named 'ANSI/ISO C BLAS Matrix Multiplication Operator Example' and consists of tfl_table_cblas_mmult_double, with the default ANSI math library as the base TFL table.

    function sl_customization(cm)
    % sl_customization function to register a target function library (TFL)
    
      % Register the TFL defined in local function locTflRegFcn
      cm.registerTargetInfo(@locTflRegFcn);
    
    end % End of SL_CUSTOMIZATION
    
    
    % Local function to define a TFL containing tfl_table_cblas_mmult_double
    function thisTfl = locTflRegFcn
    
      % Instantiate a TFL registry entry
      thisTfl = RTW.TflRegistry;
    
      % Define the TFL properties
      thisTfl.Name = 'ANSI/ISO C BLAS Matrix Multiplication Operator Example'; 
      thisTfl.Description = 'Demonstration of C BLAS mmult operator replacement';
      thisTfl.TableList = {'tfl_table_cblas_mmult_double'};
      thisTfl.BaseTfl = 'C89/C90 (ANSI)';
      thisTfl.TargetHWDeviceType = {'*'};
    
    end % End of LOCTFLREGFCN

    Place this sl_customization.m file in the MATLAB search path or in the current working directory, so that the TFL is registered at each Simulink startup.

      Tip   To refresh Simulink customizations within the current MATLAB session, use the command sl_refresh_customizations. (To refresh Embedded MATLAB Coder TFL registration information within a MATLAB session, use the command RTW.TargetRegistry.getInstance('reset');.)

    For more information about registering TFLs with Simulink or Embedded MATLAB Coder software, see Registering Target Function Libraries.

  4. With your sl_customization.m file in the MATLAB search path or in the current working directory, open an ERT-based Simulink model and navigate to the Interface pane of the Configuration Parameters dialog box. Verify that the Target function library option lists the TFL name you specified and select it.

      Note   If you hover over the selected library with the cursor, a tool tip appears. This tip provides information derived from your TFL registration file, such as the TFL description and the list of tables it contains.

    Optionally, you can relaunch the TFL Viewer, using the MATLAB command RTW.viewTFL with no argument, to examine all registered TFLs, including ANSI/ISO C BLAS Matrix Multiplication Operator Example.

  5. Create an ERT-based model with two Product blocks, such as the following:

    1. For each Product block, set the block parameter Multiplication to the value Matrix(*).

    2. Configure the Signal Attributes for the In1, In2, and In3 source blocks. For In1 and In2, set Port dimensions to [3 3] and set the Data type to double. For In3, set Port dimensions to [3 1] and set the Data type to double.

    3. Also, go to the Solver pane of the Configuration Parameters dialog box and select a fixed-step, discrete solver with a fixed-step size such as 0.1. Apply the changes.

    4. Save the model. In this example, the model is saved to the name cblas_mmult.mdl.

    5. Make sure that the TFL you registered, ANSI/ISO C BLAS Matrix Multiplication Operator Example, is selected for this model.

  6. Go to the Real-Time Workshop > Report pane of the Configuration Parameters dialog box and select the options Create code generation report and Model-to-code. Then go to the Real-Time Workshop pane, select the Generate code only option, and generate code for the model.

  7. Go to the model window and use model-to-code highlighting to trace the code generated using your TFL entry. For example, right-click the top Product block and select Real-Time Workshop > Navigate to Code. This selection highlights the Product block code within the model step function in cblas_mmult.c. In this case, code containing the matrix multiplication operator has been replaced with a call to cblas_dgemm in the generated code.

Mapping Fixed-Point Operators to Target-Specific Implementations

Overview of Fixed-Point Operator Replacement

The Real-Time Workshop Embedded Coder software supports TFL-based function replacement for the following scalar operations on fixed-point data types:

Fixed-point operator table entries can be defined as matching:

Fixed-Point Numbers and Arithmetic

Fixed-point numbers use integers and integer arithmetic to represent real numbers and arithmetic with the following encoding scheme:

where

The general equation for an operation between fixed-point operands is as follows:

The objective of TFL fixed-point operator replacement is to replace an operator that accepts and returns fixed-point or integer inputs and output with a function that accepts and returns built-in C numeric data types (not fixed-point data types). The following sections provide additional programming information for each supported operator.

Addition.  

The operation V0 = V1 + V2 implies that

If an addition replacement function is defined such that the scaling on the operands and sum are equal and the net bias

is zero (for example, a function s8_add_s8_s8 that adds two signed 8-bit values and produces a signed 8-bit result), then the TFL operator entry must set the operator entry parameters SlopesMustBeTheSame and MustHaveZeroNetBias to true. (For parameter descriptions, see the reference page for the function setTflCOperationEntryParameters.)

Subtraction.  

The operation V0 = V1 − V2 implies that

If a subtraction replacement function is defined such that the scaling on the operands and difference are equal and the net bias

is zero (for example, a function s8_sub_s8_s8 that subtracts two signed 8-bit values and produces a signed 8-bit result), then the TFL operator entry must set the operator entry parameters SlopesMustBeTheSame and MustHaveZeroNetBias to true. (For parameter descriptions, see the reference page for the function setTflCOperationEntryParameters.)

Multiplication.  

There are different ways to specify multiplication replacements. The most direct way is to specify an exact match of the input and output types. This is feasible if a model contains only a few (known) slope and bias combinations. For this, use the TflCOperationEntry class and specify the exact values of slope and bias on each argument. For scenarios where there are numerous slope/bias combinations, it is not feasible to specify each value with a different TFL entry. For this, use a relative scaling factor (RSF) entry or a net slope entry:

Division.  

There are different ways to specify division replacements. The most direct way is to specify an exact match of the input and output types. This is feasible if a model contains only a few (known) slope and bias combinations. For this, use the TflCOperationEntry class and specify the exact values of slope and bias on each argument. For scenarios where there are numerous slope/bias combinations, it is not feasible to specify each value with a different TFL entry. For this, use a relative scaling factor (RSF) entry or a net slope entry:

Data Type Conversion (Cast).  

The data type conversion operation V0 = V1 implies, for binary-point-only scaling, that

where Sn is the net slope.

Shift Left.  

The shift left operation V0 = (V1 / 2n) implies, for binary-point-only scaling, that

where Sn is the net slope.

Creating Fixed-Point Operator Entries

To create TFL table entries for fixed-point operators, you use the General Method for Creating Function and Operator Entries and specify fixed-point parameter/value pairs to the functions shown in the following table.

FunctionDescription
createAndAddConceptualArgCreate conceptual argument from specified properties and add to conceptual arguments for TFL table entry
createAndAddImplementationArgCreate implementation argument from specified properties and add to implementation arguments for TFL table entry
createAndSetCImplementationReturnCreate implementation return argument from specified properties and add to implementation for TFL table entry
setTflCOperationEntryParametersSet specified parameters for operator entry in TFL table

The following table maps some common methods of matching TFL fixed-point operator table entries to the associated fixed-point parameters that you need to specify in your TFL table definition file.

To match...Instantiate class...Minimally specify parameters...
A specific binary-point-only scaling combination on the operator inputs and output


See Example: Creating Fixed-Point Operator Entries for Binary-Point-Only Scaling.
RTW.TflCOperationEntrycreateAndAddConceptualArg function:
  • CheckSlope: Specify the value true.

  • CheckBias: Specify the value true.

  • DataTypeMode (or DataType/Scaling equivalent): Specify fixed-point binary-point-only scaling.

  • FractionLength: Specify a fraction length (for example, 3).

A specific [slope bias] scaling combination on the operator inputs and output


See Example: Creating Fixed-Point Operator Entries for [Slope Bias] Scaling.
RTW.TflCOperationEntrycreateAndAddConceptualArg function:
  • CheckSlope: Specify the value true.

  • CheckBias: Specify the value true.

  • DataTypeMode (or DataType/Scaling equivalent): Specify fixed-point [slope bias] scaling.

  • Slope (or SlopeAdjustmentFactor/FixedExponent equivalent): Specify a slope value (for example, 15).

  • Bias: Specify a bias value (for example, 2).

Relative scaling between operator inputs and output (multiplication and division)


See Example: Creating Fixed-Point Operator Entries for Relative Scaling (Multiplication and Division).
RTW.TflCOperationEntryGeneratorsetTflCOperationEntryParameters function:
  • RelativeScalingFactorF: Specify the slope adjustment factor (F) part of the relative scaling factor, F2E (for example, 1.0).

  • RelativeScalingFactorE: Specify the fixed exponent (E) part of the relative scaling factor, F2E (for example, -3.0).

createAndAddConceptualArg function:

  • CheckSlope: Specify the value false.

  • CheckBias: Specify the value false.

  • DataType: Specify the value 'Fixed'.

Net slope between operator inputs and output (multiplication and division)


See Example: Creating Fixed-Point Operator Entries for Net Slope (Multiplication and Division).
RTW.TflCOperationEntryGenerator_NetSlopesetTflCOperationEntryParameters function:
  • NetSlopeAdjustmentFactor: Specify the slope adjustment factor (F) part of the net slope, F2E (for example, 1.0).

  • NetFixedExponent: Specify the fixed exponent (E) part of the net slope, F2E (for example, -3.0).

createAndAddConceptualArg function:

  • CheckSlope: Specify the value false.

  • CheckBias: Specify the value false.

  • DataType: Specify the value 'Fixed'.

Equal slope and zero net bias across operator inputs and output (addition and subtraction)


See Example: Creating Fixed-Point Operator Entries for Equal Slope and Zero Net Bias (Addition and Subtraction).
RTW.TflCOperationEntryGeneratorsetTflCOperationEntryParameters function:
  • SlopesMustBeTheSame: Specify the value true.

  • MustHaveZeroNetBias: Specify the value true.

createAndAddConceptualArg function:

  • CheckSlope: Specify the value false.

  • CheckBias: Specify the value false.

Example: Creating Fixed-Point Operator Entries for Binary-Point-Only Scaling

TFL table entries for operations on fixed-point data types can be defined as matching a specific binary-point-only scaling combination on the operator inputs and output. These binary-point-only scaling entries can map the specified binary-point-scaling combination to a replacement function for addition, subtraction, multiplication, or division.

The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry for multiplication of fixed-point data types where arguments are specified with binary-point-only scaling. In this example:

hTable = RTW.TflTable;

op_entry = RTW.TflCOperationEntry;
setTflCOperationEntryParameters(op_entry, ...
                    'Key',                      'RTW_OP_MUL', ...
                    'Priority',                 90, ...
                    'SaturationMode',           'RTW_SATURATE_ON_OVERFLOW', ...
                    'RoundingMode',             'RTW_ROUND_UNSPECIFIED', ...
                    'ImplementationName',       's32_mul_s16_s16_binarypoint', ...
                    'ImplementationHeaderFile', 's32_mul_s16_s16_binarypoint.h', ...
                    'ImplementationSourceFile', 's32_mul_s16_s16_binarypoint.c');

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric',...
                          'Name',           'y1', ... 
                          'IOType',         'RTW_IO_OUTPUT', ...
                          'CheckSlope',     true, ...
                          'CheckBias',      true, ...
                          'DataTypeMode',   'Fixed-point: binary point scaling', ...
                          'IsSigned',       true, ...
                          'WordLength',     32, ...
                          'FractionLength', 28);

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'u1', ...
                          'IOType',         'RTW_IO_INPUT', ...
                          'CheckSlope',     true, ...
                          'CheckBias',      true, ...
                          'DataTypeMode',   'Fixed-point: binary point scaling', ...
                          'IsSigned',       true, ...
                          'WordLength',     16, ...
                          'FractionLength', 15);

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'u2', ...
                          'IOType',         'RTW_IO_INPUT', ...
                          'CheckSlope',     true, ...
                          'CheckBias',      true, ...
                          'DataTypeMode',   'Fixed-point: binary point scaling', ...
                          'IsSigned',       true, ...
                          'WordLength',     16, ...
                          'FractionLength', 13);

createAndSetCImplementationReturn(op_entry, 'RTW.TflArgNumeric', ...
                              'Name',           'y1', ...
                              'IOType',         'RTW_IO_OUTPUT', ...
                              'IsSigned',       true, ...
                              'WordLength',     32, ...
                              'FractionLength', 0);

createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                              'Name',           'u1', ...
                              'IOType',         'RTW_IO_INPUT', ...
                              'IsSigned',       true, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);
                               
createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                              'Name',           'u2', ...
                              'IOType',         'RTW_IO_INPUT', ...
                              'IsSigned',       true, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);

addEntry(hTable, op_entry);

To generate code using this table entry, you can follow the general procedure in Example: Mapping Scalar Operators to Target-Specific Implementations, substituting in the code above and an ERT-based model such as the following:

For this model,

Example: Creating Fixed-Point Operator Entries for [Slope Bias] Scaling

TFL table entries for operations on fixed-point data types can be defined as matching a specific [slope bias] scaling combination on the operator inputs and output. These [slope bias] scaling entries can map the specified [slope bias] combination to a replacement function for addition, subtraction, multiplication, or division.

The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry for division of fixed-point data types where arguments are specified using [slope bias] scaling. In this example:

hTable = RTW.TflTable;

op_entry = RTW.TflCOperationEntry;
setTflCOperationEntryParameters(op_entry, ...
                    'Key',                      'RTW_OP_DIV', ...
                    'Priority',                 90, ...
                    'SaturationMode',           'RTW_SATURATE_ON_OVERFLOW', ...
                    'RoundingMode',             'RTW_ROUND_CEILING', ...
                    'ImplementationName',       's16_div_s16_s16_slopebias', ...
                    'ImplementationHeaderFile', 's16_div_s16_s16_slopebias.h', ...
                    'ImplementationSourceFile', 's16_div_s16_s16_slopebias.c');

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'y1', ... 
                          'IOType',         'RTW_IO_OUTPUT', ...
                          'CheckSlope',     true, ...
                          'CheckBias',      true, ...
                          'DataTypeMode',   'Fixed-point: slope and bias scaling', ...
                          'IsSigned',       true, ...
                          'WordLength',     16, ...
                          'Slope',          15, ...
                          'Bias',           2);

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'u1', ...
                          'IOType',         'RTW_IO_INPUT', ...
                          'CheckSlope',     true, ...
                          'CheckBias',      true, ...
                          'DataTypeMode',   'Fixed-point: slope and bias scaling', ...
                          'IsSigned',       true, ...
                          'WordLength',     16, ...
                          'Slope',          15, ...
                          'Bias',           2);

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'u2', ...
                          'IOType',         'RTW_IO_INPUT', ...
                          'CheckSlope',     true, ...
                          'CheckBias',      true, ...
                          'DataTypeMode',   'Fixed-point: slope and bias scaling', ...
                          'IsSigned',       true, ...
                          'WordLength',     16, ...
                          'Slope',          13, ...
                          'Bias',           5);

createAndSetCImplementationReturn(op_entry, 'RTW.TflArgNumeric', ...
                              'Name',           'y1', ...
                              'IOType',         'RTW_IO_OUTPUT', ...
                              'IsSigned',       true, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);

createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                              'Name',           'u1', ...
                              'IOType',         'RTW_IO_INPUT', ...
                              'IsSigned',       true, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);
                               
createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                              'Name',           'u2', ...
                              'IOType',         'RTW_IO_INPUT', ...
                              'IsSigned',       true, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);

addEntry(hTable, op_entry);

To generate code using this table entry, you can follow the general procedure in Example: Mapping Scalar Operators to Target-Specific Implementations, substituting in the code above and an ERT-based model such as the following:

For this model,

Example: Creating Fixed-Point Operator Entries for Relative Scaling (Multiplication and Division)

TFL table entries for multiplication or division of fixed-point data types can be defined as matching relative scaling between operator inputs and output. These relative scaling entries can map a range of slope and bias values to a replacement function for multiplication or division.

The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry for division of fixed-point data types using a relative scaling factor. In this example:

hTable = RTW.TflTable;

op_entry = RTW.TflCOperationEntryGenerator;
setTflCOperationEntryParameters(op_entry, ...
                    'Key',                      'RTW_OP_DIV', ...
                    'Priority',                 90, ...
                    'SaturationMode',           'RTW_WRAP_ON_OVERFLOW', ...
                    'RoundingMode',             'RTW_ROUND_CEILING', ...
                    'RelativeScalingFactorF',   1.0, ...
                    'RelativeScalingFactorE',   -3.0, ...
                    'ImplementationName',       's16_div_s16_s16_rsf0p125', ...
                    'ImplementationHeaderFile', 's16_div_s16_s16_rsf0p125.h', ...
                    'ImplementationSourceFile', 's16_div_s16_s16_rsf0p125.c');

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'y1', ... 
                          'IOType',         'RTW_IO_OUTPUT', ...
                          'CheckSlope',     false, ...
                          'CheckBias',      false, ...
                          'DataType',       'Fixed', ...
                          'IsSigned',       true, ...
                          'WordLength',     16);

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'u1', ...
                          'IOType',         'RTW_IO_INPUT', ...
                          'CheckSlope',     false, ...
                          'CheckBias',      false, ...
                          'DataType',       'Fixed', ...
                          'IsSigned',       true, ...
                          'WordLength',     16);

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'u2', ...
                          'IOType',         'RTW_IO_INPUT', ...
                          'CheckSlope',     false, ...
                          'CheckBias',      false, ...
                          'DataType',       'Fixed', ...
                          'IsSigned',       true, ...
                          'WordLength',     16);

createAndSetCImplementationReturn(op_entry, 'RTW.TflArgNumeric', ...
                              'Name',           'y1', ...
                              'IOType',         'RTW_IO_OUTPUT', ...
                              'IsSigned',       true, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);

createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                              'Name',           'u1', ...
                              'IOType',         'RTW_IO_INPUT', ...
                              'IsSigned',       true, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);
                               
createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                              'Name',           'u2', ...
                              'IOType',         'RTW_IO_INPUT', ...
                              'IsSigned',       true, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);

addEntry(hTable, op_entry);

To generate code using this table entry, you can follow the general procedure in Example: Mapping Scalar Operators to Target-Specific Implementations, substituting in the code above and an ERT-based model such as the following:

For this model,

Example: Creating Fixed-Point Operator Entries for Net Slope (Multiplication and Division)

TFL table entries for multiplication or division of fixed-point data types can be defined as matching net slope between operator inputs and output. These net slope entries can map a range of slope and bias values to a replacement function for multiplication or division.

The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry for division of fixed-point data types using a net slope. In this example:

hTable = RTW.TflTable;

wv = [16,32];
for iy = 1:2
  for inum = 1:2
    for iden = 1:2
      hTable = getDivOpEntry(hTable, ...
                             fixdt(1,wv(iy)),fixdt(1,wv(inum)),fixdt(1,wv(iden)));
    end
  end
end


%---------------------------------------------------------
function hTable = getDivOpEntry(hTable,dty,dtnum,dtden)
%---------------------------------------------------------
% Create an entry for division of fixed-point data types where
% arguments are specified using Slope and Bias scaling
% Saturation on, Rounding unspecified

funcStr = sprintf('user_div_%s_%s_%s',...
        typeStrFunc(dty),...
        typeStrFunc(dtnum),...
        typeStrFunc(dtden)); 

op_entry = RTW.TflCOperationEntryGenerator_NetSlope;
setTflCOperationEntryParameters(op_entry, ...
                                'Key',                      'RTW_OP_DIV', ...
                                'Priority',                 90, ...
                                'SaturationMode',           'RTW_WRAP_ON_OVERFLOW',...
                                'RoundingMode',             'RTW_ROUND_UNSPECIFIED',...
                                'NetSlopeAdjustmentFactor', 1.0, ...
                                'NetFixedExponent',         0.0, ...
                                'ImplementationName',       funcStr, ...
                                'ImplementationHeaderFile', [funcStr,'.h'], ...
                                'ImplementationSourceFile', [funcStr,'.c'] );

createAndAddConceptualArg(op_entry, ...
                          'RTW.TflArgNumeric', ...
                          'Name',           'y1',... 
                          'IOType',         'RTW_IO_OUTPUT',...
                          'CheckSlope',     false,...
                          'CheckBias',      false,...
                          'DataTypeMode',   'Fixed-point: slope and bias scaling',...
                          'IsSigned',       dty.Signed,...
                          'WordLength',     dty.WordLength,...
                          'Bias',           0);

createAndAddConceptualArg(op_entry, ...
                          'RTW.TflArgNumeric',...
                          'Name',           'u1', ...
                          'IOType',         'RTW_IO_INPUT',...
                          'CheckSlope',     false,...
                          'CheckBias',      false,...
                          'DataTypeMode',   'Fixed-point: slope and bias scaling',...
                          'IsSigned',       dtnum.Signed,...
                          'WordLength',     dtnum.WordLength,...
                          'Bias',           0);

createAndAddConceptualArg(op_entry, ...
                          'RTW.TflArgNumeric', ...
                          'Name',           'u2', ...
                          'IOType',         'RTW_IO_INPUT',...
                          'CheckSlope',     false,...
                          'CheckBias',      false,...
                          'DataTypeMode',   'Fixed-point: slope and bias scaling',...
                          'IsSigned',       dtden.Signed,...
                          'WordLength',     dtden.WordLength,...
                          'Bias',           0);

arg = getTflArgFromString(hTable, 'y1', typeStrBase(dty));
op_entry.Implementation.setReturn(arg);

arg = getTflArgFromString(hTable, 'u1', typeStrBase(dtnum));
op_entry.Implementation.addArgument(arg);

arg = getTflArgFromString(hTable, 'u2',typeStrBase(dtden));
op_entry.Implementation.addArgument(arg);

addEntry(hTable, op_entry);

%-------------------------------------------------------------
function str = typeStrFunc(dt)
%-------------------------------------------------------------

if dt.Signed
    sstr = 's';
else
    sstr = 'u';
end
str = sprintf('%s%d',sstr,dt.WordLength); 

%-------------------------------------------------------------
function str = typeStrBase(dt)
%-------------------------------------------------------------

if dt.Signed
    sstr = ;
else
    sstr = 'u';
end
str = sprintf('%sint%d',sstr,dt.WordLength);

Example: Creating Fixed-Point Operator Entries for Equal Slope and Zero Net Bias (Addition and Subtraction)

TFL table entries for addition or subtraction of fixed-point data types can be defined as matching relative slope and bias values (equal slope and zero net bias) across operator inputs and output. These entries allow you to disregard specific slope and bias values and map relative slope and bias values to a replacement function for addition or subtraction.

The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry for addition of fixed-point data types where slopes must be equal and net bias must be zero across the operator inputs and output. In this example:

hTable = RTW.TflTable;

op_entry = RTW.TflCOperationEntryGenerator;
setTflCOperationEntryParameters(op_entry, ...
                    'Key',                     'RTW_OP_ADD', ...
                    'Priority',                 90, ...
                    'SaturationMode',           'RTW_WRAP_ON_OVERFLOW', ...
                    'RoundingMode',             'RTW_ROUND_UNSPECIFIED', ...
                    'SlopesMustBeTheSame',      true, ...
                    'MustHaveZeroNetBias',      true, ...
                    'ImplementationName',       'u16_add_SameSlopeZeroBias', ...
                    'ImplementationHeaderFile', 'u16_add_SameSlopeZeroBias.h', ...
                    'ImplementationSourceFile', 'u16_add_SameSlopeZeroBias.c');

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'y1', ...
                          'IOType',         'RTW_IO_OUTPUT', ...
                          'CheckSlope',     false, ...
                          'CheckBias',      false, ...
                          'IsSigned',       false, ...
                          'WordLength',     16);

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'u1', ...
                          'IOType',         'RTW_IO_INPUT', ...
                          'CheckSlope',     false, ...
                          'CheckBias',      false, ...
                          'IsSigned',       false, ...
                          'WordLength',     16);

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'u2', ...
                          'IOType',         'RTW_IO_INPUT', ...
                          'CheckSlope',     false, ...
                          'CheckBias',      false, ...
                          'IsSigned',       false, ...
                          'WordLength',     16);

createAndSetCImplementationReturn(op_entry, 'RTW.TflArgNumeric', ...
                              'Name',           'y1', ...
                              'IOType',         'RTW_IO_OUTPUT', ...
                              'IsSigned',       false, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);

createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                              'Name',           'u1', ...
                              'IOType',         'RTW_IO_INPUT', ...
                              'IsSigned',       false, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);
                               
createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                              'Name',           'u2', ...
                              'IOType',         'RTW_IO_INPUT', ...
                              'IsSigned',       false, ...
                              'WordLength',     16, ...
                              'FractionLength', 0);

addEntry(hTable, op_entry);

To generate code using this table entry, you can follow the general procedure in Example: Mapping Scalar Operators to Target-Specific Implementations, substituting in the code above and an ERT-based model such as the following:

For this model,

Mapping Data Type Conversion (Cast) Operations to Target-Specific Implementations

You can use TFL table entries to replace the default generated code for data type conversion (cast) operations with calls to optimized functions.

For details of the arithmetic supported for replacement of data type conversion, see the data type conversion (cast) subsection of Fixed-Point Numbers and Arithmetic.

Example: Creating a TFL Entry to Replace Casts From int32 To int16.   The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry to replace int32 to int16 data type conversion (cast) operations. In this example:

hTable = RTW.TflTable;

% Create an int16 to int32 cast replacement
op_entry = RTW.TflCOperationEntry;
setTflCOperationEntryParameters(op_entry, ...
    'Key',                      'RTW_OP_CAST', ...
    'Priority',                 50, ...
    'ImplementationName',       'my_sat_cast', ...
    'SaturationMode',           'RTW_SATURATE_ON_OVERFLOW', ...
    'RoundingMode',             'RTW_ROUND_FLOOR', ...
    'ImplementationHeaderFile', 'some_hdr.h', ...
    'ImplementationSourceFile', 'some_hdr.c');

% Create int16 arg as conceptual arg 1 and implementation return
arg = getTflArgFromString(hTable, 'y1', 'int16');
arg.IOType = 'RTW_IO_OUTPUT';
addConceptualArg(op_entry, arg);
op_entry.Implementation.setReturn(arg);

% Create int32 arg as conceptual arg 2 and implementation input arg 1
arg = getTflArgFromString(hTable, 'u1', 'int32');
addConceptualArg(op_entry, arg);
op_entry.Implementation.addArgument(arg);

addEntry(hTable, op_entry);

Example: Creating a TFL Entry to Replace Fixed-Point Casts Using Net Slope.   The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry to replace data type conversions (casts) of fixed-point data types using a net slope. In this example:

hTable = RTW.TflTable;

% Create a fixed-point cast replacement using a NetSlope entry
op_entry = RTW.TflCOperationEntryGenerator_NetSlope;
InFL = 2;
InWL = 16;
InSgn = true;
OutFL = 4;
OutWL = 32;
OutSgn = true;
setTflCOperationEntryParameters(op_entry, ...
   'Key',                       'RTW_OP_CAST', ...
   'Priority',                  50, ...
   'SaturationMode',            'RTW_SATURATE_ON_OVERFLOW', ...
   'RoundingMode',              'RTW_ROUND_FLOOR', ...
   'NetSlopeAdjustmentFactor',  1.0, ...
   'NetFixedExponent',          (OutFL - InFL), ...
   'SaturationMode',            'RTW_SATURATE_ON_OVERFLOW', ...
   'RoundingMode',              'RTW_ROUND_FLOOR', ...
   'ImplementationName',        'my_fxp_cast', ...
   'ImplementationHeaderFile',  'some_hdr.h', ...
   'ImplementationSourceFile',  'some_hdr.c');

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',         'y1', ...
                          'IOType',       'RTW_IO_OUTPUT', ...
                          'CheckSlope',   false, ...
                          'CheckBias',    false, ...
                          'DataTypeMode', 'Fixed-point: binary point scaling', ...
                          'IsSigned',     OutSgn, ...
                          'WordLength',   OutWL, ...
                          'FractionLength',OutFL);

createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',         'u1', ...
                          'IOType',       'RTW_IO_INPUT', ...
                          'CheckSlope',   false, ...
                          'CheckBias',    false, ...
                          'DataTypeMode', 'Fixed-point: binary point scaling', ...
                          'IsSigned',     InSgn, ...
                          'WordLength',   InWL, ...
                          'FractionLength',InFL);

createAndSetCImplementationReturn(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'y1', ...
                          'IOType',         'RTW_IO_OUTPUT', ...
                          'IsSigned',       OutSgn, ...
                          'WordLength',     OutWL, ...
                          'FractionLength', 0);

createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric',...
                          'Name',           'u1', ...
                          'IOType',         'RTW_IO_INPUT', ... 
                          'IsSigned',       InSgn, ...
                          'WordLength',     InWL, ...
                          'FractionLength', 0);

addEntry(hTable, op_entry);

Mapping Fixed-Point Shift Left Operations to Target-Specific Implementations

You can use TFL table entries to replace the default generated code for << (shift left) operations with calls to optimized functions.

For details of the arithmetic supported for replacement of shift-left operations, see the shift left subsection of Fixed-Point Numbers and Arithmetic.

Example: Creating a TFL Entry to Replace Shift Lefts for int16 Data.   The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry to replace << (shift left) operations for int16 data. In this example:

hTable = RTW.TflTable;

% Create a shift left replacement for int16 data
op_entry = RTW.TflCOperationEntry;
setTflCOperationEntryParameters(op_entry, ...
    'Key',                      'RTW_OP_SL', ...
    'Priority',                 50, ...
    'ImplementationName',       'my_shift_left', ...
    'ImplementationHeaderFile', 'some_hdr.h', ...
    'ImplementationSourceFile', 'some_hdr.c');

% Create int16 arg as conceptual arg 1 and implementation return
arg = getTflArgFromString(hTable, 'y1', 'int16');
arg.IOType = 'RTW_IO_OUTPUT';
addConceptualArg(op_entry, arg);
op_entry.Implementation.setReturn(arg);

% Create int16 arg as conceptual arg 2 and implementation input arg 1
arg = getTflArgFromString(hTable, 'u1', 'int16');
addConceptualArg(op_entry, arg);
op_entry.Implementation.addArgument(arg);

% Create int8 arg as conceptual arg 3 and implementation input arg 2
% Turn off type checking for number of bits to shift argument
arg = getTflArgFromString(hTable, 'u2', 'int8');
arg.CheckType = false;
addConceptualArg(op_entry, arg);
op_entry.Implementation.addArgument(arg);

addEntry(hTable, op_entry);

Example: Creating a TFL Entry to Replace Fixed-Point Shift Lefts Using Net Slope.   The following example uses the method described in General Method for Creating Function and Operator Entries to create a TFL table entry to replace << (shift left) operations for fixed-point data using a net slope. In this example:

hTable = RTW.TflTable;

% Create a fixed-point shift left replacement using a NetSlope entry
op_entry = RTW.TflCOperationEntryGenerator_NetSlope;
InFL = 2;
InWL = 16;
InSgn = true;
OutFL = 4;
OutWL = 32;
OutSgn = true;
setTflCOperationEntryParameters(op_entry, ...
   'Key',                       'RTW_OP_SL', ...
   'Priority',                  50, ...
   'SaturationMode',            'RTW_SATURATE_ON_OVERFLOW', ...
   'RoundingMode',              'RTW_ROUND_FLOOR', ...
   'NetSlopeAdjustmentFactor',  1.0, ...
   'NetFixedExponent',          (OutFL - InFL),...
   'SaturationMode',            'RTW_SATURATE_ON_OVERFLOW', ...
   'RoundingMode',              'RTW_ROUND_FLOOR', ...
   'ImplementationName',        'my_fxp_shift_left', ...
   'ImplementationHeaderFile',  'some_hdr.h', ...
   'ImplementationSourceFile',  'some_hdr.c');

% Create fixed-point arg as conceptual arg 1
createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',         'y1', ...
                          'IOType',       'RTW_IO_OUTPUT', ...
                          'CheckSlope',   false, ...
                          'CheckBias',    false, ...
                          'DataTypeMode', 'Fixed-point: binary point scaling', ...
                          'IsSigned',     OutSgn, ...
                          'WordLength',   OutWL, ...
                          'FractionLength',OutFL);

% Create fixed-point arg as conceptual arg 2
createAndAddConceptualArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',         'u1', ...
                          'IOType',       'RTW_IO_INPUT', ...
                          'CheckSlope',   false, ...
                          'CheckBias',    false, ...
                          'DataTypeMode', 'Fixed-point: binary point scaling', ...
                          'IsSigned',     InSgn, ...
                          'WordLength',   InWL, ...
                          'FractionLength',InFL);

% Create implementation return arg
createAndSetCImplementationReturn(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'y1', ...
                          'IOType',         'RTW_IO_OUTPUT', ...
                          'IsSigned',       OutSgn, ...
                          'WordLength',     OutWL, ...
                          'FractionLength', 0);

% Create implementation input arg 1
createAndAddImplementationArg(op_entry, 'RTW.TflArgNumeric', ...
                          'Name',           'u1', ...
                          'IOType',         'RTW_IO_INPUT', ...
                          'IsSigned',       InSgn, ...
                          'WordLength',     InWL, ...
                          'FractionLength', 0);

% Create uint8 arg as conceptual arg 3 and implementation input arg 2
% Turn off type checking for number of bits to shift argument
arg = getTflArgFromString(hTable, 'u2', 'uint8');
arg.CheckType = false;
addConceptualArg(op_entry, arg);
op_entry.Implementation.addArgument(arg);

addEntry(hTable, op_entry);

Remapping Operator Outputs to Implementation Function Input Positions

If you need your generated code to meet a specific coding pattern or you want more flexibility, for example, to further improve performance, you have the option of remapping operator outputs to input positions in an implementation function argument list.

For example, for a sum operation, the build process might generate code similar to the following:

rtY.Out1 = u8_add_u8_u8(rtU.In1, rtU.In2);

If you remap the output to the first input, the build process generates code similar to the following:

uint8_T rtb_Add8;

u8_add_u8_u8(&rtb_Add8, rtU.In1, rtU.In2);
rtY.Out1 = rtb_Add8;

To remap an operator output to an implementation function input for an existing TFL operator replacement entry, you modify the TFL table definition file as follows:

  1. In the setTflCOperationEntryParameters function call for the operator replacement, specify the SideEffects parameter as true.

  2. When defining the implementation function return, create a new void output argument, for example, y2.

  3. When defining the implementation function arguments, set the operator output argument (for example, y1) as an additional input argument, marking its IOType as output, and make its type a pointer type.

For example, the following TFL table definition file for a sum operation has been modified to remap operator output y1 as the first function input argument. The modified lines of code are shown in bold type. (This definition file generated the example remap code shown above.)

function hTable = tfl_table_add_uint8
%TFL_TABLE_ADD_UINT8 - Describe operator entry for a Target Function Library table.

hTable = RTW.TflTable;

% Create entry for addition of built-in uint8 data type
op_entry = RTW.TflCOperationEntry;
setTflCOperationEntryParameters(op_entry, ...
                    'Key',                      'RTW_OP_ADD', ...
                    'Priority',                 90, ...
                    'ImplementationName',       'u8_add_u8_u8', ...
                    'ImplementationHeaderFile', 'u8_add_u8_u8.h', ...
                    'ImplementationSourceFile', 'u8_add_u8_u8.c', ...
                    'SideEffects',              true );

arg = getTflArgFromString(hTable, 'y1', 'uint8');
arg.IOType = 'RTW_IO_OUTPUT';
addConceptualArg(op_entry, arg);

arg = getTflArgFromString(hTable, 'u1', 'uint8');
addConceptualArg(op_entry, arg );

arg = getTflArgFromString(hTable, 'u2', 'uint8');
addConceptualArg(op_entry, arg );

% Create new void output y2
arg = getTflArgFromString(hTable, 'y2', 'void');
arg.IOType = 'RTW_IO_OUTPUT';
op_entry.Implementation.setReturn(arg);

% Set y1 as first input arg, mark IOType as output, and use pointer type
arg=getTflArgFromString(hTable, 'y1', 'uint8*');
arg.IOType = 'RTW_IO_OUTPUT';
op_entry.Implementation.addArgument(arg);

arg=getTflArgFromString(hTable, 'u1', 'uint8');
op_entry.Implementation.addArgument(arg);

arg=getTflArgFromString(hTable, 'u2', 'uint8');
op_entry.Implementation.addArgument(arg);

addEntry(hTable, op_entry);

Specifying Build Information for Function Replacements

Functions for Specifying Table Entry Build Information

As you create TFL table entries for function or operator replacement, you specify the header and source file information for each function implementation using one of the following:

Also, each table entry can specify additional header files, source files, and object files to be included in model builds whenever the TFL table entry is matched and used to replace a function or operator in generated code. To add an additional header file, source file, or object file, use the following TFL table creation functions.

FunctionDescription
addAdditionalHeaderFileAdd additional header file to array of additional header files for TFL table entry
addAdditionalIncludePathAdd additional include path to array of additional include paths for TFL table entry
addAdditionalLinkObjAdd additional link object to array of additional link objects for TFL table entry
addAdditionalLinkObjPathAdd additional link object path to array of additional link object paths for TFL table entry
addAdditionalSourceFileAdd additional source file to array of additional source files for TFL table entry
addAdditionalSourcePathAdd additional source path to array of additional source paths for TFL table entry

For function descriptions and examples, see the function reference pages in the Real-Time Workshop Embedded Coder reference documentation.

Using RTW.copyFileToBuildDir to Copy Files to the Build Directory

If a TFL table entry uses header, source, or object files that reside in external directories, and if the table entry is matched and used to replace a function or operator in generated code, the external files will need to be copied to the build directory before the generated code is built. The RTW.copyFileToBuildDir function can be invoked after code generation to copy the table entry's specified header file, source file, additional header files, additional source files, and additional link objects to the build directory. The copied files are then available for use in the build process.

To direct that a table entry's external files should be copied to the build directory after code generation, specify the argument 'RTW.copyFileToBuildDir' to the genCallback parameter of the TFL function that you use to set the table entry parameters, among the following:

RTW.copyFileToBuildDir Examples

The following example defines a table entry for an optimized multiplication function that takes signed 32-bit integers and returns a signed 32-bit integer, taking saturation into account. Multiplications in the generated code will be replaced with calls to your optimized function. Your optimized function resides in an external directory and must be copied into the build directory to be compiled and linked into the application.

The multiplication table entry specifies the source and header file names as well as their full paths. To request the copy to be performed, the table entry specifies the argument 'RTW.copyFileToBuildDir' to the genCallback parameter of the setTflCOperationEntryParameters function. In this example, the header file s32_mul.h contains an inlined function that invokes assembly functions contained in s32_mul.s. If the table entry is matched and used to generate code, the RTW.copyFileToBuildDir function will copy the specified source and header files into the build directory.

function hTable = make_my_tfl_table

hTable = RTW.TflTable;

op_entry = RTW.TflCOperationEntry;
setTflCOperationEntryParameters(op_entry, ...
                'Key',                      'RTW_OP_MUL', ...
                'Priority',                 100, ...
                'SaturationMode',           'RTW_SATURATE_ON_OVERFLOW', ...
                'RoundingMode',             'RTW_ROUND_UNSPECIFIED', ...
                'ImplementationName',       's32_mul_s32_s32_sat', ...
                'ImplementationHeaderFile', 's32_mul.h', ...
                'ImplementationSourceFile', 's32_mul.s', ...
                'ImplementationHeaderPath', {fullfile('$(MATLAB_ROOT)','tfl')}, ...
                'ImplementationSourcePath', {fullfile('$(MATLAB_ROOT)','tfl')}, ...
                'GenCallback',              'RTW.copyFileToBuildDir');
.
.
.
addEntry(hTable, op_entry);

The following example shows the use of the addAdditional* functions along with RTW.copyFileToBuildDir.

hTable = RTW.TflTable;

% Path to external source, header, and object files
libdir = fullfile('$(MATLAB_ROOT)','..', '..', 'lib');

op_entry = RTW.TflCOperationEntry;
setTflCOperationEntryParameters(op_entry, ...
                'Key',                      'RTW_OP_ADD', ...
                'Priority',                 90, ...
                'SaturationMode',           'RTW_SATURATE_UNSPECIFIED', ...
                'RoundingMode',             'RTW_ROUND_UNSPECIFIED', ...
                'ImplementationName',       's32_add_s32_s32', ...
                'ImplementationHeaderFile', 's32_add_s32_s32.h', ...
                'ImplementationSourceFile', 's32_add_s32_s32.c'...
                'GenCallback',              'RTW.copyFileToBuildDir');

addAdditionalHeaderFile(op_entry, 'all_additions.h');
addAdditionalIncludePath(op_entry, fullfile(libdir, 'include'));
addAdditionalSourceFile(op_entry, 'all_additions.c');
addAdditionalSourcePath(op_entry, fullfile(libdir, 'src'));
addAdditionalLinkObj(op_entry, 'addition.o');
addAdditionalLinkObjPath(op_entry, fullfile(libdir, 'bin'));
.
.
.
addEntry(hTable, op_entry);

Adding Target Function Library Reserved Identifiers

The Real-Time Workshop software reserves certain words for its own use as keywords of the generated code language. Real-Time Workshop keywords are reserved for use internal to the Real-Time Workshop software or C programming and should not be used in Simulink models as identifiers or function names. Real-Time Workshop reserved keywords include many TFL identifiers, the majority of which are function names, such as acos. To view the base list of TFL reserved identifiers, see Reserved Keywords in the Real-Time Workshop documentation.

In a TFL table, each function implementation name defined by a table entry is registered as a reserved identifier. You can register additional reserved identifiers for the table on a per-header-file basis. Providing additional reserved identifiers can help prevent duplicate symbols and other identifier-related compile and link issues.

To register additional TFL reserved identifiers, use the following function.

FunctionDescription
setReservedIdentifiersRegister specified reserved identifiers to be associated with TFL table

You can register up to four reserved identifier structures in a TFL table. One set of reserved identifiers can be associated with an arbitrary TFL, while the other three (if present) must be associated with ANSI, ISO[4] , or GNU[5] libraries. The following example shows a reserved identifier structure that specifies two identifiers and the associated header file.

d{1}.LibraryName = 'ANSI';
d{1}.HeaderInfos{1}.HeaderName = 'math.h';
d{1}.HeaderInfos{1}.ReservedIds = {'y0', 'y1'};

The specified identifiers are added to the reserved identifiers collection and honored during the Real-Time Workshop build procedure. For more information and examples, see setReservedIdentifiers in the Real-Time Workshop Embedded Coder reference documentation.


[1] ANSI is a registered trademark of the American National Standards Institute, Inc.

[2] ANSI is a registered trademark of the American National Standards Institute, Inc.

[3] ANSI is a registered trademark of the American National Standards Institute, Inc.

[4] ISO is a registered trademark of the International Organization for Standardization.

[5] GNU is a registered trademark of the Free Software Foundation.

  


Related Products & Applications

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