S-Functions That Specify Port Scope and Reusability
You can use the following SimStruct
macros in the
mdlInitializeSizes
method to specify the scope and reusability of
the memory used for your S-function's input and output ports:
ssSetInputPortOptimOpts
: Specify the scope and reusability of the memory allocated to an S-function input port.ssSetOutputPortOptimOpts
: Specify the scope and reusability of the memory allocated to an S-function output port.ssSetInputPortOverWritable
: Specify whether one of your S-function's input ports can be overwritten by one of its output ports.ssSetOutputPortOverwritesInputPort
: Specify whether an output port can share its memory buffer with an input port.
You declare an input or output as local or global, and indicate its reusability, by
passing one of the following four options to the
ssSetInputPortOptimOpts
and
ssSetOutputPortOptimOpts
macros:
SS_NOT_REUSABLE_AND_GLOBAL
: Indicates that the input and output ports are stored in separate memory locations in the global block input and output structure.SS_NOT_REUSABLE_AND_LOCAL
: Indicates that the code generator can declare individual local variables for the input and output ports.SS_REUSABLE_AND_LOCAL
: Indicates that the code generator can reuse a single local variable for these input and output ports.SS_REUSABLE_AND_GLOBAL
: Indicates that these input and output ports are stored in a single element in the global block input and output structure.
Note
Marking an input or output port as a local variable does not imply that the code
generator uses a local variable in the generated code. If your S-function accesses
the inputs and outputs only in its mdlOutputs
routine, the code
generator declares the inputs and outputs as local variables. However, if the inputs
and outputs are used elsewhere in the S-function, the code generator includes them
in the global block input and output structure.
The reusability setting indicates if the memory associated with an input or output port can be overwritten. To reuse input and output port memory:
Indicate the ports are reusable using either the
SS_REUSABLE_AND_LOCAL
orSS_REUSABLE_AND_GLOBAL
option in thessSetInputPortOptimOpts
andssSetOutputPortOptimOpts
macros.Indicate the input port memory is overwritable using
ssSetInputPortOverWritable
.If your S-function has multiple input and output ports, use
ssSetOutputPortOverwritesInputPort
to indicate which output and input ports share memory.
The following example shows how different scope and reusability settings
affect the generated code. The following model contains an
S-function block pointing to the C MEX S-function
, which models a direct 1-D lookup table.matlabroot
/toolbox/simulink/simdemos/simfeatures/src/sfun_directlook.c
The S-function's mdlInitializeSizes
method declares the input port
as reusable, local, and overwritable and the output port as reusable and local, as
follows:
static void mdlInitializeSizes(SimStruct *S) { /* snip */ ssSetInputPortOptimOpts(S, 0, SS_REUSABLE_AND_LOCAL); ssSetInputPortOverWritable(S, 0, TRUE); /* snip */ ssSetOutputPortOptimOpts(S, 0, SS_REUSABLE_AND_LOCAL); /* snip */ }
The generated code for this model stores the input and output signals in a single
local variable rtb_SFunction
, as shown in the following output
function:
static void sl_directlook_output(int_T tid) { /* local block i/o variables */ real_T rtb_SFunction[2]; /* Sin: '<Root>/Sine Wave' */ rtb_SFunction[0] = sin(((real_T)sl_directlook_DWork.counter[0] + sl_directlook_P.SineWave_Offset) * 2.0 * 3.1415926535897931E+000 / sl_directlook_P.SineWave_NumSamp) * sl_directlook_P.SineWave_Amp[0] + sl_directlook_P.SineWave_Bias; rtb_SFunction[1] = sin(((real_T)sl_directlook_DWork.counter[1] + sl_directlook_P.SineWave_Offset) * 2.0 * 3.1415926535897931E+000 / sl_directlook_P.SineWave_NumSamp) * sl_directlook_P.SineWave_Amp[1] + sl_directlook_P.SineWave_Bias; /* S-Function Block: <Root>/S-Function */ { const real_T *xData = &sl_directlook_P.SFunction_XData[0]; const real_T *yData = &sl_directlook_P.SFunction_YData [0]; real_T spacing = xData[1] - xData[0]; if (rtb_SFunction[0] <= xData[0] ) { rtb_SFunction[0] = yData[0]; } else if (rtb_SFunction[0] >= yData[20] ) { rtb_SFunction[0] = yData[20]; } else { int_T idx = (int_T)( ( rtb_SFunction[0] - xData[0] ) / spacing ); rtb_SFunction[0] = yData[idx]; } if (rtb_SFunction[1] <= xData[0] ) { rtb_SFunction[1] = yData[0]; } else if (rtb_SFunction[1] >= yData[20] ) { rtb_SFunction[1] = yData[20]; } else { int_T idx = (int_T)( ( rtb_SFunction[1] - xData[0] ) / spacing ); rtb_SFunction[1] = yData[idx]; } } /* Outport: '<Root>/Out1' */ sl_directlook_Y.Out1[0] = rtb_SFunction[0]; sl_directlook_Y.Out1[1] = rtb_SFunction[1]; UNUSED_PARAMETER(tid); }
This table shows variations of the code generated for this model when using the generic real-time target (GRT). Each row explains a different setting for the scope and reusability of the S-function's input and output ports.
Scope and reusability | S-function mdlInitializeSizes
code | Generated code |
---|---|---|
Inputs: Local, reusable, overwritable Outputs: Local, reusable |
ssSetInputPortOptimOpts(S, 0, SS_REUSABLE_AND_LOCAL); ssSetInputPortOverWritable(S, 0, TRUE); ssSetOutputPortOptimOpts(S, 0, SS_REUSABLE_AND_LOCAL); | The /* local block i/o variables */ real_T rtb_SFunction[2]; |
Inputs: Global, reusable, overwritable Outputs: Global, reusable |
ssSetInputPortOptimOpts(S, 0, SS_REUSABLE_AND_GLOBAL); ssSetInputPortOverWritable(S, 0, TRUE); ssSetOutputPortOptimOpts(S, 0, SS_REUSABLE_AND_GLOBAL); | The /* Block signals (auto storage) */ typedef struct { real_T SFunction[2]; } BlockIO_sl_directlook; The
/* Sin: '<Root>/Sine Wave' */ sl_directlook_B.SFunction[0] = sin ... /* snip */ /*S-Function Block:<Root>/S-Function*/ { const real_T *xData = &sl_directlook_P.SFunction_XData[0] |
Inputs: Local, not reusable Outputs: Local, not reusable |
ssSetInputPortOptimOpts(S, 0, SS_NOT_REUSABLE_AND_LOCAL); ssSetInputPortOverWritable(S, 0, FALSE); ssSetOutputPortOptimOpts(S, 0, SS_NOT_REUSABLE_AND_LOCAL); | The /* local block i/o variables */ real_T rtb_SineWave[2]; real_T rtb_SFunction[2]; |
Inputs: Global, not reusable Outputs: Global, not reusable |
ssSetInputPortOptimOpts(S, 0, SS_NOT_REUSABLE_AND_GLOBAL); ssSetInputPortOverWritable(S, 0, FALSE); ssSetOutputPortOptimOpts(S, 0, SS_NOT_REUSABLE_AND_GLOBAL); | The /* Block signals (auto storage) */ typedef struct { real_T SineWave[2]; real_T SFunction[2]; } BlockIO_sl_directlook; The
/* Sin: '<Root>/Sine Wave' */ sl_directlook_B.SineWave[0] = sin ... /* snip */ /*S-Function Block:<Root>/S-Function*/ { const real_T *xData = &sl_directlook_P.SFunction_XData[0] |
To check if the S-function input or output buffer reuse takes place, you can use
LibBlockInputSignalBufferDstPort
function.