Debugger

Der Debugger dient dazu, die Programmausführung an beliebiger Stelle anzuhalten, einzelne Befehle im Schrittbetrieb abzuarbeiten und so das Geschehen im Emulator zu überwachen. Dabei ist es auch möglich, die Speicher- und Registerinhalte anzusehen. Die Registerinhalte können auch geändert werden. Zum Ändern des Speicherinhalts gibt es den Speichereditor.


1. Debugger starten

Sie befinden sich im Hauptfenster und klicken im Menü Extra, Untermenü Werkzeuge, den Punkt Debugger... an. Die weitere Beschreibung bezieht sich auf das Debugger-Fenster.

2. Programmausführung anhalten

Damit Sie die Speicher- und Registerinhalte ansehen können, muss die Programmausführung angehalten werden. Dafür gibt es zwei Möglichkeiten:
  1. Sie legen einen oder mehrere Haltepunkte an. Wenn während der Befehlsabarbeitung ein solcher Haltepunkt zutrifft, wird angehalten.
  2. Sie klicken im Menü Debuggen auf den Punkt Programmausführung anhalten.
Jedesmal wenn die Programmausführung anhält, wird der Inhalt des Debugger-Fensters aktualisiert, d.h., Sie sehen im linken Bereich des Fensters die Registerinhalte, in der Mitte die ersten Bytes der Speicherbereiche, auf die die Doppelregister zeigen und unten die nächsten auszuführenden Befehle.

3. Programm bis Haltepunkt ausführen

Mit dieser Funktion wird die Programmausführung in normaler bzw. voller Geschwindigkeit fortgesetzt. Wenn dabei das Programm auf einen Haltepunkt trifft, dessen Bedingung erfüllt ist, wird angehalten.

4. Programm bis Haltepunkt langsam ausführen

Bei dieser Funktion führt der Debugger das Programm langsam aus. Sie können so die Abarbeitung des Programms im Debugger verfolgen. Die Geschwindigkeit der Programmabarbeitung ist in drei Stufen wählbar. Wenn das Programm auf einen Haltepunkt trifft, dessen Bedingung erfüllt ist, wird angehalten.

5. Halte-/Log-Punkte

Halte-/Log-Punkt verkörpern eine Bedingung, bei der die Programmausführung angehalten (Haltepunkt) und/oder eine Log-Meldung (Log-Punkt) ausgegeben wird. Es gibt fünf verschiedene Arten von Halte-/Log-Punkten.

Das Anlegen von Halte-/Log-Punkten erfolgt über das Menü am Fenster oder über das Kontextmenü (rechte Maustaste) über dem jeweiligen Halte-/Log-Punktbereich.

5.1. Halte-/Log-Punkt auf Programmadresse

Das ist die klassische Form eines Halte-/Log-Punktes. Es wird angehalten bzw. eine Log-Meldung ausgegeben, wenn die Programmausführung an der angegebenen Adresse angelangt ist. Zusätzlich können Sie den Wert eines Registers prüfen lassen. Dann wird nur angehalten bzw. eine Log-Meldung ausgegeben, wenn neben der Adresse auch die Registerwertprüfung erfolgreich war. Diese läuft folgendermaßen ab: Vor Abarbeitung des Befehls auf der Halte-/Log-Punktadresse wird der Wert des ausgewählten Registers mit einer von Ihnen anzugebenden Maske UND-verknüpft und das Ergebnis dann mit einem ebenfalls von Ihnen anzugebenden Vergleichswert verglichen. Dabei ist nicht nur ein Vergleich auf Gleichheit möglich, sondern auch auf Ungleichheit sowie auf größer als und kleiner als.

Halte-/Log-Punkte auf Programmadressen können Sie neben den oben genanten Möglichkeiten auch über das Kontextmenü der Programmcodeanzeige sowie im Reassembler über das Kontextmenü anlegen. Bei diesen beiden Varianten wird gleich die Adresse entsprechend der Position des Kontextmenüs vorbelegt.

5.2. Halte-/Log-Punkt auf Speicherbereich

Ein solcher Halte-/Log-Punkt reagiert auf Zugriffe auf eine Speicherzelle bzw. auf einen Speicherbereich. Sie können angeben, ob nur bei Lese-, nur bei Schreib- oder bei Lese- und Schreibzugriffe angehalten bzw. eine Log-Meldung ausgegeben werden soll. Zusätzlich können Sie den Wert der betreffenden Speicherzelle (Lesezugriff) bzw. den zu schreibenden Wert (Schreibzugriff) überprüfen lassen. Auch hier geben Sie Maske, Vergleichsoperator und Vergleichswert an.

