home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
coders
/
assembler-kurs
/
listings
/
listing3b.s
< prev
next >
Wrap
Text File
|
1977-12-31
|
14KB
|
317 lines
; Listing3b.s ; DIE ERSTE COPPERLIST
SECTION ERSTECOP,CODE ; Dieser Befehl veranlasst das Betriebs-
; system, den folgenden Code in die
; Fast-Ram zu laden, wenn welche frei ist
; sonst in Chip-Ram
Anfang:
move.l 4.w,a6 ; Execbase in a6
jsr -$78(a6) ; Disable - stoppt das Multitasking
lea GfxName,a1 ; Adresse des Namen der zu öffnenden Library in a1
jsr -$198(a6) ; OpenLibrary, Routine der EXEC, die Libraris
; öffnet, und als Resultat in d0 die Basisadresse
; derselben Bibliothek liefert, ab welcher
; die Offsets (Distanzen) zu machen sind
move.l d0,GfxBase ; speichere diese Adresse in GfxBase
move.l d0,a6
move.l $26(a6),OldCop ; hier speichern wir die Adresse der Copperlist
; des Betriebssystemes (immer auf $26 nach
; GfxBase)
move.l #COPPERLIST,$dff080 ; COP1LC - "Zeiger" auf unsere COP
; (deren Adresse)
move.w d0,$dff088 ; COPJMP1 - Starten unsere COP
mouse:
btst #6,$bfe001 ; linke Maustaste gedrückt?
bne.s mouse ; wenn nicht, zurück zu mouse:
move.l OldCop(PC),$dff080 ; COP1LC - "Zeiger" auf die Orginal-COP
move.w d0,$dff088 ; COPJMP1 - und starten sie
move.l 4.w,a6
jsr -$7e(a6) ; Enable - stellt Multitasking wieder her
move.l GfxBase(PC),a1 ; Basis der Library, die es zu schließen gilt
; (Libraries werden geöffnet UND geschlossen!!)
jsr -$19e(a6) ; Closelibrary - schließt die Graphics lib
rts
GfxName:
dc.b "graphics.library",0,0 ; Bemerkung: um Charakter in den
; Speicher zu geben, verwenden wir
; immer das dc.b und setzen sie
; unter "" oder ´´, Abschluß mit ,0
GfxBase: ; Hier hinein kommt die Basisadresse der graphics.library,
dc.l 0 ; ab hier werden die Offsets gemacht
OldCop: ; Hier hinein kommt die Adresse der Orginal-Copperlist
dc.l 0 ; des Betriebssystemes
SECTION GRAPHIC,DATA_C ; Dieser Befehl veranlaßt das Betriebssystem,
; das folgende Datensegment in die CHIP-RAM
; zu laden, obligatorisch.
; Die Cpperlist MÜSSEN in die CHIP RAM!
COPPERLIST:
dc.w $100,$200 ; BPLCON0 - Kein Bild, nur Hintergrund
dc.w $180,$000 ; 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
end
Dieses Programm läßt unsere eigene Copperlist vom Copper "anpeilen", und
es kann verwendet werden, jede beliebige Copperlist anzusteuern, es eignet
sich also gut für Experimente mit dem Copper. Laßt euch nicht entmutigen,
weil ihr hier seht, daß Bibliotheken (Libraries) des Betriebssystemes
geöffent und geschlossen werden und ähnliches, da im ganzen Kurs nur die
Öffnung der Graphics.library zum rechtrücken der alten Copperlist und ein
paar andere Dinge sehen werdet. Es reicht also, wenn ihr diese paar Dinge
lernt. BEMERKUNG1: Wie ihr schon bemerkt haben werdet, enthält dieses
Listing den Befehl SECTION, das die Funktion hat, die HUNKS des
ausführbaren Files zu bestimmen, das ihr mit WO abspeichern werdet: Jedes
Programm, das ihr von der Shell aus starten könnt, wie auch der ASMONE
selbst, wird in die RAM gegeben, nachdem es von der Diskette oder Harddisk
gelesen wurde. Diese Aktion des Kopierens wird von den Hunks beeinflußt,
denn sie bestimmen, wohin das Programm geladen wird, ob in CHIP-RAM oder
ob es auch in Fast-RAM kommen kann. Ein File kann aus einem oder mehreren
Hunks bestehen, und jeder von ihnen hat seine Eigenschaften. Man muß den
Befehl SECTION verwenden, wenn man ein ausführbares Programm schreiben
will, das mit Copperlisten oder Tönen arbeitet, da diese Art von Daten
unbedingt in dir CHIP-RAM kommen muß. Wenn man das _C nicht spezifiziert,
dann wird der mit WO generierte File einen generellen Hunk besitzen, der
in jeden Typ von freiem Speicher geladen werden kann, sei es nun CHIP oder
FAST. Viele alte Demos oder sogar Demos für den A1200 funktionieren auf
Amigas mit Fast-Ram nicht, genau weil der Hunk in jeden beliebeigen
Speicher geladen werden kann, und das Betriebssystem dazu tendiert, zuerst
die Fast-Ram zu füllen, bevor es die kostbare Chip-Ram angreift:
Eindeutigerweise haben die Personen, die diese alten Spiele oder Demos
geschrieben haben, nur den A500 in der Grundversion mit 512kB Chip-Ram
besessen, ohne Fast, und die Programme funktionierten immer, weil sie wohl
oder übel immer im Chip landeten, das gleiche gilt für A500+ und A600, die
1MB Chip haben. Aber wenn diese Programme auf Computern mit FAST RAM
geladen werden, entstehen zufällige Töne und der Bildschirm spielt
verrückt, weil die CUSTOM-CHIPS nur auf CHIP-RAM zugreifen können.
Manchmal blockieren sie auch das ganze System. Die Syntax des Befehles
SECTION ist die folgende: nach dem Wort SECTION wird der Name dieser
Sektion geschrieben, irgend ein beliebiger Name. Danach wird angegeben, um
welchen Typ von Section es sich handelt: ob CODE oder DATA, also ob sie
aus Anweisungen oder Daten besteht. Der Unterschied aber ist nicht recht
wichtig, denn in der Tat nennen wir den ersten Teil dieses Listings CODE,
obwohl er auch Labels mit Texten enthält (dc.b 'graphics library'); dann
aber wird das wichtigste entschieden: ob dieser Teil in CHIP geladen
werden muß oder ob auch FAST gut geht. Wenn Chip-Ram unbedingt
erforderlich ist, dann hängen wir ein _C dem DATA oder CODE an, wenn nix
steht, dann ist er in allen Speichertypen willkommen.
SECTION FIGUREN,DATA_C ; Sektion von Daten, die in CHIP geladen werden
SECTION LISTENAMEN,DATA ; Sektion von Daten, die in CHIP oder FAST kommt
SECTION Program,CODE_C ; Sektion von Code, der in CHIP kommen muß
SECTION Program2,CODE ; Sektion von Code, der CHIP oder FAST recht ist
Lasst die erste SECTION immer CODE oder CODE_C sein, fangt natürlich mit
Anweisungen an, dann könnt iht Sektionen DATA oder DATA_C anfügen, worin
keine Befehle enthalten sind. Ein Beispiel:
SECTION Myprogram,CODE ; Kommt in CHIP oder FAST, ist egal
move...
move...
SECTION COPPER,DATA_C ; NUR in CHIP assemblierbar
dc.w $100,$200.... ; $0100,$0200, aber man kann die ersten
; Nullen weglassen, wenn wir z.B.
; dc.l $00000001 schreiben müßen, wird
; es praktischer sein, dc.l 1 zu
; schreiben, genauso kann ein dc.b $0a
; auch als dc.b $a geschrieben werden, im
; Speicher landet immer $0a
SECTION MUSIC,DATA_C ; NUR in CHIP assemblierbar
dc.b Pavarotti.....
SECTION FIGUREN,DATA_C ; NUR in CHIP!
dc.l ägyptische Pyramieden
END
Man kann auch nur eine große SECTION CODE_C erstellen, aber fragmentiert
die Grafic- und Sounddaten mindestens in Blöcke zu 50kB, so wird das
Programm leichter in die kleinen Speicherlöcher einordenbar sein als wenn
es ein einziger Block zu 300kB oder mehr ist. Weiters bedenkt, daß es
Schade ist, Anweisungen in Chip-Ram zu laden, da diese verbraucht wird,
und auch, weil sie in FAST-RAM erheblich schneller sind, vor allem auf den
Amigas mit 68020+ (bis zu 4 Mal schneller..!). Es existieren auch die
Section BSS und BSS_C, wir werden darüber reden, wenn wir sie verwenden.
BEMERKUNG2: Ihr werdet auch die Verwendung des (PC) bemerkt haben:
move.l OldCop(PC),$dff080 ; COP1LC - "Zeiger" auf orginale COP
Dieses angehängte (PC) nach dem Namen der Label ändert nichts an der
FUNKTION der Anweisung, denn wenn ihr z.B. das (PC) veglasst, passiert das
gleiche. Es ändert aber die FORM der Anweisung, denn versucht zu
assemblieren und ein D Mouse:
... BTST #$06,$00BFE001
... BNE.B $xxxxxxxx
23FA003400DFF080 MOVE.L $xxxxxx(PC),$00DFF080
... MOVE.W D0,$00DFF088
Seht ihr, daß das move.l OldCop(PC),$dff080 als $23fa... assembleirt wird.
Entfernt das (PC), assembliert und macht ein D Mouse:
23F900xxxxxx00DFF080 MOVE.L $xxxxxx,$00DFF080
Dieses Mal wird der Befehl in 10 Bytes anstatt in 8 assembliert, und das
$23f9... ist klar ersichtlich. Es bedeutet MOVE.L die Adresse von OldCop,
während im Falle von move.l mit PC der Befehl mit $23fa begann, und man
$34 an Stelle der Adresse von OldCop sieht! Der Unterschied ist der, daß
wenn ohne PC gearbeitet wird, das MOVE sich auf eine DEFINITIVE, absolute
Adresse bezieht, hingegen eine Anweisung mit PC schreibt statt der Adresse
die Distanz hin, die zwischen sich selbst und der geforderten Label
besteht: wenn der 68000 zum Move.L OLDCOP(PC) kommt, dann errechnet er
PC+$34 und erhält somit die Adresse von OldCop, die eben $34 Bytes weiter
vorne liegt. Diese Methode ist schneller und erspart, wie wir gesehen
haben, auch einige Bytes, sie kann aber nur für Label verwendet werden,
die nicht weiter entfernt sind als 32768 Bytes (wie beim BSR), und sie
kann nicht zwischen einer SECTION und der anderen verwendet werden, da
niemand genau weiß, wohin die Sections geladen werden, und wieweit sie
voneinander entfernt sind. Probiert z.B. zur Zeile LEA COPPERLIST(PC),a0
dazuzufügen, der ASMONE wird einen RELATIVE MODE ERROR melden, ohne dem PC
aber wird es keine Probleme geben. Ich rate euch, das (PC) immer den
Labels anzuhängen, wenn es möglich ist:
LEA LABEL(PC),a0
MOVE.L LABEL(PC),d0
MOVE.L LABEL1(PC),LABEL2 ; nur bei der ersten Label kann
; das (PC) stehen, bei der zweiten NIE!
MOVE.L #LABEL1,LABEL2 ; Hier kann man kein (PC) verwenden,
; denn beim ersten Operand hat es keinen
; Sinn und beim zweiten darf man es nicht
Modifizierungen: Nun könnt ihr jede beliebige Copperlist herstellen!
Beginnt damit, die ersten beiden Farben zu verändern. Ihr erinnert euch
das Format der Farben, $0RGB, in dem nur drei Zahlen (RGB) zählen, die
Stelle, wo die NULL steht, wird nicht genutzt. Jede der Stellen R, G und B
kann einen Wert zwischen 0 und 15 ($0 bis $F) erhalten, und je nach
Mischung diese drei Grundfarben kann man alle 4096 vom Amiga darstellbaren
Farben erzeugen (16*16*16=4096). Um Schwarz zu erhalten braucht es ein
$000, für Weiß $FFF, ein $999 ist grau. ACHTUNG: die Farben werden nicht
gemischt wie bei Öl- oder Wasserfarben! Z.B. um Gelb herzustellen braucht
es ROT + GRÜN, $dd0 in etwa, für ein Violett wird ROT und BLAU gemischt,
z.B. $d0e. Dieses Mixsystem ist das gleiche wie im Preferences der
Workbench oder in der Palette der Malprogramme wie DPaint, mit den drei
Reglern R,G und B. Einmal die Tests mit dem Farbwechsel del Copperlist
hinter euch, könnt ihr versuchen, Farbverläufe auf den Bildschirm zu
zaubern. Dazu müßt ihr weitere WAITs hinzufügen, gefolgt von anderen
Werten im COLOR0 ($180,xxx). Solche Farbverläufe werdet ihr aus Spielen
wir SHADOW OF THE BEAST kennen, oder aus Demos mit Balken: nun wißt ihr,
wie der Hase läuft! Tauscht mit Amiga+B+C+I diese Copperlist mit der im
Listing aus, schaut euch an, was sie tut, und gebt euren eigenen Senf
dazu, um sicher zu gehen, daß ihr alles verstanden habt:
COPPERLIST:
dc.w $100,$200 ; BPLCON0 - nur Hintergrund
dc.w $180,$000 ; COLOR0 - Beginne die Cop mit SCHWARZ
dc.w $4907,$FFFE ; WAIT - Warte auf Zeile $49 (73)
dc.w $180,$001 ; COLOR0 - Sehr dunkles Blau
dc.w $4a07,$FFFE ; WAIT - Zeile 74 ($4a)
dc.w $180,$002 ; COLOR0 - ein bißchen helleres Blau
dc.w $4b07,$FFFE ; WAIT - Zeile 75 ($4b)
dc.w $180,$003 ; COLOR0 - helleres Blau
dc.w $4c07,$FFFE ; WAIT - nächste Zeile
dc.w $180,$004 ; COLOR0 - noch helleres Blau
dc.w $4d07,$FFFE ; WAIT - nächste Zeile
dc.w $180,$005 ; COLOR0 - helleres Blau
dc.w $4e07,$FFFE ; WAIT - nächste Zeile
dc.w $180,$006 ; COLOR0 - Blau auf 6
dc.w $5007,$FFFE ; WAIT - überspringe 2 Zeilen:
; von $4e auf $50, also von 78 auf 80
dc.w $180,$007 ; COLOR0 - Blau auf 7
dc.w $5207,$FFFE ; WAIT - sato 2 Zeilen
dc.w $180,$008 ; COLOR0 - Blau auf 8
dc.w $5507,$FFFE ; WAIT - überspringe 3 Zeilen
dc.w $180,$009 ; COLOR0 - Blau auf 9
dc.w $5807,$FFFE ; WAIT - überspringe 3 Zeilen
dc.w $180,$00a ; COLOR0 - Blau auf 10
dc.w $5b07,$FFFE ; WAIT - überspringe 3 Zeilen
dc.w $180,$00b ; COLOR0 - Blau auf 11
dc.w $5e07,$FFFE ; WAIT - überspringe 3 Zeilen
dc.w $180,$00c ; COLOR0 - Blau auf 12
dc.w $6207,$FFFE ; WAIT - überspringe 4 Zeilen
dc.w $180,$00d ; COLOR0 - Blau auf 13
dc.w $6707,$FFFE ; WAIT - überspringe 5 Zeilen
dc.w $180,$00e ; COLOR0 - Blau auf 14
dc.w $6d07,$FFFE ; WAIT - überspringe 6 Zeilen
dc.w $180,$00f ; COLOR0 - Blau auf 15
dc.w $7907,$FFFE ; WAIT - Warte Teile $79 ab
dc.w $180,$300 ; COLOR0 - Beginne roten Balken: Rot auf 3
dc.w $7a07,$FFFE ; WAIT - Folgende Zeile
dc.w $180,$600 ; COLOR0 - Rot auf 6
dc.w $7b07,$FFFE ; WAIT -
dc.w $180,$900 ; COLOR0 - Rot auf 9
dc.w $7c07,$FFFE ; WAIT -
dc.w $180,$c00 ; COLOR0 - Rot auf 12
dc.w $7d07,$FFFE
dc.w $180,$f00 ; Rot auf 15 (Maximum)
dc.w $7e07,$FFFE
dc.w $180,$c00 ; Rot auf 12
dc.w $7f07,$FFFE
dc.w $180,$900 ; Rot auf 9
dc.w $8007,$FFFE
dc.w $180,$600 ; Rot auf 6
dc.w $8107,$FFFE
dc.w $180,$300 ; Rot auf 3
dc.w $8207,$FFFE
dc.w $180,$000 ; Farbe SCHWARZ
dc.w $fd07,$FFFE ; warte auf Zeile $FD
dc.w $180,$00a ; Blau Helligkeit 10
dc.w $fe07,$FFFE ; nächste Zeile
dc.w $180,$00f ; Blau maximale Intensität (15)
dc.w $FFFF,$FFFE ; ENDE DER COPPERLIST
Zusammenfassend, wenn ich auf Zeile $50 COLOR0 auf grün einstellen würde,
dann würden Zeile $50 und folgende alle Grün werden, bis COLOR0 nicht
wieder geändert wird (nach einem Wait, z.B. Wait $6007). Ein Ratschlag: Um
diese Copperlist zu schreiben, habe ich NATÜRLICH NICHT alle dc.w
$180,$... dc.w $xx07,$FFFE geschrieben!!!! Es reichen die zwei Befehle :
dc.w $xx07,$FFFE ; WAIT
dc.w $180,$000 ; COLOR0
Mit Amiga+B und Amiga+C ausgewählt, und dann eine Reihe davon hergestellt
mit einigen Amiga+I:
dc.w $xx07,$FFFE ; WAIT
dc.w $180,$000 ; COLOR0
dc.w $xx07,$FFFE ; WAIT
dc.w $180,$000 ; COLOR0
dc.w $xx07,$FFFE ; WAIT
dc.w $180,$000 ; COLOR0
.....
Nun müßen nur mehr die xx des Wait und die Werte jedes $180,...
ausgetauscht werden, und die überflüßigen Zeilen mit Amiga+B und Amiga+X
gelöscht werden. Bemerkung: Dieses Spielchen kann auch zwischen
verschiedenen Buffern des ASMONE getrieben werden, wenn ihr z.B. im Buffer
F2 ein Listing mit einer Copperlist habt, die ihr gerne kopieren möchtet,
dann braucht ihr sie nur mit Amiga+B und Amiga+C markieren, und dann in
eurem Listing im anderen Textbuffer mit Amiga+I einfügen.