📄 embOS-Classic Real-Time Operating System User Guide & Reference Manual for embOS-Classic and embOS-Classic-MPU
📄 embOS-Ultra Real-Time Operating System User Guide & Reference Manual for embOS-Ultra and embOS-Ultra-MPU
📄 emCompress-Embed User Guide & Reference Manual
📄 emCompress-LZMA User Guide & Reference Manual
📄 emCompress-Pro User Guide & Reference Manual
📄 emCompress-ToGo User Guide & Reference Manual
📄 emCrypt User Guide & Reference Manual
📄 emDropbox User Guide & Reference Manual
📄 emFile User Guide & Reference Manual
📄 emFloat User Guide & Reference Manual
📄 emNet User Guide & Reference Manual
📄 emRun User Guide & Reference Manual
📄 emSecure-ECDSA User Guide & Reference Manual
📄 emSecure-RSA User Guide & Reference Manual
📄 emSSH User Guide & Reference Manual
📄 emSSL User Guide & Reference Manual
📄 emUSB-Device User Guide & Reference Manual
📄 emUSB-Host User Guide & Reference Manual
📄 emVNC User Guide & Reference Manual
📄 emWeb User Guide & Reference Manual
📄 emWin User Guide & Reference Manual
📄 IoT Toolkit User Guide & Reference Manual
📄 Ozone-Sim Manual
📄 SEGGER Assembler User Guide & Reference Manual
📄 SEGGER Compiler User Guide & Reference Manual
📄 SEGGER Linker User Guide & Reference Manual
📄 SEGGER SystemView User Guide
📄 SEGGER Online Documentation
📄 AppWizard User Guide & Reference Manual
📄 emApps User Guide & Reference Manual

emApps User Guide & Reference Manual

Small applications for embedded systems.

emApps 1.24.0, June 26, 2026

Introducing emApps

This section presents an overview of emApps, its structure, and its capabilities.

Getting started

This chapter explains how to get started with emApps by using simple examples that can be run on the desktop.

Terminology

This document uses the following conventions to avoid confusion:

Where to find things

The emApps distribution is divided into a number of folders:

Folder Content
Doc emApps documentation including the reference guide and release notes.
Bin All tools, including the emApps C Compiler and the emApps Desktop Executor.
Apps Source code of demonstration applications that can be run on the desktop and on a SEGGER Flasher. Files in this folder act as examples and can be customized as required.
Src Source code of the emApps loader and executor. This is compiled into a program that intends to run emApps applications. Files in this folder must not be modified.
Inc Public header files that define the API provided by the emApps product to the program. The functions defined in these headers are implemented by the source files in the Src and Etc folders. Files in this folder must not be modified.
Config Configuration files that customize how the emApps product is built, selecting both features and capabilities. Files in this folder are intended to be edited to configure emApps facilities.
Etc Additional source code that demonstrates how to provide features to an application by adding code to the program. Files in this folder act as examples and can be customized as required.

Distributed tools

Two tools are provided in the distribution:

The C compiler translates source code, written in C, into executable code. The emApps desktop executor takes the executable code, loads it, and then executes it in a sandbox.

The compiler and executor are shipped in the Bin folder of the distributions.

Hello, world!

This section will describe how to compile and run the ubiquitous “Hello, World!” application. It skips irrelevant details and concentrates on a simple application running on the desktop as soon as possible.

Get ready

Open up a command-line environment, such as a Windows Command Prompt:

Microsoft Windows [Version 10.0.26200.7171]
(c) Microsoft Corporation. All rights reserved.

C:> _

Add the emApps Bin folder to the search path. For example, if emApps is installed to C:\Work\SEGGER\emApps, use:

C:> set PATH=C:\Work\SEGGER\emApps\Bin;%PATH%
C:> _

Check that both the emApps C compiler s32cc and emApps Desktop Executor apprun are found and execute:

C:> s32cc

SEGGER S32 C Compiler V4.16.0 compiled Nov 27 2026 03:39:06
Copyright (c) 2023-2026 SEGGER Microcontroller GmbH    www.segger.com

Usage:
  s32cc [option...] file

Control:
  -v, --verbose             Run in verbose mode

...and so on...

Notes:
  Use '--extra-help' for more detailed help.

C:> apprun

SEGGER emApps Desktop Executor V1.10.0 compiled Nov 28 2026 14:30:57
Copyright (c) 2008-2026 SEGGER Microcontroller GmbH  www.segger.com

Usage:
  AppRun [option...] file

Options:
  -nfunc      Execute 'func' after loading                  [default: main]
  -t          Trace instructions executed
  -s          Trace lines executed
  -r          Include register dump (before execution) in instruction trace

...and so on...

Streams:
  stdout - Application output.
  stderr - Trace and message output.

C:> _

Select the application

With that done, navigate to the folder containing the source code of the demonstration applications directory, Apps\Src:

C:> cd \Work\SEGGER\emApps\Apps\Src
C:> _

In there will be a few demonstration applications:

C:> dir /b
Default.h
DemoAckermann.c
DemoDhrystone_100k.c
DemoDhrystone_2k.c
DemoHelloWorld.c
DemoPrimes.c
DemoSieve.c

C:> _

The simplest application is DemoHelloWorld.c:

C:> more DemoHelloWorld.c
void main(void) {
  printf("Hello, world!\n");
}

C:> _

This is the application’s source code, is known worldwide to programmers, and can’t be any simpler.

Compile the application

The emApps executor does not run this source code directly. The human-readable source code must be translated to machine code for execution by compiling it.

Compile the application:

C:> s32cc DemoHelloWorld.c

SEGGER S32 C Compiler V4.16.0 compiled Nov 28 2026 15:26:55
Copyright (c) 2023-2026 SEGGER Microcontroller GmbH    www.segger.com

Files written to disk:
  DemoHelloWorld.pex       120 bytes   App executable
  DemoHelloWorld.lst      6590 bytes   App listing

Exported functions:
  main()                8 bytes stack

Application size:
     20 bytes code
     25 bytes data
      0 bytes xdata
      3 bytes alignment
      8 bytes stack
  ------------------------------------
  56 bytes total runtime image size

Compilation complete: 0 errors.

C:> _

The verbose output from compilation can safely be ignored for now, it’s good enough to know that the application compiled without error: 0 errors.

The compiler takes the source code, checks that it is a valid program, and writes a file containing the machine-executable code and other structural information to a file with a .pex file extension, in this case DemoHelloWorld.pex.

The application is now ready to be run as an emApp.

Run the application

Running, or executing, the application requires an emApps sandbox environment. On the desktop, this is provided by the emApps Desktop Executor, AppRun.

To execute the application and see what it does, invoke AppRun and provide the executable-code file DemoHelloWorld.pex:

C:> apprun DemoHelloWorld.pex

SEGGER emApps Desktop Executor V1.20.0 compiled May 20 2026 11:15:42
Copyright (c) 2008-2026 SEGGER Microcontroller GmbH  www.segger.com

Hello, world!

Execution complete:
  'main()' returned 0.

C:> _

That’s it. The output is printed along with some additional information. To hide the program’s output and show only the application’s output, redirect the standard error output to the NUL device:

C:> apprun DemoHelloWorld.pex 2>NUL
Hello, world!

C:> _

Benchmark your machine

Compiling and running other demonstration applications is just as easy. Try compiling the Dhrystone_100k application and run it to compare your machine’s performance to a MacBook Pro (M2 Max) running emApps:

C:> apprun DemoDhrystone_100k.pex

SEGGER emApps Desktop Executor V1.20.0 compiled May 20 2026 11:05:33
Copyright (c) 2008-2026 SEGGER Microcontroller GmbH  www.segger.com

306748 Dhrystones/s, 174 DMIPS

Execution complete:
  'main()' returned 0.

C:> _

If application telemetry is inhibited, Dhrystone performance improves from 174 DMIPS to 194 DMIPS:

C:> apprun -f DemoDhrystone_100k.pex

SEGGER emApps Desktop Executor V1.20.0 compiled May 20 2026 11:05:33
Copyright (c) 2008-2026 SEGGER Microcontroller GmbH  www.segger.com

342465 Dhrystones/s, 194 DMIPS

Execution complete:
  'main()' returned 0.
  
C:> _

Note: As shipped, the desktop executor supports application telemery, tracing, and profiling which would not be present in an embedded production produce. If the program is configured without these features, execution performance doubles.

The statistic that benchmarks the performance of the S32 in MIPS is only presented when the application takes more than 100 ms to complete.

Apps on real hardware

Running an application on the desktop is convenient, but emApps is designed primarily to execute within an embedded system. Fortunately, SEGGER has been using the technology behind emApps for years and it is deployed in Flashers.

Flashers can run these demonstration applications without modification. To do so, make sure that the Flasher Software and Documentation Pack, version 8.90 or later is installed and that the Flasher’s firmware is up to date—use Flasher Configurator to update the Flasher’s firmware if required.

The default installation directory for the Flasher software V8.90 on Windows is /Program Files/SEGGER/Flasher_V890. Add this to the path:

C:> set PATH=C:\Program Files\SEGGER\Flasher_V890;%PATH%
C:> _

Check that the Flasher App Runner utility is found and executes:

C:> flasherrun --version
SEGGER Flasher App Runner Utility V8.94 (Compiled Dec 10 2026 15:16:51)
Copyright (c) 2026-2026 SEGGER Microcontroller GmbH    www.segger.com
DLL version V8.94, compiled Dec 10 2026 14:54:09

C:> _

Check that the correct directory is selected:

C:> cd
\Work\SEGGER\emApps\Apps\Src

C:> _

Plug in the Flasher and run the “Hello, World!” and Dhrystone applications on the Flasher using FlasherRun, in just the same way as they are run on the desktop using AppRun:

C:> flasherrun DemoHelloWorld.pex
SEGGER Flasher App Runner Utility V8.90 (Compiled Nov 26 2026 17:52:51)
Copyright (c) 2026-2026 SEGGER Microcontroller GmbH    www.segger.com
DLL version V8.90, compiled Nov 26 2026 17:29:40

Connecting to Flasher via USB...O.K.
Firmware: J-Link / Flasher Compact V7 compiled Nov 26 2026 15:58:58
Hardware version: V7.00
Flasher uptime (since boot): 0d 00h 02m 39s
License(s): JFlash, GDB
USB speed mode: High speed (480 MBit/s)
VTref=0.000V
Successfully loaded '\Work\SEGGER\emApps\Apps\Src\DemoHelloWorld.pex'.
Executing app... (press <Enter> to cancel)
  Hello, world!

App execution finished with return value 0 after 0.031ms.

C:> flasherrun DemoDhrystone_100k.pex
SEGGER Flasher App Runner Utility V8.90 (Compiled Nov 26 2026 17:52:51)
Copyright (c) 2026-2026 SEGGER Microcontroller GmbH    www.segger.com
DLL version V8.90, compiled Nov 26 2026 17:29:40

Connecting to Flasher via USB...O.K.
Firmware: J-Link / Flasher Compact V7 compiled Nov 26 2026 15:58:58
Hardware version: V7.00
Flasher uptime (since boot): 0d 00h 00m 49s
License(s): JFlash, GDB
USB speed mode: High speed (480 MBit/s)
VTref=0.000V
Successfully loaded '\Work\SEGGER\emApps\Apps\Src\DemoDhrystone_100k.pex'.
Executing app... (press <Enter> to cancel)
  30969 Dhrystones/s, 17 DMIPS

App execution finished with return value 0 after 3229.743ms.

C:> _

A brief aside for the technically curious

From using AppRun on the desktop, we know Dhrystone executes 93,300,642 instructions on the S32E virtual CPU. The Flasher accomplishes this in 3,229,743 microseconds. Therefore, the Flasher executes applications at approximately 30 million instructions per second.

Summary

This has been a brief, simplified tour of emApps that demonstrates some of its major features. emApps offers more capabilities than those demonstrated here and the following sections will describe how to extend the software to expose emApps for use by internal and external customers.

Running applications

This chapter describes how load and run applications.

Built-in applications

An application would typically be loaded from disk or from a network connection in order that it can be updated or extended when new features or bug fixes become available. Being able to replace the application clearly means it can’t be compiled into the program as that would mean it’s almost impossible to replace.

It can be desirable, though, to build an application into the program so that it is always available. In this way, a hardware test application compiled into the program is always ready, as is some system configuration or recovery application, if desired. Delivering prebuilt applications in this manner is just another way of using applications and emApps.

Preparing a built-in application

This section explains how to load and run “Hello, World!” as a built-in application. The program is straightforward, simple to describe, and easy to understand.

The application’s executable image is already provided as a built-in application in the file Apps/Src/DemoHelloWorld_pex.h. The program to load and execute the “Hello, World!” application is contained in the file Apps/Prj/RunHelloWorld.c.

To generate a built-in application with the emApps C compiler, use the --embed option. The built-in “Hello, World!” application is created as follows:

C:> s32cc --embed DemoHelloWorld.c

SEGGER S32 C Compiler V4.16.0 compiled Nov 28 2026 15:26:55
Copyright (c) 2023-2026 SEGGER Microcontroller GmbH    www.segger.com

Files written to disk:
  DemoHelloWorld.pex         120 bytes   App executable
  DemoHelloWorld_pex.h       679 bytes   Built-in executable
  DemoHelloWorld.lst        6065 bytes   App listing

Exported functions:
  main()                8 bytes stack

Application size:
     20 bytes code
     25 bytes data
      0 bytes xdata
      3 bytes alignment
      8 bytes stack
  ------------------------------------
  56 bytes total runtime image size

Compilation complete: 0 errors.

C:> _

An additional output file that ends _pex.h contains a declaration of an array initialized to the binary content of the equivalent emApps executable file:

C:> more DemoHelloWorld_pex.h
static const unsigned char _aDemoHelloWorld[] = {
  0x50, 0x43, 0x56, 0x32, 0x08, 0x00, 0x00, 0x00,
  0x2C, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
  0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
  0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x00,
  0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x65,
  0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x77, 0x6F, 0x72,
  0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00, 0xC6, 0x00,
  0x07, 0x10, 0x93, 0x00, 0x00, 0x00, 0x06, 0x00,
  0x0B, 0x00, 0x00, 0x00,
};

C:> _

The load-and-go code

The following lays out the load and execution process:

