Programmierungstechniken: Assemblerprogrammierung, Struktogramm und Flußdiagramm

Assemblerprogrammierung

Struktogramm und Flußdiagramm

Algorithmus und Programm. Eine Verarbeitungsvorschrift, nach der Eingabedaten über Zwischenergebnisse in Ausgabedaten umgewandelt werden, bezeichnet man als Algorithmus. Die dem Mikroprozessor angepaßte Beschreibung eines Algorithmus ist das Programm. Liegt das Programm in Maschinencode vor, so kann es vom Mikroprozessor unmittelbar interpretiert werden; liegt es in symbolischer Form vor, z.B. als Assemblerprogramm oder in einer höheren Programmiersprache, so muß es in einem vorbereitenden Arbeitsgang erst in den Maschinencode umgeformt werden. Dazu ist ein Übersetzungsprogramm (Assembler bzw. Compiler) notwendig.

Zur Erleichterung der Programmerstellung wird der Algorithmus zunächst in einer prozessorunabhängigen und für den Menschen besser verständlichen und überschaubaren Form beschrieben. Dies ist vor allem bei der Programmierung auf einer relativ niedrigen Sprachebene, wie der Assemblerebene, nützlich und bei umfangreichen Aufgabenstellungen unabdingbar. Die Beschreibung kann entweder sprachlich orientiert erfolgen, durch Texte der Umgangssprache (vgl. Knuth [13]) oder in einer höheren Programmiersprache (z.B. PASCAL); oder sie kann grafisch orientiert erfolgen, durch Struktogramme (vgl. Nassi und Shneiderman [14]) oder durch Programmablaufpläne (z.B. nach DIN 66001 l15]). Programmablaufpläne werden auch als Flußdiagramme bezeichnet.

Struktogramm. Struktogramme sind an die Beschreibungselemente höherer Programmiersprachen, insbesondere an deren Kontrollstrukturen zur Programmsteuerung angelehnt. Die Beschreibungsebene ist damit höher als die der Assemblersprache und eignet sich zur komprimierten Darstellung komplexer Abläufe. Struktogramme unterstützen darüber hinaus eine strukturierte Problembeschreibung und erleichtern das Schreiben entsprechend strukturierter Programme [16].

Beispiel 3.1. Algorithmus in StruktogrammdarsteUung. Es sollen die natürlichen Zahlen 1 bis N summiert werden. Der Wert N soll als Eingabedatum eingelesen und das Ergebnis SUMME als Ausgabedatum ausgegeben werden.

Programmierungstechniken: Assemblerprogrammierung, Struktogramm und Flußdiagramm

Bild 3.1. Struktogrammdarstellungen

Die beiden Darstellungen in Bild 3.1 unterscheiden sich durch eine umgangssprachliche und eine programmiersprachliche Beschriftung. Die Ablauffolge ist durch aufeinanderfolgende Blöcke und durch die Reihenfolge der Operationen innerhalb der Blöcke beschrieben. Als Beispiel einer Kontrollstruktur wurde die while-Schleife verwendet. Solange die Schleifenbedingung I ~ N erfüllt ist, werden die als geschachtelter Block angegebenen Operationen SUMME: = SUMME + I und I: = 1+ 1 wiederholt ausgeführt. •

Flußdiagramm. Verglichen mit den Struktogrammen sind Flußdiagramme mehr an die Programmdarstellung auf Assemblerebene angelehnt. Kontrollstrukturen, wie Z.B. die while-Schleife, erscheinen in aufgelöster Form. Flußdiagramme spiegeln dadurch den tatsächlichen Programm fluß mit allen seinen Verzweigungen wider.

Flußdiagramme werden durch geometrische Sinnbilder dargestellt, die durch Ablauflinien oder -pfeile miteinander verbunden und wie Struktogramme beschriftet werden. Mit ihnen läßt sich das in Beispiel 3.1 behandelte Problem entsprechend Bild 3.2a darstellen. Die while-Schleife aus Beispiel 3.1 wird dabei durch Hochzählen einer Zählvariablen, Abfrage einer Bedingung und durch die Rückführung des Programmflusses bei erfüllter Bedingung gebildet.

Unmittelbar aufeinanderfolgende Schritte können in einem Sinnbild zusammengefaßt werden (Bild 3.2b). Sie werden von oben nach unten gelesen, unabhängig von der Richtung der Ablaufpfeile, d.h. die Bilder 3.2b und 3.2c sagen das gleiche aus. Bild 3.2d zeigt eine andere Darstellung der Bedingungsabfrage, wie sie zur Beschreibung von Dreiwegverzweigungen benutzt wird.

Programmierungstechniken: Assemblerprogrammierung, Struktogramm und FlußdiagrammBild 3.2. Flußdiagrammdarstellung

In der Beschriftung der Sinnbilder bedeutet das Zuweisungssymbol : = die Zuweisung des Wertes des auf der rechten Seite stehenden Ausdrucks an die auf der linken Seite stehende Variable, z.B. I: = 1. Die Variable auf der linken Seite kann auch im Ausdruck auf der rechten Seite auftreten; so wird z.B. bei I: = I + 1 der bisherige Wert von I (rechte Seite) um 1 erhöht und das Ergebnis wiederum I (linke Seite) zugewiesen. Entspricht I einer symbolische Adresse, so wird der Inhalt des durch sie adressierten Speicherplatzes um Eins erhöht.

