Ein In-Circuit Emulator (ICE) ist ein Hilfsmittel, um die Software für ein eingebettetes System zu entwickeln. Für die Entwicklung der Software wird der normalerweise im System vorhandene Controller durch eine spezielle Variante ersetzt, der direkt mit dem ICE verbunden ist.
SW-Entwicklung mit Logikanalysator
Eine Methode, die Software für ein eingebettetes System zu testen, sind Logikanalysatoren. Sie werden an den Kontroll-, Adress- und Datenbus angeschlossen und zeichnen deren Signale auf. Die Software des Logikanalysators kann damit nachvollziehen, was der Controller auf der Zielhardware macht. Mittels eines sog. Tracespeichers kann damit der Programmablauf des Controllers über mehrere hundert oder tausend Programmschritte nachvollzogen werden. Die Nachteile der Methode sind eine hohe Zahl von Signalen, die auf dem Zielsystem abgegriffen werden müssen (schon ein 16 Bit Controller bringt es leicht auf über 60 Signale), das Fehlen der Kontrolle über den Programmablauf, keine Möglichkeit, den Inhalt von Registern festzustellen, und der Programmcode kann nur als Assemblercode dargestellt werden. Zudem haben moderne Controller häufig ihren Speicher integriert, wodurch keine externen Leitungen für Kontroll-, Adress- und Datenbus zur Verfügung stehen. Aus diesen Gründen ist die Verwendung von Logikanalysatoren für die Softwareentwicklung heute kaum noch in Gebrauch.
SW-Entwicklung mit In-Circuit-Emulator
Abhilfe für diese Probleme bringen die In-Circuit Emulatoren. Diese Geräte ersetzen den eigentlichen Controller auf dem Zielsystem durch eine Hardware, die die notwendigen Analysefunktionen eingebaut hat.
Für die Realisierung der In-Circuit-Emulatoren gibt es mehrere Möglichkeiten. In vielen Fällen wird eine spezielle Version des zu emulierenden Chips verwendet, die zusätzliche Signale herausführt, um den Programmablauf verfolgen zu können, sog. „Bond-Out-Chips“. Dieser Bond-Out-Chip (so genannt, weil der Prozess des Verbindens der Signale eines Chips mit den Anschlüssen des Gehäuses „Bonding“ genannt wird und hier Signale herausgeführt werden, die sonst nur intern existieren) sitzt dann entweder auf einem sogenannten Pod, einem Adapter, der anstelle des normalen Controllers im Zielsystem angebracht wird, oder direkt im Emulator und nur die Signale werden zum Pod geführt.
Gibt es einen solchen Bond-Out-Chip nicht, so kann auch der Controller durch FPGA oder andere Logikschaltungen komplett nachgebildet werden. Dies ist dann aber möglicherweise mit einem deutlich höheren Aufwand verbunden und garantiert auch nicht eine 100-prozentig getreue Nachbildung.
Der ICE ist in der Regel in die Entwicklungssoftware für den Controller direkt integriert. Dadurch kann nicht nur der aufgezeichnete Befehlscode angezeigt werden, sondern im Quellcode nachvollzogen werden, was der Controller gerade tut. Debugging in Hochsprache und sogar das Auflösen von Betriebssystem-Daten ist damit möglich.
Normalerweise kommt der ICE beim Debugging zum Einsatz. Da er praktisch auch auf das „Innenleben“ des Controllers einblicken und Einfluss nehmen kann (beispielsweise Programcounter, Stackpointer, Statusregister), ist der Programmablauf nun kontrollierbar. Da die Zugriffe auch in (wahrer) „Echtzeit“ möglich sind, lassen sich damit auch Probleme analysieren, die mit sogenannten In-System-Programmern nicht mehr erfassbar sind, da diese ihre Daten über verhältnismäßig langsame Schnittstellen bekommen. Der auch schon bei den Logikanalysatoren zum Einsatz gekommene Tracespeicher ist dabei ein ausschlaggebendes Element. Je tiefer dieser Speicher ist, je mehr er also aufzeichnen kann, desto länger zurück kann man den Programmablauf verfolgen. Dies hilft beim Debugging von komplexen Systemen enorm. Vor allem Probleme mit Interrupts sind auf diese Art vergleichsweise leicht aufspürbar.
Analysemöglichkeiten mit In-Circuit-Emulatoren
Die Ausstattung mit Analysefunktionen ist zwischen verschiedenen Emulatoren sehr unterschiedlich. Als Mindestfunktion können eigentlich alle Emulatoren auf Anwenderbefehl die Programmausführung unterbrechen, die Programmausführung bei Erreichen einer bestimmten Stelle im Programm unterbrechen und das Programm in Einzelschritten ausführen. Dazu kommt die Möglichkeit, den Inhalt der Register und des Speichers auslesen zu können.
Nachfolgend werden die Analysefunktionen aufgeführt, die ein Emulator bieten kann.
Bedingte Programmunterbrechung (Breakpoint)
Im einfachsten Falle wird die Programmausführung bei Erreichen einer bestimmten Stelle (also einer bestimmten Adresse im Programmspeicher) des Programms unterbrochen. Damit lässt sich leicht feststellen, ob ein bestimmter Teil des Programms ausgeführt wird, oder es kann überprüft werden, wie der Zustand am Ende der Ausführung eines bestimmten Programmteiles ist.
Es können aber auch detailliertere Bedingungen für eine Programmunterbrechung möglich sein, wie zum Beispiel Unterbrechung nach n-mal Erreichen der Speicherstelle, Schreib- oder Lesezugriffe auf bestimmte Datenspeicheradressen, oder sogar bei bestimmten Datenwerten, die an eine Speicheradresse geschrieben oder von dort gelesen werden. Sehr komfortabel ausgerüstete Emulatoren erlauben die Verknüpfung solcher Bedingungen, um dann z. B. eine Unterbrechung zu erzeugen, wenn zuerst ein bestimmter Punkt im Programm erreicht wurde und danach ein Zugriff auf eine bestimmte Adresse erfolgt.
Einzelschrittausführung (Single Step)
Bei der Analyse von nicht zeitkritischem Code ist die Einzelschrittausführung oft hilfreich. Hier führt der Prozessor jeweils nur einen Befehl aus und der Anwender kann dann den aktuellen Zustand überprüfen, bevor er den nächsten Befehl ausführen lässt. Damit ist es möglich, dem Prozessor bei der Arbeit im Detail zuzusehen.
Ereignisaufzeichnung (Tracebuffer)
Kommt es in einem Programmabschnitt der auf externe Signale reagieren muss zu Problemen, so sind weder Breakpoints, noch Single Step adäquate Mittel, da dann das Zeitverhalten des Programms verändert wird, so dass die gewünschte Funktion nicht möglich ist, oder der Fehler nicht auftritt. In solchen Situationen ist ein Tracebuffer sehr hilfreich, jedoch bei weitem nicht in jedem Emulator vorhanden und nicht unbedingt mit allen wünschenswerten Optionen versehen. Der Tracebuffer zeichnet die ausgeführten Programmschritte auf, abhängig von der jeweiligen Realisierung können dabei auch Registerinhalte und weitere Signale mit aufgezeichnet werden. Wird das Programm unterbrochen, so können die letzten ausgeführten Programmschritte nachvollzogen werden. Wie viele Programmschritte aufgezeichnet werden, hängt wiederum vom Emulator ab, meist stehen mindestens 500 Programmschritte zur Verfügung. Auch der Tracebuffer kann wieder in unterschiedlichsten Ausführungen auftreten. Im Optimalfall lässt sich der Tracebuffer auf „Pre-“, „Post-“ und „Center-Trigger“ konfigurieren, so dass er die vor, nach, oder um (also vor und nach) einen Breakpoint ausgeführten Programmschritte aufzeichnet. Einige Emulatoren bieten dazu noch ein bedingtes Aufzeichnen, so dass z. B. nur Programmschritte, die in einem bestimmten Speicherabschnitt liegen, aufgezeichnet werden, um so den knappen Tracebuffer für die wirklich interessanten Daten zu reservieren.
Grenzen von In-Circuit-Emulatoren
Das große Problem der ICE ist die hohe Taktgeschwindigkeit der heutigen High-End Controller und deren manchmal extrem kurze Produktlebenszeit. Für den Hersteller des Controllers bedeutet ein Bond-Out Chip fast eine Neuentwicklung desselben. Damit wird er eigentlich nur dann interessant, wenn er in hohen Stückzahlen produziert werden kann. Dies ist bei Entwicklungssystemen regelmäßig aber nicht der Fall. So haben einige Chiphersteller kein Interesse daran, einen Bond-Out Chip zu entwickeln, andere Chiphersteller versehen aber mittlerweile praktisch alle neuen Controller mit einer ICE Schnittstelle. Die hohe Taktgeschwindigkeit ist eine weitere Hürde. Bei mehreren hundert Megahertz Prozessortakt ist der technische Aufwand, die Signale vom Bond-Out Chip zum Emulator zu leiten, entsprechend hoch.
Je nach Ausstattung und der Komplexität und Geschwindigkeit des zu emulierenden Controllers können ICE recht teure Produkte sein, mehrere tausend Euro sind durchaus üblich (der „Rolls-Royce“ der ICE liegt im sechsstelligen Bereich!). Auch ein Bond-Out Chip ist oft nicht billig (hier sind Preise im vierstelligen Bereich möglich). Und durch eine kleine Unachtsamkeit sind diese Chips leicht zu zerstören.
Im Bereich der professionellen Entwicklung steht dem Kostenaufwand aber eine erhebliche Zeitersparnis gegenüber.
In-System-Programmer / In-System-Debugger
Einen Ausweg aus dieser wirtschaftlichen und technischen Zwangslage liefern die In-System-Programmer (ISP) und In-System-Debugger. Teilweise bieten diese nicht die Tiefe der Kontrolle über den Zielcontroller wie ein ICE, so fehlt häufig der Tracebuffer, wodurch komplexe zeitliche Fehler nicht so leicht zu klären sind. Jedoch sind sie um Größenordnungen billiger (die Preise liegen zum Teil im zweistelligen Bereich) und kommen ohne Bond-Out Chip aus. In der Regel muss aber, zumindest beim Entwicklungsmuster, ein zusätzlicher Stecker für ihre Schnittstelle auf der Leiterplatte integriert werden.
Die Hardware für den Zugriff auf die internen Register, etwa um Haltepunkte zu setzen, ist dabei nicht mehr im Pod bzw. Emulator untergebracht, sondern auf jedem Mikrocontroller-Chip bereits enthalten. Der ISP stellt also lediglich die Schnittstelle zu den chipinternen Debugmöglichkeiten her. Neben proprietären Schnittstellen (z. B. dem BDM-Interface von Freescale) gehen mehr und mehr Hersteller von Mikrocontrollern dazu über, die genormte aber eigentlich für Boundary Scan entwickelte JTAG-Schnittstelle zu nutzen. Das Protokoll auf höherer Ebene, also mit welchen JTAG Scan Chains auf die Debug-Möglichkeiten des jeweiligen Controllers zugegriffen werden kann, ist aber bei jedem Hersteller und jedem Produkt unterschiedlich und meist geheim. Die verwendeten Stecker sind ebenfalls von Hersteller zu Hersteller unterschiedlich. Die Norm IEEE 1149.7 versucht ein einheitliches Protokoll zu etablieren.
Bei den PSoC Mikrocontrollern von Cypress wird über eine solche Schnittstelle die komplette Funktion eines ICE inklusive Tracebuffer und bedingter Breakpoints realisiert. Zu diesem Zweck bietet Cypress von jeder Unterfamilie der Controller mindestens den am besten ausgestatteten Chip mit dieser In-System-Debug Schnittstelle an, der dann sowohl als Bond-Out-Chip für den Emulator dient als auch für die Produktion eingesetzt werden kann.
Weblinks
Einige Chip-Hersteller bieten zwar eigene ICE oder ISP an, es gibt aber auch unabhängige Anbieter, bei denen meist dieselbe Programm-Oberfläche für unterschiedlichste Prozessoren verwendet wird – was die Einarbeitungszeit bei Wechsel des Prozessors verringert.
- iSYSTEM stellt ICEs und Debugger für viele Mikrocontrollerarchitekturen her
- Hitex stellt ICEs und Debugger für unterschiedlichste Prozessoren her
- Lauterbach stellt ICEs, Debugger und Logic Analyzer für nahezu alle Architekturen her
- Signum bietet ICEs mit und ohne Trace für verschiedene Architekturen an
- Wind River bietet ICEs mit und ohne Trace für verschiedene Architekturen an
- SEGGER J-Link und SEGGER J-Trace unterstützen ARM und andere Architekturen in Verbindung mit Software Debuggern von IAR, Keil oder auch YAGARTO