Achtung! Der Debugger prüft vor der Ausführung eines jeden Maschinenbefehls, ob dieser auf den angegebenen Speicherbereich zugreift. Aufgrund dieser Arbeitsweise werden jedoch die Speicherzugriffe, die während einer Interrupt-Annahme getätigt werden (Lesen der Interrupt-Tabelle im Interrupt-Mode 2 und Kellern der Rückkehradresse) von keinem Halte-/Log-Punkt erkannt.

5.3. Halte-/Log-Punkt auf Eingabetor

Bei diesem Halte-/Log-Punkt geben Sie die Adresse oder den Adressbereich eines Eingabetors an. Es wird dann vor einem Eingabebefehl angehalten bzw. eine Log-Meldung ausgegeben, der von diesem Eingabetor liest.

Die Eingabeadresse kann sowohl mit 8 Bit (2 hexadezimale Ziffern) als auch mit 16 Bit (4 hexadezimale Ziffern) angegeben werden. Dementsprechend wird dann auch die Adresse mit 8 oder 16 Bit geprüft.

5.4. Halte-/Log-Punkt auf Ausgabetor

Dieser Halte-Log-Punkt ist ähnlich wie einer auf einem Eingabetor, nur dass er auf Ausgabebefehle reagiert. Zusätzlich können Sie den auszugebenden Wert überprüfen lassen.

5.5. Halte-/Log-Punkt auf Interrupt-Quelle

Bei dieser Form eines Halte-/Log-Punktes geben Sie eine im emulierten System vorhandene Interrupt-Quelle (z.B. PIO oder CTC) an. Es wird dann angehalten, sobald die Interrupt-Quelle einen Interrupt auslöst und dieser vom Mikroprozessor auch angenommen wird, d.h., es wird vor dem ersten Befehl der Interrupt-Service-Routine angehalten bzw. eine Log-Meldung ausgegeben.

5.6. Verwaltung der Halte-/Log-Punkte

Über das Menü Debuggen können Sie beliebig viele Halte-/Log-Punkte anlegen. Mit dem Kontextmenü über der jeweiligen Haltepunktliste ist das auch möglich.

Um einen Halte-/Log-Punkt wieder zu entfernen, müssen Sie diesen im rechten Bereich des Debugger-Fensters durch Anklicken markieren. Sie können auch mehrere Halte-/Log-Punkte markieren. Anschließend klicken Sie im Menü Debuggen auf den Eintrag Ausgewählte Halte-/Log-Punkte entfernen.

Optional können Sie auch alle Haltepunkte auf einmal entfernen (Menüeintrag Alle Halte-/Log-Punkte entfernen).

Halte-/Log-Punkte, die Sie temporär nicht benötigen, müssen nicht unbedingt entfernt werden. Sie können diese einfach deaktivieren, indem Sie die beiden Aktionen (Anhalten und Loggen) deaktivieren. Bei Bedarf können Sie die gewünschte Akion später wieder aktivieren.

Der Debugger ist nur solange aktiv, wie das Debugger-Fenster sichtbar ist. Wenn Sie Halte-/Log-Punkte angelegt haben und Sie schließen das Fenster, werden die Halte-/Log-Punkte zwar nicht gelöscht, jedoch sind sie nicht mehr aktiv.

5.7. Halte-/Log-Punkte importieren

Der Debugger bietet die Möglichkeit, Halte-/Log-Punkte aus einer Datei oder aus der Zwischenablage zu importieren. Diese Halte-/Log-Punkte können dabei auch einen Namen haben. So ist z.B. der Import der Markentabelle eines Assemblers möglich, um für jede Marke einen Haltepunkt anzulegen.

Die Markentabelle des JKCEMU-Assemblers können Sie sogar automatisch in den Debugger importieren lassen. Schalten Sie dazu die Assembler-Option Im Debugger Halte-/Log-Punkte bzw. Variablen auf Marken anlegen ein.

6. Schrittbetrieb

Mit Schrittbetrieb ist gemeint, dass nach dem Anhalten der Programmausführung einzelne Befehle oder Befehlsgruppen abgearbeitet werden und danach automatisch wieder die Programmausführung angehalten wird.

Die Funktionalitäten des Schrittbetriebs finden Sie im Menü Debuggen unter den Punkten Einzelschritt über Aufruf hinweg, Einzelschritt in Aufruf hinein und Bis RETURN ausführen.

Den Schrittbetrieb beenden Sie ganz einfach durch Fortsetzung der Programmausführung. Klicken Sie dazu im Menü Debuggen den Punkt Bis Haltepunkt ausführen an.

Wenn Sie sich im Schrittbetrieb befinden und Sie schließen des Debugger-Fenster, geht der Emulator in den Pause-Zustand über. Sie können dann im Hauptfenster im Menü Extra auf Fortsetzen klicken, oder Sie öffnen wieder den Debugger.

6.1. Einzelschritt über Aufruf hinweg