Das Gleichheitszeichen = beschreibt hingegen die Gleichheit zweier Größen und wird in diesem Buch nicht zur Wertzuweisung benutzt. Es wird zusammen mit den Zeichen> (größer), < (kleiner) und =1= (ungleich) zur Formulierung von Bedingungen verwendet, z.B. wenn I~N, dann … , sonst.. ..

In Kapitel 1 wurde eine einfache Assemblersprache eingeführt, die auf den dort beschriebenen einfachen Prozessor zugeschnitten ist. Wir wollen diese Sprache erweitern, indem wir zum einen die in Kapitel 2 beschriebenen Prozessorfunktionen berücksichtigen; ein erster Schritt in dieser Richtung wurde bereits in Abschnitt 2.1 mit der Einführung der Adressierungsarten des Prozessors gemacht (dynamische Adreßrechnung). Zum anderen werden wir Funktionen in die Sprache aufnehmen, die das Programmieren erleichtern. Dabei werden dem Assembler zusätzliche Aufgaben übertragen, z.B. die Adreßrechnung zur Übersetzungszeit (statische Adreßrechnung).

Format einer Programmzeile. Das Format einer Programmzeile mit Namens-, Operations-, Adreß- und Kommentarfeld behalten wir bei. Im Namensfeld können Symbole (Namen) und im Operationsfeld die Befehlsmnemone aus Abschnitt 2.2 sowie die Mnemone der nachfolgend beschriebenen Assembleranweisungen verwendet werden. Im Adreßfeld sind Konstanten, Symbole und arithmetische Ausdrücke zugelassen. Kommentare müssen vom Adreßfeld durch mindestens ein Leerzeichen getrennt oder durch das Asterisk-Zeichen * in der Spalte Null gekennzeichnet sein.

Konstanten. Eine Konstante für den Assembler ist ein zur Übersetzungszeit fester Wert, der als ganze Zahl in dezimaler, hexadezimaler oder binärer Form oder als ASCII-Zeichenfolge angegeben wird. Dezimalkonstanten werden ohne besondere Kennzeichnung, Hexadezimalkonstanten durch ein vorangestelltes $Zeichen und Binärkonstanten durch ein vorangestelltes %-Zeichen dargestellt, Z.B.
dezimal: 1234, +527, -12
hexadezimal: $04, $FF03
binär: %00000100, % 1111000010100101.

Ein oder mehrere ASCII-Zeichen, die durch Hochkommas eingeschlossen sind, bilden eine ASCII-Zeichenfolge. Ein Hochkomma als Teil der Zeichenfolge wird durch zwei aufeinanderfolgende Hochkommas dargestellt, z.B.
‚TEXT‘ bzw. ‚IT“S ALL RIGHT‘.

Die Darstellung nicht druckbarer ASCII-Zeichen (z.B. Steuerzeichen) erfolgt in hexadezimaler Schreibweise, Z.B. $OA als Steuerzeichen für den Zeilenvorschub.

Symbole. Wir legen fest, daß Symbole maximal sechs Buchstaben oder Ziffern umfassen dürfen, wobei das erste Zeichen ein Buchstabe sein muß. Ein Symbol ist ein relatives Symbol, wenn sich sein Wert auf den Anfang eines verschiebbaren Programmblocks bezieht. Es ist ein absolutes Symbol, wenn sein Wert fest ist. Die Wertzuweisung erfolgt entweder in Abhängigkeit von den Assembleranweisungen RORG und AORG oder unmittelbar durch die Anweisungen EQU und SET. Die Art eines Symbols ist bei der Bildung von Ausdrücken zu beachten.

Das Asterisk-Zeichen * wird – neben seiner Funktion als Kennzeichen für eine Kommentarzeile – als Symbol zur Bezeichnung des Befehlszählers bei der relativen Adressierung benutzt. Es erhält als Wert jeweils die Adresse des ersten Befehlswortes des Befehls, in dessen Adreßteil es verwendet wird; diese Adresse und damit das Symbol können absolut oder relativ sein. Die Symbole RO bis R 7 und SPR sind als Registersymbole festgelegt; SPR (stack pointer register) kann wahlweise anstelle des Symbols R 7 verwendet werden. Das Befehlszählersymbol * und die Registersymbole können nur im Adreßfeld stehen.

Ausdrücke. Ausdrücke werden aus Konstanten und Symbolen gebildet, die durch die arithmetischen Operatoren +, -, . und / miteinander verknüpft werden. Wie die Symbole können sie bezüglich ihrer Werte absolut oder relativ sein. Bild 3.3 zeigt in einer schematischen Darstellung, welche Möglichkeiten zur Bildung von Ausdrücken erlaubt sind.

Programmierungstechniken: Assemblerprogrammierung, Struktogramm und Flußdiagramm

Programmierungstechniken: Assemblerprogrammierung, Struktogramm und Flußdiagramm

Bild 3.3. Bildung von absoluten und relativen Ausdrücken

