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.
Den Debugger öffnen Sie im Hauptfenster über den Menüpunkt
Extra → Werkzeuge → Debugger....
Die weitere Beschreibung bezieht sich auf das Debugger-Fenster.
Dieses besteht aus mehreren Unterfenstern (Reitern).
Das Unterfenster CPU ist das wichtigste
und bietet auf der linken Seite einen Blick
auf die Flags, die Register und die Programmausführung.
Die rechte Seite enthält Listen für die verschiedenen
Arten von Halte- und Log-Punkten.
Diese Listen lassen sich in ihrer dargestellten Größe
verändern, indem man die Balken dazwischen verschiebt.
Drückt man über solch einer Liste die rechte Maustaste,
öffnet sich ein Kontextmenü.
Dieses Kontextmenü bezieht sich nur auf die Halte-/Log-Punkte
in der Liste, über der es geöffnet wurde.
Demgegenüber bezieht sich das Fenstermenü
Halte-/Log-Punkte, welches teilweise die gleichen Einträge
wie das Kontextmenü enthält,
auf alle Halte-/Log-Punkte.
Damit Sie die Speicher- und Registerinhalte ansehen können,
muss die Programmausführung angehalten werden.
Dafür gibt es zwei Möglichkeiten:
-
Sie legen einen oder mehrere Haltepunkte an.
Wenn während der Befehlsabarbeitung ein solcher Haltepunkt
zutrifft, wird angehalten.
-
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.
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.
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.
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.
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 und bzw. oder
eine Flagbedingung prüfen lassen.
In dem Fall wird nur angehalten bzw. eine Log-Meldung ausgegeben,
wenn neben der angegebenen Adresse auch die Registerwertprüfung
erfolgreich und bzw. oder die Flagbedingung erfüllt ist.
Die Registerwertprüfung 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.
Optional kann einem Halte-/Log-Punkt auf eine Programmadresse
auch ein Name vergeben werden.
Neben einem besseren Überblick dient dieser Name der Zuordnung beim
Importieren von Halte-/Log-Punkten.
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.
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.
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.
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.
Ü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.
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 Halte-/Log-Punkt anzulegen.
Der Name dient dazu, bereits vorhandene Halte-/Log-Punkte
zu aktualisieren, d.h., ist ein zu importierender Halte-/Log-Punkt
mit gleichem Namen bereits vorhanden,
wird bei diesem nur die Adresse aktualisiert und kein neuer
Halte-/Log-Punkt angelegt.
Die Markentabelle des JKCEMU-Assemblers
können Sie automatisch in den Debugger importieren lassen.
Schalten Sie dazu die Assembler-Option
Marken im Debugger verwenden ein.
In dem Fall wird auch noch zwischen Halte-/Log-Punkte auf
Programmadressen und auf Speicherbereiche unterschieden.
Normalerweise wird für jede Marke ein Halte-/Log-Punkt
auf eine Programmadresse angelegt bzw. aktualisiert.
Enthält jedoch die betreffende Assembler-Quelltextzeile
eine DEFS- oder DS-Instruktion,
wird der Halte-/Log-Punkt auf den Speicherbereich angelegt.
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.
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.
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.
Es werden die Maschinenbefehle bis zum nächsten Return-Befehl
ausgeführt.
Werden dabei Unterprogramme aufgerufen,
so werden diese vollständig ausgeführt.
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.
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.
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 Marken im Debugger verwenden
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.
Haben Sie ein größeres Projekt vor sich,
welches Sie am nächsten Tag weiter debuggen möchten,
kann es mühselig sein, die ganzen Halte-/Log-Punkte und Variablen
erneut anlegen zu müssen.
Damit Sie sich diese Arbeit sparen können,
bietet der Debugger die Möglichkeit, alle Halte-/Log-Punkte
und alle Variablen in eine XML-Datei zu speichen
und diese auch wieder zu laden.
Die Funktionen dafür finden Sie im Menü Datei.