Assemblerkurs Teil 4

In diesem Teil des Assemblerkurses werde ich Ihnen die letzten Gruppen des 68000 Befehlssatzes vorstellen. Damit hätten wir die Adressierungsarten und den Befehlssatz abgeschlossen.

Zur Übersicht, gebe ich Ihnen an dieser Stelle, die Bezeichnungen der Gruppen, die in diesem letzten Teil des Kurses besprochen werden.

Schiebe- und Rotier-Befehle

Mit dieser Gruppe von Befehlen werden Operanden um ein oder mehrere Bits nach links oder rechts verschoben. Dies kann in einer Reihe oder im Kreis erfolgen . Die verschiedenen Befehle unterscheiden sich nur durch die Verwendung der Bits, die aus der (ea) heraus- und hereingeschoben werden.

ASL
Arithmetisches Schieben links

ASR
Arithmetisches Schieben rechts

LSL
Logisches Schieben nach links

LSR
Logisches Schieben nach rechts

ROL
Rotation nach links

ROR
Rotation nach rechts

ROXL
Rotation mit X-Bit nach links

ROXR
Rotation mit X-Bit nach rechts

Arithmetisches Schieben ASL,ASR

Beim arithmetischen Schieben des Operanden werden die Bits, die herausgeschoben werden, im C- und X-Flag gespeichert. Dem ASL-Befehl wird in die freigewordene Stelle immer eine Null nachgeschoben. Beim ASR-Befehl wird das höchstwertigste Bit kopiert, um damit die freiwerdende Stelle zu besetzen. Mit diesen Befehlen können Byte-, Wort- und Langwortdaten verarbeitet werden, nur wenn sich der Operand im Speicher befindet. Dann kann man nur mit Wortlänge arbeiten. Eine recht interessante Variante bietet der Befehl, mit einem Datenregister als Ziel. Hier ist es möglich über ein weiteres Datenregister oder einer Konstante, die Anzahl der Verschiebungen vorzugeben.

Beispiel:

                 C-Flag 
D1 = %10011101   X

     ASL.B #4,D1 
D1 = %11010000   1

     ASR.B #4,D1 
D1 = %11111001   1

Wendet man beide Beispiele auf das Register D1 an, so erscheint, nach Ausführung der Befehle, das entsprechende Ergebnis (siehe D1 letzte Zeile). Die Konstante kann Werte zwischen eins und acht annehmen. Ein Schieben um eine Stelle nach links, entspricht einer Multiplikation mit zwei, (nach rechts, dementsprechend durch zwei). Das Vorzeichen der Zahl bleibt bei diesen Operationen erhalten. Findet durch das Schieben ein Vorzeichenwechsel statt, so wird dies in dem V-Flag vermerkt.

Logisches Schieben LSL,LSR

Bei diesen zwei Befehlen gibt es nur einen winzigen Unterschied, im Vergleich zu dem ASR-Befehl. Der ASL-Befehl ist identisch mit dem LSL-Befehl. Während beim ASR-Befehl das Vorzeichenbit dupliziert wird, wird beim LSR-Befehl einfach eine null nachgeschoben.

Rotieren ROL,ROR

Das Bit, daß jeweils aus dem Operanden herausgeschoben wird, wird im C-Flag gespeichert und gleichzeitig an die freigewordene Stelle kopiert. Somit ist der Kreis gschlossen. Ebenfalls werden bei dieser Gruppe von Befehlen die Flags entsprechend gesetzt, wobei diese beiden Rotierbefehle das X-Flag nicht verändern. Als kleine Aufgabe: Wieviele Einsen sind in einem Datenregister enthalten?

Lösung:

	MOVE.L #31,D3 
	CLR.L D2 
LOOP ROR.L	#1,D1
	BCS L1 
	ADDQ #1,D2 
L1	DBRA	D3,LOOP

Der Schleifenzähler (D3) wird mit dem Wert 31 geladen, da der DBcc-Befehl bei -1 abbricht. Das Register D2 wird gelöscht, um anschließend die Anzahl der vorkommenden Einsen zu speichern. D1 selbst enthält die zu untersuchende Zahl.

Rotieren mit dem X-Flag ROXL,ROXR

Bei diesen Befehlen erfolgt das Rotieren über das X-Flag. Das X-Flag fungiert hier praktisch als ein Zwischenspeicher. Dabei wird das Bit, daß rausgeschoben wird, ins X-Flag geschoben. Dessen Inhalt wiederum, geht an den Anfang der Rotation, um die Kette zu schließen.