Der Wert eines Ausdrucks wird vom Assembler zur Übersetzungszeit ermittelt (statische Adreßrechnung), wobei die Operatoren‘ und / gegenüber den Operatoren + und – Vorrang haben. Gleichrangige Operatoren werden von links nach rechts abgearbeitet. Das Ergebnis wird als ganze Zahl dargestellt, d.h. bei der Division wird der Rest nicht berücksichtigt. Die Division durch Null gilt als nicht definiert.

Ausdrücke sind eine allgemeine Form der Darstellung numerischer und symbolischer Adreß- und Operanden angaben unter Einbeziehung der Adressierungsarten direkt (DA), Direktoperand (IM), relativ (RA) und indiziert (X). Sie werden außerdem zur Definition von Programmkonstanten in den DC-Assembleranweisungen verwendet. Tabelle 3.1 zeigt zusammengefaßt die in Abschnitt 2.1.4 beschriebenen Adressierungsarten des Prozessors (dynamische Adreßrechnung) im Zusammenhang mit der Verwendung von Konstanten, Symbolen und Ausdrükken.

Programmierungstechniken: Assemblerprogrammierung, Struktogramm und Flußdiagramm

Tabelle 3.1. Adressierungsarten

Einige Beispiele sollen die Möglichkeiten der Adreß- und Operandendarstellung durch Ausdrücke zeigen und die Wirkung der Adressierungsarten illustrieren.

Üblicherweise lassen Assembler außer arithmetischen Ausdrücken auch logische Ausdrucke zu; hierzu sei auf die Assemblerbeschreibungen der Mikroprozessorhersteller verwiesen.
MOVE Rl,FELD+2 lädt Rl mit dem auf FELD folgenden Speicherwort (direkte Adressierung); der Wert von FELD muß geradzahlig sein.

MOVEB Rl,M+2’3 lädt Rl mit dem sechsten auf M folgenden Speicherbyte (direkte Adressierung),

MOVE Rl,#N +5/2 lädt Rl mit dem um 5/2=2 erhöhten Wert von N (Direktoperand-Adressierung).

MOVE Rl,*+6 lädt Rl mit dem dritten auf den MOVE-Befehl folgenden Speicherwort (relative Adressierung).

JMP *-2 lädt den Befehlszähler mit der Adresse des vor dem JMP-Befehl stehenden Speicherwortes (relative Adressierung).

MOVE Rl,A+4(R2) lädt Rl mit dem Speicherwort, dessen Adresse der um 4 erhöhte Wert von A plus dem Inhalt des Registers R2 ist (indizierte Adressierung).

.Programmierungstechniken: Assemblerprogrammierung, Struktogramm und Flußdiagramm

Assembleranweisungen

Im folgenden wird der in Abschnitt 1.3.2 definierte, auf den vereinfachten Prozessor aus Kapitel 1 zugeschnittene Satz von Assembleranweisungen an die in Kapitel 2 eingeführte Prozessorstruktur angepaßt und um einige Anweisungen erweitert. Die in eckigen Klammern stehenden Angaben sind wahlweise, d.h. sie können eingesetzt oder weggelassen werden.

NAME Symbol ordne Programmname zu

NAME steht als erste Anweisung eines Programms und ordnet ihm ein Symbol als Programmname zu. Der Programmname kann von der Systemsoftware als Programmidentifikator zur Verwaltung von Programmbibliotheken benutzt werden.

END beende Assemblierphase

END zeigt dem Assembler die letzte zu übersetzende Quellcodezeile an. Nachfolgender Quellcode wird nicht übersetzt.

AORG Ausdruck beginne einen festen Programmoder Datenblock

AORG (absolute origin) bezeichnet den Anfang eines festen, im Speicher nicht verschiebbaren Programm- oder Datenblocks und lädt den Zuordnungszähler mit dem Wert des Ausdrucks. Dem nachfolgend erzeugten Maschinencode werden absolute Adressen, beginnend mit diesem Wert, zugewiesen. Der Ausdruck muß definiert sein, d.h. er darf keine V orwärtsadreßbezüge und keine undefinierten externen Adreßbezüge (Adreßsymbole, die in REF·Anweisungen stehen) enthalten. Ein mit AORG beginnender Programm- oder Datenblock endet mit der nächsten AORG-, RORG- oder END-Anweisung.Programmierungstechniken: Assemblerprogrammierung, Struktogramm und Flußdiagramm

RORG Symbol,[PCR] beginne einen verschiebbaren Programm- oder Datenblock

RORG (relative origin) bezeichnet den Anfang eines verschiebbaren Programmoder Datenblocks und weist ihm ein Symbol als Name zu. Tritt ein Name in einer RORG-Anweisung erstmals auf, so wird der Zuordnungszähler mit dem Wert Null geladen. Tritt ein Name wiederholt auf, so wird der Zuordnungszähler mit dem zuletzt unter diesem Namen erreichten Zuordnungszählerstand geladen. Dem nachfolgend erzeugten Maschinencode werden relative Adressen, beginnend mit dem Wert des Zuordnungszählers, zugewiesen.

Der Block endet mit der nächsten AORG-, RORG- oder END-Anweisung. Wenn der Block im Speicher verschoben werden soll, müssen die im Maschinencode stehenden relativen Adressen vor der Programmausführung, Z.B. durch einen verschiebenden Lader, um die Ladeadresse erhöht werden. Man bezeichnet einen solchen Block als statisch verschiebbar.

