Debuggen

Für diesen Beitrag wurde das CBM prg Studio verwendet.
weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

CBM prg StudioDie ‚Wanzen‚ finden…

Wir kennen jetzt alle Befehle und Adressierungsarten. Die meisten Befehle haben wir auch in Beispielprogrammen verwendet.
Das Wichtigste ist es nun weiterzumachen, nur durch üben lernt man wirklich etwas. Auch das ‚Fehlermachen‚, diese zu suchen und zu korrigieren gehört dazu und ist von unschätzbaren Wert. Wenn eine Routine einfach nicht funktionieren will und ihr euch reinhängt um das gewünschte Ergebnis zu erreichen, dann werdet ihr dabei eine Menge mehr lernen, als durchs lesen eines Textes und probieren der Beispiele mit Copy & Paste.

Mut zum Fehler
Fehler werden euch immer wieder begegnen. Schauen wir uns daher zum Abschluß des Assembler Grundlagen Tutorials exemplarisch mal die am häufigsten vorkommenden an und klären, wie man diese findet.

Am einfachsten zu finden sind Syntax-Fehler bei der Eingabe, schreibt ihr versehentlich z. B. lad #$5A statt lda #$5A oder verwendet eine für den Befehl nicht mögliche Adressierung wie z. B.  sty $D020,X dann werdet ihr spätestens beim Übersetzen vom Assembler darauf hingewiesen. Daher sind diese Fehler sehr einfach zu beheben.

Die folgenden Tippfehler sind da schon etwas fieser. Sie erzeugen nicht immer eine Meldung des Assemblers, können einen aber schon einiges an Kopfzerbrechen bereiten. Eine kleine Warnung: Jetzt wird es zwar etwas nervig, da wir sehr oft den Debugger öffnen und schließen werden. Dies dient aber der Übung und sollte von euch nicht einfach übersprungen werden.

!!! Alles voller Fehler !!!

Auf den ersten Blick sieht das Programm ganz OK aus. Eigentlich sollten wir das Programm korrigieren können, ohne das wir es einmal starten müssen. Da wir aber noch am Anfang unserer Programmiererlaufbahn auf dem C64 sind, nutzen wir die uns gegebenen Möglichkeiten zur Fehlersuche komplett aus.
Sobald ihr das Programm startet wirft euch das CBM prg Studio drei Fehler aus:

Die drei Fehler im CBM prg Studio
Die drei Fehler im CBM prg Studio

Die ersten beiden Fehler „unknown variable„ in Zeile 10 und 12 sind etwas missverständlich. So sehr wir auch schauen, bei der Variablen ZP_COPYPOS  können wir keinen Tippfehler entdecken, also warum ist diese unbekannt? Der Assembler ersetzt ZP_COPYPOS  mit dem Text, der hinter dem Gleichheitszeichen ‚=‚ folgt. Dort steht #FB  das ist aber kein gültiger Wert für einen sta  wie er in Zeile 10 und 12 vorkommt und wird deshalb als Variable erkannt, die es natürlich nicht gibt. Wie ihr wisst, könnt ihr ja auch Variablen, andere Variablen zuweisen. Hier müsste also statt der Raute ‚#‚ das Dollarzeichen ‚$‚ stehen, richtig wäre also $FB , wir wollen hier ja eine Zero-Page-Adresse verwenden.
Der dritte Fehler ist wiederum recht einfach. In Zeile 14 wollen wir mit lda etwas vom angegebenen Label+1 in den Akku laden. Die Raute hat hier also nichts verloren, sie wird nur bei der unmittelbaren Adressierung verwendet. Damit sich unser Programm starten lässt, ändern wir den lda in Zeile 14 also in lda l1:+2 .

Juhu, es läuft, oder auch nicht! Aber zumindest gibt es keinen Absturz. Da wir die uns angebotenen Mittel zur Fehlersuche nutzen wollen, verwenden wir jetzt einfach mal den eingebauten Debugger des CBM prg Studios. Um unser Programm zu debuggen, wählt aus dem Menü „Debug„ bitte einfach den Punkt „Debug Program„ aus. Das Debugfenster öffnet sich und die Adresse $0801 ist hervorgehoben.

 

Das Debug-Fenster

Der Debugger des CBM prg Studios.
Ihr soltet jetzt dieses Fenster vor euch haben.

Unter dem Menü und der Toolbar folgen als Erstes unsere Register:

PC : ProgramCounter = Adresse an der der nächste Befehl gesucht wird (hier $0801)
AC : ACcumulator = der aktuelle Akku-Inhalt
XR : XRegister = das X-Register
YR : YRegister = unser Y-Register
SP : StackPointer = nächste freie Adresse auf dem Stack
SR : StatusRegister = unser Statusregister (die Flags) als Hexzahl
Zum Schluß findet ihr die bitweise Darstellung der Flags NV-BDIZC