int main(void) {
  S32_EXEC_GEO       Geo;
  S32_EXEC_CONTEXT   Ctx;
  S32_U8           * pImage;
  S32_I32            Status;
  //
  if (S32_CheckConfig() != S32_ERROR_NONE) {
    printf("S32 configuration check failed\n");
    exit(EXIT_FAILURE);
  }
  //
  pImage = NULL;
  Status = S32_InitGeo(&Geo,   
                       _aServices,
                       sizeof(_aServices)/sizeof(_aServices[0]));
  if (Status >= 0) {
    Status = S32_LoadHeader(&Geo, _aDemoHelloWorld, sizeof(_aDemoHelloWorld));   
    if (Status >= 0) {
      pImage = malloc(sizeof(_aDemoHelloWorld) + Status);   
      if (pImage == NULL) {
        Status = S32_ERROR_OUT_OF_MEMORY;
      } else {
        memcpy(pImage, _aDemoHelloWorld, sizeof(_aDemoHelloWorld));   
        Status = S32_LoadFile(&Geo, pImage);   
        if (Status >= 0) {
          Status = S32_PrepareByName(&Geo, &Ctx, "main");   
          if (Status >= 0) {
            Status = S32_Exec(&Ctx);   
          }
        }
      }
    }
  }
  //
  free(pImage);   
  printf("\n*** Application exited with %s (%d)\n", S32_GetErrorText(Status), Status);
  //
  return Status;

The steps are:

  Initialize geometry

To prepare loading an application, the application geometry structure must be initialized. Application geometry is used to locate each section in the PEX file and is updated as loading progresses. In addition, an array of service bindings are presented that enumerate the services available to an application. This will be discussed in detail later, but for now the table contains a single entry that exposes printf to be used by the application, and only printf. The geometry is not needed when it comes to execution so can be disposed of after loading.

  Load the header

After initializing the geometry, the header is presented for verification. Only the first 32 bytes of the header need be presented: if more are presented, the excess will be ignored, and if fewer are presented, the file is invalid and an error is returned.

The value returned from S32_LoadHeader() is negative when an error occurs; a return value that is zero of greater indicates the number of additional bytes that must be allocated beyond the application file’s image to run the application. The exact details of this will be discussed later, and for the “Hello World!” application this number is zero.

  Allocate space to run the application

The memory used to execute the image is entirely allocated by the program: the emApps library does not use malloc() or free() internally. This step allocates the space for the application file, plus any additional requirement reported by S32_LoadHeader(). This example uses malloc(), but equally some other memory-allocation function could be used, or even a fixed-size static array.

  Prepare the execution image

Once memory is allocated for the image, the entire PEX file must be copied to the start. memcpy() is used here to copy the file stored in a static array into the memory allocated for execution.

  Validate the image

Now that the image is in read-write memory, it can be fully validated and all references to service functions that it uses can be resolved. The loader is very careful to examine the structure of the application file in memory, ensuring that it is not damaged in an unintentional or malicious manner. To do this, each offset and reference within the application image is validated to ensure it is entirely contained in the image.

The loader processes the list of imports in the application and matches them to the the service bindings given to S32_InitGeo(). If an import is required by the application but is not present in the API service table, an error is returned by S32_LoadFile() and the application must not be executed.

  Prepare to execute

The image is loaded and validated and passes all integrity checks and all imports are available. The function to execute, in this case main() is prepared to run using S32_PrepareByName(). The arguments to this function are the geometry, an execution context, and the name of the function to run. The execution context, which contains the state of the virtual machine, is entirely initialized by calling S32_PrepareByName() and is not initialized separately.

If the function cannot be found in the application’s export list, an error is returned.

  Execute the function

If all the previous steps execute correctly, execution can commence. Execution of the function is started by calling S32_Exec() with the execution context. The application runs until the top-level function called returns or an exception is raised.

  Wrap up

Once execution returns to the program, the memory used for the application can be freed and the value returned from executing the application’s main() is used as an exit code.

Example run

When compiled and run, this output is:

C:> RunHelloWorld

Hello, world!

*** Application exited with no error (0)

C:> _

Using multiple entry points

All applications presented so far have run to completion and stopped. This section will present another way of calling applications, essentially as a library of functions or as a dynamic-link library, to perform some actions, maintaining state between each call.

Laying out the application

The following is an application that exports three entry points: Init(), Main(), and Fini():

#pragma S32C export("Init");   
#pragma S32C export("Main", Fini);

static int Data = 10;   

void Init(void) {
  printf("In Init(), Data=%d\n", Data);   
  Data += 1;   
}

void Main(void) {
  printf("In Main(), Data=%d\n", Data);   
  Data += 2;   
}

void Fini(void) {
  printf("In Fini(), Data=%d\n", Data);   
  Data += 3;   
}

  Export entry points

The compiler must be told which functions to export as entry points. The entry points are published using #pragma S32C export which takes the name of the function to export. The pragma will accept function names with or without quotation marks according to preference, and will accept a comma-separated list of such names.

  Declare static data

Any data declared with static storage class will retain values over the lifetime of the application. In this application, Data will be updated by successive entry points and its value displayed prior to update.

  Display current data on each entry

Each entry point displays the value of Data immediately on entry.

  Update the state

Each entry point then alters the value of Data as part of its execution.

A preview of expected output

The code to call the three entry points is presented in the following section. Concentrating on the application, if the three functions Init(), Main(), and Fini() are called in that order by C code, the expected output is:

In Init(), Data=10
In Main(), Data=11
In Fini(), Data=13

Similarly, if those three emApps entry points are executed from a program, the output will be identical: static data retains its state between executions.

Executing entry points

This section demonstrates how to call the three entry points in sequence. The application’s executable image is already provided as a built-in application in the file Apps/Src/DemoMultiEntry_pex.h. The program to load and execute the application is contained in the file Apps/Prj/RunMultiEntry.c.

Loading the application follows the same steps as the “Hello, World!” application. Once loaded, the multi-entry application can be queried to expose one, some, or all of its entry points. The presence of a single named entry point can be queried using S32_FindExport() and prepared for execution using S32_PrepareByAddr():

int InitAddr;
int FiniAddr;
int MainAddr;
//
InitAddr = S32_FindExport(&Geo, "Init");   
FiniAddr = S32_FindExport(&Geo, "Fini");
MainAddr = S32_FindExport(&Geo, "Main");
//
if (InitAddr >= 0) {   
  if (S32_PrepareByAddr(&Geo, &Ctx, InitAddr) >= 0) {   
    S32_Exec(&Ctx);   
  }
}
//
if (MainAddr >= 0) {   
  S32_PrepareByAddr(&Geo, &Ctx, MainAddr);
  S32_Exec(&Ctx);
}
//
S32_PrepareByAddr(&Geo, &Ctx, FiniAddr);   
S32_Exec(&Ctx);

  Find entry points by name

Use S32_FindExport() to find the entry point, passing the application geometry and the entry point name. The entry point is the name of the exported function without parentheses. In this case, three entry points are looked up. The application will call Init() if it exists, followed by Main() if it exists, followed by Fini() if it exists.

  Check if Init() exists

If the entry point for Init() does not exist or the executable image has been corrupted in a detectable manner, an negative error status is returned. This will be either S32_ERROR_NOT_FOUND or S32_ERROR_BAD_PEX_FILE.

  Prepare for execution

Once the entry point is determined, it can be prepared for execution using S32_PrepareByAddr(). In normal operation, the address returned from S32_FindExport() will be valid and S32_PrepareByAddr() will also succeed with this address, but S32_PrepareByAddr() checks the address for validity anyway to ensure that the application is prepared correctly.

  Execute Init()

After preparation is complete, the application is ready to launch, so it can be started using S32_Exec().

  Abbreviated execution of Main()

This fragment of code checks that Main() exists as an entry point, and then proceeds to prepare for execution and executes it. It does not check that preparation succeeds as, if preparation fails, an exceptional condition is registered in the execution context and any attempt to execute will immediately fail.

  Minimal execution of Fini()

This fragment of code takes brevity even further: any negative value is never a valid address, so S32_PrepareByAddr() will immediately fail, and so will S32_Exec(). Of course, it is better programming style to check for errors when they occur, this is simply an example demonstrating that detected errors do not cause erratic execution of random application code.

Passing parameters to functions

All applications presented so far have executed functions that take no parameters and return no result. This section describes how to pass parameters to functions and how to retrieve the value returned by a function. The application’s executable image is already provided as a built-in application in the file Apps/Src/DemoParaPassing_pex.h. The program to load and execute the application is contained in the file Apps/Prj/RunParaPassing.c.

Laying out the application

The following application exports a function that computes the y coordinate of a straight line given the x coordinate, the slope of the line m, and its y intercept c:

#pragma S32C export(CalcY)

int CalcY(int x, int m, int c) {
  return m*x + c;
}

Calling the function

The function CalcY requires three integer parameters, x, m, and c and returns an integer result. Preparing to call this function is straightforward, it uses the same framework to determine the application geometry and prepare a function for execution presented before. Once prepared, the parameters are pushed to the stack before execution commences. The following code calls the function passing three parameters and retrieves the function result.

Status = S32_PrepareByName(&Geo, &Ctx, "CalcY");
if (Status >= 0) {
  S32_Push(&Ctx, 10);  
  S32_Push(&Ctx, 3);
  S32_Push(&Ctx, 7);
  Status = S32_Exec(&Ctx);  
  if (Status >= 0) {  
    printf("Calculated Y value is %d\n", S32_GetResult(&Ctx));  
  }
}

  Push the parameters

After preparing a function for execution, the parameters are pushed to the stack in reverse order, which is the standard convention for the C programming language. The function is invoked with x=7, m=3, and c=10.

  Execute the function

After pushing the parameters, the function is executed. The result of execution is returned—this is not the result of the function, but a standard status code indication successful or exceptional execution.

  Proceed only if not exceptional

If execution of the function completed without raising an exception, the value returned by S32_Exec() is nonnegative. If the function completed normally, execution continues to retrieve the function result.

  Retrieve function result

The function result is returned by S32_GetResult(). This is the value that is returned by the function after normal execution: if the execution is terminated by an exception, the value returned by S32_GetResult() is not defined.

In this case, the value returned is 31 which is 3×7 + 10.

Finding and executing services at runtime

Direct references made to functions that the application uses, offered by the program through the populated API service table, are resolved when an application is loaded. If the named service is not present, loading fails with a “not found” error.

It may be convenient to dynamically determine, when the application is running, whether a service is offered by the program or not. This can be used to introduce updated product models that offer better performance by moving compute-heavy code into the program, but otherwise continue to work on older harware, whilst the application’s executable is the same across all models. Or it might be used to run the same application on base models and more featureful models, adapting behavior as necessary.

Preparing for service lookup

The service lookup feature is exposed to the application developer through Default.h as follows:

/*********************************************************************
*
*       Introspection functions
*/
__imp int      SYS_FindService(const char *sName);
__imp unsigned SYS_ExecService(int ServiceHandle, ...);

To support service lookup in the program, the functions SYS_FindService() and SYS_ExecService() must be present in the API table, mapping to S32_API_S32_FindService() and S32_API_S32_ExecService():

static S32_SERVICE_BINDING _aServices[] = {
  { "SYS_FindService", S32_API_S32_FindService },
  { "SYS_ExecService", S32_API_S32_ExecService },
  ...
};

Finding and executing service functions

The following program uses the introspection feature to see whether printf() is an installed service and, if it is, calls it to print a message. This program is contained in the file Apps/Src/DemoFindService.c.

int main(void) {
  int PrintfHandle;   
  //
  PrintfHandle = SYS_FindService("printf");   
  if (PrintfHandle > 0) {
    SYS_ExecService(PrintfHandle, "Hello, %s!\n", "World");   
    return 0;
  } else {
    return PrintfHandle;
  }
  return 0;
}

  Declare a handle

Service functions that are looked up at runtime are not invoked by calling through a function pointer. Instead, a handle is used that refers to the particular service. This declares such a handle.

  Look up the service function

The function S32_FindSevice() takes a service function name, without parentheses, and returns a handle that identifies the service. If the service is not found, the handle is a negative error code.

  Execute the service

As explained above, the service is not invoked through a function pointer, but by S32_ExecService() which calls the particular service, passing through the provided arguments. Note that it is the user’s responsibility to provide the correct number of arguments, each of of the correct type, to match the prototype of the invoked service function.

Bechmarking S32 against native code

The following application benchmarks strcpy() written in S32 instructions against a version provided by the program, if such a service function exists.

This program is contained in the file Apps/Src/DemoBenchStrcpy.c.

char aDst[8192];
char aSrc[8192];

int main(void) {
  unsigned T;
  int      StrcpyHandle;
  int      i;
  //
  StrcpyHandle = SYS_FindService("strcpy");
  //
  if (StrcpyHandle > 0) {
    //
    printf("strcpy() is present as a service function\n\n");
    printf("Benchmarking:\n\n");
    //
    memset(aSrc, 'x', 8191);
    //
    T = SYS_GetTime_ms();
    for (i = 0; i < 2000; ++i) {
      strcpy(aDst, aSrc);
    }
    T = SYS_GetTime_ms() - T;
    printf("  strcpy() using S32 code: %5d ms\n", T);
    //
    T = SYS_GetTime_ms();
    for (i = 0; i < 2000; ++i) {
      SYS_ExecService(StrcpyHandle, aDst, aSrc);
    }
    T = SYS_GetTime_ms() - T;
    printf("  strcpy() using service:  %5d ms\n\n", T);
    printf("Done\n\n");
    //
  } else {
    printf("strcpy() is not present as a service.");
  }
  return 0;
}

Running it shows the relative performance:

C:> apprun DemoBenchStrcpy.pex

SEGGER emApps Desktop Executor V1.10.0 compiled Dec 17 2026 22:33:12
Copyright (c) 2008-2026 SEGGER Microcontroller GmbH  www.segger.com

strcpy() is present as a service function

Benchmarking:

  strcpy() using S32 code:   494 ms
  strcpy() using service:     10 ms

Done

Execution complete:
  98354052 instructions executed in 504.835 ms.
    S32 benchmarks at 194.824 MIPS.
  main() returned 0.

C:> _

Running applications on the desktop

The desktop application executor that is used throughout this manual is provided in source code in Tools/AppRun/Src/AppRun.cpp. This can be customized, for instance to emulate the system that the application will eventually be installed on, and to start developing applications before even prototype hardware is available.

AppRun entire listing

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

Purpose     : S32 sample application executor.

*/

/*********************************************************************
*
*       #include section
*
**********************************************************************
*/

#include <string>
#include <cstring>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <chrono>
#include <filesystem>
#include <cstdarg>
#include "S32.h"

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/

//
// Coarse-grained inclusion of service functions.
//
#if !defined(CONFIG_API_C)
  #define CONFIG_API_C             1
#endif
#if !defined(CONFIG_API_UTIL)
  #define CONFIG_API_UTIL          1
#endif

/*********************************************************************
*
*       Conditional includes
*
**********************************************************************
*/

#if CONFIG_API_C
  #include "S32_API_C.h"
#endif
#if CONFIG_API_UTIL
  #include "S32_API_Util.h"
#endif

/*********************************************************************
*
*       Prototypes
*
**********************************************************************
*/

[[noreturn]] static void _Die(const char *sFormat, ...);

/*********************************************************************
*
*       Data types
*
**********************************************************************
*/
struct TELEMETRY_DATA {
  S32_U32                                        PrecisePC;
  S32_U64                                        InsnCnt;
  std::chrono::high_resolution_clock::time_point ServiceTimestamp;
  std::chrono::high_resolution_clock::duration   ServiceTime;
  std::chrono::high_resolution_clock::duration   ServiceMinDuration;
  std::chrono::high_resolution_clock::duration   ServiceMaxDuration;
  S32_U32                                        ServiceCnt;
  std::chrono::high_resolution_clock::time_point ExecTimestamp;
  std::chrono::high_resolution_clock::duration   ExecTime;
  S32_U32                                        ExecCnt;

  TELEMETRY_DATA() {
    ServiceMinDuration = ServiceMinDuration.max();
    ServiceMaxDuration = ServiceMaxDuration.min();
    ExecTimestamp      = ExecTimestamp.min();
    ServiceTimestamp   = ServiceTimestamp.min();
    ExecTime           = ExecTime.zero();
    ServiceTime        = ServiceTime.zero();
    PrecisePC          = 0;
    InsnCnt            = 0;
    ServiceCnt         = 0;
    ExecCnt            = 0;
  }
};

/*********************************************************************
*
*       Prototypes
*
**********************************************************************
*/

static void _Telemetry_ExcpDetect     (S32_EXEC_CONTEXT *pCtx);
static void _Telemetry_InsnBegin_Full (S32_EXEC_CONTEXT *pCtx);
static void _Telemetry_InsnBegin_Time (S32_EXEC_CONTEXT *pCtx);
static void _Telemetry_ExecBegin      (S32_EXEC_CONTEXT *pCtx);
static void _Telemetry_ExecEnd        (S32_EXEC_CONTEXT *pCtx);
static void _Telemetry_ServiceBegin   (S32_EXEC_CONTEXT *pCtx);
static void _Telemetry_ServiceEnd     (S32_EXEC_CONTEXT *pCtx);

/*********************************************************************
*
*       Static const data
*
**********************************************************************
*/


static const S32_TELEMETRY_API _FullTelemetry = {
  _Telemetry_ExcpDetect,
  _Telemetry_InsnBegin_Full,
  nullptr,
  _Telemetry_ServiceBegin,
  _Telemetry_ServiceEnd,
  _Telemetry_ExecBegin,
  _Telemetry_ExecEnd,
};

static const S32_TELEMETRY_API _TimeTelemetry = {
  nullptr,
  _Telemetry_InsnBegin_Time,
  nullptr,
  _Telemetry_ServiceBegin,
  _Telemetry_ServiceEnd,
  _Telemetry_ExecBegin,
  _Telemetry_ExecEnd,
};

static const S32_TELEMETRY_API _StandardTelemetry = {
  nullptr,
  nullptr,
  nullptr,
  nullptr,
  nullptr,
  _Telemetry_ExecBegin,
  _Telemetry_ExecEnd,
};

static std::vector<S32_SERVICE_BINDING> _aServices{
  { "printf",            S32_API_C_printf        },
  { "__S32_udiv",        S32_API_S32_udiv        },
  { "__S32_umod",        S32_API_S32_umod        },
  { "__S32_idiv",        S32_API_S32_idiv        },
  { "__S32_imod",        S32_API_S32_imod        },
  { "SYS_FindService",   S32_API_S32_FindService },
  { "SYS_ExecService",   S32_API_S32_ExecService },
#if CONFIG_API_C
  { "memset",            S32_API_C_memset        },
  { "memcpy",            S32_API_C_memcpy        },
  { "memmove",           S32_API_C_memmove       },
  { "memchr",            S32_API_C_memchr        },
  { "strcpy",            S32_API_C_strcpy        },
  { "strchr",            S32_API_C_strchr        },
  { "strcmp",            S32_API_C_strcmp        },
  { "strlen",            S32_API_C_strlen        },
  { "puts",              S32_API_C_puts          },
  { "printf",            S32_API_C_printf        },
  { "sprintf",           S32_API_C_sprintf       },
  { "snprintf",          S32_API_C_snprintf      },
#endif
#if CONFIG_API_UTIL
  { "UTIL_MulDiv",       S32_API_Util_MulDiv     },
  { "SYS_GetTime_ms",    S32_API_Util_GetTime_ms },
  { "SYS_GetTime_us",    S32_API_Util_GetTime_us },
  { "SYS_Sleep_us",      S32_API_Util_Sleep_us   },
  { "SYS_Sleep_ns",      S32_API_Util_Sleep_ns   },
  { "FOpen",             S32_API_Util_FOpen      },
  { "FClose",            S32_API_Util_FClose     },
  { "FRead",             S32_API_Util_FRead      },
  { "FWrite",            S32_API_Util_FWrite     },
#endif
};

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/

static std::map<unsigned, std::string> InsnMap;
static std::map<unsigned, std::string> CodeMap;
static std::list<std::string>          ListFile;
static std::string                     LstName;
static std::string                     PrfName;
static std::string                     PexName;
static std::map<unsigned, unsigned>    InsnCntMap;
static std::set<std::string>           Imports;
static std::set<std::string>           MissingImports;
static std::string                     MainName;
static S32_U8                        * pPexImage;
static long                            PexImageLen;
static bool                            TraceInsns;    // Print instruction trace
static bool                            TraceRegs;     // Print registers with trace
static bool                            TraceSource;   // Print source line associated with instruction
static bool                            Time;          // Time the application
static bool                            Fast;          // Run application without telemetry
static bool                            Profile;       // Write instruction profile file
static bool                            PrintAPI;      // Print application API entries
static bool                            PrintExports;  // Print exported functions, do not run
static bool                            PrintImports;  // Print exported functions, do not run
static bool                            PrintMissing;  // Print imported functions missing from exposed API
static bool                            Verbose;       // Print configuration information
static TELEMETRY_DATA                  Telemetry;

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/

/*********************************************************************
*
*       _Die()
*
*  Function description
*    Die fatally.
*
*  Parameters
*    sFormat - Format string.
*/
static void _Die(const char *sFormat, ...) {
  va_list ap;
  //
  va_start(ap, sFormat);
  fprintf(stderr, "fatal: ");
  vfprintf(stderr, sFormat, ap);
  va_end(ap);
  fprintf(stderr, "\n");
  exit(EXIT_FAILURE);
}

/*********************************************************************
*
*       _IsHex()
*
*  Function description
*    String contains all hexadecimal digit?
*
*  Parameters
*    Str - String to test.
*
*  Return value
*    True if only valid hexadecimal digits.
*/
static bool _IsHex(const std::string &Str) {
  for (auto c : Str) {
    if ('0' <= c && c <= '9') {
      /* Pass */
    } else if ('a' <= c && c <= 'f') {
      /* Pass */
    } else if ('A' <= c && c <= 'F') {
      /* Pass */
    } else {
      return false;
    }
  }
  return true;
}

/*********************************************************************
*
*       _DeHex()
*
*  Function description
*    Convert ASCII hexadecimal digit to binary.
*
*  Parameters
*    c - Character to convert.
*
*  Return value
*    Decoded value.
*/
static int _DeHex(char c) {
  if ('0' <= c && c <= '9') {
    return c - '0';
  } else if ('a' <= c && c <= 'f') {
    return c - 'a' + 10;
  } else if ('A' <= c && c <= 'F') {
    return c - 'A' + 10;
  } else {
    return -1;
  }
}

/*********************************************************************
*
*       _IsExecLine()
*
*  Function description
*    Does line correspond to executable content?
*
*  Parameters
*    Text - Line from listing.
*
*  Return value
*    True if the line corresponds to executable content.
*/
static bool _IsExecLine(const std::string &Text) {
  return Text.length() > 13 &&
         _IsHex(Text.substr(0, 6)) &&
         Text[6] == ' ' &&
         Text[7] == ' ' &&
         _IsHex(Text.substr(8, 4)) &&
         Text[12] == ' ';
}

/*********************************************************************
*
*       _LineLC()
*
*  Function description
*    Decode line's location counter.
*
*  Parameters
*    Text - Line from listing.
*
*  Return value
*    Location counter.
*/
static unsigned _LineLC(const std::string &Text) {
  return _DeHex(Text[0]) * 0x100000 +
         _DeHex(Text[1]) * 0x10000 +
         _DeHex(Text[2]) * 0x1000 +
         _DeHex(Text[3]) * 0x100 +
         _DeHex(Text[4]) * 0x10 +
         _DeHex(Text[5]) * 0x1;
}

/*********************************************************************
*
*       _DeriveFileNames()
*
*  Function description
*    Construct listing and profile file names.
*
*  Parameters
*    FileName - File name of PEX file.
*/
static void _DeriveFileNames(const std::string &FileName) {
  LstName = std::filesystem::path(FileName).replace_extension(".lst").string();
  PrfName = std::filesystem::path(FileName).replace_extension().string() + "_pro.txt";
}

/*********************************************************************
*
*       _RdPexFile()
*
*  Function description
*    Read PEX file into memory in binary mode.
*
*  Parameters
*    FileName - File name of PEX file.
*/
static void _RdPexFile(const std::string &FileName) {
  FILE * pPexFile;
  //
  pPexFile = fopen(FileName.c_str(), "rb");
  if (pPexFile == NULL) {
    _Die("cannot open '%s' for reading", FileName.c_str());
  }
  //
  fseek(pPexFile, 0, SEEK_END);
  PexImageLen = ftell(pPexFile);
  fseek(pPexFile, 0, SEEK_SET);
  //
  pPexImage = new S32_U8[PexImageLen];
  fread(pPexImage, 1, PexImageLen, pPexFile);
  //
  fclose(pPexFile);
}

/*********************************************************************
*
*       _RdLstFile()
*
*  Function description
*    Read and parse S32 compiler listing file.
*
*  Parameters
*    FileName - File name of listing file.
*/
static void _RdLstFile(const std::string &FileName) {
  std::string CodeLine;
  //
  FILE *pLstFile = fopen(FileName.c_str(), "r");
  if (pLstFile == NULL) {
    _Die("cannot open '%s' for reading", FileName.c_str());
  }
  //
  for (;;) {
    std::string Line;
    int         c;
    //
    if (feof(pLstFile)) {
      break;
    }
    for (;;) {
      c = fgetc(pLstFile);
      if (c == '\n' || c == EOF) {
        break;
      }
      Line += c;
    }
    ListFile.push_back(Line);
    //
    if (Line.length() >= 6 && Line[5] == ':') {
      //
      // C source line.
      //
      CodeLine = Line;
    } else if (_IsExecLine(Line)) {
      //
      // Assembly language line.
      //
      InsnMap[_LineLC(Line)] = Line;
      CodeMap[_LineLC(Line)] = CodeLine;
    }
  }
}

/*********************************************************************
*
*       _VisitImport()
*
*  Function description
*    Visitor callback to collect imported function information.
*
*  Parameters
*    pGeo     - Pointer to application geometry.
*    sName    - Exported function name.
*    Index    - Imported function index.
*    pUserCtx - Pointer to user-supplied context.
*
*  Return value
*    S32_ERROR_NONE, always succeeds.
*/
static S32_I32 _VisitImport(      S32_EXEC_GEO * pGeo,
                            const char         * sName,
                                  unsigned       Index,
                                  void         * pUserCtx) {
  bool Present = false;
  //
  Imports.insert(sName);
  //
  for (unsigned i = 0; !Present && i < _aServices.size(); ++i) {
    Present = strcmp(_aServices[i].sName, sName) == 0;
  }
  //
  if (!Present) {
    MissingImports.insert(sName);
  }
  //
  return S32_ERROR_NONE;
}

/*********************************************************************
*
*       _PrMissing()
*
*  Function description
*    Print imported functions missing from API table.
*
*  Parameters
*    pGeo - Pointer to application geometry.
*/
static void _PrMissing(S32_EXEC_GEO *pGeo) {
  S32_IterateImports(pGeo, _VisitImport, NULL);
  fprintf(stderr, "Functions imported by application but missing from API:\n");
  if (MissingImports.empty()) {
    fprintf(stderr, "  None\n");
  } else {
    for (auto &Name : MissingImports) {
      fprintf(stderr, "  %s()\n", Name.c_str());
    }
  }
}

/*********************************************************************
*
*       _VisitExport()
*
*  Function description
*    Visitor callback to print exported function information.
*
*  Parameters
*    pGeo     - Pointer to application geometry.
*    pInfo    - Pointer to export descriptor.
*    pUserCtx - Pointer to user-provided context.
*
*  Return value
*    S32_ERROR_NONE, always succeeds.
*/
static S32_I32 _VisitExport(S32_EXEC_GEO * pGeo, S32_EXPORT_INFO *pInfo, void *pUserCtx) {
  fprintf(stderr, "  %s(), %u parameters, entry point 0x%04X\n", pInfo->sName, pInfo->ParaCnt, pInfo->Addr);
  return S32_ERROR_NONE;
}

/*********************************************************************
*
*       _PrExports()
*
*  Function description
*    Print functions exported by the application.
*
*  Parameters
*    pGeo - Pointer to application geometry.
*/
static void _PrExports(S32_EXEC_GEO *pGeo) {
  fprintf(stderr, "Functions exported by application:\n");
  S32_IterateExports(pGeo, _VisitExport, NULL);
}

/*********************************************************************
*
*       _PrImports()
*
*  Function description
*    Print functions imported by the application.
*
*  Parameters
*    pGeo - Pointer to application geometry.
*/
static void _PrImports(S32_EXEC_GEO *pGeo) {
  S32_IterateImports(pGeo, _VisitImport, NULL);
  fprintf(stderr, "Functions imported by application:\n");
  for (auto &Name : Imports) {
    fprintf(stderr, "  %s()\n", Name.c_str());
  }
}

/*********************************************************************
*
*       _PrAPI()
*
*  Function description
*    Print functions exported by emApps API.
*/
static void _PrAPI() {
  fprintf(stderr, "Functions exported by the API:\n");
  for (auto API : _aServices) {
    fprintf(stderr, "  %s()\n", API.sName);
  }
}

/*********************************************************************
*
*       _WrPrfFile()
*
*  Function description
*    Write profile to disk.
*/
static void _WrPrfFile() {
  FILE *pPrfFile = fopen(PrfName.c_str(), "w");
  for (auto Line : ListFile) {
    if (_IsExecLine(Line)) {
      fprintf(pPrfFile, "%7d   %s", InsnCntMap[_LineLC(Line)], Line.c_str());
    } else {
      fprintf(pPrfFile, "          %s", Line.c_str());
    }
  }
  fclose(pPrfFile);
}

/*********************************************************************
*
*       _ShowUsage()
*
*  Function description
*    Print help usage.
*/
static void _ShowUsage() {
  fprintf(stderr, "Usage:\n");
  fprintf(stderr, "  AppRun [option...] file\n");
  fprintf(stderr, "\n");
  fprintf(stderr, "Options:\n");
  fprintf(stderr, "  -nfunc      Execute 'func' after loading                  [default: main]\n");
  fprintf(stderr, "  -t          Trace instructions executed\n");
  fprintf(stderr, "  -s          Trace lines executed\n");
  fprintf(stderr, "  -r          Include register dump (before execution) in instruction trace\n");
  fprintf(stderr, "  -f          Run fast with no telemetry\n");
  fprintf(stderr, "  -p          Write instruction profile file\n");
  fprintf(stderr, "  -e          List functions provided by emApps API\n");
  fprintf(stderr, "  -i          List application's imported functions\n");
  fprintf(stderr, "  -x          List application's exported functions\n");
  fprintf(stderr, "  -m          List application's imported functions missing from exposed API\n");
  fprintf(stderr, "  -a          List application's imported, exported, and missing functions\n");
  fprintf(stderr, "  -?, --help  Print help information\n");
  fprintf(stderr, "\n");
  fprintf(stderr, "Streams:\n");
  fprintf(stderr, "  stdout - Application output.\n");
  fprintf(stderr, "  stderr - Trace and message output.\n");
  exit(EXIT_SUCCESS);
}

/*********************************************************************
*
*       _Telemetry_ExcpDetect()
*
*  Function description
*    Entry point for exception trace trace.
*
*  Parameters
*    pCtx - Pointer to execution context.
*/
static void _Telemetry_ExcpDetect(S32_EXEC_CONTEXT *pCtx) {
  //
  int Exception;
  //
  // Break raised for function termination?
  //
  Exception = S32_RdXR(pCtx);
  if (Exception == S32_ERROR_BRK && S32_RdPC(pCtx) == 4) {
    return;
  }
  //
  fprintf(stderr, "Exception %d raised (%s)\n", Exception, S32_GetErrorText(Exception));
  fprintf(stderr, "\n");
  //
  fprintf(stderr, "PC: %08X (imprecise)\n", S32_RdPC(pCtx));
  fprintf(stderr, "PC: %08X (precise)\n", Telemetry.PrecisePC);
  fprintf(stderr, "ML: %08X\n", S32_RdML(pCtx));
  //
  for (unsigned Rn = 0; Rn < 16; ++Rn) {
    if (Rn % 8 == 0) {
      fprintf(stderr, "R%u:", Rn);
    }
    fprintf(stderr, " %08X", S32_RdReg(pCtx, Rn));
    if (Rn % 8 == 7) {
      fprintf(stderr, "\n");
    }
  }
  fprintf(stderr, "\n");
}

/*********************************************************************
*
*       _Telemetry_InsnBegin_Full()
*
*  Function description
*    Entry point for per-instruction trace.
*
*  Parameters
*    pCtx - Pointer to execution context.
*/
static void _Telemetry_InsnBegin_Full(S32_EXEC_CONTEXT *pCtx) {
  static std::string LastCodeLine;
  //
  Telemetry.PrecisePC = S32_RdPC(pCtx);  // Register precise PC if an exception is raised
  Telemetry.InsnCnt  += 1;
  //
  if (TraceSource || TraceInsns || Profile) {
    S32_U32 PC = S32_RdPC(pCtx);
    if (PC == 4) {
      // BRK on RET from top-level function
    } else if (InsnMap.find(PC) == InsnMap.end()) {
      S32_Raise(pCtx, S32_ERROR_ACC_VIOLATION);
    } else {
      InsnCntMap[PC] += 1;
      if (TraceSource) {
        if (LastCodeLine != CodeMap[PC]) {
          LastCodeLine = CodeMap[PC];
          if (!LastCodeLine.empty()) {
            if (TraceInsns) { fprintf(stderr, "\n"); }
            fprintf(stderr, "%s\n", LastCodeLine.c_str());
            if (TraceInsns) { fprintf(stderr, "\n"); }
          }
        }
      }
      if (TraceInsns) {
        std::string Txt = InsnMap[PC];
        if (Txt.find(';') != std::string::npos) {
          Txt = Txt.substr(0, Txt.find(';'));
        }
        if (TraceRegs) {
          while (Txt.size() < 60) {
            Txt += ' ';
          }
          fprintf(stderr, "%s  ", Txt.c_str());
          for (int i = 0; i < 16; ++i) {
            fprintf(stderr, "%08X", S32_RdReg(pCtx, i));
            if (i % 8 == 3) {
              fprintf(stderr, "  ");
            } else if (i % 8 == 7) {
              fprintf(stderr, "  ");
            } else {
              fprintf(stderr, " ");
            }
          }
        } else {
          while (!Txt.empty() && Txt.substr(Txt.length()-1, 1) == " ") {
            Txt = Txt.substr(0, Txt.length()-1);
          }
          fprintf(stderr, "%s", Txt.c_str());
        }
        fprintf(stderr, "\n");
      }
    }
  }
}

/*********************************************************************
*
*       _Telemetry_InsnBegin_Time()
*
*  Function description
*    Entry point to collect executed instruction count.
*
*  Parameters
*    pCtx - Pointer to execution context.
*/
static void _Telemetry_InsnBegin_Time(S32_EXEC_CONTEXT *pCtx) {
  Telemetry.InsnCnt += 1;
}

/*********************************************************************
*
*       _Telemetry_ServiceBegin()
*
*  Function description
*    "Begin Service" telemetry point.
*
*  Parameters
*    pCtx - Pointer to execution context.
*/
static void _Telemetry_ServiceBegin(S32_EXEC_CONTEXT *pCtx) {
  Telemetry.ServiceCnt      += 1;
  Telemetry.ServiceTimestamp = std::chrono::high_resolution_clock::now();
}

/*********************************************************************
*
*       _Telemetry_ServiceEnd()
*
*  Function description
*    "End Service" telemetry point.
*
*  Parameters
*    pCtx - Pointer to execution context.
*/
static void _Telemetry_ServiceEnd(S32_EXEC_CONTEXT *pCtx) {
  auto Duration = std::chrono::high_resolution_clock::now() - Telemetry.ServiceTimestamp;
  Telemetry.ServiceTime += Duration;
  //
  // Don't register ultra-small service calls.
  //
  if (Duration.count() != 0) {
    Telemetry.ServiceMinDuration = std::min(Telemetry.ServiceMinDuration, Duration);
  }
  Telemetry.ServiceMaxDuration = std::max(Telemetry.ServiceMaxDuration, Duration);
}

/*********************************************************************
*
*       _Telemetry_ExecBegin()
*
*  Function description
*    "Begin Exec" telemetry point.
*
*  Parameters
*    pCtx - Pointer to execution context.
*/
static void _Telemetry_ExecBegin(S32_EXEC_CONTEXT *pCtx) {
  Telemetry.ExecCnt += 1;
  Telemetry.ExecTimestamp = std::chrono::high_resolution_clock::now();
}

/*********************************************************************
*
*       _Telemetry_ExecEnd()
*
*  Function description
*    "End Exec" telemetry point.
*
*  Parameters
*    pCtx - Pointer to execution context.
*/
static void _Telemetry_ExecEnd(S32_EXEC_CONTEXT *pCtx) {
  Telemetry.ExecTime += std::chrono::high_resolution_clock::now() - Telemetry.ExecTimestamp;
}

static std::string _FormatAsSeconds(S32_U64 Ns) {
  char acBuf[32];
  //
  sprintf(acBuf, "%5lld.%03lld %03lld %03lld", Ns / 1000000000uLL, Ns / 1000000uL % 1000u, Ns / 1000u % 1000u, Ns % 1000u);
  return acBuf;
}

static std::string _FormatWithPeriod(S32_U64 Value) {
  std::string Text;
  char        acBuf[32];
  
  while (Value >= 1000) {
    sprintf(acBuf, "%03lld", Value % 1000);
    if (!Text.empty()) {
      Text = " " + Text;
    }
    Text = acBuf + Text;
    Value /= 1000;
  }
  //
  sprintf(acBuf, "%lld", Value);
  if (!Text.empty()) {
    Text = " " + Text;
  }
  return acBuf + Text;
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       main()
*
*  Function description
*    Main function.
*
*  Parameters
*    argc - Argument count.
*    argv - Argument vector.
*
*  Return value
*    Exit code.
*/
int main(int argc, const char** argv) {
  S32_EXEC_GEO        Geo;
  S32_EXEC_CONTEXT    Ctx;
  S32_EXPORT_INFO     Info;
  bool                Newline;
  S32_U8            * pExecImage;
  int                 LoadStatus;
  int                 ExecStatus;
  //
  MainName = "main";
  //
  fprintf(stderr, "\n");
  fprintf(stderr, "SEGGER emApps Desktop Executor V%s compiled " __DATE__ " " __TIME__ "\n", S32_GetVersionText());
  fprintf(stderr, "%s  www.segger.com\n", S32_GetCopyrightText());
  fprintf(stderr, "\n");
  //
  for (int i = 1; i < argc; ++i) {
    std::string Arg = argv[i];
    //
    if      (Arg == "-t")              { TraceInsns   = true;                                           }
    else if (Arg == "-r")              { TraceInsns   = true; TraceRegs   = true;                       }
    else if (Arg == "-s")              { TraceSource  = true;                                           }
    else if (Arg == "-p")              { Profile      = true;                                           }
    else if (Arg == "-m")              { Time         = true;                                           }
    else if (Arg == "-f")              { Fast         = true;                                           }
    else if (Arg == "-e")              { PrintAPI     = true;                                           }
    else if (Arg == "-x")              { PrintExports = true;                                           }
    else if (Arg == "-i")              { PrintImports = true;                                           }
    else if (Arg == "-m")              { PrintMissing = true;                                           }
    else if (Arg == "-a")              { PrintImports = true; PrintExports = true; PrintMissing = true; }
    else if (Arg == "-v")              { Verbose      = true;                                           }
    else if (Arg == "-n")              { MainName = "main";                                             }
    else if (Arg == "-?")              { _ShowUsage();                                                  }
    else if (Arg == "--help")          { _ShowUsage();                                                  }
    else if (Arg.substr(0, 2) == "-n") { MainName = Arg.substr(2);                                      }
    else if (Arg.substr(0, 1) == "-")  { _Die("unrecognized option '%s'", Arg.c_str());                 }
    else if (!PexName.empty())         { _Die("cannot execute multiple applications");                  }
    else                               { PexName = Arg;                                                 }
  }
  //
  if (PrintAPI && PexName.empty()) {
    _PrAPI();
    exit(EXIT_SUCCESS);
  }
  //
  if (PexName.empty()) {
    _ShowUsage();
  }
  //
  if (Verbose) {
    fprintf(stderr, "Sandbox: %s\n", S32_CONFIG_SANDBOX ? "Enabled" : "Disabled");
    fprintf(stderr, "\n");
  }
  //
  _DeriveFileNames(PexName);
  _RdPexFile(PexName);
  if (TraceSource || TraceInsns || Profile) {
    _RdLstFile(LstName);
  }
  //
  LoadStatus = S32_InitGeo(&Geo, _aServices.data(), (unsigned)_aServices.size());
  if (LoadStatus < 0) {
    fprintf(stderr, "Initialization failed: %s\n", S32_GetErrorText(LoadStatus));
    return LoadStatus;
  }
  //
  LoadStatus = S32_LoadHeader(&Geo, pPexImage, PexImageLen);
  if (LoadStatus >= 0) {
    //
    // Create an execution image for the application.
    //
    pExecImage = new S32_U8[PexImageLen + LoadStatus];
    memset(pExecImage, 0, PexImageLen + LoadStatus);  // Fill stack and xdata, not strictly necessary...
    memcpy(pExecImage, pPexImage, PexImageLen);
    //
    LoadStatus = S32_LoadFile(&Geo, pExecImage);
    if (LoadStatus >= 0) {
      Newline = false;
      if (PrintAPI) {
        _PrAPI();
        Newline = true;
      }
      if (PrintImports) {
        if (Newline) { fprintf(stderr, "\n"); }
        _PrImports(&Geo);
        Newline = true;
      }
      if (PrintExports) {
        if (Newline) { fprintf(stderr, "\n"); }
        _PrExports(&Geo);
        Newline = true;
      }
      if (PrintMissing) {
        if (Newline) { fprintf(stderr, "\n"); }
        _PrMissing(&Geo);
        Newline = true;
      }
      if (Newline) {
        exit(EXIT_SUCCESS);
      }
      //
      LoadStatus = S32_FindExportEx(&Geo, MainName.c_str(), &Info);
      if (LoadStatus < 0) {
        fprintf(stderr, "fatal: function '%s()' is not exported\n", MainName.c_str());
        fprintf(stderr, "\n");
        _PrExports(&Geo);
        exit(EXIT_FAILURE);
      } else {
        LoadStatus = S32_PrepareByName(&Geo, &Ctx, MainName.c_str());
        if (LoadStatus == 0) {
          if (TraceInsns || TraceSource) {
            LoadStatus = S32_SetTelemetryAPI(&Ctx, &_FullTelemetry);
          } else if (Time) {
            LoadStatus = S32_SetTelemetryAPI(&Ctx, &_TimeTelemetry);
          } else if (!Fast) {
            LoadStatus = S32_SetTelemetryAPI(&Ctx, &_StandardTelemetry);
          }
          if (LoadStatus != 0) {
            _Die("problem activating telemetry: '%s'", S32_GetErrorText(LoadStatus));
          }
          ExecStatus = S32_Exec(&Ctx);
        } else if (LoadStatus > 0) {
          _Die("unsupported: '%s' declared with %d arguments", MainName.c_str(), LoadStatus);
        }
      }
    }
  }
  //
  if (LoadStatus < 0) {
    fprintf(stderr, "Loading failed\n");
    fprintf(stderr, "  %d returned - %s.\n", LoadStatus, S32_GetErrorText(LoadStatus));
    //
    if (LoadStatus == S32_ERROR_NOT_FOUND) {
      fprintf(stderr, "\n");
      _PrMissing(&Geo);
    }
    return LoadStatus;
  } else {
    //
    fprintf(stderr, "\n");
    fprintf(stderr, "Execution complete:\n");
    if (Profile) {
      _WrPrfFile();
      fprintf(stderr, "  Instruction profile written to '%s'.\n", PrfName.c_str());
    }
    //
    if (Telemetry.InsnCnt > 0) {
      auto ExecNs   = std::chrono::duration_cast<std::chrono::nanoseconds>(Telemetry.ExecTime).count();
      auto SvcNs    = std::chrono::duration_cast<std::chrono::nanoseconds>(Telemetry.ServiceTime).count();
      auto MinSvcNs = std::chrono::duration_cast<std::chrono::nanoseconds>(Telemetry.ServiceMinDuration).count();
      auto MaxSvcNs = std::chrono::duration_cast<std::chrono::nanoseconds>(Telemetry.ServiceMaxDuration).count();
      auto ClockRes = (double) std::chrono::high_resolution_clock::period::num
                             / std::chrono::high_resolution_clock::period::den
                             * 1.e9;
      //
      fprintf(stderr, "\n");
      fprintf(stderr, "  Summary:\n");
      fprintf(stderr, "    Total elapsed time: %17s s\n",        _FormatAsSeconds(ExecNs).c_str());
      fprintf(stderr, "    Clock resolution:   %17s s (reported)\n", _FormatAsSeconds(ClockRes).c_str());
      fprintf(stderr, "  Execution:\n");
      fprintf(stderr, "    Calls made:         %17s completed\n", _FormatWithPeriod(Telemetry.ExecCnt).c_str());
      fprintf(stderr, "    Total instructions: %17s executed\n",  _FormatWithPeriod(Telemetry.InsnCnt).c_str());
      fprintf(stderr, "    Total time:         %17s s\n",        _FormatAsSeconds(ExecNs - SvcNs).c_str());
      fprintf(stderr, "  Services:\n");
      fprintf(stderr, "    Calls made:         %17s completed\n", _FormatWithPeriod(Telemetry.ServiceCnt).c_str());
      fprintf(stderr, "    Total time:         %17s s\n",        _FormatAsSeconds(SvcNs).c_str());
      fprintf(stderr, "    Min duration:       %17s s\n",        _FormatAsSeconds(MinSvcNs).c_str());
      fprintf(stderr, "    Max duration:       %17s s\n",        _FormatAsSeconds(MaxSvcNs).c_str());
      if (ExecNs  > 100000) {
        fprintf(stderr, "  Performance:\n");
        fprintf(stderr, "    Benchmark:          %17.3f MIPS.\n",
          1000. * Telemetry.InsnCnt / ExecNs);
      }
      fprintf(stderr, "\n");
    }
    //
    if (ExecStatus == S32_ERROR_NONE) {
      fprintf(stderr, "  'main()' returned %d.\n", (S32_I32)S32_RdReg(&Ctx, S32_REG_R0));
      return 0;
    } else {
      fprintf(stderr, "  exception %d raised - %s.\n", ExecStatus, S32_GetErrorText(ExecStatus));
      return ExecStatus;
    }
  }
}

/*************************** End of file ****************************/

Configuring emApps

This section describes how to configure the emApps module when integrating it into a program.

The configuration file

emApps is completely configured entirely by editing the file Config/S32_Conf.h. It defines some preprocessor macros that configures the executor to use, how memory is accessed, what features the executor provides.

Configuration options have defaults, set using by the fileInc/S32_ConfDefaults.h. This file must not be edited configure emApps, all configuration must be accomplished by editing Config/S32_Conf.h to avoid problems when contacting SEGGER support.

Compiler configuration

Exact-bit-width types

Description

Types that have an exact number of bits.

Definition

#define S32_U8     unsigned char
#define S32_U16    unsigned short
#define S32_U32    unsigned int
#define S32_U64    unsigned long long
#define S32_I8     signed char
#define S32_I16    signed short
#define S32_I32    signed int

Symbols

Definition Description
S32_U8 Consider using uint8_t if available.
S32_U16 Consider using uint16_t if available.
S32_U32 Consider using uint32_t if available.
S32_U64 Consider using uint64_t if available.
S32_I8 Consider using int8_t if available.
S32_I16 Consider using int16_t if available.
S32_I32 Consider using int32_t if available.

Additional information

These must be configured to exactly match the number of bits required. The defaults are generally good for 32-bit architectures. These are not configured to the “intx_t” and “uintx_t” types from <stdint.h> as the ISO standard makes no guarantee that such types exist.

Sandbox memory access

Description

These macros read and write data to the sandbox. They can be configured for architectures that are big-endian, that fault on misaligned accesses, or both.

Definition

#define S32_RDU16LE(ADDR)        (*(S32_U16 *)(ADDR))
#define S32_RDU32LE(ADDR)        (*(S32_U32 *)(ADDR))
#define S32_WRU16LE(ADDR,VAL)    (*(S32_U16 *)(ADDR) = (S32_U16)(VAL))
#define S32_WRU32LE(ADDR,VAL)    (*(S32_U32 *)(ADDR) = (S32_U32)(VAL))

Symbols

Definition Description
S32_RDU16LE(ADDR) Read 16-bit unsigned, little endian
S32_RDU32LE(ADDR) Read 32-bit unsigned, little endian
S32_WRU16LE(ADDR,VAL) Write 16-bit unsigned, little endian
S32_WRU32LE(ADDR,VAL) Write 32-bit unsigned, little endian

S32_USE_PARA

Description

Mark a parameter as used.

Definition

#define S32_USE_PARA(X)    (void)(X)

Additional information

Mark the parameter X as used in order to avoid ’unused parameter’ warning messages from a compiler. It usually suffices to use the standard idiom of casting the parameter to void.

S32_INLINE

Description

Control explicit declaration of an inline function.

Definition

#define S32_INLINE    inline

Additional information

This symbol expands to a token sequence that declares a function inline. If the compiler used to compile emApps does not support inline, defined S32_INLINE to expand to the empty symbol sequence.

S32_MEMSET

Description

Set memory to value.

Definition

#define S32_MEMSET    S32_memset

Additional information

These macro is used to set memory to a value. By default it is configured to use a locally provided memory-set function rather than the C library function memset().

S32_MEMCPY

Description

Copy memory.

Definition

#define S32_MEMCPY    S32_memcpy

Additional information

These macro is used to copy memory. By default it is configured to use a locally provided memory-copy function rather than the C library function memcpy().

S32_STRCMP

Description

String compare.

Definition

#define S32_STRCMP    S32_strcmp

Additional information

These macro is used to compare strings. By default it is configured to use a locally provided string-compare function rather than the C library function memcpy().

Feature selection and adaptation

Error status codes

Description

Error codes returned by emApps API functions.

Definition

#define S32_ERROR_NONE             (  0)
#define S32_ERROR_BRK              (-11)
#define S32_ERROR_UNDEF_INSN       (-12)
#define S32_ERROR_ACC_VIOLATION    (-13)
#define S32_ERROR_ZERO_DIVIDE      (-14)
#define S32_ERROR_NOT_FOUND        (-15)
#define S32_ERROR_BAD_PEX_FILE     (-16)
#define S32_ERROR_BAD_VERSION      (-17)
#define S32_ERROR_BAD_CONFIG       (-18)
#define S32_ERROR_UNIMP_FUNC       (-19)
#define S32_ERROR_UNSUP_INSN       (-21)
#define S32_ERROR_VENEER_ERROR     (-22)
#define S32_ERROR_OUT_OF_MEMORY    (-23)
#define S32_ERROR_PHASE_ERROR      (-24)
#define S32_ERROR_NOT_SUPPORTED    (-25)

Symbols

Definition Description
S32_ERROR_NONE No error.
S32_ERROR_BRK Executed a BRK instruction.
S32_ERROR_UNDEF_INSN Attempt to execute an undefined instruction.
S32_ERROR_ACC_VIOLATION Memory access outside of sandbox.
S32_ERROR_ZERO_DIVIDE Division by zero.
S32_ERROR_NOT_FOUND File or service function not found.
S32_ERROR_BAD_PEX_FILE Error in structure of PEX file.
S32_ERROR_BAD_VERSION PEX file requires more recent executor version.
S32_ERROR_BAD_CONFIG Incorrect configuration of data types, context offsets, or service table.
S32_ERROR_UNIMP_FUNC Unimplemented function.
S32_ERROR_UNSUP_INSN Valid but unsupported instruction.
S32_ERROR_VENEER_ERROR Native code generator cannot construct veneers.
S32_ERROR_OUT_OF_MEMORY General “out of memory” error.
S32_ERROR_PHASE_ERROR Phase error between native code generation passes.
S32_ERROR_NOT_SUPPORTED Request feature is not supported.

Additional information

These error codes, other than S32_ERROR_NONE, are user-configurable in order that they do not conflict with existing codes used by other software (and then combined with emApps). All errors must be assigned negative values.

S32_CONFIG_EXECUTOR

Description

Configuration of S32 execution engine implementation.

Definition

#define S32_CONFIG_EXECUTOR    0

Additional information

If set to zero, the generic C executor is selected to execute applications. If set to one, the Arm executor is selected to execute applications.

S32_CONFIG_SANDBOX

Description

Configuration of environment protected by sandbox.

Definition

#define S32_CONFIG_SANDBOX    1

Additional information

If set to zero, the generic C executor will not perform software-based access violation trapping. In this configuration, it is expected that the executor is run in its own protected environment provided by a memory protection unit (MPU) or a memory management unit (MMU) under control of an operating system.

If set to nonzero, the generic C executor performs software-based access violation trapping on all accesses: instruction fetch and data read/writes.

S32_CONFIG_TELEMETRY

Description

Enable application telemetry.

Definition

#define S32_CONFIG_TELEMETRY    0

Additional information

This flag controls whether telemetry callbacks are called during application execution.

All other values are invalid.

Assembly executor configuration

S32_CONFIG_ARM_ISA

Description

Configure Arm instruction set for executor.

Definition

#define S32_CONFIG_ARM_ISA    S32_CONFIG_ARM_ISA_T32

Additional information

This setting controls the instruction set for the Arm assembly language executor.

This symbol can be set to:

For some architectures, selection is clear. For other architectures and cores, such as Arm v7-A implementation in the Cortex-A9, it is a trade-off between improved execution speed of the A32 instruction set compared to the T32 instruction set it also implements, and the fact that the executor in A32 is slightly larger than the executor coded in T32.

S32_CONFIG_RAM_DISPATCH

Description

Use RAM-based dispatch table.

Definition

#define S32_CONFIG_RAM_DISPATCH    0

Additional information

This flag controls whether the opcode decode dispatch table is held in RAM or (usually) flash. Setting this to zero places the table in a section marked as read-only memory. Setting this to nonzero instructs the executor to copy the instruction dispatch table from read-only memory to the stack when S32_Exec() is called.

As the dispatch table is accessed once per instruction executed, placing the small table in RAM can accelerate opcode dispatch and improve execution performance.

If RAM dispatch and TBB/TBH instructions are both activated, a RAM-based dispatch table is created and used but other instruction-field dispatching uses TBB/TBH if possible.

See also

S32_CONFIG_USE_TBB_TBH

S32_CONFIG_UNALIGNED_TRAPS

Description

Do unaligned accesses trap?

Definition

#define S32_CONFIG_UNALIGNED_TRAPS    0

Additional information

This flag controls the instructions selected by the Arm assembly language executor. Setting this symbol to zero indicates to the executor that 32-bit accesses to 16-bit-aligned addresses complete successfully without an unaligned access exception. If this symbol is set to a nonzero value, a 32-bit load from the code stream is synthesized using two 16-bit accesses.

S32_CONFIG_TAIL_THREADING

Description

Use RAM-based dispatch table.

Definition

#define S32_CONFIG_TAIL_THREADING    0

Additional information

This flag controls whether opcode decode dispatch is appended to each opcode executor laying down one opcode dispatcher per opcode group (32 groups), or whether there is a single, common opcode dispatcher.

Using a single dispatcher saves some code memory at the possible expense of execution speed, whereas appending a next-opcode dispatcher to each opcode group saves a branch instruction at the expense of extra code for each group.

The exact performance gains and code sizes are highly dependent on the target architecture and instruction cache presence.

S32_CONFIG_USE_TBB_TBH

Description

Use TBB and TBH instructions for opcode dispatch.

Definition

#define S32_CONFIG_USE_TBB_TBH    0

Additional information

This flag controls whether opcode dispatch uses the TBB and TBH instructions of the ARMv6 and ARMv7 architectures.

Using TBB and TBH reduces code size but, after benchmarking on some readily available ARMv7 cores, it also seems to reduce performance compared to a table-based opcode dispatcher.

S32_CONFIG_ALIGN_TARGETS

Description

Align branch target instructions.

Definition

#define S32_CONFIG_ALIGN_TARGETS    0

Additional information

This flag controls whether the targets of Arm branch instructions are aligned to a 32-bit boundary. For some cores, such as a cortex-A9, aligning branch targets is a small performance gain at the expense of slightly larger code.

Actual performance gains will be dependent upon the core that run the executor and its cache, branch predictor, and instruction pipeline.

S32_CONFIG_USE_PREDICTION

Description

Prime branch predictor for faster opcode dispatch.

Definition

#define S32_CONFIG_USE_PREDICTION    0

Additional information

This flag controls whether the instruction following the current instruction being executed is decoded early in order to prime the pipeline and branch prediction unit.

For cores that support a deeper pipeline and branch predictor, performance is generally improved when emApps is configured to prime the branch predictor.

Native code generator configuration

S32_NCG_CONFIG_T32_REG_CNT

Description

Number of registers used to mirror register file context.

Definition

#define S32_NCG_CONFIG_T32_REG_CNT    4

Additional information

The symbol defines the number of registers used to mirror the low registers of the S32 context. The best code density is achieved, by experimentation, to be four registers (R0-R3) in addition to the stack pointer.

At present, the only value supported is 4.

S32_NCG_CONFIG_T32_FLAGS

Description

Capability flags supported by the T32 code generator.

Definition

#define S32_NCG_CONFIG_T32_FLAGS    \
   (                                                        \
   1 * S32_NCG_T32_FLAG_FUSE_MOV_BRA                    +   \
   1 * S32_NCG_T32_FLAG_FUSE_MOV_LDR                    +   \
   1 * S32_NCG_T32_FLAG_FUSE_MOV_STR                    +   \
   1 * S32_NCG_T32_FLAG_FUSE_ADD_LDR                    +   \
   1 * S32_NCG_T32_FLAG_FUSE_ADD_STR                    +   \
   1 * S32_NCG_T32_FLAG_FUSE_MOV_ADD                    +   \
   1 * S32_NCG_T32_FLAG_FUSE_MOV_ADD_LDR                +   \
   1 * S32_NCG_T32_FLAG_FUSE_MOV_SUB_LDR                +   \
   1 * S32_NCG_T32_FLAG_FUSE_MOV_SUB                    +   \
   1 * S32_NCG_T32_FLAG_FUSE_LSL_LSL                    +   \
   1 * S32_NCG_T32_FLAG_FUSE_LSR_LSR                    +   \
   1 * S32_NCG_T32_FLAG_FUSE_AND_BXX                    +   \
   1 * S32_NCG_T32_FLAG_FUSE_CLX_BXX                    +   \
   1 * S32_NCG_T32_FLAG_REPLACE_OR_0                    +   \
   1 * S32_NCG_T32_FLAG_SHRINK_JUMPS                    +   \
   1 * S32_NCG_T32_FLAG_MINIMIZE_IMAGE                  +   \
   1 * S32_NCG_T32_FLAG_SANDBOX_INLINE                  +   \
   1 * S32_NCG_T32_FLAG_SANDBOX_OUTLINE                 +   \
   0 * S32_NCG_T32_FLAG_ASYNC_RAISE                     +   \
   (S32_CONFIG_TELEMETRY != 0) * S32_NCG_T32_FLAG_TELEMETRY \
   )

Additional information

The symbol defines the flags used to select the optimization capabilities of the T32 native code generator that are compiled into firmware.

C compiler reference

This chapter contains the documentation for the emApps C compiler.

Introduction

The compiler is located in the Bin folder of the emApps product. It is used to compile application source code files into portable executable files that can be loaded and executed in an emApps sandbox environment. A linker is not required.

The compiler implements a subset of the C90 standard with some C99 extensions (see Extensions). Restrictions and deviations tha are imposed for deeply embedded applications are listed in Restrictions and Deviations.

Usage

The compiler is called from the command line as follows:

S32CC [options] source-file

A list with all available options can be shown by invoking the compiler without any arguments.

To compile a source code file, it needs at least the path to the Inc directory, which is defined as a system include, and the file to compile. The Inc directory contains the file Default.h, which is automatically included by the compiler and provides the sandbox’s C interface to the user.

When the compiler finishes compilation successfully, there are two new files in the same folder as the source code file:

Language

Extensions

Restrictions

The supported C programming language is subject to the following restrictions:

Deviations

The supported C programming language is subject to following deviations:

Preprocessor

The compiler has a standard C90 preprocessor with following extensions:

Predefined macros

Following macros are predefined by the compiler:

Macro Description Example Output
__DATE__ Date the source code file was compiled. "Feb 20 2026"
__TIME__ Time the source code file was compiled. "12:02:05"
__FILE__ Name of the source code file. "App.c"
__LINE__ The line number the macro was used in. 80
__S32C__ The full version number containing the major, minor and patch number (Mmmpp). 21202
__S32C_MAJOR__ The major version number. 2
__S32C_MINOR__ The minor version number. 12
__S32C_PATCHLEVEL__ The patch level. 3
__S32C_VERSION__ The version string (“M.mm.pp”). "2.12.3"

Pragmas

The following pragmas are supported by the S32 C compiler.

Pragma Explanation
xdata_size Specifies the size of the memory allocated for the xdata area.
stack_size Specifies the size of the memory allocated for the stack area.
export Specifies a function to be exported from the application.
xdata_size

Syntax

#pragma S32C xdata_size (Size)

Description

This pragma specifies the size of the memory allocated for the xdata area pointed to by __S32_XDataBase. The xdata area can be used by the program to provide the data to an application, or for the application to return data to the program.

Parameter Description
Size Size of the xdata area to be allocated.

Example

#pragma S32C xdata_size (0x800)
stack_size

Syntax

#pragma S32C stack_size (size)

Description

This pragma is not usually required because the S32 compiler analyzes each entry point to determine maximum stack depth and sets this automatically. However, additional space can be added “for safety reasons” by using this pragma and override the compiler’s calculation.

The compiler will disregard stack sizes smaller than that calculated by static analysis, and therefore it is not possible to produce an application that will fail because of lack of stack space. It is also possible to increase the allocated stack above that calculated by the compiler by a given amount that is specified using a ’+’.

#pragma S32C stack_size(4096)    // Set stack size to 4096
#pragma S32C stack_size(0x1000)  // Same as above
#pragma S32C stack_size(+256)    // Calculated stack size increased by 256 bytes.

In the case where there is direct or indirect recursion or when using function pointers, an exact stack bound cannot be calculated. The compiler calculates the maximum stack requirement of all functions, including those with direct or indirect recursion up to the point of recursion, and uses this as the calculated bound. A warning is generated when the compiler detects such recursion, and the cycle is described in the compiler’s map file.

In this case, it is the user’s responsibility to determine the minimum stack space required by whatever means are at hand, and instruct the compiler by using this pragma. If the declared stack space is smaller than that actually required, overwriting of other data or the program will occur, but sandboxing ensures that no write occurs to data outside of the sandbox.

export

Syntax

#pragma S32C export("name")
#pragma S32C export(name)

Description

The function with the given name is placed into the export list contained in the application’s executable such that it can be located using S32_FindExport().

Program API reference

This chapter explains the API functions of emApps that are needed for loading and execution. The emApps API is kept as simple as possible to provide a straightforward way to integrate emApps into a product.

Data types

Type Description
S32_EXEC_GEO Layout geometry of a PEX file.
S32_EXEC_GEO_REGION Describes a region of the PEX file.
S32_EXEC_CONTEXT Execution context.
S32_SERVICE_BINDING Association of service name and its implementation.
S32_SERVICE_FUNC Prototype for service function implementation.
S32_EXPORT_INFO Exported function information.
S32_EXPORT_FUNC Prototype for exported function enumeration.
Telemetry
S32_TELEMETRY_API Structure containing telemetry point methods.
S32_TELEMETRY_EXEC_BEGIN_FUNC Prototype for Execution-Begin telemetry point.
S32_TELEMETRY_EXEC_END_FUNC Prototype for Execution-End telemetry point.
S32_TELEMETRY_SERVICE_BEGIN_FUNC Prototype for Service-Begin telemetry point.
S32_TELEMETRY_SERVICE_END_FUNC Prototype for Service-End telemetry point.
S32_TELEMETRY_INSN_BEGIN_FUNC Prototype for Instruction-Begin telemetry point.
S32_TELEMETRY_INSN_END_FUNC Prototype for Instruction-End telemetry point.
S32_TELEMETRY_EXCP_DETECTED_FUNC Prototype for Exception-Detected telemetry point.
S32_BT_TELEMETRY_DATA Structure containing basic telemetry data.
S32_BT_TIMESTAMP_FUNC Prototype for function returning a timestamp.

S32_EXEC_GEO

Description

Layout geometry of a PEX file.

Type definition

typedef struct S32_EXEC_GEO_s {
  S32_SERVICE_FUNC *const   * pIdxFn;
  S32_U32                     IdxCnt;
  const S32_SERVICE_BINDING * pImpFn;
  S32_U32                     ImpCnt;
  S32_U32                     XDataLen;
  S32_U32                     StackLen;
  S32_U32                     ExportCnt;
  S32_EXEC_GEO_REGION         FileRgn;
  S32_EXEC_GEO_REGION         ExportAddrRgn;
  S32_EXEC_GEO_REGION         ExportNameRgn;
  S32_EXEC_GEO_REGION         ImportPatchRgn;
  S32_EXEC_GEO_REGION         ImportNameRgn;
  S32_EXEC_GEO_REGION         ExecRgn;
  S32_NCG_CONTEXT           * pNcgCtx;
  const S32_NCG_API         * pNcgApi;
}S32_EXEC_GEO;

Structure members

Member Description
pIdxFn Pointer to dispatch table for function imported by index. Included for backwards compatibility with no support.
IdxCnt Number of functions imported by index. Included for backwards compatibility with no support.
pImpFn Pointer to dispatch table for function imported by name.
ImpCnt Number of functions imported by index.
XDataLen Size of additional memory beyond execution image.
StackLen Size of stack at end of image.
ExportCnt Number of exported functions.
FileRgn Covers entire PEX file.
ExportAddrRgn Export address table.
ExportNameRgn Export name table.
ImportPatchRgn Import patch table.
ImportNameRgn Import name table.
ExecRgn Execution region (does not include stack and xdata, i.e. only the data delivered in the PEX file).
pNcgCtx Pointer to native code generator context.
pNcgApi Pointer to native code generator API.

S32_EXEC_GEO_REGION

Description

Describes a region of the PEX file.

Type definition

typedef struct {
  S32_U32  Off;
  S32_U32  Len;
  S32_U8 * pData;
}S32_EXEC_GEO_REGION;

Structure members

Member Description
Off Byte offset from start of PEX file to region.
Len Size of region in bytes.
pData Native pointer to data associated with region.

S32_EXEC_CONTEXT

Description

Execution context.

Type definition

typedef struct S32_EXEC_CONTEXT_s {
  S32_U32                     aReg[];
  S32_U32                     PC;
  S32_U32                     AluOut;
  S32_U8                    * pMem;
  S32_U32                     ML;
  S32_SERVICE_FUNC *const   * pIdxFn;
  S32_U32                     IdxCnt;
  const S32_SERVICE_BINDING * pImpFn;
  S32_U32                     ImpCnt;
  volatile S32_I32            XR;
  const S32_TELEMETRY_API   * pTelemetryApi;
  S32_I32                     Primed;
  S32_NCG_CONTEXT           * pNcgCtx;
  const S32_NCG_API         * pNcgApi;
  void                      * pUserCtx;
  S32_BT_TIMESTAMP_FUNC     * pfGetTimestamp;
  S32_U32                     Timestamp;
  S32_BT_TELEMETRY_DATA       Telemetry;
}S32_EXEC_CONTEXT;

Structure members

Member Description
aReg [0-14]: general purpose registers. [15]: stack pointer.
PC Program counter, sandbox address, next instruction to execute.
AluOut Last ALU output.
pMem Native pointer to base of S32 application memory space.
ML Highest sandbox address of S32 application memory space + 1.
pIdxFn Pointer to dispatch table for functions imported by index.
IdxCnt Number of functions imported by index.
pImpFn Pointer to dispatch table for functions imported by name.
ImpCnt Number of functions imported by name.
XR Exception register holding exception raised during execution.
pTelemetryApi Pointer to telemetry API responsible for instrumentation.
Primed Flag indicating whether the S32 context is primed for execution.
pNcgCtx Pointer to native code generator context.
pNcgApi Pointer to native code generator API.
pUserCtx Pointer to user context associated with execution context.
pfGetTimestamp Pointer to “get timestamp” function for simplified telemetry.
Timestamp Telemetry timestamp for basic telemetry.
Telemetry Simplified telemetry data

Additional information

Fields in this structure are considered private. Access functions are provided, e.g. S32_RdReg(), to extract useful information from the context. SEGGER does not guarantee that the fields in this structure preserve their name, order, type, or presence between emApps versions.

S32_SERVICE_BINDING

Description

Association of service name and its implementation.

Type definition

typedef struct {
  const char       * sName;
  S32_SERVICE_FUNC * pExec;
}S32_SERVICE_BINDING;

Structure members

Member Description
sName Service name
pExec Service execution function

S32_SERVICE_FUNC

Description

Prototype for service function implementation.

Type definition

typedef S32_U32 S32_SERVICE_FUNC(S32_EXEC_CONTEXT * pCtx);

S32_IMPORT_FUNC

Description

Prototype for imported function enumeration.

Type definition

typedef S32_I32 S32_IMPORT_FUNC(      S32_EXEC_GEO * pGeo,
                                const char         * sName,
                                      S32_U32        CallAddr,
                                      void         * pUserCtx);

Parameters

Parameter Description
pGeo Pointer to application geometry.
sName Pointer to zero-terminated function name.
CallAddr Sandbox address of call instruction.
pUserCtx Pointer to user-provided context.

S32_EXPORT_FUNC

Description

Prototype for exported function enumeration.

Type definition

typedef S32_I32 S32_EXPORT_FUNC(S32_EXEC_GEO    * pGeo,
                                S32_EXPORT_INFO * pInfo,
                                void            * pUserCtx);

Parameters

Parameter Description
pGeo Pointer to application geometry.
pInfo Pointer to export descriptor.
pUserCtx Pointer to user-provided context.

S32_EXPORT_INFO

Description

Exported function information.

Type definition

typedef struct {
  const char * sName;
  S32_I32      Index;
  S32_U32      Addr;
  S32_U32      ParaCnt;
  S32_U32      AttrMask;
}S32_EXPORT_INFO;

Structure members

Member Description
sName Pointer to zero-terminated function name.
Index Exported function index, starting at zero.
Addr Entry point address into the execution region.
ParaCnt Number of parameters function expects.
AttrMask Presence of attributes 0 through 31 in the export descriptor.

S32_TELEMETRY_API

Description

Structure containing telemetry point methods.

Type definition

typedef struct {
  S32_TELEMETRY_EXCP_DETECTED_FUNC * pfExcpDetected;
  S32_TELEMETRY_INSN_BEGIN_FUNC    * pfInsnBegin;
  S32_TELEMETRY_INSN_END_FUNC      * pfInsnEnd;
  S32_TELEMETRY_SERVICE_BEGIN_FUNC * pfServiceBegin;
  S32_TELEMETRY_SERVICE_END_FUNC   * pfServiceEnd;
  S32_TELEMETRY_EXEC_BEGIN_FUNC    * pfExecBegin;
  S32_TELEMETRY_EXEC_END_FUNC      * pfExecEnd;
}S32_TELEMETRY_API;

Structure members

Member Description
pfExcpDetected Called when an exception is detected.
pfInsnBegin Called before an instruction starts to execute.
pfInsnEnd Called after an instruction completes.
pfServiceBegin Called before entering a service function.
pfServiceEnd Called after a service function returns.
pfExecBegin Called after entering S32_Exec().
pfExecEnd Called before leaving S32_Exec().

Additional information

Each member can be NULL to indicate that telemetry for this point is not required.

S32_TELEMETRY_EXEC_BEGIN_FUNC

Description

Prototype for Execution-Begin telemetry point.

Type definition

typedef void S32_TELEMETRY_EXEC_BEGIN_FUNC(S32_EXEC_CONTEXT * pCtx);

Additional information

The Execution-Begin telemetry point is called immediately on entering S32_Exec() to indicate application execution has started.

S32_TELEMETRY_EXEC_END_FUNC

Description

Prototype for Execution-End telemetry point.

Type definition

typedef void S32_TELEMETRY_EXEC_END_FUNC(S32_EXEC_CONTEXT * pCtx);

Additional information

The Execution-End telemetry point is called immediately prior to S32_Exec() returning to indicate application execution has ended.

S32_TELEMETRY_SERVICE_BEGIN_FUNC

Description

Prototype for Service-Begin telemetry point.

Type definition

typedef void S32_TELEMETRY_SERVICE_BEGIN_FUNC(S32_EXEC_CONTEXT * pCtx);

Additional information

The Service-Begin telemetry point is called immediately prior to entering a service function.

The Service-Begin telemetry point is guaranteed to be paired with a following Service-End telemetry point.

The Service-Begin and Service-End telemetry points will be called only between the Instruction-Begin and Instruction-End telemetry points.

S32_TELEMETRY_SERVICE_END_FUNC

Description

Prototype for Service-End telemetry point.

Type definition

typedef void S32_TELEMETRY_SERVICE_END_FUNC(S32_EXEC_CONTEXT * pCtx);

Additional information

The Service-End telemetry point is called immediately after returning from a service function.

S32_TELEMETRY_INSN_BEGIN_FUNC

Description

Prototype for Instruction-Begin telemetry point.

Type definition

typedef void S32_TELEMETRY_INSN_BEGIN_FUNC(S32_EXEC_CONTEXT * pCtx);

Additional information

The Instruction-Begin telemetry point is called immediately prior to executing an instruction.

The Instruction-Begin telemetry point is guaranteed to be paired with a following Instruction-End telemetry point.

The Instruction-Begin and Instruction-End telemetry points will be called only between the Execution-Begin and Execution-End telemetry points.

Notes

The Instruction-Begin telemetry point is only supported by the C executor.

S32_TELEMETRY_INSN_END_FUNC

Description

Prototype for Instruction-End telemetry point.

Type definition

typedef void S32_TELEMETRY_INSN_END_FUNC(S32_EXEC_CONTEXT * pCtx);

Additional information

The Instruction-End telemetry point is called immediately following completion of an instruction.

The Instruction-End telemetry point is guaranteed to be paired with a previous Instruction-Begin telemetry point.

Notes

The Instruction-End telemetry point is only supported by the C executor.

S32_TELEMETRY_EXCP_DETECTED_FUNC

Description

Prototype for Exception-Detected telemetry point.

Type definition

typedef void S32_TELEMETRY_EXCP_DETECTED_FUNC(S32_EXEC_CONTEXT * pCtx);

Additional information

The Exception-Detected telemetry point is called on detection of an exception; this does not fire immediately an exception is raised, i.e. when calling S32_Raise(), it fires when the executor detects the exception in the instruction fetch-decode-execute loop.

It is guaranteed that the exception is raised outside of instruction execution, i.e. never between Instruction-Begin and Instruction-End telemetry points.

S32_BT_TELEMETRY_DATA

Description

Structure containing basic telemetry data.

Type definition

typedef struct {
  S32_U32  ExecCnt;
  S32_U32  ServiceCnt;
  S32_U64  ExecTime;
  S32_U64  ServiceTime;
  S32_U64  TotalTime;
}S32_BT_TELEMETRY_DATA;

Structure members

Member Description
ExecCnt Running count of number of execution invocations.
ServiceCnt Running count of number of service function invocations.
ExecTime Accumulated time in application captured by telemetry.
ServiceTime Accumulated time in service functions captured by telemetry.
TotalTime Accumulated total time executing application and services.

S32_BT_TIMESTAMP_FUNC

Description

Prototype for function returning a timestamp.

Type definition

typedef S32_U32 S32_BT_TIMESTAMP_FUNC(void);

General functions

The table below lists the functions that return information related to the emApps product.

Function Description
S32_GetVersionText() Get emApps product version.
S32_GetCopyrightText() Get emApps copyright attribution.
S32_GetErrorText() Get printable text for error.
S32_CheckConfig() Check configuration of emApps product.

S32_GetVersionText()

Description

Get emApps product version.

Prototype

const char *S32_GetVersionText(void);

Return value

Pointer to a zero-terminated string that contains the version number of the product.

S32_GetCopyrightText()

Description

Get emApps copyright attribution.

Prototype

const char *S32_GetCopyrightText(void);

Return value

Pointer to a zero-terminated string that contains the copyright string.

S32_GetErrorText()

Description

Get printable text for error.

Prototype

const char *S32_GetErrorText(S32_I32 Status);

Parameters

Parameter Description
Status Error or exception code.

Return value

Pointer to string describing error or exception.

S32_CheckConfig()

Description

Check configuration of emApps product.

Prototype

S32_I32 S32_CheckConfig(void);

Return value

= 0 Configuration check passed.
≠ 0 Configuration check failed.

Additional information

If this function fails, check the configuration of the S32 to ensure that data types are correct and, if using the assembly language executor, that calculated offsets into the execution context are correct.

Loading functions

The table below lists the functions that are used to prepare an application for execution.

Function Description
S32_InitGeo() Initialize application geometry.
S32_LoadHeader() Validate application file header.
S32_LoadFile() Load entire application file.

S32_InitGeo()

Description

Initialize application geometry.

Prototype

S32_I32 S32_InitGeo(      S32_EXEC_GEO        * pGeo,
                    const S32_SERVICE_BINDING * pImp,
                          unsigned              ImpCnt);

Parameters

Parameter Description
pGeo Pointer to application geometry.
pImp Pointer to function-imported-by-name table.
ImpCnt Number of entries in function-imported-by-name table.

Return value

≥ 0 Success.
< 0 Failure status.

S32_LoadHeader()

Description

Validate application file header.

Prototype

S32_I32 S32_LoadHeader(      S32_EXEC_GEO * pGeo,
                       const S32_U8       * pFile,
                             S32_U32        FileLen);

Parameters

Parameter Description
pGeo Pointer to object receiving application geometry.
pFile Pointer to PEX file header.
FileLen Total length of PEX file, in bytes.

Return value

≥ 0 Success, number of bytes of additional memory required to hold the stack and xdata areas.
< 0 Failure.

Additional information

The PEX file header consists of eight 32-bit words, and this is all that is examined by S32_LoadHeader(). If FileLen indicates the PEX file does not contain a complete header, an error is returned.

If the file contains a complete header, it is examined and validated as far as it can be. It is not necessary to provide the entire file at this time, only the header part (i.e. 32 bytes). Full validation is deferred to S32_LoadFile(). Note that there is no security risk associated with partial validation of the header, everything that is required during a call to S32_LoadHeader() undergoes validation.

On successful completion, the number of bytes required to hold the stack and xdata areas is returned, which can be used to allocate memory for the execution image in memory before calling S32_LoadFile().

See also

S32_LoadFile.

S32_LoadFile()

Description

Load entire application file.

Prototype

S32_I32 S32_LoadFile(S32_EXEC_GEO * pGeo,
                     S32_U8       * pFile);

Parameters

Parameter Description
pGeo Pointer to object containing application geometry.
pFile Pointer to PEX file content plus additional memory allocated for stack and xdata areas.

Return value

≥ 0 Success, PEX file is valid.
< 0 Failure.

Additional information

Once the PEX file header is validated successfully, the entire execution image is presented for validation in preparation for application execution. S32_LoadFile() validates that the file is structurally sound, that import-by-name functions exist before execution, and that all in-file structural “section offsets” point within and are entirely contained by the section content pointed to.

See also

S32_LoadHeader.

Image inquiry functions

The table below lists the functions that are used to query information on the loaded application.

Function Description
S32_FindImport() Find index of import-by-name function.
S32_FindExport() Find address of exported function.
S32_FindExportEx() Find address of exported function, extended.
S32_IterateImports() Iterate over import table.
S32_IterateExports() Iterate over export table.
S32_PtrToSandboxAddr() Convert pointer to sandbox address.
S32_SandboxAddrToPtr() Convert sandbox address to native pointer.
S32_SandboxAddrToPtrOrNull() Convert sandbox address to native pointer or NULL.
S32_XDataAddr() Get sandbox xdata address.
S32_XDataLen() Get sandbox xdata size.

S32_FindImport()

Description

Find index of import-by-name function.

Prototype

S32_I32 S32_FindImport(      S32_EXEC_GEO * pGeo,
                       const char         * sName);

Parameters

Parameter Description
pGeo Pointer to application geometry.
sName Pointer to zero-terminated function name.

Return value

≥ 0 Index of imported-by-name function in API table.
< 0 Imported function not present.

S32_FindExport()

Description

Find address of exported function.

Prototype

S32_I32 S32_FindExport(      S32_EXEC_GEO * pGeo,
                       const char         * sName);

Parameters

Parameter Description
pGeo Pointer to application geometry.
sName Pointer to zero-terminated function name.

Return value

≥ 0 Succes, sandbox address of function.
< 0 Failure status, function does not exist or PEX file is damaged.

S32_FindExportEx()

Description

Find address of exported function, extended.

Prototype

S32_I32 S32_FindExportEx(      S32_EXEC_GEO    * pGeo,
                         const char            * sName,
                               S32_EXPORT_INFO * pInfo);

Parameters

Parameter Description
pGeo Pointer to application geometry.
sName Pointer to zero-terminated function name.
pInfo Pointer to object that receives additional exported function information. This pointer must not be null.

Return value

≥ 0 Succes, sandbox address of function.
< 0 Failure status, function does not exist or PEX file is damaged.

S32_IterateImports()

Description

Iterate over import table.

Prototype

S32_I32 S32_IterateImports(S32_EXEC_GEO    * pGeo,
                           S32_IMPORT_FUNC * pfVisitor,
                           void            * pUserCtx);

Parameters

Parameter Description
pGeo Pointer to application geometry.
pfVisitor Pointer to visitor function, called for each import.
pUserCtx Pointer to user-provided context, passed to visitor function.

Return value

≥ 0 Success.
< 0 Failure status.

S32_IterateExports()

Description

Iterate over export table.

Prototype

S32_I32 S32_IterateExports(S32_EXEC_GEO    * pGeo,
                           S32_EXPORT_FUNC * pfVisitor,
                           void            * pUserCtx);

Parameters

Parameter Description
pGeo Pointer to application geometry.
pfVisitor Pointer to visitor function, called for each export.
pUserCtx Pointer to user-provided context, passed to visitor function.

Return value

≥ 0 Success.
< 0 Failure status.

S32_SandboxAddrToPtr()

Description

Convert sandbox address to native pointer.

Prototype

void *S32_SandboxAddrToPtr(S32_EXEC_CONTEXT * pCtx,
                           S32_U32            Addr);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Ssandbox address.

Return value

Pointer that is a native address. Note that a sandbox address of zero, corresponding to a null pointer, is converted to a pointer to the start of memory and not to a native null pointer.

It is expected that sandbox addresses are checked for acceptability outside of this function. S32_AcceptStr() and S32_AcceptMem() ensure that accesses through null pointers are detected and, therefore, any string or memory block that passes through S32_AcceptStr() or S32_AcceptMem() is guaranteed to point to a memory block entirely contained in the sandbox address space.

S32_SandboxAddrToPtrOrNull()

Description

Convert sandbox address to native pointer or NULL.

Prototype

void *S32_SandboxAddrToPtrOrNull(S32_EXEC_CONTEXT * pCtx,
                                 S32_U32            Addr);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Ssandbox address.

Return value

Pointer that is a native address. Sandbox address zero converted to a corresponding to a null pointer, otherwise it is converted as S32_SandboxAddrToPtr() would convert it.

It is expected that sandbox addresses are checked for acceptability outside of this function.

S32_PtrToSandboxAddr()

Description

Convert pointer to sandbox address.

Prototype

S32_U32 S32_PtrToSandboxAddr(S32_EXEC_CONTEXT * pCtx,
                             void             * pVoid);

Parameters

Parameter Description
pCtx Pointer to execution context.
pVoid Native address to convert.

Return value

Sandbox address. A null pointer is converted to the sandbox address zero.

S32_XDataAddr()

Description

Get sandbox xdata address.

Prototype

S32_U32 S32_XDataAddr(S32_EXEC_GEO * pGeo);

Parameters

Parameter Description
pGeo Pointer to object containing application geometry.

Return value

Base address of application’s xdata area.

S32_XDataLen()

Description

Get sandbox xdata size.

Prototype

S32_U32 S32_XDataLen(S32_EXEC_GEO * pGeo);

Parameters

Parameter Description
pGeo Pointer to object containing application geometry.

Return value

Size in bytes of application’s xdata area.

Execution functions

The table below lists the functions that are used to control execution.

Function Description
S32_PrepareByName() Prepare context, by function name.
S32_PrepareByAddr() Prepare context, by address.
S32_Exec() Start execution.
S32_GetResult() Read value returned as a function result.
S32_SetUserContext() Associate user context with an execution context.
S32_GetUserContext() Query user context associated with an execution context.

S32_PrepareByName()

Description

Prepare context, by function name.

Prototype

S32_I32 S32_PrepareByName(      S32_EXEC_GEO     * pGeo,
                                S32_EXEC_CONTEXT * pCtx,
                          const char             * sFunc);

Parameters

Parameter Description
pGeo Pointer to object containing application geometry.
pCtx Pointer to execution context to prepare.
sFunc Exported function name to be executed.

Return value

≥ 0 Success, context is prepared, number of parameters function expects.
< 0 Failure.

Additional information

If preparation fails, an exceptional condition is registered in the execution context and an attempt to start execution will immediately fail.

S32_PrepareByAddr()

Description

Prepare context, by address.

Prototype

S32_I32 S32_PrepareByAddr(S32_EXEC_GEO     * pGeo,
                          S32_EXEC_CONTEXT * pCtx,
                          S32_U32            Addr);

Parameters

Parameter Description
pGeo Pointer to object containing application geometry.
pCtx Pointer to execution context to prepare.
Addr Address of function to be executed.

Return value

≥ 0 Success, context is prepared.
< 0 Failure.

Additional information

If preparation fails, an exceptional condition is registered in the execution context and an attempt to start execution will immediately fail.

S32_Exec()

Description

Start execution.

Prototype

S32_I32 S32_Exec(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

= S32_ERROR_NONE No execution error.
S32_ERROR_NONE Termination condition.

Additional information

This function starts executing instructions until an exception is raised. When a top-level function returns, a “break” exception is raised causing termination.

S32_GetResult()

Description

Read value returned as a function result.

Prototype

S32_U32 S32_GetResult(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Function result.

S32_SetUserContext()

Description

Associate user context with an execution context.

Prototype

void S32_SetUserContext(S32_EXEC_CONTEXT * pCtx,
                        void             * pUserCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.
pUserCtx Pointer to user context.

S32_GetUserContext()

Description

Query user context associated with an execution context.

Prototype

void *S32_GetUserContext(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Pointer to the user context associated with the execution context.

Service API support functions

The table below lists the functions that are used to implement service API functions that operate within a sandbox.

Function Description
S32_GetArg() Read function argument.
S32_AcceptMem() Check address range against sandbox.
S32_AcceptMemBits() Check address range against sandbox.
S32_AcceptMemOrNull() Check address range against sandbox, allow null pointer.
S32_AcceptStr() Check string against sandbox.

S32_GetArg()

Description

Read function argument.

Prototype

S32_U32 S32_GetArg(S32_EXEC_CONTEXT * pCtx,
                   int                Para);

Parameters

Parameter Description
pCtx Pointer to execution context.
Para Parameter index, zero being the first function parameter.

Return value

If the parameter lies outside of the sandbox address space, the return value has zero substituted and an access violation exception is raised in the execution context.

S32_AcceptMem()

Description

Check address range against sandbox.

Prototype

int S32_AcceptMem(S32_EXEC_CONTEXT * pCtx,
                  S32_U32            Addr,
                  S32_U32            Len);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address of first address of range.
Len Size in bytes of the address range to test.

Return value

= 0 Address range fails the test and is entirely or partly outside of the sandbox address space.
≠ 0 Address range passes the test and is entirely within the sandbox address space.

Additional information

If any of the address range lies outside of the sandbox address space, an access violation exception is raised in the execution context.

S32_AcceptMemBits()

Description

Check address range against sandbox.

Prototype

int S32_AcceptMemBits(S32_EXEC_CONTEXT * pCtx,
                      S32_U32            Addr,
                      S32_U32            Len);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address of first address of range.
Len Size in bits of the address range to test. The number of bits is rounded up to the next byte boundary.

Return value

= 0 Address range fails the test and is entirely or partly outside of the sandbox address space.
≠ 0 Address range passes the test and is entirely within the sandbox address space.

Additional information

If any of the address range lies outside of the sandbox address space, an access violation exception is raised in the execution context.

S32_AcceptMemOrNull()

Description

Check address range against sandbox, allow null pointer.

Prototype

int S32_AcceptMemOrNull(S32_EXEC_CONTEXT * pCtx,
                        S32_U32            Addr,
                        S32_U32            Len);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address of first address of range.
Len Size in bytes of the address range to test.

Return value

= 0 Address range fails the test and is entirely or partly outside of the sandbox address space.
≠ 0 Address range passes the test and is entirely within the sandbox address space.

Additional information

If any of the address range lies outside of the sandbox address space, an access violation exception is raised in the execution context.

If the address is S32_NULL, representing the C null pointer, the length must also be zero.

S32_AcceptStr()

Description

Check string against sandbox.

Prototype

int S32_AcceptStr(S32_EXEC_CONTEXT * pCtx,
                  S32_U32            Addr,
                  S32_U32            MaxLen);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address of the zero-terminated string.
MaxLen Maximum number of bytes to examine for null terminator.

Return value

= 0 String fails the test and is wholly or partly outside of the application’s address space.
≠ 0 String passes the test and is wholly within the application’s address space.

Additional information

If the string wholly or partially lies outside of the application’s address space, an access violation exception is raised.

Telemetry functions

The table below lists the functions that are used to acquire telemetry data about an application.

Function Description
Basic telemetry
S32_BT_ConfigTelemetry() Select basic telemetry.
S32_BT_ResetTelemetry() Set basic telemetry data to zero.
S32_BT_QueryTelemetry() Query basic telemetry data.
User-defined telemetry
S32_SetTelemetryAPI() Set telemetry API for execution context.

S32_BT_ConfigTelemetry()

Description

Select basic telemetry.

Prototype

S32_I32 S32_BT_ConfigTelemetry(S32_EXEC_CONTEXT      * pCtx,
                               S32_BT_TIMESTAMP_FUNC * pfGetTimestamp);

Parameters

Parameter Description
pCtx Pointer to execution context.
pfGetTimestamp Pointer to function that returns a timestamp.

Return value

≥ 0 Timestamp function installed and telemetry activated.
= S32_ERROR_NOT_SUPPORTED Basic telemetry is not supported.

Additional information

This function installs basic telemetry support using timestamps delivered by the function pointed to by pfGetTimestamp.

Note that telemetry data is not zeroed when the execution context is prepared using S32_PreapreByName() or S32_PrepareByAddr(), and it is not zeroed when selecting basic telemetry using S32_BT_ConfigTelemetry(). Basic telemetry data must be zeroed by calling S32_ResetTelemetry() before acquisition commences.

Basic telemetry is configured by building with S32_CONFIG_TELEMETRY=1.

See also

S32_ResetTelemetry()

S32_BT_ResetTelemetry()

Description

Set basic telemetry data to zero.

Prototype

void S32_BT_ResetTelemetry(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Additional information

Telemetry data, if used, must be zeroed before application execution starts.

S32_BT_QueryTelemetry()

Description

Query basic telemetry data.

Prototype

void S32_BT_QueryTelemetry(S32_EXEC_CONTEXT      * pCtx,
                           S32_BT_TELEMETRY_DATA * pData,
                           unsigned                Mul,
                           unsigned                Div);

Parameters

Parameter Description
pCtx Pointer to execution context.
pData Pointer to object that receives the basic telemetry data.
Mul Numerator of fractional multiplier.
Div Denominator of fractional multiplier.

Additional information

This function queries the basic telemetry data for total time spent in service functions. If no basic telemetry is configured, or user-defined telemetry is configured, all telemetry data returned are zero.

Telemetry data is collected using the timestamps returned by the get-timestamp function passed to S32_BT_ConfigTelemetry(). Typically the processor’s cycle counter or an RTOS’s tick counter are used as a reference.

The telemetry data returned by S32_BT_QueryTelemetry() can be scaled by the fraction Mul/Div to convert timestamp units into a more accessible form for presentation.

For instance, a 600 MHz device using the processor’s cycle counter as reference provides accurate telemetry in cycles, but is not that useful when analyzing it. Therefore, passing Mul=1 and Div=600 would return telemetry data in microsecond units, or Mul=1 and Div=60000 would return it in millisecond units.

S32_SetTelemetryAPI()

Description

Set telemetry API for execution context.

Prototype

S32_I32 S32_SetTelemetryAPI(      S32_EXEC_CONTEXT  * pCtx,
                            const S32_TELEMETRY_API * pApi);

Parameters

Parameter Description
pCtx Pointer to execution context.
pApi Pointer to telemetry API.

Return value

≥ 0 Telemetry API installed for user-defined telemetry.
< 0 Telemetry is not configured or basic telemetry is configured.

Additional information

User-defined telemetry is configured by building with S32_CONFIG_TELEMETRY=2.

Machine state functions

The table below lists the functions that are used to read and write the application memory space.

Function Description
Accessing registers
S32_RdPC() Read program counter register.
S32_RdML() Read memory limit register.
S32_RdXR() Read exception register.
S32_RdReg() Read general-purpose register.
Accessing memory
S32_RdMem_U8() Read sandbox memory, U8.
S32_RdMem_U16() Read sandbox memory, U16.
S32_RdMem_U32() Read sandbox memory, U32.
S32_RdMem_Blk() Read sandbox memory, block.
S32_WrMem_U8() Write sandbox memory, U8.
S32_WrMem_U16() Write sandbox memory, U16.
S32_WrMem_U32() Write sandbox memory, U32.
S32_WrMem_Blk() Write sandbox memory, block.
Utility functions
S32_Push() Push to stack.
S32_Raise() Raise exception.
S32_Continue() Query if execution should continue.

S32_RdPC()

Description

Read program counter register.

Prototype

S32_U32 S32_RdPC(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Program counter, offset into the execution area.

S32_RdML()

Description

Read memory limit register.

Prototype

S32_U32 S32_RdML(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Memory limit of S32 address space.

S32_RdXR()

Description

Read exception register.

Prototype

S32_U32 S32_RdXR(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

If no exception has been raised, S32_ERROR_NONE (defined as zero) is returned. Any other value raised by S32_Raise() is taken to be an exceptional state and is the exception value returned.

S32_RdReg()

Description

Read general-purpose register.

Prototype

S32_U32 S32_RdReg(S32_EXEC_CONTEXT * pCtx,
                  unsigned           Index);

Parameters

Parameter Description
pCtx Pointer to execution context.
Index Register index, 0 through 15.

Return value

Value of register.

S32_RdMem_U8()

Description

Read sandbox memory, U8.

Prototype

S32_U32 S32_RdMem_U8(S32_EXEC_CONTEXT * pCtx,
                     S32_U32            Addr);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address to read from.

Return value

U8 at the sandbox address if the address is valid, and zero if the sandbox address is not valid.

Additional information

If the datum lies outside of the sandbox address space, the return value has zero substituted and an access violation exception is raised in the execution context.

S32_RdMem_U16()

Description

Read sandbox memory, U16.

Prototype

S32_U32 S32_RdMem_U16(S32_EXEC_CONTEXT * pCtx,
                      S32_U32            Addr);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address to read from.

Return value

U16 at the sandbox address if the address is valid, and zero if the address is not valid.

Additional information

If the datum lies outside of the sandbox address space, the return value has zero substituted and an access violation exception is raised in the execution context.

S32_RdMem_U32()

Description

Read sandbox memory, U32.

Prototype

S32_U32 S32_RdMem_U32(S32_EXEC_CONTEXT * pCtx,
                      S32_U32            Addr);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address to read from.

Return value

U32 at the sandbox address if the address is valid, and zero if the address is not valid.

Additional information

If the datum lies outside of the sandbox address space, the return value has zero substituted and an access violation exception is raised in the execution context.

S32_RdMem_Blk()

Description

Read sandbox memory, block.

Prototype

void S32_RdMem_Blk(S32_EXEC_CONTEXT * pCtx,
                   S32_U32            Addr,
                   S32_U8           * pData,
                   S32_U32            DataLen);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address to read from.
pData Pointer to object that receives the data read.
DataLen Octet length of data to read.

Additional information

If any of the the data lies outside of the sandbox address space, the read is canceled and an access violation exception is raised in the execution context.

S32_WrMem_U8()

Description

Write sandbox memory, U8.

Prototype

void S32_WrMem_U8(S32_EXEC_CONTEXT * pCtx,
                  S32_U32            Addr,
                  S32_U32            Val);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address to write to.
Val Value to write.

Additional information

If the datum lies outside of the sandbox address space, the write is canceled and and an access violation exception is raised in the execution context.

S32_WrMem_U16()

Description

Write sandbox memory, U16.

Prototype

void S32_WrMem_U16(S32_EXEC_CONTEXT * pCtx,
                   S32_U32            Addr,
                   S32_U32            Val);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address to write to.
Val Value to write.

Additional information

If the datum lies outside of the sandbox address space, the write is canceled and an access violation exception is raised in the execution context.

S32_WrMem_U32()

Description

Write sandbox memory, U32.

Prototype

void S32_WrMem_U32(S32_EXEC_CONTEXT * pCtx,
                   S32_U32            Addr,
                   S32_U32            Val);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address to write to.
Val Value to write.

Additional information

If the datum lies outside of the sandbox address space, the write is canceled and an access violation exception is raised in the execution context.

S32_WrMem_Blk()

Description

Write sandbox memory, block.

Prototype

void S32_WrMem_Blk(      S32_EXEC_CONTEXT * pCtx,
                         S32_U32            Addr,
                   const S32_U8           * pData,
                         S32_U32            DataLen);

Parameters

Parameter Description
pCtx Pointer to execution context.
Addr Sandbox address to write to.
pData Pointer to data to write.
DataLen Octet length of data to write.

Additional information

If any of the the data lies outside of the sandbox address space, the write is canceled and an access violation exception is raised in the execution context.

S32_Push()

Description

Push to stack.

Prototype

void S32_Push(S32_EXEC_CONTEXT * pCtx,
              S32_U32            Val);

Parameters

Parameter Description
pCtx Pointer to execution context.
Val Value to push.

Additional information

If the address written when pushing lies outside the sandbox address space, the write is canceled and an access violation exception is raised in the execution context.

S32_Raise()

Description

Raise exception.

Prototype

void S32_Raise(S32_EXEC_CONTEXT * pCtx,
               S32_I32            Code);

Parameters

Parameter Description
pCtx Pointer to execution context.
Code Exception to raise. If Code is zero, it is replaced with a breakpoint exception.

Additional information

This sets the execution environment into an exceptional state and causes immediate termination of the application.

S32_Continue()

Description

Query if execution should continue.

Prototype

int S32_Continue(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

≠ 0 No exception raised, execution can continue.
= 0 Exception raised, execution should not continue.

Application API reference

This chapter details some optional functions that can be added to the service API table to offer additional functions available to the application.

Runtime functions

The table below lists the functions that are used for C-language runtime support. If your application uses division or modulo operators, it will likely require these functions to be present in the service API table.

Function Description
S32_API_S32_idiv() Signed division.
S32_API_S32_imod() Signed modulus.
S32_API_S32_udiv() Unsigned division.
S32_API_S32_umod() Unsigned modulus.

Application interface

The following is the interface provided to the application and may be required by the C compiler to implement division and modulus with unknown inputs:

/*********************************************************************
*
*       Runtime functions
*/
__imp int      __S32_imod     (int, int);
__imp int      __S32_idiv     (int, int);
__imp unsigned __S32_umod     (unsigned, unsigned);
__imp unsigned __S32_udiv     (unsigned, unsigned);

Binding

The functions above can be bound using the following service table:

static const _aServices[] = {
  { "__S32_umod", S32_API_S32_umod },
  { "__S32_udiv", S32_API_S32_udiv },
  { "__S32_imod", S32_API_S32_imod },
  { "__S32_idiv", S32_API_S32_idiv },
};

S32_API_S32_idiv()

Description

Signed division.

Prototype

S32_U32 S32_API_S32_idiv(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Quotient.

Additional information

If the divisor is zero, a zero-divide exception is raised in the execution context.

This function implements the function __S32_idiv() that the compiler calls in order to perform signed division:

int __S32_idiv(int Num, int Div);

S32_API_S32_imod()

Description

Signed modulus.

Prototype

S32_U32 S32_API_S32_imod(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Modulus.

Additional information

If the divisor is zero, a zero-divide exception is raised in the execution context.

This function implements the function __S32_imod() that the compiler calls in order to perform signed remainder-after-division:

int __S32_imod(int Num, int Div);

S32_API_S32_udiv()

Description

Unsigned division.

Prototype

S32_U32 S32_API_S32_udiv(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Quotient.

Additional information

If the divisor is zero, a zero-divide exception is raised in the execution context.

This function implements the function __S32_udiv() that the compiler calls in order to perform unsigned division:

unsigned __S32_udiv(unsigned Num, unsigned Div);

S32_API_S32_umod()

Description

Unsigned modulus.

Prototype

S32_U32 S32_API_S32_umod(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Modulus.

Additional information

If the divisor is zero, a zero-divide exception is raised in the execution context.

This function implements the function __S32_umod() that the compiler calls in order to perform unsigned remainder-after-division:

unsigned __S32_umod(unsigned Num, unsigned Div);

Introspection functions

The table below lists the functions that can be used within an application to find services offered by the program.

Service functions

Function Description
S32_API_S32_FindService() Find service API function.
S32_API_S32_ExecService() Execute service API function.

Application interface

The following is the interface provided to the application:

/*********************************************************************
*
*       Introspection functions
*/
__imp int      SYS_FindService(const char *sName);
__imp unsigned SYS_ExecService(int ServiceHandle, ...);

Binding

The functions above can be bound for use on a Microsoft Windows operating system, using the following service table:

static S32_SERVICE_BINDING _aServices[] = {
  { "SYS_FindService", S32_API_S32_FindService },
  { "SYS_ExecService", S32_API_S32_ExecService },
};

S32_API_S32_FindService()

Description

Find service API function.

Prototype

S32_U32 S32_API_S32_FindService(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

≥ 0 Handle to service API function.
< 0 Service API not found.

Additional information

This function implements:

int SYS_FindService(const char *sName);

S32_API_S32_ExecService()

Description

Execute service API function.

Prototype

S32_U32 S32_API_S32_ExecService(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by executed service API function.

Additional information

This function implements:

int SYS_ExecService(int Handle, …);

C library functions

The functions in this section can be installed into the service API table to provide fully sandboxed implementations of the equivalent C library functions.

The C source files for these functions are provided in the Etc folder.

Function Description
S32_API_C_memset() Fill memory.
S32_API_C_memcpy() Copy memory.
S32_API_C_memmove() Move memory.
S32_API_C_memchr() Find character, in memory.
S32_API_C_strcpy() Copy string.
S32_API_C_strcat() Concatenate strings.
S32_API_C_strlen() Calculate string length.
S32_API_C_strchr() Find character, in string.
S32_API_C_strcmp() Compare strings.
S32_API_C_putchar() Write standard output, character.
S32_API_C_puts() Write standard output, string.
S32_API_C_printf() Write standard output, formatted.
S32_API_C_sprintf() Write string, formatted.
S32_API_C_snprintf() Write string, formatted.

S32_API_C_memset()

Description

Fill memory.

Prototype

S32_U32 S32_API_C_memset(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by memset().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function memset():

void * memset(void *pDst, int Val, unsigned DstLen);

S32_API_C_memcpy()

Description

Copy memory.

Prototype

S32_U32 S32_API_C_memcpy(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by memcpy().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function memcpy():

void * memcpy(void *pDst, const void *pSrc, unsigned Len);

S32_API_C_memmove()

Description

Move memory.

Prototype

S32_U32 S32_API_C_memmove(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by memmove().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function memmove():

void * memmove(void *pDst, const void *pSrc, unsigned Len);

S32_API_C_memchr()

Description

Find character, in memory.

Prototype

S32_U32 S32_API_C_memchr(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by memchr().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function memchr():

void * memchr(const void *pSrc, int Chr, unsigned Len);

S32_API_C_strcpy()

Description

Copy string.

Prototype

S32_U32 S32_API_C_strcpy(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by strcpy().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function strcpy():

char * strcpy(char *pDst, const char *pSrc);

S32_API_C_strcat()

Description

Concatenate strings.

Prototype

S32_U32 S32_API_C_strcat(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by strcat().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function strcpy():

char * strcat(char *pDst, const char *pSrc);

S32_API_C_strlen()

Description

Calculate string length.

Prototype

S32_U32 S32_API_C_strlen(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by strlen().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function strlen():

unsigned strlen(const char *pSrc);

S32_API_C_strchr()

Description

Find character, in string.

Prototype

S32_U32 S32_API_C_strchr(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by strchr().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function strchr():

char * strchr(const char *pSrc, int Chr, unsigned Len);

S32_API_C_strcmp()

Description

Compare strings.

Prototype

S32_U32 S32_API_C_strcmp(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by strcmp().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function strcmp():

int strcmp(const char *pSrc1, const char *pSrc2);

S32_API_C_putchar()

Description

Write standard output, character.

Prototype

S32_U32 S32_API_C_putchar(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by putchar().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function putchar():

int putchar(int Ch);

S32_API_C_puts()

Description

Write standard output, string.

Prototype

S32_U32 S32_API_C_puts(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Value returned by puts().

Additional information

Implementation is fully sandboxed.

This function implements the standard C function puts():

int puts(const char *sSrc);

S32_API_C_printf()

Description

Write standard output, formatted.

Prototype

S32_U32 S32_API_C_printf(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to formatting context.

Return value

Value returned from printf().

This function implements the standard C function printf():

int printf(const char *sFmt, …);

S32_API_C_sprintf()

Description

Write string, formatted.

Prototype

S32_U32 S32_API_C_sprintf(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to formatting context.

Return value

Value returned from sprintf().

This function implements the standard C function sprintf():

int sprintf(char *pDst, const char *sFmt, …);

S32_API_C_snprintf()

Description

Write string, formatted.

Prototype

S32_U32 S32_API_C_snprintf(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to formatting context.

Return value

Value returned from sprintf().

This function implements the standard C function sprintf():

int snprintf(char *pDst, unsigned MaxLen, const char *sFmt, …);

Utility functions

The functions in this section can be installed into the service API table as generic functions. The C and C++ source files for these functions are provided in the Etc folder.

Function Description
S32_API_Util_GetTime_ms() Get time, milliseconds.
S32_API_Util_GetTime_us() Get time, microseconds.
S32_API_Util_Sleep_ms() Sleep, duration in milliseconds.
S32_API_Util_Sleep_ns() Sleep, duration in nanoseconds.
S32_API_Util_MulDiv() Fractional multiply.
S32_API_Util_FOpen() Open file.
S32_API_Util_FClose() Close file.
S32_API_Util_FRead() Read file.
S32_API_Util_FWrite() Write file.

Installation

The functions above can be installed for use with the Flasher using the following API table:

static S32_SERVICE_BINDING _aServices[] = {
  { "UTIL_MulDiv",    S32_API_Util_MulDiv     },
  { "SYS_GetTime_ms", S32_API_Util_GetTime_ms },
  { "SYS_GetTime_us", S32_API_Util_GetTime_us },
  { "SYS_Sleep_ms",   S32_API_Util_Sleep_ms   },
  { "SYS_Sleep_ns",   S32_API_Util_Sleep_ns   },
  { "FOpen",          S32_API_Util_FOpen      },
  { "FClose",         S32_API_Util_FClose     },
  { "FRead",          S32_API_Util_FRead      },
  { "FWrite",         S32_API_Util_FWrite     },
};

Application interface

To use these functions (as implemented by the SEGGER Flasher), use the following definitions:

#define FILE_MODE_READ     (1u<<0)
#define FILE_MODE_WRITE    (1u<<2)

__imp unsigned SYS_GetTime_ms (void);
__imp unsigned SYS_GetTime_us (void);
__imp void     SYS_Sleep_us   (unsigned Cnt);
__imp void     SYS_Sleep_ns   (unsigned Cnt);
__imp unsigned UTIL_MulDiv    (unsigned Val, unsigned Mul, unsigned Div);
__imp int      FOpen          (const char *sName, int Mode);
__imp int      FClose         (int Handle);
__imp int      FRead          (int Handle, void *pBuf, unsigned BufLen);
__imp int      FWrite         (int Handle, const void *pBuf, unsigned BufLen);

S32_API_Util_GetTime_ms()

Description

Get time, milliseconds.

Prototype

S32_U32 S32_API_Util_GetTime_ms(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Time in milliseconds.

Additional information

This function implements the prototype:

unsigned SYS_GetTime_ms(void);

S32_API_Util_GetTime_us()

Description

Get time, microseconds.

Prototype

S32_U32 S32_API_Util_GetTime_us(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Time in microseconds.

Additional information

This function implements the prototype:

unsigned SYS_GetTime_us(void);

S32_API_Util_Sleep_ms()

Description

Sleep, duration in milliseconds.

Prototype

S32_U32 S32_API_Util_Sleep_ms(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Zero, success.

Additional information

This function implements the prototype:

unsigned SYS_Sleep_ms(unsigned Cnt);

S32_API_Util_Sleep_ns()

Description

Sleep, duration in nanoseconds.

Prototype

S32_U32 S32_API_Util_Sleep_ns(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Zero, success.

Additional information

This function implements the prototype:

unsigned SYS_Sleep_ns(unsigned Cnt);

S32_API_Util_MulDiv()

Description

Fractional multiply.

Prototype

S32_U32 S32_API_Util_MulDiv(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

Val * Mul/Div using 64-bit arithmetic.

Additional information

If Div is zero, a zero-divide exception is raised in the execution context.

This function implements the prototype:

unsigned UTIL_MulDiv(void);

S32_API_Util_FOpen()

Description

Open file.

Prototype

S32_U32 S32_API_Util_FOpen(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

≥ 0 File handle.
< 0 Error opening file.

Additional information

This function implements the prototype:

unsigned FOpen(const char *sName, int Mode);

S32_API_Util_FClose()

Description

Close file.

Prototype

S32_U32 S32_API_Util_FClose(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

≥ 0 Success.
< 0 Write error or invalid file handle.

Additional information

This function implements the prototype:

unsigned FClose(int Handle);

S32_API_Util_FRead()

Description

Read file.

Prototype

S32_U32 S32_API_Util_FRead(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

≥ 0 Success, number of bytes read.
< 0 Read error or invalid file handle.

Additional information

This function implements the prototype:

int FRead(int Handle, void *pData, unsigned DataLen);

S32_API_Util_FWrite()

Description

Write file.

Prototype

S32_U32 S32_API_Util_FWrite(S32_EXEC_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to execution context.

Return value

≥ 0 Success, number of bytes written.
< 0 Write error or invalid file handle.

Additional information

This function implements the prototype:

int FWrite(int Handle, const void *pData, unsigned DataLen);

Native code generator (Add-on)

This chapter describes the native code generation add-on for emApps.

What is the native code generator?

The emApps native code generator add-on provides a means to accelerate execution of applications by translating them into native machine instructions. The native code generator is small and fast, does not require excessive resources for translation, and produces excellent code, and is uniquely positioned for on-device just-in-time code tranlsation on low-end microcontrollers.

Not all applications can be native coded

The native code generator is not able to translate all applications into natve code. Whilst it is certainly possible to always translate applications to native code, doing so would complicate the code generator, make its code footprint much bigger, it would take longer to analyze and generate native code, and the workspace required would be much larger. As such, the native code generator will translate typical applications into native code without issue. Applications that make use of function pointers will not be translated to native code by the native code generator.

Using the code generator

Accelerating execution by the native code generator requires that code is generated after the application is loaded into memory by S32_LoadFile(). Once loaded, code generation can be requested using S32_NCG_GenerateCode() or S32_NCG_GenerateCodeEx() to provide detailed information about the generated code.

The code generator context

The code generator context is required to hold overall progress of the code generation process.

The code generation workspace

The native code generator requires a workspace to use for bookkeeping when generating native code and for storing the native code generated. The workspace required depends upon the complexity and size of the application to native code and the options selected for code generation. For the T32 instruction set, for instance, using an estimate of “code size multiplied by 1.7” is generally adequate, however workspace allocation is described in more detail in Strategies for workspace allocation.

For simplicity, a single block of memory can be reserved using the C malloc() function, or a static array can be used, e.g.

static unsigned aWorkspace[1024];  // 4K workspace on 32-bit machine

The workspace provided to the code generator must be correctly aligned for the target architecture, e.g. be on a double-word boundary for Arm architectures—the C malloc() and realloc() functions guarantee that allocated memory blocks are aligned to the maximum alignment for the target architecture.

Relying on alignment using “unsigned” as the underlying datatype does not, in general, guarantee alignment to the maximal alignment of the machine. For instance, on Arm, the alignment of unsigned is 4, but the maximal alignment is 8 in order that 64-bit data can be loaded and stored using LDRD and STRD instructions and that items on the stack are 64-bit aligned as required by the Arm calling convention.

Alignment can be forced by using either compiler attributes, which is generally nonportable, or by forcing alignment using a union.

For instance, alignment can be specified using GCC or clang using an attribute:

static unsigned char __attribute__((__aligned__(8))) _aWorkspace[4096];

Alignment can be specified in a compiler-indepdent way using a union:

static union {
  unsigned char      aBytes[4096];  // 4Kbytes
  unsigned long long ForceAlign;    // Force 64-bit alignment
} _Workspace;

Strategies for workspace allocation

It is possible to attempt code generation multiple times, increasing the size of the workspace until code generation succeeds. For instance, a simple “double the workspace size and try again” strategy would be:

void     * pWs;      // Pointer to current workspace
void     * pNewWs;   // Pointer to new workspace
unsigned   WsSize;   // Current workspace size
int        Status;
//
WsSize = 1024;                     // 1 kilobyte to start with
pWs    = NULL;                     // Workspace not yet allocated
Status = S32_ERROR_OUT_OF_MEMORY;  // Code generation has not yet succeeded
//
for (;;) {
  //
  // Try to extend the workspace.
  //
  pNewWs = realloc(pWs, WsSize);
  if (pNewWs == NULL) {
    break;  // Failed to allocate workspace
  }
  //
  // Workspace is extended, try code generation.
  //
  pWs = pNewWs;
  Status = S32_NCG_GenerateCodeEx(&Geo,             // Application geometry
                                  &S32_NCG_T32_API, // Code for T32 instruction set
                                  ~0u,              // Enable all optimizations
                                  pWs,              // Workspace, correctly aligned
                                  WsSize);          // Size of workspace, in bytes
  //
  // Exit the loop if code generation succeeded or something
  // other than an out-of-memory error occurred.
  //
  if (Status >= 0 || Status != S32_ERROR_OUT_OF_MEMORY) {
    break;
  }
  //
  // Double the workspace size and try again.
  //
  WsSize *= 2;
}
//
// If code generation failed, recover workspace memory.
//
if (Status < 0) {
  free(pWs);
}

The reallocation strategy is entirely under user control. Other strategies could be:

Example NCG application

The following application generates code for a Cortex device that implements the T32 instruction set. The example is for 2000 iterations of Dhrystone:

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

Purpose     : Simple load-and-go for DemoDhrystone.c using native
              code generation.

*/

/*********************************************************************
*
*       #include section
*
**********************************************************************
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "S32.h"
#include "S32_API_C.h"
#include "S32_API_Util.h"

/*********************************************************************
*
*       Check configuration
*
**********************************************************************
*/

/*********************************************************************
*
*       Prototypes
*
**********************************************************************
*/

static S32_U32 _SYS_GetTime_ms(S32_EXEC_CONTEXT *pCtx);

/*********************************************************************
*
*       Static const data
*
**********************************************************************
*/

//
// Application as an array of bytes.
//
#include "DemoDhrystone_2k_pex.h"

//
// Service API exported to the application.
//
static const S32_SERVICE_BINDING _aServices[] = {
  { "printf",         S32_API_C_printf    },
  { "__S32_idiv",     S32_API_S32_idiv    },
  { "__S32_udiv",     S32_API_S32_udiv    },
  { "UTIL_MulDiv",    S32_API_Util_MulDiv },
  { "SYS_GetTime_ms", _SYS_GetTime_ms     },
};

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/

static union {
  S32_U8             aBytes[4096];  // 4Kbytes
  unsigned long long ForceAlign;    // Force 64-bit alignment
} _Workspace;

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/

/*********************************************************************
*
*       _SYS_GetTime_ms()
*
*  Function description
*    Get current millisecond timer.
*
*  Parameters
*    pCtx - Pointer to execution context.
*/
static S32_U32 _SYS_GetTime_ms(S32_EXEC_CONTEXT *pCtx) {
  unsigned CycleCnt;
  //
  (void)pCtx;
  //
  // Get cycle count from core.  Assume core runs at 100 MHz
  // then milliseconds elapsed is CycleCnt / 100000.
  //
  CycleCnt = *(unsigned *)0xE0001004;
  return CycleCnt / 100000;
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       main()
*
*  Function description
*    Program entry point.
*
*  Return value
*    Application exit code.
*/
int main(void) {
  S32_EXEC_GEO       Geo;
  S32_EXEC_CONTEXT   Ctx;
  S32_U8           * pImage;
  S32_NCG_INFO       Info;
  unsigned           Flags;
  S32_I32            Status;
  //
  if (S32_CheckConfig() != S32_ERROR_NONE) {
    printf("S32 configuration check failed\n");
    exit(EXIT_FAILURE);
  }
  //
  pImage  = NULL;
  Status = S32_InitGeo(&Geo,
                       _aServices, sizeof(_aServices)/sizeof(_aServices[0]));
  if (Status >= 0) {
    Status = S32_LoadHeader(&Geo, _aDemoDhrystone_2k, sizeof(_aDemoDhrystone_2k));
    if (Status >= 0) {
      pImage = malloc(sizeof(_aDemoDhrystone_2k) + Status);
      if (pImage == NULL) {
        Status = S32_ERROR_OUT_OF_MEMORY;
      } else {
        memcpy(pImage, _aDemoDhrystone_2k, sizeof(_aDemoDhrystone_2k));
        Status = S32_LoadFile(&Geo, pImage);
        if (Status >= 0) {
          //
          // Select all configured optimization features.
          //
          Flags = S32_NCG_CONFIG_T32_FLAGS;
          //
          // Turn off default generation of all sandbox checks.
          //
          Flags &= ~S32_NCG_T32_FLAG_SANDBOX_INLINE;
          Flags &= ~S32_NCG_T32_FLAG_SANDBOX_OUTLINE;
          //
          // Force generation of sandbox checks with inline code,
          // not millicode subroutines.
          //
          Flags |= S32_NCG_T32_FLAG_SANDBOX_INLINE;
          //
          Status = S32_NCG_GenerateCodeEx(&Geo, 
                                          &S32_NCG_T32_API,
                                          Flags,
                                          &_Workspace,
                                          sizeof(_Workspace),
                                          &Info);
          if (Status >= 0) {
            //
            printf("Native code generation successful:\n");
            printf("  %d bytes of native code generated...\n",
                   Info.NativeCodeSize);
            printf("  ...clear instruction cache from %08X to %08X\n",
                   Info.NativeCodeAddr,
                   Info.NativeCodeAddr + Info.NativeCodeSize - 1);
            printf("  ...%d bytes of workspace must be retained\n", Status);
            printf("\n");
          } else {
            printf("Native code generation failed:\n");
            printf("  %s (%d)\n", S32_GetErrorText(Status), Status);
            printf("Reverting to standard executor\n");
            printf("\n");
          }
          Status = S32_PrepareByName(&Geo, &Ctx, "main");
          if (Status >= 0) {
            Status = S32_Exec(&Ctx);
          }
        }
      }
    }
  }
  //
  free(pImage);
  printf("\n*** Application exited with %s (%d)\n", S32_GetErrorText(Status), Status);
  //
  return Status;
}

/*************************** End of file ****************************/

Code generator functions

The table below lists the functions that are used to inquire and support native code generation.

Function Description
Inquiry functions
S32_NCG_GetArchitecture() Get architecture code is generated for.
S32_NCG_GetSupported() Query code generation features supported.
S32_NCG_IsSupported() Query if code generation features supported.
Generation functions
S32_NCG_GenerateCode() Generate native code for application.
S32_NCG_GenerateCodeEx() Generate native code for application, extended.

S32_NCG_INFO

Description

Information relating to generated code.

Type definition

typedef struct {
  unsigned  PeakWorkSize;
  unsigned  PeakTransTableSize;
  unsigned  FinalWorkSize;
  unsigned  FinalTransTableSize;
  unsigned  S32CodeSize;
  unsigned  NativeCodeAddr;
  int       ContextSize;
  int       NativeCodeSize;
  int       PureCodeSize;
  int       MillicodeSize;
  int       VeneerSize;
  S32_U16   aChkCnt[];
  S32_U16   aOptCnt[];
}S32_NCG_INFO;

Structure members

Member Description
PeakWorkSize Peak number of bytes used in workspace
PeakTransTableSize Peak number of bytes used by branch target translation table in workspace
FinalWorkSize Final number of bytes used in workspace (after any minimization)
FinalTransTableSize Final number of bytes used by branch target translation table in workspace (after any minimization)
S32CodeSize Total number of bytes of S32 code processed
NativeCodeAddr Start address of native code relative to start of workspace, if generated into workspace
ContextSize Fixed overhead for generation context
NativeCodeSize Total number of bytes of target code produced
PureCodeSize Total number of bytes produced from S32 translation
MillicodeSize Number of bytes of supporting millicode produced
VeneerSize Number of bytes of supporting entrypoint veneer code produced
aChkCnt Number of sandbox checks generated for byte, half, word pointers
aOptCnt Number of times selected optimization applied

Additional information

The members aChkCnt and aOptCnt are present only if code generation optimization recording is enabled by setting S32_CONFIG_NCG_T32_RECORD_OPTS=1.

S32_NCG_GetArchitecture()

Description

Get architecture code is generated for.

Prototype

S32_I32 S32_NCG_GetArchitecture(const S32_NCG_API * pApi);

Parameters

Parameter Description
pApi Pointer to code generator API.

Return value

Architecture compiled for.

S32_NCG_GetSupported()

Description

Query code generation features supported.

Prototype

unsigned S32_NCG_GetSupported(const S32_NCG_API * pApi);

Parameters

Parameter Description
pApi Pointer to code generator API.

Return value

Bitwise-or of support features for the API’s target architecture.

S32_NCG_IsSupported()

Description

Query if code generation features supported.

Prototype

int S32_NCG_IsSupported(const S32_NCG_API * pApi,
                              unsigned      Flags);

Parameters

Parameter Description
pApi Pointer to code generator API.
Flags Bitwise-or of flags to query.

Return value

= 0 One or more features are not supported.
≠ 0 All queried features are supported.

S32_NCG_GenerateCode()

Description

Generate native code for application.

Prototype

S32_I32 S32_NCG_GenerateCode(      S32_EXEC_GEO * pGeo,
                             const S32_NCG_API  * pApi,
                                   unsigned       Flags,
                                   void         * pWorkspace,
                                   unsigned       WorkspaceLen);

Parameters

Parameter Description
pGeo Pointer to application geometry.
pApi Pointer to code generator API.
Flags Bitwise-or of flags to use for compilation.
pWorkspace Pointer to code generation workspace.
WorkspaceLen Size of code generation workspace, in bytes.

Return value

< 0 Failure status.
≥ 0 Active size of workspace after generation, in bytes.

Additional information

The returned value indicates the number of bytes of the provided workspace are to be retained after code generation. This portion of the workspace contains entry point information and the generated native code. If the workspace has been allocated dynamically by a client, the client can shrink the size of the workspace but such reallocation must not move the workspace as embedded pointers and native code are not guaranteed to be position independent. As such, the C function realloc() generally cannot be used to shrink the workspace as it does not guarantee that an allocation remains at the same address even if the reallocation is of a smaller size.

Note that the peak workspace allocation requirement during code generation will be larger than that returned by this function when S32_NCG_T32_FLAG_MINIMIZE_IMAGE is set in Flags and emApps configured to support workspace minimization.

See also

S32_NCG_GenerateCodeEx()

S32_NCG_GenerateCodeEx()

Description

Generate native code for application, extended.

Prototype

S32_I32 S32_NCG_GenerateCodeEx(      S32_EXEC_GEO * pGeo,
                               const S32_NCG_API  * pApi,
                                     unsigned       Flags,
                                     void         * pWorkspace,
                                     unsigned       WorkspaceLen,
                                     S32_NCG_INFO * pInfo);

Parameters

Parameter Description
pGeo Pointer to application geometry.
pApi Pointer to code generator API.
Flags Bitwise-or of flags to use for compilation.
pWorkspace Pointer to code generation workspace.
WorkspaceLen Size of code generation workspace, in bytes.
pInfo Pointer to object that receives generated code statistics.

Return value

< 0 Failure status.
≥ 0 Active size of workspace after generation, in bytes.

Additional information

The returned value indicates the number of bytes of the provided workspace are to be retained after code generation. This portion of the workspace contains entry point information and the generated native code. If the workspace has been allocated dynamically by a client, the client can shrink the size of the workspace but such reallocation must not move the workspace as embedded pointers and native code are not guaranteed to be position independent. As such, the C function realloc() generally cannot be used to shrink the workspace as it does not guarantee that an allocation remains at the same address even if the reallocation is of a smaller size.

Note that the peak workspace allocation requirement during code generation will be larger than that returned by this function when S32_NCG_T32_FLAG_MINIMIZE_IMAGE is set in Flags and emApps configured to support workspace minimization.

See also

S32_NCG_GenerateCode()

Arm T32 code generator

T32 code generation flags

Description

Flags controlling T32 code generation.

Definition

#define S32_NCG_T32_FLAG_FUSE_MOV_BRA        (1u<<0)
#define S32_NCG_T32_FLAG_FUSE_MOV_LDR        (1u<<1)
#define S32_NCG_T32_FLAG_FUSE_MOV_STR        (1u<<2)
#define S32_NCG_T32_FLAG_FUSE_ADD_LDR        (1u<<3)
#define S32_NCG_T32_FLAG_FUSE_ADD_STR        (1u<<4)
#define S32_NCG_T32_FLAG_FUSE_MOV_ADD        (1u<<5)
#define S32_NCG_T32_FLAG_FUSE_MOV_SUB        (1u<<6)
#define S32_NCG_T32_FLAG_FUSE_MOV_ADD_LDR    (1u<<7)
#define S32_NCG_T32_FLAG_FUSE_MOV_SUB_LDR    (1u<<8)
#define S32_NCG_T32_FLAG_FUSE_LSL_LSL        (1u<<9)
#define S32_NCG_T32_FLAG_FUSE_LSR_LSR        (1u<<10)
#define S32_NCG_T32_FLAG_FUSE_AND_BXX        (1u<<11)
#define S32_NCG_T32_FLAG_FUSE_CLX_BXX        (1u<<12)
#define S32_NCG_T32_FLAG_REPLACE_OR_0        (1u<<13)
#define S32_NCG_T32_FLAG_SHRINK_JUMPS        (1u<<14)
#define S32_NCG_T32_FLAG_MINIMIZE_IMAGE      (1u<<15)
#define S32_NCG_T32_FLAG_SANDBOX_INLINE      (1u<<16)
#define S32_NCG_T32_FLAG_SANDBOX_OUTLINE     (1u<<17)
#define S32_NCG_T32_FLAG_TELEMETRY           (1u<<18)
#define S32_NCG_T32_FLAG_ASYNC_RAISE         (1u<<19)

Symbols

Definition Description
S32_NCG_T32_FLAG_FUSE_MOV_BRA Fuse MOV{W,L} Rn, #x; BRA/CALL Rn into direct call.
S32_NCG_T32_FLAG_FUSE_MOV_LDR Fuse MOV Rn, #Imm; LDRx Rn, [Rn] into single Arm load.
S32_NCG_T32_FLAG_FUSE_MOV_STR Fuse MOV Rn, #Imm; STRx Rt, [Rn] to avoid a sandbox check.
S32_NCG_T32_FLAG_FUSE_ADD_LDR Fuse ADD Rn, SP, #Imm; LDRx Rn, [Rn] into single Arm load.
S32_NCG_T32_FLAG_FUSE_ADD_STR Fuse ADD Rn, SP, #Imm; STRx Rn, [Rn] to avoid sandbox check.
S32_NCG_T32_FLAG_FUSE_MOV_ADD Fuse MOV Rn, #Imm; ADD Rn, Rm into ADD Rn, Rm, #Imm.
S32_NCG_T32_FLAG_FUSE_MOV_SUB Fuse MOV Rn, Rm; SUB Rn, #Imm into SUB Rn, Rm, #Imm.
S32_NCG_T32_FLAG_FUSE_MOV_ADD_LDR Fuse MOV Rn, #Imm; ADD Rn, SP; LDR Rn, [Rn] into LDR Rn, [SP, #Imm].
S32_NCG_T32_FLAG_FUSE_MOV_SUB_LDR Fuse MOV Rn, SP; SUB Rn, #Imm; LDR Rn, [Rn] into LDR Rn, [SP, #-Imm].
S32_NCG_T32_FLAG_FUSE_LSL_LSL Fuse LSL Rn, #a; LSL Rn, #b into LSL Rn, #a+b.
S32_NCG_T32_FLAG_FUSE_LSR_LSR Fuse LSR Rn, #a; LSR Rn, #b into LSR Rn, #a+b.
S32_NCG_T32_FLAG_FUSE_AND_BXX Fuse AND Rn, Rn; Bxx BEQ/BNE Addr into a CBZ/CBNZ.
S32_NCG_T32_FLAG_FUSE_CLX_BXX Fuse CLT/CLO Rn, Rm; BEQ/BNE Addr into a CMP and branch.
S32_NCG_T32_FLAG_REPLACE_OR_0 Replace OR Rn, #0 with shorter OR Rn, Rn.
S32_NCG_T32_FLAG_SHRINK_JUMPS Use short branches where possible.
S32_NCG_T32_FLAG_MINIMIZE_IMAGE Evict unused entries in the branch translation table after code generation.
S32_NCG_T32_FLAG_SANDBOX_INLINE Apply sandbox checks using inline code.
S32_NCG_T32_FLAG_SANDBOX_OUTLINE Apply sandbox checks using millicode.
S32_NCG_T32_FLAG_TELEMETRY Place code to call telemetry API, if telemetry is configured.
S32_NCG_T32_FLAG_ASYNC_RAISE Test for asynchronously raised exception at branch targets.

S32_NCG_T32_GetFlagName()

Description

Get name of optimization flag.

Prototype

const char *S32_NCG_T32_GetFlagName(unsigned Flag);

Parameters

Parameter Description
Flag Single-bit-set flag to query.

Return value

Pointer to zero-terminated flag name if Flag is valid, else NULL.

S32_NCG_T32_GetFlagDesc()

Description

Get short description of optimization flag.

Prototype

const char *S32_NCG_T32_GetFlagDesc(unsigned Flag);

Parameters

Parameter Description
Flag Single-bit-set flag to query.

Return value

Pointer to zero-terminated flag description if Flag is valid, else NULL.

Resource use and performance

This chapter provides some guidance on the memory use of emApps and the performance that is achieved in practice.

Note that these numbers are correct at the time of writing, and are indicative only. The actual memory footprint and performance will vary on configuration of emApps, the compiler used, and its enabled features and optimizations.

Executor

The executor can be configured in various ways as described in The configuration file.

The following shows the size in bytes for the executor and the performance delivered in Dhrystones per second for the Arm assembly language executor in various configurations for each instruction set. The code was compiled for a Cortex-A9 using the SEGGER Compiler version 20.1.2, optimized for speed.

Flags T16 ISA T32 ISA A32 ISA Perf T16 Perf T32 Perf A32
None 696 720 960 17 370 26 021 26 539
USE_TBB_TBH 624 640 15 905 20 588
TAIL_THREADING 900 916 1 120 19 054 28 926 29 735
RAM_DISPATCH 712 724 980 17 743 25 926 26 281
USE_PREDICTION 876 1 152 N/A 32 669 34 199

Native code generation

Read-only memory required

The native code generator for T32 can be statically configured to support each code optimization feature individually, allowing the code footprint of the code generator to be tuned as required whilst achieving great conversion speeds with excellent execution performance.

The following are the sizes of the T32 code generator compiled for a Cortex-A9 using the SEGGER Compiler version 20.1.2, optimized for size and for speed.

Flags Small code Fast code
With S32_NCG_CONFIG_T32_REG_CNT = 4
None 4 740 10 004
S32_NCG_T32_FLAG_FUSE_MOV_LDR 4 896 10 250
S32_NCG_T32_FLAG_FUSE_MOV_ADD 4 792 10 162
S32_NCG_T32_FLAG_FUSE_MOV_SUB 4 800 10 402
S32_NCG_T32_FLAG_FUSE_CLX_BXX 4 836 10 630
S32_NCG_T32_FLAG_REPLACE_OR_0 4 772 10 044
S32_NCG_T32_FLAG_SHRINK_JUMPS 4 902 10 216
Cumulative (all above) 5 468 11 502

Execution performance

The assembly-language executor running on a 600 MHz Cortex-A9 achieves 32669 Dhrystones per second with the T32 instruction set and the executor tuned for prediction. The following is the relative performance of the same application after code generation for the T32 instruction set.

Flags Code size Dhrystones/s Factor
With S32_NCG_CONFIG_T32_REG_CNT = 4
None 2 088 518 134 x15.9
S32_NCG_T32_FLAG_FUSE_MOV_LDR 2 028 523 560 x16.0
S32_NCG_T32_FLAG_FUSE_MOV_ADD 2 088 518 134 x15.9
S32_NCG_T32_FLAG_FUSE_MOV_SUB 2 068 518 820 x15.9
S32_NCG_T32_FLAG_FUSE_CLX_BXX 2 012 537 634 x16.5
S32_NCG_T32_FLAG_REPLACE_OR_0 2 082 495 095 x15.2
S32_NCG_T32_FLAG_SHRINK_JUMPS 2 002 523 560 x16.0
Cumulative (all above) 1 844 540 540 x16.6

Conversion performance

It is essential that just-in-time code generation is fast. The T32 code generator generates compact, fast code and does so very quickly. The following table shows the duration for and conversion rate of S32 instructions to Arm T32 instructions, running on on a 600 MHz Cortex-A9, for the Dhrystone application comprising 1454 bytes of S32 executable code.

Flags Duration S32 to T32 conversion rate
None 877 µs 1.66 MB/s
S32_NCG_T32_FLAG_FUSE_MOV_LDR 938 µs 1.55 MB/s
S32_NCG_T32_FLAG_FUSE_MOV_ADD 958 µs 1.52 MB/s
S32_NCG_T32_FLAG_FUSE_MOV_SUB 923 µs 1.57 MB/s
S32_NCG_T32_FLAG_FUSE_CLX_BXX 925 µs 1.57 MB/s
S32_NCG_T32_FLAG_REPLACE_OR_0 927 µs 1.57 MB/s
S32_NCG_T32_FLAG_SHRINK_JUMPS 924 µs 1.57 MB/s
Cumulative (all above) 977 µs 1.49 MB/s

S32 architecture reference

This chapter describes the S32 machine and its architecture.

Register file

The S32 comprises a general-purpose register file of 16 registers plus a program counter PC and a transitory zero flag Z.

R0 R1 R2 R3 R12 R13 R14 (WP) R15 (SP) PC XR ML General-purpose registers Special-purpose registers

General-purpose registers

Registers R0 through R14 are general-purpose registers used for calculation and parameter passing. Register R14, or WP, is a general-purpose register in the S32 architecture but has a dedicated purpose in C programs, described below.

Program counter

The program counter PC is not directly addressable. It increments to fetch and execute S32 instructions. Execution is controlled by subroutine call and return instructions (CALL, RET) and by branch instructions (BRA, BEQ, BNE, DBNZ) which update the program counter as required.

Stack pointer

The stack pointer SP is directly addressable and is a synonym for R15. The stack pointer is directly affected by CALL, RET, PUSH, and POP instructions.

It is only possible to modify the stack pointer, for instance to construct or destroy an activation record, using the ADD and SUB instructions: any other operation addressing the stack pointer is defined to be illegal.

Work pointer

The work pointer WP is directly addressable and a synonym for R14. It is conventionally used by the S32 C compiler to extend the range of conditional and unconditional branch instuctions and also for the CALL instruction. Otherwise, it can be used as a general-purpose register in any instruction.

Exception register

The exception register XR is not directly addressable. Its value is zero until an exception is raised, registering the nonzero exception cause into XR, and execution halts.

The exception register can be read from an execution context using the S32_RdXR() function; an exception can be raised from a service function using the S32_Raise() function.

Memory limit register

The memory limit register ML is not directly addressable. Its value is set to point to the first address beyond application-addressable memory. It is used internally within the S32 architecture to ensure that all reads and writes are to valid memory addresses within the S32 address space.

The memory limit register can be read from an execution context using the S32_RdML() function. No facility is provided for a user to write to the memory limit register.

Zero flag

The zero flag Z is used to conditionally branch using the BEQ and BNE instructions. Its value, 0 or 1, can also be placed into a general-purpose register using the SZ instruction.

The zero flag has a defined value only after execution of some instructions. The value is defined following nearly all arithmetic instructions and also after the compare instructions.

Memory layout

The S32 memory space comprises four distinct areas:

XData Stack Code Data Communication areabetween programand application Stack required forexecution

Data area

This contains the static data of the application.

Code area

This contains the executable code of the application.

Stack area

This contains the space reserved to contain activation frames as the program executes.

XData area

This contains an unmanaged communication area that is shared between application and program to communicate bulk data.

Instruction descriptions

This section lists every instruction.

In the Operation section of a description, an ILLEGAL reference indicates that the instruction encoding is illegal and must not occur in a valid S32 program. Illegal instructions are detected at runtime by the executor and at compile-time by the native code generator.

Any instruction coding not covered by the following descriptions is ILLEGAL.

Data movement

MOV MOVW MOVL

Arithmetic and logic

ADD SUB MUL LSL LSR AND OR XOR CLO CLT SZ

Load and store

LDR LDRB LDRH STR STRB STRH PUSH POP

Control flow

BRK BRA BEQ BNE DBNZ CALL RET ACALL ICALL

ACALL

Description

Call service function by index.

Encoding

Index 15 9 0 8 0 7 Cnt 6 4 0 3 0 2 1 1 1 0

Syntax

ACALL Index, #Cnt

Operation

Reg[R0] := CALL(service function identified by well-known index #Index)
Reg[SP] := Reg[SP] - 4 * Cnt
Reg[R1] := UNDEFINED
Reg[R2] := UNDEFINED
Reg[R3] := UNDEFINED
Z := UNDEFINED

Exceptions

Defined by API function invoked

ADD

Register form #1

Description

Add register.

Encoding

Rx 15 12 Rn 11 8 0 7 0 6 0 5 1 4 0 3 0 2 0 1 1 0

Syntax

ADD Rn, Rx

Operation

Reg[Rn] := Reg[Rn] + Reg[Rx]
Z       := Reg[Rn] == 0

Exceptions

None

Register form #2

Description

Add register and constant.

Encoding

Rx 15 12 Rn 11 8 Imm4u 7 4 0 3 1 2 0 1 1 0

Syntax

ADD Rn, Rx, #Imm4u

Operation

Reg[Rn] := Reg[Rn] + Reg[Rx] + ZeroExtend(Imm4u)
Z       := UNDEFINED

Exceptions

None

Immediate form #1

Description

Add constant.

Encoding

Imm4u 15 12 Rn 11 8 0 7 0 6 0 5 0 4 0 3 0 2 0 1 1 0

Syntax

ADD Rn, #Imm4u

Operation

Reg[Rn] := Reg[Rn] + ZeroExtend(Imm4u)
Z       := Reg[Rn] == 0

Exceptions

None

Immediate form #2

Description

Add constant.

Encoding

Rn 15 12 Imm7s 11 5 0 4 1 3 0 2 0 1 1 0

Syntax

ADD Rn, #Imm7s

Operation

Reg[Rn] := Reg[Rn] + SignExtend(Imm7)
Z       := UNDEFINED

Exceptions

None

AND

Immediate form

Description

Bitwise-and constant.

Encoding

Rx 15 12 Rn 11 8 0 7 1 6 0 5 1 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP or Rx=SP is ILLEGAL.

Syntax

AND Rn, Rx

Operation

if Rn == SP or Rx == SP then ILLEGAL
Reg[Rn] := Reg[Rn] & Reg[Rx]
Z       := Reg[Rn] == 0

Exceptions

None

Register form

Description

Bitwise-and register.

Encoding

Imm4u 15 12 Rn 11 8 0 7 1 6 0 5 0 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP is ILLEGAL.

Syntax

AND Rn, #Imm4u

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := Reg[Rn] & ZeroExtend(Imm4u)
Z       := Reg[Rn] == 0

Exceptions

None

BEQ

Description

Branch on “equal” condition.

Encoding

Disp8 15 8 0 7 0 6 0 5 1 4 0 3 0 2 1 1 0 0

Syntax

BEQ Label

Operation

if Z == 1 then PC := PC + 2 * SignExtend(Disp8)
Z := UNDEFINED

Exceptions

None

BNE

Description

Branch on “not equal” condition.

Encoding

Disp8 15 8 0 7 0 6 0 5 0 4 0 3 0 2 1 1 0 0

Syntax

BNE Label

Operation

if Z == 0 then PC := PC + 2 * SignExtend(Disp8)
Z := UNDEFINED

Exceptions

None

BRA

Immediate form

Description

Branch to address.

Encoding

Disp10 15 6 0 5 0 4 0 3 1 2 0 1 0 0

Syntax

BRA Label

Operation

PC := PC + 2 * SignExtend(Disp10)
Z := UNDEFINED

Exceptions

None

Register form

Description

Branch to address.

Encoding

Rn 15 12 0 11 6 0 5 1 4 0 3 1 2 0 1 0 0

Syntax

BRA Rn

Operation

PC := (Reg[Rn] & 1) == 0 then Reg[Rn] else UNDEFINED
Z := UNDEFINED

Exceptions

None

BRK

Description

Raise a BREAK exception.

Encoding

0 15 5 0 4 0 3 0 2 0 1 0 0

Syntax

BRK

Operation

XR := BREAK
STOP

Exceptions

BREAK

CALL

Immediate form

Description

Call address.

Encoding

Disp10 15 6 1 5 0 4 0 3 1 2 0 1 0 0

Syntax

CALL Label

Operation

Reg[SP] := Reg[SP] - 4
Mem[Reg[SP]]::WORD := PC
PC := PC + 2 * SignExtend(Disp10)
Z := UNDEFINED

Exceptions

None

Register form

Call address.

Encoding

Rn 15 12 0 11 6 1 5 1 4 0 3 1 2 0 1 0 0

Syntax

CALL Rn

Operation

Reg[SP] := Reg[SP] - 4
Mem[Reg[SP]]::WORD := PC
PC := (Reg[Rn] & 1) == 0 then Reg[Rn] else UNDEFINED
Z := UNDEFINED

Exceptions

None

CLO

Description

Compare register, unsigned.

Encoding

Rx 15 12 Rn 11 8 0 7 1 6 0 5 1 4 0 3 0 2 0 1 0 0

Syntax

CLO Rn, Rx

Operation

Z := if Reg[Rn] < Reg[Rx] then 0 else 1

Exceptions

None

CLT

Description

Compare register, signed.

Encoding

Rx 15 12 Rn 11 8 0 7 0 6 0 5 1 4 0 3 0 2 0 1 0 0

Syntax

CLT Rn, Rx

Operation

Z := if Reg[Rn] <(S) Reg[Rx] then 0 else 1

Exceptions

None

DBNZ

Description

Decrement and branch not equal.

Encoding

Rn 15 12 Disp7u 11 5 0 4 1 3 0 2 1 1 0 0

The encoding with Rn=SP is ILLEGAL.

Syntax

DBNZ Rn, Label

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := Reg[Rn] - 1
if Reg[Rn] != 0 then PC := PC - 2 * ZeroExtend(Disp7u)
Z := UNDEFINED

Exceptions

None

ICALL

Description

Call service function by name.

Encoding

0 15 8 1 7 Cnt 6 4 0 3 0 2 1 1 1 0 Index

Syntax

ICALL Index, #Cnt

Operation

Reg[R0] := CALL(service function identified by import index #Index)
Reg[SP] := Reg[SP] - 4 * Cnt
Reg[R1] := UNDEFINED
Reg[R2] := UNDEFINED
Reg[R3] := UNDEFINED
Z := UNDEFINED

Exceptions

Defined by API function invoked

LDR

Register form

Description

Load word from memory.

Encoding

Rx 15 12 Rn 11 8 1 7 0 6 1 5 0 4 1 3 0 2 0 1 0 0

Syntax

LDR Rn, [Rx]

Operation

Reg[Rn] := Mem[Reg[Rx]]::WORD
Z := UNDEFINED

Exceptions

ACCVIO on read outside of sandbox

Stack form

Description

Store word to stack.

Encoding

Off5s 15 11 0 10 Rn 9 6 0 5 0 4 1 3 1 2 0 1 0 0

Syntax

LDR Rn, [SP, #Off5s]

Operation

Reg[Rn] := Mem[Reg[SP] + 4*SignExtend(Off5s)]::WORD
Z := UNDEFINED

Exceptions

ACCVIO on read outside of sandbox

LDRB

Description

Load byte from memory.

Encoding

Rx 15 12 Rn 11 8 1 7 0 6 0 5 0 4 1 3 0 2 0 1 0 0

Syntax

LDRB Rn, [Rx]

Operation

Reg[Rn] := ZeroExtend(Mem[Reg[Rx]]::BYTE)
Z := UNDEFINED

Exceptions

ACCVIO on read outside of sandbox

LDRH

Description

Read halfword from memory.

Encoding

Rx 15 12 Rn 11 8 1 7 0 6 0 5 1 4 1 3 0 2 0 1 0 0

Syntax

LDRH Rn, [Rx]

Operation

Reg[Rn] := ZeroExtend(Mem[Reg[Rx]]::HALF)
Z := UNDEFINED

Exceptions

ACCVIO on read outside of sandbox

LSL

Immediate form

Description

Shift left immediate.

Encoding

Imm4u 15 12 Rn 11 8 1 7 0 6 1 5 0 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP is ILLEGAL.

Syntax

LSL Rn, #Imm4u

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := Reg[Rn] << Imm4u
Z       := Reg[Rn] == 0

Exceptions

None

Register form

Description

Shift leftAssign register.

Encoding

Rx 15 12 Rn 11 8 1 7 0 6 1 5 1 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP or Rx=SP is ILLEGAL.

Syntax

LSL Rn, Rx

Operation

if Rn == SP or Rx == SP then ILLEGAL
Reg[Rn] := if Reg[Rx] <= 31 then Reg[Rn] << Reg[Rx] else UNDEFINED
Z       := if Reg[Rx] <= 31 then Reg[Rn] == 0 else UNDEFINED

Exceptions

None

LSR

Immediate form

Description

Shift right constant.

Encoding

Imm4u 15 12 Rn 11 8 1 7 1 6 0 5 0 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP is ILLEGAL.

Syntax

LSR Rn, #Imm4u

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := Reg[Rn] >> Imm4u
Z       := Reg[Rn] == 0

Exceptions

None

Register form

Description

Shift right register.

Encoding

Rx 15 12 Rn 11 8 1 7 1 6 0 5 1 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP or Rx=SP is ILLEGAL.

Syntax

LSR Rn, Rx

Operation

if Rn == SP or Rx == SP then ILLEGAL
Reg[Rn] := if Reg[Rx] <= 31 then Reg[Rn] >> Reg[Rx] else UNDEFINED
Z       := if Reg[Rx] <= 31 then Reg[Rn] == 0 else UNDEFINED

Exceptions

None

MOV

Description

Move 7-bit constant.

Encoding

Rn 15 12 Imm7u 11 5 0 4 0 3 1 2 1 1 0 0

The encoding with Rn=SP is ILLEGAL.

Syntax

MOV Rn, #Imm7u

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := ZeroExtend(Imm7u)

Exceptions

None

MOVL

Description

Move 32-bit constant.

Encoding

Rn 15 12 0 11 5 1 4 0 3 1 2 1 1 0 0 Imm32[15:0] Imm32[31:16]

The encoding with Rn=SP is ILLEGAL.

Syntax

MOVL Rn, #Imm32

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := Imm32

Exceptions

None

MOVW

Description

Move 16-bit constant.

Encoding

Rn 15 12 0 11 5 0 4 1 3 1 2 1 1 1 0 Imm16u

The encoding with Rn=SP is ILLEGAL.

Syntax

MOVW Rn, #Imm16u

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := ZeroExtend(Imm16u)

Exceptions

None

MUL

Immediate form

Description

Multiply by constant.

Encoding

Imm4u 15 12 Rn 11 8 1 7 1 6 1 5 0 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP is ILLEGAL.

Syntax

MUL Rn, #Imm4u

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := Reg[Rn] * ZeroExtend(Imm4u)
Z       := Reg[Rn] == 0

Exceptions

None

Register form

Description

Multiple by register.

Encoding

Rx 15 12 Rn 11 8 1 7 1 6 1 5 1 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP or Rx=SP is ILLEGAL.

Syntax

MUL Rn, Rx

Operation

if Rn == SP or Rx == SP then ILLEGAL
Reg[Rn] := Reg[Rn] * Reg[Rx]
Z       := Reg[Rx] == 0

Exceptions

None

OR

Immediate form

Description

Bitwise-or constant.

Encoding

Imm4u 15 12 Rn 11 8 0 7 1 6 1 5 0 4 0 3 0 2 0 1 1 0

The encoding with or Rn=SP is ILLEGAL.

Syntax

OR Rn, #Imm4u

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := Reg[Rn] | ZeroExtend(Imm4u)
Z       := Reg[Rn] == 0

Exceptions

None

Register form

Description

Bitwise-or register.

Encoding

Rx 15 12 Rn 11 8 0 7 1 6 1 5 1 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP or Rx=SP is ILLEGAL.

Syntax

OR Rn, Rx

Operation

if Rn == SP or Rx == SP then ILLEGAL
Reg[Rn] := Reg[Rn] | Reg[Rx]
Z       := Reg[Rn] == 0

Exceptions

None

POP

Description

Pop registers from stack.

Encoding

Cnt 15 12 Rn 11 8 0 7 0 6 0 5 1 4 0 3 1 2 1 1 1 0

Syntax

POP Rn, #Cnt

Operation

if Cnt == 0 then ILLEGAL
if Rn + Cnt > SP then ILLEGAL
for N := 0 to Cnt-1
  Reg[Rn + N] := Mem[Reg[SP] + 4*N]::WORD
Reg[SP] := Reg[SP] + 4*Cnt
Z := UNDEFINED

Exceptions

ACCVIO on read outside of sandbox

PUSH

Description

Push registers to stack.

Encoding

Cnt 15 12 Rn 11 8 0 7 0 6 0 5 0 4 0 3 1 2 1 1 1 0

Syntax

PUSH Rn, #Cnt

Operation

if Cnt == 0 then ILLEGAL
if Rn + Cnt > SP then ILLEGAL
Reg[SP] := Reg[SP] - 4*Cnt
for N := 0 to Cnt-1
  Mem[Reg[SP] + 4*N]::WORD := Reg[Rn + N]
Z := UNDEFINED

Exceptions

ACCVIO on write outside of sandbox

RET

Description

Return from subroutine.

Encoding

Cnt 15 5 0 4 1 3 0 2 1 1 1 0

Syntax

RET #Cnt

Operation

PC := Mem[Reg[SP]]::WORD
Reg[SP] := Reg[SP] + 4 * (Cnt+1)
Z := UNDEFINED

Exceptions

None

STR

Register form

Description

Store word to memory.

Encoding

Rx 15 12 Rn 11 8 0 7 0 6 1 5 0 4 1 3 0 2 0 1 0 0

Syntax

STR Rn, [Rx]

Operation

Mem[Reg[Rx]]::WORD := Reg[Rn]
Z := UNDEFINED

Exceptions

ACCVIO on write outside of sandbox

Stack form

Description

Store word to stack.

Encoding

Off5s 15 11 1 10 Rn 9 6 0 5 0 4 1 3 1 2 0 1 0 0

Syntax

STR Rn, [SP, #Off5s]

Operation

Mem[Reg[SP] + 4*SignExtend(Off5s)]::WORD := Reg[Rn]
Z := UNDEFINED

Exceptions

ACCVIO on write outside of sandbox

STRB

Description

Store byte to memory.

Encoding

Rx 15 12 Rn 11 8 0 7 0 6 0 5 0 4 1 3 0 2 0 1 0 0

Syntax

STRB Rn, [Rx]

Operation

Mem[Reg[Rx]]::BYTE := Reg[Rn] & 0xFF
Z := UNDEFINED

Exceptions

ACCVIO on write outside of sandbox

STRH

Description

Store halfword to memory.

Encoding

Rx 15 12 Rn 11 8 0 7 0 6 0 5 1 4 1 3 0 2 0 1 0 0

Syntax

STRH Rn, [Rx]

Operation

Mem[Reg[Rx]]::HALF := Reg[Rn] & 0xFFFF
Z := UNDEFINED

Exceptions

ACCVIO on write outside of sandbox

SUB

Immediate form

Description

Subtract constant.

Encoding

Imm4u 15 12 Rn 11 8 0 7 0 6 1 5 0 4 0 3 0 2 0 1 1 0

Syntax

SUB Rn, #Imm4u

Operation

Reg[Rn] := Reg[Rn] - ZeroExtend(Imm4u)
Z       := Reg[Rn] == 0

Exceptions

None

Register form

Description

Subtract register.

Encoding

Rx 15 12 Rn 11 8 0 7 0 6 1 5 1 4 0 3 0 2 0 1 1 0

The encoding with Rx=SP is ILLEGAL.

Syntax

SUB Rn, Rx

Operation

if Rx == SP then ILLEGAL
Reg[Rn] := Reg[Rn] - Reg[Rx]
Z       := Reg[Rn] == 0

Exceptions

None

SZ

Description

Store zero flag.

Encoding

Rn 15 12 0 11 5 0 4 1 3 1 2 0 1 1 0

The encoding with Rn=SP is ILLEGAL.

Syntax

SZ Rn

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := Z
Z := UNDEFINED

Exceptions

None

XOR

Immediate form

Description

Exclusive-or constant.

Encoding

Imm4u 15 12 Rn 11 8 1 7 0 6 0 5 0 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP is ILLEGAL.

Syntax

XOR Rn, #Imm4u

Operation

if Rn == SP then ILLEGAL
Reg[Rn] := Reg[Rn] ^ ZeroExtend(Imm4u)
Z       := Reg[Rn] == 0

Exceptions

None

Register form

Description

Eclusive-or register.

Encoding

Rx 15 12 Rn 11 8 1 7 0 6 0 5 1 4 0 3 0 2 0 1 1 0

The encoding with Rn=SP or Rx=SP is ILLEGAL.

Syntax

XOR Rn, Rx

Operation

if Rn == SP or Rx == SP then ILLEGAL
Reg[Rn] := Reg[Rn] ^ Reg[Rx]
Z       := Reg[Rn] == 0

Exceptions

None

Encoding quick reference

The following table is a quick refererence to the encoding of all instructions, grouped by function.

Data Movement Rn Imm7u 0 0 1 1 0 MOV Rn, #Imm7u Rn 0 0 1 1 1 1 MOVW Rn, #Imm16u Rn 0 1 0 1 1 0 MOVL Rn, #Imm32 Rx Rn 0 0 0 0 0 1 0 1 MOV Rn, Rx Arithmetic / Logic Rx Rn Imm4u 0 1 0 1 ADD Rn, Rx, #Imm4u Rn Imm7s 0 1 0 0 1 ADD Rn, #Imm7s Imm4u Rn 0 0 0 0 0 0 0 1 ADD Rn, #Imm4u Imm4u Rn 0 0 1 0 0 0 0 1 SUB Rn, #Imm4u Imm4u Rn 0 1 0 0 0 0 0 1 AND Rn, #Imm4u Imm4u Rn 0 1 1 0 0 0 0 1 OR Rn, #Imm4u Imm4u Rn 1 0 0 0 0 0 0 1 XOR Rn, #Imm4u Imm4u Rn 1 0 1 0 0 0 0 1 LSL Rn, #Imm4u Imm4u Rn 1 1 0 0 0 0 0 1 LSR Rn, #Imm4u Imm4u Rn 1 1 1 0 0 0 0 1 MUL Rn, #Imm4u Rx Rn 0 0 0 1 0 0 0 1 ADD Rn, Rx Rx Rn 0 0 1 1 0 0 0 1 SUB Rn, Rx Rx Rn 0 1 0 1 0 0 0 1 AND Rn, Rx Rx Rn 0 1 1 1 0 0 0 1 OR Rn, Rx Rx Rn 1 0 0 1 0 0 0 1 XOR Rn, Rx Rx Rn 1 0 1 1 0 0 0 1 LSL Rn, Rx Rx Rn 1 1 0 1 0 0 0 1 LSR Rn, Rx Rx Rn 1 1 1 1 0 0 0 1 MUL Rn, Rx Rn 0 0 1 1 0 1 SZ Rn Rx Rn 0 0 0 1 0 0 0 0 CLT Rn, Rx Rx Rn 0 1 0 1 0 0 0 0 CLO Rn, Rx Load / Store Cnt Rn 0 0 0 0 0 1 1 1 PUSH Rn, #Cnt Cnt Rn 0 0 0 1 0 1 1 1 POP Rn, #Cnt Rx Rn 0 0 0 0 1 0 0 0 STRB Rn, [Rx] Rx Rn 0 0 0 1 1 0 0 0 STRH Rn, [Rx] Rx Rn 0 0 1 0 1 0 0 0 STR Rn, [Rx] Rx Rn 1 0 0 0 1 0 0 0 LDRB Rn, [Rx] Rx Rn 1 0 0 1 1 0 0 0 LDR Rn, [Rx] Rx Rn 1 0 1 0 1 0 0 0 LDRH Rn, [Rx] Off5s 0 Rn 0 0 1 1 0 0 LDR Rn, [SP, #Off5s] Off5s 1 Rn 0 0 1 1 0 0 STR Rn, [SP, #Off5s] Control Flow 0 0 0 0 0 0 BRK Disp8 0 0 0 0 0 0 1 0 BNE Disp8 Disp8 0 0 0 1 0 0 1 0 BEQ Disp8 Index 0 0 Cnt 0 0 1 1 ACALL Index, #Cnt 0 1 Cnt 0 0 1 1 ICALL Index, #Cnt Disp10 0 0 0 1 0 0 BRA Disp10 Disp10 1 0 0 1 0 0 CALL Disp10 Rn 0 0 1 0 1 0 0 BRA Rn Rn 0 1 1 0 1 0 0 CALL Rn Rn Disp7u 0 1 0 1 0 DBNZ Rn, Disp7u Cnt 0 1 0 1 1 RET #Cnt

SEGGER formatter reference

Introduction

The SEGGER formatter can be used to implement all C library “formatted output” functions. It is also able to provide useful functionality that goes beyond that of the C standard which is particularly useful in embedded systems.

The way in which the formatter works is entirely parameterized by a context held in a SEGGER_FORMAT_CONTEXT object. The task is to initialize the context to match the expected semantics of the function being emulated and to provide the necessary mechanisms for extracting arguments as formatting progresses.

The following sections will describe how to achieve this.

Format control strings

The formatter implements a subset of the C library format specification. In particular:

Format Description
Format conversions
%c Character.
%s String.
%d, %i Signed decimal.
%o Unsigned octal.
%u Unsigned decimal.
%x, %X Unsigned hexadecimal.
Length modifiers
l long size modifier.
ll long long size modifier.
h short size modifier.
hh char size modifier.
Flags
0 Zero-pad value.
space Space-separate values.
- Left-adjust value.
+ Force sign.
# Use alternate form.

Field width and precision are supported both as literals contained in the format string and as runtime inputs when specified by * in the format string.

The formatter does not implement the following format conversions:

Format Description
%a, %A Format floating-point value in hexadecimal form.
%e, %E Format floating-point value in exponential form.
%f, %F Format floating-point value in fixed form.
%g, %G Format floating-point value in general form.

Using the formatter

Formatting contexts

There are two contexts used by the formatter:

The structure SEGGER_FORMAT_CONTEXT is defined by the formatter and its is described below. The structure SEGGER_FORMAT_USER_CONTEXT is defined by the user and several examples are shown in order to implement the functions in the C library.

Implementing printf()

This section describes how to use the SEGGER formatter to implement a function that is equivalent to printf() from the C standard library,

The top-level code

The example here implements HOST_printf() using the SEGGER formatter. Here is the top-level code to set up and call the SEGGER formatter:

int HOST_printf(const char *sFmt, ...) {
  SEGGER_FORMAT_USER_CONTEXT UserCtx;
  SEGGER_FORMAT_CONTEXT      FmtCtx;
  int                        Res;
  //
  SEGGER_FORMAT_Init(&FmtCtx);   
  FmtCtx.MaxLen   = ~0u;   
  FmtCtx.pUserCtx = &UserCtx;   
  FmtCtx.pfGetVal = _HOST_GetVal;   
  FmtCtx.pfGetStr = _HOST_GetStr;   
  FmtCtx.pfFlush  = _WrStdOut;   
  //
  va_start(UserCtx.ap, sFmt);   
  Res = SEGGER_FORMAT_Exec(&FmtCtx, sFmt);   
  va_end(UserCtx.ap);   
  //
  return Res;

Some of the mechanisms behind the formatter will be ignored for the moment; they will, however, be described later.

  Initialize the formatting context

The formatting context is initialized by calling SEGGER_FORMAT_Init(). All members within the context are set to default values which are zero for all integer-style members and NULL for pointer-style members.

  Set the maximum number of characters output

The printf() function prints all its output and is not bounded; the MaxLen member is set to the largest unsigned value so that output is not truncated during formatting. MaxLen will be important when implementing functions such as snprintf() where output must be truncated.

  Establish the user context

The user context, together with some functions described below, is used to extract the incoming arguments that have been passed to HOST_printf(). This assignment links the formatting context to a specific user context provided for this purpose.

  Provide a method to access incoming integer-style parameters

The formatting context uses the function pointed to by pfGetVal to get the next argument to format. The function pointed to by pfGetVal is passed the user context along with some additional information in order to accomplish this. Not to complicate matters, the specific implementation of _HOST_GetVal() used here will be considered a black box for now.

  Provide a method to access incoming string-style parameters

Much like the integer-based arguments above, it will be necesary to access string parameters. When a string is necessary, the function pointed to by pfGetStr to get this. Again, the implementation of _HOST_GetStr() will be considered a black box.

  Tell the formatter how to output

The formatter does not output formatted strings directly. Instead, it uses the function pointed to by pfFlush to output characters that must be printed. The implementation for this printf() is to use fwrite() to write the presented data to the standard output stream:

static int _HOST_WrStdOut(      SEGGER_FORMAT_CONTEXT * pCtx,
                          const char                  * pData,
                                unsigned                DataLen) {
  return fwrite(pData, 1, DataLen, stdout);
}

  Initialize the user context

The user context is initialized by calling va_start() to commence iteration over the incoming parameters. The definition of the user context for this is:

struct SEGGER_FORMAT_USER_CONTEXT_s {
  va_list ap;
};

  Call the formatter

The formatter is called and formatting takes place. It is provided the formatting context and the format control string. The vlaue returned is the number of characters that were output, or a negative value if there was any output error.

  Wrap up

For compliance with the ISO standard, a call to va_start() must have a matching call to to va_end(). Once done, the number of characters or error indication is returned to the caller.

Retrieving string arguments

The code for _HOST_GetStr() used above is very simple in this case:

static const char *_HOST_GetStr(SEGGER_FORMAT_USER_CONTEXT *pCtx, unsigned MaxLen) {
  (void)MaxLen;
  //
  return va_arg(pCtx->ap, const char *);
}

This simply extracts the string from the user context using va_arg(). The parameter MaxLen is ignored here, it simply encodes the precision argument provided in the format string. This parameter is important in some cases, especially when implementing a sandboxed environment.

Retrieving integer-style arguments

The code for _HOST_GetVal() used above is more complex than _HOST_GetStr() and requires explanation.

The prototype for the function to retrieve an integer is:

void SEGGER_FORMAT_GET_VAL_FUNC(SEGGER_FORMAT_USER_CONTEXT * pCtx,
                                SEGGER_FORMAT_VALUE        * pValue,
                                unsigned                     Flags);

The user context is provided in pCtx; the value retrieved must be stored into the object pointed to by pValue which is never NULL; the value is extracted according to the formatting flags in Flags.

The combination of these parameters is as follows.

Flags is a set of flags that encode the expected form of the incoming argument. Each flag is bitwise-or’d into the set. The combination of flags are described in the following table:

Flags Argument is…
Signedness
SEGGER_FORMAT_FLAG_SIGNED Signed integer else an unsigned integer. This is combined with the length modifier.
Length
SEGGER_FORMAT_FLAG_CHAR char size (specified by hh modifier).
SEGGER_FORMAT_FLAG_SHORT short size, (specified by h modifier).
SEGGER_FORMAT_FLAG_LONG long size, (specified by l modifier).
SEGGER_FORMAT_FLAG_LONG_LONG short size, (specified by ll modifier).
SEGGER_FORMAT_FLAG_PTR void * size (specified by %p conversion).
None of the above set int size (no length modifier).

Only one of the length flags will be set and enable correct interpretation of the incoming argument. The following implementation is highly generic and works on both 32-bit and 64-bit operating systems and with compilers that implement both int and long as 32 bits, compilers that implement int as 32 bits and long as 64 bits, and even compilers that implements both int and long as 64 bits.

void HOST_GetVal(SEGGER_FORMAT_USER_CONTEXT * pCtx,
                 SEGGER_FORMAT_VALUE        * pValue,
                 unsigned                     Flags) {
  if (Flags & SEGGER_FORMAT_FLAG_PTR) {
    pValue->u = (uintptr_t)va_arg(pCtx->ap, void *);
  } else if (Flags & SEGGER_FORMAT_FLAG_SIGNED) {
    if (Flags & SEGGER_FORMAT_FLAG_CHAR) {
      pValue->i = (signed char)va_arg(pCtx->ap, int);
    } else if (Flags & SEGGER_FORMAT_FLAG_SHORT) {
      pValue->i = (short)va_arg(pCtx->ap, int);
    } else if (Flags & SEGGER_FORMATf_FLAG_LONG) {
      pValue->i = va_arg(pCtx->ap, long);
    } else if (Flags & SEGGER_FORMAT_FLAG_LONGLONG) {
      pValue->i = va_arg(pCtx->ap, long long);
    } else {
      pValue->i = va_arg(pCtx->ap, int);
    }
  } else {
    if (Flags & SEGGER_FORMAT_FLAG_CHAR) {
      pValue->u = (unsigned char)va_arg(pCtx->ap, unsigned);
    } else if (Flags & SEGGER_FORMAT_FLAG_SHORT) {
      pValue->u = (unsigned short)va_arg(pCtx->ap, unsigned);
    } else if (Flags & SEGGER_FORMAT_FLAG_LONG) {
      pValue->u = va_arg(pCtx->ap, unsigned long);
    } else if (Flags & SEGGER_FORMAT_FLAG_LONGLONG) {
      pValue->u = va_arg(pCtx->ap, unsigned long long);
    } else {
      pValue->u = va_arg(pCtx->ap, unsigned);
    }
  }
}
Testing the function

Rudimentary testing of HOST_printf() reveals everything is in order:

int main(void) {
  HOST_printf("The square of |%d| is |%+4ld|, and the cube is |%-4lld|\n", 3, 3L*3, 3LL*3*3);
  return 0;
}

Running this:

The square of |3| is |  +9|, and the cube is |27  |

Preprocessor symbols

Formatting flags

Description

Flags set by format parsing.

Definition

#define SEGGER_FORMAT_FLAG_MINUS             (1 <<  0)
#define SEGGER_FORMAT_FLAG_PLUS              (1 <<  1)
#define SEGGER_FORMAT_FLAG_SPACE             (1 <<  2)
#define SEGGER_FORMAT_FLAG_HASH              (1 <<  3)
#define SEGGER_FORMAT_FLAG_ZERO              (1 <<  4)
#define SEGGER_FORMAT_FLAG_HAVE_PRECISION    (1 <<  5)
#define SEGGER_FORMAT_FLAG_CAPS              (1 <<  6)
#define SEGGER_FORMAT_FLAG_SIGNED            (1 <<  7)
#define SEGGER_FORMAT_FLAG_CHAR              (1 <<  8)
#define SEGGER_FORMAT_FLAG_SHORT             (1 <<  9)
#define SEGGER_FORMAT_FLAG_LONG              (1 << 10)
#define SEGGER_FORMAT_FLAG_LONGLONG          (1 << 11)
#define SEGGER_FORMAT_FLAG_PTR               (1 << 12)
#define SEGGER_FORMAT_FLAG_NEGATIVE_INPUT    (1 << 13)

Symbols

Definition Description
SEGGER_FORMAT_FLAG_MINUS ’-’ flag specified in format string (literally or by variable).
SEGGER_FORMAT_FLAG_PLUS ’+’ flag specified in format string.
SEGGER_FORMAT_FLAG_SPACE ’ ’ flag specified in format string.
SEGGER_FORMAT_FLAG_HASH ’#’ flag specified in format string.
SEGGER_FORMAT_FLAG_ZERO ’0’ flag specified in format string.
SEGGER_FORMAT_FLAG_HAVE_PRECISION Precision is specified in format string (literally or by variable).
SEGGER_FORMAT_FLAG_CAPS ’%X’ format conversion, uppercase output.
SEGGER_FORMAT_FLAG_SIGNED ’%i’ or ’%d’ format conversion, signed argument.
SEGGER_FORMAT_FLAG_CHAR ’hh’ length modifier specified.
SEGGER_FORMAT_FLAG_SHORT ’h’ length modifier specified.
SEGGER_FORMAT_FLAG_LONG ’l’ length modifier specified.
SEGGER_FORMAT_FLAG_LONGLONG ’ll’ length modifier specified.
SEGGER_FORMAT_FLAG_PTR ’%p’ format conversion.
SEGGER_FORMAT_FLAG_NEGATIVE_INPUT Argument is considered negative.

Data types

Data type Description
SEGGER_FORMAT_VALUE Union containing value to format.
SEGGER_FORMAT_GET_STR_FUNC Parameter acquisition, string object.
SEGGER_FORMAT_GET_VAL_FUNC Parameter acquisition, integer-type object.
SEGGER_FORMAT_FLUSH_FUNC Write formatted output.
SEGGER_FORMAT_CONTEXT Formatting context.
SEGGER_FORMAT_USER_CONTEXT Parameter acquisition context.

SEGGER_FORMAT_VALUE

Description

Union containing value to format.

Type definition

typedef union {
  long long           i;
  unsigned long long  u;
}SEGGER_FORMAT_VALUE;

Structure members

Member Description
i Signed value.
u Unsigned value.

SEGGER_FORMAT_GET_STR_FUNC

Description

Parameter acquisition, string object.

Type definition

typedef const char * (SEGGER_FORMAT_GET_STR_FUNC)
                                             (SEGGER_FORMAT_USER_CONTEXT * pCtx,
                                              unsigned                     MaxLen);

Parameters

Parameter Description
pCtx Pointer to user context.
MaxLen Maximum number of characters to examine for null terminator.

Return value

Pointer to string.

SEGGER_FORMAT_GET_VAL_FUNC

Description

Parameter acquisition, integer-type object.

Type definition

typedef void (SEGGER_FORMAT_GET_VAL_FUNC)(SEGGER_FORMAT_USER_CONTEXT * pCtx,
                                          SEGGER_FORMAT_VALUE        * pValue,
                                          unsigned                     Flags);

Parameters

Parameter Description
pCtx Pointer to user context.
pValue Pointer to object that receives the next argument.
pFlags Pointer to flags that encode the argument length modifier.

Additional information

This function is called to extract the value of the next argument to format.

SEGGER_FORMAT_FLUSH_FUNC

Description

Write formatted output.

Type definition

typedef int (SEGGER_FORMAT_FLUSH_FUNC)(      SEGGER_FORMAT_USER_CONTEXT * pCtx,
                                       const char                       * pData,
                                             unsigned                     DataLen);

Parameters

Parameter Description
pCtx Pointer to user context.
pData Pointer to object to write.
DataLen Number of characters to write.

Return value

≥ 0 Success.
< 0 Error.

SEGGER_FORMAT_CONTEXT

Description

Formatting context.

Type definition

typedef struct SEGGER_FORMAT_CONTEXT_s {
  SEGGER_FORMAT_USER_CONTEXT * pUserCtx;
  char                       * pData;
  unsigned                     DataLen;
  unsigned                     Cnt;
  unsigned                     MaxLen;
  unsigned                     TrueCnt;
  SEGGER_FORMAT_GET_STR_FUNC * pfGetStr;
  SEGGER_FORMAT_GET_VAL_FUNC * pfGetVal;
  SEGGER_FORMAT_FLUSH_FUNC   * pfFlush;
}SEGGER_FORMAT_CONTEXT;

Structure members

Member Description
pUserCtx Pointer to the user-provided context used to iterate over incoming arguments and hold any other formatting data.
pData Pointer to a user-provided object that collects formatted output as formatting progresses, the collection buffer. It may also be NULL.
DataLen Capacity of the collection buffer in characters, pointed to by pData.
Cnt Number of characters currently written to the collection buffer. Cnt is always less than or equal to DataLen.
MaxLen Maximum number of characters, in total, to pass pass to the flush method. Characters beyond the maximum length are dropped.
TrueCnt Number of characters that a fully formatted operation would output.
pfGetStr Method to deque a string parameter.
pfGetVal Method to deque an integer or pointer parameter.
pfFlush Method to flush converted data.

SEGGER_FORMAT_USER_CONTEXT

Description

Parameter acquisition context.

Type definition

typedef struct SEGGER_FORMAT_USER_CONTEXT_s {
}SEGGER_FORMAT_USER_CONTEXT;

Additional information

This opaque type contains the context required to extract arguments passed to the formatting function as the format string is processed. Its structure is entirely defined by the user.

Functions

Function Description
SEGGER_FORMAT_Init() Initialize formatter context.
SEGGER_FORMAT_Exec() Run formatter.

SEGGER_FORMAT_Init()

Description

Initialize formatter context.

Prototype

void SEGGER_FORMAT_Init(SEGGER_FORMAT_CONTEXT * pCtx);

Parameters

Parameter Description
pCtx Pointer to formatting context.

Additional information

This function initializes the formatting context pointed to by pCtx. All members are set to zero or NULL as appropriate.

SEGGER_FORMAT_Exec()

Description

Run formatter.

Prototype

int SEGGER_FORMAT_Exec(      SEGGER_FORMAT_CONTEXT * pCtx,
                       const char                  * sFormat);

Parameters

Parameter Description
pCtx Pointer to formatting context.
sFormat Format control string.

Return value

Number of characters (without termination) that would have been stored if the buffer had been large enough.

Additional information

Performs formatting using the formatting context pointed to by pCtx under control of the formatting string sFormat.