Die Option PCR (program counter relative) veranlaßt den Assembler, die direkte und die indizierte Adressierung in den Maschinenbefehlen durch die relative Adressierung bzw. die relative Adressierung mit Indizierung zu ersetzen, sofern die Adreßangaben innerhalb des Blocks oder in einem anderen RORGBlock gleichen Namens als relative Adressen definiert sind. Die Anpassung der Adreßbezüge an eine Programmverschiebung im Speicher erfolgt somit während der Programmausführung durch die befehlszählerrelative Adressierung. Man bezeichnet einen solchen Block als dynamisch verschiebbar (s. dazu auch Abschnitt 3.1.4).

Symbol EQU Ausdruck setze gleich

EQU (equate) setzt das Symbol im Namensfeld gleich dem Wert des Ausdrucks im Adreßfeld. Die Wertzuweisung kann durch nachfolgende EQU- oder SETAnweisungen nicht mehr verändert werden. Im Ausdruck auftretende Symbole müssen vor der EQU-Anweisung definiert sein.

Symbol SET Ausdruck welse zu

SET weist dem Symbol im Namensfeld den Wert des Ausdrucks im Adreßfeld zu. Im Gegensatz zu EQU kann das Symbol durch nachfolgende SET-Anweisungen neu definiert werden, wobei das bereits definierte Symbol wiederum im Ausdruck verwendet werden darf.

[Symbol] DCB Operand(en) definiere Bytekonstante(n)
[Symbol] DCW Operand(en) definiere Wortkonstante(n)
[Symbol] DCD Operand(en) definiere Doppelwortkonstante(n)

Mit den DC-Anweisungen (define constant) werden im Speicher Konstanten im Byte-, Wort- und Doppelwortformat erzeugt. Sie werden durch einen oder mehrere durch Kommas getrennte Operanden im Adreßfeld angegeben. Konstanten sind in hexadezimaler, dezimaler und binärer Darstellung sowie im ASCII-Format zugelassen; außerdem dürfen Symbole und Ausdrücke benutzt werden.

Mit DCB werden Byteoperanden, beginnend mit dem höherwertigen Byte (Byte 0) des nächsten freien Speicherwortes, erzeugt. Eine unmittelbar darauf folgende DCB-Anweisung setzt die Speicherbelegung mit dem ersten freien Byte fort. Die DCW-Anweisung erzeugt Wortoperanden ab der ersten freien Speicherzelle. Ist im vorangehenden Wort nur das höherwertige Byte belegt, so wird das niedrigerwertige Byte zusätzlich als Null definiert.

Entsprechendes gilt auch für die Erzeugung von Doppelwortoperanden durch die DCD-Anweisung. Steht ein Symbol im Namensfeld einer DC-Anweisung, so bezeichnet es das erste durch die Anweisung belegte Speicherbyte. Der Zuordnungszähler wird jeweils um die Anzahl der erzeugten Bytes weitergezählt. Dazu einige Beispiele.

Die DC-Anweisungen dienen zur Erzeugung von Konstanten, d.h. von Operanden, deren Werte durch das Programm nicht verändert werden. Wenn sie zur Initialisierung von Variablen benutzt werden, so ist zu beachten, daß das Programm vor jedem Start erneut übersetzt werden muß, da die Werte der Variablen bei einem Programmlauf verändert werden können.

[Symbol] DSB Operand reserviere Byte-Speicherplatz
[Symbol] DSW Operand reserviere Wort-Speicherplatz
[Symbol] DSD Operand reserviere Doppelwort-Speicherplatz

Mit DS (define storage) wird Speicherplatz im Byte-, Wort- und Doppelwortformat reserviert, ohne daß der Speicherplatz mit Werten belegt wird. Die Anzahl der Bytes, Wörter bzw. Doppelwörter wird durch einen Operanden im Adreßfeld angegeben. Dazu sind mit Ausnahme von ASCII-Zeichen die gleichen Darstellungen wie bei den DC-Anweisungen erlaubt. Steht ein Symbol im Namensfeld, so bezeichnet es den ersten Bytespeicherplatz des reservierten Bereichs. Der Zuordnungszähler wird um die Anzahl der reservierten Bytes weitergezählt. Dazu einige Beispiele.

STRING DSB 11 reserviert 11 aufeinanderfolgende Bytes; das erste Byte hat die symbolische Adresse STRING.

FELD DSW $10 reserviert 16 aufeinanderfolgende Wörter, beginnend bei der ersten geradzahligen Byteadresse ; das erste Wort hat die symbolische Adresse FELD.
BLOCK DSD N·2 reserviert 2N aufeinanderfolgende Doppelwörter, beginnend bei der ersten geradzahligen Byteadresse; das erste Wort hat die symbolische Adresse BLOCK. Der Wert für N muß zuvor definiert worden sein.

EVEN mache Zuordnungszähler geradzahlig

EVEN setzt den Zuordnungszähler auf die erste verfügbare gerade Speicheradresse (Wortadresse). Dazu wird ein ungerader Zählerstand um Eins erhöht, ein gerader Zählerstand bleibt unverändert.

