Kernel: Funktionen für Textausgaben
Bevor wir mit unserem nächsten Tutorial zum Thema Tastatureingaben weitermachen, könnten wir noch ein paar Funktionen gebrauchen, die Zeichen und Texte auf dem Bildschirm anzeigen können.
Im Grunde reichen uns hierfür ein paar wirkliche Basisfunktionen, zur Ausgabe von einzelnen Zeichen, Zahlen und ganzen Strings:
Sinnvollerweise definieren wir uns gleich ein paar Konstanten, die den Bildschirm und die Position des Bildschirms im Speicher beschreiben und haben dann die gesamte Header-Datei io.h
auch schon fertig:
Mit dem Wissen aus vorherigen Tutorials, wie man auf den Bildschirm-Speicher schreibt, können wir die Funktion printc()
schnell schreiben. Wir schreiben einfach das Zeichen an die aktuelle Textposition.
Wichtig ist hier der Begriff aktuelle Textposition: Wir müssen uns irgendwie merken, wo der nächste Buchstabe auf dem Bildschirm stehen sollte. Also definieren wir uns eine Variable, die genau diese Information enthält:
Was passiert nun aber, wenn wir den ganzen Monitor von 80x25 Zeichen vollgeschrieben haben? Dann läuft unser Cursor über den Bildschirmspeicher hinaus und schreibt in fremden Speicher. Das darf natürlich nicht passieren! Außerdem wäre es sinnvolles Verhalten, wenn in so einem Fall der Bildschirm entweder geleert wird und der Text wieder oben beginnt oder die letzte Zeile geleert wird und alle anderen Zeilen nach oben geschoben werden.
Ich habe mich für zweitere Lösung entschieden, d.h. es wird immer nur eine Zeile vom Bildschirm geworfen. Dazu programmieren wir am besten eine Funktion increment_cursor()
und diese ruft wiederum eine Funktion shift_screen_up()
auf (oder falls ihr die andere Variante implementieren wollt, eine Funktion clear_screen_to_begin()
).
Damit können wir nun auch die Funktion kprintc()
ausbessern:
Sobald wir diese Funktion einmal haben, ist auch die Funktion zum Ausgeben von Strings nicht mehr schwer:
Die Funktion zum Ausgeben von Zahlen wird hingegen ein bisschen trickreich. Wir haben nämlich keine Mathematik-Bibliothek in einer Freestanding-GCC-Umgebung. Und bisher haben wir auch keine für unseren Kernel programmiert. Wir müssen die Zahl jedoch von links nach rechts schreiben, d.h. mit der höchsten Potenz zuerst. Dazu müssen wir aber wissen, durch welche Potenz von 10 wir maximal teilen müssen (oder alternativ alle durchprobieren, aber da wäre wieder das Problem, dass int
in der Länge nicht plattformübergreifend standardisiert ist).
Deshalb brauchen wir erstmal eine Funktion, die uns die höchste Zehnerpotenz gibt oder anders gesagt die Anzahl der Stellen, wenn man die Zahl in Basis 10 schreibt. Eine Multiplikation mit 10 kann man auch durch eine Kombination von Bitshifts schreiben, nämlich indem man den Wert um drei Stellen nach links shiftet (Multiplikation mit 8), um eine Stelle nach links shiftet (Multiplikation mit 2) und die beiden Werte addiert:
Außerdem werden wir für das weitere vorgehen eine Funktion für die Potenz benötigen. Ich selbst habe diese direkt in eine Datei math.c
geschrieben, aber ihr könnt sie natürlich auch vorerst in der io.c
lassen:
Wer die Funktion direkt in die io.c
schreibt, sollte sie zusätzlich als static
deklarieren, damit sie nicht im Namensraum des Linkers auftaucht.
Mit dieser Funktionen können wir nun unsere Eingabezahl nach und nach durch immer kleinere Zehnerpotenzen teilen und so jede einzelne Stelle ermitteln. Nehmen wir als Beispiel die Zahl 12345. Wir würden beginnen:
- 12345 / 10000 = 1 (/ steht für Integerdivision)
- 12345 % 10000 = 2345; 2345 / 1000 = 2
- 2345 % 1000 = 234; 345 % 100 = 3
- 345 % 100 = 45; 45 % 10 = 4
- 45 % 10 = 5; 5 % 1 = 5
Dies können wir mit folgender Funktion automatisiert erledigen:
I do not maintain a comments section. If you have any questions or comments regarding my posts, please do not hesitate to send me an e-mail to blog@stefan-koch.name.