Customize Match and Replacement Process
During the build process, the code generator uses:
Preset match criteria to identify functions and operators for which application-specific implementations replace default implementations.
Preset replacement function signatures.
It is possible that preset match criteria and preset replacement function signatures do not completely meet your function and operator replacement needs. For example:
You want to replace an operator with a particular fixed-point implementation function only when fraction lengths are within a particular range.
When a match occurs, you want to modify your replacement function signature based on compile-time information, such as passing fraction-length values into the function.
To add extra logic into the code replacement match and replacement process, create custom code replacement table entries.
With custom entries, you can specify additional match criteria that the base class does not provie. The base class provides a match based on:
Argument number
Argument name
Signedness
Word size
Slope (if not specified with wildcards)
Bias (if not specified with wildcards)
Math modes, such as saturation and rounding
Operator or function key
You can also use custom entries to modify the replacement function signature to meet application needs. You can:
Add additional arguments.
Set constant input argument values.
You can inject a constant value, such as an input scaling value, as an additional argument to the replacement function.
To create a custom code replacement entry:
Create a custom code replacement entry class, derived from
RTW.TflCFunctionEntryML
(for function replacement)or
RTW.TflCOperationEntryML
(for operator replacement).In your derived class, implement a
do_match
method with a fixed preset signature as a MATLAB® function. In yourdo_match
method, create a copy of an existing code replacement entry type and provide customizations on the copy.Create code replacement entries that instantiate the custom entry class.
Register a library containing the code replacement table that includes your entries.
During code generation, the code replacement match process tries to match function or operator call sites with the base class of your derived entry class. If the process finds a match, the software calls your do_match
method to execute your additional match logic (if any) and your replacement function customizations (if any).
Customize Code Match and Replacement for Functions
This example shows how to use custom code replacement table entries to refine the match and replacement logic for functions. The example shows how to:
Modify a sine function replacement only if the integer size on the current target platform is 32 bits.
Change the replacement such that the implementation function passes in a degrees-versus-radians flag as an input argument.
To exercise the table entries that you create in this example, open CRLMath.slx
, which is an ERT-based model with a sine function block.
model = "CRLMath";
open_system(model)
The model contains a Sin block with input and output that have Data type set to double
.
In the Configuration Parameters, set Hardware Implementation > Device type to a target platform with a 32-bit integer size. For example, set it to x86-64 (Windows 32)
.
set_param(model,"ProdHWDeviceType",'Intel->x86-32 (Windows32)')
Create a class that is derived from the base class RTW.TflCFunctionEntryML
. For this example, use the pre-written example class TflCustomFunctionEntry
.
open("TflCustomFunctionEntry.m");
The derived class defines a do_match
method with the signature:
function ent = do_match(hThis, ...
hCSO, ...
targetBitPerChar, ...
targetBitPerShort, ...
targetBitPerInt, ...
targetBitPerLong, ...
targetBitPerLongLong)
In the do_match
signature:
ent
is the return handle. If the match succeeds,ent
is returned as aTflCFunctionEntry
handle. If the match fails,enty
is returned as empty or as an error message that you specify by callingerror
in the entry.hThis
is a handle to the class instance.hCSO
is a handle to an object that the code generator creates for querying the library for a replacement.Remaining arguments are the number of bits for various data types of the current target.
The do_match
method:
Creates a copy of an existing type of code replacement entry.
Adds required additional match criteria that the base class does not provide.
Makes required modifications to the implementation signature.
In this case, the do_match
method must match only targetBitPerInt
, representing the number of bits in the C int
data type for the current target, to the value 32. If the code generator finds a match, the method sets the return handle and creates and adds an input argument. The input argument represents whether units are expressed as degrees or radians, to the replacement function signature.
Alternatively, create and add the additional implementation function argument for passing a units flag in each code replacement table definition file that instantiates this class. In that case, this class definition code does not create the argument. That code sets only the argument value. For an example of creating and adding additional implementation function arguments in a table definition file, see .
Create a code replacement table definition file. For example, use the file crl_table_custom_sinfcn_double.m
. This file defines a code replacement table that contains a function table entry for sine with double
input and output. This entry instantiates the derived class from the previous step, TflCustomFunctionEntry
.function
hTable = crl_table_custom_sinfcn_double
open("crl_table_custom_sinfcn_double.m");
Check the validity of the code replacement table entry. At the command prompt, invoke the table definition file.
tbl = crl_table_custom_sinfcn_double
tbl = TflTable with properties: Version: '1.0' ReservedSymbols: [] StringResolutionMap: [] AllEntries: [1x1 TflCustomFunctionEntry] EnableTrace: 1
In the Code Replacement Viewer, view the table definition file.
crviewer(crl_table_custom_sinfcn_double)
Register the code replacement library. Create a file named rtwTargetInfo.m
. For this example, copy the contents from the example text file to rtwTargetInfo.m
.
delete ("rtwTargetInfo.m") copyfile CRLCustomEntriesRtwTargetInfo.txt rtwTargetInfo.m type rtwTargetInfo.m
function rtwTargetInfo(cm) cm.registerTargetInfo(@loc_register_crl); end function this = loc_register_crl % Register a code replacement library for use with CRLMath this(1) = RTW.TflRegistry; this(1).Name = 'My Sin CRL'; this(1).TableList = {'crl_table_custom_sinfcn_double'}; this(1).BaseTfl = ''; this(1).TargetHWDeviceType = {'*'}; this(1).Description = ''; % Register a code replacement library for use with CRLMultiplicationDivision this(2) = RTW.TflRegistry; this(2).Name = 'My Element-Wise Multiplication CRL'; this(2).TableList = {'myElemMultCrlTable'}; this(2).BaseTfl = ''; this(2).TargetHWDeviceType = {'*'}; this(2).Description = ''; end
Refresh your current MATLAB session by using the command sl_refresh_customizations
.
sl_refresh_customizations;
Set these configuration parameters for the model:
System target file —
ert.tlc
Code replacement libraries —
My Sin CRL
set_param(model,"SystemTargetFile","ert.tlc"); set_param(model,"CodeReplacementLibrary",'My Sin CRL'); sl_refresh_customizations;
When you generate code from the model, the generated code calls the replacement source code.
slbuild(model);
### Starting build procedure for: CRLMath ### Successful completion of code generation for: CRLMath Build Summary Top model targets: Model Build Reason Status Build Duration ============================================================================================= CRLMath Information cache folder or artifacts were missing. Code generated. 0h 0m 11.996s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 13.196s
cfile = fullfile("CRLMath_ert_rtw","CRLMath.c"); coder.example.extractLines(cfile,' rtY.Y3 = asin(rtU.U3) + tanh(rtU.U3);','rtY.Y5 = mySin(rtU.U6, 1);',0, 1);
/* Outport: '<Root>/Y5' incorporates: * Inport: '<Root>/U6' * Trigonometry: '<Root>/Trigonometric Function' */ rtY.Y5 = mySin(rtU.U6, 1);
Customize Code Match and Replacement for Nonscalar Operations
This example shows how to create custom code replacement entries that add logic to the code match and replacement process for a nonscalar operation. Custom entries specify additional match criteria or modify the replacement function signature to meet application needs.
This example restricts the match criteria for an element-wise multiplication replacement to entries with a specific dimension range. When a match occurs, the custom do_match
method modifies the replacement signature to pass the number of elements into the function.
Open the model CRLMultiplicationDivision.slx
, which will use the code replacement library.
model = "CRLMultiplicationDivision";
open_system(model)
The model contains the block MultiplyElements, which has:
Two Input ports with Data type
Int32
and Port dimensions set to[3 3]
Integer rounding mode set to
Floor
Saturate on integer overflow de-selected
Create the replacement function source and header files. For this example, use the directory named src
, which contains myMulImplLib.c
and myMulImplLib.h
.
type src/myMulImplLib.c
#include "myMulImplLib.h" void myElemMul_s32(int32_T* u1, int32_T* u2, int32_T* y1, uint32_T numElements) { int idx; for(idx = 0; idx<numElements; ++idx) { y1[idx] = u1[idx] * u2[idx]; } }
type src/myMulImplLib.h
#ifndef __myMulImplLib_h #define __myMulImplLib_h #include "rtwtypes.h" void myElemMul_s32(int32_T* u1, int32_T* u2, int32_T* y1, uint32_T numElements); #endif /*__myMulImplLib_h*/
Create a class that is derived from the base class RTW.TflCOperationEntryML
. For this example, use the pre-written class MyElemMultEntry
.
open("MyElemMultEntry.m");
The derived class defines a do_match
method with the following signature:
function ent = do_match(hThis, ...
hCSO, ...
targetBitPerChar, ...
targetBitPerShort, ...
targetBitPerInt, ...
targetBitPerLong, ...
targetBitPerLongLong)
In the do_match
signature:
ent
is the return handle. If the match succeeds,ent
is returned as aTflCOperationEntry
handle. If the match fails,ent
is returned as empty or as an error message that you specify by callingerror
in the entry.hThis
is the handle to the derived instance.hCSO
is a handle to an object that the code generator creates for querying the library for a replacement.Remaining arguments are the number of bits for various data types of the current target.
The do_match
method:
Creates a copy of an existing type of code replacement entry.
Adds match criteria that the base class does not provide.
Makes changes to the implementation signature.
The do_match
method relies on the base class for checking data types and dimension ranges. If the code generator finds a match, do_match
:
Sets the return handle.
Uses the conceptual arguments to compute the number of elements in the array. In the replacement entry returned, sets the value of the constant implementation argument as the number of elements of the array.
Create a code replacement table definition file. For example, use the file myElemMultCrlTable.m
.
open("myElemMultCrlTable.m")
This file defines a code replacement table that contains an operator entry generator for element-wise multiplication. The table entry:
Instantiates the derived class
myElemMultEntry
from the previous step.Sets operator entry parameters with the call to the
setTflCOperationEntryParameters
function.Creates conceptual arguments
y1
,u1
, andu2
. The argument classRTW.TflArgMatrix
specifies matrix arguments to match. The three arguments are set up to match 2-dimensional matrices with at least two elements in each dimension.Calls the
getTflArgFromString
function to create a return value and four implementation arguments. Argumentsu1
andu2
are the operands,y1
is the product, and the fourth argument is the number of elements.Alternatively, thedo_match
method of the derived classmyElemMultEntry
can create and add the implementation arguments. When the number of additional implementation arguments required can vary based on compile-time information, use the alternative approach.Calls
addEntry
to add the entry to a code replacement table.
Check the validity of the code replacement table entry. At the command prompt, invoke the table definition file.
tbl = myElemMultCrlTable
tbl = TflTable with properties: Version: '1.0' ReservedSymbols: [] StringResolutionMap: [] AllEntries: [1x1 MyElemMultEntry] EnableTrace: 1
In the Code Replacement Viewer, view the table definition file.
crviewer(myElemMultCrlTable)
Register the code replacement library. Create a file named rtwTargetInfo.m
. For this example, copy the contents from the example text file to rtwTargetInfo.m
.
delete ("rtwTargetInfo.m") copyfile CRLCustomEntriesRtwTargetInfo.txt rtwTargetInfo.m type rtwTargetInfo.m
function rtwTargetInfo(cm) cm.registerTargetInfo(@loc_register_crl); end function this = loc_register_crl % Register a code replacement library for use with CRLMath this(1) = RTW.TflRegistry; this(1).Name = 'My Sin CRL'; this(1).TableList = {'crl_table_custom_sinfcn_double'}; this(1).BaseTfl = ''; this(1).TargetHWDeviceType = {'*'}; this(1).Description = ''; % Register a code replacement library for use with CRLMultiplicationDivision this(2) = RTW.TflRegistry; this(2).Name = 'My Element-Wise Multiplication CRL'; this(2).TableList = {'myElemMultCrlTable'}; this(2).BaseTfl = ''; this(2).TargetHWDeviceType = {'*'}; this(2).Description = ''; end
Refresh your current MATLAB session by using the command sl_refresh_customizations
.
sl_refresh_customizations;
Set these configuration parameters for the model:
System target file —
ert.tlc
Code replacement libraries —
My CRL Lib
set_param(model,"SystemTargetFile","ert.tlc"); set_param(model,"CodeReplacementLibrary",'My Element-Wise Multiplication CRL'); sl_refresh_customizations;
When you generate code from the model, the generated code calls the replacement source code.
slbuild(model);
### Starting build procedure for: CRLMultiplicationDivision ### Successful completion of code generation for: CRLMultiplicationDivision Build Summary Top model targets: Model Build Reason Status Build Duration =============================================================================================================== CRLMultiplicationDivision Information cache folder or artifacts were missing. Code generated. 0h 0m 12.299s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 13.589s
cfile = fullfile("CRLMultiplicationDivision_ert_rtw","CRLMultiplicationDivision.c"); coder.example.extractLines(cfile, ' rtY.Out8 = (int16_T)(rtU.In15 / rtU.In16);','/* Model initialize function */',1, 0);
rtY.Out8 = (int16_T)(rtU.In15 / rtU.In16); /* Outport: '<Root>/Out9' incorporates: * Inport: '<Root>/In17' * Inport: '<Root>/In18' * Product: '<Root>/MultiplyElements' */ myElemMul_s32(&rtU.In17[0], &rtU.In18[0], &rtY.Out9[0], 9U); }
Customize Code Match and Replacement for Scalar Operations
This example shows how to create custom code replacement entries that add logic to the code match and replacement process for a scalar operation. Custom entries specify additional match criteria or modify the replacement function signature to meet application needs.
For example:
When fraction lengths are within a specific range, replace an operator with a fixed-point implementation function.
When a match occurs, modify the replacement function signature based on compile-time information, such as passing fraction-length values into the function.
This example modifies a fixed-point addition replacement such that the implementation function passes in the fraction lengths of the input and output data types as arguments.
Create a class that is derived from the base class RTW.TflCOperationEntryML
. For this example, use the pre-written class TflCustomOperationEntry
.
type TflCustomOperationEntry.m
classdef TflCustomOperationEntry < RTW.TflCOperationEntryML methods function ent = do_match(hThis, ... hCSO, ... %#ok targetBitPerChar, ... %#ok targetBitPerShort, ... %#ok targetBitPerInt, ... %#ok targetBitPerLong, ... %#ok targetBitPerLongLong) %#ok % DO_MATCH - Create a custom match function. The base class % checks the types of the arguments prior to calling this % method. This class will check additional data and can % modify the implementation function. % The base class checks word size and signedness. Slopes and biases % have been wildcarded, so the only additional checking to do is % to check that the biases are zero and that there are only three % conceptual arguments (one output, two inputs) ent = []; % default the return to empty, indicating the match failed if length(hCSO.ConceptualArgs) == 3 && ... hCSO.ConceptualArgs(1).Type.Bias == 0 && ... hCSO.ConceptualArgs(2).Type.Bias == 0 && ... hCSO.ConceptualArgs(3).Type.Bias == 0 % Modify the default implementation. Since this is a % generator entry, a concrete entry is created using this entry % as a template. The type of entry being created is a standard % TflCOperationEntry. Using the standard operation entry % provides required information, and you do not need % a custom match function. ent = RTW.TflCOperationEntry(hThis); % Set the fraction-length values in the implementation function. ent.Implementation.Arguments(3).Value = ... -1.0*hCSO.ConceptualArgs(2).Type.FixedExponent; ent.Implementation.Arguments(4).Value = ... -1.0*hCSO.ConceptualArgs(3).Type.FixedExponent; ent.Implementation.Arguments(5).Value = ... -1.0*hCSO.ConceptualArgs(1).Type.FixedExponent; end end end end
The derived class defines a do_match
method with the following signature:function ent = do_match(hThis, ...
hCSO, ...
targetBitPerChar, ...
targetBitPerShort, ...
targetBitPerInt, ...
targetBitPerLong, ...
targetBitPerLongLong)
In the do_match
signature:
ent
is the return handle. If the match succeeds,ent
is returned as aTflCOperationEntry
handle. If the match fails,enty
is returned as empty or as an error message that you specify by callingerror
in the entry.hThis
is the handle to the class instance.hCSO
is a handle to an object that the code generator creates for querying the library for a replacement.Remaining arguments are the number of bits for various data types of the current target.
The do_match
method adds match criteria that the base class does not provide. The method makes modifications to the implementation signature. In this case, the do_match
method relies on the base class for checking word size and signedness. do_match
must match only the number of conceptual arguments to the value 3 (two inputs and one output) and the bias for each argument to value 0. If the code generator finds a match, do_match
:
Sets the return handle.
Removes slope and bias wild cards from the conceptual arguments (the match is for specific slope and bias values).
Writes fraction-length values for the inputs and output into replacement function arguments 3, 4, and 5.
You can create and add three additional implementation function arguments for passing fraction lengths in the class definition or in each code replacement entry definition that instantiates this class. This example creates the arguments, adds them to a code replacement table definition file, and sets them to specific values in the class definition code.
Create a code replacement table definition file. For this example, use crl_table_custom_add_ufix32.m
.
open("crl_table_custom_add_ufix32.m");
This file defines a code replacement table that contains a single operator entry, an entry generator for unsigned 32-bit fixed-point addition operations, with arbitrary fraction-length values on the inputs and the output. The table entry:
Instantiates the derived class
TflCustomOperationEntry
from the previous step. If you want to replace word sizes and signedness attributes, you can use the same derived class, but not the same entry, because you cannot use a wild card with theWordLength
andIsSigned
arguments. For example, to supportuint8
,int8
,uint16
,int16
, andint32
, add five other distinct entries. To use different implementation functions for saturation and rounding modes other than overflow and round to floor, add entries for those match permutations.Sets operator entry parameters with the call to the
setTflCOperationEntryParameters
function.Calls the
createAndAddConceptualArg
function to create conceptual argumentsy1
,u1
, andu2
.Calls
createAndSetCImplementationReturn
andcreateAndAddImplementationArg
to define the signature for the replacement function. Three of the calls tocreateAndAddImplementationArg
create implementation arguments to hold the fraction-length values for the inputs and output. Alternatively, the entry can omit those argument definitions. Instead, thedo_match
method of the derived classTflCustomOperationEntry
can create and add the three implementation arguments. When the number of additional implementation arguments required can vary based on compile-time information, use the alternative approach.Calls
addEntry
to add the entry to a code replacement table.
Check the validity of the operator entry. At the command prompt, invoke the table definition file.
tbl = crl_table_custom_add_ufix32
tbl = TflTable with properties: Version: '1.0' ReservedSymbols: [] StringResolutionMap: [] AllEntries: [1x1 TflCustomOperationEntry] EnableTrace: 1
In the Code Replacement Viewer, view the table definition file.
crviewer(crl_table_custom_add_ufix32)