Textausgabe — Änderungen 7359 → 7559

Zeile 1: Zeile 1:
 
[[Category:Tutorials]]
 
[[Category:Tutorials]]
−
==Vorwort==
+
Die Textausgabe ist für so gut wie jedes Programm eine wichtige Möglichkeit, dem User oder Programmierer Informationen über sich mitzuteilen bzw. generell Output auszugeben. Auch und gerade für ein Betriebssystem ist es, auch schon in einer sehr frühen Phase wichtig, dass es Informationen per Textausgabe ausgeben kann um z.B. anzuzeigen, ob diverse Aufgaben gelungen sind oder nicht.
−
In diesem Artikel geht es nur darum wie im Textmode Schrift (und nur Schrift, keine Grafiken) auf dem Bildschirm ausgegeben werden kann. Normalerweise geht das über einen BIOS-Interrupt, aber man will ja auch im Protected Mode Text auf dem Bildschirm schreiben können.
 
  
−
==Textspeicher==
+
Folgend wird nun beschrieben, wie man im Protected Mode Text auf dem Bildschirm ausgeben kann.
−
Zur Ausgabe von Text gibt es einen 4kB großen Speicher an der Adresse 0xB8000. Dieser Speicher kann linear angesprochen werden und benutzt 2 Byte pro Zeichen auf dem Bildschirm. Es gibt also 80 Spalten (Zeichen pro Zeile) und 25 Zeilen.
 
  
−
==Schreiben in den Textspeicher==
+
== Textspeicher ==
−
Um nun auf dem Bildschirm ein Zeichen zu haben, muss man erstmal das Offset ausrechnen, an dem das Zeichen steht. Da der Speicher linear ist geht das auch mit einer linearen Gleichung: o = z*80+s
+
Zur Ausgabe von Text gibt es einen 4 kB großen Speicher an der Adresse 0xB8000. Dieser Speicher kann linear angesprochen werden und benutzt 2 Byte pro Zeichen auf dem Bildschirm. Es ergeben sich also 80 Spalten (Zeichen pro Zeile) und 25 Zeilen, insgesamt also 2000 gleichzeitig darstellbare Zeichen.
−
Wobei hier o das Offset ist, z die Zeile und s die Spalte ist.
+
 
 +
== Schreiben in den Textspeicher ==
 +
Um nun auf dem Bildschirm ein Zeichen auszugeben, muss erstmal das Offset ausgerechnet werden, an dem das Zeichen steht. Da der Speicher linear ist geht das auch mit einer linearen Gleichung: o = z*80+s
 +
o steht für das Offset, z für die Zeile und s für die Spalte.
  
 
In dem ersten Byte wird der Buchstabe selbst, in dem 2. Byte wird das Attribut, also die Vorder- und Hintergrundfarbe gespeichert. Als Code wird [[Codepage 437]] verwendet, welche eine Erweiterung von [[ASCII]] darstelt.
 
In dem ersten Byte wird der Buchstabe selbst, in dem 2. Byte wird das Attribut, also die Vorder- und Hintergrundfarbe gespeichert. Als Code wird [[Codepage 437]] verwendet, welche eine Erweiterung von [[ASCII]] darstelt.
  
 
==Attribut-Byte==
 
==Attribut-Byte==
−
Das Attribute-Byte ist wie folgt gestaltet:
+
Das Attribute-Byte ist wie folgt aufgebaut:
  
−
BXXXYYYYb, Hierbei ist X die Hintergrundfarbe, Y die Vordergrundfarbe und B das "Blinkbit". Ist es gesetzt, dann blinkt das entsprechende Zeichen. Hier ist eine Tabelle aller Farben:
+
BXXXYYYYb, Hierbei ist X die Hintergrundfarbe, Y die Vordergrundfarbe und B das "Blinkbit". Ist es gesetzt, blinkt das entsprechende Zeichen. Hier ist eine Tabelle aller Farben:
  
 
{| {{Prettytable}}
 
{| {{Prettytable}}
Zeile 38: Zeile 39:
 
|}
 
|}
  
−
Nebenbei bemerkt: Die Standardfarbe ist 0x07. Also Hellgrau auf Schwarz.
+
Nebenbei bemerkt: Die inoffizielle Standardfarbe ist 0x07, Hellgrau auf Schwarz.
 +
 
 +
=== Blinken ===
 +
Man kann sich nicht darauf verlassen, dass das höchstwertige Bit des Attributbytes wirklich anzeigt, ob das Zeichen blinken soll oder nicht. Bei einigen Computern ist dieses Bit einfach das höherwertige Bit der Hintergrundfarbe, sodass man hier auch helle Farben als Hintergrund verwenden kann.
  
−
===Blinken===
 