Bei der Schreibweise der erlaubten Adressierungsarten bedeutet:

ARI alle Adressregister indirekt
abs Absolut kurz und lang
PCR alle Programmcounter relativ
SR Statusregister
CCR Condition Code Register
USP User Stack Pointer

Um alle Adressierungsarten zu ermitteln, kann man jede Quelle mit jedem Ziel verknüpfen.

Für den Platzhalter „d“ kann hier „L oder R“ eingesetzt werden. Um die Wirkung der Befehle besser klarzumachen, habe ich noch eine grafische Darstellung gewählt, an der Sie die Verhältnisse genau ersehen können.

Bitmanipulation-Befehle

Wie der Name schon sagt, kann man mit diesen Befehlen einzelne Bits manipulieren. Deshalb haben die Befehle auch keine Operandengröße. In welcher Art und Weise man die Bits manipulieren kann, sagt Ihnen die folgende Tabelle:

Steht der Zieloperand im Speicher, so kann nur ein Bit innerhalb eines Bytes angesprochen werden. Nur wenn ein Datenregister das Ziel der Operation ist, sind alle 32 Bit ansprechbar. Das niederwertigste Bit hat dabei die Nummer null.

Als erstes wird das spezifizierte Bit getestet. Ist es null, so wird das Z-Flag (Zero), das einzigste Bit im CCR, daß von dieser Gruppe verändert wird, auf eins gesetzt. Dies entspricht dem BTST-Befehl. Dieser Befehl wird häufig mit einem anschließenden Bcc-Befehl gebraucht. Durch diese Kombination kann man einfache Entscheidungen aufgrund eines Bits fällen. Die anderen drei Befehle bauen auf dem BTST-Befehl auf. Nachdem das entsprechende Bit getestet worden ist, wird das angesprochene Bit anschließend gesetzt (BSET), gelöscht (BCLR) oder geändert (BCHG). In der Tabelle der Adressierungsarten steht der BTST-Befehl stellvertretend für die anderen Befehle dieser Gruppe.

Datenübertragungs-Befehle

In dem zweiten Teil hatten Sie ja schon einen Teil dieser Gruppe kennengelernt. Dies war im Prinzip nur der leistungsstarke MOVE-Befehl. Die restlichen Befehle dieser Gruppe sind:

EXG
Austausch von Registerinhalten

LEA
Lade effektive Adresse

LINK
Baue Stackbereich auf

PEA
Lege Adresse auf Stack

SWAP
Vertausche Registerhälften

UNLK
Baue Stackbereich ab

Tausche Registerinhalte EXG

Manchmal ist es notendig, die Inhalte von zwei Registern auszutauschen. Dazu dient dieser Befehl. Dieses Problem wird Ihnen in einer höheren Programmiersprache schon mal begegnet sein. Zur Lösung benötigten Sie eine weitere Variable. In Assembler existiert ein Befehl, der ohne ein weiteres Register zwei Registerinhalte austauscht. Der Befehl arbeitet nur mit Registern und mit einer Operandenlänge von 32 Bit. Manche Assembler, lassen deshalb die Schreibweise EXG.L zu, obwohl dies nicht notwendig wäre.

Beispiel:

EXG Dl,A2

      vorher     nachher 
D1    18273645   77661254
A2    77661254   18273645

Tausche Registerhälften SWAP

Im Gegensatz zum Austausch von Registerinhalten wird hier der Inhalt eines Datenregisters vertauscht. Dies geschieht, indem die Bits 16-31 nach 0-15, und die Bits 0-15 nach 16-31 kopiert werden. Die Operation erfolgt also nur in Wortlänge. Die Flags N und Z werden nach dem 32 Bit-Ergebnis gesetzt. Das heißt, daß Z gleich eins wird, wenn die Bits im Datenregister (Bits 0-31) null sind. Entsprechend geht demzufolge das Bit 31 ins N-Flag.

Beispiel:

SWAP D2

   vorher   nachher 
D2 11112222	22221111
Bild 1: Schiebeoperationen
Syntax           Flags    .x       Quelle       Ziel
                 XNZVC

