The increasing emphasis on green technologies has focused more attention on low power design. Microcontroller vendors are responding by increasing their offerings of ultra low power devices that consume as little as 350 uA/MHz and have sub-uA sleep modes.

Using a low power microcontroller is a good first step in lowering power consumption. The next step should be to minimize the number of instructions the CPU must execute to get the job done, so it can spend as much time as possible in the deepest sleep mode available. This can be accomplished with careful design of the application software structure, tight coding and a compiler that reduces the number of required instructions. Compilers can have a significant effect on the number of instructions required to execute the application and the resulting power consumption. All too often the method of compilation wastes CPU cycles on interrupt routines, and on locating addresses in devices with banked memory.

Interrupt Routines.

Interrupt should always be small and fast. This is especially true when speed and/or power consumption are critical. Keeping interrupt routines small reduces interrupt overhead.

OCG compiler call graph
The compiler's contribution to interrupt is in the way it generates the context – the number of registers it saves in response to an interrupt. Ordinary compilers save every register that might be used by an interrupt because they have no way of knowing which registers will or will not be used by a given interrupt. The problem is that the number of cycles used is a direct function of the number of registers that are saved and restored. Cycles spent saving and restoring the context consume power. For example, one compiler for Microchip's PIC16 always saves 8 Bytes of data for every interrupt using a total of 42 instruction cycles (23 for the context save and 19 for the restore). This may not seem like much, but in an interrupt intensive application, the CPU could spend thousands of extra cycles "awake," unnecessarily consuming power.

Newer compilers are now available with "omniscient code generation" (OCG) technology that has the intelligence to save only those registers that are required for each particular interrupt. Omniscient code generation works by collecting comprehensive data on register, stack, pointer, object and variable declarations from all program modules before compiling the code. An OCG compiler combines all the program modules into one large program, which it loads into a call graph structure. Based on the call graph, the OCG code generator creates a pointer reference graph that shows each instance of a variable having its address taken, plus each instance of an assignment of a pointer value to a pointer (either directly, via function return, function parameter passing, or indirectly via another pointer). It then identifies all objects that can possibly be referenced by each pointer. This information is used to determine exactly how much memory space each pointer will be required to access.

Since an OCG compiler knows exactly which functions call, and are called by, other functions, which variables and registers are required, and which pointers are pointing to which memory banks, it also knows exactly which registers will be used for every interrupt in the program. It can generate code accordingly, minimizing both the code size and the cycles required to save and restore the context.

The smallest context will require 17 cycles - 10 to save the context and 7 to restore it. The worst case for the OCG compiler is only 25 cycles. Compared to a conventional compiler, an OCG compiler can reduce the number of interrupt- related instruction cycles by 40% to 60%.