
ASSEMBLERKURS - LEKTION 17

1. ReadMe.txt
2. copper.txt
3. plasm.txt
4. shadebobs.txt

      ____ ___ _____  ___  ___  ___  ___
     (_,  V   ),  . \|,  ~]   |(___)|   |
..-----|o      |o  |  )o  7o  | \o  /o|  |------.    ^    ^    ^    ^   ^
|  ___|___Y___|_____/|___!_____/___L____|____  |   +----------------------+
| ( , !   )___)/,___)(___),  . \|,  \  \/,___) |   |Feel the DEATH inside!|
`--\o    /|o  (___  \|o  |o  |  )o      )__  \-'   `----------------------'
.p.\___/ |___(______)___!_____/|___!___|_____)       v    v    v    v   v

 WHQ: Extrema +39-861-413362
 IHQ: DoWn ToWn +39-2-48000352


Das gesamte Material in diesem Verzeichnis ist *** COPYDEATH *** Morbid
Visions. Die Morbid Visions (oder einer der Autoren) übernehmen keine
Verantwortung für direkte oder indirekte Schäden, die durch die Verwendung des
oben genannten Materials verursacht werden, einschließlich Kochen des Monitors!

ANMERKUNGEN ZU DEN QUELLEN
Die Quellen wurden für den ASM-One 1.29 von T.F.A. geschrieben. Alle Quellen
haben am Anfang ein INCDIR "Infamy: MV_Code/". Zum Assemblieren müssen Sie ein
"ASSIGN INFAMIA:" für das Verzeichnis ausführen, das den MV_Code-Verzeichnis
enthält oder Sie müssen die INCDIRs in den Quellen bearbeiten. All die Quellen
verwenden denselben Startcode, der in der Datei MVStartup.S enthalten ist.
Dies ist ein SEHR einfacher Startcode, der nur für Tests verwendet werden kann.
Verwenden Sie ihn nicht für Ihre Demos!

In den Quellen verwenden wir die dunklen Regeln, die durch die dunklen Texte
der Coding Mortale festgelegt wurden, den Büchern, in denen die Philosophie
der Codierung der Morbid Visions zum Ausdruck kommt. Um das Lesen für
diejenigen zu erleichtern, die an die Quellen von Randys Kurs gewöhnt sind,
listen wir einige der Dunklen Regeln auf, die sich von den Konventionen 
unterscheiden, die während des Kurses befolgt wurden:

