Host-based formatting

From SEGGER Wiki
Jump to: navigation, search

Host-based formatting is a technology that reduces the on-target code and data size associated with typical semihosting.

Classic semihosting

Many embedded system development tools offer support for Semihosting where a host computer system provides I/O and other services to an embedded target. Semihosting is typically used during product development and is not included as part of the embedded system's code when the product is released.

Typical semihosting provides very simple I/O functions such as reading and writing characters to the terminal and to files. Such an implementation requires target code on the embedded system that implements the C-based format specifications used in calls to printf and scanf. This code is typically bulky even after eliminating floating-point I/O: 2k to 4k of code can be brought into the application just to support printf which will not be present in the production code.

Host-based formatting

For MCUs with very small amounts of flash and RAM, debug messages delivered through semihosting can be an unacceptable burden, consuming most of the flash and RAM space of the target thereby leaving very little space for the application. For instance, MSP430 processors can have as little as 256 bytes of RAM and 1 KiB of flash. Usually a PCB would be populated with a larger device for product development to enable larger debug builds to be programmed into the flash. However, some device families do not offer larger memory versions that could be used for development and, therefore, reducing the footprint of debug code is essential for the application to fit.

Advantages

Host-based formatting shifts the burden of formatting from the target system, where resources are limited, to the host system, where resources are plentiful. The host system supports all formatting specifications (such as width, precision, text alignment, floating point, and so on) simply because it has ample resources to do so. In this scenario the target footprint for printf, for instance, is no more than a few instructions to issue a semihosting call and have the debug agent perform the semihosting operation.

Implementation details

The following is the implementation of printf using the SEGGER Runtime Library using host-based formatting for semihosting:

int printf(const char *fmt, ...) {
  return __do_debug_operation(DEBOP_PRINTF, &fmt);
}

The debugger or host agent identifies the semihosting request from the target (see the Semihosting page for details) and proceeds to service the request. It will first identify the parameters of the semihosting call: the debug operation and the incoming C arguments. With access to all of memory through the debug probe it can find the address of the format string, read the format string from memory under debug control, and format the output "virtually" on the host, taking arguments from the target's memory or registers, as needed, under debug control.

Worked example

With host-based formatting, the call...

printf("There are %u bottles of %s on the wall", 99, "beer");

...would be processed, in detail, as follows:

  • Target calls printf with format string address in a register and additional arguments typically passed on processor stack.
  • Target execution enters printf and immediately requests a semihosting call (e.g. using breakpoint).
  • Host recognizes semihosting requests and proceeds to service it with the target halted.
  • Host decodes the semihosting operation e.g. register R0 and identifies it as a printf request.
  • Host reads e.g. register R1 to find the address of the format string.
  • Host reads the format string from target memory into host memory, up to and including the terminating null character.
  • Host starts formatting the string, sending There are to the console.
  • Host recognizes %u format specifier and reads a word (corresponding to the argument) from the processor stack under debug control, in this case 99.
  • Host formats the argument, 99, and writes 99 to the console.
  • Host continues and copies  bottles of  to the console.
  • Host recognizes %s format specifier and reads an pointer value from the processor stack under debug control.
  • Host reads zero-terminated string using that pointer as the base address and copies beer to the console.
  • Host continues and copies  on the wall to the console.
  • Host finds end of control string and writes an "success" result to e.g. register R0.
  • Host restarts program execution on the target.
  • Target continues execution.

The semihosting call is now complete.