| 1.3 Der Mikroprozessor 6809 |  | A: relative Adressierungsarten, Postbyte |

1.4/1

## 1.4 Anleitung zur Lösung der Übungsaufgaben

In diesem Abschnitt wollen wir Ihnen anhand einer Beispielaufgabe 1) aufzeigen, wie Sie die Lösung der Übungsaufgaben systematisch und erfolgversprechend durchführen können. Die folgende Musterlösung zeigt Ihnen dazu die einzelnen Schritte einer Problemlösung auf. Die Aufgabe lautet:

Aufgabe: Schreiben Sie ein Programm, das der Reihe nach die Anzeige löscht, die Kennung "dA" ins Operationsfeld der Anzeige schreibt und danach drei Bytes über die Tastatur einliest und im Adreß- und Datenfeld anzeigt, die Anzeige löscht, die Kennung "AA" ins Operationsfeld schreibt und eine (Anfangs-)Adresse einliest und im Adreßfeld darstellt, die Kennung "EA" ins Operationsfeld schreibt und eine (End-)Adresse einliest und im Adreßfeld darstellt, den durch die Anfangs- und Endadresse angegebenen Adreßbereich im Speicher nach dem Auftreten von drei direkt hintereinander folgenden Bytes durchsucht, die die mit den unter 2. angegebenen übereinstimmen; dabei muß auch die Reihen-folge dieselbe sein, werden die drei eingegebenen Bytes gefunden, wird im Operationsfeld die Kennung "F0" und im Adreßfeld die Adresse ihres Fundortes ausgegeben, werden die Bytes nicht gefunden, wird die Kennung "00" im Operationsfeld und die Endadresse (siehe 5.) im Adreßfeld angezeigt.

1.4/2

Lösung:

Das Flußdiagramm in Bild 1.4-1 stellt den Aufgabentext ohne Verfeinerungen dar. Lediglich die Adreßausgaben von Punkt 7. und 8. wurden zusammengeführt. Die Aufgabenstellung dieses ersten Diagramms ohne inhaltliche Änderung empfiehlt sich, weil die Darstellung übersichtlicher als der Text ist. Dadurch werden Mißverständnisse geklärt bzw. vermieden und ähnliche oder gleiche Funktionsblöcke sind leichter erkennbar. In diesem Fall kommt der Ablauf "Anzeige löschen, Kennung 'XX' ins Operationsfeld schreiben " fünfmal vor. Die Programmlänge und damit die Schreib- und "Eintipp"-Arbeit läßt sich wesentlich verringern, wenn dieser Ablauf als Unterprogramm geschrieben wird, das an den entsprechenden Stellen im Hauptprogramm aufgerufen wird. Die Kennung muß als Parameter übergeben werden, am einfachsten in einem CPU-Register.

Bild 1.4-1: | Grobes Flußdiagramm nach Aufgabentext |

Bei der folgenden Verfeinerung des Programmablaufs ist zu beachten, welche Aufgaben von schon vorhandenen Hilfsroutinen ( siehe Abschnitt 1.2.2) übernommen werden können: "Anzeige löschen " entspricht "CLRDISP", "Kennung 'X' ins Operationsfeld schreiben " wird von "SHOWB7SG" geleistet, wenn 'XX' in B steht und das X-Register den Wert $0006 enthält. Beim Aufruf des oben erwähnten Unterprogramms sollte die Kennung also gleich im B-Register übergeben werden. Eingabe und Anzeige eines bzw. zweier Bytes wird von "SHOWDATA" bzw. "SHOWADR" ausgeführt. Die Anzeige der aktuellen Adresse wird mit "SHOWD7SG" gelöst.
Ohne Hilfsroutinen muß nur die Aufgabe "Adreßbereich durchsuchen " gelöst werden. Hierzu legen wir zunächst ein allgemeines Flußdiagramm an (s. Bild 1.4-2 ).

1.4/3

Die Entscheidung "Gefunden? " liegt außerhalb der Suchroutine, da dies zunächst übersichtlicher ist. Selbstverständlich muß schon während des Suchens entschieden werden, ob die Bytefolge gefunden wurde. An diese Entscheidung wird nun direkt angeknüpft und in Abhängigkeit vom Ergebnis die Kennung auf "F0" oder "00" gesetzt. Da die aktuelle Adresse nicht gleich der Endadresse ist, wenn die Suche erfolglos abgebrochen wird, muß in diesem Fall noch die aktuelle Adresse auf den Wert der Endadresse gesetzt werden, damit bei der abschließenden Adreßausgabe immer die aktuelle Adresse ausgegeben werden kann (s. Punkt 8. der Aufgabenstellung).