- Die Größe der Operanden wird nur angezeigt, wenn sie von der 
Standardeinstellung unterschiedlich ist. (Denken Sie daran, dass dies
standardmäßig der Fall ist, wenn nichts angegeben ist geht ASMOne davon aus,
dass die Dimension WORD ist, mit Ausnahme von Anweisungen mit fester Größe,
wie z.B. Scc (mit BYTE-Dimension), BTST (mit der Dimension BYTE, wenn sich das
Ziel im Speicher befindet und LONG, wenn das Ziel ein Register ist) usw.

Zum Beispiel:
 move	d0,d1		entspricht		move.w	d0,d1
 btst	#6,$bfe001	entspricht		btst.b	#6,$bfe001
 btst	#14,d0		entspricht		btst.l	#14,d0
 lea	label,a0	entspricht		lea.l	label,a0

- Der Blitter-Double-Wait-Test wird NICHT durchgeführt: Um auf den Blitter
zu warten führen wir einfach durch:

.wait
	btst	#6,dmaconr(a5)		; warte auf den Blitter
	bne.s	.wait

Der berühmte Agnus BUG ist nur in sehr wenigen zusammengesetzten Exemplaren
auf dem ersten A1000 vorhanden und tritt auch nur unter bestimmten Umständen
auf. Dieser Fehler ist alltäglich geworden, aber eigentlich hat niemand ihn
gesehen. Die Tests, die wir mit dem Hobbit / MV A1000 durchgeführt haben,
haben den BUG nicht gefunden. ALLE unsere OCS-Routinen funktionieren
ALLE AUF OCS Amigas OHNE den Doppeltest. Wenn nun auch die AGA-Ära auf den 
Sonnenuntergang zugeht macht es keinen Sinn, diesen unnötigen zusätzlichen
BTSTs mitzunehmen, das ruiniert nur die Ästhetik der Quellen.

- Oft werden MACROs und lokale Labels verwendet, die den Code verbessern
ordentlich und leserlich.

 Morbid Visions


 2. Datei copper.txt

 VERY ADVANCED COPPER


In diesem Artikel werden wir über die fortgeschrittenen Programmiertechniken
des coppers sprechen. Die Inspiration für diesen Artikel war, als ich in
Lektion 11 des Asm-Kurses von Randy las, dass die Anweisung SKIP des Coppers
nutzlos ist. Ich bin nicht dieser Meinung und während des Kursschreiben (an dem
ich mitgearbeitet habe, indem ich in den Lektionen 7, 9 und 10 die meisten
geschrieben habe) teilte ich dies Randy anhand einiger Beispiele mit. Ich habe
ihn gebeten, sie in Lektion 11 mit aufzunehmen. Leider hat Randy das nicht
getan, vielleicht aus Zeitmangel oder vielleicht weil er das Material verloren
hat, dass ich ihm geschickt hatte. Aber ich mag die Idee nicht, dass junge
Programmierer, die den Kurs gelesen haben (wie viele gibt es?), glauben, dass
der SKIP nutzlos ist, weil es im Gengensatz zu einem der dunklen Axiome der
Philosophie steht - Morbide Visionen:

 Amiga RULEZ => Hardware Amiga perfekt => HW frei von unnötigen Dingen.

Der AGA weist ebenfalls Defekte auf, der OCS jedoch nicht. Also dachte ich
über das Schreiben nach. In diesem Artikel geht es um SKIP und auch um die
Maskierung von Koordinaten des coppers, ein Thema, das im Kurs eher 
zusammenfassend behandelt wird. Wir werden in der Tat sehen, dass SKIP in
einigen Fälle sehr nützlich ist und dass die Möglichkeiten der Maskierung der
Koordinaten des coppers viel größer ist als erklärt wurde, zum Beispiel werden
wir sehen, dass auch die horizontalen Positionen maskiert werden können. Die
Techniken, die wir in diesem Artikel behandeln, können uns nicht das Ray
Tracing in Echtzeit erlauben (sonst hätte Randy es auch bemerkt), aber unter
bestimmten Umständen können sie uns jedoch einige kostbare Rasterzeilen
ersparen. Und wie in den dunklen Texten der tödlichen Kodierung behauptet wird,
dass eines der Ziele eines Codierers darin besteht, die Hardware maximal
auszunutzen, müssen wir auch in der Lage sein, diese Techniken auszunutzen.
Beginnen wir mit einer detaillierteren Beschreibung des vom copper verwendeten
Formats für WAIT- und SKIP-Anweisungen. Diese 2 Anweisungen haben ein sehr
ähnliches Format, darum werden wir eine einzige Beschreibung für beide machen.
Die Beschreibung Über die Funktionsweise des SKIP werden wir später sehen. Wie
Sie wissen besteht jede copper-Anweisung aus 2 WORTEN. Das Format des ersten
Wortes ist in der folgenden Tabelle beschrieben:

     ERSTES WORD INSTRUKTION WAIT UND SKIP
     -------------------------------------
     Bit 0           Immer auf 1 einstellen.

     Bits 7 - 1      Horizontale Position des Elektronenstrahls (HP).

     Bits 15 - 8     Vertikale Position des Elektronenstrahls (VP).

Diese beiden Aussagen basieren auf dem Verhalten, der Überprüfung eines 
bestimmten Zustands, welches (normalerweise) das Erreichen bzw. die Überwindung
der Position durch den Elektronenstrahl ist, die durch die VP- und HP-Bitfelder 
angegeben wird. Wie wir gleich sehen werden, ist es möglich, diesen Zustand
durch Halten zu ändern. Wir berücksichtigen auch den Zustand des Blitters.
Später werden wir auch das Verhalten des SKIP beschreiben. Schauen wir und das
zweite WORT an:

     ZWEITES WORD INSTRUKTION WAIT UND SKIP
     --------------------------------------
	 Bit 0           Für WAIT auf 0 und für SKIP auf 1 setzen.

	 Bits 7 - 1      Bit Maske Position horizontal (HE).

	 Bits 14 - 8     Bit Maske Position vertikal (VE).

     Bit 15          Blitter-finished-disable bit. 
					 Normalerweise auf 1 eingestellt.

Bit 0 wird vom copper verwendet, um zu wissen, ob der betreffende Befehl ein
WAIT oder ein SKIP ist. Die HE- und VE-Bitfelder werden jeweils zur Maskierung 
der horizontalen und vertikalen Positionen verwendet. Die Operation ist wie
folgt: Der copper vergleicht den von HP und VP angegebenen Standort mit der
Position des Elektronenstrahls unter Verwendung nur der Bits, bei denen die
entsprechenden Bits von HE und VE auf 1 gesetzt sind. Wenn wir zum Beispiel bei
einem WAIT die Bits von HE alle auf 1 setzen, während die Bits 8-12 von VE
auf 0 und die Bits 13 und 14 auf 1 gesetzt sind, wartet der copper darauf, dass
der Elektronenstrahl die horizontale Position HP (weil alle Bits von HE auf 1
sind) und die vertikale Position, bei denen die Bits 13 und 14 von HE gleich
den Bits 13 und 14 von VP erreicht sind (weil sie die einzigen Bits von VE
sind, die auf 1 gesetzt sind). Sehen wir uns einige bemerkenswerte Fälle an.
Wenn wir ALLE HP- und VP-Bits verwenden möchten (dh wir verwenden nicht die
Maskierung) müssen wir alle Bits von HE und VE auf 1 setzen. In diesem Fall,
wenn wir ein WAIT haben, nimmt das zweite WORT den Wert $FFFE an. Sie kennen
es gut. Wenn wir stattdessen ein WAIT wollen, das die vertikalen Positionen
vollständig ignorieren, aber alle Bits der horizontale berücksichtigen,
erhalten wir für das zweite WORT den Wert $80FE, wie es z.B. im Beispiel in
Lektion 11 von Randys Kurs ist.
Mit Bit 15, dieser Option können Sie die Bedingung ändern, die in den beiden
Anweisungen überprüft wird, wenn dieses Bit auf 1 gesetzt wird. Andernfalls
verhalten sie sich normal.
Sie müssen auch überprüfen, ob der Blitter einen möglichen Blitt beendet hat.	
(dh BLTBUSY, Bit 14 von DMACONR muss 0 sein). Zum Beispiel, im Fall von WAIT
wartet es mit dem fraglichen Bit bei 0, ob die durch die VP- und HP-Bits
angegebene Videoposition erreicht ist und es wird auch auf das Ende eines
möglichen Blitts gewartet. Dies kann in dem Fall hilfreich sein, wenn Sie
Blittings durchführen möchten, die mit der Position der Elektronenstrahls
elektronisch synchronisiert sind.

Die Aufmerksamen werden die Tatsache nicht übersehen haben, dass aufgrund der
Anwesenheit des Blitter Finished Disable-Bit, die VE-Bits eins weniger als
die VP-Bits sind. Genauer gesagt gibt es in VE kein Bit, das dem höchsten Bit 
korrospondierend von VP entspricht. Dies bedeutet, dass dieses Bit (Bit 8 der
vertikalen Position des Bildschirms) NICHT maskiert werden kann. Dieser Fakt
hat wichtige Konsequenzen. In der Tat wird in Anwendungen die Maskierung
verwendet, um Anweisungen zu haben, die sich auf die gleiche Weise in
verschiedenen Bildschirmpositionen verhalten. Die Tatsache, nicht in der Lage
zu sein Bit 8 der vertikalen Position zu maskieren, verhindert daher das
Haben von Anweisungen, die sich in Bereichen des Bildschirms gleich verhalten,
die Bit 8 der unterschiedlichen vertikalen Position haben.
Das typische Beispiel, dass auch von Randy gezeigt wird, ist das WAIT, dass
auf eine bestimmte horizontale Position wartet, unabhängig davon, in welcher
Zeile es sich befindet. Wenn wir versuchen würden solch ein WAIT durch Setzen
von DC.W $00xx,$80FE zu machen, würden wir tatsächlich ein WAIT bekommen, dass
auf eine Bildschirmposition wartet, bei der Bit 8 der vertikalen Position 0
und die horizontale Position xx ist. Die Anweisung wird ausgeführt, wenn Bit 8
und die Elektronenstrahlposition gleich 0 ist und es wartet nach Wunsch darauf,
dass der Elektronenstrahl die horizontale Position xx erreicht hat.
Ansonsten wenn Bit 8 der vertikalen Position des Elektronenstrahls 1 ist und		
das Bit 8 von VP 0 ist, wird die WAIT-Bedingung sofort überprüft, daher
blockiert solche Anweisung NICHT den copper. Wegen dieses Phänomens behauptet
Randy in seinem Kurs funktioniert das Maskieren nicht bei Zeilen zwischen $80
und $FF. Dies ist eine entschieden voreilige Schlussfolgerung.
In der Tat, um den gewünschten Effekt zu erzielen, verwenden Sie einfach ein
WAIT, dass die niedrigen Bits von VP, wie im vorherigen Fall maskiert, aber das
nicht maskierbare Bit von VP bei 1 platziert, was ein DC.W $80xx,$80FE ist.
Solches WAIT in den Zeilen zwischen $80 und $FF hat gleichzeitig das nicht 
maskierbare Bit von VP, d.h. den Wert von Bit 8 der vertikalen Position des
Elektronenstrahls und es wird daher in jeder Zeile auf die horizontale Position
xx gewartet. Als Beispiel-Anwendung schlagen wir den Effekt in der Quelle
MV_Code / Copper / mask1.s vor wie von Randy verwendet, um die Maskierung
vertikaler Positionen (im Gegensatz zu Randy) in Zeilen zwischen $80 und $FF
zu veranschaulichen.
Erlauben Sie uns an dieser Stelle, respektable Leser, den Anfang des 
Scrolltextes des berühmten INTROs KickReset von Razor 1911 zu paraphrasieren.
"Randy sagte uns, dass dies nicht möglich war ... trotzdem ist es hier !! :))

Es sollte jedoch beachtet werden, dass ein maskiertes WAIT bei dem Bit 8 von VP
auf 1 gesetzt ist, wenn es in einer Zeile ausgeführt wird, in der Bit 8 der
vertikalen Position gleich Bit 8 der vertikalen Position gleich 0 ist, wird der
Copper IMMER blockiert, da die Nummer der Zeilennummer immer kleiner als
die in WAIT angegebene Position betrachtet wird.

Dies bedeutet, dass das WAIT unseres Beispiels den gewünschten Effekt erzielt
(Warten auf die horizontale Position xx NUR in Zeilen zwischen $80 und $FF.) 
Was wäre, wenn wir die WAIT-Maske auf den gesamten Bildschirm verwenden
wollten?? Die Quelle MV_Code / Copper / mask2.s ist genau eine Implementierung
des in der vorherigen Quelle, die über den Bildschirm funktioniert. Ich
verweise auf den Quellkommentar für eine Beschreibung der verwendeten
Techniken.

Wir kommen also zur Anweisung SKIP. Wie bereits erwähnt, hat es ein sehr 
ähnliches Format wie bei WAIT. Das Verhalten des SKIP ist wie folgt:
es bewirkt, dass der copper die folgende Anweisung überspringt, wenn der
Elektronenstrahl die angegebene Position erreicht bzw. überschritten hat.
Betrachten Sie beispielsweise folgende Anweisungen:

		dc.w	$4037,$ffff	; Skip (überspringen),
							; wenn Sie die Zeile $40 überschreiten
ISTR1:	dc.w	$182,$0456	; copper move-Anweisung
ISTR2:	dc.w	$182,$0fff	; copper move-Anweisung

Wenn der copper den SKIP-Befehl ausführt, prüft er, wo der Elektronenstrahl
ist und ob die durch die Bits VP und HP des SKIPs angegebene Position 
(im Beispiel HP = $36 und VP = $40) überschritten wurde. Wenn ja überspringt
der copper die folgende Anweisung (bei ISTR1) und führt die Anweisung 
danach aus (dh die Anweisung bei ISTR2). Wenn stattdessen der Elektronenstrahl
noch nicht die angegebene Position erreicht hat wird (normalerweise) die
nächste Anweisung ausgeführt, als ob der SKIP nicht vorhanden wäre.
Wie wir bereits gesagt haben, hat die Maskierung der Positionen mittels der
VE- und HE-Bits des zweiten WORD eine selbe Art und Weise wie beim WAIT.					
Darüber hinaus kann auch für den SKIP das Bit Blitter Finished Disable auf 0
sein, wodurch der Sprung unter Berücksichtigung des Status des Blitters
durchgeführt wird.

Mit SKIP können Sie Schleifen in der copperliste erstellen. D.h.
In der copperliste befinden sich eine Reihe von Copperanweisungen, die
wiederholt werden bis der Elektronenstrahl eine bestimmte Position erreicht.
Zur Realisierung der Schleife wird auch das COP2LC-Register verwendet. Der
Mechanismus ist durch das folgende Beispiel veranschaulicht:

im Hauptprogramm

	move.l	#Copperloop,COP2LC(A5)	; schreibt die Schleifenadresse
									; im COP2LC-Register

und in die copperliste geben Sie die folgenden Anweisungen ein:

	dc.w	$2007,$FFFE	; WAIT Zeile $20
Copperloop:
	dc.w	$180,$F00	; copper Anweisungen der Schleife
	dc.w	$180,$0F0
	dc.w	$180,$00F

	.
	.

	dc.w	$180,$F0F	; letzte Anweisung der Schleife
	dc.w	$4007,$ffff	; SKIP wenn Sie die Grenze $40 überschreiten 
	dc.w	$8a,0		; COPJMP2 Springe zum Anfang der Schleife

	dc.w	$182,$00F	; Anweisung außerhalb der Schleife

Die Bedienung ist sehr einfach. Nach der Zeile $20 tritt der copper in die
Schleife. Nachdem alle Anweisungen der Schleife ausgeführt wurden, gelangt es
zum SKIP. An diesem Punkt, wenn der Elektronenstrahl die Zeile $40 noch 
NICHT überschritten hat (dh er ist höher auf dem Bildschirm) überspringt
der copper NICHT die folgende Anweisung. Die folgende Anweisung schreibt jedoch
in COPJMP2. Dies führt zu einem coppersprung zu der in COP2LC geschriebenen
Adresse. An der Adresse steht der erste Befehl der Schleife. Auf diese Weise
wird die Schleife wiederholt. Nach einer bestimmten Anzahl von Wiederholungen
wird der Elektronenstrahl die $40-Linie erreichen. Zu diesem Zeitpunkt, erfolgt
SKIP und der copper überspringt den Befehl, in COPJMP2 zu schreiben.
Auf diese Weise springt es nicht mehr zum Anfang der Schleife, sondern führt
den ersten Befehl außerhalb der Schleife aus.

Wofür sind die Schleifen in der copperliste gut? Es ist klar, dass wir es immer 
auch ohne machen können: Anstatt die Schleife zu machen, schreiben wir so oft
den Teil der copperliste der wiederholt werden soll. Auf diese Weise sparen wir
uns das SKIP und die Anweisung, die in COPJMP2 schreibt, die den copper etwas
langsamer macht. Die Verwendung von Schleifen hat jedoch einige Vorteile: An
erster Stelle sparen wir Speicher, weil wir nur das "kurze" Stück copperliste
schreiben. Zweitens, wenn das wiederholte Copperlistenstück vom Prozessor
modifiziert werden muss, um einen Effekt zu erzielen, muss natürlich nur das
Copperlistenstück einmal (durch die Schleifen) modifiziert werden, was die
Arbeit des Prozessors erheblich beschleunigt.

Die Verwendung von WAIT-Anweisungen in Schleifen ist mit einigen Problemen
verbunden. Angenommen, wir haben eine Schleife, die sich von Zeile $20 bis
Zeile $70 wiederholt und innerhalb der Schleife ein WAIT in Zeile $38.
Was geschieht? Bei der ersten Ausführung der Schleife blockiert das WAIT den
copper. Nach Zeile $38 wird der copper entsperrt, erreicht das Ende der
Schleife und wiederholt es. An diesem Punkt, wenn der Elektronenstrahl die 
Zeile $38 passiert hat, wird das WAIT keinen copper mehr blockieren. Als
Ergebnis führt die Ausführung der ersten Iteration der Schleife zu
unterschiedlichen Ergebnissen gegenüber den folgenden Iterationen.

Normalerweise ist dies nicht das, was Sie wollen. In Schleifen mit dem copper
wäre es wünschenswert, auf eine bestimmte Zeile in der Anzeigenschleife jeder
Iteration warten zu können. Zum Beispiel möchten Sie vielleicht so etwas:

CopperLoop:
		; verschiedene Anweisungen

		Warten Sie 4 Zeilen ab dem Beginn der Iteration

		; verschiedene Anweisungen

		Wiederholen Sie die Schleife bis zu einer bestimmten Zeile.

Wie kann ein solcher Mechanismus implementiert werden? Es ist notwendig ein
WAIT mit einigen maskierten Teilen der vertikalen Position zu verwenden.
Angenommen, wir haben eine Schleife, die 16 Rasterzeilen umfasst und die wir
von Zeile $10 bis Zeile $70 wiederholen möchten, dh für 96 Zeilen. Da 96/16 = 6
ist, führt der copper 6 Iterationen durch. Beachten Sie, dass 96 durch 16 
teilbar ist (es gibt keinen Rest), was bedeutet, dass der Elektronenstrahl
genau dann Zeile 96 erreicht, wenn der copper die sechste Iteration beendet. 
Wir wollen in jeder Iteration der Schleife, dass der copper in der vierten
Zeile ab dem Beginn der Iteration hängt.

Um dies zu erreichen, verwenden wir ein WAIT, in dem wir die signifikanten
Bits der vertikalen Position maskieren. In diesem Fall, da die Schleife
sich alle 16 Zeilen wiederholt, muss sich das WAIT alle 16 Zeilen gleich
verhalten und muss nicht die Positionsunterschiede zwischen einer Gruppe von 16 
Zeien und die anderen berücksichtigen. Daher müssen nur die 4 Bits die eine
Gruppe von 16 Zeilen bilden berücksichtigt werden.
Um die Bits der vertikalen Position zu maskieren, werden wie im Kurs erklärt
die Bits von 8 bis 14 des zweiten Wortes des WAIT verwendet.
Wenn eins dieser Bits auf 1 gesetzt wird (wie üblich), wird das entsprechende
Bit der vertikalen Position genutzt. Andereseits wenn eines dieser Bits
zurückgesetzt ist, ist es maskiert.

Betrachten wir zum Beispiel Folgende WAIT Anweisung:

	dc.w	$0301,$8FFE

Diese Anweisung wartet auf die vierte Zeile einer Gruppe von 16 Zeilen. Mal			
sehen was in unserem Beispiel passiert?  Die Schleife beginnt in Zeile $20.
Das copper führt die ersten Anweisungen aus und erfüllt das WAIT. Es werden
nur die 4 Bits weniger bedeutsam als die Position berücksichtigt, auf die es
auf eine Zeile wartet das diese 4 Bits auf dem Wert $3 hat (tatsächlich im
zweiten WORT die Bits 12, 13, 14 die den Bits 5, 6 und 7 der vertikalen
Position entsprechen, liegen bei 0).

Dies geschieht in Zeile $23. Zu diesem Zeitpunkt wird der copper entsperrt. Die
zweite Wiederholung der Schleife beginnt bei Zeile $30. Auch hier kommt der
copper zum Wait und wartet auf eine Zeile mit den 4 niedrigstwertigen Bits
mit dem Wert $3. Das passiert in Zeile $33, die immer noch die vierte Zeile
der Schleife ist.
Dieses Verhalten wird bei jeder nachfolgenden Iteration wiederholt. Wenn wir 
8 Zeilen lange Iterationen mit WAITs dieses Typs wollten, sollten wir nur die
3 niedrigstwertigen Bits der Position aktiviert lassen. Beachten Sie, dass
diese Technik nur dann leicht zu implementieren ist, wenn die Länge einer
Iteration eine Potenz von 2 ist. Ein Beispiel für eine Copperschleife ist die
Quelle MV_Code / Copper / skip1.s.

Eine Einschränkung der Verwendung von WAITs in der von uns gezeigten Weise ist
aufgrund der Tatsache, dass das höchstwertige Bit der vertikalen Position nicht
maskiert werden kann. 
 
Dies verhindert, dass wir Schleifen erstellen, die sich	in gleicher Weise
verhalten wie über der Zeile $80, wo das höchstsignifikante Bit 0 ist, beide
unten, wobei das höchstwertige Bit 1 ist, gerade weil wir diesen Unterschied
nicht durch maskieren ignorieren können.

Die einzige Lösung besteht darin, zwei Schleifen zu verwenden, von denen eine
oberhalb von $80 und eine darunter ausgeführt wird, wie in
MV_Code / Copper / skip2.s gezeigt.

Ein etwas komplexeres Beispiel ist die Quelle MV_Code / Copper / skip3.s.
In dieser Quelle werden die copperlisten mit MACROs anstatt mittels DC.W
geschrieben. Mit MACROs kann beispielsweise CMOVE $0f0,COLOR00 geschrieben
werden, anstelle von DC.W $180,$0f0 und im Fall von WAIT WAIT $07 $60
anstelle von DC.W $6007,$FFFE. Es ist eine stilistische Wahl, die (mir
persönlich) die Quellen viel sauberer und aufgeräumter macht. Auch (in diesen)
vermeiden Sie so viele "ablenkende" Fehler beim Schreiben der copperliste, wie
z.B. zu vergessen, dass das Bit 0 des ersten WAIT-Wortes auf 1 eingestellt sein
MUSS. Im ersten Teil des Artikels habe ich sie nicht verwendet, weil ich
während der Erklärung des SKIPs sie nicht mit weiteren Ideen verwirren wollte.
Ich empfehle daher jedem, sie zu benutzen. In der Quelle dort sind reduzierte
Versionen meiner Makros, die Sie verbessern und in Ihre Quellen aufnehmen
können.

Mit SKIPs können Sie natürlich Wiederholungsschleifen sogar innerhalb der
gleichen Zeile des Bildschirms erstellen. Wegen der Langsamkeit des coppers,
(1 Anweisung = 8 Pixel) ist die Anzahl der Iterationen pro Zeile
normalerweise ziemlich klein. Sie können ein Beispiel in der Quelle 
MV_Code / Copper / skip4.s sehen.

                                       The Dark Coder / Morbid Visions

3. Datei plasm.txt


Das Plasma		(Lektion von The Dark Coder)

In diesem Text werden wir über den "Plasma"-Effekt sprechen. Insbesondere
werden wir sehen, wie wir Plasmaeffekte mit Techniken, die bei allen Amiga
angewendet werden können erstellen. Heutzutage dank des AGA-Chipsatzes und der
68020-Prozessoren und höher werden auch verschiedene Plasmen hergestellt,
basierend auf Techniken wie "chunky Pixel". Die Effekte, die wir in diesem
Text diskutieren werden, können jedoch auch auf dem guten alten Amiga 500
verwendet werden.
Die grundlegende Technik zur Herstellung eines Plasmas ist die Verwendung
einer copperliste, die einige Farbregister kontinuierlich ändert, mittels
aufeinanderfolgenden "copper moves". Wir haben bereits in Lektion 11 gesehen,
wie man viele copperlisten dieses Typs baut und benutzt. Insbesondere in
den Beispielen Listing11g1.s, Listing11g2.s und Listing11g3.s, in denen wir
Farb-Gradienten mit copperlisten gemacht haben, in dem wir den Inhalt von
COLOR00 verändert haben.
Es handelt sich jedoch um statische copperlisten. Der Hauptunterschied zwischen
diesen Beispielen und Plasma ist genau das: Bei einem Plasmaeffekt wird eine
copperlist so strukturiert verwendet, aber dynamisch, so dass in jedem Frame
die Farben im COLOR00-Register geschrieben werden. 
Jeder "copper move" besteht aus 2 Wörtern:

	dc.w	$180,COLOR	; Struktur eines "copper move"

Das erste Wort enthält die Adresse von COLOR00 und das zweite den Wert von
schreibe in dieses Register. Um den Plasmaeffekt zu erzielen, müssen wir 
diesen Wert bei jedem Frame variieren, dh wir müssen jedes Mal einen anderen
Wert in das zweite Wort schreiben, das den "copper move" macht.
Das Problem ist, dass wir diesen Vorgang für alle "copper moves" wiederholen
müssen, die Teil der copperlist sind. Es ist daher eine große Menge von zu
ändernden Daten. Da sich die copperliste im CHIP-RAM befindet, können wir den
Blitter verwenden, um Änderungen vorzunehmen.
Abschließend also, der Plasma-Effekt, wird durch eine Routine hergestellt,
die (unter Verwendung des Blitters) aus einer Tabelle Farben liest und sie in 
die copperliste kopiert. Durch Variieren, der kopierten Farben in jedem Frame
wird das Plasma erstellt. Beachten Sie, dass für diesen Effekt die Verwendung
von Bitplanes nicht erforderlich ist, da Sie alles durch ändern der
Hintergrundfarbe machen.
Aus diesem Grund wird es als "0-Bitebenen"-Plasma bezeichnet, im Gegensatz zu
den anderen Varianten, die wir später sehen werden. Ein Beispiel für ein
0-Bitebenen-Plasma ist plasm1.s.
Eine signifikante Verbesserung des Effekts ist das RGB-Plasma. Es unterscheidet
sich vom normalem Plasma, weil die Farben nicht einfach aus einer Tabelle
kopiert werden, sondern wie folgt "berechnet" sind:
Die Komponenten R, G und B werden separat gelesen (aus 3 verschiedenen Quellen
einer Farbe) und werden dann mit einem OR verknüpft. Auf diese Weise, weil die
Komponenten R, G und B kontinuierlich zwischen einem "copper move" und dem
anderen variieren werden mehr Farben produziert. In der Praxis wird eine
Blitt-Operation beim Kopieren verwendet, die ein ODER zwischen 3 Quellen
ausführt, die die Komponenten R, G und B enthalten. Ein erstes Beispiel für ein
RGB-Plasma ist plasm2.s.
Um den Effekt weiter zu verstärken, wird versucht, das Plasma so zu machen.
Eine einfache Möglichkeit, dies zu tun, besteht darin, die Start-Position
jeder Plasma-Zeile zu bestimmen. Dies kann sehr einfach durchgeführt werden
da die Startposition durch die WAIT-Anweisung bestimmt wird, die am Anfang 
jeder Zeile der copperliste steht. Eine Variation dieser Art ist in
plasm3.s dargestellt.
Leider haben jedoch die horizontalen WAIT Positionen eine Auflösung von
4 Pixel, was bedeutet, dass es nur möglich ist die Startposition des Plasmas in
"Schritten" von 4 Pixel zu variieren. In geeigneter Weise können die Parameter
des Beispiels plasm3.s Phänomens hervorgehoben werden.
Um weniger ruckartige Schwingungen zu erhalten, verwenden wir eine andere
Technik, das eine Bitebene verwendet und daher als "1-Bitebenen"-Plasma
bezeichnet wird. Die Technik ist die folgende: Es wird eine 8-Pixel-breite
vertikale "gestreifte" Bitebene verwendet. Auf diese Weise hat das Bild
8 Pixel, die mit COLOR00 gefärbt sind, dann 8 Pixel gefärbt mit COLOR01, dann
wieder 8 mit COLOR00 und so weiter. In der Korrespondenz verwenden wir eine
copperliste ähnlich der in den vorherigen Beispielen, aber es wechselt einen
"copper move" in COLOR00 mit einem in COLOR01. Die Situation ist dargestellt
durch die folgende Abbildung:

Ziel
des 
"copper move":	| COL.0 | COL.1 | COL.0 | COL.1 | COL.0 | COL.1  - - -


Zeile von
bitplane:	000000001111111100000000111111110000000011111111 - - -											

Wie Sie sehen können, besteht eine genaue Übereinstimmung zwischen der
angezeigten Farbe und dem geänderten Register der copperliste. Ein Farbregister
behält seinen Wert für einen Abstand von 16 Pixeln konstant, aber diese Farbe
wird nur für die 8 Pixel der Bitebene angezeigt, die sie auswählen (dh nur für
die 8 Pixel bei 0) im Fall von COLOR00 und nur die Pixel bei 1 im Fall von
COLOR01). Bisher haben wir mit unserer Bitplane genau das Gleiche gemacht wie
zuvor, als wir darauf verzichtet haben. Aber jetzt komt das Neue.
Wir können den Hardwarescroll benutzen, um die Bitebene horizontal zu bewegen.
Beachten Sie, dass wenn der Wert des Bildlaufs von 0 bis 7 variiert, bleibt
die Farbe jeder Gruppe von 8 Pixeln immer gleich. Tatsächlich variiert der in
einem Register enthaltene Wert alle 16 Pixel. Mit Scrollwerten von 0 bis 7
verschieben wir die Gruppe immer um 8 Pixel innerhalb dieses "Bandes" von
16 Pixeln. Wenn wir stattdessen größere Werte verwenden, werden einige der
Pixel in der Gruppe aus dem Band herauskommen, vorausgesetzt es ist eine neue
Farbe.
Schauen wir uns das Phänomen anhand einiger Zahlen genauer an. Beachten Sie,
wie die Farbregister ihren Wert pro Bänder von 16 Pixeln konstant halten.
Die Bänder der 2 Register überlappen sich: die Bänder von COLOR01 beginnen und
enden in der Mitte von COLOR00 und umgekehrt.
Wenn wir einen Scrollwert von 0 verwenden, haben wir die folgende Situation:

