home *** CD-ROM | disk | FTP | other *** search
- A S S E M B L E R - K U R S (c) Jeff Kandle 1990
-
- 16.Teil...
-
- So, nachdem wir wissen wie wir unsere sachen auch weitergeben und damit
- Strunzen koennen, macht es doch gleich wieder spass, oder ?
-
- In diesem Teil werde ich am anfang erstmal ein paar neue Befehle
- vorstellen, sie aber nicht in irgendein programm verpacken. Ich bin sicher
- das ihr diese Befehle irgendwann gut gebrauchen koennt, und dann erinnert
- ihr euch bestimmt daran.
-
- Als ersten nette befehl kommt der Swap-befehl. Er kann auf die Adress und
- Datenregister zugreifen, und vertauscht oberes Wort mit dem unteren.
- Aus...
-
- $40981546
-
- wird...
-
- $15464098
-
- Naja, hoert sich ja nicht besonders an. Aber den grund warum ich den Befehl
- vorstelle, ich hatte ja gesagt ich stelle nur die Befehle vor die man
- wirklich zum Intro schreiben braucht, ist, das er sich ganz besonders gut
- fuer manipulationen an Copperlisten eignet, wenn es darum geht Adressen
- einzutragen.
- Wie ihr wisst sind die Adresse in einer Copperliste immer getrennt in
- Highwort und Lowwort.
-
- Um die adresse $40000 als adresse fuer die erste Bitplane festzulegen, muss
- man das ja die beiden befehle..
-
- $00e0 $0004
- $00e2 $0000
-
- schreiben. Naja wenn wir wissen wo das liegt koennen wir das ja relativ
- einfach eintragen. Aber was ist wenn wir zum Beispiel die Adresse der
- Sprite datenliste in die Copperliste eintragen wollen. Dann gibt es schon
- schwierigkeiten. Wir koennten das zwar ermitteln, weil wir ja das mainprog
- mit Org/Load fixieren. Aber die Adresse der Datenliste aendert sich ja
- jedesmal wenn wir erweiterungen am listing vornehmen, also das ist es nicht.
- Die moeglichkeit ist also, sich mit Move.l # die Adresse in ein Datenregister
- zu holen, um dann die Zwei worte in die Copperliste einzutragen.
- In der Praxis sieht das dann so aus...
-
- Move.l #Sprite1,d0
- Move.w d0,Copperlist+2
- Swap d0
- Move.w d0,Copperlist+6
- Rts
-
- Copperlist:
- dc.w $0120,$0000
- dc.w $0122,$0000
- dc.l $-2
-
- Sprite1:
- ..Hier liegt dann die Spritedefinition
-
- Die Funktion muesste eigentlich Klar sein...
-
- Dann kommt ein Kuerzel das man z.b hinter die Befehle Move, Add und Sub
- klemmen kann.
-
- Naemlich `q`...
-
- Es bedeutet dann soviel wie Quick, man kann damit allerdings nur
- vorzeichenbehaftete 4 bit werte uebertragen. Also von -8 bis +7.
- Quick wird es genannt weil es sehr schnell geht, denn der wert wird direkt
- in den Befehl mit eingebaut. Es kommt nur ein Wort bei raus, und das der
- Prozessor das Schneller abarbeiten kann ist ja wohl jedem Klar..ne.
-
- Wenn irgendwie moeglich solltet ihr wenn irgendwie moeglich bei Sprung
- operationen immer die Branch befehle vor ziehen. Also anstatt
-
- Jmp und Jsr...immer Bra und Bsr...
-
- Denn dort ist sowieso der Befehl kuerzer. Man kann ihn aber auch von hand
- noch kuerzer machen. Indem man einfach .S fuer kurze Distanz, oder .L fuer
- lange Distanz eingebt. Wenn ihr euch vertut und Kurz statt lang eingebt ist
- das nicht so schlimm, der Seka merkt das und verbessert euch. Falls aber
- umgekehrt, wenn ihr also .L schreibt, aber .S moeglich waere, tja dann habt
- ihr pech gehabt, da mischt sich der Seka nicht ein.
- Dieses Kuerzel habt ihr aber auch schon in meinen Listings gesehen. Es
- klebt immer an den Bne`s, Beq`s, und an den Bsr`s dran. Naja jetzt wisst
- ihr auch was das bedeutet.
-
- Eine weiteres Kuerzel kann man noch in den Daten fuer den befehl
- unterbringen. Und zwar wenn man mit Adresse arbeitet die eigentlich nur ein
- Wort lang sind, dann waere es unsinnig ein ganzes langwort dafuer zu
- verschwenden. Es koennte dann so aussehen...
-
- Vorher
- Move.l $00000040,$00000050
-
- schiebt das langwort von $40 nach $50
- Das ergibt nach dem Assemblieren
-
- 2 Bytes fuer den Move befehl
- 4 Bytes fuer die Adresse $00000040
- 4 Bytes fuer die Adresse $00000050
-
- ----------------------------------
- 10 Bytes
-
- Wenn ihr aber die Kuerzel benutzt, sieht es so aus.
-
- Move.l $0040.w,$0050.w
-
- belegt..
-
- 2 Bytes fuer den Move befehl
- 2 Bytes fuer die Adresse $00000040
- 2 Bytes fuer die Adresse $00000050
-
- ----------------------------------
- 6 Bytes
-
- Denkt daran, die schreibweise $0040 aendert nichts, das .w muss dahinter,
- denn ich kann den Befehl mit den Langwoertern auch so schreiben.
-
- Move.l $40,$50
-
- Es bleiben langwoerter, und als solche werden sie eingesetzt.
-
- Naja, wir haben also im Beispiel 4 Bytes gespart, was das ist nicht viel,
- das meint ihr aber auch nur, wenn ihr mal euren ersten Bootblock
- beschreibt, dann werdet ihr noch an mich denken, den dort zaehlt jedes
- Byte.
- Leider gibt es kein Kuerzel .B, denn dann waere die ersparnis noch
- groesser.
-
- Jetzt kommt ein Befehl den ich manchmal benutze, um schnell irgend was
- auszutauschen.
- Stellt euch vor ihr habt irgendwann mal eine tolle Routine geschrieben, die
- einen Haufen sachen ausrechnet, und die ergebnisse in allen Datenregistern,
- das heisst von 0 bis 7. Und irgendwann schreibt ihr mal ein programm das
- halt solche werte braucht, und ihr erinnert euch an die alte
- Routine...Jetzt merkt ihr aber das die routine etwas anders ist, und zwar
- so das das Ergebnis was die neue Routinen in d6 braucht, in d7 liegt, und
- das ergebnis was sie in d7 braucht, aber in d6 liegt.
- Jetzt gibt es drei moeglichkeiten dieser Situation Herr zu werden.
-
- Wir schreiben eine der beiden Routinen um...was aber bei 20 Kilobyte
- SourceCode nicht gerade leicht ist. Und da Programmierer grundsaetzlich
- faule Menschen sind, faellt das also weg.
-
- Also muessen wir gucken wie wir da sachen vertauscht kriegen, so viel ist
- klar. Man kann es mit dem Stack, oder mit einer X-beliebigen adresse
- machen. Hier die zwei moeglichkeiten.
-
- Move.l d6,$40000
- Move.l d7,d6
- Move.l $40000,d7
-
- Oder
-
- Move.l d6,-(a7)
- Move.l d7,d6
- Move.l (a7)+,d7
-
- Die zweite moeglichkeit ist etwas komplizierter, aber wird im Source
- kuerzer als die erste. Der effekt ist derselbe, was vorher in d6 stand
- steht jetzt in d7, und umgekehrt.
-
- Aber jetzt tritt der neue Befehl auf die Buehne. Er heisst schlicht und
- ergreifend `Exchange` kurz `EXG`, und mit ihm passiert dann die ganze
- sachen in einem Wort.
-
- Exg d6,d7
-
- Das wars...Im prinzip ist es dasselbe wie die kuerzere Variante von eben,
- denn der Prozessor macht genau das auch. Nur wenn er es macht geht es
- natuerlich viel schneller. Alles Klor ?
-
- Es kommt immer mal wieder vor das man, wenn man ein Intro programmiert, die
- einzelnen Effekte in Modulen abarbeiten laesst. Dabei kann es vorkommen das
- man die module an verschiedenen Tagen programmiert, und nicht darauf achtet
- welche Arbeits und datenregister man den nun noch frei hat. Und wenn man
- ein Intro mit 20 Effektmodulen hat, dann wird es eng mit den registern, mit
- denen man doch so hervorragend arbeiten kann, oder.
-
- So, da gibt es eine ganz einfache sache. Wir legen uns jeden die inhalte der
- Datenregister und der Adressregister jedes Modules, einen Sicherungsplatz
- an, indem wir nach abarbeitung des Modul alle sachen abspeichern, und bevor
- wir das naechste mal mit dem modul anfangen, holen wir uns einfach die
- sachen wieder rein. Das saehe, wenn wir es jetzt machen muessten allerdings
- etwas lang, naemlich so aus.
-
- Move.l d0,$40000
- Move.l d1,$40004
- ....
- ....
- Move.l a0,$40020
- Move.l a1,$40024
-
- naja das waere ja ein bisschen lang. Das haben sich die Leute die den 68000
- gebaut haben auch gedacht, und deshalb fuer den move befehl noch ein Kurzel
- ausgedacht. naemlich `m`. Das `m` steht fuer viele oder mehrere, das heisst
- wir koennen mit einem Befehl direkt mehrere register retten. Wir koennen
- sie dann auf den Stack oder einfach in den Speicher schreiben. Der Befehl
- der den Kompletten registerinhalt nach $40000 rettet sehae dann so aus.
-
- Movem.l d0-d7/a0-a6,$40000
-
- Er erhoeht auch selbsttaetig die adresse wo er das hinschreibt.
- Wir muessen allerdings nicht alles retten, sondern wir koennen auch ganz
- bestimmt retten. Wenn wir nur d0,d1,d4,d5,d7,a0,a1,a2 und a6 retten wollen
- schreiben wir einfach
-
- Movem.l d0-d1/d4-d5/d7/a0-a2/a6,$40000
-
- Also ihr seht..ziemlich cool der Befehl. Natuerlich geht es zurueck
- genauso. Der Befehl der den ersten Movem befehl von mir rueckgaengig macht
- heisst
-
- Movem.l $40000,d0-d7/a0-a6
-
- Mehr nicht...
-
- Nach moeglichkeit den Clr befehl in langen schleifen und auch sonst meiden.
- Denn er dauert einfach zu lange. Ein Ersatz fuer diese Schleife
-
- Lea $40000,a0
- Move.w #$ffff,d0
- Clearloop:
- Clr.l (a0)+
- Dbf d0,clearloop
- Rts
-
- waere ohne Clr.l, und sehr viel schneller...
-
- Lea $40000,a0
- Move.l #$ffff,d0
- Clearloop:
- Moveq.l #0,(a0)+
- Dbf d0,clearloop
- Rts
-
- All right ?
-
- Wenn ihr mal etwas groessere sachen programmiert, und ihr kleine Zeitliche
- abstaende braucht, dann koennt ihr euch ja mit der einfachen Warteschleife
- helfen die ihr schon kennt. Aber gerade bei sachen in Echtzeit, muss man
- manchmal kurze abstaende warten. Je nach dem sind die Abstaende sogar so
- kurz, das man noch nicht mal eine kleine Routine dazwischensetzen kann.
- Dazu gibt es einen netten Befehl, der eigentlich nichts macht. Und so
- heisst er auch..
-
- `Nop` - No OPeration
-
- Der Prozessor braucht Vier Taktzyklen um zu merken das der Befehl garkeinen
- gueltigen Code ergibt, dann springt er weiter. Solche Codes gibt es noch
- viele andere. Die Erbauer von Prozessoren, nehmen immer einen davon der
- dann den Namen `Nop` kriegt, und dann ist das so.
-
- So jetzt kommt die Aufstellung der Sprungkriterien fuer die Befehle aus der
- Gruppe der Bedingten Branch Befehle. Zwei davon kennt ihr ja schon, Bne und
- Beq, ich zaehle sie aber der komplettheit wegen nochmal auf.
-
- Das B davor muesst ihr euch immer denken, da ich nur die bedingung
- beschreibe.
-
- CC = Carry Flag nicht gesetzt (Carry Flag wird spaeter erklaert)
-
- CS = Carry Flag gesetzt
-
- EQ = Zero Flag gesetzt, oder letzte Operation gleich 0
-
- GE = Groesser oder Gleich > =
-
- GT = Groesser, aber mit vorzeichen >
-
- HI = Groesser >
-
- LE = Kleiner oder 0, aber mit vorzeichen <
-
- LS = Kleiner oder Gleich < =
-
- LT = Kleiner, aber mit vorzeichen <
-
- MI = Wert im Minus Bereich -
-
- NE = Zero Flag nicht gesetzt, oder letzte operation nicht 0 <>
-
- PL = Wert im Plus Bereich
-
- VC = Overflow nicht gesetzt, mit vorzeichen (Overflow Flag kommt spaeter)
-
- VS = Overflow gesetzt, mit vorzeichen
-
-
- So das waeren sie, den Groessten teil braucht man halt sehr selten, es ist
- aber schon mal gut wenn man weiss das es sie ueberhaupt gibt.
-
- So jetzt noch ein Paar Klaerende worte zum Carry- und Overflow Flag.
-
- Zuerst da carryflag....
-
- Was die Flags sind wisst ihr ja schon, deshalb kann ich ja loslegen.
- Das Carry Flag ist praktisch das 33 ste Bit der Datenregister, wenn ein
- Wert durch Addition zu gross fuer ein Datenregister wird, dann wird der
- rest ins Carry geschrieben. Deshalb mus man es bei Addtion und Subtraktion
- immer beruecksichtigen.
-
- Das Overflowflag ist immer dann gesetzt wenn bei der letzten operation, ein
- bereich ueberschritten wurde, sei es der Byte, Wort oder Langwort bereich.
- Sobald die Zahl diesen Ueberlaueft wird es gesetzt. Wofuer das gut sein
- soll weiss ich zwar nicht, aber ich habe es so gelernt.
-
- So jetzt erstmal in die Heia, muss morgen inne Schule...
-
- bis denne
-
- Jeff Kandle
-