How can I use int64 and uint64 with my Simulink S-function?

40 views (last 30 days)
How can I use int64 and uint64 with my Simulink S-function?

Accepted Answer

Andy Bartlett
Andy Bartlett on 11 Feb 2022
Edited: Andy Bartlett on 18 Oct 2023
Two Key Headers for 64-bit Integers in Simulink S-functions.
To use 64 bit integers, your S-function should include these two headers.
#include "simstruc.h"
#include "fixedpoint.h"
APIs Handle Any WordLength
APIs available in those two headers can handle any WordLength. That includes 8-bits for a uint8, 64-bits for an int64, 123-bits for a fixed-point sfix123 type, and anything from 1-bit up to the maximum supported in the Simulink environment.
To see a very simple, example open this shipping S-function.
edit sfun_user_fxp_ContainWordLenProbe.c
Notice the lines contain this code
dataTypeId = ssGetInputPortDataType(S,0);
<snip>
y[0] = ssGetDataTypeFxpContainWordLen(S,dataTypeId);
That code will provide the WordLength of any input using an integer or fixed-point type. Any integer naturally includes Simulink's eight basic integers int8, uint8, int16, uint16, int32, uint32, int64, and uint64.
Registering a 64 bit integer type
Simulink requires data types to be register to use them with declared data such as inport, outports, states, etc. Once a type is registered, it will have been assigned an integer valued DTypeId.
To register int64 and uint64, the APIs can be used like this.
/* In R2020a or later, these simplified APIs can be used.
*/
DTypeId dtId_Int64 = ssRegisterDataTypeInteger(S,1,64,0);
DTypeId dtId_Uint64 = ssRegisterDataTypeInteger(S,0,64,0);
or
/* In any release, an older API requiring one extra argument of 0 can be used.
*/
DTypeId dtId_Int64 = ssRegisterDataTypeFxpBinaryPoint(S,1,64,0,0);
DTypeId dtId_Uint64 = ssRegisterDataTypeFxpBinaryPoint(S,0,64,0,0);
To learn more about this API read the header comments for this function in:
edit([matlabroot,'/simulink/include/fixedpoint.h'])
Once a data type has been registered, all the APIs involving DTypeIds can be used. For example, you can specify that input ports and outputs ports will use that data type.
ssSetInputPortDataType( S,3,dtId_Int64); // 4th input port uses int64
ssSetOutputPortDataType(S,1,dtId_Uint64); // 2nd output port uses uint64
Testing if a DTypeId is 64-bit integer
Two ways to test if a DTypeId is a 64-bit integer will be described here.
The first approach is to compare DTypeIds.
/* In R2020a or later */
DTypeId dtId_Int64 = ssRegisterDataTypeInteger(S,1,64,0);
DTypeId dtId_Uint64 = ssRegisterDataTypeInteger(S,0,64,0);
/* or in any release
* DTypeId dtId_Int64 = ssRegisterDataTypeFxpBinaryPoint(S,1,64,0,0);
* DTypeId dtId_Uint64 = ssRegisterDataTypeFxpBinaryPoint(S,0,64,0,0);
*/
DTypeId dtId_input0 = ssGetInputPortDataType(S,0);
bool input0Is64BitInt = (dtId_input0 == dtId_Int64) || (dtId_input0 == dtId_Uint64);
The second approach is to test the attributes.
/* In R2020a or later
*/
DTypeId dtId_input0 = ssGetInputPortDataType(S,0);
bool input0Is64BitInt = ssGetDataTypeIsSpecifiedInteger(S,dtId_input0,0,64) ||
ssGetDataTypeIsSpecifiedInteger(S,dtId_input0,1,64);
Important: When mex'ing your S-Function give link option -lfixedpoint
When you mex you S-Function, you need to specify where it can link to the libraries that provide the type registration functions. To do that just append the argument -lfixedpoint to the mex argument list, like so.
mex('sfun_user_fxp_asr.c','-lfixedpoint')
If your S-Function complaints that it can't find ssRegister... or another of the APIs from fixedpoint.h, then you need to mex it again and provide the link option, -lfixedpoint.
Why do I have to register the 64-bit types?
MathWorks' Simulink products provide a rich variety for numeric types for floating-point, integers, and fixed-point. The number of distinct numeric types exceeds 10^40. Dynamically registering types and dynamically handing out DTypeIDs to only the small number of types used in any one model is the only way for this breadth of possibilities to scale.
There are a small number of exceptions to the dynamic design. Types that were commonly available on workstations of the 1990s such as double, single, boolean, int8, uint8, int16, uint16, int32, and uint32 are always pre-registered with Simulink models and have statically known DTypeId such as SS_DOUBLE and SS_UINT8, see section on Preassigned Data Type IDs. This old set of static DTypeId has not been extended in favor using using the more general registration approach.
FAQ Answer: Using API only requires Simulink to be installed.
Both S-function API sets
#include "simstruc.h"
#include "fixedpoint.h"
are installed whenever Simulink is installed. No product beyond Simulink needs to be installed.
If you are worried that "fixedpoint.h" requires Fixed-Point Designer to be installed, then stop worrying. Simulink is sufficient.
FAQ Answer: Calling API for 64 bit ints only requires Simulink license.
As of R2017a and later, using the APIs with int64 and uin64 only requires a Simulnk license.
So in R2017a and later, calling these two APIs like so would need just a Simulink license.
/* API for R2020a and later */
DTypeId dtId_Int64 = ssRegisterDataTypeInteger(S,1,64,0);
DTypeId dtId_Uint64 = ssRegisterDataTypeInteger(S,0,64,0);
The equivalent older APIs also just need a Simulink license in R2017a and later.
/* Older APIs can be used for any release */
DTypeId dtId_Int64 = ssRegisterDataTypeFxpBinaryPoint(S,1,64,0,0);
DTypeId dtId_Uint64 = ssRegisterDataTypeFxpBinaryPoint(S,0,64,0,0);
Likewise calling the APIs for other types in base Simulink, such as int8, uint8, int16, uint16, int32, and uint32, has never required more than a Simulink license.
/* API for R2020a and later */
DTypeId dtId_Int8 = ssRegisterDataTypeInteger(S,1, 8,0); // returns SS_INT8
DTypeId dtId_Uint8 = ssRegisterDataTypeInteger(S,0, 8,0); // returns SS_UINT8
DTypeId dtId_Int16 = ssRegisterDataTypeInteger(S,1,16,0); // returns SS_INT16
DTypeId dtId_Uint16 = ssRegisterDataTypeInteger(S,0,16,0); // returns SS_UINT16
DTypeId dtId_Int32 = ssRegisterDataTypeInteger(S,1,32,0); // returns SS_INT32
DTypeId dtId_Uint32 = ssRegisterDataTypeInteger(S,0,32,0); // returns SS_UINT32
An alternate API if you need to work with any release, before or after R2020a is as follows. These older APIs have also never required more than a Simulink license for registration of int8, uint8, int16, uint16, int32, and uint32.
/* An older API can be used for any release */
DTypeId dtId_Int8 = ssRegisterDataTypeFxpBinaryPoint(S,1, 8,0,0); // returns SS_INT8
DTypeId dtId_Uint8 = ssRegisterDataTypeFxpBinaryPoint(S,0, 8,0,0); // returns SS_UINT8
DTypeId dtId_Int16 = ssRegisterDataTypeFxpBinaryPoint(S,1,16,0,0); // returns SS_INT16
DTypeId dtId_Uint16 = ssRegisterDataTypeFxpBinaryPoint(S,0,16,0,0); // returns SS_UINT16
DTypeId dtId_Int32 = ssRegisterDataTypeFxpBinaryPoint(S,1,32,0,0); // returns SS_INT32
DTypeId dtId_Uint32 = ssRegisterDataTypeFxpBinaryPoint(S,0,32,0,0); // returns SS_UINT32
If you are worried by the header name "fixedpoint.h" or by the older API name containing "FxpBinaryPoint" that a Fixed-Point Designer license will be pulled, then you do NOT need to worry if you are just handling the 11 base types from Simulink, double, single, boolean, int8, uint8, int16, uint16, int32, uint32, and as of R2017a int64 and uint64 too.
If you are using R2016b or earlier, then ANY use of 64 bit integers for Simulink signals would require a Fixed-Point Designer license. But as of the latest update to this FAQ, that's 6.5 years and 13 releases in the past. If that's an issue, your next release upgrade will solve it.
If the APIs were used to register other numeric data types such as a custom 13 bit integer, a type with a fixed-point scaling, or half-precision floating-point, then Fixed-Point Designer license pull is to be expected. For example, registering a custom sized 57-bit integer data type would be expected to require pulling Fixed-Point Designer license.
DTypeId dtId_Int64 = ssRegisterDataTypeInteger(S,1,57,0);
The API is not the cause of the license need; its the use of a data type not provided in base Simulink.
FAQ Answer: Do I need to #include fixedpoint.c too?
No, you do not need to #include fixedpoint.c in your S-Function. That file stopped serving a necessary role many years ago and can be ignored.
  2 Comments
David Niemann
David Niemann on 16 Nov 2022
Edited: Stefanie Schwarz on 18 Oct 2023
Andy Bartlett you should also mention that you need to include "fixedpoint.c" at the bottom of the s-function.
Stefanie Schwarz
Stefanie Schwarz on 18 Oct 2023
Edited: Stefanie Schwarz on 18 Oct 2023
This doc page summarizes the requirements for any user-written fixed-point S-functions:
As of R2023b, they are the following:
  • In your S-function, include fixedpoint.c and fixedpoint.h. For more information, see Structure of the S-Function.
  • Pass an extra argument, -lfixedpoint, to the mex command. For example: mex('sfun_user_fxp_asr.c','-lfixedpoint')

Sign in to comment.

More Answers (0)

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!