Skip to Main Content Skip to Search
Product Documentation

Fixed-Point S-Function Examples

List of Fixed-Point S-Function Examples

The following files in matlabroot/toolbox/simulink/fixedandfloat/fxpdemos/ are examples of S-functions written with the API for user-written fixed-point S-functions:

The sections that follow present smaller portions of code that focus on specific kinds of tasks you might want to perform within your S-function.

Get the Input Port Data Type

Within your S-function, you might need to know the data types of different ports, run-time parameters, and DWorks. In each case, you will need to get the data type ID of the data type, and then use functions from this API to extract information about the data type.

For example, suppose you need to know the data type of your input port. To do this,

  1. Use ssGetInputPortDataType. The data type ID of the input port is returned.

  2. Use API functions to extract information about the data type.

The following lines of example code are from sfun_user_fxp_dtprop.c.

In lines 191 and 192, ssGetInputPortDataType is used to get the data type ID for the two input ports of the S-function:

dataTypeIdU0 = ssGetInputPortDataType( S, 0 );
dataTypeIdU1 = ssGetInputPortDataType( S, 1 );

Further on in the file, the data type IDs are used with API functions to get information about the input port data types. In lines 205 through 226, a check is made to see whether the input port data types are single or double:

storageContainerU0 = ssGetDataTypeStorageContainCat( S,
					dataTypeIdU0 );
storageContainerU1 = ssGetDataTypeStorageContainCat( S,
					dataTypeIdU1 );
    
    if ( storageContainerU0 == FXP_STORAGE_DOUBLE ||
         storageContainerU1 == FXP_STORAGE_DOUBLE )
    {
        /* Doubles take priority over all other rules.
         * If either of first two inputs is double,
         * then third input is set to double.
         */
        dataTypeIdU2Desired = SS_DOUBLE;
    }
    else if ( storageContainerU0 == FXP_STORAGE_SINGLE ||
              storageContainerU1 == FXP_STORAGE_SINGLE )
    {
        /* Singles take priority over all other rules,
         *	except doubles.
         * If either of first two inputs is single
         * then third input is set to single.
         */
        dataTypeIdU2Desired = SS_SINGLE;
    }
    else

In lines 227 through 244, additional API functions are used to get information about the data types if they are neither single nor double:

{
    isSignedU0 = ssGetDataTypeFxpIsSigned( S, dataTypeIdU0 );
    isSignedU1 = ssGetDataTypeFxpIsSigned( S, dataTypeIdU1 );

    wordLengthU0 = ssGetDataTypeFxpWordLength( S, dataTypeIdU0 );
    wordLengthU1 = ssGetDataTypeFxpWordLength( S, dataTypeIdU1 );

    fracSlopeU0 = ssGetDataTypeFracSlope( S, dataTypeIdU0 );
    fracSlopeU1 = ssGetDataTypeFracSlope( S, dataTypeIdU1 );

    fixedExponentU0 = ssGetDataTypeFixedExponent( S,dataTypeIdU0 );
    fixedExponentU1 = ssGetDataTypeFixedExponent( S,dataTypeIdU1 );

    totalSlopeU0 = ssGetDataTypeTotalSlope( S, dataTypeIdU0 );
    totalSlopeU1 = ssGetDataTypeTotalSlope( S, dataTypeIdU1 );

    biasU0 = ssGetDataTypeBias( S, dataTypeIdU0 );
    biasU1 = ssGetDataTypeBias( S, dataTypeIdU1 );
}

The functions used above return whether the data types are signed or unsigned, as well as their word lengths, fractional slopes, exponents, total slopes, and biases. Together, these quantities give full information about the fixed-point data types of the input ports.

Set the Output Port Data Type

You may want to set the data type of various ports, run-time parameters, or DWorks in your S-function.

For example, suppose you want to set the output port data type of your S-function. To do this,

  1. Register a data type by using one of the functions listed in the table Data Type Registration Functions. A data type ID is returned.

    Alternately, you can use one of the predefined data type IDs of the Simulink built-in data types.

  2. Use ssSetOutputPortDataType with the data type ID from Step 1 to set the output port to the desired data type.

In the example below from lines 336 - 352 of sfun_user_fxp_const.c, ssRegisterDataTypeFxpBinaryPoint is used to register the data type. ssSetOutputPortDataType then sets the output data type either to the given data type ID, or to be dynamically typed:

/* Register data type
     */
    if ( notSizesOnlyCall )
    {
        DTypeId DataTypeId = ssRegisterDataTypeFxpBinaryPoint(
            S,
            V_ISSIGNED,
            V_WORDLENGTH,
            V_FRACTIONLENGTH,
			1 /* true means obey data type override setting for
					this subsystem */ );

            ssSetOutputPortDataType( S, 0, DataTypeId );
    }
    else
    {
        ssSetOutputPortDataType( S, 0, DYNAMICALLY_TYPED );
    }

Interpret an Input Value