ASd.x Dx,Dy      *****   B,W,L      Dn          Dn
ASd.x #Kons,Dn   *****   B,W,L      #           Dn
ASd.x (ea)       *****     W                    abs,ARI
LSd.x Dx,Dy      *****   B,W,L      Dn          Dn
LSd.x #Kons,Dn   *****   B,W,L      #           Dn
LSd.x (ea)       *****     W                    abs,ARI
ROd.x Dx,Dy      -**O*   B,W,L      Dn          Dn
ROd.x #Kons,Dn   -**O*   B,W,L      #           Dn
ROd.x (ea)       -**O*     W                    abs,ARI
ROXd.x Dx,Dy     ***O*   B,W,L      Dn          Dn
ROXd.x #Kons,Dn  ***O*   B,W,L      #           Dn
ROXd.x (ea)      ***O*     W                    abs,ARI
BTST Dn,(ea)     --*--              Dn          Dn,ARI,abs
BTST #Konst,(ea) --*--              #           Dn,ARI,abs

Lade effektive Adresse LEA

Mit diesem Befehl kann man sich die Arbeit etwas erleichtern und die Programme übersichtlicher gestalten. LEA berechnet eine Adresse und gibt sie an ein Adressregister weiter. Somit ist die Operandenlänge auf 32-Bit festgelegt. Die Berechnung der effektiven Adresse erfolgt genauso wie bei der Adressrechnung der einzelnen Adressierungsarten. Nehmen wir einmal an, wir wollten ein Tabellenelement im Speicher bearbeiten. Die Adresse des Tabellenelements wird durch die Adressierung 7(A1,D3.L) beschrieben. Ein Zugriff auf dieses Tabellenelement sähe dann so aus.

MOVE.L 7(A1,D3.L),D0

Benötigt man mehrere Zugriffe auf diese Speicherzelle, und will man mit dieser Adressierung noch weitere Tabellenteile damit verarbeiten, so wird dies recht lange dauern. Denn jedesmal muß die Adressrechnung durchgeführt werden. Besser ist es dann schon, eine Adressrechnung auszuführen und diese Adresse in einem Adressregister zu behalten. Z. B.:

LEA 7(A1,D3.L),A0
MOVE.L (A0),D0,(A0)

Vergleicht man die zwei Darstellungen, die das gleiche bewirken, so merkt man, daß LEA und MO VE dieselbe effektive Adresse berechnen. LEA bringt das Ergebnis dieser Rechnung nach A0 und der MOVE den Inhalt der Adresse nach D0.

Lege Adresse auf Stack PEA

Der PEA-Befehl ist recht einfach erklärt. Er berechnet genauso wie der LEA-Befehl eine effektive Adresse, nur gibt er diese nicht an ein Adressregister weiter, sondern legt diese auf den Stack (-(A7)). Man könnte PEA entsprechend so beschreiben:

LEA (ea),-(A7)

Da dieser Befehl aber nicht existiert, könnte man ihn durch folgende Sequenz ersetzen:

LEA (ea),A3 
MOVE.L A3,-(A7)

Baue Stackbereich auf LINK

Der Aufbau eines Stackbereiches erfolgt in drei Schritten.

  1. ein Adressregister auf den Stack bringen.
  2. das Adressregister mit Stackpointer laden.
  3. eine Adressdistanz auf Stackpointer addieren.

Die Zahl, die auf den Stackpointer addiert wird, ist eine 16-Bit-Zahl im Zweierkomplement, die Vorzeichenrichtig auf 32-Bit erweitert wird. Damit hat man zwei Möglichkeiten einen neuen Stackbereich anzulegen. Entweder mit einer positiven oder negativen Zahl. Meist wird eine negative Zahl benutzt, um Platz für Daten zu schaffen. Die Länge dieses Bereiches entspricht der Adressdistanz. Uber diesen Datenbereich können Datenblöcke, variabel im Stack untergebracht, zwischen Elaupt- und Unterprogramm ausgetauscht werden. Die Funktion soll folgende Grafik erläutern. Ein Schema zur Nutzung dieses Befehls erfolgt in diesem kleinen Beispiel:

	; Hauptprogramm
			.
	JSR UNTERPROGRAMM
			.
	; Unterprogramm 
	LINK A6,-$80
	MOVEM.L D0-D7/A3,-(A7)
			.
			.
			.
	MOVEM.L (A7)+,D0-D7/A3
	UNLK A6
	RTS

Da das Adressregister die Adresse des alten Stack enthält, sollte man es auf dem neuen Stack abspeichern. Geht dieser Wert verloren, so kann der alte Wert dieses Registers nicht wiederhergestellt werden (was ja nicht unbedingt tragisch ist), aber der RTS-Befehl findet nicht mehr die richtige Rücksprungadresse ins Hauptprogramm!!! Somit ist das Programm rettungslos verloren.