ODD mache Zuordnungszähler ungeradzahlig

ODD setzt den Zuordnungszähler auf die erste verfügbare ungerade Speicheradresse. Dazu wird ein gerader Zählerstand um Eins erhöht, ein ungerader Zählerstand bleibt unverändert.

DEF Symbolliste kennzeichne Symbole als definiert

DEF (defined) gibt in einer Symbolliste diejenigen im Programmteil definierten Symbole an, die in anderen, getrennt davon übersetzten Programmteilen verwendet werden. Der Assembler erzeugt daraus die Binde-Information für das spätere Zusammenfügen der unabhängig voneinander übersetzten Programmteile. Die Symbole in der Symbolliste werden durch Kommas getrennt.
REF Symbolliste kennzeichne Symbole als verwendet
REF (referenced) ist das Gegenstück zu DEF und gibt in einer Symbolliste diejenigen im Programmteil verwendeten Symbole an, die in anderen, getrennt davon übersetzten Programmteilen definiert sind.

Neben den beschriebenen Anweisungen gibt es eine Reihe weiterer Assembleranweisungen, z.B. um bestimmte Informationen nach Abschluß des Übersetzungsvorgangs auszugeben. Da solche Anweisungen jedoch für das eigentliche Programmieren nicht von Bedeutung sind, geben wir hier nur einige von ihnen an.Programmierungstechniken: Assemblerprogrammierung, Struktogramm und Flußdiagramm

OPT Schlüsselwortliste

OPT (option) veranlaßt das Ausdrucken folgender, 1ll der Schlüsselwortliste angegebenen Information
LIST Programmliste
SYMB Symboltabelle
XREF Kreuzreferenzliste (erweiterte Symboltabelle mit Angaben, wo die Symbole verwendet sind.)

PAGE beginne neue Seite
PAGE veranlaßt den Assembler, beim Ausdrucken der Programmliste für die nachfolgenden Programmzeilen mit einer neuen Seite zu beginnen.

TITLE Text erzeuge Seitenkopf

TITLE veranlaßt den Assembler, im Kopf einer jeden Seite der Programmliste den im Adreßfeld angegebenen Text auszudrucken.

Feste und verschiebbare Programmblöcke

In der Mikroprozessortechnik ist man bestrebt, Programme so zu schreiben, daß sie auf einfache Weise im Adreßraum des Speichers verschoben werden können. Das gilt insbesondere für Programme und Konstanten, die in Festwertspeichern, wie ROMs und EPROMs, gespeichert sind und deren Adreßbezüge bei einer Verschiebung entweder gar nicht oder nur mit größerem Aufwand verändert werden können. Ob Programmverschiebungen vorgenommen werden können, hängt letztlich von der Erzeugung absoluter oder relativer Adressen beim Übersetzungsvorgang und von der Verwendung der vom Prozessor vorgesehenen relativen Adressierung ab. Maßgeblich beteiligt daran sind die Assembleranweisungen AORG und RORG.

Beispiel 3.2. Feste und verschiebbare Programmblöcke. Ein Programmbeispiel, das in Ausschnitten dargestellt ist, soll drei grundsätzliche Möglichkeiten zur Erzeugung absoluter und relativer Adressen auf grund der Verwendung der drei unterschiedlichen ORG-Anweisungen

1. AORG $200
2. RORG BLOCK1
3. RORG BLOCK1,PCR,

die dem folgenden Programmblock vorangestellt werden können, illustrieren:

  1. AORG $200. Mit der AORG-Anweisung werden sämtliche Adressen, die sich auf die AORG-Anweisung beziehen, d.h. N, FELD, LOC und AGAIN, zur Übersetzungszeit als absolute Adressen festgelegt. Eine spätere Programmverschiebung ist nicht möglich. Das gilt auch für Adreßbezüge, die von anderen Blöcken auf diesen Block führen (fester Block).
  2. RORG BLOCK1. Mit der RORG-Anweisung werden sämtliche Adressen, die sich auf die RORG-Anweisung beziehen, d.h. N, FELD, LOC und AGAIN, vom Assembler als relative Adressen festgelegt. Bezugspunkt für den Assembler ist der Wert des Zuordnungszählers beim Eintritt in diesen Block. Beim ersten Block mit dem Namen BLOCKl ist das der Wert Null. Beim Binden oder beim Laden des Programms wird zu den Adreßwerten des Blocks die Verschiebe- bzw. Ladeadresse addiert, d.h. der Block ist zur Bindezeit bzw. zur Ladezeit verschiebbar (statisch verschiebbarer Block). Zur Ausführungszeit liegen die Adressen als absolute Adressen fest.
  3. RORG BLOCK1,PCR. Die PCR-Option in der RORG-Anweisung veranlaßt den Assembler, die direkte und die indizierte Adressierung durch die befehlszählerrelative Adressierung und die befehlszählerrelative Adressierung mit Indizierung zu ersetzen. Davon betroffen sind sämtliche Adressen, die sich auf die RORG-Anweisung beziehen: N, LOC und AGAIN als direkte Adreßangaben und FELD als Adreßangabe bei einer Indizierung. Bezugspunkt für die Bildung der Relativadressen ist das auf die jeweilige Relativadresse folgende Befehlswort (Befehlszählerstand). Dadurch ist der Block zur Ausführungszeit verschiebbar (dynamisch verschiebbarer Block) .•