Es wird ein einzelner Maschinenbefehl abgearbeitet. Handelt es sich jedoch um den Aufruf eines Unterprogramms, so wird das ganze Unterprogramm ausgeführt und erst danach wieder angehalten. Das gleiche gilt für Blockbefehle und leere DJNZ-Schleifen.

6.2. Einzelschritt in Aufruf hinein

Es wird immer nur ein einzelner Maschinenbefehl abgearbeitet. Handelt es sich um den Aufruf eines Unterprogramms, so wird nur der CALL-Befehl abgearbeitet und somit vor dem ersten Maschinenbefehl des Unterprogramms wieder angehalten.

Bei Blockbefehlen wird nur ein Zyklus des Blockbefehls abgearbeitet und danach wieder angehalten.

6.3. Bis RET ausführen

Es werden die Maschinenbefehle bis zum nächsten Return-Befehl ausgeführt. Werden dabei Unterprogramme aufgerufen, so werden diese vollständig ausgeführt.

6.4. Registerinhalte und Flags ändern

Im Schrittbetrieb, d.h. wenn die Programmausführung angehalten wurde, können die Inhalte der Register geändert werden. Geben Sie dazu den gewünschten neuen Wert in das jeweilige Feld hexadezimal ein. Die Werte der einzelnen Flags können Sie festlegen, indem Sie auf die entsprechenden Boxen im oberen Bereich des Fensters klicken und so ein Häkchen setzen oder entfernen.

7. Befehle aufzeichnen

Eine weitere Möglichkeit der Verfolgung des Geschehens im Emulator ist die Befehlsaufzeichnung. Dabei werden vor der Abarbeitung eines jeden Maschinenbefehls die Adresse, die Inhalte der wichtigsten Register und der anstehende Maschinenbefehl in Form einer Zeile in eine Textdatei geschrieben. Diese können Sie sich dann mit einem Editor ansehen, z.B. mit dem im JKCEMU eingebauten Texteditor.

Die Befehlsaufzeichnung schalten Sie über den Schalter Befehle aufzeichnen im Menü Debuggen ein und wieder aus. Immer wenn Sie die Befehlsaufzeichnung einschalten, werden Sie nach dem Namen der Datei gefragt, in der die Befehle aufgezeichnet werden sollen.

Achtung! Die Befehlsaufzeichnung schreibt pro Maschinenbefehl eine ganze Zeile in eine Textdatei. Diese Textdatei wächst somit sehr schnell und sehr stark an. Sie sollten deshalb die Befehlsaufzeichnung nicht zu lange eingeschaltet lassen und sicherstellen, dass auf dem Speichermedium ausreichend Platz ist. Außerdem wird die Programmausführung in Abhängigkeit von der Schreibgeschwindigkeit des Speichermediums deutlich gebremst.

8. Variablen

Ein Programm speichert seine Daten üblicherweise in Variablen. Da es beim Debuggen sehr hilfreich ist, die aktuellen Variableninhalte zu sehen und ggf. auch zu ändern, bietet der JKCEMU Debugger dafür eine Unterstützung. Allerdings weiß der Debugger nicht, welche Speicherbereiche für Variablen verwendet werden und welche Datentypen diese haben. Aus diesem Grund müssen die Variablen dem Debugger erst bekannt gemacht werden, d.h., sie müssen im Debugger angelegt werden. Für jede Variable geben Sie eine Adresse, einen Datentyp und optional einen Namen an. Wenn Sie das erledigt haben, zeigt der Debugger die aktuellen Variableninhalte an, sobald die Programmausführung anhält.

Neben dem manuellen Anlegen können Variablen auch von dem im JKCEMU integrierten Assembler importiert werden. Wenn Sie die Assembler-Option Im Debugger Halte-/Log-Punkte bzw. Variablen auf Marken anlegen eingeschaltet haben, wird für jede Marke, die unmittelbar vor einer DS- oder DEFS-Anweisung steht, eine Variable angelegt.

Im technischen Sinne ist eine Variable im JKCEMU Debugger nur eine Deklaration, die besagt, wie ein ein oder mehrere Bytes großer Bereich im Arbeitsspeicher zu betrachten ist, d.h. ob dort ein numerischer, alphanumerischer oder binärer Wert gespeichert wird. Sie können beliebig viele Variablen anlegen.

Den Inhalt des Arbeitsspeichers können Sie sich auch mit dem Speichereditor anzeigen lassen und auch ändern. Das Anlegen von Variablen im Debugger hat jedoch den Vorteil, dass die Anzeige beim Anhalten der Programmausführung automatisch aktualisiert wird und dass Sie nur die Bytes sehen, die Sie interessieren, auch wenn die Bytes im ganzen Arbeitsspeicher verstreut sind.