Baue Stackbereich ab UNLK

Hier haben wir das Gegenstück zu dem vorhergehenden Befehl. Was damit passieren kann, haben Sie ja schon erfahren. Warum das so ist, werden Sie mit der Funktion dieses Befehls verstehen. Der Abbau des Stackbereichs erfolgt in zwei Schritten.

1.) lade Stackpointer mit alter Adresse. 2.) lade Adressregister mit Wert vom Stack.

Sie sehen, der Schritt zurück geht nur richtig, wenn der Stackpointer mit seinem alten Wert geladen wird.

Damit hätten wir die vorletzte Gruppe der Befehle vervollständigt. Nun folgt noch die Tabelle dieser Gruppe:

Syntax          Flags     .x        Que1le           Ziel
				XNZVC

EXG  (ea),(ea)  -----               Dn, An           Dn, An
LEA  (ea),An    -----               ARI/(An)+/-(An)  An
LEA  (ea),An    -----               abs,PCR          An
LINK An,Kons    -----               An 
PEA  (ea)       -----               ARI/(An)+/-(An) 
PEA  (ea)       -----               abs,PCR 
SWAP Dn         -**OO                                Dn
UNLK An         -----               An 

Die Programmsteuerbefehle

Mit der Vervollständigung dieser Gruppe wird die Besprechung des 60000’er Befehlssatzes abgeschlossen sein. Einen Teil, Sie erinnern sich, hatte ich ja schon besprochen. Zu den besprochenen Befehlen gehörten z. B. die Verzweigungsbefehle. Nun wieder eine Übersicht über die Befehle.

CHK
Prüfe gegen Grenzen

NOP
Keine Operation

RESET
Rücksetzen der Peripherie

Scc
Setze nach Bedingung

STOP
Halte die Verarbeitung an

TAS
Prüfe und setze ein Bit

TRAPV
Exception mit Bedingung

Prüfen gegen Grenzen CHK

Mit diesem Befehl kann man den Inhalt eines Datenregisters, bzw. die Bits 0-15, gegen Grenzen prüfen. Die Grenzen sind zum einen die Null, die nicht verändert werden kann, und zum anderen eine effektive Adresse. Bewegt sich der Inhalt des Datenregisters in diesen Grenzen, so wird die Verarbeitung mit dem nächsten Befehl fortgeführt. Ansonsten setzt der 68000 das N-Flag auf eins, wenn Dn kleiner null, oder N= 1, wenn Dn größer (ea) war. Danach wird in eine Ausnahmeverarbeitung (Exception) verzweigt. Als Vektor für diese Exception wird der Vektor Nummer 6 benutzt. Zu beachten wäre, daß nach Ausführung des Befehls alle Flags, außer dem X-Flag, Undefiniert sind.

Meist findet der Befehl seinen Einsatz in Compilern. Mit ihm kann sehr einfach geprüft werden, ob der Zugriff auf eine indizierte Variable oder ein Matrizenelement zulässig ist.

Keine Operation NOP

Dies ist wohl der einfachste Befehl des 68000, denn hier arbeitet er nicht! Garnicht wäre etwas übertrieben, sonst wäre der Befehl ja nicht implementiert worden. Daran kann man sehen, das Nichtstun auch seine Berechtigung hat. So zum Beispiel kann er dazu benutzt werden, Zeitschleifen abzugleichen. Denn Rechenzeit kostet der Befehl schon. Da er auch Speicherplatz benötigt, kann man mit ihm einen Speicherbereich im Programm belegen, um diesen Teil später mit richtigen Befehlen vom Programm aus zu beschreiben.

Läßt man ein Unterprogramm mit einem NOP-Befehl anfangen, so kann sich das Unterprogramm gegen einen zweiten Aufruf schützen, wenn es den NOP-Befehl einfach mit dem Code für RTS überschreibt. Jeder weitere Aufruf führt dann zur sofortigen Beendigung des Unterprogrammes. Ebenso ist es denkbar, daß ein weiteres Programm dieses Unterprogramm wieder freigibt. Damit hat man sich eine aufwendige Verwaltung erspart.

Rücksetzen der Peripherie RESET

Da dies ein priviligierter Befehl ist, kann er nur im Supervisormodus ausgeführt werden. Er ermöglicht es, die an die Resetleitung des 68000 angeschlossene Peripherie zurückzusetzen. Dies macht er, indem er die Leitung für 124 Clockzyklen auf „Low“ (ca. null Volt) legt. Danach befinden sich alle angeschlossenen Bausteine im Zustand nach dem Einschalten.

