VESA-Pixel setzen in Assembler Hier geht's um die praktische Durchfhrung des Theorietextes ber das Punktesetzen in den Modi 101h/103h/105h. Ich stelle hier nur die Routine vor, ein Programm, das diese einbindet, findet Ihr im Pfad 'SOURCE'. Also, die Routi: DOSSEG .MODEL SMALL .STACK 256 ScreenSeg equ 0A000h .DATA Granu db ? xAufloesung dw ? Puffer db 256 dup (?) FensterProc dw ? dw ? PUBLIC InitSetVESAPixASM PUBLIC SetVESAPixASM .CODE InitSetVESAPixASM PROC NEAR MOV AX,4F03h INT 10h ;VESA-Modus kommt in BX zurck MOV CX,BX ;Modus nach CX MOV AX,@Data MOV ES,AX ;ES mit Segment (Datensegment) von Puffer ; laden LEA DI,Puffer ;DI mit Offset " " " ; " MOV AX,4F01h INT 10h ;Infos holen und in Puffer ablegen MOV AX,WORD PTR Puffer+12h MOV XAufloesung,AX ;XAufloesung aus Puffer in Variable MOV AX,WORD PTR Puffer+04h MOV CX,6 ;Granularitt aus Puffer nach CX Schleife: SHR AX,1 JC Weiter2 LOOP Schleife Weiter2: MOV Granu,CL ;Bearbeitete 'Granularitt' nach Granu2 MOV AX,WORD PTR Puffer+0Ch MOV FensterProc,AX MOV AX,WORD PTR Puffer+0Eh MOV FensterProc+2,AX RET InitSetVESAPixASM ENDP SetVESAPixASM PROC NEAR SFrame STRUC BP0 dw ? Back dd ? Farbe dw ? y dw ? x dw ? SFrame ENDs Frame EQU [BP - BP0] PUSH BP MOV BP,SP MOV AX,ScreenSeg MOV ES,AX MOV AX,xAufloesung MOV BX,Frame.y MUL BX ADD AX,Frame.x JNC Weiter INC DX Weiter: MOV CL,Granu SHL DX,CL MOV DI,AX ;Offset nach DI XOR BX,BX ;Fenster 0 setzen CALL DWORD PTR FensterProc ;Das richtige Fenster ein- ;stellen MOV AL,BYTE PTR Frame.Farbe ;Farbe holen STOSB ;Farbe in Videospeicher POP BP RET 6 SetVESAPixASM ENDP END Wenn Ihr sie gut durchgeschaut habt und nebenbei noch mit der Routine aus der Pascal-Rubrik verglichen habt..., dann ist Euch sicherlich aufgefallen, da sie anders ist. Sie funktioniert aber trotzdem! Es gibt zwei Prozeduren: Die eine (InitSetVESAPixASM) initialis- iert die Variablen Granu, xAufloesung und FensterProc. Die andere (SetVESAPixASM) benutzt dann diese 'Startwerte' und setzt die bergebenen Punkte. Zuerst, weil es fr's Verstndnis einfacher ist, die Prozedur SetVESAPixASM: Die Prozedur baut zu Anfang einen Stack-Rahmen auf, soda man leicht ber Frame.VARIABLE auf eine der drei bergebenen Variab- len (x,y,Farbe) zugreifen kann. ES wird mit der Segmentadresse des Videosegments geladen. Weiter geht's mit der Berechnung des 'PseudoOffsets'. Die Vorgehensweise ist die gleiche, die auch im Theorieartikel beschrieben wurde. Doch gibt es da eine Schwierigkeit, die sich aber leicht in ein Vorteil umfunktionie- ren lt: Man mu ja eine Multiplikation der y-Koordinate mit der x-Auflsung durchfhren. Doch kann man in Assembler fr eine Multiplikation nur das AX-Register verwenden. Nun ist das AX-Register aber nur 16 Bit breit, kann also maximal den Wert 65535 annehmen. Das reicht aber fr die Berechnung des Pseudo- Offsets nicht, die dieser selbst in dem 'kleinsten' Modus (101h) bis zu 307199 gro sein kann. Doch: multipliziert man eine Zahl, und das Ergebnis wird grer als 65535, pat also nicht mehr ins AX-Register, so wird dieses sogesehen auf 32- Bit ausgebaut: das DX-Register springt ein. Man kann also in DX ablesen, wie oft AX 'bergelaufen' ist. So, und diese Zahl, die in DX abzulesen ist, hilft uns nun weiter: Man wei nun, da der Punkt, der gesetzt werden soll, im DX'ten Videofenster liegt, wenn man von einer Granularitt von 64 KB ausgeht. Das ist jetzt wahrscheinlich nur den Wenigsten klar, doch vielleicht hilft dieses Beispiel weiter: Ich will den Punkt (0/400) setzen. PseudoOffset : 400*640 = 256000. Nun wrde in AX E800h und in DX 3 stehen, da 256000 in Hex 3E800h ist (ehrlich!). Das wrde be- deuten, ich mte da Videofenster, um 3 * 65536 Byte verschie- ben, um ber 0A000h:0E800h den gewnschten Punkt zu setzen. Naja, war auch kein besonderns gutes Beispiel, aber egal. Halten wir fest: In DX knnen wir ablesen, um wieviele Segmente (um wieviele 65536er-Schritte) wir das Videofenster im Videospei- cher der Grafikkarte verschieben mssen. Halten wir durch das Beispiel auch noch fest: AX gibt nun direkt den Offset an, wo wir den Punkt hinsetzen sollen. Nun kommt nur noch eine Sache hinzu: Die x-Koordinate mu ad- diert werden. Auch hier kann es passieren, da AX 'berluft', also einen Wert annehmen wrde, der grer als 65535 ist. Da das nun mal aber nicht geht, wird in solch einem Fall das Carry- Flag gesetzt. Man fragt also einfach ab, ob das Carry-Flag auf 1 steht - und wenn ja, erhht man DX nochmals um eins. Nun hat man zwar die Anzahl der 'Segmente', um die das Video- fenster verschoben werden mu, doch ist ja nicht gegeben, da die Granularitt ebenfalls Segment-Gre, also 64Kb aufweist. Bei mir kann ich das Videofenster zum Beispiel nur mit einer Granularitt von 4Kb verschieben, da heit, ich mte das Vi- deofenster 16 mal verschieben (64/4=16), um es um ein Segment verschoben zu haben. Also mte man an sich 65536 durch die Granularitt teilen und dann die Zahl, die man in DX berechnet hat, mal dem Ergebnis nehmen. Nehmen wir das Beispiel von oben, wo DX 3 war, meine Granularitt von 4Kb und die daraus erfol- genen 16 Verschiebungen pro Segment und multiplizieren nun DX mit diesen 16. Das Ergebnis wre also 48 - Ich mte mein Vi- deofenster 48 mal verschieben, um den oben genannten Punkt rich- tig zu setzen. Alles klar? Gut! Nun dauert es aber einfach zu lange, eine Multiplikation durchzufhren. Und da gibt es auch eine Lsung: Schneller als der MUL-Befehl ist der Befehl SHL, der einen Bitweisen Linksshift durchfhrt, was einer Multipli- kation zur Basis 2 ermglicht - also mit 2, 4, 8 etc. Und da die Granularitt ebenfalls immer eine Potenz von 2 ist, lt sich das gut vereinen. Wie das genau abluft, steht unten, da da in der Prozedur InitSetVESAPixASM gemacht wird. Hier findet SetVESAPixASM nur ein Zahl wieder (in Granu bergeben), die an- gibt, um wieviele Stellen DX nach links geshiftet werden mu, um die richtige Anzahl der Fenster zu bekommen. Irgendwie habe ich den Eindruck, da das relativ schwierig zu verstehen ist... Aber weiter: Hat man nun alles, was man zum Setzen des Punktes bentigt, berechnet, schiebt man den Offset, der sich noch in AX befindet nach DI, setzt BX auf null (also: 1. Fenster setzen) und ruft dann mittels einem FAR-CALL die Routine auf, die das Videofenster verschiebt. Dies wre auch mit der Unterfunktion 05h mglich gewesen, doch ist es so um einiges schneller. Zum Schlu wird dann noch die Farbe in ES:DI, also in 0A000h:Offset geschrieben, und der Punkt erscheint am Monitor! InitSetVESAPixASM: Die Routine liest zuerst den VESA-Modus aus, der zur Zeit aktu- ell ist. Dieser kommt in BX zurck und wird dann gleich nach CX 'ge-mov-t'. Dann wird die Unterfunktion 01h (hole Infos) vorbe- reitet: ES:DI zeigt auf Puffer. An der Adresse 12h findet sich ein WORD, da die x-Auflsung angibt. Eigentlich mte man noch abfragen, ob diese berhaupt zurckgeliefert wurden (ber's erste Byte im Puffer). Das spare ich mir aber, da diese Info eigentlich immer vorhanden ist. An der Pufferstelle 04h befindet sich die Granularitt. Doch knnen wir sie so, wie sie dort steht, nicht gebrauchen(s.o.). Die Speicherstelle gibt an, in welchen Schritten das Fenster verschoben werden kann. Was wir aber brauchen, ist, wie oben beschrieben, die Anzahl der Bits, um die wir die Anzahl der berechneten Segmente, um die wir das Videofenster verschieben mssen, nach links shiften mssen, um die reale Anzahl der Verschiebungen herauszubekommen, um die das Videofenster verschoben werden mu.... ;->. Toller Satzbau! Lest das Ding mindestens noch 50 mal, vielleicht wird dann deut- lich, was ich meine - zumindest steht alles drin! Um diese An- zahl also zu erhalten, habe ich mir folgenden Zusammenhang klar gemacht: Vorgefundene Binr- Nummer der '1' Anzahl der Links- Granularitt schreibweise shifte 1 0000 0001 1 6 2 0000 0010 2 5 4 0000 0100 3 4 8 0000 1000 4 3 16 0001 0000 5 2 32 0010 0000 6 1 64 0100 0000 7 0 Was soll uns diese Tabelle sagen? Sie soll den Zusammenhang zwischen der binren Schreibweise der Granularitt, die man im Puffer bei 04h vorfindet, und der Anzahl der Linksshifte, die man spter bentigt, um die Anzahl der Verschiebungen fr das Videofenster zu ermitteln, erlutern. Wie man sieht, ergibt sich diese Anzahl aus 7 minus der Stelle, wo die '1' in der binren Schreibweise steht. Also: haben wir eine Granularitt von 4Kb, befindet sich die '1' bei 00000100 an der 3. Stelle. Das heit, wir mssen DX um 4 Stellen (7-3) nach links shiften, bzw. mal 16 nehmen (s.o.), um das richtige Videofenster einzustellen. Haben wir eine Granularitt von 64Kb, so braucht man DX natr- lich nicht mehr verschieben, was man auch aus der oberen Tabelle entnehmen kann. Wie das gemacht wird, kann man dem Listing ent- nehmen. Zum Schlu der Prozedur wird noch Sprungadresse fr den FAR-CALL ermittelt, der im Puffer ab 0Ch steht (Offset und Seg- ment). Tja, damit wre eigentlich alles erklrt. Ich gebe zu, da es nicht ganz einfach ist, aber glaubt mir: auch nicht fr mich! Es ist ziemlich schwierig, ein Problem zu erlutern, da man mit- lerweile in- und auswendig kennt. Aber: Lest den Text einfach noch ein paar mal. Irgendwann wird schon etwas hngenbleiben. Und wenn nicht, gibt's ja immer noch den Brief an uns...! Kemil