home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
coders
/
assembler-kurs
/
lektionen
/
lektion3.txt
< prev
next >
Wrap
Text File
|
1977-12-31
|
26KB
|
542 lines
ASSEMBLERKURS - LEKTION 3
Nun fahren wir mit der Praxis fort, ich rate euch vorher aber, 68000.TXT
in einen Textbuffer zu laden, es ist eine Art Zusammenfassung von
Lektion2. Diese wird euch nützlich sein, wenn ihr eine Adressierungsart
vergessen habt oder mit einem Befehl nichts mehr anzufangen wißt, da diese
Lektion eine gewisse Vertrautheit mit ihnen voraussetzt. In diesem Text
sind alle Adressierungen erklärt, auch jene, die nur sehr selten verwendet
werden, deswegen lest ihn aber sorgt euch nicht, wenn ihr einige Dinge
nicht versteht, wie z.B. die Adressierung mit INDEX, denn in Lektion3 wird
sie noch nicht verwendet!
In diesem Kapitel beginnen wir damit, etwas auf dem Bildschirm
darzustellen: um das zu erreichen, müssen wir eine COPPERLIST schreiben,
das ist ein Programm für den COPPER-Chip, dem Typen, der dir Grafik
steuert, wir haben ihn bereits verwendet, um die Bildschirmfarbe zu ändern
($dff180 ist ein Register des Copper, das COLOR0 heißt). Bis jetzt aber
haben wir die Register nur direkt mittels Prozessor angesprochen, und wie
ihr beim Debuggen der Listings bemerkt haben werdet, sind nur kurze
"Lichtblitze" in der Farbe aufgetreten, die wir hineinschrieben, sofort
aber ersetzte die Farbe des Betriebssystemes, oder des ASMONE, unsere
eigene. Nur in einer Schleife, bei der dauernd eine Zahl in das Register
geschieben wurde, schafften wir es, den ganzen Bildschirm zu färben, aber,
kaum aus dem Programm ausgestieben, kehrt erbarmungslos der alte Zustand
zurück. Das ist darauf zurückzuführen, daß alles, was wir auf dem
Bildschirm sehen - Fenster, Schriften und der Rest - ist das Ergebnis
einer COPPERLIST, genauer einer SYSTEM-COPPERLIST. Diese ist nichts
anderes als eine Art:
MOVE.W #$123,dff180 ; COLOR0 - Beschreibe Farbe 0
MOVE.W #$456,dff182 ; COLOR1 - Beschreibe Farbe 1
etc....
Diese wird dauernd ausgeführt, und hier liegt auch die Erklärung, warum
die System-Farbe sofort zurückkehrt, wenn nur mit dem Prozessor in die
Register schreiben: weil die Copperlist jede 1/50 Sekunde alle Farben neu
definiert!!! Nun werdet ihr ahnen, daß es schier unmöglich sein wird, eine
Figur in Ruhe und Frieden auf den Bildschirm zu bringen, wenn man dauernd
mit der Copperlist des Betriebssystemes zu kämpfen hat, die dauernd alles
umdefiniert. Wir müßten unsere eigene Copperlist erstellen und sie mit der
des Systemes ersetzen... NICHTS LEICHTER ALS DAS! Wie ich schon
prophezeiht habe, ist die Copperlist nichts anderes als eine Schlange von
MOVE, die Werte in die Register des Copper geben, also den
$dffxxx-Registern. Diese Move aber werden nicht vom Prozessor, sondern vom
Copper selbst gemacht, der unabhängig vom Prozessor läuft und den für
andere Sachen freihält... das ist einer der Gründe, wieso sie auf PC nicht
LIONHEART oder PROJECT X des Amiga haben. Wir müssen ihm also wirklich ein
Listing schreiben, wie wir es vom 68000er her kennen, und danach den
Copper darüber informieren, wo es sich befindet und es ihn an Stelle der
Workbench-Copperlist ausführen lassen. Der Copper besitzt nur 3 Befehle,
wovon in der Praxis nur zwei verwendet werden: diese sind ein MOVE und ein
WAIT; derjenige, den niemand verwendet, ist das SKIP, deswegen behandeln
wir es nur, wenn wir ein Listing damit finden.
Das MOVE ist kinderleicht: könnt ihr euch an das erinnern ? :
MOVE.W #$123,dff180 ; Gib die Farbe RGB in COLOR0
Gut, in Copperlist schaut das so aus:
dc.w $180,$123 ; die Zahlen werden direkt mit dc.w
; in den Speicher gegeben, aber wir
; müssen ja nur zwei Befehle lernen!!
Das heißt, man muß zuerst die Adresse angeben, in die der Wert kommt (ohne
dem $dff, so wie wir es schon gesehen haben wenn wir in a0 $dff180 gegeben
haben: $180(a0). Genauso haben die Entwickler daran gedacht, uns das
dauernde $dff zu ersparen, und so reicht es, wenn wir $180 oder $182 oder
was auch immer, schreiben. Hauptsache, wir beschreiben nur Copperregister,
denn nur Register des COPPER können mit der COPPERLIST angesteuert
werden!! Weiters darf nur auf GERADE Adressen zugegriffen werden, wie
$180, $182 ..., NIE $181, $179 etc, weiters können nur WORD verwendet
werden. Wie ihr seht, wird die COPPERLIST nicht auf die gleiche Art
assembliert wie die Instruktionen des 68000, bei denen aus Befehlen wie
RTS, MOVE... $4e75 usw. wird, sondern es müssen die BYTES so in den
Speicher gelegt werden, wie sie der Coprozessor Copper lesen kann. Deshalb
verwenden wir das DC, um Byte für Byte die Befehle hineinzuschreiben, aber
es ist sehr einfach! Z.B. um die ersten vier Farben zu definieren:
COPPERLIST:
dc.w $180,$000 ; COLOR0 = SCHWARZ
dc.w $182,$f00 ; COLOR1 = ROT
dc.w $184,$0f0 ; COLOR2 = GRÜN
dc.w $186,$00f ; COLOR3 = BLAU
Erinnert ihr euchm wie das Farbformat aussieht? RGB = RED , GREEN, BLUE.
Um einen Kommentar über die $dffxxx - Register zu erhalten, könnt ihr
jederzeit "=C" schreiben, oder, speziell Z.B. für $dff180 "=C 180", und
ihr werdet eine Zusammenfassung in englisch bekommen. Probiert z.B. "=C
006" und ihr werdet Namen und Erklärung über dieses Register bekommen, das
ihr verwendet habt, um den Bildschirm zum Blinken zu bringen. Um alle
Register zu sehen, "=C".
Das WAIT hingegen dient dazu, eine bestimmte Zeile abzuwarten, wenn man
z.B. die Hintergrundfarbe (COLOR0) bis zur Hälfte des Bildschirmes
schwarz, und von da ab blau machen möchte, dann sieht das so aus:
dc.w $180,0 ; COLOR0 Schwarz
gefolgt von einem WAIT, das die Mitte des Bildschirmes abwartet, und dann
dc.w $180,$00F ; COLOR0 Blau
Mit dieser Strategie kann man die ganze Palette (die Farbliste) in jeder
Bildschrirmzeile verändern, von so was können die PC mit VGA nur träumen,
denn in der Tat haben die meisten Amiga-Spiele nur Screens mit 32 Farben,
aber durch ändern der Farbpalette hie und da, z.B. wenn das Spielfeld nach
unten scrollt, kann man mehr Farben erzeugen als eine VGA mit 256 Farben.
Vor allem wenn man in Betrachtung zieht, daß man einen Farbverlauf im
Hintergrund erzeugen kann, indem man bei jeder Bildschirmzeile Farbe
wechselt, und das wird unser erstes Programm in dieser Lektion sein. Der
WAIT-Befehl präsentiert sich so:
dc.w $1007,$FFFE ; WAIT Koordinate X = $10, Y = $07
Dieser Befehl bedeutet: WARTE DIE HORIZONTALE LINIE $10 AB, SPALTE 7 (also
der siebte Punkt von links, diese "Punkte" werden Pixel genannt). Das
$FFFE steht für WAIT, es muß immer gesetzt werden, während das erste Byte
die horizontale Linie (x) ist, die es abzuwarten gilt, und das zweite Byte
die Vertikale (y). Der Bildschirm besteht aus vielen kleinen Punkten, die
alle aneinander gereiht sind, wie ein Blatt Papier mit kleinen Kästchen,
Millimeterpapier in etwa. Um den Punkt (Pixel) an Position 16,7
anzupeilen, also der 16. Punkt vom oberen Rand und der 7. vom linken Rand
nach rechts, werden wir $1007 ($10 = 16!) schreiben. Wie bei Schiffe
versenken! Normalerweise gibt man nur die horizontale Linie an ihrem
Anfang an, der ist $07 statt $01, weil der Rest über dem linken Rand des
Monitors liegt. Der WAIT-Befehl wird auch dazu verwendet, das Ende der
Copperlist zu kennzeichnen. Am Ende der COP setzt man ein
dc.w $FFFF,$FFFE ; Ende Copperlist
Dies interpretiert der Copper per Definition als Ende, auch weil es
bedeuten würde, eine Linie abzuwarten, die es nicht gibt! Die Copperlist
startet dann von vorne. Es hat sich auch rumgesprochen, daß bei einigen
älteren Amigamodellen zwei abschließende Instruktionen nötig seien, aber
es scheint eine Art von Massenpsychose zu sein, da niemand jemals zwei
verwendet hat und alles immer funktionierte.
Um unsere Copperlist zu schreiben, die am Anfang noch ohne Bilder sein
wird, lediglich mit einigen Farbverläufen, müssen wir die BITPLANE
abschalten, also die aus Bits bestehenden "Ebenen", die übereinander
gelegt die Bilder erzeugen. Um da zu erreichen, setzen wir am Anfang ein
DC.W $100,$200 ein, wir geben also den Wert $200 ins Register $dff200, das
das Kontrollregister der Bitplane ist.
NUN SIND WIR IMSTANDE, EINE VOLLSTÄNDIGE COPPERLIST ZU SCHREIBEN, DIE BIS
MITTE BILDSCHIRM GEHT UND DANN FARBE WECHSELT!
Copperlist:
dc.w $100,$200 ; BPLCON0 Keine Bilder, nur Hintergrund
dc.w $180,0 ; COLOR0 Schwarz (Hintergrund)
dc.w $7f07,$FFFE ; WAIT - warte Linie $7f ab (127)
dc.w $180,$00f ; COLOR0 Blau
dc.w $FFFF,$FFFE ; ENDE DER COPPERLIST
Wenn man bedenkt, daß ihr die Funktionstüchtigkeit eurer Copperlisten
überprüfen wollen werdet, hier eine TABELLE ZUM NACHSCHLAGEN DER FARBEN
DES COPPER:
Der Amiga besitzt 32 Register für dementsprechend vielen verschiedenen
Farben:
$dff180 ; COLOR0 (Hintergrund)
$dff182 ; COLOR1
$dff184 ; COLOR2
$dff186 ; COLOR3
...
$dff1be ; COLOR31
In jedes dieser Register kann eine der 4096 möglichen Farben kommen, die
durch Mischen der drei Grundfarben Rot, Grün und Blau zustande kommen
können. Jede dieser Farben kann eine Intensität von 0 bis 15 haben, also
16 "Helligkeitsstufen". Nachgerechnet ergibt sich aus allen möglichen
Kombinationen, 16*16*16=4096, eben die Anzahl der darstellbaren Farben (16
Farbtöne Rot, 16 von Grün und 16 von Blau). Den Wert der Farbe kann man
entweder mit dem Prozessor oder mit dem Copper eingeben:
move.w #$000,$dff180 ; Farbe SCHWARZ in COLOR0
dc.w $180,$FFF ; Farbe WEIß in COLOR0
In diesem Beispiel haben wir die zwei Extremwerte gesehen: $FFF, gleich
Weiß, und $000, Schwarz. Um die Farbe zu wählen muß man bedenken, daß das
WORD der Farbe so aufgebaut ist:
dc.w $0RGB
wobei die vierte 0 (ganz links) nicht verwendet wird, und gilt:
R = ROT -Komponente der Farbe (RED)
G = GRÜN-Komponente der Farbe (GREEN)
B = BLAU-Komponente der Farbe (BLUE)
Die Bit vom 15 bis zum 12 sind nicht verwendet, die Bit von 11 bis 8
stellen den Rotanteil dar, Bit 7 bis Bit 4 den Grünanteil und Bit 4 bis
Bit 0 den Blauanteil.
Jede RGB-Farbe kann einen Wert von 0 bis 15 haben, also von $0 bis $15 in
Hexadezimal, es ist also leicht eine Farbe auszuwählen:
$FFF = Weiß
$D00 = Ziegelrot
$F00 = Rot
$F80 = Rot-Orange
$F90 = Orange
$fb0 = Goldgelb
$fd0 = Cadmiumgelb
$FF0 = Zitrone
$8e0 = Hellgrün
$0f0 = Grün
$2c0 = Dunkelgrün
$0b1 = Baumgrün
$0db = Wasser
$1fb = Wasser Hell
$6fe = Himmelblau
$6ce = Helles Blau
$00f = Blau
$61f = Brillantes Blau
$06d = Dunkelblau
$c1f = Violett
$fac = Rosa
$db9 = Beige
$c80 = Braun
$a87 = Dunkelbraun
$999 = Mittelgrau
$000 = Schwarz
Nun ist das einzige Problem, den Copper dazu zu zwingen, unsere Copperlist
auszuführen und die der Workbench bei Seite zu lassen. Aber da gibt´s noch
ein anderes Problem: wenn wir unsere eigene ausführen lssen, wie schaffen
wir es dann, den Orginalzustand wiederherzustellen? Antwort: Man muß auf
ein Zettelchen aufschreiben, wo sie war!!! Oder anders: Wir schreiben in
ein bestimmtes Longword die Adresse, an der sie zu finden ist. Wir werden
dieses Longword OLDCOP nennen, also ALTE COPPERLIST, die des Systemes.
Aber wen müssen wir fragen, um zu wissen, wo sich die Copperlist des
Systemes befindet? Das Betriebssystem natürlich!!! Um es das zu fragen,
müssen wir eine Routine aus dem CHIP des Kickstart ausführen! Um das zu
tun, müssen wir immer als Bezug die Adresse nehmen, die in Adresse $4
steht. Diese wird vom Kickstart geschrieben und enthält die Adresse, ab
der wir unsere AdressierungsDistanzen (Offsetes) machen müssen. Diese sind
vordefiniert, wir werden später darüber plaudern. Um das Long der Adresse
$4 aufzusammeln, reicht ein:
MOVE.L $4,a6 ; In a6 haben wir nun die ExecBase
Oder besser:
MOVE.L 4.w,a6 ; 4 ist eine kleine Zahl, deswegen kann 4.w
; geschrieben werden, was Platz spart.
; Es wird also $0004 statt $00000004 geschrieben,
; bei dem die ersten vier Nullen nicht gebraucht
; werden. VERSCHOBEN WIRD ABER IMMER EIN LONGWORD!
; Also das Long, das in Adresse 4, 5, 6 und 7
; enthalten ist.
Ist einmal die Adresse, die in $4 enthalten war, in a6 kopiert, können wir
darangehen, die Routinen des Kickis auszuführen, indem wir JSR verwenden,
kombiniert mit der richtigen Distanz (Offset), denn es existieren ganz
exakte Distanzen, die gewissen Routinen entsprechen. Nun wissen wir, daß
z.B. mit einem JSR -$78(a6) das Multitasking abgeschalten wird!!! Es wird
also nur unser Programm ausgeführt, nix anderes! Sofort testen! Ladet
Listing3a.s in einen Buffer und startet es. Aber die Exec kümmert sich
nicht um alles: der Kickstart, 256kB lang, wenn es sich um die Versionen
1.2 oder 1.3 handelt, oder 512k bei V2.0 und V3.0, ist in Libraries
aufgeteilt, eine Art "Sammlung" von Routinen, die schon fertig sind und
aufgerufen werden können. Und da jeder Kickstart anders ist, ja richtig
hardwaremäßig, im Sinne daß die Routine, die das Multitasking abschaltet,
im Kick 1.3 z.B. auf Adresse $fc1000 liegen könnte, während sie bei
anderen Versionen irgendwo anders im Speicher sein könnte, haben die
lieben Erbauer des Amiga eine ihrer wunderbaren Geistesblitze gehabt:
"WARUM GEBEN WIR IN SPEICHERZELLE 4 NICHT EINE ADRESSE, VON DER AUS MAN
IMMER DIE GLEICHEN ROUTINEN AUSFÜHREN KANN, WENN MAN MIT EINEM JSR EINEN
BESTIMMTEN OFFSET ANSPRINGT?" (P.S. JSR ist das gleiche wie BSR, nur kann
ein JSR Routinen im gesamten Speicher anspringen, während das BSR nur
innherhalb 32768 Bytes nach vorne oder hinten operieren kann).
Und das haben sie getan! Um z.B. das Disable, also das Multitasking
killen, auszuführen, wird auf jedem Kickstart folgendes getan:
move.l 4.w,a6 ; Adresse der Exec in a6
jsr -$78(a6) ; Disable - blockiert Multitasking
bsr.w MeinProgramm
jsr -$7e(a6) ; Enabel -schaltet Multitasking wieder ein
In jedem Kickstart liegt die Routine auf einer anderen Adresse, aber mit
dieser Methode sind wir sicher, daß wir immer diese ausführen. Man muß nur
alle Offsets der verschiedenen Routinen kennen, und das Spiel ist gemacht.
Uns interessiert aber nur, die Copperlist des Betriebssystemes
abzuspeichern, und um das zu schaffen, müssen wir und an eine Routine des
Kick wenden, die Graphics.library heißt. Es ist die, die sich mit der
Graphic befaßt, aber nur unter dem Betriebssystem, das sei klar, nicht auf
Hardwareebene. Um auf diese Bibliothek (Library) zugreifen zu können,
müssen wir sie zuerst öffnen:
move.l 4.w,a6 ; ExecBase in a6 schreiben
lea GfxName,a1 ; Adresse des Namens der Library, die
; es zu öffnen gilt, in a1
JSR -$198(a6) ; OpenLibrary, Routine der Exec, die
; eine Bibliothek öffnet, und als Resultat
; die Basisadresse dieser zurückliefert
; (in d0), ab
; welcher wir die Offsets ansetzen müssen.
move.l d0,GfxBase ; Speichere die Basisadresse der Gfx in
... ; GfxBase
...
GfxBase:
dc.b "graphics.library",0,0 ; BEMERKUNG: Um Charakter, also
; Buchstaben, in den Speicher zu
; geben, verwenden wir immer das
; dc.b und setzen sie unter ""oder´´
GfxBase:
dc.l 0
In diesem Fall haben wir die Routine der Exec verwendet, die Bibliotheken
öffnet, die "OpenLibrary". Sie verlangt, daß in a1 die Adresse steht, an
der der Text mit dem Name der zu öffnenden Library zu finden ist. Wir
hätten z.B. auch die "dos.library" öffnen können, um mit Files umzugehen,
oder "intuition.library" für die Fenster, Screens etc. Einmal ausgeführt,
liefert OpenLibrary in d0 die Basisadresse der gefragten Bibliothek., um
uns zu verstehen, eine Adresse wie GfxBase, ab der wir dann mit JSR unsere
Offsets machen, um die verschiedensten Routinen anzuspringen, die mit der
Grafik zu tun haben. Außer den JSR wissen wir auch noch, daß die Adresse
der aktuellen COPPERLIST des Systemes auf $26 nach GfxBase leigt, also
fahren wir mit unserem Programm fort, indem wir diese Adresse in ein Label
(OLDCOP) abspeichern:
move.l 4.w,a6 ; ExecBase in a6 schreiben
lea GfxName,a1 ; Adresse des Namens der Library, die
; es zu öffnen gilt, in a1
JSR -$198(a6) ; OpenLibrary, Routine der Exec, die
; eine Bibliothek öffnet, und als Resultat
; die Basisadresse dieser in d0 zurückliefert,
; ab welcher wir die Offsets ansetzen müssen.
move.l d0,GfxBase ; Speichere die Basisadresse der Gfx in
; GfxBase
move.l d0,a6
move.l $26(a6),OldCop ; Nun speichern wir die Adresse der z.Z
; aktuellen System-Copper in OLDCOP ab
....
GfxName:
dc.b "graphics.library",0,0 ; BEMERKUNG: Um Charakter, also
; Buchstaben, in den Speicher zu
; geben, verwenden wir immer das
; dc.b und setzen sie unter ""oder´´
GfxBase:
dc.l 0
OldCop:
dc.l 0
Nun können wir unsere eigene Copperlist ansteuern, ein WaitMouse dazufügen
und dann wieder den alten Zustand herstellen; mit ansteuern meine ich, daß
wir die Adresse unserer Copperlist ins Register COP1LC geben, das ist das
$dff080, das der Zeiger auf die sie ist, d.h. der Copper führt die
Copperlist aus, deren Adresse sich im Register $dff080 befindet. Also,
einmal die Adresse unserer Copperlist in $dff080, müssen wir sie noch
"starten", indem wir ins Register $dff088 (COPJMP1) irgend einen Nonsens
schreiben, egal, ob wir hineinschreiben oder was rauslesen, denn da es ein
sog. STROBE-Register ist, reicht irgend eine Änderung, um es zu
aktivieren. Die Strobe-Register sind wie eine Art Knopf, der grade mal
berührt werden muß, um ausgelöst zu werden. Verwendet aber nicht CLR.W
$dff088, das gibt komischerweise Probleme. Nun wird unsere Liste bei jedem
Fotogramm ausgeführt, solange, bis in $dff080 nicht wieder eine andere
kommt (oder besser, deren Adresse...!). Ein Problem ist, daß $dff080 ein
NUR-SCHREIBE-REGISTER ist, probiert ein "=c 080" und ihr werdet das W
bemerken (WRITE). Um die alte Copperlist - die, die der Asmone oder die
Workbench verwendet- wieder an ihren Platz zu setzen, müssen wir das
Betriebssystem fragen, welche Adresse in $dff080 enthalten ist, da dieses
Register selbst ja nicht ausgelesen werden kann. Und dafür verwenden wir
die Routine des Kickstart. Wenn wir dann diese Adresse erhalten haben,
speichern wir sie in ein LONGWORD unseres Programmes, danach starten wir
unsere einene Copperlist, und am Ende des Programmes geben wir die
gespeicherte Adresse wieder in COP1LC ($dff080).
move.l 4.w,a6 ; ExecBase in a6 schreiben
JSR -78(a6) ; Disable - schaltet Multitasking aus
lea GfxName,a1 ; Adresse des Namens der Library, die
; es zu öffnen gilt, in a1
JSR -$198(a6) ; OpenLibrary, Routine der Exec, die
; eine Bibliothek öffnet, und als Resultat
; die Basisadresse dieser in d0 zurückliefert,
; ab welcher wir die Offsets ansetzen müssen.
move.l d0,GfxBase ; Speichere die Basisadresse der Gfx in
; GfxBase
move.l d0,a6
move.l $26(a6),OldCop ; Nun speichern wir die Adresse der z.Z
; aktuellen System-Copper in OLDCOP ab
move.l #COPPERLIST,$dff080 ; COP1LC-Wir zeigen auf unsere COP
move.w d0,$dff088 ; COPJMP1-Wir starten unsere COP,
; indem wir etwas hineinschreiben,
; z.B. d0
mouse:
btst #6,$bfe001
bne.s mouse
move.l OldCop(PC),$dff080 ; COP1LC - Wir zeigen auf die alte
; System-Copperlist
move.w d0,$dff088 ; COPJMP1 - und starten sie
move.l 4.w,a6
jsr -$7e(a6) ; Enable - schaltet Multitasking wieder ein
move.l GfxBase(PC),a1 ; Base der zu schließenden Bibliothek
; (Bibliotheken werden IMMER geschloßen!!!)
jsr -$19e(a6) ; Closelibrary - Schließt die graphics lib
rts
GfxName:
dc.b "graphics.library",0,0 ; BEMERKUNG: Um Charakter, also
; Buchstaben, in den Speicher zu
; geben, verwenden wir immer das
; dc.b und setzen sie unter ""oder´´
GfxBase:
dc.l 0
OldCop:
dc.l 0
COPPERLIST:
dc.w $100,$200 ; BPLCON0 - Keine Bilder, nur Hintergrund
dc.w $180,0 ; COLOR0 SCHWARZ
dc.w $7f07,$FFFE ; WAIT - Warte auf Zeile $7f (127)
dc.w $180,$00F ; COLOR0 BLAU
dc.w $FFFF,$FFFE ; ENDE DER COPPERLIST
Ihr werdet dieses Beispiel mit Vorschlägen und Änderungen in Listing3b.s
finden. Holt es in den Buffer mit F2 oder einem x-beliebigen anderen und
bestaunt das erste Programm aus dem Kurs, das den Chips des Amiga so
richtig "Power unterm Hintern" macht.
Habt ihr eure Experimente mit der Copperlist gemacht? Gut, nun versuchen
wir, einige bewegte Effekte zu erzeugen. Bevor wir aber anfangen muß ich
euch mitteilen, daß um irgend eine Bewegung zu machen, diese Routinen mit
dem Elektronenstrahl, der das Bild auf dem Monitor zeichnet,
synchronisiert werden müssen. Für die, die es noch nicht wissen, der
Bildschirm wird 50 Mal pro Sekunde neu gezeichnet, und die Bewegungen, die
uns flüssig erscheinen,z.B. die der besser programmierten Spiele, sind auf
diese fünfzigstel Sekunde angepaßt. Wir haben das Register $dff006 schon
verwende, das bekanntlich dauernd seinen Inhalt ändert. Aus gutem Grund,
es beinhaltet ja die Position des Elektronenstrahles auf dem Monitor, und
der düst mit 50 Seiten pro Sekunde durch die Gegend... Er startet bei 0,
also dem höchten Teil des Monitors, ganz oben, und durchläuft ihn bis ganz
unten. Wenn wir nun eine Routine schreiben, die Bewegungen auf den Schirm
bringt, ohne sie zu zeitlich anzupassen, ohne Timing, dann wird sie mit
der Geschwindigkeit des Prozessors laufen, also viel zu schnell um etwas
zu sehen. Um eine gewisse Zeile des Bildschirmes abzuwarten müssen wir nur
das erste Byte von $dff006 auslesen. In ihm steht die gerade erreichte
Zeile, also die vertikale Position (gleich dem WAIT des COPPER):
WaitZeile:
CMPI.B #$f0,$dff006 ; VHPOSR - Sind wir auf Zeile $f0 ? (240)
bne.s WaitZeile ; wenn nicht, kontrolliere nochmal
...
Dieser Zyklus wartet die Zeile 240 ab, und erst dann fährt er mit den
folgenden Befehlen fort, wie etwa die Routine, die auf einen Mausdruck
wartet. Fügen wir auch diesen Teil ein:
mouse:
CMPI.B #$f0,$dff006 ; VHPOSR - Sind wir auf Zeile $f0 ? (240)
bne.s mouse ; wenn nicht, kontrolliere nochmal
BSR.s RoutineMitTiming ; Diese Routine wird nur einmal
; pro Fotogramm ausgeführt
bsr.s MuoviCopper ; Die erste Bewegung am Bildschirm!!!!!
btst #6,$bfe001 ; linke Maustaste gedrückt?
bne.s mouse ; wenn nicht, zurück zu mouse:
rts
Jetzt haben wir eine Routine, die 1 Mal pro FRAME - oder Fotogramm -
ausgeführt wird, also 1 Mal alle 50stel Sekunden, und um genau zu sein,
wird sie jedesmal ausgeführt, wenn wir bei Zeile 240 angekommen sind, und
dann wird sie ruhen, bis wir erneut Zeile 240 erreichen, dem nächstem
FRAME.
Bemerkung: Die Bilder werden mit der RASTER-Technik gezeichnet, die mit
einem "ElektronenPinsel" links oben beginnt, nach rechts geht, bis zum
Ende der Zeile, dann wieder ganz links, Zeile 2, usw. bis er am Ende des
Bildschirms angekommen ist. Es ist mit dem Lesen vergleichbar: jede Zeile
von links nahc rechts, angefangen bei der ersten ganz oben bis runter zur
letzten auf der Seite, und DANN startet man wieder von vorne, so, als ob
wir vergessen hätten, Seite zu wechseln. Denn der Monitor ist ja auch nur
einer, und er muß nur auf dem einen Schirm schreiben, der Elektronenpinsel
malt ja nicht auf die Wand.
Ladet das Beispiel Listing3c.s in einen anderen Textbuffer und probiert es
aus. Dieses bewegt ein WAIT nach unten und somit die folgende Farbe, wenn
ihr die Maustaste drückt. Linke Taste zum Aussteigen.
Listing3c.s verstanden? Dann lassen wir es ein bißchen schwiereiger
werden! Ladet Listing3c2.s in einen Buffer und studiert es, ich habe eine
Zeilenkontrolle eingefügt, um den Scroll zu stoppen.
Alles klar in Listing3c2.s?? Gut, dann geht´s weiter mit der Praxis in
Listing 3c3.s, in der ein Balken mit 10 WAIT verschoben wird, anstatt nur
ein Wait alleine. Immer schwieriger!!!
Lebt ihr noch nach Listing3c3.s? Dann massakriert euer Hirn mit dem
nächsten Listing, dem Listing3c4.s, in der wir von 10 Label BALKEN auf ein
einziges umsteigen, und die Adressierungsdistanz verwenden.
Nun, es war ja nicht recht schwer, oder? Das Schwierige konne jetzt mit
Listing 3d.s, in dem der Balken rauf und runter geht, und wir werden auch
die Geschwindigkeit ändern.
Habt ihr Listing3d.s verstanden? Ja? Glaub ich nicht! Euch kommt nur vor,
ihr hättet verstanden... ich würde noch mal nachsehen, bevor ich
weitergehen würde...na, noch mal angeschaut? Tja...dann holt euch eine
Variante zum Thema rein mit Listing 3d2.s.
Nun seid ihr bereit, Listing3e.s in Angriff zu nehmen, in der erklärt
wird, wie man ein RASTERBAR herzaubert, also ein wiederholendes Fließen
der Farben.
Ein anderer Spezialfall: Wie erreiche ich die PAL-Zone (nach $FF) mit den
Wait des Copper. Soviel in Listing3f.s.
Um Lektion3.TXT abzuschließen, schaut euch Listing3g.s und Listing3h.s an,
bei dem ein Verlauf von Links nach Rechts statt von oben nach unten
erzielt wird. Danach seid ihr bereit, Lektion4.TXT durchzuackern. Dort
wird die Verwaltung von farbigen Bildern und die möglichen Effekte auf
ihnen behandelt!
Bemerkung: Die Beispiele 4x.s der Lektion4.TXT befinden sich in der
Directory Listings2, darum müßt ihr ein "V df0:Listings2" tippen, um die
Bilder in dieser Directory laden zu können. Danach ladet Lektion4.TXT in
diesen oder einen anderen Buffer (mit "r").
* Komplimente, daß ihr bis hier her gekommen seid! Das Größte ist
geschafft! Nun werden wir mit Leichtigkeit weitergehen, da wir in die
Logik der Assemblerprogrammierung eingestiegen sind!