Setze nach Bedingung Scc

Dieser Befehl setzt ein Byte (nur Byteverarbeitung) in Abhängigkeit einer Bedingung (cc). Die Bedingungen sind die gleichen wie bei dem DBcc-Befehl. Ist die Bedingung erfüllt, so wird das über die (ea) adressierte Byte mit Einsen gefüllt, also auf $FF gesetzt. Ansonsten wird es auf $00 gesetzt.

Beispiel:

	SEQ D3

			 vorher   nachher
Z=1 (Bed. erfüllt)
	 D3      XX       00

Z = 0 (Bed.	nicht erfüllt)
	 D3      XX       FF

Halte die Verarbeitung an STOP

Dies ist ebenfalls ein priviligierter Befehl. Wird er nicht im Supervisor-Modus ausgeführt, so geht der 68000 in eine Exception. Der Ausdruck hinter dem STOP-Befehl ist eine 16 Bit Zahl. Diese Zahl wird benutzt, um das Statusregister damit zu laden. Ist dies geschehen, so geht der 68000 in den Halt-Zustand. Der Prozessor nimmt seine Arbeit wieder auf, wenn:

Tritt ein sogenannter katastrophaler Fehler auf, der nicht behoben werden kann, so setzt man den Prozessor auf Halt. Über die Interruptmaske, können laufende Prozesse, die sich an den Prozessor wenden, gesperrt werden. In den Flags könnte man eine Nummer ablegen, die später Auskunft über den Stoppunkt gibt. Somit kann man dann auf den Fehler im System schließen.

Prüfe und setze ein Bit TAS

Als erstes wird der 8-Bit lange Operand getestet, und danach die Flags entsprechend gesetzt. Dann wird vom Operand das 7. Bit gesetzt, egal ob dieses null oder eins war.

Beispiel:

TAS $1000

      vorher   nachher 
1000  00       80 
1000  87       87

Exception mit Bedingung TRAPV

Den TRAP-Befehl hatte ich ja schon besprochen. An den TRAPV-Befehl wird allerdings nur eine kleine Bedingung geknüpft, bevor dieser in die Exceptionbehandlung geht. Der Befehl fragt erst das V-Flag ab. Ist dieses gesetzt, so wird TRAP ausgeführt.

Da wir jetzt die 56 Befehle des 68000 Befehlssatzes besprochen haben, gebe ich Ihnen noch eine Tabelle der privi-ligierten Befehle. Um diese Befehle nutzen zu können, müssen Sie zuerst die TOS-Funktion SUPER aufrufen. Diese bringt Sie in den Supervisormodus.

Es gibt allerdings noch einen „Befehl“ den der 68000 verarbeitet. Allgemein wird er als ILLEGAL bezeichnet. Trifft der 68000 auf eine Bitfolge, die er nicht als Befehl interpretieren kann, so löst er eine Exception aus. Diese Exception hat die Vektornummer 4. Manche Assembler haben diesen „Befehl“ als ILLEGAL implementiert, obwohl Motorola keinen Assemblersyntax dafür vorgesehen hat.

Das Programm

Das Programm, daß ich Ihnen zum Abschluß dieses Assemblerkurses vorstellen möchte, soll Ihnen den Rahmen für die GEM-Programmierung in Assembler geben. In diesem Rahmen befindet sich ein recht bekanntes Programmbeispiel. Eine Alertbox! Im Prinzip geht es nicht um diese Alertbox, sondern um die Verwaltung der AES und VDI Variablen. Da wir uns auf der untersten Ebene der Programmiersprachen bewegen, ist die Verwaltung in Assembler etwas aufwendiger als zum Beispiel in C.

Die erste kleine Routine hat den Namen Setblock. Dies ist ein TOS Aufruf, wie Sie ihn schon kennen. Diese Routine gibt den nicht benötigten Speicherplatz an das Betriebssystem zurück. Dazu wird aus der Base Page (256 Bytes), die vom Betriebssystem zur Verfügung gestellt wird, die Länge des Programms berechnet. Außerdem wird der Userstackpointer auf das obere Ende des neuen Bereichs gesetzt. Den alten Stackpointer wird der Setblock-Routine zur Verwahrung mitge-geben. Diese Prozedur ist nötig, wenn ein weiteres Programm oder ein RSC-File in den Speicher geladen werden soll. Denn das Betriebssystem verwaltet ja den Speicher.

