Semi-hosting is a debugging capability supported by ARM processors that allows the embedded target to access i/o capabilities on a host PC through the debugging interface. The i/o capabilities are most often used with printf to transmit text data to a virtual terminal within the debugging environment but it can also be used for file access and for keyboard input.
Semi-hosting capabilities are usually implemented through a special library that interfaces with the standard C libraries. In many cases, the library is included in the development environment by default. For example, in the Renesas Synergy(TM) platforms e2 Studio, the –specs=rdimon.specs option is included by default which includes the hooks for using semi-hosting. All a developer needs to do is include the standard library and all printf statements in their module are redirected through the semi-hosting facilities.
At the lowest levels, semi-hosting is implemented in the ARM core by triggering either the SWI instruction (Software Interrupt), which has been replaced by the SVC instruction (Supervisory Call). On some parts, the BKPT instruction might also be used. When the instruction is executed, the processor stops executing the application and waits for the debugger to access the processor and retrieve the contents that need to be transferred to the host.
Semi-hosting at the surface seems like a great idea. Not all embedded targets have the i/o capabilities to connect a keyboard, screen or a file system. Semi-hosting provides the ability to have this functionality through the host environment and use the debugger to transfer the data. However, there are several major problems with semi-hosting that make it a capability that I avoid at nearly all costs.
First, semi-hosting is ridiculously slow. The fact that the CPU is halted and the debugger must access the core, transfer to the host and then resume operation causes a delayed execution which can be tens of milliseconds! This is longer than most system tick durations and can wreak havoc on the softwares real-time performance. For example, below is a screen shot I took to measure the time it takes to print “Hello World!\r\n” over semi-hosting. As you can see, it took over 60 milliseconds!
Second, when semi-hosting is enabled, the processor halts and waits for the debugger. If the debugger is not attached to the system, the processor will halt indefinitely! This means that semi-hosting can only be used during debugging and a developer must compile out their semi-hosting capabilities for production. Otherwise, their device may hang-up on their end-user as it waits for a debugger to retrieve information and resume operation. This blocking behavior is disappointing but a fact developers need to live with.
Finally, semi-hosting is not deterministic. The execution times can vary widely and potentially drive developers crazy as they try to track down strange behaviors in their software that are really stemming from using semi-hosting. In a real-time application, determinism is critical and anything that can affect this should be avoided at all costs.
Semi-hosting is a really neat feature that can certainly be helpful to developers in many instances. However, in most cases, I’ve found it to be more of a problem than an asset. All the same, it’s important for us developers to understand the tools and capabilities that are available to us. I would still recommend that you take an hour or so to explore the semi-hosting capabilities that exist in your toolchain and understand how they effect timing and your ability to develop your system.