Suppose you need to get the value of the signal on your input port to use in your S-function. You should write your code so that the pointer to the input value is properly typed, so that the values read from the input port are interpreted correctly. To do this, you can use these steps, which are shown in the example code below:

  1. Create a void pointer to the value of the input signal.

  2. Get the data type ID of the input port using ssGetInputPortDataType.

  3. Use the data type ID to get the storage container type of the input.

  4. Have a case for each input storage container type you want to handle. Within each case, you will need to perform the following in some way:

    • Create a pointer of the correct type according to the storage container, and cast the original void pointer into the new fully typed pointer (see a and c).

    • You can now store and use the value by dereferencing the new, fully typed pointer (see b and d).

For example,

static void mdlOutputs(SimStruct *S, int_T tid)
{
    const void *pVoidIn = 
					(const void *)ssGetInputPortSignal( S, 0 ); (1)

    DTypeId dataTypeIdU0 = ssGetInputPortDataType( S, 0 ); (2)
      
    fxpStorageContainerCategory storageContainerU0 =
					ssGetDataTypeStorageContainCat( S, dataTypeIdU0 ); (3)

    switch ( storageContainerU0 )
    {
      case FXP_STORAGE_UINT8: (4)
        {
            const uint8_T *pU8_Properly_Typed_Pointer_To_U0; (a)

            uint8_T u8_Stored_Integer_U0; (b)

            pU8_Properly_Typed_Pointer_To_U0 = 
					(const uint8_T  *)pVoidIn; (c)

            u8_Stored_Integer_U0 = 
					*pU8_Properly_Typed_Pointer_To_U0; (d)
            
            <snip: code that uses input when it's in a uint8_T>
        }
        break;

      case FXP_STORAGE_INT8: (4)
        {
            const int8_T *pS8_Properly_Typed_Pointer_To_U0; (a)

            int8_T s8_Stored_Integer_U0; (b)

            pS8_Properly_Typed_Pointer_To_U0 = 
					(const int8_T  *)pVoidIn; (c)

            s8_Stored_Integer_U0 = 
					*pS8_Properly_Typed_Pointer_To_U0; (d)
            
            <snip: code that uses input when it's in a int8_T>
        }
        break;

Write an Output Value

Suppose you need to write the value of the output signal to the output port in your S-function. You should write your code so that the pointer to the output value is properly typed. To do this, you can use these steps, which are followed in the example code below:

  1. Create a void pointer to the value of the output signal.

  2. Get the data type ID of the output port using ssGetOutputPortDataType.

  3. Use the data type ID to get the storage container type of the output.

  4. Have a case for each output storage container type you want to handle. Within each case, you will need to perform the following in some way:

    • Create a pointer of the correct type according to the storage container, and cast the original void pointer into the new fully typed pointer (see a and c).

    • You can now write the value by dereferencing the new, fully typed pointer (see b and d).

For example,

static void mdlOutputs(SimStruct *S, int_T tid)
{
    <snip>

    void *pVoidOut = ssGetOutputPortSignal( S, 0 ); (1)

    DTypeId dataTypeIdY0 = ssGetOutputPortDataType( S, 0 ); (2)
      
    fxpStorageContainerCategory storageContainerY0 =
					ssGetDataTypeStorageContainCat( S, 
					dataTypeIdY0 ); (3)

    switch ( storageContainerY0 )
    {
      case FXP_STORAGE_UINT8: (4)
        {
            const uint8_T *pU8_Properly_Typed_Pointer_To_Y0; (a)

            uint8_T u8_Stored_Integer_Y0; (b)

          <snip: code that puts the desired output stored integer
				value in to temporary variable u8_Stored_Integer_Y0>
					
            pU8_Properly_Typed_Pointer_To_Y0 = 
					(const uint8_T  *)pVoidOut; (c)

            *pU8_Properly_Typed_Pointer_To_Y0 = 
					u8_Stored_Integer_Y0; (d)
            
        }
        break;

      case FXP_STORAGE_INT8: (4)
        {
            const int8_T *pS8_Properly_Typed_Pointer_To_Y0; (a)

            int8_T s8_Stored_Integer_Y0; (b)

          <snip: code that puts the desired output stored integer
				value in to temporary variable s8_Stored_Integer_Y0>
					
            pS8_Properly_Typed_Pointer_To_Y0 = 
					(const int8_T  *)pVoidY0; (c)

            *pS8_Properly_Typed_Pointer_To_Y0 = 
					s8_Stored_Integer_Y0; (d)
            
        }
        break;

    <snip>

Use the Input Data Type to Determine the Output Data Type

The following sample code from lines 243 through 261 of sfun_user_fxp_asr.c gives an example of using the data type of the input to your S-function to calculate the output data type. Notice that in this code

  


Related Products & Applications

Learn more about Simulink through this collection of videos, articles, technical literature and the Getting Started with Simulink Guide.

 © 1984-2012- The MathWorks, Inc.    -   Site Help   -   Patents   -   Trademarks   -   Privacy Policy   -   Preventing Piracy   -   RSS