Ein symbolisches Programm kann aus mehreren aufeinanderfolgenden AORGund RORG-Blöcken bestehen. Durch AORG-Blöcke erzeugter fester Code wird vorwiegend bei kleineren Mikroprozessorsystemen eingesetzt, bei denen die Speicherbereiche – z.B. ein ROM-Bereich für das Programm und ein RAM-Bereich für die Daten – durch eine unvollständige Adreßdecodierung von vornherein in ihrem Umfang begrenzt und im Adreßraum festgelegt sind (s. auch Abschnitt 4.2.2).

Bei größeren Systemen, die mit verschiebbarem Code arbeiten, werden AORG-Blöcke vorwiegend zur Erzeugung von nicht verschiebbaren Tabellen, so z.B. zum Anlegen der Vektortabelle, oder zur Festlegung von Stackbereichen benutzt. In diesen Systemen können durch die Namensgebung in RORG-Blökken mehrere voneinander unabhängig verschiebbare Programm- und Datenbereiche definiert werden. Die durch die Option PCR verursachte befehlszählerrelative Adressierung bezieht sich dabei jeweils auf RORG-Blöcke gleichen Namens.

Die Adreßbezüge zu anderen Bereichen werden entweder als Absolutadressen vom Assembler oder als Relativadressen vom Binder bzw. bindenden Lader hergestellt.

Ein Programm- und Datenblock mit befehlszählerrelativer Adressierung innerhalb des Blocks und ausschließlich absoluten Adreßbezügen zur Blockumgebung ist – wie bereits beschrieben – im Speicher dynamisch verschiebbar. Ist der Programmteil in einem Festwertspeicher gespeichert, so kann dessen Lage im Adreßraum beliebig festgelegt werden, ohne daß der Speicherinhalt geändert zu werden braucht.

Eine Verschiebung im Adreßraum wird z.B. durch Änderung der Adreßdecodierung an der Speicherkarte vorgenommen (s. auch Abschnitt 4.2.2). Von Nachteil ist dabei, daß die im RAM-Bereich stehenden Daten mitverschoben werden müssen.

Das dynamische Verschieben der Daten, unabhängig vom Programmcode, wird durch basisrelative Adressierung ermöglicht. Hierbei wird die effektive Adresse eines Datums durch Addition der Anfangsadresse des Datenbereichs (Basisadresse) und einer im Befehl stehenden Distanz (Relativadresse) gebildet. Das Register, z.B. ein allgemeines Register, in dem die Basisadresse steht, wird als Basisadreßregister bezeichnet. Das Laden dieses Registers muß vor der Programmausführung erfolgen.

Die basisrelative Adressierung kann durch die indizierte Adressierung nachgebildet werden. Das Indexregister übernimmt dabei die Funktion eines Basisadreßregisters und wird zu Beginn der Programmausführung mit der aktuellen Datenbasisadresse geladen. Die bei der indizierten Adressierung in den Befehlen stehenden Adreßwerte bilden die relativen Datenadressen ; sie müssen bei der Assemblierung auf die Datenbasis Null bezogen werden.

Eine zusätzliche Indizierung innerhalb des dynamisch verschiebbaren Datenbereichs ist bei unserem etwas einfacheren Prozessor nicht mehr möglich. Um die basisrelative Adressierung und die Indizierung kombinieren zu können, sehen einige Mikroprozessoren die Basisadressierung mit Indizierung vor und erlauben damit die Verarbeitung von Datenfeldern innerhalb eines dynamisch verschiebbaren Datenbereichs.

Strukturierte Assemblerprogrammierung

Heutige Mikroprozessorsysteme besitzen Assembler, die nicht nur jeweils eine Zeile, sondern auch ein aus mehreren Zeilen bestehendes Stück eines Assemblerprogramms als Einheit in Maschinencode übersetzen können. Dabei werden die l-zu-l-Zuordnung von Assemblerbefehlszeilen zu Maschinenbefehlswörtern und die maschinengebundene Darstellung von Programmen zugunsten maschinenunabhängigen Programmdarstellungen aufgegeben.

Diese Technik wird insbesondere zur Verdeutlichung der Ablaufstruktur von Assemblerprogrammen eingesetzt, wodurch die Übersichtlichkeit der Programme verbessert werden kann, ohne daß ihre Effizienz bezüglich Platzbedarf und Zeitbedarf wesentlich zurückgeht.

Ähnlich wie bei höheren Programmiersprachen werden hierbei Sprachelemente verwendet, die eine weitgehende goto-freie Programmierung von Programmverzweigungen und von Programmschleifen ermöglichen. Solche höheren Assembleranweisungen sind Z.B.
– IF in Verbindung mit THEN und ELSE,
– FOR in Verbindung mit STEP, TO und DO oder
– WHILE in Verbindung mit DO.

Um innerhalb solcher Anweisungen mehrere Assemblerbefehlszeilen (statements) zu größeren Befehlsblöcken (compound statements) zusammenfassen zu können, sind weitere Assemblerschlüsselwörter notwendig, wie z.B. BEGIN, END oder in Verbindung mit IF und DO die Schlüsselwörter FI beziehungsweise OD.