Wert in
COLOR01		        |	   Wert 1     |    Wert 2       |    Wert 3		|   - -
			V			      V	      V	       
scroll=0:	00000000.11111111.00000000.11111111.00000000.11111111 - - -
			^				  ^					^				  ^
Wert in		|				  |					|				  |
COLOR00		|    Wert 1		  |    Wert 2	    |    Wert 3		  |   - - 

Wie Sie sehen können, befindet sich jede Gruppe von 8 Pixeln mit dem Wert 0 in
Übereinstimmung mit den ersten 8 Pixeln (dh die am weitesten links liegenden)
jedes 16er-Bandes, für das COLOR00 einen konstanten Wert annimmt.
Gleiches gilt für Gruppen von 8 Pixeln in Bezug auf die 16-Pixel-Bänder, für
die COLOR01 auf 1 gesetzt die Konstante bleibt.

Mit zunehmendem Scrollwert bewegen sich die Gruppen von 8 Pixeln in Richtung 
der rechten Ränder der Bänder. Zum Beispiel. Folgendes passiert, wenn
der Scroll 4 Pixel beträgt:

Wert in 
COLOR01		        |    Wert 1    |    Wert 2    |    Wert 3  |   - - 
					V	           V	          V	       
scroll=4:	1111000000001111111100000000111111110000000011111111 - - -
			^			   ^	          ^		         ^
