Main Content

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:

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:

  1. Indicate the ports are reusable using either the SS_REUSABLE_AND_LOCAL or SS_REUSABLE_AND_GLOBAL option in the ssSetInputPortOptimOpts and ssSetOutputPortOptimOpts macros.

  2. Indicate the input port memory is overwritable using ssSetInputPortOverWritable.

  3. 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 matlabroot/toolbox/simulink/simdemos/simfeatures/src/sfun_directlook.c, which models a direct 1-D lookup table.

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 reusabilityS-function mdlInitializeSizes codeGenerated 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 model.c file declares a local variable in the output function.

/* 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 model.h file defines a block signals structure with a single element to store the S-function's input and output.

/* Block signals (auto storage) */
typedef struct {
  real_T SFunction[2];
} BlockIO_sl_directlook;

The model.c file uses this element of the structure in calculations of the S-function's input and output signals.

 /* 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 model.c file declares local variables for the S-function's input and output in the output function

/* 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 model.h file defines a block signal structure with individual elements to store the S-function's input and output.

/* Block signals (auto storage) */
typedef struct {
  real_T SineWave[2];
  real_T SFunction[2];
} BlockIO_sl_directlook;

The model.c file uses the different elements in this structure when calculating the S-function's input and output.

 /* 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.

Related Topics