Anstatt einzelne Anweisungen zu definieren und auf Einzelheiten ihrer Anwendung einzugehen, wollen wir diese Programmierungstechnik durch ein einfaches Beispiel illustrieren, in dem neben dem strukturierten Assemblerprogramm auch das vom Assembler übersetzte Maschinenprogramm in symbolischer Darstellung angegeben ist.

Beispiel 3.3. Strukturiertes Assemblerprogramm. Der in Beispiel 3.1 in der Form eines Struktogramms dargestellte Algorithmus für das Summieren der natürlichen Zahlen 1 bis N soll unter Benutzung der WHILE-Anweisung programmiert werden. – In der WHILE-Anweisung folgt auf das Schlüsselwort WHILE eine Bedingung, die von zwei Operanden abhängt. Zur Darstellung der Vergleichsrelation ~ dient im Beispiel das Schlüsselwort LS (lower or same).

Die im Falle des positiven Verg1cichsausgangs auszuführenden Befehle werden durch die Schlüsselwörter DO und OD eingerahmt. Zur Eingabe der Zahl N und zur Ausgabe des Ergebnisses SUM dient ein Peripheriegerät, dessen Interface-Register durch die numerische Adresse $FFFF beziehungsweise ihr symbolisches Äquivalent EAREG angesprochen wird. Das Programm schließt mit dem Aufruf des Betriebssystems durch einen TRAP-Befehl ab.

Beispiel 3.3.

Das Assemblerprogramm ist nicht im Hinblick auf kürzeste Ausführungszeit, sondern mit dem Ziel möglichst guter Übersichtlichkeit geschrieben. Eine bei der Summation eventuell auftretende Überschreitung des Zahlenbereichs aufgrund der Eingabe einer zu großen Zahl ist im Programm nicht berücksichtigt. Rechts neben dem strukturierten Assemblerprogramm ist auf gleicher Höhe das vom Assembler erzeugte Maschinenprogramm in symbolischer Darstellung angegeben, das einen Befehl mehr als nötig enthält.

Ohne Ausnutzung der strukturierten Programmierung würde man nämlich die am Anfang des Programmblocks stehende Abfrage CMP/BHI (branch if higher) durch die zu ihr komplementäre Abfrage CMP/BLS (branch if lower or same) am Ende des Blocks ersetzen. Dadurch würde der JMP-Befehl entfallen .•

Makrobefehle und bedingte Assemblierung

Assemblersprachen heutiger Mikroprozessorsysteme erlauben neben der l-zu-lUmformung von Assembler- in Maschinenbefehle auch die l-zu-n-Übersetzung von sogenannten Makrobefehlen in im allgemeinen mehrere Maschinenbefehle. Diese Ausdehnung einer Zeile Assemblercode in n Zeilen Maschinencode während der Übersetzungszeit wird als Makroexpansion bezeichnet.

Makrobefehle haben den gleichen Aufbau wie symbolische Maschinenbefehle. Dem Code des Maschinenbefehls entspricht der Name und den Adressen entsprechen die Parameter des Makrobefehls. Während die Maschinenbefehle jedoch in Format und Anzahl von der Prozessorhardware bestimmt sind, können Makrobefehle vom Programmierer im Rahmen der Assemblersprache selbst definiert werden.

Dementsprechend kann die Anzahl von Parametern und ihre Bedeutung vom Anwender weitgehend frei festgelegt werden. Auch die Anzahl von Makrobefehlen und ihre Wirkung ist nahezu unabhängig von der Prozessorhardware.

Makrobefehle ermöglichen es, den Befehlssatz des Prozessors auf der Assemblerebene zu erweitern und tragen damit wesentlich zur übersichtlichen Gestaltung von Assemblerprogrammen bei. Der Benutzer eines Mikroprozessorsystems kann sich eine seinem Problemkreis angepaßte problemorientierte höhere Assembiersprache schaffen, indem er sich geeignete, aufeinander abgestimmte Makrobefehle definiert.

Erlaubt es die Software des Mikroprozessorsystems, eine solche durch den Anwender geschaffene Programmiersprache in eine Makrobibliothek zu übernehmen oder die Sprache in das Betriebssystem der Anlage zu integrieren, so kann das Mikroprozessorsystem im Extremfall ohne die Benutzung eines einzigen Maschinenbefehls programmiert werden.

Um bei einer solchen, weitgehend von den Aufgaben und dem Stil des Anwenders geprägten Programmierungs technik möglichst effiziente Maschinenprogramme zu erzeugen, bedient man sich des Mittels der bedingten Assemblierung. Dabei wird in Abhängigkeit von der Art und der Anzahl der Parameter eines im Assemblerprogramm auftretenden Makrobefehls während der Makroexpansion unterschiedlicher Maschinencode erzeugt.

Im Rahmen der von der Assemblersprache vorgegebenen Mittel hängt es von der Geschicklichkeit des Programmierers beim Definieren und bei der Programmierung des Makrobefehls ab, ob das Ziel erreicht wird, bei einem Maximum an Übersichtlichkeit eines Assemblerprogramms ein Minimum an Speicherplatzbedarf und Ausführungszeit zu erreichen.

