Beginner's Corner - In-Circuit-Emulators
|For novel ideas about building embedded systems (both hardware and firmware), join the 27,000+ engineers who subscribe to The Embedded Muse, a free biweekly newsletter. The Muse has no hype and no vendor PR. It takes just a few seconds (just enter your email, which is shared with absolutely no one) to subscribe.
By Jack Ganssle
Beginner's Corner - In-Circuit-Emulators
Embedded systems pose unique debugging challenges. With neither terminal nor display (in most cases) there's no natural way to probe these devices, to extract the behavioral information needed to find what's wrong. This magazine is filled with ads from vendors selling quite a wide variety of debuggers; all let us connect an external computer to the system being debugged to enable single stepping, breakpoints, and all of the debug resources enjoyed by programmers of desktop computers.
The In-Circuit Emulator (ICE) is one of the oldest embedded debugging tools, and is still unmatched in power and capability. It's the only tool that substitutes it's own internal processor for the one in your target system. Via one of a number of hardware tricks the emulator can monitor everything that goes on in this on-board CPU, giving you complete visibility into the target code's operation. In a sense the emulator is a bridge between your target and your PC, giving you both an interactive terminal peering deeply into the target, while providing a rich set of debugging resources.
Years ago the ICE physically replaced the target processor. Users extracted the CPU from its socket, plugging the emulator's cable in instead. Today we're usually faced with a soldered-in surface mounted chip, so connection strategies are more difficult. Some emulators come with an adapter that clips over the SMT processor, tri-stating the device's core which is then replaced by the ICE's own CPU. In other cases the emulator vendor provides adapters that can be soldered in place of the target CPU. As chip sizes and lead pitches shrink the range of connection approaches goes up; rest assured that connecting the emulator is usually the most difficult and frustrating part of using such devices. Add at least a few days to your schedule to surmount these difficulties. Work closely with the vendors, all of whom are connections experts anxious to share their knowledge.
Like all debuggers the emulator's most fundamental resource is target access - the ability to examine and change the contents of registers, memory and I/O. However, since the ICE replaces the CPU it generally does not need working hardware to provide this capability. This makes the ICE by far the best tool for troubleshooting new or defective systems. For example, you can repeatedly access a single byte of RAM or ROM, creating a known and consistent stimulus to the system that is easy to track using an oscilloscope.
Breakpoints are another important debugging resource; these give you the ability to stop your program at precise locations or conditions (like "stop just before executing line 51"). Emulators also use breakpoints to implement single stepping, since the processor's single step mode, if any, isn't particularly useful for stepping through C code.
There's an important distinction between the two types of breakpoints used by different sorts of debuggers: software breakpoints (generally found on BDMs, software-only monitors, and the like) work by replacing the destination instruction by a software interrupt or similar instruction. Clearly, it's impossible to debug code in ROM with these. Emulators generally offer a huge number of hardware breakpoints, which use the unit's internal magic to compare the break condition against the execution stream. Hardware breakpoints work in RAM or ROM, Flash or even unused address spaces.
Complex breakpoints let us ask deeper questions of the tool. A typical condition might be: "Break if the program writes 0x1234 to variable buffer, but only if function get_data was called first". Some software-only debuggers (like that supplied with Visual C++) offer similar power, but must essentially interpret the program at a snail-like pace while watching for the trigger condition. Emulators implement complex breakpoints in hardware, so impose (in general) no performance penalty.
ROM and to some extent Flash memory for program storage leads to debugging difficulties since it's hard to impossible to download code into these. During a typical debug session we might change and redownload code many times an hour so it's important to have RAM-like program memory. The ICE's emulation memory is high speed RAM inside of the emulator itself that maps logically in place of your system's ROM. Download changes at will.
Many ICEs have programmable guard conditions for accesses to both the emulation and target memory. Thus, it's easy to break when, say, the code wanders off and tries to write to program space, or attempts any sort of access to unused addresses.
Nothing prevents you from mapping emulation memory in place of your entire address space, so you can actually debug much of the code with no working hardware. Why wait for the designers! who will likely be late anyway? Operate the emulator stand-alone (without the target) and start debugging code long before engineering delivers prototypes.
Real time trace is one of the most important emulator features, and is one practically unique to this tool. Trace captures a snapshot of your executing code to a very large memory array, at full speed. It saves thousands to hundreds of thousands of machine cycles, displaying the addresses, the instructions, and transferred data. The emulator and its supporting software translates raw machine cycles to assembly code or even C/C++ statements, drawing on your source files and the link map for assistance.
Trace is always accompanied by sophisticated triggering mechanisms. It's easy to start and stop trace collection based on what the program does. An example might be to capture every instance of the execution of an infrequent interrupt service routine. You'll see everything the ISR does, with no impact on the real time performance of the code.
Emulators generally use no target resources. They don't eat your stack space, memory, or effect the code's execution speed. This "non-intrusive" feature is critical for dealing with real-time systems.
Be aware, though, that emulators face challenges that may change the nature of the market and the products. As processors shrink it's awfully hard to connect anything to those whisker-thin package leads. Vendors offer all sorts of adapter options, some of which work better than others.
Skyrocketing CPU speeds create profound difficulties. At 100 MHz each machine cycle takes a mere 10 nsec; even an 18 inch cable between your target and the ICE starts to act as a very complex electrical circuit rather than a simple wire. One solution is to shrink the emulator, putting all or most of the unit near the target socket. As speeds increase, though, even this option imposes tough electrical problems.
Page through the ads in this magazine and you'll see a wide range of emulators for 8 and 16 bit processors, the arena where speeds are more tractable. Few ICEs exist for high end processors due to the immense cost of providing fast emulation memory and a reliable yet speedy connection.
Oddly, one of the biggest user complaints about emulators is their complexity of use. Too many developers never progress beyond the most basic of ICE features. Sophisticated triggering and breakpoints invariably means rather complex setups. Figure on reading the manual and experimenting a bit; the up-front time will pay off big time later in the project. Can you imagine the poor word processor user who tediously edits the same change dozens of times! because he never learned search-and-replace? Time spent in learning tools always gets the project done faster.
ICE Technology Unplugged - http://www.embedded.com/1999/9910/9910sr.htm