Wert in		|			   |	          |		         |
COLOR00		|    Wert 1    |    Wert 2    |    Wert 3    |   - - 

Wenn der Scrollwert 7 Pixel beträgt, werden die Gruppen von 8 Pixeln an den
Kanten an den rechten Seiten der Bänder ausgerichtet (bzw. die Pixel bei 0 mit
den Bändern von COLOR00 und und Pixel mit 1 mit den Bändern von COLOR01):


Wert in
COLOR01			    |    Wert 1    |    Wert 2    |    Wert 3		 |   - - 
					V			   V			  V	       
scroll=7:	1111111000000001111111100000000111111110000000011111111 - - -
			^			   ^			  ^				 ^
Wert in		|			   |			  |			     |
COLOR00		|    Wert 1	   |    Wert 2	  |    Wert 3    |   - - 


Sobald der Bildlauf 8 überschreitet, gehen die Gruppen von 8 Pixeln über die
Ränder der Bänder hinaus. Dies bedeutet, dass die 8 Pixel in der Gruppe nicht
mehr den gleichen Wert haben. Die folgende Abbildung zeigt die Situation für
einen Scroll von 8 Pixel.

Wert in
COLOR01		        |    Wert 1    |    Wert 2    |    Wert 3  |   - - 
					V	           V	          V	       
