Generate Native Half-Precision C Code from Simulink Models
Some embedded hardware targets natively support special types for half precision, such as
_Float16
and _fp16
data types for ARM® compilers. You can generate native half-precision C code for embedded hardware
targets that natively support half precision floating-point data types. The process to
generate native half C code is as follows:
Register a new hardware target device that natively supports half precision using the
target
namespace.Set up the Simulink® model for native half code generation with the new target hardware.
Configure the Simulink model toolchain and set up the compiler for half precision.
Generate native half type code.
Fixed-Point Designer™ includes preconfigured language implementations for Armclang and GCC compilers. For other hardware targets, you can specify a custom language implementation based on your hardware specifications.
Generate Native Half-Precision C Code for ARM Cortex-A with Armclang Compiler
In this example, an ARM Cortex®-A processor is used as the hardware target. The model is configured to use this ARM target and the Armclang compiler toolchain. Refer to the ARM developer documentation for detailed information on using the half-precision data type on this hardware. See Arm Compiler armclang Reference Guide: Half-precision floating-point data types.
Register Target Hardware
Use the target.create
function to create an ARM
Cortex-A processor target that is compatible with half precision.
arm_half = target.create('Processor', ... 'Manufacturer', "ARM Compatible", ... 'Name', 'ARM Cortex-A Half-Precision');
Add the language implementation. The 32-bit version of Clang for ARM has half precision enabled by default. Use target.get
to
retrieve the target object from the internal database.
li = target.get('LanguageImplementation',"Clang ARM 32-bit");
Replace the default language implementation for ARM Cortex with Armclang.
arm_half.LanguageImplementations = li;
Use the target.add
function to add the target object to the internal database.
target.add(arm_half);
Open Half-Precision Model
Open the model for which you want to generate native half-precision C code. The model should use half-precision data types and be configured for code generation.
model = 'simpleHalfModel';
open_system(model);
Set Up Simulink Model with Target Hardware
Optionally, enable the model parameter Inherit floating-point output type smaller than single precision to propagate half precision.
set_param(model,'InheritOutputTypeSmallerThanSingle','on');
Set the code generation target to the ARM target modified for half precision.
set_param(model,'ProdEqTarget','on'); set_param(model,'ProdHWDeviceType',... 'ARM Compatible->ARM Cortex-A Half-Precision');
Set Up Simulink Model with Armclang Compiler Toolchain
Register the Armclang compiler toolchain according to Set Up and Configure Armclang Compiler Toolchain for Code Generation (Embedded Coder).
Set up the Armclang compiler toolchain for code generation.
set_param(model,'SystemTargetFile','ert.tlc'); set_param(model,'GenCodeOnly','off'); set_param(model,'Toolchain','Armclang Compiler'); set_param(model,'BuildConfiguration','Specify');
Configure the Armclang compiler for custom C flags.
compilerOptions = get_param(model,'CustomToolchainOptions'); compilerIdx = find(strcmp(compilerOptions,'C Compiler'));
Add half-precision flags.
appendToCCompilerOptions = ' --target=arm-arm-none-eabi -mcpu=cortex-a75+fp16';
compilerOptions{compilerIdx+1} = strcat(compilerOptions{compilerIdx+1},appendToCCompilerOptions);
Apply the custom toolchain options to the model.
set_param(model,'CustomToolchainOptions',compilerOptions );
You can confirm these settings in the Code Generation pane of the Configuration Parameters dialog box.
Generate Code
Once the model has been set up for the ARM Cortex-A target hardware and the Armclang compiler toolchain, you can generate C code. You can only run the model executable on an ARM target or emulator.
Use the slbuild
function to build a standalone
executable for the model.
slbuild(model);
You can inspect the code generation report to confirm that the custom header and type definitions are used.
The generated code uses the native half-precision data type.
Register ARM Cortex-A with GCC Compiler
In this example, an ARM Cortex-A processor is used as the hardware target. The model is configured to use this ARM target and the GCC compiler toolchain.
Use the target.create
function to create an ARM
Cortex-A processor target.
arm_half = target.create('Processor', ... 'Manufacturer', "ARM Compatible", ... 'Name', 'ARM Cortex-A Half-Precision');
Add the language implementation. The 32-bit version of GCC for ARM has half precision enabled by default. Use the target.get
function to retrieve the target object from the internal database.
li = target.get('LanguageImplementation',"GNU GCC ARM 32-bit");
Replace the default language implementation for ARM Cortex with Armclang.
arm_half.LanguageImplementations = li;
Use the target.add
function to add the target object to the internal database.
target.add(arm_half);
Register ARM Target Hardware with Custom Language Implementation
In this example, you create a new custom language implementation with half precision for a compatible ARM target.
Use the target.create
function to copy the ARM Compatible-ARM
Cortex language implementation.
languageImplementation = target.create('LanguageImplementation',... 'Name','ARM with half',... 'Copy','ARM Compatible-ARM Cortex');
Specify custom half information and target specific headers, as given by your target hardware documentation. For more information, see Register New Hardware Devices.
customHalf = target.create('FloatingPointDataType',... 'Name','BCM2711 Half Type',... 'TypeName','float16_T',... 'LiteralSuffix','f16',... 'Size',16, ... 'SystemIncludes',"arm_fp16.h,arm_neon.h");
languageImplementation.DataTypes.NonStandardDataTypes = customHalf;
Provide information about your target processor.
% Broadcom BCM2711 % Quad core Cortex-A72 (ARM v8) 64-bit SoC pi4a72 = target.create('Processor',... 'Manufacturer','Broadcom',... 'Name','BCM2711');
Add the custom half precision language implementation.
pi4a72.LanguageImplementations = languageImplementation;
Use the target.add
function to add the target object to the internal database.
target.add(pi4a72);
Register Other Hardware Targets for Half Precision
This example uses a Renesas® RH850 to show you how to set up non-ARM targets for half precision.
Use the target.create
function to create the target processor.
prh850 = target.create('Processor', ... 'Manufacturer', 'Renesas', ... 'Name', 'Renesas-RH850 With Half', ... 'Copy', 'Renesas-RH850');
Add the language implementation.
li = target.create('LanguageImplementation',... 'Name', 'Renesas-RH850 with Half', ... 'Copy', 'Renesas-RH850');
Provide additional information the custom half-precision implementation for this hardware.
customHalf = target.create('FloatingPointDataType',... 'Name','Renesas Half Type'); customHalf.TypeName = '__fp16'; customHalf.Size = 16; customHalf.LiteralSuffix = ''; customHalf.SystemIncludes = '';
Add the custom half-precision data type.
li.DataTypes.NonStandardDataTypes = customHalf; prh850.LanguageImplementations = li;
Use the target.add
function to add the target object to the internal database.
target.add(prh850);
See Also
target.FloatingPointDataType
| target.add
| target.create
| target.get
| target.remove
Related Topics
External Websites
- Clang Language Extensions for Half-Precision Floating Point
- Arm Compiler armclang Reference Guide: Half-precision floating-point data types
- GCC Half-Precision Floating Point
- Reduce the Program Data Size with Ease! Introducing Half-Precision Floating-Point Feature in Renesas Compiler Professional Edition