Semihosting: a life-saver during SoC and board bring-up

In this blog you will find information about semihosting, an implementation of the C library that uses a JTAG debugger to interface the world. Semihosting is very useful for board bring-up, as it works on any ARM processor and it only requires a JTAG connection: you do not need any working peripherals or drivers in order to use it.

Semihosting is a feature of ARM software development tools that has been available for many years, proving its usefulness, but unfortunately is often poorly understood. I have used semihosting in many occasions, and it has been extremely useful, so I will share my experience with you.

A bit of background...
When you write a simple "hello world" application on your PC you expect a character string to be printed on a window in your debugger or on your PC console. However, when you have a brand new ARM-based development board coming to the lab and you write your first "hello world" application for it, what do you expect it to do?

At this stage of development, the "hello world" application is "bare metal". By this I mean that the ARM target is not running an operating system providing peripheral drivers to your application. Therefore, an out-of-the-box bare metal application does not have the software infrastructure to send the character string to a suitable peripheral, such as a UART, a USB port or an LCD.

At this stage some developers start to switch LEDs to prove that the target is alive (assuming they have got the target's I/O configuration right). However, for a while, until they get some decent communication interface working, they lack the ability to do "printf-style debugging", a powerful tool in the software engineer's arsenal.

What is semihosting
Semihosting is the default implementation of the C library in the ARM Compiler.

When you write a printf statement in your code, the underlying C library translates it into a software interrupt with a pointer to the character string to print. This software interrupt is trapped and processed by an attached debugger. Obviously, you can "retarget" the C library to take the character string and send it to a peripheral. However, this is not useful until later stages of your design cycle.

Semihosting requires that a JTAG debugger is connected to the target. For example, if you connected DS-5 Debugger and DSTREAM to your target, they would handle semihosting like this:

1-  When loading the "hello world" application to the target, the debugger detects that semihosting is enabled, and configures the target to trap the semihosting software interrupt

2-  When the software interrupt that implements the printf call is executed, the application stops at the debugger's trap, and the debugger takes control of the target, reads the character string from memory, and displays it in its Application Console window

3-  The debugger makes the processor execute an instruction to return from the software interrupt and continue running the code

Why semihosting works for me
Semihosting has some properties that made it a great tool when I was working as an ARM support engineer:

  • It works on any ARM processor
  • It only requires a working JTAG connection, processor and memory system. It has no dependency with peripherals, timers, software infrastructure, or other functional blocks on the SoC, which makes it very safe and reliable
  • It works by default with the ARM Compiler: you do not have to write any special code to use it

Semihosting can also be used for tasks beyond printing messages, as it is used as the out-of-the-box implementation for all C library functionality that is target specific.

For example, you can use the C library file I/O functions to read and write files directly on the host PC file system. For instance, you can use a text file on the host PC to write the test parameters, and another text file to log the output of the test. Thanks to the standard C library (for which there is plenty of example code around) this is pretty easy, and works from day one.

Similarly, you can use the C library time functions to get a reference time from the host PC. This will not be as accurate as a timer on the target, but again, it just works out of the box.

If you want to use semihosting, just get a software toolchain that supports it. For example, the ARM Compiler, DS-5 Debugger and DSTREAM. Good luck!