Artikel
Text im Grafikmodus
Eigene Zeichensätze schnell darstellen
Das Beschriften von Grafiken ist eine Aufgabe, die oft auf einen Programmierer zukommt. Zahlreiche Möglichkeiten, Zeichen im Grafikmodus auszugeben, bietet das BIOS. Wem diese Funktionen nicht genügen, dem stellen wir ein schnelles und erweiterbares Assemblermodul vor, um beliebige Zeichen in Bildschirmgrafiken zu setzen.
Von der CGA
über die EGA bis hin
zur VGA bietet das
Video-BIOS immer mehr
Möglichkeiten, Texte im Grafikmodus auszugeben und hierzu
vorhandene oder eigene Zeichensätze zu benutzen.
Im Unterschied zum Textmodus, in dem der
Zeichencode und das Attributbyte aus dem Bildschirmspeicher
automatisch in die entsprechenden Bildpunkte umgesetzt werden, müssen
bei der Zeichenausgabe im Grafikmodus die Position und Abfolge der
Pixel einzeln bestimmt werden. Ihre Adressen im Videospeicher und
ihre Programmierung sind zudem abhängig vom Grafikmodus selbst.
Tabelle 1. Interrupt 10h – Aufrufe zur Darstellung von Text im Grafikmodus | ||
---|---|---|
ah | Beschreibung | Parameter für den Aufruf |
2 | Set Cursor Location Auch in den Grafikmodes gelten Textkoordinaten! |
|
9 | Write Character & Attribute at Cursor Location |
|
0Ah | Write Character at Cursor Location |
|
0Eh | Display Character in Teletype Mode |
|
11h | Character Generator Interfaces | siehe Tabelle 2 |
13h | Display Character String |
|
In den Tabellen 1 und 2 sind die Funktionsaufrufe des Softwareinterrupts 10h zusammengefaßt, mit denen man Zeichen in einem Grafikmodus ausgeben kann. Diese Funktionen haben eine sinngemäße Bedeutung in den Textmodi.
Tabelle 2. Interrupt 10h, ah = 11h: Character Generator Interface | ||
---|---|---|
al | Beschreibung | Parameter für den Aufruf |
0 |
Load alphanumeric character definition Benutzerdefinierbarer Zeichensatz |
|
1 | 8×14-Matrix des ROM-BIOS |
|
2 | 8×8-Matrix des ROM-BIOS |
|
3 | Character Map Select Register setzen |
|
4 | 8×16-Matrix des ROM-BIOS Load alphanumeric character definition and program the CRT |
|
10h | Benutzerdefinierter Zeichensatz |
|
11h | 8×14-Matrix des ROM-BIOS |
|
12h | 8×8-Matrix des ROM-BIOS |
|
14h | 8×16-Matrix des ROM-BIOS Load graphics character definition |
|
20h | Benutzerdefinierter Zeichensatz mit 8×8-Matrix für INT 1Fh |
|
21h | Benutzerdefinierter Zeichensatz |
|
22h | 8×14-Matrix des ROM-BIOS |
|
23h | 8×8-Matrix des ROM-BIOS |
|
24h | 8×16-Matrix des ROM-BIOS |
|
30h | Informationen über den derzeitigen Character Generator |
|
Das BIOS hat's
Den Ort, an dem Text mit einer BIOS-Funktion
ausgegeben werden kann, legt der Cursor fest. Seine Position ist in
der Video Display Data Area (Tabelle 3) für alle
anwählbaren Bildschirmseiten gespeichert und kann mit Interrupt
10h, Funktion 2, auf eine neue Stelle gesetzt werden. Die
Funktionsnummer wird dem Interrupt im Register ah übergeben. So
wie die Cursorposition werden alle Systemvariablen in der Video
Display Data Area gespeichert und von den jeweiligen
Interrupt-10h-Aufrufen abgefragt oder verändert.
Jene BIOS-Aufrufe, die Zeichen in einem
Grafikmodus darstellen können, verwenden einen Zeichensatz, der
nach der Anwahl des Grafikmodus ausdrücklich bestimmt werden
muß. Das besorgt Funktion 11h, die wegen ihrer besonderen
Bedeutung und ihres Parameterumfangs in der Tabelle 2 herausgehoben
ist.
Ein Aufruf mit den Parametern al = 0 bis 4 legt
einen Zeichensatz für einen Textmodus fest, bei den Parametern
al = 10h bis 14h wird zudem der Cathode Ray Tube Controller (CRTC)
für die neue Zeilen- und Spaltenzahl umprogrammiert. Der
Interrupt-10h-Aufruf mit ax = 1112h, bl = 0 schaltet beispielsweise
eine VGA vom Textmode 80×25- in die 80×50-Darstellung.
Der Zeichensatz mit der 8×8-Matrix stammt
aus der CGA. Die erste Hälfte seiner Zeichenmatrizen, das sind
die Zeichencodes 0 bis 127, sind an einer festen Speicheradresse
(F000:FA6Eh) im ROM des PCs abgelegt. Das MS-DOS-Programm Graftabl
installiert den zweiten Teil (Zeichencodes 128 bis 255) resident im
RAM und richtet den Interruptvektor 1Fh auf diese Zeichenmatrizen.
Wenn dieser Zeiger nicht korrekt gesetzt ist – beispielsweise
noch mit 0000:0000h initialisiert – werden bei Ausgabe der
Zeichen 128 bis 255 im Grafikmodus unsinnige Pixelanreihungen aus den
ersten 1024 Byte des Hauptspeichers ausgegeben, auf dessen Anfang der
Vektor 0000:0000h ja zeigt.
Tabelle 3. Video Display Data Area | ||
---|---|---|
Adresse | Typ | Beschreibung für den Aufruf |
0040:0040h | Word | Größe des verwendeten Videospeichers in Bytes |
0040:0050h | Word*8 | Cursorpositionen für maximal 8 Bildschirmseiten, Zeile im MSB, Spalte im LSB |
0040:0060h | Word | Oberste (MSB) und unterste (LSB) Linie des Cursorblocks |
0040:0084h | Byte | Angezeigte Textzeilen pro Bildschirmseite − 1 |
0040:0085h | Word | Höhe der Zeichenmatrix |
Mit der EGA kam die 8×14-Matrix hinzu, und
mit der MCGA und der VGA die 8×16-Matrix. Natürlich
ergeben bei den jeweiligen Grafikkarten nur die Funktionsaufrufe aus
Tabelle 2 sinnvolle Ergebnisse, die sich auf vorhandene Eigenschaften
der Grafikadapter beziehen. Im ROM-BIOS der neueren Videokarten sind
alle Zeichensätze komplett enthalten, also auch die
CGA-kompatiblen 8×8-Matrizen. Die Adressen lassen sich mit Int
10h, ax = 1130h und bh laut Tabelle 2 ermitteln.
Für die Zeichenausgaben in den Grafikmodi
sind die Aufrufe al = 20h bis 24h des Interrupt 10h, mit ah = 11h
wichtig. Beim VGA-Adapter kann zum Beispiel eine der vordefinierten
8×8-, 8×14- oder 8×16-Matrizen ausgewählt oder
ein eigener Zeichensatz eingebunden werden. Das Format für
eigene Zeichenmatrizen läßt sich aus dem Prinzip, das in
Bild 1 für die 8×8-ROM-Matrix dargestellt ist,
leicht ableiten. Einzelne Bytes repräsentieren das Zeichen
zeilenweise, gesetzte Bits entsprechen Pixeln in der
Vordergrundfarbe.
- Bild 1. Die Zeichenmatrizen sind byteweise im Speicher abgelegt
Das Character Generator Interface (CGI) ist flexibel und bietet eine bequeme Möglichkeit, einen neuen Zeichensatz für die Bildschirmausgabe zu bestimmen. Die Änderungen in der Video Data Display Area werden automatisch durchgeführt. Hierbei wird im Eintrag 0040:0085h die Höhe der Zeichenmatrix festgehalten, die bei den grundsätzlich ein Byte breiten Matrizen der PC-Zeichensätze gleichbedeutend ist mit der Größe einer Zeichenmatrix in Byte. Das Wort an der Adresse 0040:0084h enthält die Nummer der untersten Textzeile einer Bildschirmseite. Der Zeiger des Interrupt 43h wird auf den Beginn der Zeichenmatrizen im Speicher gerichtet.
Einzelne Zeilen...
Zurück zu den Textausgabefunktionen aus
Tabelle 1. Die mit Interrupt 10h, ah = 11h installierte Zeichenmatrix
wird von den BIOS-Routinen ah = 9, 0Ah, 0Eh und 13h zur
Zeichenausgabe verwendet. Die Aufrufe 9 und 0Ah arbeiten im
Grafikmodus identisch, im Textmodus läßt sich mit Funktion
0Ah zusätzlich auch das Attribut verändern. Beide
BIOS-Routinen geben ein Zeichen, das mehrfach wiederholt werden kann,
an der Cursorposition aus, ohne diese zu aktualisieren.
Die Zeichenmatrix wird dabei so in den
Grafikbildschirm übertragen, daß die Hintergrundfarbe auf
0 gesetzt wird, oder – sofern Bit 7 der Vordergrundfarbe im
Aufruf gesetzt ist – das Zeichen mit dem ursprünglichen
Inhalt des Videospeichers XOR-verknüpft wird. Hierbei bleibt im
Bereich des Hintergrundes der Bildschirminhalt erhalten, die Farbe
der einzelnen Pixel des neuen Zeichens können sich aus der
gewählten Vordergrund- und der bisherigen Pixelfarbe jedoch
unterschiedlich ergeben. Mit den BIOS-Routinen ist es daher in den
Grafikmodi nicht möglich, Zeichen unter Beibehaltung des
Hintergrundes auf jeden Fall in einer bestimmten Vordergrundfarbe –
unabhängig vom bisherigen Bildschirminhalt – auszugeben.
Dies ist ein erhebliches Manko der BIOS-Funktionen.
Die Aufrufe ah = 0Eh und 13h verwenden die eben
besprochene Routine 0Ah zur Ausgabe ihrer Zeichen, die Verarbeitung
der Farben bleibt also die gleiche. Die Int-10h-Funktion ah = 0Eh
gibt ein Zeichen im Teletype-Mode aus. Der Cursor wird hierbei
mitbewegt, und die Steuercodes 7 (Glocke), 8 (Rückschritt), 10
(Zeilenvorschub) und 13 (Wagenrücklauf) werden ausgewertet,
leider jedoch nicht ASCII 9, der Tabulator.
...oder ganze Strings
Funktion 13h gibt gleich eine ganze Zeichenkette
aus, wobei die oben genannten Steuerzeichen ausgewertet werden, der
Cursor wahlweise weiterbewegt und die Attribute ebenfalls wahlweise
im String jedem einzelnen Zeichen mitgegeben werden.
Eine Besonderheit ergibt sich bei PC/AT mit EGA
oder MCGA: Zeilenvorschub und Wagenrücklauf werden immer auf die
angezeigte Bildschirmseite bezogen, egal welche Bildschirmseite man
für die gesamte Zeichenkette im bh-Register angibt.
Die BIOS-Routinen können Zeichen nur an
Cursorpositionen in Textkoordinaten ausgeben, also nicht auf ein
beliebiges Pixel genau in Grafikkoordinaten. Die Cursorsteuerung
arbeitet byteorientiert – alle ROM-Zeichensätze sind 8 Bit
breit – und orientiert sich an den Byte-Adressen im
Videospeicher. Das bedeutet für die Ausgabe im Grafikmode, daß
eine Zeile, die über den rechten Bildschirmrand hinausgehen
würde, im Speicher kontinuierlich abgelegt und auf dem Monitor
links eine Pixelreihe tiefer als neuer Zeilenanfang fortgesetzt wird.
Unter Umständen werden dort bereits vorhandene Zeichen
überschrieben und unleserlich. Wer die BIOS-Routinen verwenden
will, muß also selbst auf die Zeichenumbrüche achten.
Die vorhandenen Ausgabefunktionen sind
unkompliziert geschrieben und erfüllen ihre Aufgabe, ohne sich
durch besondere Raffinessen auszuzeichnen. Listing 1 enthält
ein Assemblermodul für den EGA-640×350-und den
VGA-640×480-Grafikmodus, das eine Zeichenkette ausgibt und zwei
Hauptnachteile der BIOS-Funktionen abstellt. Zum einen werden alle
Zeichen in ihrer Vordergrundfarbe vor unverändertem Hintergrund
dargestellt, wobei alle mit dem Character Generator Interface
installierten Zeichensätze verarbeitet werden können. Zum
anderen lassen sich die Zeichen über Grafikkoordinaten
unabhängig vom Textcursor an jede beliebige Stelle des
Bildschirmes schreiben. So können auch Diagramme in hoher
Auflösung exakt und auf das Pixel genau beschriftet werden.
Bitbewegungen in Assembler
Routinen zum pixelweisen Darstellen von Zeichen
sind immer zeitkritisch, daher sollten sie in Assembler programmiert
werden. Darüber hinaus sollte immer maximale Kompatibilität
zur Vorgehensweise des BIOS angestrebt werden, zum Beispiel das
Installieren neuer Zeichensätze mit Interrupt 10h, ah = 11h,
damit alle notwendigen Zeiger gesetzt werden, und die Video Display
Data Area sinnvolle Informationen enthält.
Nun noch einige Tips, wie Sie an neue Zeichensätze
– genauer gesagt neue Zeichenmatrizen – kommen. Einen
eigenen Assembler-Quellcode mit einzelnen Define-Bytes-Anweisungen (DB)
einzutippen, ist sehr mühevoll. Ein Beispiellisting hierzu
hätte den Beitrag ziemlich aufgebläht, und wer will schon
2048 Byte, die allein für einen Zeichensatz mit 256
verschiedenen 8×8-Matrizen notwendig sind, per Hand eintippen?
Wenn Sie die im BIOS-ROM vorhandenen Zeichensätze
nur wenig verändern wollen, können sie diese in den
Hauptspeicher kopieren und gezielt verändern. Wie Sie die
Matrizen im ROM aufstöbern, wissen sie ja jetzt. Sollte Ihnen
jedoch ein völlig neues Outfit für Ihre Zeichen
vorschweben, so bietet der Public-Domain-Markt eine reichhaltige
Auswahl an Editoren – zur bequemen Eingabe der Pixelmatrizen
per Maus – oder fertige Fonts. Es lassen sich übrigens
auch Softfonts für Laserdrucker zweckentfremden.
Ingo Eickmann/ed
Literatur
- [1] Wilton, Richard: Programmer's guide to PC and PS/2, Video Systems, Microsoft Press, 1987.
Listing 1. Das Include-File GRSTRING.INC gibt Texte im Grafikmode normal oder kursiv vor beliebigem Hintergrund aus
; ----------------------------------------------
; GRSTRING.INC
; ----------------------------------------------
; Include-Datei zur Ausgabe von Text
; in den EGA/VGA-Grafikmodes 10h und 12h
; ----------------------------------------------
BIOSSeg equ 0040h
GRC equ 3CEh
GRSeg equ 0A000h
INT43h equ 43h shl 2
LineLength equ 80
PointsOfs equ 85h
OUTDX macro X ; Makro zur Ausgabe
; eines Wortes an
mov ax,X ; den Port in DX
out dx,ax
endm
; ----------------------------------------------
.DATA ; Beginn des Daten-
; Segments
Color db 0 ; Variable der Sub-
; routine GRString
Func db 0
Points dw 0
TabSeg dw 0
VAddr dw 0
; ----------------------------------------------
.CODE ; Beginn des Code-
; Segments
; ==============================================
; Subroutine GRString: Ausgabe eines Strings im
; Grafikmode
; ax: X-Grafikkordinate
; bx: Y-Grafikkordinate
; dh: Farbe
; dl: Funktion
; 0: Normal
; 1: Kursiv (max Höhe: 17 Pts.)
; es:si: Zeiger auf String, letztes
; Zeichen muß 00h sein
; ==============================================
GRString proc near
mov [Func],dl ; Funktion zwi-
; schenspeichern
push ax ; X retten
mov ah,dh
xor al,al
mov dx,GRC ; Graphics Controller
; programmieren
out dx,ax ; Farbe in das
; Set/Reset Register
OUTDX 0F01h ; Enable Set Reset
; Register
OUTDX 0003h ; Data Rotate/
; Function
; Select Register
mov ax,LineLength ; Offset im Video-
; speicher berechnen:
mul bx ; Adr = Y * 80
; Byte/Line
pop bx
mov ch,bl
and ch,00000111b ; Anzahl der hori-
; zontalen Shifts
mov cl,3
shr bx,cl ; Adr = Adr + X div 8
mov cl,ch
xor ch,ch
add ax,bx
mov [VAddr],ax ; Offset im Video-
; speicher ablegen
push ds ; Datensegment retten
mov ax,BIOSSeg ; BIOS-Datensegment
mov bx,INT43h ; Offset des INT 43h-
; Vektors
mov ds,ax
mov dl,ds:[PointsOfs]; Höhe der aktu-
; ellen Zeichenmatrix
xor ax,ax ; aus der Video
; Display Data Area
mov ds,ax
lds di,ds:[bx] ; Zeiger DS:DI auf
; aktuellen Font
mov bx,ds ; laut INT 43h
pop ds
mov [TabSeg],bx ; ermittelte Werte
; zwischenspeichern
mov byte ptr [Points],dl
cmp [Func],1 ; Kursiv ?
jnz NextChr2
add cl,dl ; JA: Versatz für
; oberste Scan Line
dec cl
NextChr2:
; ==============================================
push ds ; äußere Schleife für
; nächstes Zeichen
push es
pop ds
cld
lodsb ; nächstes ASCII-
; Zeichen auf String
pop ds
or al,al ; Endmarke 00h ge-
; funden?
jnz NoEnd ; NEIN => Rausspringen
jmp Raus ; JA => Rausspringen
NoEnd: push [VAddr] ; Adresse und Versatz
; für nächstes
push cx ; Zeichen retten
xor ah,ah
mov bx,[Points]
mul bx ; Eintrag in Matrizen-
; tabelle berechnen
push bx
mov bx,ax
NextLine:
; ----------------------------------------------
push ds ; innere Schleife für
; nächste Scan Line
mov ax,TabSeg
mov ds,ax ; nächste Scan Line
; des Zeichens aus der
mov ah,[di+bx] ; Tabelle holen
pop ds
inc bx ; Zeiger bx erhöhen
push bx ; Register für das Be-
; schreiben des Video-
push di ; speichers retten
xor bx,bx
push cx
and cx,0FFh ; LSB extrahieren
jz Weiter ; Verschiebung = 0 ?
Rotate: shr ax,1 ; Bitmuster pixelweise
; horz. verschieben
rcr bx,1
loop Rotate
Weiter: mov ch,al ; 2. Byte zwischen-
; speichern
mov al,8 ; Bit Mask Register des
; Graphic-Controllers
mov dx,GRC ; programmieren
out dx,ax
mov di,[VAddr]
push ds
mov ax,GRSeg ; Segment des Video-
; speichers im Grafik-
mov ds,ax ; mode herstellen
mov cl,[di] ; Pixel des linken
; Byte setzen
mov [di],cl
mov al,8 ; Bit Mask Register
; adressieren
IRP n,<ch,bh,bl> ; die restlichen
; 3 Byte schreiben
inc di ; Videospeicheradresse
; des Bytes
mov ah,&n
or ah,ah ; Pixel setzen ?
jz Zero&n
out dx,ax ; JA: Bitmaske in
; Graphic Controller
mov cl,[di] ; Pixel dieser Scan-
; Line setzen
mov [di],cl
Zero&n label near
endm
add di,LineLength - 3
; Adresse fur nächste
pop ds ; Scan Line berechnen
mov [VAddr],di ; und ablegen
pop cx
cmp [Func],1 ; Kursiv ?
jnz Norm
dec cl ; JA: Versatz verrin-
; gern
Norm: pop di ; Register wieder her-
; stellen
pop bx
pop ax
dec ax
jz NextChr1 ; letzte Scan Line er-
; reicht?
push ax ; NEIN => weiter zur
; nächsten Scan Line
jmp NextLine ; Sprung zum Schlei-
; fenanfang
; ----------------------------------------------
NextChr1:
pop cx ; Versatz der obersten
; Scan Line
pop ax ; Adresse im Video
; speicher für nächs-
inc ax ; tes Zeichen erhöhen
mov [VAddr],ax
jmp NextChr2 ; Sprung zum
; Schleifenanfang
; ==============================================
Raus: ; Standardwerte für
; den Graphics Contr.
OUTDX 0000h ; Set/Reset Register
OUTDX 0F01h ; Enable Set Reset Re-
; gister
OUTDX 0003h ; Data Rotate/Function
; Select Register
OUTDX 0FF08h ; Bit Mask Register
ret
GRString endp
Listing 2. Das Programm GRDEMO.ASM zeigt die Möglichkeiten der Include-Datei
; ----------------------------------------------
; GRDEMO.ASM
; ----------------------------------------------
; Assemblieren mit MASM 5.x :
; MASM grdemo;
; LINK grdemo;
; ----------------------------------------------
; Beispielprogramm zu GRSTRING.INC fur EGA/VGA.
; Farbziffern werden normal und kursiv,
; horizontal und vertikal um einzelne Pixel
; versetzt ausgegeben.
; ----------------------------------------------
PAGE 65,80
TITLE GRDEMO
Font8 equ 1123h ; ax-Register für
; CGI (8x16-Matrix
Font14 equ 1122h ; nur bei VGA)
Font16 equ 1124h
HorzOff equ 100 ; horizontaler Offset
; für '(kursiv)'
Rows8 equ 3 ; bl-Register für CGI
Rows14 equ 2 ; (8x16-Matrix nur
Rows16 equ 2 ; bei VGA)
VertOff equ 175 ; Versatz fur untere
; Bildhälfte
DOSSEG
.MODEL SMALL ; Standard Memory
; Model
.STACK 100h
INCLUDE GRSTRING.INC
; ----------------------------------------------
.DATA ; Beginn des Daten-
; Segments
Paras dw 0 ; Zwischenspeicher für
; dh und dl
Str8 db '8x8 Matrix',0
; String für CGA-
; Zeichenmatrix
Str14 db '8x14 Matrix',0
; String für EGA-
; Zeichenmatrix
Str16 db '8x16 Matrix',0
; String für VGA-
; Zeichenmatrix
StrKurs db '(kursiv)',0 ; String für kursiv
StrZ dw 0 ; Platzhalter für
; Ziffern
; ----------------------------------------------
.CODE ; Beginn des Code Seg-
; ments
Start:
mov ax,@DATA ; Datensegment in DS
; laden
mov ds,ax
mov es,ax ; für GRString auch ES
; mit DS laden
mov ax,0010h ; Grafikmode 10h
; (650x350, 16 colors)
int 10h
xor dl,dl ; 1. Normal ausgeben
xor bp,bp ; 2. Kursiv (dl=1) mit
; Versatz (bp)
Lop3: mov cx,10h ; Laufvariable für 16
; Farben
push dx
mov ax,Font8 ; 8x8-Matrix anwählen
mov bl,Rows8 ; maximal 43 Zeilen zu-
; lassen
int 10h
pop dx
Lop1: push cx ; Farbe retten
mov ax,cx ; X- und Y-Grafik-
mov bx,cx ; koordinate berechnen
dec cx ; Farbnummer ermitteln
mov dh,cl
add cl,'0' ; in ASCII umwandeln
cmp cl,'9'
jle Lop2
add cl,'A'-'9'-1 ; Farben 0Ah bis 0Fh
; berücksichtigen
Lop2: mov byte ptr [StrZ],cl
; Farbnummer als String
; ablegen
mov si,offset StrZ
; Zeiger ES:SI auf den
; String richten
mov cl,3
shl ax,cl ; X-Koordinate für
; horizontale Reihe
push ax ; Parameter für 2. Auf-
; ruf speichern
push bx
add bx,bp ; vertikalen Versatz
; addieren
push dx
push si
call GRString ; Farbnummer in horiz.
; Reihe ausgeben
pop si ; Parameter für 2. Auf-
; ruf neu laden
pop dx
pop ax ; X- und Y-Koordinate
; vertauschen
pop bx
add bx,bp ; vertikalen Versatz
; addieren
push dx
call GRString ; Farbnummer in vertik.
; Reihe ausgeben
pop dx
pop cx
loop Lop1 ; nächster Farbwert
mov dh,7 ; Pixelfarbe weiß
mov [Paras],dx
IRP n,<8,14> ; Bei VGA: <8,14,16>
mov ax,Font&n
mov bl,Rows&n
int 10h ; Font für Matrix an-
; wählen
mov ax,160 ; Grafikkoordinaten für
mov bx,10 * &n; die Strings berechnen
add bx,bp ; vertikalen Versatz
; addieren
mov dx,[Paras]
cmp dl,1 ; kursive Ausgabe ?
jnz Norm&n ; NEIN => nur normaler
; String
push ax ; JA => '(kursiv)'
; ausgeben
push bx
add ax,HorzOff;horizontalen Offset
; addieren
mov si,offset StrKurs
call GRString ; String ausgeben
pop bx
pop ax
mov dx,[Paras]
Norm&n: mov si,offset Str&n
; ES:SI auf String
; richten
call GRString ; String ausgeben
endm
mov bp,VertOff ; Versatz für 2. Durch-
; lauf
mov dx,[Paras]
inc dl ; Funktionsparameter
; erhöhen
cmp dl,1 ; noch kursiv ?
jg DOS ; NEIN => Ende Ausgabe
jmp Lop3 ; JA => Anfang der
; Ausgabe
DOS: mov ah,0 ; auf Tastatureingabe
; warten
int 16h
mov ax,0003 ; Textmode 3 (80x25,
; 16 colors)
int 10h
mov ax,4C00h ; Programmende und
; Rücksprung ins DOS
int 21h
END Start ; Ende von GRDemo.ASM
aus mc 08/91 – Seite 102-107