scroll=8:	11111111000000001111111100000000111111110000000011111111 - - -
		    ^			   ^	          ^		         ^
Wert in  	|	           |	          |		         |
COLOR00		|    Wert 1    |    Wert 2    |    Wert 3    |   - - 

In dieser Situation fallen die ersten 7 Pixel jeder Gruppe von 8 in ein Band
und daher erscheinen sie mit der im Farbregister enthaltenen Farbe für dieses
Band, während die letzten in das folgende Band fallen und daher in der Farbe
erscheinen, die vom Farbregister im neuen Band angenommen wird.
Dieses Phänomen schafft abrupte Farbveränderungen, die das Plasma unangenehm
machen. Dieser Effekt basiert auf dem "mischenden" Eindruck von Farben.
Im Beispiel plasm4.s wird diese Technik angewendet.
Die Verwendung von Bitebenen ermöglicht es uns auch, Masken von Plasmas
überlagernd zu verwenden. Ein Beispiel ist in plasm5.s.
Die in den letzten beiden Beispielen gezeigte Technik hat die Grenze in der 
horizontalen Schwingung, die auf eine Breite von 8 Pixel begrenzt ist. Dies
liegt an der Tatsache, dass jedes Farbregister über einen Bereich von 16 Pixeln
konstant bleibt und das jede Pixelgruppe 8 Pixel breit ist. Aus diesem Grund
kann sich die Gruppe im Bereich von 16-8 = 8 Pixel bewegen. Um die Breite der
Schwingungen zu erhöhen ist es notwendig, die Bänder zu verbreitern, und dazu
ist es notwendig mehrere Farbregister zu verwenden und es ist erforderlich die
Register alle 8 Pixel zu ändern.
Zusammenfassend ist es daher notwendig, eine Hauptanzahl der Bitebenen zu
verwenden. Beachten Sie, dass wir in den vorherigen Beispielen die Schwingungen 
mit dem Hardware-Scroll gemacht haben, der es uns ermöglicht, bis zu 16 Pixel
zu bewegen. Diese weitere Einschränkung kann durch Schwenken der Bitebenen 
mit dem Blitter überwunden werden. In diesem Fall erfordert die Schwingung
natürlich eine viel langsamere Routine und spezielle Tricks werden verwendet
um es zu erreichen.
In dem Beispiel plasm6.s, das diese "Monographie" über Plasma abschließt,
werden wir sehen, wie man ein Plasma mit einer horizontalen Schwingung von
56 Pixeln macht.
Alle Plasmen, die wir gesehen haben, können durch Variation von Paramtern
und die Tabellen, die die Farben (oder deren Komponenten) enthalten während
der Ausführung interessanter gemacht werden. 