Dann folgt ein Label ‚Status‚ hier seht ihr ob der Debugger darauf wartet ‚Idle‚, dass ihr den nächsten Schritt ausführt oder ob ihr ihn automatisch laufen lasst ‚Runnig…‚. Unterbrecht ihr die Automatik, dann seht ihr dort die Adresse z. B. ‚Stopped at 081A‚.

Den meisten Platz nimmt das Disassembler-Fenster ein. Hier seht ihr, ähnlich wie beim Assembly-Dump, die Speicheradressen, Bytes und Mnemonics eures Programms.

Unter diesem Bereich gibt es einen Schieberegler, mit dem ihr die Geschwindkeit für die Automatik regulieren könnt.

Ganz unten seht ihr links zunächst den Inhalt des Stacks.
Daneben folgt die Watch List, leider aktualisiert der Debugger die Speicherstellen im Disassembler-Fenster nicht! Möchtet ihr also den Inhalt einer Speicherstelle kontrollieren, dann müsst ihr diese der Watch List hinzufügen.
Als Letztes finden wir ganz rechts unten eine Auflistung unseren aktuellen Breakpoints. Eine schöne Funktion ist, dass man neben ‘normalen‚ Breaktpoints (z. B. stoppe wenn du bei Adresse $0821 angekommen bist) auch Bedingungen als Breakpoint eingeben kann. Damit könnt ihr das Programm z. B. anhalten, sobald im Akku eine Zahl über 16 steht.

 

Die Grenzen des Debuggers
Wie ich schon erwähnt habe, ist der Debugger des CBM prg Studios z. Zt. sehr einfach gehalten. Eben habe ich bereits darauf hingewiesen, dass z. B. Änderungen an den Speicherstellen nicht direkt sichtbar sind. Auch nicht im Memory Viewer, den ihr im Hauptfenster unter Tools findet. Dann könnt ihr keine Systemroutinen des C64 verwenden und seht natürlich auch keine BS-Ausgaben. Früher oder später werdet ihr wohl nicht daran vorbeikommen, eure Programme auf einem echten C64 oder zumindest direkt im Emulator zu debuggen. Die Emulatoren bieten in der Regel eingebaute Tools, mit denen ihr eure Programme untersuchen könnt. Ein sehr schöne Lösung bietet das C64 Studio von Georg Rottensteiner, dort kann man aus der Entwicklungsumgebung direkt den VICE-Emulator debuggen.

 

Weiter mit unserem Programm…
Beim Start des Debuggers stehen wir also an der Speicherstelle $0801, was logisch ist, denn diese Adresse haben wir im Source mittels *=$0801 festgelegt. Da wir eben erfahren haben, das der Debugger keine Systemroutinen kennt, müssen wir erstmal unsere BASIC-Startzeile überspringen. Klickt dazu doppelt auf die Adresse $080E, damit diese markiert ist, klickt anschließend mit der rechten Maustaste darauf und wählt „Set PC„ aus dem Menü. Jetzt sollte ganz oben unter PC die Adrese $080E stehen. Wenn ihr euch nun mal den LDA #$03 anschaut solltet ihr stutzig werden. Wir wollten laut Kommentar im Source doch als erstes das LSB an die Zero-Page Adresse ZP_COPYPOS = $FB schreiben. Die Adresse lautet ja $03FF , also hätte hier ein lda $FF  stehen müssen, das finden wir aber erst an der Speicherstelle $0812. Wir haben uns also bei den Befehlen für die Ermittlung des LSB/MSB vertippt. Schließt den Debugger und tauscht die Zeilen 9 und 11 aus. Da wir hier gerade rumfuhrwerken, das Speichern sieht auch nicht korrekt aus. Wir verwenden beide mal sta ZP_COPYPOS , das stimmt so ja auch nicht. Wir überschreiben fälschlich die zuerst gefüllte Adresse, statt das MSB in die darauffolgende zu schreiben. Ändert Zeile 12 also in sta ZP_COPYPOS+1.
Ein weiterer Programmstart bringt leider noch keine wirkliche Verbesserung. Also wieder Debug -> Debug Program auswählen, im Debugger die Adresse $080E markieren und Set PC im Kontextmenü wählen.

 