Bild 1.4-2: | Verfeinerung der Suchroutine |

Bevor wir die Diagramme unter Berücksichtigung der CPU-Architektur verfeinern, müssen wir entscheiden, wie die Variablen abgelegt und die CPU-Register benutzt werden:

Da Vergleiche nur zwischen Registerinhalt und Speicherinhalt stattfinden können, sollten die drei zu suchenden Bytes in Registern gehalten werden, z.B. in A und U. Die aktuelle Adresse kann im X-Register stehen. Die Endadresse-2 muß für den Vergleich im Speicher stehen. Die Endadresse kann im Y-Register abgelegt werden. PC, DP und S werden für den Programmablauf gebraucht. B steht zur freien Verfügung bereit. Die Anfangsadresse muß im Speicher abgelegt werden, weil in der CPU kein 16-bit-Register frei ist.
Wenn wir das Flußdiagramm in Bild 1.4-2 an diese Festlegungen anpassen, erhalten wir das Flußdiagramm in Bild 1.4-3. Ein zusätzlicher Unterschied zu Bild 1.4-2 besteht in der Übergabe der Fundortadresse: Das X-Register wird vom Unterpro-gramm KENNUNG verwendet, das Y-Register wird dagegen nicht benötigt. Deshalb wird die auszugebende Adresse im Y-Register an das Hauptprogramm übergeben. Im rechten Zweig des Flußdiagramms in Bild 1.4-3 wird das Y-Register nicht modifiziert, da es die Endadresse enthält. Im linken Zweig wird die Endadresse in Y mit der aktuellen Adresse überschrieben.

1.4/4

Bild 1.4-3: | Suchroutine, an Prozessorarchitektur angepaßt |

Für das Unterprogramm "KENNUNG" erhalten wir:

    	CLRDISP aufrufen
    	X := #$0006
    	SHOWB7SG aufrufen
    	Rückkehr zum Hauptprogramm

Beachten Sie, daß in diesem Unterprogramm keine Registerinhalte auf den Stack "gerettet" werden. Zumindest der Inhalt des X-Registers wird innerhalb des Unterprogramms verändert. In unserem kleinen Musterprogramm ergeben sich daraus keine Probleme. In komplexeren Progammen ist es jedoch ratsam, zu Beginn jedes Unterprogramms alle Registerinhalte, die im Verlauf der Unterroutine verändert werden, auf dem Stack abzulegen und vor der Rückkehr zum aufrufenden Programm wieder in die Register zu holen.
Das Hauptprogramm enthält nun keine Verzweigungen mehr. Wir verzichten daher auf ein Flußdiagramm. Die Bezeichner "ERSTBYTE", "ZWEITBYTE", "DRITTBYTE", "ANFADR" und "LETZTADR" entsprechen je einer bzw. zwei konsekutiven Speicheradressen. Nach Anpassung an die Prozessorarchitektur erhalten wir:

1.4/5

B := "DA" | ( * Kennung *)
KENNUNG aufrufen |
X := #$0004 |
SHOWDATA aufrufen | ( * erstes Byte lesen * )
(ERSTBYTE) := A |
X := #$0002 |
SHOWDATA aufrufen | ( *zweites Byte lesen * )
(ZWEITBYTE) :=A |
X := #$0000 |
SHOWDATA aufrufen | ( *drittes Byte lesen * )
(DRITTBYTE ) := A |
U:= (ZWEITBYTE) und(DRITTBYTE) |
B := "AA" | ( * Kennung * )
KENNUNG aufrufen |
X := #$0002 |
SHOWADR aufrufen | ( * Anfangsadresse lesen * )
(ANFADR) := Y |
B := "EA" | ( * Kennung * )
KENNUNG aufrufen |
X := #$0002 |
SHOWADR aufrufen | ( * Endadresse lesen * )
D := Y |
D:= D-2 |
(LETZTADR) := D | ( * LETZTADR := Endadresse -2 *)
A := (ERSTBYTE) |
SUCHE |
KENNUNG aufrufen | ( * "F0" oder "00"ausgeben * )
D := Y |
X := #$0002 |
SHOWD7SG aufrufen | ( * Fund- oder Endadresse ausgeben * )
Endlosschleife |

Zur Kontrolle sollte man sich noch eine Tabelle (s. Tabelle 1.4-1) anlegen, in der die Verwendung der CPU-Register gelistet ist. Man kann mit Hilfe der Tabelle unbeabsichtigte Mehrfachbenutzungen erkennen.
Der nächste Schritt ist nun die Übertragung der einzelnen Operationen in Assemblercode. Hierbei dürfte es im allgemeinen keine Schwierigkeiten geben, da die Abbildung fast überall "isomorph" ist, wenn die Vefeinerung ausführlich genug war. Statt numerischer Sprungadressen werden Marken (Labels) verwendet und die Variablennamen für Speicherplätze werden zunächst beibehalten. Das einzige Problem stellt in unserem Beispiel die Anweisung "X := X + 1" dar. Der INC-Befehl ist nur auf die Register A und B und den Speicher anwendbar. Das X-Register muß daher z.B. mit der Anweisung "LDB ,X+" inkrementiert werden.

1.4/6

Tabelle 1.4-1: Registerbelegungen

Reg. | Kennung | Eingabe | Suchroutine | Ausgabe
--- | --- | --- | --- | ---
A | --- | Eingabebyte | 1. Byte | ---
B | Kennung | verändert | verändert | Kennung
X | Anzeigestelle | Anzeigestelle | aktuelle Adresse | Anzeigestelle
Y |  | Eingabeadresse | Endadresse | Adresse
S | Stackzeiger, für Betriebssystem und UP "KENNUNG" nötig
U | --- | 2. und 3. Byte | 2. und 3. Byte | ---
DP | für Betriebssystemroutinen unverändert gelassen

Abschließend werden die mnemonischen Assembleranweisungen in Maschinencode übersetzt und gleichzeitig die dadurch belegten Speicheradressen hingeschrieben. Für die "Übersetzung" eines Assemblerbefehls in den Maschinencode müssen Sie zunächst in den Tabellen des Anhangs B die Zeile suchen, die durch den Mnemocode des Assemblerbefehls bezeichnet ist. Danach entnehmen Sie den gesuchten OpCode der Spalte, die durch die gewünschte Adressierungsart gekennzeichnet ist. Hier finden Sie auch die Gesamtzahl der Bytes, die der Befehl umfaßt. Es empfiehlt sich, Programmblöcke, die nur über Programmverzweigungen oder Unterprogrammaufrufe erreichbar sind, nicht direkt an das übrige Programm anschließen zu lassen, sondern einige Bytes Freiraum zu schaffen. Auf diese Weise müssen Sie nicht das gesamte Programm verschieben und eventuell viele Sprungadressen ändern, wenn Sie nachträglich einige Programmbytes einfügen 2) .
Für Variablennamen, die Speicherzellen bezeichnen, werden jetzt die Speicheradressen eingesetzt. Wenn alle Labeladressen bekannt sind, können Sie die Sprungziele der absoluten Sprünge einsetzen und die Sprungweiten der relativen Sprünge berechnen. Beachten Sie, daß die Sprungweite "0" keinem Sprung entspricht, d.h. es wird die Anweisung nach dem Sprungbefehl abgearbeitet.

1.4/7

ADR. | OPCODE | LABEL | MNEMON. | BEMERKUNGEN
--- | --- | --- | --- | ---
0400 | C6 DA |  | LDB #$DA |
0402 | BD 05 00 |  | JSR KENNUNG | "DA" IM OP.FELD
0405 | 8E 00 04 |  | LDX #0004 |
0408 | BD F1 50 |  | JSR SHOWDATA | EINGABE 1.BYTE
040B | B7 06 00 |  | STA ERSTBYTE |
040E | 8E 00 02 |  | LDX #0002 |
0411 | BD F1 50 |  | JSR SHOWDATA | EINGABE 2.BYTE
0414 | B7 06 01 |  | STA ZWEITBYTE |
0417 | 8E 00 00 |  | LDX #0000 |
041A | BD F1 50 |  | JSR SHOWDATA | EINGABE 3.BYTE
041D | B7 06 02 |  | STA DRITTBYTE |
0420 | FE 06 01 |  | LDU ZWEITBYTE | U := 2.+3.Byte
0423 | C6 AA |  | LDB #$AA |
0425 | BD 05 00 |  | JSR KENNNUNG | "AA" IM OP.FELD
0428 | 8E 00 02 |  | LDX #0002 |
042B | BD F1 56 |  | JSR SHOWADR | EINGABE ANF.ADR.
042E | 10 BF 06 03 |  | STY ANFADR |
0432 | C6 EA |  | LDB #$EA |
0434 | BD 05 00 |  | JSR KENNNUNG | "EA" IM OP.FELD
0437 | 8E 00 02 |  | LDX #0002 |
043A | BD F1 56 |  | JSR SHOWADR | EINGABE ENDADR
043D | 1F 20 |  | TFR Y,D | D := ENDADR.
043F | 83 00 02 |  | SUBD #$0002 | LETZTADR :=
0442 | FD 06 05 |  | STD LETZTADR | ENDADR - 2
0445 | BE 06 03 |  | LDX ANFADR |
0448 | B6 06 00 |  | LDA ERSTBYTE |
044B | A1 84 | VERGLCH: | CMPA ,X | A = (X) ?
044D | 26 11 |  | BNE COMPADR |
044F | 11 A3 01 |  | CMPU 1,X | U = (X+1) ?
0452 | 26 0C |  | BNE COMPADR |
0454 | 1F 12 |  | TRF X,Y | Y := AKT.ADR.
0456 | C6 F0 |  | LDB #$F0 | KENNUNG := "F0"
0458 | 20 16 |  | BRA ERGEBNIS |
0460 | 5F | COMPADR: | CLRB | KENNUNG := "00"
0461 | BC 06 05 |  | CMPX LETZTADR | AKT.ADR.=
0464 | 27 0A |  | BEQ ERGEBNIS | LETZTADR ?
0466 | E6 80 |  | LDB ,X+ | X := X + 1
0468 | 20 E7 |  | BRA VERGLCH |
0470 | BD 05 00 | ERGEBNIS: | JSR KENNUNG | "F0" ODER "00"
0473 | 1F 20 |  | TFR Y,D | AKT.ADR BZW.
0475 | 8E 00 02 |  | LDX #$0002 | ENDADRESSE
0478 | BD F1 23 |  | JSR SHOWD7SG | ANZEIGEN
047B | 20 FE | ENDE: | BRA ENDE |
0500 | BD F1 10 | KENNUNG: | JSR CLRDISP |
0503 | 8E 00 06 |  | LDX #$0006 | AUF STELLE 6 U. 7
0506 | BD F1 20 |  | JSR SHOWB7SG | B ANZEIGEN
0509 | 39 |  | RTS |

1.4/8

    Variablennamen:
    	ERSTBYTE  = $0600
    	ZWEITBYTE = $0601
    	DRITTBYTE = $0602
    	ANFADR    = $0603
    	LETZTADR  = $0605

Der oben beschriebene Lösungsweg erscheint vielleicht etwas aufwendig. Wenn er auch in dieser oder ähnlicher Form immer beschritten wird, so werden häufig nicht alle Zwischenschritte zu Papier gebracht. Ihre Übungsaufgaben brauchen auch nicht alle Zwischenergebnisse zu enthalten, sondern könnten sich in diesem Fall auf die Flußdiagrammme der Bilder 1.4-1 und 1.4-2 und das kommentierte Assembler- und Maschinenprogramm beschränken. Wir empfehlen Ihnen aber (vor allem, wenn Sie keine Erfahrung mit Maschinenprogrammierung besitzen ), alle hier beschriebenen Schritte explizit abzuarbeiten. Sie strukturieren Ihre Programme dadurch automatisch und die Problemlösung und Fehlersuche gestaltet sich für Sie leichter.

Praktische Übung 1.4-1:
Geben Sie das obenstehende Programm in den Praktikumsrechner ein und führen Sie es mit verschiedenen zu suchenden Bytefolgen aus. Machen Sie sich anhand dieses Programms mit den Testmöglichkeiten (debugging) des Monitorprogramms quot;Einzelschrittausführung" (Taste T) und "Setzen eines Breakpoints" (Tasten G, +) vertraut. Nutzen Sie diese Möglichkeiten insbesondere zur Überprüfung der relativen Verzweigungsbefehle.

| 1.3 Der Mikroprozessor 6809 |  | A: relative Adressierungsarten, Postbyte |