home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
coders
/
assembler-kurs
/
lektionen
/
68000d.txt
next >
Wrap
Text File
|
1977-12-31
|
27KB
|
654 lines
; REFERENZTABELLE FÜR DIE 68000er PROGRAMMIERUNG
Synthetisch zusammengefaßt: Die Adressierungen:
move.l #123,xxxx ; Immediate: die Zahl 123 kommt sofort ins xxxx
move.l xxxx,$50000 ; Absolut long
move.l xxxx,$500.w ; Absolut kurz (weniger als $7FFF)
move.l xxxx,D0 ; Datenregister direkt
move.l xxxx,A0 ; Adressregister direkt
move.l xxxx,(A0) ; Datenregister indirekt
move.l xxxx,(A0)+ ; Adressregister indirekt mit Post-Inkrement
move.l xxxx,-(A0) ; Adressregister indirekt mit Pre-Dekrement
move.l xxxx,$123(A0) ; Adressregister indirekt mit Offset (Adressdistanz)
move.l xxxx,$12(a0,d0.w) ; Adressregister indirekt mit Offset und Index
move.l Offset(PC),xxxx ; Relativ zum PC mit Offset
move.l Offset(PC,d0.w),xxxx ; Relativ zum PC mit OFFSET
- - -
* Die verschiedensten Adressierungsarten kann man in Befehlen mit
Datenquelle und Datenziel "mischen", z.B. "move.l -(A0),12(a0,d3.l)".
- - -
* Die Dezimalzahlen werden von keinem Symbol angeführt (z.B. 123), die
Hexadezimalzahlen von einem $ (z.B. $1a0). Hexzahlen enthalten auch die
Buchstaben von A bis F. Binärzahlen werden von einem % angeführt, z.B.
%10010110, sie bestehen nur aus 0 und 1 (Strom oder nicht im Draht!). Die
Konvertierung untereinander der drei Zahlensysteme bereitet keine
Probleme, da es unter dem ASMONE den "?"-Befehl gibt, gefolgt von der zu
konvertierenden Zahl. Als Resultat erhält man das Äquivalente in Dezimal,
Hexadezimal und ASCII, also CHARAKTERN: denn auch die Buchstaben wie
"ABCDabcde..." sind nur durch ein Byte dargestellt. So ist z.B. das "Z"
$5a (Probiert ?"z"). Um Charakter anzugeben setzt man sie unter
Gänsefüßchen ("" oder ´´), und man kann sie mit den Befehlen kombinieren
(z.B. MOVE.B #"a",Label1) oder mit dem DC.B direkt in den Speicher geben
(DC.B "Ein Text im Speicher").
- - -
* In Assembler wird die Multiplikation durch * dargestellt, die Division
durch /, und man kann runde Klammern verwenden, wieviel man will, z.B:
move.l #(100/2*(12+$41-32)+%01101010),RESULTAT
* 1 byte = 8 bit ($00 = %00000000; $FF = %11111111)
1 word = 16 bit ($0000 = %0000000000000000; $FFFF = %1111111111111111)
1 long = 32 bit, ossia 2 words ($00000000 = %000000000000000000000000000000)
- - -
Bei Bits zählt man folgens: von 0 rechts nach links: z.B. ein Byte, das
Bit 5 auf 1 hat (oder High): $00100000. Bei einem Byte gehen die Bits von
0 (niederwertigsten) zum siebten (höchstwertigsten), ein Word von 0 bis
15, ein Longword von 0 bis 31. Um Bits leicht numerieren zu können, könnt
ihr diesen Trick verwenden:
; 5432109876543210 - ein word
move.l #%1000010000110000,d0 ; bit 15,10,5 e 4 High (auf 1)
- - -
*Adressen werden per Konvention durch Hexzahlen dargestellt.
- - -
* Befehle mit dem "#"-Symbol, wie etwa MOVE.L #123,d0, CMP.L #10,LABEL1
etc. betrachten die Zahl nach dem Lattenzaun (#) wie eine konstante Zahl,
also wirklich als "Nummer", nicht als Adresse, zum Unterschied wenn kein #
vorhanden ist: move.b $12,$45 kopiert das Byte aus Adresse $12 in Adresse
$45, während move.b #$12,$45 die Zahl $12 in Adresse $45 kopiert.
- - -
* Die DATENREGISTER und die ADRESSREGISTER sind alle 32 Bit lang, also ein
Longword. Auf Adressregistern kann man nur mit .W oder .L arbeiten, nicht
mit .B.
- - -
* Auf ungeraden Adressen kann man nicht mit .W oder .L-Instruktionen
arbeiten, nur mit .B. Ein move.l #1,$10001 schickt den computer in GURU,
während ein move.b #1,$10001 keine Probleme verursacht.
- - -
* Ein Byte kann eine Zahl zwischen $00 und $FF (255) enthalten, wenn dann
noch etwas addiert wird, startet die Zahl wieder bei NULL. Das gleiche
gilt für das Word, bei dem $FFFF die größte, darstellbare Zahl ist, und
für das Longword. Dies hat max. $FFFFFFFF.
- - -
* Das LABEL, die KOMMENTARE nach den ";" und die DC.x sind keine
68000erBefehle, aber Assemblerbefehle, die es uns ermöglichen, Punkte im
Listing (z.B. Daten oder Routinen) zu markieren, Kommentare einzufügen, um
das Listing klarer und verständlicher zu gestalten oder Bytes, Words oder
Longwords direkt an einen bestimmten Punkt im Speicher zu geben (DC.x).
Das kann verifiziert werden, indem man den Speicher mit dem Befehl "D
$xxxx" oder "D LABEL" disassembliert.
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
; ADRESSIERUNGEN DES 68000 (Beispiele)
; Adressierungen mit absoluten Adressen, .L (Longword)
move.l #$123,$50000 ; wir geben $00000123 in $50000. Die Nullen links sind
; Optional, denn move.l #$00000123,xxx unterscheidet
; sich nicht von move.l #$123,xxx, im Speicher werden
; die Nullen immer trotzdem angehängt.
; ZU BEACHTEN ist, daß mit diesem .L-Befehl vier
; Bytes im Speicher verändert werden, also die Bytes an
; Adresse $50000, $50001, $50002 und $50003, die
; folgende Werte erhalten:
; $50000 = $00
; $50001 = $00
; $50002 = $01
; $50003 = $23
- - -
; Adressierungen mit absoluten Adressen, .W (Word)
move.w #$123,$50000 ; Wir geben $0123 in Adresse $50000 - Mit dieser
; .W - Instruktion haben wir zwei Bytes verändert,
; da ein Word 2 Bytes lang ist, und zwar die
; Adressen $50000 und $50001:
; $50000 = $01
; $50001 = $23
- - -
; Adressierungen mit absoluten Adressen, .B (Byte)
move.B #$12,$50000 ; Wir geben $12 in Adresse $50000. Mit diesem .b-Befehl
; haben wir 1 Byte modifiziert, und zwar das an
; Adresse $50000 = $12.
; PASST GUT AUF DIE UNTERSCHIEDE AUF, DIE EINTRETEN,
; WENN IHR EINFACH .L, .W UND .B VERTAUSCHT. In der Tat
; liegen oft Fehler der Anfänger darin, diese drei
; Typen zu vertauschen oder ihrer falschen Einschätzung
; Verwendet den Debugger ("AD"), dann die > Taste um
; auch die letztn Zweifel auszuschalten.
move.l $40000,$50000 ; In diesem Fall geben wir den Inhalt aus Byte
; $40000, $40001, $40002 und $40003 in die vier
; Bytes ab $50000, also in das Byte $50000, $50001,
; $50003 und $50004. Wenn z.B. $40000 = 00102305 war:
; $50000 = $00
; $50001 = $10
; $50002 = $23
; $50003 = $04
; Auf die gleiche Weise kopieren wir mit einem
; .W oder .B von einer Adresse zu anderen jeweils
; zwei Bytes oder eines.
- - -
BEMERKUNG: Wenn wir LABEL verwenden, um Daten im Speicher zu verändern,
werden sie vom Assembler in die EFFEKTIVEN ADRESSEN umgewandelt, die sie
darstellen. Da Label ja Punkte im Speicher markieren, wie Etiketten oder
Schildchen, werden wir uns auf genau diesen Punkt beziehen, wenn wir eine
in irgend einer Art ansprechen oder aufrufen. Befehle wie die folgenden
sind dann auch bei der absoluten Adressierung mit beinhaltet:
MOVE.L LABEL1,$50000
MOVE.W #$123,LABELBLAU
MOVE.B LABELHUND,LABELKATZE
Diese werden im Speicher dann immer in ähnlicher Weise dastehen:
MOVE.L $64230,$50000 ; angenommen LABEL1 sei auf $64230
MOVE.W #$123,$726e0 ; angenommen LABEL1 sei auf $726e0
MOVE.B $23450,$3a010 ; wie oben...
Also, mit Bytes, Words oder Longwords, die mit Labels gekennzeichnet sind,
müßt ihr umgehen, als seien es Adressen, den, einmal ASSEMBLIERT, SIND ES
ADRESSEN!!!
Deswegen wird bei folgendem Befehl
MOVE.L #LABEL1,$dff080 ; Verwendet, um unsere Copperlist
; "anzupeilen"
in $dff080 die Adresse von LABEL1 gegeben, und nicht die vier Bytes, die
ab LABEL1 stehen: weil LABEL1 in ihre äquivalente Adresse konvertiert
wird, und da es nach einem # steht, wird diese Adresse als ("konstante")
Zahl betrachtet, und somit wird diese Zahl in $dff080 kopiert. Machen wir
ein Beispiel:
MOVE.L #LABEL1,LABEL2
MOVE.L LABEL1,LABEL2
Werden so assembliert: (Für das Label werden hypotetische Adressen
angenommen)
MOVE.L #$42300,$53120 ; In $53120 kommt die Zahl $42300,
; also die Adresse des Label
MOVE.L $42300,$53120 ; In $53120 wird das Longword kopiert,
; das sich ab Adresse $42300 befindet
- - -
Es ist möglich, sich auf elegantere Weise auf absolute Adressen zu
beziehen, wenn sie kleiner als das Word sind, also $7FFF, indem man ein .W
nach der Adresse anhängt: das ist z.B. der Fall bei Move.L 4.w,A6, das die
ExecBase in A6 ladet, aber jede Instruktion, die mit Adressen mit der
Länge des Word operieren, können so abgekürzt werden. Die Ersparnis der
linken vier Nullen wirkt sich Geschwindigkeitssteigernd aus. Schauen wir
uns den Unterschied an:
(assembliert)
MOVE.B #10,$123 -> MOVE.B #10,$00000123
MOVE.B #10,$123.w -> MOVE.B #10,$0123 -OHNE ÜBERFLÜSSIGEN
NULLEN
Der Effekt des Befehles ÄNDERT SICH NICHT! Es ändert sich nur die "Form",
die schlanker und schneller erscheint. Wenn man vergißt, das .w bei den
"kurzen" Befehlen anzuhängen, dann produziert man nur Code, der einige
Word länger ist, nicht mehr.
** ** ** ** ** ** ** ** ** ** **
; Datenregister, .L (Longword)
move.l #$123,d0 ; Datenregister direkt (wir geben $123 in D0)
move.l d1,d0 ; Datenregister direkt, wir geben den Wert, der in
; d1 enthalten ist, in d0)
; Datenregister, .W (Word) (Bemerkung: Man nennt die rechte Hälfte des
Long das "niederwertige Word", die linke
das "höherwertige Word": $HOCH+NIEDER,
.L = 4 Byte = 2 Word)
move.w #$123,d0 ; In diesem Fall haben wir nur das niederwertige
; Word von d0 verändert: wenn d0 $0012fe3c war, und
; wir nur auf dem niederwertigen Word agieren, also
; $fe3c, dann wird d0 danach so aussehen: $00120123
move.w d1,d0 ; Das Gleiche, wir kopieren das niederwertige Word
; von d1 ins niederwertige Word von d0. Wenn d1
; $12345678 enthält, und d0 $9abcdef0, dann wird nach
; diesem Befehl d0 folgendes enthalten: $9abc5678
^^^^ WORD!
; Datenregister, .B (Byte)
move.b #$12,d0 ; In diesem Fall ändern wir nur das Byte ganz rechts,
; wenn d0 z.B. $0012fe3c war, nur auf dem ersten
; Byte zugreifend, wird es so verändert: d0=$0012fe12
move.b d1,d0 ; Das Gleiche, wir kopieren das erste Byte von d1
; in das erste Byte von d0. Wenn d1 $12345678 enthält,
; während d0 $9abcdef0, dann wird nach dieser Instr.
; d0 so aussehen: $9abcde78
^^ Byte!
Die Adressregister a0,a1,a2,a3,a4,a5 und a6 (VERWENDET NICHT A7, auch SP
genannt - Stack Pointer) verhalten sich wie die Datenregister, nur kann
man auf ihnen NICHT mit .B zugreifen. Man kann darin auch Daten geben,
auch wenn sie für Adressen vorgesehen sind.
** ** ** ** ** ** ** ** ** ** **
; INDIREKTE ADRESSIERUNGEN MITTELS ADRESSREGISTERN
move.w #123,(a0) ; Bei diesem Move wird die Zahl 123 in das Word
; kopiert, das sich ab der Adresse befindet, die
; in a0 steht. Man sagt indirekt dazu, weil die
; Zieladresse nicht direkt angegeben ist, sondern
; Mittels Register, das die Adresse enthält. Das
; geschieht nur, wenn das Adressregister in Klammern
; geschrieben steht, ansonsten würde man 123 in das
; Register selbst schreiben. Ein DATENREGISTER kann
; NICHT dazu verwendet werden, eine indirekte
; Adressierung zu verrichten.
; Man kann sagen, daß das Ragister a0 als ZEIGER
; auf eine Speicherzelle verwendet wurde, es ZEIGT
; also wie der Mauspointer oder ein Spürhund in
; Richtung der Beute: man nennt eine Adresse oder
; ein Register "ZEIGER", wenn dessen Inhalt eine Adres.
; von irgend etwas enthält,auf das man zugreift,
; indem man den Zeiger fragt, wo sich dieses befindet.
; Zeiger werden meist auch als "POINTER" bezeichnet.
; Z.B. die Copperlist hat ein Pointerregister, das
; $dff080, in das die Adresse der Copperlist gegeben
; wird. Der Copper schaut bei jedem Fotogramm in
; $dff080 nach, wo sich die Copperlist befindet.
move.l (a0),(a1) ; In diesem Fall wird das Long, das sich ab Adresse a0
; befindet, in Adresse a1 kopiert. Wenn vor der
; Ausführung dieses Befehles in a0 die Adresse $100
; gestanden hätte, und in a1 $200, dann wäre dieser
; gleichwertig mit einem
; MOVE.L $100,$200, oder, noch raffinierter,
; MOVE.L $100.w,$200.w...
- - -
; INDIREKTE ADRESSIERUNG MIT POST-INKREMENTIERUNG (Erhöhung der Adresse NACH
Ausführung)
move.w #123,(a0)+ ; Auf diese Art wird die Zahl 123 in das Word kopiert,
; das sich ab Adresse a0 befindet, und DANACH wird
; a0 um ein WORD INKREMENTIERT. Wenn die Anweisung ein
; .B gewesen wäre, dann würde nach dem Move a0 um nur
; ein Byte erhöht, bei einem .L um 4 Bytes, also ein
; Long.
move.l (a0)+,(a1)+ ; Mit dieser Anordnung kopieren wir das Long, das sich
; ab Adresse a0 befindet, in Adresse a1 und folgende,
; und danach werden beide Register, a0 und a1, um
; jeweils vier Byte erhöht (Long).
; Praktisch bewegen wir uns auf die darauffolgenden
; Longword im Speicher. Mit einer Serie solcher
; Instruktionen könnte man ein Stück Speicher kopieren:
lea $50000,a0 ; Quell-Adressee
lea $60000,a1 ; Ziel-Adresse
move.l (a0)+,(a1)+
move.l (a0)+,(a1)+
move.l (a0)+,(a1)+
move.l (a0)+,(a1)+
move.l (a0)+,(a1)+
; Jetzt haben wir 5 Longwords von $50000 nach
; $60000 kopiert.
- - -
; INDIREKTE ADRESSIERUNG MIT PRE-DEKREMENT (Adresse wird VOR Ausführung
erniedrigt)
move.w #123,-(a0) ; ALS ERSTES WIRD A0 UM 2 BYTES DEKREMENTIERT
; (verringert, abgezogen), ALSO UM EIN WORD,
; und DANACH wird 123 in das Word kopiert, das
; sich ab der Adresse, die in a0 steht, befindet.
; Wenn die Anweisung eine .B gewesen wäre, dann
; würde dem a0 nur 1 Byte abgezogen, bei einem
; .L hingegen 4 Byte (Long).
move.l -(a0),-(a1) ; a0 und a1 werden beide um jeweils 4 Bytes
; dekrementiert (Long), und dann wird der Inhalt,
; der sich ab der nun resultierenden Adresse a0
; befindet, in die jetzt resultierende Adresse a1
; kopiert.
; Mit einer Reihe solcher Befehle könnte man, wie im vorigen
; Fall, ein Stück Speicher kopieren, aber mit dem
; Unterschied, daß man rückwärts vorgehen würde, so
; wie Krebse. Wir müßten bei der Adresse starten, die
; das Ende der Kopie ist, und nach hinten gehen, bis
; wir den Anfang erreicht haben, im Beispiel $50000 und
; $60000. Setzten wir also $50014 und $60014 als Startwert,
; und dann kopieren wir solange ein Long "nach hinten", bis
; wir bei $50000 bzw. $60000 angekommen sind: um die Adresse
; zu berechnen, bei der wir starten müssen, habe ich zum
; Anfangswert (5*4) dazugezählt, also = $14, praktisch
; 5 Longwords * 4 Bytes pro Long. Zu Beachten, daß im Speicher
; $50000+(5*4) als $50014 assembliert wird, denn während der
; Assemblierfase werden auch eventuelle mathematische
; Operationen durchgeführt.
lea $50000+(5*4),a0 ; Quelladresse am ENDE
lea $60000+(5*4),a1 ; Zieladresse am ENDE
move.l -(a0),-(a1)
move.l -(a0),-(a1)
move.l -(a0),-(a1)
move.l -(a0),-(a1)
move.l -(a0),-(a1)
; In diesem Fall haben wir 5 Longwords von $50000
; nach $60000 kopiert, aber sind bei $50014 gestartet
; und bis $50000 nach "hinten" gegangen. Der Unter-
; schied zum vorigen Beispiel ist wie der Unterschied,
; der darin besteht, den Flur von Links oder von
; Rechts her zu putzen: in beiden Fällen "kopieren" wir
; den Schmutz in den Eimer, aber in zwei verschiedenen
; Richtungen.
- - -
; INDIREKTE ADRESSIERUNG MIT ADRESSIERUNGSDISTANZ (OFFSET) UND INDEX
move.w #12,5(a0,d0.w) ; Bei dieser Anweisung wird 12 in das Word kopiert,
; das sich ab der Adresse befindet, die sich aus
; der Summe von 5 + a0 + Word in d0 bildet. Wenn z.B.
; in a0 $50000 stehen würde, und in d0 $1000, dann
; würde 12 auf die Adresse $51005 kopiert.
; Das Offset kann hier aber nur zwischen -128 und +127
; variieren.
; Praktisch wird zur Summe, die die Adresse ergibt,
; auch noch ein Register hinzugezogen,das sowohl
; DATEN- wie auch ADRESSREGISTER sein kann, bei dem
; der ganze Inhalt verwendet werden kann (.L) wie auch
; nur ein Word (.W).
; Byteweise ist es nicht verwendbar. Man nennt dieses
; zusätzliche Register INDEX.
EINIGE BEISPIELE:
lea $50000,a3
move.w #$6000,d2
move.l #123,$30(a3,d2.w) ; kopiert 123 in $56030
*
lea $33000,a1
move.w #$2000,a2
move.l #123,$10(a1,a2.w) ; kopiert 123 in $35010
*
lea $33000,a1
lea $20010,a2
move.l #123,-$10(a1,a2.l) ; kopiert 123 in $53000
** ** ** ** ** ** ** ** ** ** **
; ADRESSIERUNGEN RELATIV ZUM PC (mit automatischem Offset)
Diese Art der Adressierungen werden vom ASMONE automatisch in Ordnung
gebracht, sie werden unbemerkt übergangen: z.B. schaut euch den
Unterschied zwischen diesen beiden Anweisungen an:
MOVE.L LABEL1,d0 ; ABSOLUTE ADRESSE
MOVE.L LABEL1(PC),d0 ; ADRESSE RELATIV ZUM PC
Diese beiden Anweisungen tun das Geliche, aber die mit dem (PC) ist kürzer
und schneller als die Erste. Sie ist relativ zum PC, denn die basiert auf
einer Adressierungs-Distanz (Offset) in Bezug auf das PC-Register, dem
PROGRAM COUNTER, das ist das Register, in dem der 68000 Buch führt, wo er
gerade mit der Ausführung ist. Das Offset wird automatisch von Assembler
errechnet, und im Speicher landet dann gleich schon das richtige Offset,
um sich zwischen den Label und anderen Anweisungen richtig zu orientieren.
Die Instruktion enthält nun nicht mehr die Adresse der Label, sondern die
Anzahl der Bytes, die die Entfernung davon nach vorne/hinten angeben. Der
Unterschied ist klar: wenn wir den ganzen Code in eine andere
Speicherregion verlegen, dann verschieben sich die absoluten Adressen, die
Distanzen zwischen den Labels und den (PC)-Befehlen aber bleibt gleich
groß, deswegen "funktioniert" diese Methode immer, während ein nicht zum
PC-relatives Programm, wenn an einen anderen Ort im Speicher versetzt,
alles in Chaos stürzt. Denn ein move.l LABEL1,d0 wird als (angenommen)
MOVE.L $23000,d0 übersetzt, also befindet sich das Label auf Adresse
$23000. Wenn wir nun das ganze Programm, das z.B. bei $20000 startete und
bei $25000 endete, um $10000 nach vorne verschieben, dann werden bei der
Ausführung nicht indifferente Fehler auftreten, da sich ein MOVE.L
$23000,d0 nicht mehr auf LABEL1 bezieht, das liegt jetzt ja auf $33000!
Aber wenn der Code vollständig relativ zum PC erstellt wurde, dann hätte
sich das MOVE immer auf das Label bezogen, also auf $33000, da es die -
immer gleichbelibende -Distanz zum Label berechnet hätte. Auch Befehle wie
BRA, BSR, BNE, BEQ sind relativ zum PC, ein BSR.W ROUTINE1 wird im
Speicher z.B. als BSR (50 Bytes weiter vorne) assembliert, und nicht BSR
$30000. Adressen werden von Befehlen assembliert, die äquivalent zum BSR
sind, wie etwa JSR: ein JSR LABEL1 wird mit der Adresse von Label1
assembliert, genauso ein wird JMP (SPRINGE-Äquivalent zum BRA) die REALE
ADRESSE von LABLE1 bekommen. Aber wieso wird nicht immer einfach eine
Adressierung relativ zum PC vorgezogen, also ein BSR einem JSR? Weil die
Adressierungen mit PC das Limit haben, sich nur auf Adressen beziehen zu
können, die maximal 32767 Bytes nach vorne oder -32768 Bytes nach hinten
liegen. Für weiter entfernte Label müssen Move mit absoluter Adresse oder
JSR/JMP eingesetzt werden. Aber, wie schon gesagt, werden all diese
Rechenaufgaben vom Assembler übernommen, deswegen interessieren sie uns
nicht, wir müssen uns nur erinnern, DAß WENN MÖGLICH, IMMER ein (PC)
gesetzt werden sollte, und BSR und BRA an Stelle von JSR und JMP verwendet
werden sollten. Sollte die Distanz zu groß sein, dann meldet der Assembler
einen Fehler, und wir müssen das (PC) entfernen oder schlimmstenfalls das
BRA/BSR durch JMP/JSR ersetzen, das die größten Entfernungen erreichen
kann. Man könnte auch nur mit JMP/JSR und ohne (PC) programmieren, aber
der Code würde länger und um einen Augenblick langsamer erscheinen,
deswegen ist immer besser, alles so gut als möglich zu machen!!! Das
Problem der RELOCATION, also des Verschiebens im Speicher, wird vom
Betriebssystem übernommen: wenn wir unser Programm mit WO als Ausführbares
abspeichern, dann speichern wir ein File ab, das von der Shell aus
aufgerufen werden kann, indem man seinen Namen eingibt. Das Betriebssystem
kümmert sich dann darum, es an einen freien Platz im Speicher zu geben,
der irgendwo sein kann, und reallociert (A.d.Ü: tut mir leid, mir fällt
für ALLOCATE kein deutsches Wort ein. Es bedeutet soviel wie "ansiedeln",
"zuteilen", "anweisen". Wer einen Deutsche Ausdruck kennt, bitte
"Readme.Deutsch" lesen!) das Programm, es passt also die Adressen der JSR
und der nicht zum PC relativen Move an, um den neuen Gegebenheiten (andere
Adressen) zu entprechen. Deswegen kann man auch programmieren, ohne sich
den Kopf darüber zu zerbrechen, überall die (PC) für Labels zu setzen, die
sich in anderen SECTIONS befinden: z.B. die COPPERLIST befindet sich in
einer anderen SECTION, und sie kann nur geändert werden, wenn man ohne
(PC) arbeitet, weil das Betriebssystem die Sektionen auf unvorhersehbare
Distanzen setzt (allocate...), die vielleicht sogar größer sind als 32768,
also dem LIMIT der RC-Realtiven Adressierung.
BEISPIELE FÜR PC-RELATIVE ADRESSIERUNGEN:
MOVE.L LABEL1(PC),LABEL2 ; Bemerkung: man kann das (PC) nicht
; für Labels verwenden, die als Ziel
; stehen!
; move.l a0,LABEL(PC) ist ein Fehler!
ADD.L LABELBAU(PC),d0 ; Geht weil das Label die QUELLE ist
SUB.L #500,LABEL ; KEIN PC, WEIL HIER DAS LABEL
; EIN ZIEL IST
CLR.L LABEL ; hier kann kein PC gesetzt werden.
; Praktisch kann man ein (PC) nur
; einsetzen, wenn es vor einem
; Beistrich steht!
; ADRESSIERUNGEN RELATIV ZUM PC MIT OFFSET UND INDEX
Diese Adressierung ist das Gleiche wie vorhin, nur mit INDEX, also einem
Register, das zum (PC) und zum Offset summiert wird, genauso wie es beim
Offset+Index mit Adressregistern geschieht:
MOVE.L LABEL1(PC,d0.w),LABEL2 ; Wie die PC-Adressierung, nur muß
; noch das Word in d0 dazugezählt
; werden, wir beziehen uns also nicht
; auf LABEL1, sondern auf ein Label,
; das d0 von LABEL1 entfernt ist.
ADD.L LABELWAU(PC,a0.l),d0 ; Wie vorher, a0.l wird als Index
; verwendet.
Das ist alles, was die Adressierungen angeht.
** ** ** ** ** ** ** ** ** ** **
GEBRÄUCHLICHSTEN BEFEHLE:
MOVE.x QUELLE,ZIEL ; Kopiert ein Byte, ein Word oder
; ein Longword
LEA Adresse,Ax ; Ladet eine Adresse: Diese Anweisung
; kann nur mit Adressregistern verwendet
; werden. Sie dient dazu, die entsprechende
; Adresse (sei sie nun in Form eines Label
; oder einer Zahl gegeben, z.B. $50000)
; ins Register zu geben.
; Das gleiche wie : MOVE.L #Adresse,a0
; aber schneller!
CLR.x Ziel ; Dieser Befehl löscht das Ziel
; (setzt es auf 0) CLR = CLEAR = "REINIGE"
BEDINGTE SPRÜNGE MIT EINEM TST, BTST, CMP
CMP.x Quelle, Ziel ; Vergleicht zwei Operanden, die ein
; Label oder ein Register sein können, oder
; sonst eine absolute Zahl (#) mit einem
; Register uvm. POITIVES Ergebnis, wenn die
; zwei Operanden GLEICH sind (für folgende
; BEQ/BNE)
TST.x Register.Label/Adresse ; Kontrolliert, ob der fragliche
; Operand gleich NULL ist, wenn ja,
; Positives Ergebnis
BTST #x,Adresse/Dx ; Kontrolliert, ob Bit x der Adresse
; auf NULL steht; wenn ja POSITIVES
; Ergebnis. Man kann ein BTST auch auf
; ein Datenregister ausführen, in diesem
; Fall ist ein Test auf einem der 32 möglichen
; Bits (0-31) erlaubt. Wird das BTST auf eine
; Speicherzelle angewandt, so muß man sich mit
; einem Byte (0-7) begnügen.
Sofort nach dem CMP, TST oder BTST steht immer ein BNE, ein BEQ oder ein
anderer, ähnlicher Befehl. Im Falle des BNE oder des BEQ kann man
Verzweigungen oder konditionierte Sprünge vom TST/CMP aus machen. DIE
BEW/BNE/BSR/BRA können sowohl .w wie auch .b sein, jenachdem, wie weit die
Routine vom Aufrufenden Befehl entfernt ist. Wenn sie sehr nahe liegen,
kann auch ein .b verwendet werden, das oft als .s geschrieben wird. Es ist
das Gleiche (s= SHORT, -> KURZ).
BSR.x label ; Führe die Routine LABEL aus, und wenn
; du auf ein RTS am Ende der Routine stößt,
; dann kehre zurück.
BEQ.x label ; Wenn das Resultat der vorherigen Abfrage
; POSITIV war, dann springe zum Label
; (DANACH ABER KEHRE NICHT ZURÜCK, WIE IM
; FALLE DES BSR, HIER WIRD GEWÄHLT ZWISCHEN
; SPRINGEN ODER NICHT
BNE.x label ; Wenn das Resultat NICHT positiv war,
; dann springe zum Label
; (DANACH ABER KEHRE NICHT ZURÜCK, WIE IM
; FALLE DES BSR, HIER WIRD GEWÄHLT ZWISCHEN
; SPRINGEN ODER NICHT
BRA.x label ; Springe IMMER zum Label (wie JMP)
ADD.x Operand1,Ziel ; Mit diesem Befehl wird ein Wert zum
; Ziel addiert
SUB.x Operand1,Ziel ; Mit diesem Befehl wird ein Wert
; von Ziel subtrahiert
SWAP Dx ; Vertauscht die 2 Words des Longwords
; in einem DATENREGISTER, braucht kein
; .B, .W oder .L
SWAP kommt aus dem Englichen (Wunder, Wunder), und bedeutet "Vertausche",
in der Tat vertauscht es die zwei Words, aus dem ein Longword besteht:
MOVE.L #HUNDMAUS,d0 ; in d0 kommt das Longword HUNDMAUS
SWAP d0 ; Wir vertauschen die Words: in d0
; steht jetzt MAUSHUND !!!!
*
Bemerkung: Es existieren Anweisungen, die den Adressregistern gewidmet
sind: z.B. müssen wir CMPA.W d0,a0 schreiben und nicht CMP.W d0,a0,auf die
gleiche Art und Weise ADDA.W a2,a0 und nicht ADD.W a2,a0. Für Konstanten
hingegen (#xxxx) müssen wir CMPI.x #10,d0 verwenden, und nicht CMP.x
#10,d0. Genauso SUBI.x #123,d2 und nicht SUB.x #123,d2, aber der ASMONE
assembliert immer AUTOMATISCH die richtige Anweisung, auch wenn wir nur
cmp/add/sub schreiben. Also, keine Sorgen, wenn in einem Listing einmal
CMPI auftaucht, weiter unten dann CMP alleine, oder adda und add, weil der
ASMONE immer alles zum Rechten biegt. Zum Testen assembliert die folgenden
Zeilen und disassembliert mit "D PROBE", der ASMONE wird nach den Regeln
assemblieren.
PROBE:
CMP.W d0,a0
ADD.W a1,a2
SUB.L #123,$10000
CMP.b #20,d4
Wird so assembliert werden:
CMPA.W D0,A0
ADDA.W A1,A2
SUBI.L #$0000007B,$00010000
CMPI.B #$14,D4
- - -
Bemerkung2: Gewisse Instruktionen, die das gleiche tun, können auf
verschiedene Weise geschrieben werden: z.B. hat der 68000er Befehle, die
bestimmten Situationen angepasst sind, und dort schneller sind:
1) ADDQ.x #Zahl,Ziel ; Der Befehl ADDQ.x kann für Additionen
; verwendet werden, dessen Zahlen kleiner
; sind als 8 (Q = Quick, "Schnell")
2) SUBQ.x #Zahl,Ziel ; Der Befehl SUBQ.x kann für Subtraktionen
; mit Zahlen von 1 bis 8 verwendet werde,
; (wie oben...)
3) MOVEQ #Zahl,dx ; Das MOVEQ kann dazu verwendet werden, um
; das MOVE.L #Zahl,d0 zu ersetzen, wobei
; Zahl zwischen -128 und +127 liegen muß.
; Das MoveQ ist immer .L, deswegen braucht
; es kein .B, .W oder .L.