Mit einem kleinen JSR verzweigen wir in unser Programm. Dieses Programm wird zur ordnungsgemäßen Terminierung mit einem RTS abgeschlossen. Allerdings habe ich auch ein gewaltsames Verlassen des Programms eingebaut, nämlich mit einem Sprung nach END.

Nehmen wir einmal an das Programm wird ordnungsgemäß verlassen, so wird das Programm nach dem Unterprogrammaufruf fortgesetzt. An dieser Stelle findet man den TOS Aufruf zur Eingabe eines Zeichens. Dann folgt die Marke END, mit der anschließenden Funktion TERM, die das Programm beendet.

Da ich im Rahmen dieses Assemblerkurses nicht auf die GEM-Programmierung eingehen kann, werde ich mich hier auf die Parameterübergabe beschränken. Um diesen Ausführungen folgen zu können, sollten Sie sich schon ein wenig mit der GEM-Programmierung auskennen. Die Variablennamen halten sich weitgehend an die üblichen Bezeichnung.

Syntax            Flags         .x      Quelle         Ziel
				  XNZVC

CHK (ea),Dn       -*UUU                 Alle/An        Dn
NOP               -----
RESET             -----
Scc (ea)          -----                                Alle/PCR/abs(lang)
STOP #Kons        *****                 # (16 Bit)
TAS (ea)          -**OO                                Alle/An/PCR
TRAPV #Kons       -----                 # (0-15)

AES

Wenn Sie sich einmal das kleine Unterprogramm AES anschauen, so sehen Sie, daß der AES Aufruf ein Softwareinterrupt ist. Zu diesem Zwecke werden zwei Register initialisiert. Das Register D1 enthält eine Adresse und D0 die Geheimnummer von AES. Die Sache sieht bis jetzt noch ganz einfach aus. Wenn Sie das Programm weiter verfolgen, und zu der Stelle AESPB (am Anfang vom Datenbereich) kommen, stehen die Adressen von weiteren Marken. Dies sind die Adressen der Felder zur Übergabe der Variablen-Felder an AES. Diese Felder muß der Benutzer entsprechend seinen Wünschen mit Daten versorgen. Wenn Sie richtig gezählt haben, so macht dies sechs Felder. Jedes Feld hat eine bestimmte Bedeutung.

Das CONTRL Feld

Dieses Feld enthält alle Informationen über die Art der Funktion, sowie die Größe der Eingabefelder. Es besteht aus fünf Worten (10 Bytes). Hier erfolgt auch die Rückmeldung über die Größe der Ausgabefelder. Das Feld ist folgendermaßen aufgebaut:

contrl
Befehlsnummer

sintin
Größe des intin-Feldes in Bytes

sintout
Größe des intout-Feldes in Bytes

saddrin
Anzahl der Adressen im addrin-Feld

saddrout
Anzahl der Adressen im addrout-Feld

Die Einträge contrl, sintin und saddrin müssen von Ihnen gemacht werden. Rückmeldungen über die Anzahl der Einträge in den Feldern, die an Sie gehen, geben die Variablen sintout und saddrout an.

Das GLOBAL Feld

Dieses Feld enthält einige Daten über die Applikaton. Mit diesem Feld werden Sie wahrscheinlich nie in Berührung kommen.

Die anderen Felder müßten Ihnen bekannt Vorkommen. Basic beispielsweise, stellt Ihnen diese Variablen zur Verfügung. Wenn Sie nun noch beachten, daß diese Felder Wortlänge haben, so kann nicht mehr viel schiefgehen. Definiert wurden die Felder mit 128 Worten. Wollen Sie größere Datenmengen auf einmal verarbeiten, so vergrößern Sie diese.

VDI

Wenn Sie sich den Zeiger VDIPB anschauen, und das Unterprogramm VDI, so sehen Sie nicht viel Neues. Der Zeiger enthält diesmal nur 5 Einträge. Das CONTRL-Feld wird hier ähnlich benutzt. Da VDI mehr Einträge im CONTRL-Feld benötigt (Insgesamt 12 Wörter), habe ich saddrout mit acht Wörter reserviert. Die Funktion des CONTRL-Feldes sieht nun folgendermaßen aus:

contrl
Befehlsnummer

contrl + 2
Anzahl der Koordinatenpaare im ptsin-Feld

