
                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

