Textausgabe im Modus 12h So, den Theorieteil habt Ihr hoffentlich hinter Euch, jetzt geht's um die praktische Durchfhrung in Assembler. Ich habe die Dokumentation diesmal ein wenig anders gemacht als in vorherigen Artikeln. Ich hoffe, es freut Euch ;-). Allerdings habe ich nur die erste Prozedur (G_TranText) 'richtig' dokumen- tiert. Die anderen sehen so aus, wie ich sie fr mich habe... Ich glaube aber, es reicht. DOSSEG .MODEL SMALL .STACK 256 PUBLIC G_TranText ; Transparente Textausgabe im 'Grafikmodus-Stil' PUBLIC T_TranText ; Transparente Textausgabe im 'Textmodus-Stil' PUBLIC T_SolidText ; Solide Textausgabe (mit Hintergrundfarbe) im 'Textmodus-Stil' PUBLIC G_SolidText ; Solide Textausgabe (mit H-Farbe) im 'Grafikmodus-Stil' .DATA TSeg dw (?) TOfs dw (?) ; Segment und Offset der Zeichentabelle im Speicher StringSeg dw (?) StringOfs dw (?) ; Segment und Offset der bergebenen Zeichenkette im Speicher x dw (?) y dw (?) ; Naja, was wohl? VFarbe db (?) HFarbe db (?) ; Vorder- und Hintergrundfarbe .CODE G_Tran MACRO Entfernung,ZeichenByte LOCAL G_TranEnde ; Mu als LOCAL deklariert werden mov ah,[si+ZeichenByte] ; angegebenes ZeichenByte auslesen cmp ah,0 ; Leerzeile? --> nicht ausgeben! je G_TranEnde ; Springe nach TranEnde xor al,al ; al lschen shr ax,cl ; BitMasken 'zurecht schieben' mov ch,al ; BitMaske2 nach ch mov al,08h ; BitMask-Register setzen out dx,ax ; BitMask-Register auf BitMaske1 mov bh,es:[di+Entfernung] ; LatchRegister auslesen mov es:[di+Entfernung],bl ; LatchRegister beschreiben mov ah,ch ; BitMaske2 nach ah out dx,ax ; BitMask-Register auf BitMaske2 mov bh,es:[di+Entfernung+1] ; LatchRegister auslesen mov es:[di+Entfernung+1],bl ; LatchRegister beschreiben G_TranEnde: ; Und wech ENDM G_TranText PROC FAR sFrame STRUC BP0_G_tran dw (?) Return_G_tran dd (?) ; Rcksprungadresse StringOfs_G_tran dw (?) StringSeg_G_tran dw (?) ; Segment und Offset von String im Speicher Farbe_G_tran dw (?) ; Vordergrundfarbe y_G_tran dw (?) x_G_tran dw (?) ; Koordinaten fr Ausgabe sFrame ends Frame equ [BP-BP0_G_tran] push bp mov bp,sp ; BP retten und mit SP laden (fr Stack-Operationen) mov ax,Frame.StringSeg_G_tran mov StringSeg,ax mov ax,Frame.StringOfs_G_tran mov StringOfs,ax mov ax,Frame.x_G_tran mov x,ax ; Alle Werte vom Stack holen und Variablen zwischenspeichern mov bx,Frame.y_G_Tran ; y nach bx mov ax,80 ; Faktor 80 nach ax mul bx ; ax = bx * ax mov di,ax ; berechnete Zeile nach DI mov ax,x ; x nach ax shr ax,3 ; ax = x div 8 add di,ax ; Spaltenoffset dazu and x,7 ; x = x MOD 8 mov bx,Frame.Farbe_G_tran ; Farbe nach bl ; Hier wird nun die Position fr die Ausgabe ermittelt (steht ; in DI), die Anzahl, um die die Bytes aus der Zeichentabelle ; verschoben werden mssen, bestimmt und bx/bl mit der Vorder- ; grundfarbe geladen. mov ax,1130h ; Position des Zeichensatzes ermitteln: mov bh,02h ; BP : Offset ; ES : Segment int 10h ; Aufruf des Interrupts 10h mov TOfs,bp ; Offset von ZeichenTabelle nach TOfs mov TSeg,es ; Segment von Zeichentabelle nach TSeg mov dx,03CEh ; Adresse des GraphicControllers mov ax,0205h ; Write Modus 2 / Read Modus 0 out dx,ax ; setzen mov ax,0003h ; Mode-Register : berschreiben out dx,ax ; setzen ; Die Position des 14'er Zeichensatzes wird bestimmt (BH=02h), ; wobei die Segmentadresse in TSeg und die Offsetadresse in ; TOfs zwischengespeichert werden. Anschlieend wird der ; WriteModus 2 (und der ReadModus 0, aber unwichtig) einge- ; stellt und das Mode-Register auf 'berschreiben' gesetzt. mov bp,StringOfs ; Offset des bergebenen Strings nach bp mov es,StringSeg ; Segment des bergebenen Strings nach es xor cx,cx ; CX auf null mov cl,es:[bp] ; Anzahl der Zeichen nach CL ; ES:BP wird mit Segment und Offset des bergebenen Strings ; geladen. CX erhlt die Anzahl der auszugebenen Zeichen ; (steht in Pascal immer im ersten Byte vor der eigentlichen ; Zeichenkette!) G_TextTran: inc bp ; BP zeigt auf das nchste Zeichen mov ax,StringSeg ; Segment der Zeichenkette nach AX mov es,ax ; und nun nach ES mov bh,es:[bp] ; Das nchste Zeichen nach BH schaffen cmp bh,32 ; Wenn's kein Leerzeichen ist: jne G_Tran_NoSpace ; Ausgabe! Sonst: inc di ; Nchste Zeile loop G_TextTran ; Nchstes Zeichen jmp G_Tran_Ende ; Wenn kein Zeichen mehr da: Ende G_Tran_NoSpace: ; Alles andere, nur kein Leerzeichen mov ax,0A000h ; Adresse des Videosegments nach AX mov es,ax ; und dann nach ES mov ax,14 ; 14 Bytes pro Zeichen mul bh ; Offset vom Zeichen berechnen mov si,TOfs ; ZeichenTabellen-Offset nach SI add si,ax ; Offset vom Zeichen zu SI addieren ; Hier wird die Adresse des Zeichens ermittelt. ; Adresse = ASCII-Code vom Zeichen * 14 + Offset der Zeichen- ; satztabelle. push ds ; DS auf den Stack push cx ; CX auch mal retten mov cl,byte ptr x ; CX := 'x' --> Anzahl der Verschiebungen ; um die das ZeichenByte nach rechts ge- ; shiftet werden mu. mov ds,TSeg ; Segment vom ZeichenSatz nach DS G_Tran 0, 0 ; Adresse DI+ 0, ZeichenByte 0 G_Tran 80, 1 ; Adresse DI+80, ZeichenByte 1 G_Tran 160, 2 ; Adres... G_Tran 240, 3 ; . G_Tran 320, 4 ; . G_Tran 400, 5 ; . G_Tran 480, 6 ; . G_Tran 560, 7 ; . G_Tran 640, 8 ; . G_Tran 720, 9 ; . G_Tran 800, 10 ; . G_Tran 880, 11 ; . G_Tran 960, 12 ; . G_Tran 1040,13 ; Bringe Zeichen auf den Bildschirm pop cx ; CX vom Stack pop ds ; DS zurck holen inc di ; Nchste Speicherstelle bzw. Zeile im ; Videospeicher dec cx ; Schleifenzhler dekrementieren jz G_Tran_Ende ; Wenn CX = 0 (kein Zeichen mher da), ; dann Ende jmp G_TextTran ; Ansonsten: nchstes Zeichen holen G_Tran_Ende: mov dx,03ceh ; Ausgangssituation wiederherstellen mov ax,0005h out dx,ax ; Write Modus #0 ReadModus #0 mov ax,0ff08h out dx,ax ; MapMaskRegister auf $ff pop bp ; bp vom Stack retf 10 ; Zurck zu TP G_TranText ENDP T_Tran MACRO Entfernung,ZeichenByte LOCAL T_TranEnde ; Mu LOCAL deklariert sein mov ah,[si+ZeichenByte] ; Nchstes CharakterByte auslesen cmp ah,0 ; Wenn's ne Leerzeile: Wozu ausgeben? je T_TranEnde ; Springe nach TranEnde out dx,ax ; Bit Mask Register auf CharakterByte mov bh,es:[di+Entfernung] ; LatchRegister auslesen mov es:[di+Entfernung],bl ; LatchRegister beschreiben T_TranEnde: ENDM T_TranText PROC FAR sFrame STRUC BP0_T_tran dw (?) Return_T_tran dd (?) StringOfs_T_tran dw (?) StringSeg_T_tran dw (?) Farbe_T_tran dw (?) y_T_tran dw (?) x_T_tran dw (?) sFrame ends Frame equ [BP-BP0_T_tran] push bp mov bp,sp ; SP in BP mov ax,Frame.StringSeg_T_tran mov StringSeg,ax mov ax,Frame.StringOfs_T_tran mov StringOfs,ax mov ax,Frame.x_T_tran mov x,ax mov bx,Frame.y_T_Tran mov ax,80 ; Faktor 80 nach ax mul bx ; ax := bx * ax mov di,ax ; berechnete Zeile nach DI add di,x ; x dazu addieren ("TextModus") mov bx,Frame.Farbe_T_Tran ; bl mit Farbenummer laden mov ax,1130h ; Position des Zeichensatzes ermitteln: mov bh,2h ; BP : Offset ; ES : Segment int 10h mov TOfs,bp ; Offset von ZeichenTabelle nach TOfs mov TSeg,es ; Segment von Zeichentabelle nach TSeg mov dx,03CEh ; Adresse des GraphicControllers mov ax,0205h out dx,ax ; Write Modus 2 / Read Modus 0 mov ax,0003h out dx,ax ; Mode-Register : berschreiben mov bp,StringOfs ; Offset des bergebenen Strings nach bp mov es,StringSeg ; Segment des bergebenen Strings nach es xor cx,cx mov cl,es:[bp] ; Anzahl der Zeichen nach cl T_TextTran: inc bp ; Nchstes Zeichen lesen mov ax,StringSeg mov es,ax ; StringSeg nach es mov bh,es:[bp] ; Zeichen auslesen (nach bh) cmp bh,32 ; Wenn's ein Leerzeichen ist: jne T_Tran_NoSpace ; berspringe Ausgabe! Sonst: inc di ; Nchstes CursorPosition loop T_TextTran ; Nchstes Zeichen jmp T_Tran_Ende ; Wenn kein Zeichen mehr da: Ende T_Tran_NoSpace: ; Alles andere, nur kein Leerzeichen mov ax,0A000h mov es,ax ; VideoSegment nach es mov ax,14 ; 14 Bytes pro Zeichen mul bh ; Offset vom Zeichen berechnen mov si,TOfs ; Charakter-Tabelle Ofs in SI add si,ax ; Offset von Zeichen ins SI push ds ; ds auf den Stack mov ds,TSeg ; Segment vom ZeichenSatz nach DS mov al,08h T_Tran 0 , 0 T_Tran 80 , 1 T_Tran 160 , 2 T_Tran 240 , 3 T_Tran 320 , 4 T_Tran 400 , 5 T_Tran 480 , 6 T_Tran 560 , 7 T_Tran 640 , 8 T_Tran 720 , 9 T_Tran 800 ,10 T_Tran 880 ,11 T_Tran 960 ,12 T_Tran 1040,13 ; Bringe Zeichen auf den Bildschirm pop ds ; ds zurck holen inc di ; Nchste Speicherstelle dec cx ; Schleifenzhler dekrementieren jz T_Tran_Ende ; Wenn cx = 0 dann Ende jmp T_TextTran ; Ansonsten: nchstes Zeichen holen T_Tran_Ende: mov dx,03ceh ; Ausgangssituation wiederherstellen mov ax,0005h out dx,ax ; Write Modus #0 ReadModus #0 mov ax,0ff08h out dx,ax ; MapMaskRegister auf $ff pop bp ; bp vom Stack retf 10 ; Zurck zu TP T_TranText ENDP T_Vordergrund MACRO Entfernung mov es:[di+Entfernung],bh ENDM T_Hintergrund MACRO Entfernung,ZeichenByte LOCAL T_HinterGrund_Ende mov ah,[si+ZeichenByte] cmp ah,0 je T_HinterGrund_Ende out dx,ax mov es:[di+Entfernung],bl T_HinterGrund_Ende: ENDM T_SolidText PROC FAR sFrame STRUC BP0_T_solid dw (?) Return_T_solid dd (?) StringOfs_T_solid dw (?) StringSeg_T_solid dw (?) HFarbe_T_solid dw (?) VFarbe_T_solid dw (?) y_T_solid dw (?) x_T_solid dw (?) sFrame ends Frame equ [BP-BP0_T_solid] push bp mov bp,sp ; SP in BP push ds mov ax,@Data mov ds,ax ; Init DS mov ax,Frame.StringSeg_T_solid mov StringSeg,ax mov ax,Frame.StringOfs_T_solid mov StringOfs,ax mov ax,Frame.VFarbe_T_solid mov VFarbe,al mov ax,Frame.HFarbe_T_solid mov HFarbe,al mov ax,Frame.x_T_solid mov x,ax mov bx,Frame.y_T_Solid ; y nach bx mov ax,80 ; Faktor ax mit 80 laden mul bx ; ax = ax * bx mov di,ax ; berechnete Zeile nach di add di,x ; x = Spaltenoffset dazu ('TextModus') mov ax,1130h ; Position des Zeichensatzes ermitteln mov bh,2h int 10h ; BP : Offset ; ES : Segment mov TOfs,bp mov TSeg,es ; Adresse vom Zeichensatz laden mov dx,03ceh mov ax,0205h out dx,ax ; Write Modus 2 / Read Modus 0 mov ax,0003h out dx,ax ; berschreib-Modus mov bp,StringOfs mov es,StringSeg xor cx,cx mov cl,es:[bp] ; Lnge des Strings nach cl mov bl,VFarbe ; Farbe Vordergrund CLI T_TextSolid: inc bp ; Nchstes Zeichen mov ax,@data mov ds,ax mov es,StringSeg mov bh,es:[bp] ; Zeichen auslesen mov ax,0A000h mov es,ax mov ax,14 ; 14 Bytes pro Zeichen mul bh ; Offset vom Zeichen im RAM berechnen mov si,TOfs add si,ax ; Offset von Zeichen ins SI mov bh,HFarbe ; Farbe Hintergrund mov ds,TSeg ; Segment vom ZeichenSatz nach DS mov ah,0ffh mov al,08h out dx,ax T_Vordergrund 0 T_Vordergrund 80 T_Vordergrund 160 T_Vordergrund 240 T_Vordergrund 320 T_Vordergrund 400 T_Vordergrund 480 T_Vordergrund 560 T_Vordergrund 640 T_Vordergrund 720 T_Vordergrund 800 T_Vordergrund 880 T_Vordergrund 960 T_Vordergrund 1040 mov ah,es:[di] T_Hintergrund 0,0 T_Hintergrund 80,1 T_Hintergrund 160,2 T_Hintergrund 240,3 T_Hintergrund 320,4 T_Hintergrund 400,5 T_Hintergrund 480,6 T_Hintergrund 560,7 T_Hintergrund 640,8 T_Hintergrund 720,9 T_Hintergrund 800,10 T_Hintergrund 880,11 T_Hintergrund 960,12 T_Hintergrund 1040,13 inc di dec cx jz T_Solid_Weiter2 jmp T_TextSolid T_Solid_Weiter2: mov dx,03ceh ;Ausgangszustand wieder herstellen mov ax,0ff08h ; BitMaskRegister auf ff out dx,ax mov ax,0005h ; ModeRegister auf 00 out dx,ax STI pop ds pop bp retf 12 T_SolidText ENDP G_Vordergrund MACRO Entfernung mov ah,es:[di+Entfernung] mov es:[di+Entfernung],bh ENDM G_Hintergrund MACRO Entfernung,ZeichenByte xor al,al ; al auf null mov ah,[si+ZeichenByte] ; CharakterByte aus Tabelle holen shr ax,cl ; ah verschieben mov ch,al ; Zweites CharakterByte retten mov al,08h ; MapMaskRegister out dx,ax ; mit erstem CharakterByte laden mov ah,es:[di+Entfernung] mov es:[di+Entfernung],bl mov ah,ch ; ah mit zweiten CharakterByte laden out dx,ax ; und ins MapMaskRegister damit mov ah,es:[di+Entfernung+1] mov es:[di+Entfernung+1],bl ENDM G_SolidText PROC FAR sFrame STRUC BP0_G_solid dw (?) Return_G_solid dd (?) StringOfs_G_solid dw (?) StringSeg_G_solid dw (?) HFarbe_G_solid dw (?) VFarbe_G_solid dw (?) y_G_solid dw (?) x_G_solid dw (?) sFrame ends Frame equ [BP-BP0_G_solid] push bp mov bp,sp ; SP in BP push ds mov ax,@Data mov ds,ax ; Init DS mov ax,Frame.StringSeg_G_solid mov StringSeg,ax mov ax,Frame.StringOfs_G_solid mov StringOfs,ax mov ax,Frame.VFarbe_G_solid mov VFarbe,al mov ax,Frame.HFarbe_G_solid mov HFarbe,al mov ax,Frame.x_G_solid mov x,ax mov bx,Frame.y_G_Solid ; bx mit y laden mov ax,80 ; Faktor 80 nach ax mul bx ; ax = bx * ax mov di,ax ; berechnete Zeile nach DI mov ax,x ; x nach ax shr ax,1 shr ax,1 shr ax,1 ; ax = x div 8 add di,ax ; Spaltenoffset dazu and x,7 ; x = x MOD 8 mov ax,1130h ; Position des Zeichensatzes ermitteln mov bh,2h int 10h ; BP : Offset ; ES : Segment mov TOfs,bp mov TSeg,es ; Adresse vom Zeichensatz laden mov dx,03ceh mov ax,0205h out dx,ax ; Write Modus 2 / Read Modus 0 mov ax,0003h out dx,ax ; berschreib-Modus mov bp,StringOfs mov es,StringSeg xor cx,cx mov cl,es:[bp] ; Lnge des Strings nach cl mov bl,VFarbe ; Farbe Vordergrund CLI G_TextSolid: inc bp ; Nchstes Zeichen mov ax,@data mov ds,ax mov es,StringSeg mov bh,es:[bp] ; Zeichen auslesen mov ax,0A000h mov es,ax mov ax,14 ; 14 Bytes pro Zeichen mul bh ; Offset vom Zeichen im RAM berechnen mov si,TOfs add si,ax ; Offset von Zeichen ins SI mov bh,HFarbe ; Farbe Hintergrund push cx mov ax,0ff00h ; Hintergrund bestimmen mov cx,x ; lade cl mit Anzahl der Verschiebungen shr ax,cl ; und 'richtig' schieben mov ch,al ; Zweites CharakterByte retten mov al,08h ; MapMaskRegister out dx,ax ; auf erstes CharakterByte mov ds,TSeg ; Segment vom ZeichenSatz nach DS G_Vordergrund 0 G_Vordergrund 80 G_Vordergrund 160 G_Vordergrund 240 G_Vordergrund 320 G_Vordergrund 400 G_Vordergrund 480 G_Vordergrund 560 G_Vordergrund 640 G_Vordergrund 720 G_Vordergrund 800 G_Vordergrund 880 G_Vordergrund 960 G_Vordergrund 1040 ; Erster Hintergrund schreiben mov ah,ch ; Zweites CharakterByte nach ah out dx,ax ; Und ins MapMaskRegister damit G_Vordergrund 1 G_Vordergrund 81 G_Vordergrund 161 G_Vordergrund 241 G_Vordergrund 321 G_Vordergrund 401 G_Vordergrund 481 G_Vordergrund 561 G_Vordergrund 641 G_Vordergrund 721 G_Vordergrund 801 G_Vordergrund 881 G_Vordergrund 961 G_Vordergrund 1041 ; Zweiter Hintergrund schreiben VorderGrund: G_Hintergrund 0,0 G_Hintergrund 80,1 G_Hintergrund 160,2 G_Hintergrund 240,3 G_Hintergrund 320,4 G_Hintergrund 400,5 G_Hintergrund 480,6 G_Hintergrund 560,7 G_Hintergrund 640,8 G_Hintergrund 720,9 G_Hintergrund 800,10 G_Hintergrund 880,11 G_Hintergrund 960,12 G_Hintergrund 1040,13 pop cx inc di dec cx jz G_Solid_Weiter2 jmp G_TextSolid G_Solid_Weiter2: mov dx,03ceh ;Ausgangszustand wieder herstellen mov ax,0ff08h ; BitMaskRegister auf ff out dx,ax mov ax,0005h ; ModeRegister auf 00 out dx,ax STI pop ds pop bp retf 12 G_SolidText ENDP END Nunja, ich hoffe mal, da das hier berhaupt noch einer liest ;-) Aufgefallen sind Euch sicherlich die hufigen Macro-Anweisungen und 'Aufrufe'. Man htte das ganze natrlich auch als Schleife konzipieren knnen, nur mte man dafr ein weiteres mal das CX- Register retten, was wiederum Zeit kosten wrde. So ist ein wenig schneller und meiner Meinung nach gar nicht allzu unbersicht- lich, oder? Achja: Strt Euch bitte nicht daran, da ich die Vordergrund und Hintergrund-Label und Macros ein wenig durcheinander geworfen habe... ich hatte aber keinen Bock mehr, es richtig zu stellen... Es funktioniert (hoffentlich auch bei Euch), und das ist doch die Hauptsache, oder? Falls es jemanden unter Euch geben sollte, der tatschlich durch- gestiegen ist und dann womglich auch noch etwas verschnellern konnte (was ich echt nicht ausschlieen mchte), dann mge er sich doch mal bei mir/uns melden. Naja, dafr, da dies der lngste Text ist, der je bei uns er- schienen ist, bitte ich vielmals um Entschuldigung! Man schreibt sich, Kemil.