4. Datei shadebobs.txt

;By DeathBringer/MORBID VISIONS

Shade Bobs

Die ShadeBob-Routine ist im Wesentlichen eine Implementierung der Fähigkeit
des Blitters zu addieren. Denken Sie nur an jedes Pixel auf dem Bildschirm
ist eine binäre n-stellige Zahl, wobei n beispielsweise die Anzahl der
Bitebenen ist. Mit 5 Bitebenen wäre die Situation wie folgt:

Plane5        0        0        0        0        0
Plane4        0        0        1        0        1
Plane3        0        1        0        1        0
Plane2        0        1        1        0        1
Plane1        1        0        1        0        0
-----------------------------------------------------
Anzahl        1        6       11        4        10

Die Routine addiert 1 zu dieser Zahl unter Verwendung einer einfachen
angewendeten Technik in binären Zählern und mit raffinierten Verbesserungen
wie sie auch im Addierer in unserer ALU vorhanden sind.

Um den Schatten auszuführen, müssen wir 1 zu der von allen dargestellten Zahl 
die bitplanes hinzufügen. Hier ist wie.

Die Tatsache, dass Binärzahlen hinzugefügt werden, erleichtert unser Leben
jedoch erheblich. Zuerst berechnen wir, ob es einen Übertrag zwischen einer
Bitebene und einer anderen gibt, wenn dies geschieht, wenn Sie es für die
Stellen in einer normalen Addition berechnen, und dann berechne die Summe.

