A S S E M B L E R - K U R S (c) Jeff Kandle 1990 18.Teil... So jetzt erstmal wieder was zum Bueffeln, ein etwas schwieriges unterfangen. Wenn wir es aber beherrschen dann ist die grosse Lernphase der Kunst des Introprogrammirens leider schon vorbei. Kommen wir zu einem Chip des Amigas dem er einen grossen teil seiner Grafischen moeglichkeiten verdankt. 17.Der Blitter Vielleicht habt ihr schon irgendwelche Schauermaerchen ueber den Blitter gehoert, und ich gebt auch zu das es ziemlich Haarig ist in erstmal zu verstehen. Aber wenn man das gefressen hat dann ist er relativ einfach. Und die wirklich schweren Sachen machen wir ja jetzt noch nicht. Ich meine jetzt VectorenGrafik und solche Tollen sachen Wie Filled Bobs, oder Sogar Stencil Bobs. Auch werden wir nicht versuchen neue rekorde zu brechen, obwohl das jeder der ihn beherscht versucht, wir wollen einfach nur ein bisschen Kopieren und so... Erstmal: Wofuer ist der Blitter eigentlich da ? Nun im Amiga ist er fuer die Textausgabe da, er zeichnet die Fenster und schaufelt beim laden von Programmen die Daten aus den puffern in den Arbeitsspeicher, und decodiert sie gleichzeitig. Ganz schoen wichtig das Ding, oder ? Ja wichtig ist er, und schnell - Er kopiert mit einer Geschwindigkeit von 16 Millionen Punkten in der Sekunde Das ist verdammt schnell, ich glaube der Prozessor liegt knapp unter einer Millionen. Also liegt es doch auf der Hand das wir den fuer uns Arbeiten lassen. Wie sprechen ich den Blitter an ? Ganz einfach ueber die Hardwareregister, von denen wir schon soviele kennen und schaetzen gelernt haben. Fuer alles moegliche gibt es Register. Die Aufgabe von uns ist nur diese register richtig zu initialisieren, den rest macht der Blitter ganz alleine. Was uns am Blitter interressiert, ist das kopieren mit ihm. Nun dafuer stellt und der Blitter 3 Quellbereiche und 1 Zielbereich zur verfuegung. Man kann immer nur von Quellbereich in Zielbereich Schreiben, deswegen heissen sie auch so. Das Heisst von A,B,C, so heissen die Quellen, nach D, so heisst das Ziel. Allerding kann man auch die Quellen miteinander verknuepfen, aber das Spaeter. Uns Interresiert einfaches kopieren. Der Blitter braucht zum Kopieren einige Angaben, die Operation und das Ausmass betreffend. Erstmal muss er wissen, welche seiner Kanaele daran beteiligt ist. D ist meistens dabei, und A wenn es ums einfaches kopieren geht auch. Sagen wir also A und D. Dann muss man eingeben ob irgendwelche verknuepfungen waehrend der Aktion durchgefuehrt werden sollen. Das ist in unserem Fall ja nicht der Fall. Dann muessen wir dem Blitter sagen wo der bereich ist von dem wir die Daten abholen, das ist der Quellbereich. Da setzen wir mal $50000 ein. Nun kommt der Zielbereich, D genannt, dort setzen wir mal $60000 ein. Als letztes muss der Blitter noch wissen wieviel er von dort nach da kopieren soll. Sobald wir das eingegeben haben startet er auch die Aktion, denn das register indem die Angabe ueber die Groesse liegt ist ein Stroberegister (Sprich: Strohp) Das heisst, bei Schreibzugriff wird gleichzeitig eine Aktion gestartet. In dem Fall ist es der Blitter. Mit diesem Register fuer die laenge ist es aber etwas schwerer da man nicht einfach eingibt `So 100000 Bytes`, sondern man muss in gedanken aus der Anzahl der Bytes ein Rechteck bauen, und dem Register die Seitenlaenge A und B uebergeben. In manchen Faellen reicht es wenn wir die Quadratwurzel ziehen, und eine Grade zahl rauskommt. Bei 100 oder 10000 waere das zum Beispiel der fall. Aber das sind halt die Ausnahmen, also schauen wir mal wie wir das machen koennen. Bis auf eine Ausnahme arbeitet der Blitter nur mir Woertern, also muessen wir den bereich den wir kopieren wollen in Woertern angeben. Also, wenn wir z.b 30000 Bytes von $50000 nach $60000 kopieren wollen dann muessen wir den Bereich ungefaehr so definieren 300 Zeilen zu 100 Bytes bzw. 50 Woertern das heisst 300*50, sind 30000, so einfach ist das. Der Bereich ist aber Beschraenkt, die maximale Zeilenzahl betraegt 1024 Zeilen, wobei man da 0 als Zeilen zahl angeben muss, die nimmt er dann als 1024, da 0 ja eine Unsinnige angabe waere. Die maximale Breite betraegt 64 Woerter, wobei wieder das mit der 0 ist. Wir koennen also mit einem Schlag 128 KB durch den Speicher Schleudern, anders kann man es nicht mehr ausdruecken. Diese laengen und breiten angaben muessen wir aber auch irgendwie unterbringen in dem Registers unterbringen. Die ersten 6 Bits sind die Breite, und die restlichen 10 sind fuer die laenge. Wichtig ist aber wie wir die Masse da rein kriegen, einfach 300 * 50 kann man ja nicht schreiben, dann waere das System mit dem rechteckigen bereich wieder hin. Also muessen wir die LaengenBits auch noch oben schieben. Stellen wir uns das Leere BLTSIZE register , so heisst es naemlich, mal bildlich vor. I Zeilen I Breite 0000000000000000 I I Schreiben wir einfach mal die Zeilen zahl 9 rein. Mit Move.w #$9,Bltsize I Zeilen I Breite 0000000000001001 I I So jetzt steht die laenge aber in den Registern fuer die Breite, wie kriegen wir die rueber. Ganz einfach, mal 64, dann wird naehmlich alles nur um 6 Bit nach oben gesetzt. Also es sieht dann so aus I Zeilen I Breite 0000001001000000 I Zeilen I Naja, und weiter...Hmmm ich will euch nicht damit Qualen, es waeren ziemlich aufwendige rechnungen um die Sachen vom Programm da reinzusetzen. Erstmal reicht es wenn wir das vom Seka machen lassen. Bei unserem Beispiel saehe die Initialisierung des BLTSIZE registers ungefaehr so aus. Move.w #300*64+50,BLTSIZE So einfach ist das.... Damit haetten wir schon alle schritte die fuer ein Kopieraktion noetig waeren beisammen. Schreiben wir sie mal auf, mit SourceCode-beispiel. Quelle A und Ziel D angeben, keine Verknuepfung. Move.w #%0000100111110000,BLTCON0 Adresse der Quelle A angeben Move.l #$50000,BLTAPT Adresse des Ziels D angeben Move.l #$60000,BLTDPT Laenge und Breite angeben, und gleichzeitig Aktion starten Move.w #300*64+50,BLTSIZE Damit waere die Sache dann fertig...Komplett ist der Aufruf allerdings noch nicht. Es fehlen noch ein paar sachen die sehr viele moeglichkeiten mitsichbringen, aber beim normalen Kopieren nur hindern. Da waeren erstmal die Modulowerte fuer die Quelle und das Ziel. Ja, die Modulos mit denen wir bei den Bitplanes schon so toll arbeiten konnten, hat der Blitter auch. Sie geben an wieviel Bytes, hier ist die Ausnahme von der ich Sprach, nach jeder zeile uebersprungen werden sollen. Es gibt sie fuer die Quellbereiche A,B und C sowie fuer den Zielbereich D. Wir muessen diese Register natuerlich auf 0 setzen, damit es wirklich eine Kopie gibt. Desweiteren sind da BLTAFWM und BLTALWM. Sie sind fuer das erste und das letzte worte jeder zeile zustaendig. Mit ihnen kann man eine And Maske ueber eben diese beiden Woerter legen. Die And funktion kennt ihr ja schon, deshalb will ich das hier auch niocht nochmal erklaeren. Also, die muessen wir natuerlich vollschreiben, alles gesetzt brauchen wir. Und dann als letztes muessen wir natuerlich auf den Blitter warten bis das er fertig ist, denn sonst waere jede weitere Initialisierung sinnlos, denn wenn er arbeitet nimmt er keine Befehle entgegen. So wie warten wir den auf den Blitter ? Ganz einfach, im DMACON register gibt ja auch den Blitterkanal, solange der Blitter arbeitet wird der kanal geschlossen. Wir koennen das zwar nicht im DMACON register erfahren, da es ja kein Leseregister ist. Aber wofuer gibt es das DMACONR register. Dort fragen wir einfach das Bit 6 ab. Es gibt noch eine Zweite moeglichkeit, aber die ich hier vorgestellt habe benutze ich selbst schon immer und habe da nie Schwierigkeiten mit gehabt. Also eine Komplette Kopierroutine sieht dann so aus. Move.w #$ffff,BLTAFWM ; Maske fuer erstes Wort Move.w #$ffff,BLTALWM ; Maske fuer letztes Wort Move.w #$0000,BLTAMOD ; Modulo Register A auf Null Move.w #$0000,BLTDMOD ; Modulo Register D auf Null Move.w #%0000100111110000,BLTCON0 ; Bereiche anschalten, und ; moegliche Verknuepfungen anmelden Move.l #$50000,BLTAPT ; Quelladresse angeben Move.l #$60000,BLTDPT ; Zieladresse angeben Move.w #300*64+50,BLTSIZE ; Groesse der Operation, und Los WaitBlitter: Btst #6,DMACONR ; Bit vom DMA.Kanal testen. Bne.s WaitBlitter ; Nicht gedrueckt -> Zurueck Rts ; Gedrueckt -> Raus So, das ist ein Kompletter aufruf zu einer Kopieraktion des Blitters. Allerdings im loeschen ist er auch einsame Spitze. Man muss im da nur sagen wo der zu loeschende liegt, und das er nur mit dem Zielbereich arbeiten soll. Ein Aufruf der den Blitter veranlasst das ebenkopierte jetzt zu loeschen saehe dann so aus. Move.w #%0000000100000000,BLTCON0 Move.l #$50000,BLTDPT Move.w #300*64+50,BLTSIZE WaitBlitter: Btst #6,DMACONR Bne.s WaitBlitter Rts So, das sind die ersten anwendungsgebiete des Blitter, es gibt aber noch sehr viele mehr. Bevor ich mich im naechsten Teil so langsam an die Bobs, und an das Thema Laufschrift heranwage, zeige ich euch gerade noch wie man mit dem Blitter invertiert. Move.w #%0000100100001111,BLTCON0 Move.l #$60000,BLTAPT Move.l #$60000,BLTDPT move.w #300*64+50,BLTSIZE WaitBlitter: Btst #6,DMACONR Bne.s WaitBlitter Rts Zu beachten ist das Quelle und Ziel dieselbe Adresse erhalten, da die Operation sehr kompliziert ist. Was noch wichtig ist das ihr die Interrupts und das Taskswitching ausschaltet, denn der Blitter wird halt immer benutzt, und dann muesste man immer warten. Wenn wir allerdings den Rest abschalten macht der Blitter nor noch seine Aufgabe zuende, und gehoert dann sofort uns. Deshalb muessen wir bei einen Programm das den Blitter benutzt, immer ganz am anfang auf den Blitter warten, damit wir dann richtig loslegen koennen. Allerdings habe ich das jetzt etwas schlecht angefangen, da man die WaitBlitterschleife immer vor den Aufruf setzt, damit das Programm was den Blitter braucht schonmal weiter arbeitet, und erst auf den Blitter wartet wenn es ihn wieder braucht...Alles Klor ? Bis die tage... Jeff Kandle