Schritt für Schritt
Schauen wir uns also schrittweise mal an, was unser Programm so macht. Euer PC sollte jetzt wieder bei $080E auf dem ersten Befehl lda #$FF stehen. Um jetzt den Befehl auszuführen, klickt einfach oben im Menü auf Debug -> Step Program oder auf das entsprechende Symbol in der Toolbar (bisher das 4. von links). Jetzt könnt ihr sehen, dass im PC die Adresse des nächsten Befehls ($0810) steht, im Akku (AC) jetzt  #$FF  steht und bei den Flags das Negativ-Flag auf eins gesetzt wurde, wie wir wissen entspricht  #$FF  ja -1. Soweit sieht alles gut aus, klickt noch 3x auf Step, bis im PC $0816 steht und beobachtet, was passiert. Wollt ihr nun wissen was in $FB / $FC steht, so könnt ihr wie beschrieben leider nicht einfach im Disassembler-Fenster zur Speicherstelle scrollen und nachschauen. Dort werdet ihr vermutlich nur $00 vorfinden. Klickt zunächst ins Disassembler-Fenster um eine evtl. vorhandene Markierung zu löschen. Klickt anschließend mit der rechten Maustaste in das Fenster und wählt Add Watch (gibt es auch oben im Menü bzw. auf der Toolleiste). Gebt im Dialog dann einfach FB ein und bestätigt mit OK, wiederholt das nochmal für FC. In der Watch List (unten in der Mitte) solltet ihr nun den Inhalt der Speicherstellen sehen. Auch dies ist korrekt, wir können unser Programm also weiter untersuchen.
Im PC sollte immer noch $0816 stehen. Führt den nächsten Schritt aus, wir wollten ja #$40 ins X-Register für unsere Schleife laden. Wie wir sehen hat sich das X-Register aber nicht verändert. Es steht immer noch $00 drin. Ein Blick auf den eben ausgeführten Befehl, bringt die Lösung. Wir haben den Inhalt der Speicherstelle $40 ins X-Register geladen. Also Debugger schließen, um im Source die Zeile 13 in  ldx #$40  zu ändern. Dann den Debugger direkt wieder starten und den PC auf $080E setzen. Lasst das Programm nun automatisch bis zur Adresse $0818 laufen. Markiert dazu diese z. B. per Doppelklick und wählt dann aus dem Kontextmenü (rechte Maustaste) ‚Run to adress‚ das Programm läuft und sollte stoppen, sobald der PC bei $0818 angekommen ist. Im X-Register seht ihr nun auch unsere #$40. An der aktuellen Adresse wollen wir unser Zeichen in den Akku laden. Wie ihr dem Source entnehmen könnt haben wir dazu die Zeichen ABC mit der BYTE-Anweisung im Speicher abgelegt. In der PETSCII-Tabelle könnt ihr sehen, dass diese Zeichen die Werte $01, $02 und $03 haben. Führen wir den Befehl aus und schauen was im AC landet. Mist, #$88 ist nicht korrekt. Schauen wir auf den Befehl, dann sehen wir von welcher Adresse der Wert geholt wird  lda $081D . Im Disassembler-Fenster entdecken wir an der Speicherstelle $081D aber den Befehl dey, den wir für die Schleife benötigen. Da dieser den OpCode #$88 hat, erklärt sich auch unser Akku-Inhalt. Etwas tiefer, ab der Adresse $0821, finden wir die von uns vorgegebenen Bytes. Also stoppen wir den Debugger und schauen wieder in den Source. In Zeile 20 finden wir unser Label  l11:  und direkt danach die erwartete BYTE-Anweisung mit den richtigen Zeichen, hier ist also alles korrekt.  Schaut auf den Befehl in Zeile 14, dieser lautet lda l1:+2 . Da rächt es sich, dass ich so tippfaul war! Ich habe die Label l1:  und l11:  nicht auseinander gehalten. Wir sollten also den Befehl in lda l11:+2  ändern. Noch besser wäre es natürlich deutlich unterscheidbare Label z. B. loop:  und zeichen:  zu verwenden.
Ich nehme es mal vorweg (ihr könnt es selbstverständlich überprüfen), aber das Programm funktioniert immer noch nicht!
Also ab in den Debugger, $080E in den PC und diesmal lassen wir es bis zur Adresse $081B durchlaufen. Im AC befindet sich endlich unser Zeichen ‚C‚, das ja $03 entspricht.
Als nächstes geben wir unser Zeichen an der auf der Zero-Page hinterlegten Adresse (ZP_COPYPOS) plus Y-Register aus. PLUS Y??? Verdammt, wir haben die Schleifenanzahl doch nach X geladen. Da wir auch dey  verwenden, ist oben also noch das X-Register falsch. Debugger stoppen und Zeile 13 in ldy #$40  ändern.

Startet ihr jetzt das Programm und schaut ganz genau hin, dann seht ihr, dass sich endlich mal etwas getan hat. In der zweiten Zeile wurde ein ‚C‚ ausgegeben. Bei der standard Startmeldung steht dort jetzt „BCSIC„ statt „BASIC„. Aber so ganz ist das immer noch nicht unsere gewünschte Anzeige.

 