Zur Definition von Makrobefehlen und zur Anwendung der bedingten Assemblierung wird die Assemblersprache durch die Einführung zusätzlicher Sprachelemente erweitert. Solche Makroassembleranweisungen sind z.B.

  • MACRO (macro begin) in Verbindung mit ENDM (end macro) zur Definition eines Makrobefehls,
  • NUMB (number) zur Feststellung der Anzahl der bei der Benutzung des Makrobefehls auftretenden Parameter,
  • IFEQ (if equal), IFGR (if greater) usw. in Verbindung mit ENDC (end condition) zur Abfrage von zur Assemblierzeit bekannten Bedingungen und
  • REPT (repetition) in Verbindung mit ENDR (end repetition) zur wiederholten Assemblierung einer bestimmten Anzahl von Assemblerzeilen.

Die letzten beiden Anweisungsgruppen unterscheiden sich grundsätzlich von allen anderen Assembleranweisungen, da bei ihnen die sonst übliche zeilenweise fortschreitende Übersetzung des Quellprogramms durchbrochen wird. In Abhängigkeit einer Bedingung kann nämlich die Assemblierung von Programmzeilen übersprungen bzw. in Abhängigkeit eines Zählerstandes mehrfach durchlaufen werden.

Bei der Übersetzung eines Assemblerprogramms nehmen die Symbole der Parameter eines Makrobefehls (kurz aktuelle Parameter) im Sinne einer Textersetzung die Plätze ihrer in der Makrodefinition benutzten formalen Entsprechungen (kurz formale Parameter) ein. Durch die Anwendung der bedingten Assemblierung werden je nach Art und Anzahl der Parameter verschiedene und unterschiedlich viele Programmzeilen der Makrodefinition übersetzt, so daß dementsprechend unterschiedlich viele Maschinencodewörter entstehen können.

Um einen kurzen Eindruck sowohl von den Möglichkeiten der Programmierung mit Makrobefehlen als auch den Abläufen bei der Makroexpansion zu bekommen, ist im folgenden Beispiel die Definition eines Makrobefehls zusammen mit drei Makroaufrufen und ihren durch den Makroassembler erzeugten unterschiedlichen expandierten Formen als symbolische Maschinenprogramme angegeben.

Beispiel 3.4. Makrobefehl mit mehreren Makroexpansionen. Es soll ein Makrobefehl SA VR geschrieben werden, der die Inhalte der ab zweitem Parameter angegebenen Register in den Stack lädt, wenn der erste Parameter STACK lautet, und der andernfalls die Registerinhalte in ein Feld rettet, dessen Anfangsadresse durch den ersten Parameter vorgegeben ist. – Die MACRO-Anweisung enthält im Namensfeld den Namen und im Adreßfeld ein wählbares Zeichen – hier / – zur Bezeichnung der formalen Parameter des Makrobefehls.

Eine Dezimalzahl unmittelbar nach dem Zeichen gibt die Position des bei der Benutzung des Makrobefehls auftretenden aktuellen Parameters an. Die NUMB-Anweisung ermittelt die Anzahl der Elemente der in ihrem Adreßfeld angegebenen Liste – hier die Anzahl der aktuellen Parameter – und ordnet sie dem im Namensfeld auftretenden Symbol zu.

Die IFEQ-Anweisung bewirkt bei Gleichheit des im Namensund Adreßfeld stehenden Textes die Assemblierung der zwischen IFEQ und ENDC stehenden Programmzeilen. Die REPT -Anweisung wiederholt entsprechend der im Adreßfeld erscheinenden Angabe die Assemblierung der zwischen REPT und ENDR stehenden Zeilen, wobei die im Namensfeld erscheinende Größe jeweils um 1 erhöht wird.Programmierungstechniken: Assemblerprogrammierung, Struktogramm und Flußdiagramm

Heißt der erste aktuelle Parameter STACK, so werden bei der Expansion des Makrobefehls so viele PUSH-Befehle erzeugt, wie Registerinhalte in den Stack geladen werden sollen. Andernfalls wird ein MOVE-Befehl erzeugt, der den Inhalt des als zweiten aktuellen Parameter angegebenen Registers in die durch den ersten aktuellen Parameter angegebene Feldanfangsadresse lädt. Sollen nicht nur ein, sondern mehrere Registerinhalte gerettet werden, so werden zusätzlich folgende Befehle generiert: ein LEA-Befehl, der die effektive Feldanfangsadresse in das durch den vorhergehenden MOVE-Befehl freigemachte Register lädt, ein INC-Befehl, der diese Adresse um 2 erhöht, und so viele MOVE-Befehle, wie Registerinhalte in Verbindung mit der Autoinkrement-Adressierung in den Speicher transportieren werden sollen.

Die neben den Makroaufrufen angegebenen Makroexpansionen illustrieren, wie aufgrund verschiedener Parameterangaben drei Maschinenbefehlsfolgen entstehen, die sich hinsichtlich ihres Speicherplatzbedarfs und ihrer Ausführungszeiten stark voneinander unterscheiden.

Beispiel 3.4.

Like this post? Please share to your friends:
Schreibe einen Kommentar

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: