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

  1. die Anzeige löscht,
  2. die Kennung "dA" ins Operationsfeld der Anzeige schreibt und danach drei Bytes über die Tastatur einliest und im Adreß- und Datenfeld anzeigt,
  3. die Anzeige löscht,
  4. die Kennung "AA" ins Operationsfeld schreibt und eine (Anfangs-)Adresse einliest und im Adreßfeld darstellt,
  5. die Kennung "EA" ins Operationsfeld schreibt und eine (End-)Adresse einliest und im Adreßfeld darstellt,
  6. 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,
  7. werden die drei eingegebenen Bytes gefunden, wird im Operationsfeld die Kennung "F0" und im Adreßfeld die Adresse ihres Fundortes ausgegeben,
  8. 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.KennungEingabe SuchroutineAusgabe
A--- Eingabebyte1. Byte ---
B Kennungverändert verändertKennung
X AnzeigestelleAnzeigestelle aktuelle AdresseAnzeigestelle
Y  EingabeadresseEndadresse Adresse
S Stackzeiger, für Betriebssystem und UP "KENNUNG" nötig
U--- 2. und 3. Byte2. 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.OPCODELABEL MNEMON.BEMERKUNGEN
0400C6 DA LDB #$DA
0402BD 05 00 JSR KENNUNG "DA" IM OP.FELD
04058E 00 04 LDX #0004
0408BD F1 50 JSR SHOWDATAEINGABE 1.BYTE
040BB7 06 00 STA ERSTBYTE
040E8E 00 02 LDX #0002
0411BD F1 50 JSR SHOWDATAEINGABE 2.BYTE
0414B7 06 01 STA ZWEITBYTE
04178E 00 00 LDX #0000
041ABD F1 50 JSR SHOWDATAEINGABE 3.BYTE
041DB7 06 02 STA DRITTBYTE
0420FE 06 01 LDU ZWEITBYTEU := 2.+3.Byte
0423C6 AA LDB #$AA
0425 BD 05 00JSR KENNNUNG "AA" IM OP.FELD
04288E 00 02 LDX #0002
042BBD F1 56 JSR SHOWADREINGABE ANF.ADR.
042E10 BF 06 03 STY ANFADR
0432C6 EA LDB #$EA
0434BD 05 00 JSR KENNNUNG "EA" IM OP.FELD
04378E 00 02 LDX #0002
043ABD F1 56 JSR SHOWADREINGABE ENDADR
043D1F 20TFR Y,D D := ENDADR.
043F83 00 02 SUBD #$0002LETZTADR :=
0442FD 06 05 STD LETZTADRENDADR - 2
0445BE 06 03 LDX ANFADR
0448B6 06 00 LDA ERSTBYTE
044BA1 84VERGLCH: CMPA ,XA = (X) ?
044D26 11 BNE COMPADR
044F11 A3 01 CMPU 1,XU = (X+1) ?
045226 0C BNE COMPADR
04541F 12TRF X,Y Y := AKT.ADR.
0456C6 F0LDB #$F0 KENNUNG := "F0"
045820 16 BRA ERGEBNIS
04605FCOMPADR: CLRBKENNUNG := "00"
0461BC 06 05 CMPX LETZTADRAKT.ADR.=
046427 0A BEQ ERGEBNISLETZTADR ?
0466E6 80 LDB ,X+X := X + 1
046820 E7 BRA VERGLCH
0470BD 05 00ERGEBNIS: JSR KENNUNG "F0" ODER "00"
04731F 20TFR Y,D AKT.ADR BZW.
04758E 00 02 LDX #$0002ENDADRESSE
0478BD F1 23 JSR SHOWD7SGANZEIGEN
047B20 FEENDE: BRA ENDE
0500BD F1 10 KENNUNG:JSR CLRDISP
05038E 00 06 LDX #$0006AUF STELLE 6 U. 7
0506BD F1 20 JSR SHOWB7SGB ANZEIGEN
050939RTS

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