contrl + 4
Anzahl der Koordinatenpaare im ptsout-Feld

contrl + 6
Anzahl der Wörter im intin-Feld

contrl + 8
Anzahl der Wörter im intout-Feld

contrl +10
Unterfunktion-Befehlsnummer

contrl +12
Anwendungskennziffer

Die Variablen contrl, contrl+ 2, 6, 10 und 2 werden dem VDI übergeben. Als Rückmeldung enthalten contrl + 4, 8 und evtl, contrl+12 einen Wert.

Die Felder intin und intout werden von beiden Funktionen gemeinsam benutzt.

Da dies die Verwaltung der Variablen war, können wir uns nun mit dem Hauptprogramm befassen. Das Hauptprogramm beginnt mit vier Aufrufen. Zwei davon sind AES. Diese Funktionen dienen zur Initialisierung der Applikation. Als erstes, wird die Applikation mit Applikation Init angemeldet. Danach benutzt man die Funktion Graf Handle, um von ihr die Variable grhandle zu erhalten. Diese Variable benötigen Sie für die VDI-Aufrufe.

Da wir den Bildschirm benutzen möchten, müssen wir beim ATARI dies durch ein Open Virtuell Workstation dem Betriebssystem mitteilen. Als Dank erhalten Sie dann insgesamt 57 Werte. Diese Werte enthalten z. B. Daten über das Auflösungsvermögen des Monitors, Linien- und Schrifttypen usw..

Und als letzte Funktion Clear Workstation, die ich aus Schönheitsgründen nicht benutzt habe, löscht einfach den Bildschirm.

Jetzt sind wir endlich mit der Initialisierung fertig, und können unseren Ideen freien Lauf lassen. Die Alertbox, ein beliebtes Beispiel, wird deshalb so gern benutzt, weil GEM die komplette Verwaltung dafür übernimmt. Dazu gehört das Zwischenspeichern des benötigten Bildschirmbereiches, die Aufbereitung des Aussehens der Box, nebst ihrer Größe, bis hin zur Restaurierung des Bildschirms. Als Antwort bekommt man eine Zahl in intout zurück, die die Nummer der gedrückten Taste enthält.

Diese Information bringe ich zur weiteren Auswertung ins Register DO. Wurde die Taste 1 betätigt, so endet das Programm mit einem gewaltsamen Abbruch. Taste 3 hingegen beendet das Programm normal. Hier kann man schön die Restaurierung des Bildschirmes erkennen, da erst noch eine weitere Taste gedrückt werden muß, bis sich das Desktop wieder aufbaut. Die Taste 2 quitiere ich mit einer neuen Alertbox. Diese Box hat als einzigsten Ausgang nur das brutale Ende zur Folge.

Ich hoffe, ich konnte Ihnen mit diesem Assemblerkurs die Assemblersprache ein wenig näher bringen. Wenn Sie sich in Assembler ein wenig eingearbeitet haben, so dürftes es Ihnen keine Probleme bereiten Beispiele oder Anwendungen, die in Assembler programmiert wurden, zu verstehen und für sich selbst zu nutzen. Sind Sie mit der Materie etwas besser vertraut, so sollte Ihnen die Anpassung solcher Programme zu Ihren eigenen Zwecken unproblematisch sein.

Sven Schüler

; Dieses Programm soll Ihnen die Anwendung der VDI und AES 
; Routinen zeigen. Das Programm beinhaltet hauptsächlich 
; die Verwaltung der Routinen. Diesen Teil sollten Sie sich 
; auf Diskette abspeichern, um sich unnötige Tipparbeit bei 
; weiteren Programmen zu sparen. Aus Schönheitsgründen habe 
; ich die Funktion CLEAR WORKSTATION nicht benutzt.

	move.l	a7,a5		; Stackpointer speichern
	move.l	#nstack,a7	: neuen Stack setzen
	move.l	4(a5),a5	;
	move.l	$c(a5),d0	; Textsegment
	add.l	$14(a5),d0	; Datensegment
	add.l	$1c(a5),d0	; Blocksegment
	add.l	#$100, d0	; base page
	move.l	d0,-(a7)	; Speicherplatzbedarf
	move.l	a5,-(a7)	; alter Stackpointer
	move	#0,-(a7)	; dummy
	move	#$4a,-(a7)	; TOS SETBLOCK
	trap	#1			; Aufruf
	adda	#12,a7		; Stackkorrektur

	jsr		main		; Hautprogramm

	move	#1,-(a7)
	trap	#1			; wartet auf Taste
	addq.l	#2,a7