Den letzten Fehler entfernen
Daher nochmal den Debugger starten, PC auf $080E setzen und bis $081D laufen lassen. Jetzt haben wir im Y-Register unsere Anzahl (#$40). Die Ausgabe sta ($FB),Y können wir hier leider nicht sehen, aber beim Probelauf von eben haben wir ja ein ‚C‚ in der zweiten Zeile an der 24. Stelle gesehen. Die #$40 aus dem Y-Register macht ja nichts anderes als ins 64. Zeichen in den BS-Speicher zuschreiben. Da eine Zeile 40 Zeichen hat, erklärt sich warum an der eben beschriebenen Stelle unser ‚C‚ steht. Soweit scheint das Programm also zu klappen. Führen wir nun im Einzelschritt den dey aus.
Der PC steht danach auf $081E und im Y-Register steht jetzt #$3F. Die Flags wurden nicht verändert. Als nächstes kommt unser bedingter Sprung. Wir testen mit beq  ob das Ergebnis gleich (sprich null) ist. Falls ja springen wir für die Schleife wieder nach oben, anderenfalls ist das Programm fertig und kehrt mit dem rts  zum BASIC zurück. Aktuell ist das Zero-Flag wie wir sehen können aber nicht gesetzt. Wir haben offensichtlich die falsche Bedingung genommen. Es müsste lauten, solange nicht null, also bne . Daher eine vorletzte Korrektur. Stoppt den Debugger und ändert den Sprung in Zeile 18 entsprechend.
Nach einem Start seht ihr im Emulator unsere Zeichen. Aber eigentlich ist dass immer noch nicht ganz korrekt. Laut Kommentar wollten wir 40 Zeichen ausgeben. Ändert als letztes noch die Zeile 13 in ldy #40 , damit wir eine einzige Zeile auf dem BS erhalten.

Wer möchte kann jetzt den Debugger nochmal starten und das Programm bis zur Adresse  $0820 laufen lassen (vergesst nicht zu Beginn den PC wieder auf $080E zu stellen). Es wird jetzt etwas dauern, ihr könnt sehen wie sich der PC ändert und YR laufend weniger wird. Sobald YR 0 erreicht, stoppt der Debugger und wir stehen auf dem rts . Diesen sollten wir im Debugger nicht ausführen, da es ja keinen Aufrufer gab. Ein Blick auf den Stack links unten zeigt, dass dieser leer ist. Im Gegensatz zum Emulator oder echten C64 (die sich evtl. aufhängen), passiert hier aber auch nichts Schlimmes, probiert es einfach mal aus.

Der Vorhang fällt
Hier konntet ihr nun sehen, wie man Fehler aufspüren kann. Natürlich werdet ihr in Kürze soweit sein, dass der eingebaute Debugger euch nicht mehr weiter hilft. Sobald ihr mit Interrupts anfangt steigt die Fehlergefahr erheblich an. Diese sind dann auch nicht mehr so einfach wie die obigen zu finden. Auch Logikfehler sind manchmal schwer aufzuspüren.

Um solchen Fehlern vorzubeugen und die Fehlersuche zu erleichtern, solltet ihr versuchen das Programm möglichst strukturiert und vernünftig kommentiert einzugeben. Gebt ihr die Programme auf einem PC ein, dann stellt dies kein Problem dar. Direkt auf dem C64 müsst ihr natürlich mit dem verfügbaren Speicher sparsam umgehen. Auch die Verwendung von Variablen und Labels ist hilfreich, allerdings sollten die Namen aussagekräftig und eindeutig sein. Ansonsten gilt auch hier, üben, üben, üben…


Damit schließe ich das Assembler Grundlagen Tutorial und hätte noch eine Bitte:

Eure Meinung ist mir sehr wichtig!
Es wäre daher schön, wenn ihr die anonyme Bewertungsmöglichkeit bzw. das ebenfalls anonym verwendbare Feedback (s. links) benutzt um mir zu helfen in Zukunft bessere Texte zu fabrizieren.
Bewertet die Beiträge oder teilt mir eure Meinungen und Wünsche in einem kleinen Text mit. Ein evtl. berechtigtes ‚Schrott!!‚ hilft dabei natürlich nicht soviel, wie ein kurzer Text, warum ihr das so empfindet.

Ich danke für euer Interesse und hoffe ihr schaut demnächst wieder vorbei.
Dann werden wir unsere Kenntnisse durch ein komplettes Programm in einem neuen Tutorial vertiefen.

Stay tuned


Schrott!!Naja...Geht so...Ganz gut...SUPER! (10 Bewertungen | Ø 4,70 von 5 | 94,00%)

Loading...


 

<<< zurück

 

weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Protected by WP Anti Spam