−
Man kann sich nicht darauf verlassen, dass das höchstwertige Bit des Attributbytes wirklich anzeigt, ob das Zeichen blinken soll oder nicht. Bei einigen Computern ist dieses Bit einfach das höchstwertige Bit der Hintergrundfarbe, sodass man hier auch helle Farben als Hintergrund verwenden kann.<br />
 
 
Wie man die Bedeutung dieses Bits manuell bestimmen kann, steht im Artikel [[Color_Graphics_Adapter#16_Hintergrundfarben|Color Graphics Adapter]].
 
Wie man die Bedeutung dieses Bits manuell bestimmen kann, steht im Artikel [[Color_Graphics_Adapter#16_Hintergrundfarben|Color Graphics Adapter]].
  
−
==Beispiel==
+
== Beispiel ==
 
Hier ein kleines Beispiel einer Funktion, die ein Zeichen (chr), in der Farbe color auf den Bildschirm, an die Position x,y schreiben soll. Hierbei werden Steuerzeichen nicht beachtet, bzw. als normales Zeichen auch ausgegeben (siehe [[Codepage 437]]).  
 
Hier ein kleines Beispiel einer Funktion, die ein Zeichen (chr), in der Farbe color auf den Bildschirm, an die Position x,y schreiben soll. Hierbei werden Steuerzeichen nicht beachtet, bzw. als normales Zeichen auch ausgegeben (siehe [[Codepage 437]]).  
  
Zeile 58: Zeile 60:
 
</c>
 
</c>
  
−
Nun folgt die Erklärung:
+
Erläuterung des Codes:
 +
 
 
Mit der 1. Zeile wird ein Pointer auf den Textspeicher erzeugt. Der Dateityp ist uint16_t, also 2byte, damit wir das Zeichen und das Attributebyte gleichzeitig schreiben können (geht einfach schneller). Nun wird die Adresse ausgerechnet, mit der oben genannten Formel. Hätten wird vorhin uint8_t benutzt müssten wir jetzt noch mit 2 multiplizieren, da ja jedes Zeichen 2 Byte benutzt. Das Setzen des Zeichens machen wir, indem wir einfach das Attribute auf 16 Bit erweitern, dann eine Linksverschiebung von 8 Bit vornehmen und per logischen Oder mit dem Zeichenbyte verknüpfen.
 
Mit der 1. Zeile wird ein Pointer auf den Textspeicher erzeugt. Der Dateityp ist uint16_t, also 2byte, damit wir das Zeichen und das Attributebyte gleichzeitig schreiben können (geht einfach schneller). Nun wird die Adresse ausgerechnet, mit der oben genannten Formel. Hätten wird vorhin uint8_t benutzt müssten wir jetzt noch mit 2 multiplizieren, da ja jedes Zeichen 2 Byte benutzt. Das Setzen des Zeichens machen wir, indem wir einfach das Attribute auf 16 Bit erweitern, dann eine Linksverschiebung von 8 Bit vornehmen und per logischen Oder mit dem Zeichenbyte verknüpfen.
  
Zeile 70: Zeile 73:
 
  0x0700 | 0x41 = 0x0741
 
  0x0700 | 0x41 = 0x0741
  
−
==Bildschirm scrollen==
+
== Bildschirm scrollen ==
−
Um den Bildschirm zu scrollen muss man einfach den ganzen Textspeicher ab der 2. Zeile zur 1. Zeile kopieren und die letzte Zeile löschen, also auf 0 oder irgendwas setzen. Wenn man eine memmove- und eine memset-Funktion bzw. eine memsetw-Funktion bei einem Attributbyte != 0 hat, geht das in ein paar Zeilen. Denn die Funktion memcpy muss für sich überlappende Speicherbereiche nicht das gewünschte Ergebnis erzielen.
+
Um den Bildschirm zu scrollen muss einfach der gesamte Textspeicher ab der 2. Zeile zur 1. Zeile kopiert werden und die letzte Zeile gelöscht werden, also auf 0 oder einen sonstigen Wert setzen. Wenn man eine memmove- und eine memset-Funktion bzw. eine memsetw-Funktion bei einem Attributbyte != 0 hat, geht das in ein paar Zeilen. Denn die Funktion memcpy muss für sich überlappende Speicherbereiche nicht das gewünschte Ergebnis erzielen.
  
−
==Cursor==
+
== Cursor ==
−
Manchen wird schon aufgefallen sein, dass auf dem Bildschirm ein Unterstrich ist, wo keiner sein sollte. Also zumindest wo keiner im Textspeicher ist. Das ist der Bildschirmcursor, der vom BIOS zur Verfügung gestellt wird. Ich will nicht lange darauf eingehen, ich stelle nur eine Funktion zum Verschieben und zum "Löschen" des Cursors zur Verfügung. Ich selber benutze ihn nicht, da das Verschieben des Cursors wirklich lahm geht ([http://www.osdev.org/wiki/Text_Mode_Cursor "Keep in mind that in/out to VGA Hardware is a slow operation"]), es ist aber jedem selbst überlassen.
+
Einigen wird schon aufgefallen sein, dass auf dem Bildschirm ein Unterstrich ist, wo keiner sein sollte. Also zumindest wo keiner im Textspeicher ist. Das ist der Bildschirmcursor, der vom BIOS zur Verfügung gestellt wird. Ich will nicht lange darauf eingehen, ich stelle nur eine Funktion zum Verschieben und zum "Löschen" des Cursors zur Verfügung. Ich selber benutze ihn nicht, da das Verschieben des Cursors wirklich lahm geht ([http://www.osdev.org/wiki/Text_Mode_Cursor "Keep in mind that in/out to VGA Hardware is a slow operation"]), es ist aber jedem selbst überlassen.
  
 
Hier eine Funktion zum Verschieben des Cursors (dies kann auch mit Int 0x10,0x02 gemacht werden). In dem Artikel [[I/O Ports]] wird genauer erklärt, was es mit den hier verwendeten I/O Ports auf sich hat.
 
Hier eine Funktion zum Verschieben des Cursors (dies kann auch mit Int 0x10,0x02 gemacht werden). In dem Artikel [[I/O Ports]] wird genauer erklärt, was es mit den hier verwendeten I/O Ports auf sich hat.