end 
	clr.l	(a7)
	trap	#1			; beendet Programm
;
aes						; AES Aufruf
	move.l	#aespb,d1	; Pointer
	move 	#$c8,d0		; AES Nummer
	trap 	#2			; doit
	rts
;
vdi						; VDI Aufruf
	move.l	#vdipb,d1	; Pointer
	move.l	#$73,d0		; VDI Nummer
	trap 	#2			; doit
	rts
;
main					; Anfang der Initialisierung
	clr.l	aplresv
	clr.l	ap2resv
	clr.l	ap3resv
	clr.l	ap4resv
	move	#10,opcode
	clr 	sintin 
	move	#1,sintout
	clr 	saddrin 
	clr 	saddrout
	jsr		aes			; Applikation Init
;
	move	#77,opcode
	clr 	sintin 
	move	#5,sintout
	clr 	saddrin 
	clr 	saddrout
	jsr		aes				; Graf Handle
;
	move	intout,grhandle ; grhandle von Routine speichern
;
	move	#100,opcode
	clr 	contrl+2 
	move	#11,contrl+6
	move	grhandle,contrl+12
;
	lea	intin,a1	; Intin (0-9) löschen
	move	#9,d1
loop 
	move	#1,(a1)+
	dbra 	d1,loop
;
	move 	#2,(a1)
	jsr		vdi		; Open virtuell Workstation
;
	jmp 	nloesch	; Clear Workstation	überspringen
;
	move 	#3,contrl
	clr		contrl+2
	clr		contrl+6
	move	grhandle,contrl+12
	move	#1,intin
	jsr		vdi		; Clear Workstation
;
nloesch
;
; Hier kann nun ihr Programm folgen
;
	move.l #alert,addrin	; Alarmtext nach addrin
box
	move	#52,contrl
	move	#1,contrl+2
	move	#1,contrl+4
	move	#1,contrl+6
	move	#0.contrl+8
	move	#1,intin	; 1. Knopf ist Returnknopf
	jsr		aes			; Form	Alert
;
	move	intout,d0	; Rückmeldung der Taste
	cmp		#1,d0
	beq 	end				; Taste 1, dann ende
	cmp		#2,d0
	bne 	weiter			; taste 2, weiter, mit Returntaste beenden
	move.l	#alert2,addrin	; 2. Alarmtext nach	addrin
	jmp		box				; und ausführen
weiter
;
	rts						; ende von main
	.data 
	.even
; Daten zu den Alertboxen 
alert
; Pictogramm (0-3) 
	dc.b "[1]"
; Text 5 Zeile a 40 Zeichen durch | getrennt 
	dc.b "[Dies ist eine|Alertbox in Assembler]"
; Bis zu drei Tasten. Pro Taste maximal 20 Zeichen 
	dc.b "[Taste 1|Taste 2|Taste 3]",0,0
	.even			; Wichtig, da ungerade Adresse wahrscheinlich
;
alert2				; dito
	dc.b "[2]"+
	dc.b "[Sie haben die Taste 2|gedrückt] " 
	dc.b "[ende]",0,0 
	.even

; Hier endet Ihr Programm 
;
; Daten zu der Initialisierung
;
aespb				; Pointer auf AES Felder
	dc.1 contrl,global,intin,intout,addrin,addrout
;
vdipb				; Pointer auf VDI Felder
	dc.l contrl,intin,ptsin,intout,ptsout
;
grhandle ds.w 1		; Speicher Graf Handle
; 			FELDER

contrl
opcode		ds.w	1
sintin		ds.w	1
sintout		ds.w	1
saddrin		ds.w	1
saddrout	ds.w	8	; noch 7 Worte für AES
;
global
apversion	ds.w	1
apcount		ds.w	1
apid		ds.w	1
apprivate	ds.1	1
aptree		ds.l	1
ap1resv		ds.l	1
ap2resv		ds.l	1
ap3resv		ds.l	1
ap4resv		ds.l	1
;
intin		ds.w	128
;
ptsin		ds.w	128
;
intout		ds.w	128
;
ptsout		ds.w	128
;
addrin		ds.w	128
;
addrout		ds.w	128
;
	.bss 
	.even
	ds.l 300	; 1200 Bytes müssten reichen

nstack	; Neuer Stackpointer


Aus: ST-Computer 03 / 1987, Seite 93

Links

Copyright-Bestimmungen: siehe Über diese Seite