Es ist klar, dass es einen Übertrag gibt, wenn beide Bits gleich 1 sind und die
Summe ist 1, wenn die Bits unterschiedlich sind, 0, wenn die Bits gleich sind 
(0 + 0, 1 + 1). Sie können es einfach anhand der folgenden Tabelle überprüfen:

Bitplane | Bit Hinzufügen | Summe | Übertrag 
--------------------------------------------
    0    |        0       |   0   |    0   
    0    |        1       |   1   |    0  
    1    |        0       |   1   |    0  
    1    |        1       |   0   |    1  
---------------------------------------------    

Jetzt können wir sehen, welche Funktionen hinzugefügt und übertragen werden:

Summe = Bitplane XOR Bit

Übertrag = Bitplane AND Bit

An diesem Punkt wiederholen Sie einfach die vorherige Prozedur für alle
Bitebenen. Hinzufügen des Carry, und das war's !!!

Beispiel:
        Anzahl       Bit Hinzufügen          Summe            Übertrag
------------------------------------------------------------------------
plane1  1        +          __1        =        0                1 ->\    
                           /      /---------------------<-------------|
plane2  1        +        /   1 <-     =        0                1 ->\  
                         /        /-----------------------------------|
plane3  0        +       |    1 <-     =        1                0 ->\   
                         |        /-----------------------------------|
plane4  0        +       |    0 <-     =        0                0
        ^                |                      ^
        |                |                      |
        3        +        \_->1        =        4
------------------------------------------------------------------------
        
Unser 1-Bitplane-Bob repräsentiert die Maske, die angibt, welche Pixel
interessant für die Addition des Frame.
Sie nehmen den Bob und den betroffenen Bildschirmbereich und führen ein UND durch
als Ziel ein zusätzliches Gebiet namens Carry.
Sobald dies erledigt ist, nimm den Bob und führe das XOR mit der entsprechenden
Bitebene aus Bildschirm, um die Summe zu erhalten.
Dann nutzen wir den Carry-Bereich weiter, als wäre es unser Bob für jede
Bitplane. Es sind eindeutig 2 Carry Bereiche erforderlich !!!


ENDE ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++